Skip to content

Commit

Permalink
Merge branch 'main' into tedi/envvars
Browse files Browse the repository at this point in the history
Signed-off-by: Tedi Mitiku <[email protected]>
  • Loading branch information
tedim52 authored Oct 11, 2024
2 parents 666bc03 + 6c034d6 commit 22ec3a1
Show file tree
Hide file tree
Showing 17 changed files with 322 additions and 87 deletions.
9 changes: 9 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
linters:
enable:
- exhaustruct
- exportloopref
- gomnd
- staticcheck
- exhaustive
max-issues-per-linter: 0
sort-results: true
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
# Changelog

## [0.4.1](https://github.com/kurtosis-tech/kardinal/compare/0.4.0...0.4.1) (2024-10-03)


### Bug Fixes

* add auth for statefulset during manager deployment ([#268](https://github.com/kurtosis-tech/kardinal/issues/268)) ([9c011c6](https://github.com/kurtosis-tech/kardinal/commit/9c011c66f8315a5ada9183ac0b5873a4156f7246))

## [0.4.0](https://github.com/kurtosis-tech/kardinal/compare/0.3.3...0.4.0) (2024-10-03)


### ⚠ BREAKING CHANGES

* add support to StatefulSet ([#263](https://github.com/kurtosis-tech/kardinal/issues/263))

### Features

* add canonical tag to website pages ([#266](https://github.com/kurtosis-tech/kardinal/issues/266)) ([64bdab1](https://github.com/kurtosis-tech/kardinal/commit/64bdab125ed308ca5282f70f58b0d88949e3c124)), closes [#236](https://github.com/kurtosis-tech/kardinal/issues/236)
* add support to StatefulSet ([#263](https://github.com/kurtosis-tech/kardinal/issues/263)) ([a1632d5](https://github.com/kurtosis-tech/kardinal/commit/a1632d5aecd857f8de5b77db342c39daff91bcb2))


### Bug Fixes

* avoid trying to delete default namespace ([#265](https://github.com/kurtosis-tech/kardinal/issues/265)) ([907ad38](https://github.com/kurtosis-tech/kardinal/commit/907ad38cde24d7a7baac2b3b900187685be92149))

## [0.3.3](https://github.com/kurtosis-tech/kardinal/compare/0.3.2...0.3.3) (2024-10-02)


Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,3 +303,4 @@ kardinal flow telepresence-intercept {{flow-id}} {{service-name}} {{local-port}}
- Ask questions and get help in our community [forum](https://discuss.kardinal.dev).
- Read our [blog](https://blog.kardinal.dev/) for tips from developers and creators.
2 changes: 1 addition & 1 deletion ci/obd-demo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ spec:

---
apiVersion: apps/v1
kind: Deployment
kind: StatefulSet
metadata:
name: postgres-v1
labels:
Expand Down
134 changes: 87 additions & 47 deletions kardinal-cli/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"io"
"k8s.io/apimachinery/pkg/runtime"
"log"
"net"
"net/http"
Expand All @@ -23,6 +24,7 @@ import (
"kardinal.cli/multi_os_cmd_executor"

"github.com/kurtosis-tech/stacktrace"
"github.com/samber/lo"
"github.com/segmentio/analytics-go/v3"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -120,7 +122,9 @@ var deployCmd = &cobra.Command{
Short: "Deploy services",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
serviceConfigs, ingressConfigs, gatewayConfigs, routeConfigs, namespace, err := parseKubernetesManifestFile(kubernetesManifestFile)
ctx := context.Background()

services, deployments, statefulSets, ingresses, gateways, routes, noSupportedResourcesSpecs, namespace, err := parseKubernetesManifestFile(kubernetesManifestFile)
if err != nil {
log.Fatalf("Error loading k8s manifest file: %v", err)
}
Expand All @@ -129,7 +133,9 @@ var deployCmd = &cobra.Command{
log.Fatal("Error getting or creating user tenant UUID", err)
}

deploy(tenantUuid.String(), serviceConfigs, ingressConfigs, gatewayConfigs, routeConfigs, namespace)
if err := deploy(ctx, tenantUuid.String(), services, deployments, statefulSets, ingresses, gateways, routes, noSupportedResourcesSpecs, namespace); err != nil {
log.Fatalf("Error deploying k8s manifest file: %v", err)
}
},
}

Expand All @@ -145,7 +151,7 @@ var templateCreateCmd = &cobra.Command{
// A valid template only modifies services
// A valid template has metadata.name
// A valid template modifies at least one service
serviceConfigs, _, _, _, _, err := parseKubernetesManifestFile(templateYamlFile)
serviceConfigs, _, _, _, _, _, _, _, err := parseKubernetesManifestFile(templateYamlFile)
if err != nil {
log.Fatalf("Error loading template file: %v", err)
}
Expand Down Expand Up @@ -680,8 +686,8 @@ func init() {
createCmd.Flags().StringSliceVarP(&serviceImagePairs, "service-image", "s", []string{}, "Extra service and respective image to include in the same flow (can be used multiple times)")
createCmd.Flags().StringVarP(&templateName, "template", "t", "", "Template name to use for the flow creation")
createCmd.Flags().StringVarP(&templateArgsFile, "template-args", "a", "", "JSON with the template arguments or path to YAML file containing template arguments")
createCmd.Flags().StringVarP(&flowID, "ID", "i", "", "Set the flow id")
createCmd.Flags().StringVarP(&flowSpecFilepath, "flow-spec-config", "", "", "Path to the flow spec configuration file")
createCmd.Flags().StringVarP(&flowID, "id", "i", "", "Set the flow id")

deployCmd.PersistentFlags().StringVarP(&kubernetesManifestFile, "k8s-manifest", "k", "", "Path to the K8S manifest file")
deployCmd.MarkPersistentFlagRequired("k8s-manifest")
Expand Down Expand Up @@ -717,19 +723,32 @@ func parsePairs(pairs []string) map[string]string {
return pairsMap
}

func parseKubernetesManifestFile(kubernetesManifestFile string) ([]api_types.ServiceConfig, []api_types.IngressConfig, []api_types.GatewayConfig, []api_types.RouteConfig, string, error) {
func parseKubernetesManifestFile(kubernetesManifestFile string) (
[]api_types.ServiceConfig,
[]api_types.DeploymentConfig,
[]api_types.StatefulSetConfig,
[]api_types.IngressConfig,
[]api_types.GatewayConfig,
[]api_types.RouteConfig,
[]string,
string,
error,
) {
fileBytes, err := loadKubernetesManifestFile(kubernetesManifestFile)
if err != nil {
log.Fatalf("Error loading kubernetest manifest file: %v", err)
return nil, nil, nil, nil, "", err
return nil, nil, nil, nil, nil, nil, nil, "", err
}

manifest := string(fileBytes)
var namespace string
serviceConfigs := map[string]*api_types.ServiceConfig{}
ingressConfigs := map[string]*api_types.IngressConfig{}
gatewayConfigs := map[string]*api_types.GatewayConfig{}
routeConfigs := map[string]*api_types.RouteConfig{}
serviceConfigs := map[string]api_types.ServiceConfig{}
deploymentConfigs := map[string]api_types.DeploymentConfig{}
statefulSetConfigs := map[string]api_types.StatefulSetConfig{}
ingressConfigs := map[string]api_types.IngressConfig{}
gatewayConfigs := map[string]api_types.GatewayConfig{}
routeConfigs := map[string]api_types.RouteConfig{}
noSupportedResourcesSpecs := []string{}

// Register the gateway scheme to parse the Gateway CRD
gatewayscheme.AddToScheme(scheme.Scheme)
Expand All @@ -738,75 +757,71 @@ func parseKubernetesManifestFile(kubernetesManifestFile string) ([]api_types.Ser
if len(spec) == 0 {
continue
}

obj, _, err := decode([]byte(spec), nil, nil)
if err != nil {
return nil, nil, nil, nil, "", stacktrace.Propagate(err, "An error occurred parsing the spec: %s", spec)
if runtime.IsNotRegisteredError(err) {
noSupportedResourcesSpecs = append(noSupportedResourcesSpecs, spec)
continue
}
return nil, nil, nil, nil, nil, nil, nil, "", stacktrace.Propagate(err, "An error occurred parsing the spec: %s", spec)
}
switch obj := obj.(type) {
case *corev1.Service:
service := obj
serviceName := getObjectName(service.GetObjectMeta().(*metav1.ObjectMeta))
_, ok := serviceConfigs[serviceName]
if !ok {
serviceConfigs[serviceName] = &api_types.ServiceConfig{
serviceConfigs[serviceName] = api_types.ServiceConfig{
Service: *service,
}
} else {
serviceConfigs[serviceName].Service = *service
logrus.Warnf("Service %s already exists, skipping it", serviceName)
}
case *appv1.Deployment:
deployment := obj
deploymentName := getObjectName(deployment.GetObjectMeta().(*metav1.ObjectMeta))
_, ok := serviceConfigs[deploymentName]
_, ok := deploymentConfigs[deploymentName]
if !ok {
serviceConfigs[deploymentName] = &api_types.ServiceConfig{
deploymentConfigs[deploymentName] = api_types.DeploymentConfig{
Deployment: *deployment,
}
} else {
serviceConfigs[deploymentName].Deployment = *deployment
logrus.Warnf("Deployment %s already exists, skipping it", deploymentName)
}
case *appv1.StatefulSet:
statefulset := obj
statefulsetName := getObjectName(statefulset.GetObjectMeta().(*metav1.ObjectMeta))
_, ok := statefulSetConfigs[statefulsetName]
if !ok {
statefulSetConfigs[statefulsetName] = api_types.StatefulSetConfig{
StatefulSet: *statefulset,
}
} else {
logrus.Warnf("StatefulSet %s already exists, skipping it", statefulsetName)
}
case *k8snet.Ingress:
ingress := obj
ingressName := getObjectName(ingress.GetObjectMeta().(*metav1.ObjectMeta))
ingressConfigs[ingressName] = &api_types.IngressConfig{Ingress: *ingress}
ingressConfigs[ingressName] = api_types.IngressConfig{Ingress: *ingress}
case *corev1.Namespace:
namespaceObj := obj
namespaceName := getObjectName(namespaceObj.GetObjectMeta().(*metav1.ObjectMeta))
namespace = namespaceName
case *gateway.Gateway:
gatewayObj := obj
gatewayName := getObjectName(gatewayObj.GetObjectMeta().(*metav1.ObjectMeta))
gatewayConfigs[gatewayName] = &api_types.GatewayConfig{Gateway: *gatewayObj}
gatewayConfigs[gatewayName] = api_types.GatewayConfig{Gateway: *gatewayObj}
case *gateway.HTTPRoute:
routeObj := obj
routeName := getObjectName(routeObj.GetObjectMeta().(*metav1.ObjectMeta))
routeConfigs[routeName] = &api_types.RouteConfig{HttpRoute: *routeObj}
routeConfigs[routeName] = api_types.RouteConfig{HttpRoute: *routeObj}
default:
return nil, nil, nil, nil, "", stacktrace.NewError("An error occurred parsing the manifest because of an unsupported kubernetes type")
noSupportedResourcesSpecs = append(noSupportedResourcesSpecs, spec)
}
}

finalServiceConfigs := []api_types.ServiceConfig{}
for _, serviceConfig := range serviceConfigs {
finalServiceConfigs = append(finalServiceConfigs, *serviceConfig)
}

finalIngressConfigs := []api_types.IngressConfig{}
for _, ingressConfig := range ingressConfigs {
finalIngressConfigs = append(finalIngressConfigs, *ingressConfig)
}

finalGatewayConfigs := []api_types.GatewayConfig{}
for _, gatewayConfig := range gatewayConfigs {
finalGatewayConfigs = append(finalGatewayConfigs, *gatewayConfig)
}

finalRouteConfigs := []api_types.RouteConfig{}
for _, routeConfig := range routeConfigs {
finalRouteConfigs = append(finalRouteConfigs, *routeConfig)
}

return finalServiceConfigs, finalIngressConfigs, finalGatewayConfigs, finalRouteConfigs, namespace, nil
return lo.Values(serviceConfigs), lo.Values(deploymentConfigs), lo.Values(statefulSetConfigs), lo.Values(ingressConfigs), lo.Values(gatewayConfigs), lo.Values(routeConfigs), noSupportedResourcesSpecs, namespace, nil
}

func parseTemplateArgs(filepathOrJson string) (map[string]interface{}, error) {
Expand Down Expand Up @@ -856,7 +871,6 @@ func listDevFlow(tenantUuid api_types.Uuid) {
}

printFlowTable(flows)
return
}

func getTenantUuidFlows(tenantUuid api_types.Uuid) ([]api_types.Flow, error) {
Expand Down Expand Up @@ -958,8 +972,32 @@ func createDevFlow(tenantUuid api_types.Uuid, pairsMap map[string]string, templa
}

func deploy(
ctx context.Context,
tenantUuid api_types.Uuid,
serviceConfigs []api_types.ServiceConfig,
deploymentConfigs []api_types.DeploymentConfig,
statefulSetConfigs []api_types.StatefulSetConfig,
ingressConfigs []api_types.IngressConfig,
gatewayConfigs []api_types.GatewayConfig,
routeConfigs []api_types.RouteConfig,
noSupportedResourcesSpecs []string,
namespace string,
) error {

if err := deployment.DeployResourceSpecs(ctx, noSupportedResourcesSpecs); err != nil {
return stacktrace.Propagate(err, "an error occurred deploying not supported resources")
}

deploySupportedResources(tenantUuid, serviceConfigs, deploymentConfigs, statefulSetConfigs, ingressConfigs, gatewayConfigs, routeConfigs, namespace)

return nil
}

func deploySupportedResources(
tenantUuid api_types.Uuid,
serviceConfigs []api_types.ServiceConfig,
deploymentConfigs []api_types.DeploymentConfig,
statefulSetConfigs []api_types.StatefulSetConfig,
ingressConfigs []api_types.IngressConfig,
gatewayConfigs []api_types.GatewayConfig,
routeConfigs []api_types.RouteConfig,
Expand All @@ -968,11 +1006,13 @@ func deploy(
ctx := context.Background()

body := api_types.PostTenantUuidDeployJSONRequestBody{
ServiceConfigs: &serviceConfigs,
IngressConfigs: &ingressConfigs,
GatewayConfigs: &gatewayConfigs,
RouteConfigs: &routeConfigs,
Namespace: &namespace,
ServiceConfigs: &serviceConfigs,
DeploymentConfigs: &deploymentConfigs,
StatefulSetConfigs: &statefulSetConfigs,
IngressConfigs: &ingressConfigs,
GatewayConfigs: &gatewayConfigs,
RouteConfigs: &routeConfigs,
Namespace: &namespace,
}
client := getKontrolServiceClient()

Expand Down
40 changes: 39 additions & 1 deletion kardinal-cli/deployment/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"context"
"fmt"
"gopkg.in/yaml.v3"
"io"
"net/http"
"text/template"
Expand Down Expand Up @@ -41,7 +42,7 @@ metadata:
{{.KardinalAppIDLabelKey}}: {{.KardinalManagerAppIDLabelValue}}
rules:
- apiGroups: ["*"]
resources: ["namespaces", "pods", "services", "deployments", "virtualservices", "workloadgroups", "workloadentries", "sidecars", "serviceentries", "gateways", "envoyfilters", "destinationrules", "authorizationpolicies", "ingresses", "httproutes"]
resources: ["namespaces", "pods", "services", "deployments", "statefulsets", "virtualservices", "workloadgroups", "workloadentries", "sidecars", "serviceentries", "gateways", "envoyfilters", "destinationrules", "authorizationpolicies", "ingresses", "httproutes"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
Expand Down Expand Up @@ -252,6 +253,43 @@ func DeployKardinalManagerInCluster(ctx context.Context, clusterResourcesURL str
return nil
}

type k8sResourceKindAndMetadata struct {
Kind string `yaml:"kind"`
Metadata struct {
Name string `yaml:"name"`
Namespace string `yaml:"namespace"`
}
}

func DeployResourceSpecs(ctx context.Context, resourceSpecs []string) error {
k8sConfig, err := kubernetes.GetConfig()
if err != nil {
return stacktrace.Propagate(err, "An error occurred while creating the Kubernetes client")
}
kubernetesClientObj, err := kubernetes.CreateKubernetesClient(k8sConfig)
if err != nil {
return stacktrace.Propagate(err, "An error occurred while creating the Kubernetes client")
}

for _, resourceSpec := range resourceSpecs {
resourceSpecBytes := []byte(resourceSpec)

var k8sResourceMetadataObj k8sResourceKindAndMetadata
err := yaml.Unmarshal([]byte(resourceSpec), &k8sResourceMetadataObj)
if err != nil {
return stacktrace.Propagate(err, "An error occurred while unmarshalling a resource spec")
}
namespaceName := k8sResourceMetadataObj.Metadata.Namespace

logrus.Debugf("Deploying resource '%s' kind '%s' in namespace '%s'", k8sResourceMetadataObj.Metadata.Name, k8sResourceMetadataObj.Kind, namespaceName)
if err := kubernetesClientObj.ApplyYamlFileContentInNamespace(ctx, namespaceName, resourceSpecBytes); err != nil {
return stacktrace.Propagate(err, "An error occurred while applying resource '%s' kind '%s' in namespace '%s'", k8sResourceMetadataObj.Metadata.Name, k8sResourceMetadataObj.Kind, namespaceName)
}
}

return nil
}

func installGatewayAPI(ctx context.Context, kubernetesClientObj *kubernetes.KubernetesClient) error {
resp, err := http.Get(gatewayAPIInstallYamlURL)
if err != nil {
Expand Down
Loading

0 comments on commit 22ec3a1

Please sign in to comment.