From 201fbe544ef124331b6639f4b7199a274e60c9e8 Mon Sep 17 00:00:00 2001 From: lostbean Date: Tue, 1 Oct 2024 13:41:20 -0300 Subject: [PATCH 01/16] add golang linter config --- .golangci.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .golangci.yml diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..4ce7517 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,9 @@ +linters: + enable: + - exhaustruct + - exportloopref + - gomnd + - staticcheck + - exhaustive + max-issues-per-linter: 0 + sort-results: true From b555df00591f5ab7679e2b79869b6ffedbc6421a Mon Sep 17 00:00:00 2001 From: lostbean Date: Tue, 1 Oct 2024 13:46:55 -0300 Subject: [PATCH 02/16] use stateful sets --- kontrol-service/api/server.go | 89 +++++++++---- kontrol-service/database/tenant.go | 2 + kontrol-service/engine/docker.go | 118 ++++++++++++++++-- kontrol-service/engine/docker_test.go | 14 ++- kontrol-service/engine/flow/render.go | 63 +++++++++- kontrol-service/go.mod | 4 +- kontrol-service/go.sum | 8 +- kontrol-service/gomod2nix.toml | 8 +- kontrol-service/test/data.go | 19 ++- kontrol-service/topology/topology_test.go | 10 +- .../types/cluster_topology/resolved/core.go | 19 +-- kontrol-service/types/k8s.go | 1 + kontrol-service/types/kardinal.go | 42 ------- 13 files changed, 285 insertions(+), 112 deletions(-) delete mode 100644 kontrol-service/types/kardinal.go diff --git a/kontrol-service/api/server.go b/kontrol-service/api/server.go index 7800248..2452928 100644 --- a/kontrol-service/api/server.go +++ b/kontrol-service/api/server.go @@ -67,7 +67,7 @@ func (sv *Server) GetHealth(_ context.Context, _ api.GetHealthRequestObject) (ap } func (sv *Server) GetTenantUuidFlows(_ context.Context, request api.GetTenantUuidFlowsRequestObject) (api.GetTenantUuidFlowsResponseObject, error) { - clusterTopology, allFlows, _, _, _, _, _, err := getTenantTopologies(sv, request.Uuid) + clusterTopology, allFlows, _, _, _, _, _, _, _, err := getTenantTopologies(sv, request.Uuid) if err != nil { resourceType := "tenant" missing := api.NotFoundJSONResponse{ResourceType: resourceType, Id: request.Uuid} @@ -88,6 +88,16 @@ func (sv *Server) PostTenantUuidDeploy(_ context.Context, request api.PostTenant sv.analyticsWrapper.TrackEvent(EVENT_DEPLOY, request.Uuid) serviceConfigs := *request.Body.ServiceConfigs + deploymentConfigs := []apitypes.DeploymentConfig{} + if request.Body.DeploymentConfigs != nil { + deploymentConfigs = *request.Body.DeploymentConfigs + } + + statefulSetConfigs := []apitypes.StatefulSetConfig{} + if request.Body.StatefulSetConfigs != nil { + statefulSetConfigs = *request.Body.StatefulSetConfigs + } + ingressConfigs := []apitypes.IngressConfig{} if request.Body.IngressConfigs != nil { ingressConfigs = *request.Body.IngressConfigs @@ -110,7 +120,7 @@ func (sv *Server) PostTenantUuidDeploy(_ context.Context, request api.PostTenant } flowId := namespace - entries, err := applyProdOnlyFlow(sv, request.Uuid, serviceConfigs, ingressConfigs, gatewayConfigs, routesConfigs, namespace, flowId) + entries, err := applyProdOnlyFlow(sv, request.Uuid, serviceConfigs, deploymentConfigs, statefulSetConfigs, ingressConfigs, gatewayConfigs, routesConfigs, namespace, flowId) if err != nil { errMsg := fmt.Sprintf("An error occurred deploying flow '%v'", flowId) errResp := api.ErrorJSONResponse{ @@ -128,7 +138,7 @@ func (sv *Server) DeleteTenantUuidFlowFlowId(_ context.Context, request api.Dele logrus.Infof("deleting dev flow for tenant '%s'", request.Uuid) sv.analyticsWrapper.TrackEvent(EVENT_FLOW_DELETE, request.Uuid) - baseClusterTopology, allFlows, _, _, _, _, _, err := getTenantTopologies(sv, request.Uuid) + baseClusterTopology, allFlows, _, _, _, _, _, _, _, err := getTenantTopologies(sv, request.Uuid) if err != nil { resourceType := "tenant" missing := api.NotFoundJSONResponse{ResourceType: resourceType, Id: request.Uuid} @@ -213,7 +223,7 @@ func (sv *Server) PostTenantUuidFlowCreate(_ context.Context, request api.PostTe func (sv *Server) GetTenantUuidTopology(_ context.Context, request api.GetTenantUuidTopologyRequestObject) (api.GetTenantUuidTopologyResponseObject, error) { logrus.Infof("getting topology for tenant '%s'", request.Uuid) - clusterTopology, allFlows, _, _, _, _, _, err := getTenantTopologies(sv, request.Uuid) + clusterTopology, allFlows, _, _, _, _, _, _, _, err := getTenantTopologies(sv, request.Uuid) if err != nil { resourceType := "tenant" missing := api.NotFoundJSONResponse{ResourceType: resourceType, Id: request.Uuid} @@ -226,7 +236,7 @@ func (sv *Server) GetTenantUuidTopology(_ context.Context, request api.GetTenant } func (sv *Server) GetTenantUuidClusterResources(_ context.Context, request managerapi.GetTenantUuidClusterResourcesRequestObject) (managerapi.GetTenantUuidClusterResourcesResponseObject, error) { - clusterTopology, allFlows, _, _, _, _, _, err := getTenantTopologies(sv, request.Uuid) + clusterTopology, allFlows, _, _, _, _, _, _, _, err := getTenantTopologies(sv, request.Uuid) if err != nil { return nil, nil } @@ -240,7 +250,7 @@ func (sv *Server) GetTenantUuidClusterResources(_ context.Context, request manag func (sv *Server) GetTenantUuidManifest(_ context.Context, request api.GetTenantUuidManifestRequestObject) (api.GetTenantUuidManifestResponseObject, error) { logrus.Infof("generating manifest for tenant '%s'", request.Uuid) - clusterTopology, allFlows, _, _, _, _, _, err := getTenantTopologies(sv, request.Uuid) + clusterTopology, allFlows, _, _, _, _, _, _, _, err := getTenantTopologies(sv, request.Uuid) if err != nil { logrus.WithError(err).Errorf("An error occurred while getting topologys for tenant '%s'", request.Uuid) return nil, err @@ -338,7 +348,7 @@ func (sv *Server) GetTenantUuidManifest(_ context.Context, request api.GetTenant } func (sv *Server) GetTenantUuidTemplates(ctx context.Context, request api.GetTenantUuidTemplatesRequestObject) (api.GetTenantUuidTemplatesResponseObject, error) { - _, _, tenantTemplates, _, _, _, _, err := getTenantTopologies(sv, request.Uuid) + _, _, tenantTemplates, _, _, _, _, _, _, err := getTenantTopologies(sv, request.Uuid) if err != nil { resourceType := "tenant" missing := api.NotFoundJSONResponse{ResourceType: resourceType, Id: request.Uuid} @@ -358,7 +368,7 @@ func (sv *Server) DeleteTenantUuidTemplatesTemplateName(_ context.Context, reque tenantUuid := request.Uuid templateName := request.TemplateName - _, _, tenantTemplates, _, _, _, _, err := getTenantTopologies(sv, tenantUuid) + _, _, tenantTemplates, _, _, _, _, _, _, err := getTenantTopologies(sv, tenantUuid) if err != nil { resourceType := "tenant" missing := api.NotFoundJSONResponse{ResourceType: resourceType, Id: request.Uuid} @@ -391,7 +401,7 @@ func (sv *Server) PostTenantUuidTemplatesCreate(_ context.Context, request api.P templateOverrides := request.Body.Service templateId := getRandTemplateID() - _, _, tenantTemplates, _, _, _, _, err := getTenantTopologies(sv, tenantUuid) + _, _, tenantTemplates, _, _, _, _, _, _, err := getTenantTopologies(sv, tenantUuid) if err != nil { resourceType := "tenant" missing := api.NotFoundJSONResponse{ResourceType: resourceType, Id: request.Uuid} @@ -450,13 +460,15 @@ func applyProdOnlyFlow( sv *Server, tenantUuidStr string, serviceConfigs []apitypes.ServiceConfig, + deploymentConfigs []apitypes.DeploymentConfig, + statefulSetConfigs []apitypes.StatefulSetConfig, ingressConfigs []apitypes.IngressConfig, gatewayConfigs []apitypes.GatewayConfig, routeConfigs []apitypes.RouteConfig, namespace string, flowID string, ) ([]resolved.IngressAccessEntry, error) { - clusterTopology, err := engine.GenerateProdOnlyCluster(flowID, serviceConfigs, ingressConfigs, gatewayConfigs, routeConfigs, namespace) + clusterTopology, err := engine.GenerateProdOnlyCluster(flowID, serviceConfigs, deploymentConfigs, statefulSetConfigs, ingressConfigs, gatewayConfigs, routeConfigs, namespace) if err != nil { return nil, err } @@ -525,7 +537,7 @@ func applyProdDevFlow( logrus.Debugf("generating base cluster topology for tenant %s on flowID %s", tenantUuidStr, flowID) - baseTopology, _, tenantTemplates, serviceConfigs, ingressConfigs, gatewayConfigs, routeConfigs, err := getTenantTopologies(sv, tenantUuidStr) + baseTopology, _, tenantTemplates, serviceConfigs, deploymentConfigs, statefulSetConfigs, ingressConfigs, gatewayConfigs, routeConfigs, err := getTenantTopologies(sv, tenantUuidStr) if err != nil { return nil, nil, fmt.Errorf("no base cluster topology found for tenant %s, did you deploy the cluster?", tenantUuidStr) } @@ -543,7 +555,7 @@ func applyProdDevFlow( // the baseline flow ID uses the base cluster topology namespace name baselineFlowID := baseClusterTopologyMaybeWithTemplateOverrides.Namespace - baseClusterTopologyWithTemplateOverridesPtr, err := engine.GenerateProdOnlyCluster(baselineFlowID, serviceConfigs, ingressConfigs, gatewayConfigs, routeConfigs, baseTopology.Namespace) + baseClusterTopologyWithTemplateOverridesPtr, err := engine.GenerateProdOnlyCluster(baselineFlowID, serviceConfigs, deploymentConfigs, statefulSetConfigs, ingressConfigs, gatewayConfigs, routeConfigs, baseTopology.Namespace) if err != nil { return nil, nil, fmt.Errorf("an error occurred while creating base cluster topology from templates:\n %s", err) } @@ -587,15 +599,25 @@ func applyProdDevFlow( // - Base service configs // - Base ingress configs // TOOD: Could return a struct if it becomes too heavy to manipulate the return values. -func getTenantTopologies(sv *Server, tenantUuidStr string) (*resolved.ClusterTopology, map[string]resolved.ClusterTopology, map[string]templates.Template, []apitypes.ServiceConfig, []apitypes.IngressConfig, []apitypes.GatewayConfig, []apitypes.RouteConfig, error) { +func getTenantTopologies(sv *Server, tenantUuidStr string) (*resolved.ClusterTopology, + map[string]resolved.ClusterTopology, + map[string]templates.Template, + []apitypes.ServiceConfig, + []apitypes.DeploymentConfig, + []apitypes.StatefulSetConfig, + []apitypes.IngressConfig, + []apitypes.GatewayConfig, + []apitypes.RouteConfig, + error, +) { tenant, err := sv.db.GetTenant(tenantUuidStr) if err != nil { logrus.Errorf("an error occured while getting the tenant %s\n: '%v'", tenantUuidStr, err.Error()) - return nil, nil, nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, nil, nil, err } if tenant == nil { - return nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("Cannot find tenant %s", tenantUuidStr) + return nil, nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("Cannot find tenant %s", tenantUuidStr) } flows := map[string]resolved.ClusterTopology{} @@ -604,7 +626,7 @@ func getTenantTopologies(sv *Server, tenantUuidStr string) (*resolved.ClusterTop err := json.Unmarshal(flow.ClusterTopology, &clusterTopology) if err != nil { logrus.Errorf("An error occurred decoding the cluster topology for flow '%v'", flow.FlowId) - return nil, nil, nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, nil, nil, err } flows[flow.FlowId] = clusterTopology } @@ -615,7 +637,7 @@ func getTenantTopologies(sv *Server, tenantUuidStr string) (*resolved.ClusterTop err := json.Unmarshal(tenantTemplate.Body, &template) if err != nil { logrus.Errorf("An error occurred decoding the template body for template '%v'", tenantTemplate.Name) - return nil, nil, nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, nil, nil, err } tenantTemplates[tenantTemplate.Name] = template } @@ -625,7 +647,7 @@ func getTenantTopologies(sv *Server, tenantUuidStr string) (*resolved.ClusterTop err = json.Unmarshal(tenant.BaseClusterTopology, &baseClusterTopology) if err != nil { logrus.Errorf("An error occurred decoding the cluster topology for tenant '%v'", tenantUuidStr) - return nil, nil, nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, nil, nil, err } } else { baseClusterTopology.FlowID = defaultBaselineFlowId @@ -637,7 +659,25 @@ func getTenantTopologies(sv *Server, tenantUuidStr string) (*resolved.ClusterTop err = json.Unmarshal(tenant.ServiceConfigs, &serviceConfigs) if err != nil { logrus.Errorf("An error occurred decoding the service configs for tenant '%v'", tenantUuidStr) - return nil, nil, nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, nil, nil, err + } + } + + var deploymentConfigs []apitypes.DeploymentConfig + if tenant.DeploymentConfigs != nil { + err = json.Unmarshal(tenant.DeploymentConfigs, &deploymentConfigs) + if err != nil { + logrus.Errorf("An error occurred decoding the deployment configs for tenant '%v'", tenantUuidStr) + return nil, nil, nil, nil, nil, nil, nil, nil, nil, err + } + } + + var statefulSetConfigs []apitypes.StatefulSetConfig + if tenant.StatefulSetConfigs != nil { + err = json.Unmarshal(tenant.StatefulSetConfigs, &statefulSetConfigs) + if err != nil { + logrus.Errorf("An error occurred decoding the stateful set configs for tenant '%v'", tenantUuidStr) + return nil, nil, nil, nil, nil, nil, nil, nil, nil, err } } @@ -646,7 +686,7 @@ func getTenantTopologies(sv *Server, tenantUuidStr string) (*resolved.ClusterTop err = json.Unmarshal(tenant.IngressConfigs, &ingressConfigs) if err != nil { logrus.Errorf("An error occurred decoding the ingress configs for tenant '%v'", tenantUuidStr) - return nil, nil, nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, nil, nil, err } } @@ -655,7 +695,7 @@ func getTenantTopologies(sv *Server, tenantUuidStr string) (*resolved.ClusterTop err = json.Unmarshal(tenant.GatewayConfigs, &gatewayConfigs) if err != nil { logrus.Errorf("An error occurred decoding the gateway configs for tenant '%v'", tenantUuidStr) - return nil, nil, nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, nil, nil, err } } @@ -664,11 +704,11 @@ func getTenantTopologies(sv *Server, tenantUuidStr string) (*resolved.ClusterTop err = json.Unmarshal(tenant.RouteConfigs, &routeConfigs) if err != nil { logrus.Errorf("An error occurred decoding the route configs for tenant '%v'", tenantUuidStr) - return nil, nil, nil, nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, nil, nil, nil, nil, err } } - return &baseClusterTopology, flows, tenantTemplates, serviceConfigs, ingressConfigs, gatewayConfigs, routeConfigs, nil + return &baseClusterTopology, flows, tenantTemplates, serviceConfigs, deploymentConfigs, statefulSetConfigs, ingressConfigs, gatewayConfigs, routeConfigs, nil } func deleteTenantTopologies(sv *Server, tenantUuidStr string) error { @@ -718,8 +758,9 @@ func newClIAPITemplates(templates []templates.Template) []apitypes.Template { func newManagerAPIClusterResources(clusterResources types.ClusterResources) managerapitypes.ClusterResources { return managerapitypes.ClusterResources{ - Deployments: &clusterResources.Deployments, Services: &clusterResources.Services, + Deployments: &clusterResources.Deployments, + StatefulSets: &clusterResources.StatefulSets, VirtualServices: &clusterResources.VirtualServices, DestinationRules: &clusterResources.DestinationRules, Gateways: &clusterResources.Gateways, diff --git a/kontrol-service/database/tenant.go b/kontrol-service/database/tenant.go index d56a252..d320f2c 100644 --- a/kontrol-service/database/tenant.go +++ b/kontrol-service/database/tenant.go @@ -11,6 +11,8 @@ type Tenant struct { TenantId string `gorm:"uniqueIndex"` BaseClusterTopology datatypes.JSON ServiceConfigs datatypes.JSON + DeploymentConfigs datatypes.JSON + StatefulSetConfigs datatypes.JSON IngressConfigs datatypes.JSON GatewayConfigs datatypes.JSON RouteConfigs datatypes.JSON diff --git a/kontrol-service/engine/docker.go b/kontrol-service/engine/docker.go index d35ae61..8ca8b4a 100644 --- a/kontrol-service/engine/docker.go +++ b/kontrol-service/engine/docker.go @@ -2,15 +2,17 @@ package engine import ( "fmt" + "strings" + apitypes "github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api/api/golang/types" "github.com/kurtosis-tech/stacktrace" + "github.com/samber/lo" "github.com/sirupsen/logrus" "gopkg.in/yaml.v2" corev1 "k8s.io/api/core/v1" net "k8s.io/api/networking/v1" gateway "sigs.k8s.io/gateway-api/apis/v1" - "strings" "kardinal.kontrol-service/engine/flow" "kardinal.kontrol-service/plugins" @@ -21,12 +23,14 @@ import ( func GenerateProdOnlyCluster( flowID string, serviceConfigs []apitypes.ServiceConfig, + deploymentConfigs []apitypes.DeploymentConfig, + statefulSetConfigs []apitypes.StatefulSetConfig, ingressConfigs []apitypes.IngressConfig, gatewayConfigs []apitypes.GatewayConfig, routeConfigs []apitypes.RouteConfig, namespace string, ) (*resolved.ClusterTopology, error) { - clusterTopology, err := generateClusterTopology(serviceConfigs, ingressConfigs, gatewayConfigs, routeConfigs, namespace, flowID) + clusterTopology, err := generateClusterTopology(serviceConfigs, deploymentConfigs, statefulSetConfigs, ingressConfigs, gatewayConfigs, routeConfigs, namespace, flowID) if err != nil { return nil, stacktrace.Propagate(err, "An error occurred generating the cluster topology from the service configs") } @@ -72,6 +76,8 @@ func GenerateProdDevCluster(baseClusterTopologyMaybeWithTemplateOverrides *resol func generateClusterTopology( serviceConfigs []apitypes.ServiceConfig, + deploymentConfigs []apitypes.DeploymentConfig, + statefulSetConfig []apitypes.StatefulSetConfig, ingressConfigs []apitypes.IngressConfig, gatewayConfigs []apitypes.GatewayConfig, routeConfigs []apitypes.RouteConfig, @@ -80,7 +86,11 @@ func generateClusterTopology( ) (*resolved.ClusterTopology, error) { clusterTopologyGatewayAndRoutes := processGatewayAndRouteConfigs(gatewayConfigs, routeConfigs, version) clusterTopologyIngress := processIngressConfigs(ingressConfigs, version) - clusterTopologyServices, clusterTopologyServiceDependencies, err := processServiceConfigs(serviceConfigs, version) + clusterTopologyServices, clusterTopologyServiceDependencies, err := processServiceConfigs( + serviceConfigs, + deploymentConfigs, + statefulSetConfig, + version) if err != nil { return nil, stacktrace.NewError("an error occurred processing the service configs") } @@ -140,7 +150,60 @@ func processGatewayAndRouteConfigs(gatewayConfigs []apitypes.GatewayConfig, rout return gatewayAndRoutes } -func processServiceConfigs(serviceConfigs []apitypes.ServiceConfig, version string) ([]*resolved.Service, []resolved.ServiceDependency, error) { +func getDeploymentForService( + serviceConfig apitypes.ServiceConfig, + workloadConfigs []apitypes.DeploymentConfig, +) *apitypes.DeploymentConfig { + service := serviceConfig.Service + workload, foundworkload := lo.Find(workloadConfigs, func(workloadConfig apitypes.DeploymentConfig) bool { + deploymentLabels := workloadConfig.Deployment.GetLabels() + matchSelectors := true + for key, value := range service.Spec.Selector { + label, found := deploymentLabels[key] + if !found || value != label { + return false + } + } + return matchSelectors + }) + + if foundworkload { + return &workload + } + + return nil +} + +func getSatefulSetForService( + serviceConfig apitypes.ServiceConfig, + workloadConfigs []apitypes.StatefulSetConfig, +) *apitypes.StatefulSetConfig { + service := serviceConfig.Service + workload, foundworkload := lo.Find(workloadConfigs, func(workloadConfig apitypes.StatefulSetConfig) bool { + workloadLabel := workloadConfig.StatefulSet.GetLabels() + matchSelectors := true + for key, value := range service.Spec.Selector { + label, found := workloadLabel[key] + if !found || value != label { + return false + } + } + return matchSelectors + }) + + if foundworkload { + return &workload + } + + return nil +} + +func processServiceConfigs( + serviceConfigs []apitypes.ServiceConfig, + deploymentConfigs []apitypes.DeploymentConfig, + statefulSetConfigs []apitypes.StatefulSetConfig, + version string, +) ([]*resolved.Service, []resolved.ServiceDependency, error) { clusterTopologyServices := []*resolved.Service{} clusterTopologyServiceDependencies := []resolved.ServiceDependency{} externalServicesDependencies := []resolved.ServiceDependency{} @@ -157,7 +220,13 @@ func processServiceConfigs(serviceConfigs []apitypes.ServiceConfig, version stri // 1- Service logrus.Infof("Processing service: %v", service.GetObjectMeta().GetName()) - clusterTopologyService := newClusterTopologyServiceFromServiceConfig(serviceConfig, version) + + deploymentConfig := getDeploymentForService(serviceConfig, deploymentConfigs) + statefulSetConfig := getSatefulSetForService(serviceConfig, statefulSetConfigs) + clusterTopologyService, error := newClusterTopologyServiceFromServiceConfig(serviceConfig, deploymentConfig, statefulSetConfig, version) + if error != nil { + return nil, nil, stacktrace.Propagate(error, "An error occurred creating new cluster topology service from service config '%s'", service.Name) + } // 2- Service plugins serviceStatefulPlugins, externalServices, newExternalServicesDependencies, err := newStatefulPluginsAndExternalServicesFromServiceConfig(serviceConfig, version, &clusterTopologyService) @@ -259,17 +328,42 @@ func newStatefulPluginsAndExternalServicesFromServiceConfig(serviceConfig apityp return serviceStatefulPlugins, externalServices, externalServiceDependencies, nil } -func newClusterTopologyServiceFromServiceConfig(serviceConfig apitypes.ServiceConfig, version string) resolved.Service { +func newClusterTopologyServiceFromServiceConfig( + serviceConfig apitypes.ServiceConfig, + deploymentConfig *apitypes.DeploymentConfig, + statefulSetConfig *apitypes.StatefulSetConfig, + version string, +) (resolved.Service, error) { service := serviceConfig.Service - deployment := serviceConfig.Deployment + serviceName := service.GetObjectMeta().GetName() + + if deploymentConfig == nil && statefulSetConfig == nil { + logrus.Warnf("Service %s has no workload", serviceName) + } + + if deploymentConfig != nil && statefulSetConfig != nil { + workloads := []string{ + deploymentConfig.Deployment.GetObjectMeta().GetName(), + statefulSetConfig.StatefulSet.GetObjectMeta().GetName(), + } + logrus.Error("Service %s is associated with more than one workload: %v", serviceName, workloads) + } + serviceAnnotations := service.GetObjectMeta().GetAnnotations() clusterTopologyService := resolved.Service{ - ServiceID: service.GetObjectMeta().GetName(), - Version: version, - ServiceSpec: &service.Spec, - DeploymentSpec: &deployment.Spec, + ServiceID: service.GetObjectMeta().GetName(), + Version: version, + ServiceSpec: &service.Spec, } + + if deploymentConfig != nil { + clusterTopologyService.DeploymentSpec = &deploymentConfig.Deployment.Spec + } + if statefulSetConfig != nil { + clusterTopologyService.StatefulSetSpec = &statefulSetConfig.StatefulSet.Spec + } + isStateful, ok := serviceAnnotations["kardinal.dev.service/stateful"] if ok && isStateful == "true" { clusterTopologyService.IsStateful = true @@ -283,7 +377,7 @@ func newClusterTopologyServiceFromServiceConfig(serviceConfig apitypes.ServiceCo if ok && isShared == "true" { clusterTopologyService.IsShared = true } - return clusterTopologyService + return clusterTopologyService, nil } func getServiceAndPortFromClusterTopologyServices(serviceName string, servicePortName string, clusterTopologyServices []*resolved.Service) (*resolved.Service, *corev1.ServicePort, error) { diff --git a/kontrol-service/engine/docker_test.go b/kontrol-service/engine/docker_test.go index 5acb7bd..f14731e 100644 --- a/kontrol-service/engine/docker_test.go +++ b/kontrol-service/engine/docker_test.go @@ -10,14 +10,15 @@ import ( ) func TestServiceConfigsToClusterTopology(t *testing.T) { - testServiceConfigs := test.GetServiceConfigs() + testServiceConfigs, testDeploymentConfigs := test.GetServiceConfigs() testVersion := "prod" testNamespace := "prod" testIngressConfigs := test.GetIngressConfigs() testGatewayConfigs := []apitypes.GatewayConfig{} testRouteConfigs := []apitypes.RouteConfig{} - cluster, err := generateClusterTopology(testServiceConfigs, testIngressConfigs, testGatewayConfigs, testRouteConfigs, testVersion, testNamespace) + testStatefulSetConfigs := []apitypes.StatefulSetConfig{} + cluster, err := generateClusterTopology(testServiceConfigs, testDeploymentConfigs, testStatefulSetConfigs, testIngressConfigs, testGatewayConfigs, testRouteConfigs, testVersion, testNamespace) if err != nil { t.Errorf("Error generating cluster: %s", err) } @@ -29,14 +30,14 @@ func TestServiceConfigsToClusterTopology(t *testing.T) { statefulPlugin := redisProdService.StatefulPlugins[0] require.Equal(t, statefulPlugin.Name, "github.com/kardinaldev/redis-db-sidecar-plugin:36ed9a4") require.Equal(t, *redisProdService.ServiceSpec, testServiceConfigs[0].Service.Spec) - require.Equal(t, *redisProdService.DeploymentSpec, testServiceConfigs[0].Deployment.Spec) + require.Equal(t, *redisProdService.DeploymentSpec, testDeploymentConfigs[0].Deployment.Spec) votingAppUIService := cluster.Services[1] require.Equal(t, votingAppUIService.ServiceID, "voting-app-ui") require.Equal(t, votingAppUIService.IsExternal, false) require.Equal(t, votingAppUIService.IsStateful, false) require.Equal(t, *votingAppUIService.ServiceSpec, testServiceConfigs[1].Service.Spec) - require.Equal(t, *votingAppUIService.DeploymentSpec, testServiceConfigs[1].Deployment.Spec) + require.Equal(t, *votingAppUIService.DeploymentSpec, testDeploymentConfigs[1].Deployment.Spec) dependency := cluster.ServiceDependencies[0] require.Equal(t, dependency.Service, votingAppUIService) @@ -48,17 +49,18 @@ func TestServiceConfigsToClusterTopology(t *testing.T) { } func TestIngressConfigsTakePrecedenceOverK8sServicesActingAsIngresses(t *testing.T) { - testServiceConfigs := test.GetServiceConfigs() + testServiceConfigs, testDeploymentConfigs := test.GetServiceConfigs() // use an Ingress Config // this should take precedence over any Ingress defined elsewhere in the k8s manifest testIngressConfigs := test.GetIngressConfigs() testGatewayConfigs := []apitypes.GatewayConfig{} testRouteConfigs := []apitypes.RouteConfig{} + testStatefulSetConfigs := []apitypes.StatefulSetConfig{} testVersion := "prod" testNamespace := "prod" - cluster, err := generateClusterTopology(testServiceConfigs, testIngressConfigs, testGatewayConfigs, testRouteConfigs, testVersion, testNamespace) + cluster, err := generateClusterTopology(testServiceConfigs, testDeploymentConfigs, testStatefulSetConfigs, testIngressConfigs, testGatewayConfigs, testRouteConfigs, testVersion, testNamespace) if err != nil { t.Errorf("Error generating cluster: %s", err) } diff --git a/kontrol-service/engine/flow/render.go b/kontrol-service/engine/flow/render.go index 6646776..e66a936 100644 --- a/kontrol-service/engine/flow/render.go +++ b/kontrol-service/engine/flow/render.go @@ -117,10 +117,20 @@ func RenderClusterResources(clusterTopology *resolved.ClusterTopology, namespace Deployments: lo.FilterMap(clusterTopology.Services, func(service *resolved.Service, _ int) (appsv1.Deployment, bool) { // Deployment spec is nil for external services, don't need to add anything to cluster - if service.DeploymentSpec == nil { + deployment := getDeployment(service, namespace) + if deployment == nil { return appsv1.Deployment{}, false } - return *getDeployment(service, namespace), true + return *deployment, true + }), + + StatefulSets: lo.FilterMap(clusterTopology.Services, func(service *resolved.Service, _ int) (appsv1.StatefulSet, bool) { + // StatefulSet spec is nil for external services, don't need to add anything to cluster + statefulSet := getStatefulSet(service, namespace) + if statefulSet == nil { + return appsv1.StatefulSet{}, false + } + return *statefulSet, true }), Gateways: getGateways(clusterTopology.GatewayAndRoutes), @@ -300,7 +310,56 @@ func getService(service *resolved.Service, namespace string) *v1.Service { } } +func getStatefulSet(service *resolved.Service, namespace string) *appsv1.StatefulSet { + if service.StatefulSetSpec == nil { + return nil + } + + statefulSet := appsv1.StatefulSet{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "statefulSet", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-%s", service.ServiceID, service.Version), + Namespace: namespace, + Labels: map[string]string{ + "app": service.ServiceID, + "version": service.Version, + }, + }, + Spec: *service.StatefulSetSpec, + } + + numReplicas := int32(1) + statefulSet.Spec.Replicas = int32Ptr(numReplicas) + statefulSet.Spec.Selector = &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": service.ServiceID, + "version": service.Version, + }, + } + statefulSet.Spec.Template.ObjectMeta = metav1.ObjectMeta{ + Annotations: map[string]string{ + "sidecar.istio.io/inject": "true", + // TODO: make this a flag to help debugging + // One can view the logs with: kubeclt logs -f -l app= -n -c istio-proxy + "sidecar.istio.io/componentLogLevel": "lua:info", + }, + Labels: map[string]string{ + "app": service.ServiceID, + "version": service.Version, + }, + } + + return &statefulSet +} + func getDeployment(service *resolved.Service, namespace string) *appsv1.Deployment { + if service.DeploymentSpec == nil { + return nil + } + deployment := appsv1.Deployment{ TypeMeta: metav1.TypeMeta{ APIVersion: "apps/v1", diff --git a/kontrol-service/go.mod b/kontrol-service/go.mod index d02291e..7c3e793 100644 --- a/kontrol-service/go.mod +++ b/kontrol-service/go.mod @@ -7,8 +7,8 @@ toolchain go1.22.3 require ( github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/dominikbraun/graph v0.23.0 - github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240926004715-b5a991623aeb - github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240926004715-b5a991623aeb + github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240930193043-70ada6ebca1b + github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240930193043-70ada6ebca1b github.com/kurtosis-tech/stacktrace v0.0.0-20211028211901-1c67a77b5409 github.com/labstack/echo/v4 v4.12.0 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 diff --git a/kontrol-service/go.sum b/kontrol-service/go.sum index 0f8b270..a09fcd4 100644 --- a/kontrol-service/go.sum +++ b/kontrol-service/go.sum @@ -77,10 +77,10 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240926004715-b5a991623aeb h1:VVpES+F4ZLrvR6HnZ+vNOnaSt9J1OulYu6ITWFb+fmQ= -github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240926004715-b5a991623aeb/go.mod h1:dQ+ZYcpSrex3FlfyYAvGuhIFHim+oJuJvslNp8rwuFo= -github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240926004715-b5a991623aeb h1:rMT8EvgX+dFL0Aq2Ea1lBeIFxCPHPDSF59FktBnKhRs= -github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240926004715-b5a991623aeb/go.mod h1:uUIEjxgSYw58hJgD1AwGOBE3LGPwLDiYtNmLGmnO8vI= +github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240930193043-70ada6ebca1b h1:n/n0AsQpkXhslrfX4AVduzl6IlabOq7X5mKshjqplvw= +github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240930193043-70ada6ebca1b/go.mod h1:dQ+ZYcpSrex3FlfyYAvGuhIFHim+oJuJvslNp8rwuFo= +github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240930193043-70ada6ebca1b h1:VuCPQLRAzqMVQ7DUfxFuSv1LFk465PUsaQvdIvAxyQA= +github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240930193043-70ada6ebca1b/go.mod h1:uUIEjxgSYw58hJgD1AwGOBE3LGPwLDiYtNmLGmnO8vI= github.com/kurtosis-tech/stacktrace v0.0.0-20211028211901-1c67a77b5409 h1:YQTATifMUwZEtZYb0LVA7DK2pj8s71iY8rzweuUQ5+g= github.com/kurtosis-tech/stacktrace v0.0.0-20211028211901-1c67a77b5409/go.mod h1:y5weVs5d9wXXHcDA1awRxkIhhHC1xxYJN8a7aXnE6S8= github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0= diff --git a/kontrol-service/gomod2nix.toml b/kontrol-service/gomod2nix.toml index 3c031b1..3598b26 100644 --- a/kontrol-service/gomod2nix.toml +++ b/kontrol-service/gomod2nix.toml @@ -278,11 +278,11 @@ schema = 3 version = "v0.2.0" hash = "sha256-fadcWxZOORv44oak3jTxm6YcITcFxdGt4bpn869HxUE=" [mod."github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api"] - version = "v0.0.0-20240926004715-b5a991623aeb" - hash = "sha256-0IFdSzfoxYnA+0Dm1cVnlnx4eGXmCJwDVK67nd4Eipw=" + version = "v0.0.0-20240930193043-70ada6ebca1b" + hash = "sha256-v9p9lE0WLQvzpkdV9X13Mpfid/2P2EVrQf4Xn16qFq8=" [mod."github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api"] - version = "v0.0.0-20240926004715-b5a991623aeb" - hash = "sha256-u6fSYBRONpUBP/Mb9hWgzzlbcM0NQ6hROygvDn2tbBM=" + version = "v0.0.0-20240930193043-70ada6ebca1b" + hash = "sha256-jJPe/rGOg0G1D64rOWk303FF3+uYS5vHfs3lOXhR4tQ=" [mod."github.com/kurtosis-tech/stacktrace"] version = "v0.0.0-20211028211901-1c67a77b5409" hash = "sha256-xm9l7tlCb0U25WJvByFikWxnAmOwTmOtlSDBdbyDMMY=" diff --git a/kontrol-service/test/data.go b/kontrol-service/test/data.go index 22865f4..9478f00 100644 --- a/kontrol-service/test/data.go +++ b/kontrol-service/test/data.go @@ -39,8 +39,9 @@ func GetIngressConfigs() []apitypes.IngressConfig { } } -func GetServiceConfigs() []apitypes.ServiceConfig { +func GetServiceConfigs() ([]apitypes.ServiceConfig, []apitypes.DeploymentConfig) { serviceConfigs := []apitypes.ServiceConfig{} + deploymentConfigs := []apitypes.DeploymentConfig{} // Redis prod service allowEmpty := "yes" @@ -87,6 +88,9 @@ func GetServiceConfigs() []apitypes.ServiceConfig { }, }, }, + }) + + deploymentConfigs = append(deploymentConfigs, apitypes.DeploymentConfig{ Deployment: apps.Deployment{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", @@ -121,17 +125,17 @@ func GetServiceConfigs() []apitypes.ServiceConfig { Image: containerImage, ImagePullPolicy: "IfNotPresent", Env: []v1.EnvVar{ - v1.EnvVar{ + { Name: "ALLOW_EMPTY_PASSWORD", Value: allowEmpty, }, - v1.EnvVar{ + { Name: "REDIS_PORT_NUMBER", Value: portStr, }, }, Ports: []v1.ContainerPort{ - v1.ContainerPort{ + { Name: fmt.Sprintf("tcp-%d", port), ContainerPort: port, Protocol: v1.ProtocolTCP, @@ -182,6 +186,9 @@ func GetServiceConfigs() []apitypes.ServiceConfig { }, }, }, + }) + + deploymentConfigs = append(deploymentConfigs, apitypes.DeploymentConfig{ Deployment: apps.Deployment{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", @@ -216,7 +223,7 @@ func GetServiceConfigs() []apitypes.ServiceConfig { Image: containerImage, ImagePullPolicy: "IfNotPresent", Ports: []v1.ContainerPort{ - v1.ContainerPort{ + { Name: fmt.Sprintf("tcp-%d", port), ContainerPort: port, Protocol: v1.ProtocolTCP, @@ -266,5 +273,5 @@ func GetServiceConfigs() []apitypes.ServiceConfig { }, }) - return serviceConfigs + return serviceConfigs, deploymentConfigs } diff --git a/kontrol-service/topology/topology_test.go b/kontrol-service/topology/topology_test.go index 1602356..f8e4e59 100644 --- a/kontrol-service/topology/topology_test.go +++ b/kontrol-service/topology/topology_test.go @@ -19,6 +19,7 @@ import ( func TestServiceConfigsToTopology(t *testing.T) { testServiceConfigs := []apitypes.ServiceConfig{} + testDeploymentConfigs := []apitypes.DeploymentConfig{} // Redis prod service allowEmpty := "yes" @@ -56,6 +57,9 @@ func TestServiceConfigsToTopology(t *testing.T) { }, }, }, + }) + + testDeploymentConfigs = append(testDeploymentConfigs, apitypes.DeploymentConfig{ Deployment: apps.Deployment{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", @@ -151,6 +155,9 @@ func TestServiceConfigsToTopology(t *testing.T) { }, }, }, + }) + + testDeploymentConfigs = append(testDeploymentConfigs, apitypes.DeploymentConfig{ Deployment: apps.Deployment{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", @@ -240,7 +247,8 @@ func TestServiceConfigsToTopology(t *testing.T) { testGatewayConfigs := []apitypes.GatewayConfig{} testRouteConfigs := []apitypes.RouteConfig{} - clusterTopology, err := engine.GenerateProdOnlyCluster("prod", testServiceConfigs, testIngressConfigs, testGatewayConfigs, testRouteConfigs, "prod") + testStatefulSetConfigs := []apitypes.StatefulSetConfig{} + clusterTopology, err := engine.GenerateProdOnlyCluster("prod", testServiceConfigs, testDeploymentConfigs, testStatefulSetConfigs, testIngressConfigs, testGatewayConfigs, testRouteConfigs, "prod") if err != nil { t.Errorf("Error generating cluster: %s", err) return diff --git a/kontrol-service/types/cluster_topology/resolved/core.go b/kontrol-service/types/cluster_topology/resolved/core.go index 9045ec5..54d71b3 100644 --- a/kontrol-service/types/cluster_topology/resolved/core.go +++ b/kontrol-service/types/cluster_topology/resolved/core.go @@ -25,15 +25,16 @@ type ClusterTopology struct { } type Service struct { - ServiceID string `json:"serviceID"` - Version string `json:"version"` - ServiceSpec *corev1.ServiceSpec `json:"serviceSpec"` - DeploymentSpec *appsv1.DeploymentSpec `json:"deploymentSpec"` - IsExternal bool `json:"isExternal"` - IsStateful bool `json:"isStateful"` - StatefulPlugins []*StatefulPlugin `json:"statefulPlugins"` - IsShared bool `json:"isShared"` - OriginalVersionIfShared string `json:"originalVersionIfShared"` + ServiceID string `json:"serviceID"` + Version string `json:"version"` + ServiceSpec *corev1.ServiceSpec `json:"serviceSpec"` + DeploymentSpec *appsv1.DeploymentSpec `json:"deploymentSpec"` + StatefulSetSpec *appsv1.StatefulSetSpec `json:"statefulSetSpec"` + IsExternal bool `json:"isExternal"` + IsStateful bool `json:"isStateful"` + StatefulPlugins []*StatefulPlugin `json:"statefulPlugins"` + IsShared bool `json:"isShared"` + OriginalVersionIfShared string `json:"originalVersionIfShared"` } type ServiceHash string diff --git a/kontrol-service/types/k8s.go b/kontrol-service/types/k8s.go index 8fa4d40..97d21bc 100644 --- a/kontrol-service/types/k8s.go +++ b/kontrol-service/types/k8s.go @@ -20,6 +20,7 @@ const ( type ClusterResources struct { Services []corev1.Service `json:"services"` Deployments []appsv1.Deployment `json:"deployments"` + StatefulSets []appsv1.StatefulSet `json:"stateful_sets"` VirtualServices []v1alpha3.VirtualService `json:"virtualServices"` DestinationRules []v1alpha3.DestinationRule `json:"destinationRules"` EnvoyFilters []v1alpha3.EnvoyFilter `json:"envoy_filters"` diff --git a/kontrol-service/types/kardinal.go b/kontrol-service/types/kardinal.go deleted file mode 100644 index d88d411..0000000 --- a/kontrol-service/types/kardinal.go +++ /dev/null @@ -1,42 +0,0 @@ -package types - -import ( - apitypes "github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api/api/golang/types" - net "k8s.io/api/networking/v1" - gateway "sigs.k8s.io/gateway-api/apis/v1" -) - -type Traffic struct { - HasMirroring bool - MirrorPercentage uint - MirrorToVersion string - Routes []*gateway.HTTPRoute - Gateways []*gateway.Gateway - Ingresses []*net.Ingress -} - -// TODO: Needs to: 1) Validate/restrict version and name, 2) assume just on port on TCP -// TODO: Remove dup ports and name -type ServiceSpec struct { - Version string - Name string - Port int32 - TargetPort int32 - Config apitypes.ServiceConfig -} - -type NamespaceSpec struct { - Name string -} - -type ServiceDependency struct { - OriginService *ServiceSpec - DestinationService *ServiceSpec -} - -type Cluster struct { - Services []*ServiceSpec - ServiceDependencies []*ServiceDependency - TrafficSource Traffic - Namespace NamespaceSpec -} From 9651760101ecaab8962d93a9b3b9e703809ad783 Mon Sep 17 00:00:00 2001 From: lostbean Date: Wed, 2 Oct 2024 13:30:59 -0300 Subject: [PATCH 03/16] combine workloads --- kontrol-service/api/server.go | 4 +- kontrol-service/engine/docker.go | 33 ++++--- kontrol-service/engine/docker_test.go | 4 +- kontrol-service/engine/flow/dev_flow.go | 30 ++++--- kontrol-service/engine/flow/dev_flow_test.go | 88 +++++++++---------- kontrol-service/engine/flow/render.go | 8 +- kontrol-service/plugins/mock_github.go | 24 +++-- kontrol-service/plugins/plugins.go | 48 +++++----- kontrol-service/plugins/plugins_test.go | 23 ++--- kontrol-service/topology/toplogy.go | 5 +- kontrol-service/topology/topology_test.go | 13 ++- .../types/cluster_topology/resolved/core.go | 27 +++--- .../cluster_topology/resolved/core_test.go | 18 ++-- kontrol-service/types/flow_spec/resolved.go | 6 +- kontrol-service/types/kardinal/workload.go | 53 +++++++++++ .../types/kardinal/workload_spec.go | 77 ++++++++++++++++ 16 files changed, 304 insertions(+), 157 deletions(-) create mode 100644 kontrol-service/types/kardinal/workload.go create mode 100644 kontrol-service/types/kardinal/workload_spec.go diff --git a/kontrol-service/api/server.go b/kontrol-service/api/server.go index 2452928..0d9db90 100644 --- a/kontrol-service/api/server.go +++ b/kontrol-service/api/server.go @@ -505,14 +505,14 @@ func applyProdOnlyFlow( logrus.Errorf("an error occured while encoding the gateway configs for tenant %s, error was \n: '%v'", tenantUuidStr, err.Error()) return nil, err } - tenant.IngressConfigs = gatewayConfigsJson + tenant.GatewayConfigs = gatewayConfigsJson routeConfigsJson, err := json.Marshal(routeConfigs) if err != nil { logrus.Errorf("an error occured while encoding the ingress configs for tenant %s, error was \n: '%v'", tenantUuidStr, err.Error()) return nil, err } - tenant.IngressConfigs = routeConfigsJson + tenant.RouteConfigs = routeConfigsJson err = sv.db.SaveTenant(tenant) if err != nil { diff --git a/kontrol-service/engine/docker.go b/kontrol-service/engine/docker.go index 8ca8b4a..e575f0c 100644 --- a/kontrol-service/engine/docker.go +++ b/kontrol-service/engine/docker.go @@ -18,6 +18,7 @@ import ( "kardinal.kontrol-service/plugins" "kardinal.kontrol-service/types/cluster_topology/resolved" "kardinal.kontrol-service/types/flow_spec" + kardinal "kardinal.kontrol-service/types/kardinal" ) func GenerateProdOnlyCluster( @@ -46,18 +47,16 @@ func GenerateProdDevCluster(baseClusterTopologyMaybeWithTemplateOverrides *resol if err != nil { return nil, stacktrace.Propagate(err, "Service with UUID %s not found", devServiceName) } - if devService.DeploymentSpec == nil { - return nil, stacktrace.NewError("Service with UUID %s has no DeploymentSpec", devServiceName) - } - deploymentSpec := flow.DeepCopyDeploymentSpec(devService.DeploymentSpec) + workloadSpec := devService.WorkloadSpec + clonedWorkloadSpec := workloadSpec.DeepCopy() // TODO: find a better way to update deploymentSpec, this assumes there is only container in the pod - deploymentSpec.Template.Spec.Containers[0].Image = item.Image + clonedWorkloadSpec.GetTemplateSpec().Containers[0].Image = item.Image patches = append(patches, flow_spec.ServicePatch{ - Service: devServiceName, - DeploymentSpec: deploymentSpec, + Service: devServiceName, + WorkloadSpec: &clonedWorkloadSpec, }) } @@ -303,11 +302,11 @@ func newStatefulPluginsAndExternalServicesFromServiceConfig(serviceConfig apityp serviceName = fmt.Sprintf("%v:%v", serviceID, "external") } externalService := resolved.Service{ - ServiceID: serviceName, - Version: version, - ServiceSpec: nil, // leave empty for now - DeploymentSpec: nil, // leave empty for now - IsExternal: true, + ServiceID: serviceName, + Version: version, + ServiceSpec: nil, // leave empty for now + WorkloadSpec: nil, // leave empty for now + IsExternal: true, // external services can definitely be stateful but for now treat external and stateful services as mutually exclusive to make plugin logic easier to handle IsStateful: false, } @@ -358,10 +357,16 @@ func newClusterTopologyServiceFromServiceConfig( } if deploymentConfig != nil { - clusterTopologyService.DeploymentSpec = &deploymentConfig.Deployment.Spec + workload := kardinal.NewDeploymentWorkloadSpec(deploymentConfig.Deployment.Spec) + clusterTopologyService.WorkloadSpec = &workload } if statefulSetConfig != nil { - clusterTopologyService.StatefulSetSpec = &statefulSetConfig.StatefulSet.Spec + workload := kardinal.NewStatefulSetWorkloadSpec(statefulSetConfig.StatefulSet.Spec) + clusterTopologyService.WorkloadSpec = &workload + } + + if clusterTopologyService.WorkloadSpec == nil { + return clusterTopologyService, stacktrace.NewError("Service %s has no workload", serviceName) } isStateful, ok := serviceAnnotations["kardinal.dev.service/stateful"] diff --git a/kontrol-service/engine/docker_test.go b/kontrol-service/engine/docker_test.go index f14731e..3d3602d 100644 --- a/kontrol-service/engine/docker_test.go +++ b/kontrol-service/engine/docker_test.go @@ -30,14 +30,14 @@ func TestServiceConfigsToClusterTopology(t *testing.T) { statefulPlugin := redisProdService.StatefulPlugins[0] require.Equal(t, statefulPlugin.Name, "github.com/kardinaldev/redis-db-sidecar-plugin:36ed9a4") require.Equal(t, *redisProdService.ServiceSpec, testServiceConfigs[0].Service.Spec) - require.Equal(t, *redisProdService.DeploymentSpec, testDeploymentConfigs[0].Deployment.Spec) + require.Equal(t, *redisProdService.WorkloadSpec.GetTemplateSpec(), testDeploymentConfigs[0].Deployment.Spec.Template.Spec) votingAppUIService := cluster.Services[1] require.Equal(t, votingAppUIService.ServiceID, "voting-app-ui") require.Equal(t, votingAppUIService.IsExternal, false) require.Equal(t, votingAppUIService.IsStateful, false) require.Equal(t, *votingAppUIService.ServiceSpec, testServiceConfigs[1].Service.Spec) - require.Equal(t, *votingAppUIService.DeploymentSpec, testDeploymentConfigs[1].Deployment.Spec) + require.Equal(t, *votingAppUIService.WorkloadSpec.GetTemplateSpec(), testDeploymentConfigs[1].Deployment.Spec.Template.Spec) dependency := cluster.ServiceDependencies[0] require.Equal(t, dependency.Service, votingAppUIService) diff --git a/kontrol-service/engine/flow/dev_flow.go b/kontrol-service/engine/flow/dev_flow.go index a4ff802..9527665 100644 --- a/kontrol-service/engine/flow/dev_flow.go +++ b/kontrol-service/engine/flow/dev_flow.go @@ -14,8 +14,7 @@ import ( "kardinal.kontrol-service/plugins" "kardinal.kontrol-service/types/cluster_topology/resolved" "kardinal.kontrol-service/types/flow_spec" - - v1 "k8s.io/api/apps/v1" + kardinal "kardinal.kontrol-service/types/kardinal" ) // CreateDevFlow creates a dev flow from the given topologies @@ -56,7 +55,7 @@ func CreateDevFlow( if err != nil { return nil, err } - _, err = applyPatch(pluginRunner, topologyRef, clusterGraph, flowID, targetService, servicePatch.DeploymentSpec) + _, err = applyPatch(pluginRunner, topologyRef, clusterGraph, flowID, targetService, servicePatch.WorkloadSpec) if err != nil { return nil, err } @@ -66,7 +65,6 @@ func CreateDevFlow( baselineFlowVersion := baseTopology.Namespace // Replace "baseline" version services with baseTopology versions for i, service := range topologyRef.Services { - if service.Version == baselineFlowVersion { prodService, err := baseTopology.GetService(service.ServiceID) if err != nil { @@ -147,7 +145,7 @@ func applyPatch( clusterGraph graph.Graph[resolved.ServiceHash, *resolved.Service], flowID string, targetService *resolved.Service, - deploymentSpec *v1.DeploymentSpec, + workloadSpec *kardinal.WorkloadSpec, ) (*resolved.ClusterTopology, error) { // Find downstream stateful services statefulPaths := findAllDownstreamStatefulPaths(targetService, clusterGraph, topology) @@ -206,7 +204,7 @@ func applyPatch( } modifiedTargetService := DeepCopyService(targetService) - modifiedTargetService.DeploymentSpec = deploymentSpec + modifiedTargetService.WorkloadSpec = workloadSpec modifiedTargetService.Version = flowID err := topology.UpdateWithService(modifiedTargetService) if err != nil { @@ -225,7 +223,7 @@ func applyPatch( } // Apply a chain of stateful plugins to the stateful service - resultSpec := DeepCopyDeploymentSpec(modifiedService.DeploymentSpec) + resultSpec := modifiedService.WorkloadSpec.DeepCopy() for pluginIdx, plugin := range modifiedService.StatefulPlugins { if plugin.Type == "external" { // we handle external plugins above @@ -234,15 +232,15 @@ func applyPatch( } logrus.Infof("Applying plugin %s for service %s with flow id %s", plugin.Name, modifiedService.ServiceID, flowID) pluginId := plugins.GetPluginId(flowID, modifiedService.ServiceID, pluginIdx) - spec, _, err := pluginRunner.CreateFlow(plugin.Name, *modifiedService.ServiceSpec, *resultSpec, pluginId, plugin.Args) + spec, _, err := pluginRunner.CreateFlow(plugin.Name, *modifiedService.ServiceSpec, resultSpec, pluginId, plugin.Args) if err != nil { return nil, fmt.Errorf("error creating flow for service %s: %v", modifiedService.ServiceID, err) } - resultSpec = &spec + resultSpec = spec } // Update service with final deployment spec - modifiedService.DeploymentSpec = resultSpec + modifiedService.WorkloadSpec = &resultSpec topology.Services[serviceIdx] = modifiedService topology.UpdateDependencies(service, modifiedService) @@ -322,14 +320,22 @@ func applyExternalServicePlugin( return nil } + if dependentService.ServiceSpec == nil { + return stacktrace.NewError("Dependent service '%v' does not have a service spec", dependentService.ServiceID) + } + + if dependentService.WorkloadSpec == nil { + return stacktrace.NewError("Dependent service '%v' does not have a workload spec", dependentService.ServiceID) + } + logrus.Infof("Calling external service '%v' plugin with parent service '%v'...", externalService.ServiceID, dependentService.ServiceID) pluginId := plugins.GetPluginId(flowId, dependentService.ServiceID, pluginIdx) - spec, _, err := pluginRunner.CreateFlow(externalServicePlugin.Name, *dependentService.ServiceSpec, *dependentService.DeploymentSpec, pluginId, externalServicePlugin.Args) + spec, _, err := pluginRunner.CreateFlow(externalServicePlugin.Name, *dependentService.ServiceSpec, *dependentService.WorkloadSpec, pluginId, externalServicePlugin.Args) if err != nil { return stacktrace.Propagate(err, "error creating flow for external service '%s'", externalService.ServiceID) } - dependentService.DeploymentSpec = &spec + dependentService.WorkloadSpec = &spec return nil } diff --git a/kontrol-service/engine/flow/dev_flow_test.go b/kontrol-service/engine/flow/dev_flow_test.go index 45504e9..6fa52a1 100644 --- a/kontrol-service/engine/flow/dev_flow_test.go +++ b/kontrol-service/engine/flow/dev_flow_test.go @@ -9,17 +9,17 @@ import ( "github.com/samber/lo" "github.com/stretchr/testify/require" - appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" netv1 "k8s.io/api/networking/v1" "kardinal.kontrol-service/types/cluster_topology/resolved" "kardinal.kontrol-service/types/flow_spec" + kardinal "kardinal.kontrol-service/types/kardinal" ) const dummyPluginName = "https://github.com/h4ck3rk3y/identity-plugin.git" func clusterTopologyExample() resolved.ClusterTopology { - dummySpec := &appsv1.DeploymentSpec{} + dummySpec := &kardinal.WorkloadSpec{} testPlugins := []*resolved.StatefulPlugin{ { Name: dummyPluginName, @@ -42,9 +42,9 @@ func clusterTopologyExample() resolved.ClusterTopology { "app": "frontend", }, }, - DeploymentSpec: dummySpec, - IsExternal: false, - IsStateful: false, + WorkloadSpec: dummySpec, + IsExternal: false, + IsStateful: false, StatefulPlugins: []*resolved.StatefulPlugin{ { Name: dummyPluginName, @@ -69,9 +69,9 @@ func clusterTopologyExample() resolved.ClusterTopology { "app": "cartservice", }, }, - DeploymentSpec: dummySpec, - IsExternal: false, - IsStateful: false, + WorkloadSpec: dummySpec, + IsExternal: false, + IsStateful: false, StatefulPlugins: []*resolved.StatefulPlugin{ { Name: dummyPluginName, @@ -96,9 +96,9 @@ func clusterTopologyExample() resolved.ClusterTopology { "app": "productcatalogservice", }, }, - DeploymentSpec: dummySpec, - IsExternal: false, - IsStateful: false, + WorkloadSpec: dummySpec, + IsExternal: false, + IsStateful: false, } paymentService := resolved.Service{ @@ -115,7 +115,7 @@ func clusterTopologyExample() resolved.ClusterTopology { "app": "paymentservice", }, }, - DeploymentSpec: dummySpec, + WorkloadSpec: dummySpec, IsExternal: false, IsStateful: true, StatefulPlugins: testPlugins, @@ -135,7 +135,7 @@ func clusterTopologyExample() resolved.ClusterTopology { "app": "shippingservice", }, }, - DeploymentSpec: dummySpec, + WorkloadSpec: dummySpec, IsExternal: false, IsStateful: true, StatefulPlugins: testPlugins, @@ -155,9 +155,9 @@ func clusterTopologyExample() resolved.ClusterTopology { "app": "checkoutservice", }, }, - DeploymentSpec: dummySpec, - IsExternal: false, - IsStateful: false, + WorkloadSpec: dummySpec, + IsExternal: false, + IsStateful: false, } recommendationService := resolved.Service{ @@ -174,9 +174,9 @@ func clusterTopologyExample() resolved.ClusterTopology { "app": "recommendationservice", }, }, - DeploymentSpec: dummySpec, - IsExternal: false, - IsStateful: false, + WorkloadSpec: dummySpec, + IsExternal: false, + IsStateful: false, } redisService := resolved.Service{ @@ -192,7 +192,7 @@ func clusterTopologyExample() resolved.ClusterTopology { "app": "redis", }, }, - DeploymentSpec: dummySpec, + WorkloadSpec: dummySpec, IsExternal: false, IsStateful: true, StatefulPlugins: testPlugins, @@ -202,7 +202,7 @@ func clusterTopologyExample() resolved.ClusterTopology { neonService := resolved.Service{ ServiceID: "neon-postgres-db", ServiceSpec: nil, - DeploymentSpec: nil, + WorkloadSpec: nil, IsExternal: true, IsStateful: false, // neon is technically stateful but right now IsExternal and IsStateful are mutually exclusive StatefulPlugins: nil, @@ -211,7 +211,7 @@ func clusterTopologyExample() resolved.ClusterTopology { freeCurrencyApiService := resolved.Service{ ServiceID: "free-currency-api", ServiceSpec: nil, - DeploymentSpec: nil, + WorkloadSpec: nil, IsExternal: true, IsStateful: false, StatefulPlugins: nil, @@ -377,7 +377,7 @@ func clusterTopologyExample() resolved.ClusterTopology { } func getNewOBDClusterTopologyExample() resolved.ClusterTopology { - dummySpec := &appsv1.DeploymentSpec{} + dummySpec := &kardinal.WorkloadSpec{} httpProtocol := "HTTP" // Create services @@ -395,9 +395,9 @@ func getNewOBDClusterTopologyExample() resolved.ClusterTopology { "app": "frontend", }, }, - DeploymentSpec: dummySpec, - IsExternal: false, - IsStateful: false, + WorkloadSpec: dummySpec, + IsExternal: false, + IsStateful: false, StatefulPlugins: []*resolved.StatefulPlugin{ { Name: dummyPluginName, @@ -422,9 +422,9 @@ func getNewOBDClusterTopologyExample() resolved.ClusterTopology { "app": "cartservice", }, }, - DeploymentSpec: dummySpec, - IsExternal: false, - IsStateful: false, + WorkloadSpec: dummySpec, + IsExternal: false, + IsStateful: false, StatefulPlugins: []*resolved.StatefulPlugin{ { Name: dummyPluginName, @@ -449,9 +449,9 @@ func getNewOBDClusterTopologyExample() resolved.ClusterTopology { "app": "productcatalogservice", }, }, - DeploymentSpec: dummySpec, - IsExternal: false, - IsStateful: false, + WorkloadSpec: dummySpec, + IsExternal: false, + IsStateful: false, } postgresService := resolved.Service{ @@ -467,15 +467,15 @@ func getNewOBDClusterTopologyExample() resolved.ClusterTopology { "app": "postgres", }, }, - DeploymentSpec: dummySpec, - IsExternal: false, - IsStateful: true, + WorkloadSpec: dummySpec, + IsExternal: false, + IsStateful: true, } jsdeliverAPIPluginService := resolved.Service{ ServiceID: "jsdelivr-api", ServiceSpec: nil, - DeploymentSpec: nil, + WorkloadSpec: nil, IsExternal: true, IsStateful: false, StatefulPlugins: nil, @@ -710,8 +710,8 @@ func TestDevFlowImmutability(t *testing.T) { FlowId: "dev-flow-1", ServicePatches: []flow_spec.ServicePatch{ { - Service: "checkoutservice", - DeploymentSpec: checkoutservice.DeploymentSpec, + Service: "checkoutservice", + WorkloadSpec: checkoutservice.WorkloadSpec, }, }, } @@ -761,8 +761,8 @@ func TestFlowMerging(t *testing.T) { FlowId: "dev-flow-1", ServicePatches: []flow_spec.ServicePatch{ { - Service: "checkoutservice", - DeploymentSpec: checkoutservice.DeploymentSpec, + Service: "checkoutservice", + WorkloadSpec: checkoutservice.WorkloadSpec, }, }, } @@ -800,8 +800,8 @@ func TestExternalServicesFlowOnDependentService(t *testing.T) { FlowId: "dev-flow-1", ServicePatches: []flow_spec.ServicePatch{ { - Service: "cartservice", - DeploymentSpec: cartservice.DeploymentSpec, + Service: "cartservice", + WorkloadSpec: cartservice.WorkloadSpec, }, }, } @@ -833,8 +833,8 @@ func TestExternalServicesCreateDevFlowOnNotDependentService(t *testing.T) { FlowId: "dev-flow-1", ServicePatches: []flow_spec.ServicePatch{ { - Service: "frontend", - DeploymentSpec: frontend.DeploymentSpec, + Service: "frontend", + WorkloadSpec: frontend.WorkloadSpec, }, }, } diff --git a/kontrol-service/engine/flow/render.go b/kontrol-service/engine/flow/render.go index e66a936..eebdbc7 100644 --- a/kontrol-service/engine/flow/render.go +++ b/kontrol-service/engine/flow/render.go @@ -311,7 +311,7 @@ func getService(service *resolved.Service, namespace string) *v1.Service { } func getStatefulSet(service *resolved.Service, namespace string) *appsv1.StatefulSet { - if service.StatefulSetSpec == nil { + if !service.WorkloadSpec.IsStatefulSet() { return nil } @@ -328,7 +328,7 @@ func getStatefulSet(service *resolved.Service, namespace string) *appsv1.Statefu "version": service.Version, }, }, - Spec: *service.StatefulSetSpec, + Spec: *service.WorkloadSpec.GetStatefulSetSpec(), } numReplicas := int32(1) @@ -356,7 +356,7 @@ func getStatefulSet(service *resolved.Service, namespace string) *appsv1.Statefu } func getDeployment(service *resolved.Service, namespace string) *appsv1.Deployment { - if service.DeploymentSpec == nil { + if !service.WorkloadSpec.IsDeployment() { return nil } @@ -373,7 +373,7 @@ func getDeployment(service *resolved.Service, namespace string) *appsv1.Deployme "version": service.Version, }, }, - Spec: *service.DeploymentSpec, + Spec: *service.WorkloadSpec.GetDeploymentSpec(), } numReplicas := int32(1) diff --git a/kontrol-service/plugins/mock_github.go b/kontrol-service/plugins/mock_github.go index 9aa464b..51bba52 100644 --- a/kontrol-service/plugins/mock_github.go +++ b/kontrol-service/plugins/mock_github.go @@ -5,17 +5,15 @@ var MockGitHub = map[string]map[string]string{ "https://github.com/h4ck3rk3y/a-test-plugin.git": { "main.py": `REPLACED = "the-text-has-been-replaced" -def create_flow(service_spec, deployment_spec, flow_uuid, text_to_replace): - deployment_spec['template']['metadata']['labels']['app'] = deployment_spec['template']['metadata']['labels']['app'].replace(text_to_replace, REPLACED) - deployment_spec['selector']['matchLabels']['app'] = deployment_spec['selector']['matchLabels']['app'].replace(text_to_replace, REPLACED) - deployment_spec['template']['spec']['containers'][0]['name'] = deployment_spec['template']['spec']['containers'][0]['name'].replace(text_to_replace, REPLACED) +def create_flow(service_spec, pod_spec, flow_uuid, text_to_replace): + pod_spec['containers'][0]['name'] = pod_spec['containers'][0]['name'].replace(text_to_replace, REPLACED) config_map = { "original_text": text_to_replace } return { - "deployment_spec": deployment_spec, + "pod_spec": pod_spec, "config_map": config_map } @@ -28,7 +26,7 @@ def delete_flow(config_map, flow_uuid): "main.py": `import json import requests -def create_flow(service_spec, deployment_spec, flow_uuid): +def create_flow(service_spec, pod_spec, flow_uuid): response = requests.get("https://4.ident.me") if response.status_code != 200: raise Exception("An unexpected error occurred") @@ -36,7 +34,7 @@ def create_flow(service_spec, deployment_spec, flow_uuid): ip_address = response.text.strip() # Replace the IP address in the environment variable - for container in deployment_spec['template']['spec']['containers']: + for container in pod_spec['containers']: for env in container['env']: if env['name'] == 'REDIS': env['value'] = ip_address @@ -46,7 +44,7 @@ def create_flow(service_spec, deployment_spec, flow_uuid): } return { - "deployment_spec": deployment_spec, + "pod_spec": pod_spec, "config_map": config_map } @@ -57,9 +55,9 @@ def delete_flow(config_map, flow_uuid): }, // Identity Plugin "https://github.com/h4ck3rk3y/identity-plugin.git": { - "main.py": `def create_flow(service_spec, deployment_spec, flow_uuid): + "main.py": `def create_flow(service_spec, pod_spec, flow_uuid): return { - "deployment_spec": deployment_spec, + "pod_spec": pod_spec, "config_map": {} } @@ -69,10 +67,10 @@ def delete_flow(config_map, flow_uuid): }, // Redis sidecar plugin "https://github.com/h4ck3rk3y/redis-sidecar-plugin.git": { - "main.py": `def create_flow(service_spec, deployment_spec, flow_uuid): - deployment_spec['template']['spec']['containers'][0]["image"] = "kurtosistech/redis-proxy-overlay:latest" + "main.py": `def create_flow(service_spec, pod_spec, flow_uuid): + pod_spec['containers'][0]["image"] = "kurtosistech/redis-proxy-overlay:latest" return { - "deployment_spec": deployment_spec, + "pod_spec": pod_spec, "config_map": {} } diff --git a/kontrol-service/plugins/plugins.go b/kontrol-service/plugins/plugins.go index eb64a8b..7d38266 100644 --- a/kontrol-service/plugins/plugins.go +++ b/kontrol-service/plugins/plugins.go @@ -11,9 +11,9 @@ import ( "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" "kardinal.kontrol-service/database" - - appv1 "k8s.io/api/apps/v1" + kardinal "kardinal.kontrol-service/types/kardinal" ) const ( @@ -37,58 +37,66 @@ func NewPluginRunner(gitPluginProvider GitPluginProvider, tenantId string, db *d } } -func (pr *PluginRunner) CreateFlow(pluginUrl string, serviceSpec corev1.ServiceSpec, deploymentSpec appv1.DeploymentSpec, flowUuid string, arguments map[string]string) (appv1.DeploymentSpec, string, error) { +func (pr *PluginRunner) CreateFlow(pluginUrl string, serviceSpec corev1.ServiceSpec, originalWorkloadSpec kardinal.WorkloadSpec, flowUuid string, arguments map[string]string) (kardinal.WorkloadSpec, string, error) { + workloadSpec := originalWorkloadSpec.DeepCopy() + repoPath, err := pr.getOrCloneRepo(pluginUrl) if err != nil { - return appv1.DeploymentSpec{}, "", fmt.Errorf("failed to get or clone repository: %v", err) + return workloadSpec, "", fmt.Errorf("failed to get or clone repository: %v", err) } serviceSpecJSON, err := json.Marshal(serviceSpec) if err != nil { - return appv1.DeploymentSpec{}, "", fmt.Errorf("failed to marshal service spec: %v", err) + return workloadSpec, "", fmt.Errorf("failed to marshal service spec: %v", err) } - deploymentSpecJSON, err := json.Marshal(deploymentSpec) + deploymentSpecJSON, err := json.Marshal(workloadSpec.GetTemplateSpec()) if err != nil { - return appv1.DeploymentSpec{}, "", fmt.Errorf("failed to marshal deployment spec: %v", err) + return workloadSpec, "", fmt.Errorf("failed to marshal deployment spec: %v", err) } result, err := runPythonCreateFlow(repoPath, string(serviceSpecJSON), string(deploymentSpecJSON), flowUuid, arguments) if err != nil { - return appv1.DeploymentSpec{}, "", err + return workloadSpec, "", err } var resultMap map[string]json.RawMessage err = json.Unmarshal([]byte(result), &resultMap) if err != nil { - return appv1.DeploymentSpec{}, "", fmt.Errorf("failed to parse result: %v", err) + return workloadSpec, "", fmt.Errorf("failed to parse result: %v", err) } - var newDeploymentSpec appv1.DeploymentSpec - err = json.Unmarshal(resultMap["deployment_spec"], &newDeploymentSpec) - if err != nil { - return appv1.DeploymentSpec{}, "", fmt.Errorf("failed to unmarshal deployment spec: %v", err) + if resultMap["pod_spec"] == nil { + logrus.Warnf("No pod_spec found in plugin result") + } else { + var newDeploymentSpec v1.PodSpec + err = json.Unmarshal(resultMap["pod_spec"], &newDeploymentSpec) + if err != nil { + logrus.Errorf("Failed to unmarshal pod spec: %v", string(resultMap["pod_spec"])) + return workloadSpec, "", fmt.Errorf("failed to unmarshal deployment spec: %v", err) + } + workloadSpec.UpdateTemplateSpec(newDeploymentSpec) } configMapJSON := resultMap["config_map"] var configMap map[string]interface{} err = json.Unmarshal(configMapJSON, &configMap) if err != nil { - return appv1.DeploymentSpec{}, "", fmt.Errorf("invalid config map: %v", err) + return workloadSpec, "", fmt.Errorf("invalid config map: %v", err) } configMapBytes, err := json.Marshal(configMap) if err != nil { - return appv1.DeploymentSpec{}, "", fmt.Errorf("failed to re-marshal config map: %v", err) + return workloadSpec, "", fmt.Errorf("failed to re-marshal config map: %v", err) } logrus.Infof("Storing config map for plugin called with uuid '%v':\n %s\n...", flowUuid, string(configMapBytes)) _, err = pr.db.CreatePluginConfig(flowUuid, string(configMapBytes), pr.tenantId) if err != nil { - return appv1.DeploymentSpec{}, "", fmt.Errorf("failed to store the config map: %v", err) + return workloadSpec, "", fmt.Errorf("failed to store the config map: %v", err) } - return newDeploymentSpec, string(configMapBytes), nil + return workloadSpec, string(configMapBytes), nil } func (pr *PluginRunner) DeleteFlow(pluginUrl, flowUuid string, arguments map[string]string) error { @@ -171,7 +179,7 @@ sys.path.append("%s") import main service_spec = json.loads('''%s''') -deployment_spec = json.loads('''%s''') +pod_spec = json.loads('''%s''') flow_uuid = %q args_json = base64.b64decode('%s').decode('utf-8') args = json.loads(args_json) @@ -184,8 +192,8 @@ kwargs = {} for param in sig.parameters.values(): if param.name == 'service_spec': kwargs['service_spec'] = service_spec - elif param.name == 'deployment_spec': - kwargs['deployment_spec'] = deployment_spec + elif param.name == 'pod_spec': + kwargs['pod_spec'] = pod_spec elif param.name == 'flow_uuid': kwargs['flow_uuid'] = flow_uuid elif param.name in args: diff --git a/kontrol-service/plugins/plugins_test.go b/kontrol-service/plugins/plugins_test.go index 5200156..661cc71 100644 --- a/kontrol-service/plugins/plugins_test.go +++ b/kontrol-service/plugins/plugins_test.go @@ -9,6 +9,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "kardinal.kontrol-service/database" + kardinal "kardinal.kontrol-service/types/kardinal" ) const ( @@ -56,6 +57,8 @@ var deploymentSpec = appv1.DeploymentSpec{ }, } +var workloadSpec = kardinal.NewDeploymentWorkloadSpec(deploymentSpec) + func getPluginRunner(t *testing.T) (*PluginRunner, func() error) { db, cleanUpDbFunc, err := database.NewSQLiteDB() require.NoError(t, err) @@ -81,13 +84,11 @@ func TestSimplePlugin(t *testing.T) { "text_to_replace": "helloworld", } - updatedDeploymentSpec, configMap, err := runner.CreateFlow(simplePlugin, serviceSpec, deploymentSpec, flowUuid, arguments) + updatedDeploymentSpec, configMap, err := runner.CreateFlow(simplePlugin, serviceSpec, workloadSpec, flowUuid, arguments) require.NoError(t, err) // Check if the deployment spec was updated correctly - require.Equal(t, "the-text-has-been-replaced", updatedDeploymentSpec.Template.Labels["app"]) - require.Equal(t, "the-text-has-been-replaced", updatedDeploymentSpec.Selector.MatchLabels["app"]) - require.Equal(t, "the-text-has-been-replaced", updatedDeploymentSpec.Template.Spec.Containers[0].Name) + require.Equal(t, "the-text-has-been-replaced", updatedDeploymentSpec.GetTemplateSpec().Containers[0].Name) // Verify the config map var configMapData map[string]interface{} @@ -108,11 +109,11 @@ func TestIdentityPlugin(t *testing.T) { runner, cleanUpDbFunc := getPluginRunner(t) defer cleanUpDbFunc() - updatedServiceSpec, configMap, err := runner.CreateFlow(identityPlugin, serviceSpec, deploymentSpec, flowUuid, map[string]string{}) + updatedServiceSpec, configMap, err := runner.CreateFlow(identityPlugin, serviceSpec, workloadSpec, flowUuid, map[string]string{}) require.NoError(t, err) // Check if the deployment spec was updated correctly - require.Equal(t, deploymentSpec, updatedServiceSpec) + require.Equal(t, workloadSpec, updatedServiceSpec) // Verify the config map var configMapData map[string]interface{} @@ -133,12 +134,12 @@ func TestComplexPlugin(t *testing.T) { runner, cleanUpDbFunc := getPluginRunner(t) defer cleanUpDbFunc() - updatedServiceSpec, configMap, err := runner.CreateFlow(complexPlugin, serviceSpec, deploymentSpec, flowUuid, map[string]string{}) + updatedServiceSpec, configMap, err := runner.CreateFlow(complexPlugin, serviceSpec, workloadSpec, flowUuid, map[string]string{}) require.NoError(t, err) // Check if the deployment spec was updated correctly - require.NotEqual(t, "ip_addr", updatedServiceSpec.Template.Spec.Containers[0].Env[0].Value) - require.Regexp(t, `\b(?:\d{1,3}\.){3}\d{1,3}\b`, updatedServiceSpec.Template.Spec.Containers[0].Env[0].Value) + require.NotEqual(t, "ip_addr", updatedServiceSpec.GetTemplateSpec().Containers[0].Env[0].Value) + require.Regexp(t, `\b(?:\d{1,3}\.){3}\d{1,3}\b`, updatedServiceSpec.GetTemplateSpec().Containers[0].Env[0].Value) // Verify the config map var configMapData map[string]interface{} @@ -159,11 +160,11 @@ func TestRedisPluginTest(t *testing.T) { runner, cleanUpDbFunc := getPluginRunner(t) defer cleanUpDbFunc() - updatedServiceSpec, configMap, err := runner.CreateFlow(redisPlugin, serviceSpec, deploymentSpec, flowUuid, map[string]string{}) + updatedServiceSpec, configMap, err := runner.CreateFlow(redisPlugin, serviceSpec, workloadSpec, flowUuid, map[string]string{}) require.NoError(t, err) // Check if the deployment spec was updated correctly - require.Equal(t, "kurtosistech/redis-proxy-overlay:latest", updatedServiceSpec.Template.Spec.Containers[0].Image) + require.Equal(t, "kurtosistech/redis-proxy-overlay:latest", updatedServiceSpec.GetTemplateSpec().Containers[0].Image) // Verify the config map var configMapData map[string]interface{} diff --git a/kontrol-service/topology/toplogy.go b/kontrol-service/topology/toplogy.go index 88d33bf..3647648 100644 --- a/kontrol-service/topology/toplogy.go +++ b/kontrol-service/topology/toplogy.go @@ -31,8 +31,9 @@ func ClusterTopology(clusterTopology *resolved.ClusterTopology, flowsClusterTopo label := key versions := lo.Map(services, func(service *resolved.Service, _ int) apiTypes.NodeVersion { var imageTag *string - if service.DeploymentSpec != nil { - imageTag = &service.DeploymentSpec.Template.Spec.Containers[0].Image + containers := service.WorkloadSpec.GetTemplateSpec().Containers + if containers != nil && len(containers) > 0 { + imageTag = &containers[0].Image } isBaseline := service.Version == clusterTopology.Namespace return apiTypes.NodeVersion{ diff --git a/kontrol-service/topology/topology_test.go b/kontrol-service/topology/topology_test.go index f8e4e59..312a53d 100644 --- a/kontrol-service/topology/topology_test.go +++ b/kontrol-service/topology/topology_test.go @@ -261,14 +261,11 @@ func TestServiceConfigsToTopology(t *testing.T) { if service == nil { panic("Service is nil") } - if service.DeploymentSpec == nil { - panic("DeploymentSpec is nil: " + service.ServiceID) - } - if len(service.DeploymentSpec.Template.Spec.Containers) == 0 { + if len(service.WorkloadSpec.GetTemplateSpec().Containers) == 0 { panic("DeploymentSpec is empty: " + service.ServiceID) } - image := service.DeploymentSpec.Template.Spec.Containers[0].Image - service.DeploymentSpec.Template.Spec.Containers[0].Image = fmt.Sprintf("%s.a", image) + image := service.WorkloadSpec.GetTemplateSpec().Containers[0].Image + service.WorkloadSpec.GetTemplateSpec().Containers[0].Image = fmt.Sprintf("%s.a", image) } clusterTopologyFlowB := deepcopy.Copy(*clusterTopology).(resolved.ClusterTopology) @@ -276,8 +273,8 @@ func TestServiceConfigsToTopology(t *testing.T) { clusterTopologyFlowB.FlowID = flowID for _, service := range clusterTopologyFlowB.Services { service.Version = flowID - image := service.DeploymentSpec.Template.Spec.Containers[0].Image - service.DeploymentSpec.Template.Spec.Containers[0].Image = fmt.Sprintf("%s.b", image) + image := service.WorkloadSpec.GetTemplateSpec().Containers[0].Image + service.WorkloadSpec.GetTemplateSpec().Containers[0].Image = fmt.Sprintf("%s.b", image) } allFlows := []resolved.ClusterTopology{} allFlows = append(allFlows, clusterTopologyFlowA, clusterTopologyFlowB) diff --git a/kontrol-service/types/cluster_topology/resolved/core.go b/kontrol-service/types/cluster_topology/resolved/core.go index 54d71b3..4c7a8c2 100644 --- a/kontrol-service/types/cluster_topology/resolved/core.go +++ b/kontrol-service/types/cluster_topology/resolved/core.go @@ -9,9 +9,9 @@ import ( "github.com/kurtosis-tech/stacktrace" "github.com/mohae/deepcopy" - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" net "k8s.io/api/networking/v1" + kardinal "kardinal.kontrol-service/types/kardinal" gateway "sigs.k8s.io/gateway-api/apis/v1" ) @@ -25,16 +25,15 @@ type ClusterTopology struct { } type Service struct { - ServiceID string `json:"serviceID"` - Version string `json:"version"` - ServiceSpec *corev1.ServiceSpec `json:"serviceSpec"` - DeploymentSpec *appsv1.DeploymentSpec `json:"deploymentSpec"` - StatefulSetSpec *appsv1.StatefulSetSpec `json:"statefulSetSpec"` - IsExternal bool `json:"isExternal"` - IsStateful bool `json:"isStateful"` - StatefulPlugins []*StatefulPlugin `json:"statefulPlugins"` - IsShared bool `json:"isShared"` - OriginalVersionIfShared string `json:"originalVersionIfShared"` + ServiceID string `json:"serviceID"` + Version string `json:"version"` + ServiceSpec *corev1.ServiceSpec `json:"serviceSpec"` + WorkloadSpec *kardinal.WorkloadSpec `json:"workloadSpec"` + IsExternal bool `json:"isExternal"` + IsStateful bool `json:"isStateful"` + StatefulPlugins []*StatefulPlugin `json:"statefulPlugins"` + IsShared bool `json:"isShared"` + OriginalVersionIfShared string `json:"originalVersionIfShared"` } type ServiceHash string @@ -236,10 +235,8 @@ func (service *Service) Hash() ServiceHash { h.Write(serviceSpecJSON) } - if service.DeploymentSpec != nil { - deploymentSpecJSON, _ := json.Marshal(service.DeploymentSpec) - h.Write(deploymentSpecJSON) - } + deploymentSpecJSON, _ := json.Marshal(service.WorkloadSpec) + h.Write(deploymentSpecJSON) // Handle slice of StatefulPlugin if service.StatefulPlugins != nil { diff --git a/kontrol-service/types/cluster_topology/resolved/core_test.go b/kontrol-service/types/cluster_topology/resolved/core_test.go index 1fc1207..9b5e792 100644 --- a/kontrol-service/types/cluster_topology/resolved/core_test.go +++ b/kontrol-service/types/cluster_topology/resolved/core_test.go @@ -1,16 +1,20 @@ package resolved import ( + "testing" + "github.com/stretchr/testify/assert" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - "testing" + kardinal "kardinal.kontrol-service/types/kardinal" ) const dummyPluginName = "https://github.com/h4ck3rk3y/identity-plugin.git" -var httpProtocol = "HTTP" -var dummySpec = &appsv1.DeploymentSpec{} +var ( + httpProtocol = "HTTP" + dummySpec = &appsv1.DeploymentSpec{} +) func TestHashFunc(t *testing.T) { feSer1 := createService() @@ -20,7 +24,7 @@ func TestHashFunc(t *testing.T) { } func createService() *Service { - + workloadSpec := kardinal.NewDeploymentWorkloadSpec(appsv1.DeploymentSpec{}) return &Service{ ServiceID: "frontend", ServiceSpec: &corev1.ServiceSpec{ @@ -35,9 +39,9 @@ func createService() *Service { "app": "frontend", }, }, - DeploymentSpec: dummySpec, - IsExternal: false, - IsStateful: false, + WorkloadSpec: &workloadSpec, + IsExternal: false, + IsStateful: false, StatefulPlugins: []*StatefulPlugin{ { Name: dummyPluginName, diff --git a/kontrol-service/types/flow_spec/resolved.go b/kontrol-service/types/flow_spec/resolved.go index 9268e78..d782b78 100644 --- a/kontrol-service/types/flow_spec/resolved.go +++ b/kontrol-service/types/flow_spec/resolved.go @@ -1,6 +1,6 @@ package flow_spec -import v1 "k8s.io/api/apps/v1" +import kardinal "kardinal.kontrol-service/types/kardinal" type FlowPatch struct { FlowId string @@ -8,6 +8,6 @@ type FlowPatch struct { } type ServicePatch struct { - Service string - DeploymentSpec *v1.DeploymentSpec + Service string + WorkloadSpec *kardinal.WorkloadSpec } diff --git a/kontrol-service/types/kardinal/workload.go b/kontrol-service/types/kardinal/workload.go new file mode 100644 index 0000000..5d3be28 --- /dev/null +++ b/kontrol-service/types/kardinal/workload.go @@ -0,0 +1,53 @@ +package types + +import ( + appsv1 "k8s.io/api/apps/v1" + v1 "k8s.io/api/core/v1" +) + +type Workload struct { + Deployment *appsv1.Deployment `json:"deployment"` + StatefulSet *appsv1.StatefulSet `json:"stateful_set"` +} + +func (w *Workload) IsStatefulSet() bool { + return w.StatefulSet != nil +} + +func (w *Workload) IsDeployment() bool { + return w.Deployment != nil +} + +func (w *Workload) GetDeployments() *appsv1.Deployment { + return w.Deployment +} + +func (w *Workload) GetStatefulSet() *appsv1.StatefulSet { + return w.StatefulSet +} + +func NewDeploymentWorkload(deployment *appsv1.Deployment) Workload { + return Workload{ + Deployment: deployment, + } +} + +func NewStatefulSetWorkload(statefulSet *appsv1.StatefulSet) Workload { + return Workload{ + StatefulSet: statefulSet, + } +} + +func (w *Workload) DeepCopy() Workload { + if w.IsDeployment() { + return NewDeploymentWorkload(w.GetDeployments().DeepCopy()) + } + return NewStatefulSetWorkload(w.GetStatefulSet().DeepCopy()) +} + +func (w *Workload) GetTemplateSpec() v1.PodSpec { + if w.IsDeployment() { + return w.GetDeployments().Spec.Template.Spec + } + return w.GetStatefulSet().Spec.Template.Spec +} diff --git a/kontrol-service/types/kardinal/workload_spec.go b/kontrol-service/types/kardinal/workload_spec.go new file mode 100644 index 0000000..5152cad --- /dev/null +++ b/kontrol-service/types/kardinal/workload_spec.go @@ -0,0 +1,77 @@ +package types + +import ( + appsv1 "k8s.io/api/apps/v1" + v1 "k8s.io/api/core/v1" +) + +type WorkloadSpec struct { + DeploymentSpec *appsv1.DeploymentSpec `json:"deployment_spec"` + StatefulSetSpec *appsv1.StatefulSetSpec `json:"stateful_set_spec"` +} + +func (w *WorkloadSpec) IsStatefulSet() bool { + return w != nil && w.StatefulSetSpec != nil +} + +func (w *WorkloadSpec) IsDeployment() bool { + return w != nil && w.DeploymentSpec != nil +} + +func (w *WorkloadSpec) GetDeploymentSpec() *appsv1.DeploymentSpec { + return w.DeploymentSpec +} + +func (w *WorkloadSpec) GetStatefulSetSpec() *appsv1.StatefulSetSpec { + return w.StatefulSetSpec +} + +func NewDeploymentWorkloadSpec(spec appsv1.DeploymentSpec) WorkloadSpec { + return WorkloadSpec{ + DeploymentSpec: &spec, + } +} + +func NewStatefulSetWorkloadSpec(spec appsv1.StatefulSetSpec) WorkloadSpec { + return WorkloadSpec{ + StatefulSetSpec: &spec, + } +} + +func (w *Workload) WorkloadSpec() WorkloadSpec { + if w.IsDeployment() { + return NewDeploymentWorkloadSpec(w.GetDeployments().Spec) + } else if w.IsStatefulSet() { + return NewStatefulSetWorkloadSpec(w.GetStatefulSet().Spec) + } + + return WorkloadSpec{} +} + +func (w *WorkloadSpec) DeepCopy() WorkloadSpec { + if w.IsDeployment() { + return NewDeploymentWorkloadSpec(*w.GetDeploymentSpec().DeepCopy()) + } else if w.IsStatefulSet() { + return NewStatefulSetWorkloadSpec(*w.GetStatefulSetSpec().DeepCopy()) + } + + return WorkloadSpec{} +} + +func (w *WorkloadSpec) GetTemplateSpec() *v1.PodSpec { + if w.IsDeployment() { + return &w.GetDeploymentSpec().Template.Spec + } else if w.IsStatefulSet() { + return &w.GetStatefulSetSpec().Template.Spec + } + + return nil +} + +func (w *WorkloadSpec) UpdateTemplateSpec(spec v1.PodSpec) { + if w.IsDeployment() { + w.GetDeploymentSpec().Template.Spec = spec + } else if w.IsStatefulSet() { + w.GetStatefulSetSpec().Template.Spec = spec + } +} From 09ce770fec34e65605b0dc3eafd870171fc95219 Mon Sep 17 00:00:00 2001 From: lostbean Date: Wed, 2 Oct 2024 14:02:38 -0300 Subject: [PATCH 04/16] update kardinal in flake --- flake.lock | 8 ++++---- flake.nix | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/flake.lock b/flake.lock index bf46a8d..17c3a16 100644 --- a/flake.lock +++ b/flake.lock @@ -91,16 +91,16 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1727311635, - "narHash": "sha256-Q+Yi0v6eRPaEQzij5mcLJMnNfhPGVdWHfPq11jl46i0=", + "lastModified": 1727887180, + "narHash": "sha256-wG066JPIYqCx9MBLg23s8ynH5YihOOf+y3u4JIIqdNc=", "owner": "kurtosis-tech", "repo": "kardinal", - "rev": "b5a991623aebf5a49cbd96e740d873e493564f34", + "rev": "0d4cf56200c22b4c5b2e60bccbb5499a84b3c291", "type": "github" }, "original": { "owner": "kurtosis-tech", - "ref": "b5a991623aeb", + "ref": "0d4cf56200c2", "repo": "kardinal", "type": "github" } diff --git a/flake.nix b/flake.nix index da0ecf3..3000506 100644 --- a/flake.nix +++ b/flake.nix @@ -5,7 +5,7 @@ gomod2nix.url = "github:nix-community/gomod2nix"; gomod2nix.inputs.nixpkgs.follows = "nixpkgs"; gomod2nix.inputs.flake-utils.follows = "flake-utils"; - kardinal.url = "github:kurtosis-tech/kardinal/b5a991623aeb"; + kardinal.url = "github:kurtosis-tech/kardinal/0d4cf56200c2"; }; outputs = { self, From 7a8ca03c7bd6d02effcb1d0b128099aa2771bb23 Mon Sep 17 00:00:00 2001 From: lostbean Date: Wed, 2 Oct 2024 14:18:06 -0300 Subject: [PATCH 05/16] fix after merge --- kontrol-service/api/server.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kontrol-service/api/server.go b/kontrol-service/api/server.go index d8e795e..23195ee 100644 --- a/kontrol-service/api/server.go +++ b/kontrol-service/api/server.go @@ -245,10 +245,9 @@ func (sv *Server) PostTenantUuidFlowCreate(_ context.Context, request api.PostTe } func (sv *Server) checkOrCreateFlowID(tenantUuid apitypes.Uuid, requestFlowId *string) (string, bool, error) { - var flowIdAlreadyExist bool - clusterTopology, allFlows, _, _, _, _, _, err := getTenantTopologies(sv, tenantUuid) + clusterTopology, allFlows, _, _, _, _, _, _, _, err := getTenantTopologies(sv, tenantUuid) if err != nil { return "", flowIdAlreadyExist, err } @@ -590,7 +589,6 @@ func applyProdDevFlow( patches []flow_spec.ServicePatchSpec, templateSpec *apitypes.TemplateSpec, ) ([]resolved.IngressAccessEntry, error) { - logrus.Debugf("generating base cluster topology for tenant %s on flowID %s", tenantUuidStr, flowID) baseTopology, _, tenantTemplates, serviceConfigs, deploymentConfigs, statefulSetConfigs, ingressConfigs, gatewayConfigs, routeConfigs, err := getTenantTopologies(sv, tenantUuidStr) From 4aa64cec7298f7aac9e23bd7ad632e4f50801fc2 Mon Sep 17 00:00:00 2001 From: lostbean Date: Wed, 2 Oct 2024 14:48:30 -0300 Subject: [PATCH 06/16] check nil spec --- kontrol-service/topology/toplogy.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kontrol-service/topology/toplogy.go b/kontrol-service/topology/toplogy.go index 3647648..c589199 100644 --- a/kontrol-service/topology/toplogy.go +++ b/kontrol-service/topology/toplogy.go @@ -31,9 +31,9 @@ func ClusterTopology(clusterTopology *resolved.ClusterTopology, flowsClusterTopo label := key versions := lo.Map(services, func(service *resolved.Service, _ int) apiTypes.NodeVersion { var imageTag *string - containers := service.WorkloadSpec.GetTemplateSpec().Containers - if containers != nil && len(containers) > 0 { - imageTag = &containers[0].Image + podSpec := service.WorkloadSpec.GetTemplateSpec() + if podSpec != nil && len(podSpec.Containers) > 0 { + imageTag = &podSpec.Containers[0].Image } isBaseline := service.Version == clusterTopology.Namespace return apiTypes.NodeVersion{ From 7637e121207181dfb106c4fbc4cf9358d222f9dd Mon Sep 17 00:00:00 2001 From: lostbean Date: Wed, 2 Oct 2024 15:35:04 -0300 Subject: [PATCH 07/16] temporary: use forked plugin repo --- ci/obd-demo.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/obd-demo.yaml b/ci/obd-demo.yaml index 0ecad13..bafefc1 100644 --- a/ci/obd-demo.yaml +++ b/ci/obd-demo.yaml @@ -144,7 +144,7 @@ metadata: annotations: kardinal.dev.service/dependencies: "productcatalogservice:http,cartservice:http" kardinal.dev.service/plugins: | - - name: https://github.com/kurtosis-tech/free-currency-api-plugin.git + - name: https://github.com/lostbean/free-currency-api-plugin.git type: external servicename: free-currency-api args: @@ -211,7 +211,7 @@ metadata: annotations: kardinal.dev.service/stateful: "true" kardinal.dev.service/plugins: | - - name: github.com/kurtosis-tech/postgres-seed-plugin + - name: github.com/lostbean/postgres-seed-plugin args: seed_script: | -- create the table From 27c2d0beb9afbd927b43aaabf3cb7d0e754a7c7c Mon Sep 17 00:00:00 2001 From: lostbean Date: Wed, 2 Oct 2024 19:47:55 -0300 Subject: [PATCH 08/16] fix deployment and statefulset storage --- kontrol-service/api/server.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/kontrol-service/api/server.go b/kontrol-service/api/server.go index 23195ee..6ce2b1d 100644 --- a/kontrol-service/api/server.go +++ b/kontrol-service/api/server.go @@ -549,6 +549,20 @@ func applyProdOnlyFlow( } tenant.ServiceConfigs = serviceConfigsJson + deploymentConfigsJson, err := json.Marshal(deploymentConfigs) + if err != nil { + logrus.Errorf("an error occured while encoding the deployment configs for tenant %s, error was \n: '%v'", tenantUuidStr, err.Error()) + return nil, err + } + tenant.DeploymentConfigs = deploymentConfigsJson + + statefulSetConfigsJson, err := json.Marshal(statefulSetConfigs) + if err != nil { + logrus.Errorf("an error occured while encoding the stateful set configs for tenant %s, error was \n: '%v'", tenantUuidStr, err.Error()) + return nil, err + } + tenant.StatefulSetConfigs = statefulSetConfigsJson + ingressConfigsJson, err := json.Marshal(ingressConfigs) if err != nil { logrus.Errorf("an error occured while encoding the ingress configs for tenant %s, error was \n: '%v'", tenantUuidStr, err.Error()) @@ -774,6 +788,8 @@ func deleteTenantTopologies(sv *Server, tenantUuidStr string) error { tenant.BaseClusterTopology = nil tenant.ServiceConfigs = nil + tenant.DeploymentConfigs = nil + tenant.StatefulSetConfigs = nil tenant.IngressConfigs = nil err = sv.db.SaveTenant(tenant) From 4e601e85eab47728acd1c6a82b8652c043676753 Mon Sep 17 00:00:00 2001 From: lostbean Date: Wed, 2 Oct 2024 20:04:27 -0300 Subject: [PATCH 09/16] set StatefulSet workloads as stateful services by default --- kontrol-service/engine/docker.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kontrol-service/engine/docker.go b/kontrol-service/engine/docker.go index e575f0c..40a546c 100644 --- a/kontrol-service/engine/docker.go +++ b/kontrol-service/engine/docker.go @@ -369,10 +369,18 @@ func newClusterTopologyServiceFromServiceConfig( return clusterTopologyService, stacktrace.NewError("Service %s has no workload", serviceName) } + // Set default for IsStateful to true if the workload is a StatefulSet, otherwise false + clusterTopologyService.IsExternal = clusterTopologyService.WorkloadSpec.IsStatefulSet() + + // Override the IsStateful value by manual annotations isStateful, ok := serviceAnnotations["kardinal.dev.service/stateful"] if ok && isStateful == "true" { clusterTopologyService.IsStateful = true } + if ok && isStateful == "false" { + clusterTopologyService.IsStateful = false + } + isExternal, ok := serviceAnnotations["kardinal.dev.service/external"] if ok && isExternal == "true" { clusterTopologyService.IsExternal = true From b5a83b3769d4587b0eaf69d99c6eb044c3cddb33 Mon Sep 17 00:00:00 2001 From: lostbean Date: Thu, 3 Oct 2024 10:50:38 -0300 Subject: [PATCH 10/16] fix comments --- kontrol-service/engine/docker.go | 41 +++++++++++---------------- kontrol-service/engine/flow/render.go | 2 +- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/kontrol-service/engine/docker.go b/kontrol-service/engine/docker.go index 40a546c..80238a0 100644 --- a/kontrol-service/engine/docker.go +++ b/kontrol-service/engine/docker.go @@ -151,19 +151,18 @@ func processGatewayAndRouteConfigs(gatewayConfigs []apitypes.GatewayConfig, rout func getDeploymentForService( serviceConfig apitypes.ServiceConfig, - workloadConfigs []apitypes.DeploymentConfig, + deploymentConfigs []apitypes.DeploymentConfig, ) *apitypes.DeploymentConfig { service := serviceConfig.Service - workload, foundworkload := lo.Find(workloadConfigs, func(workloadConfig apitypes.DeploymentConfig) bool { + workload, foundworkload := lo.Find(deploymentConfigs, func(workloadConfig apitypes.DeploymentConfig) bool { deploymentLabels := workloadConfig.Deployment.GetLabels() - matchSelectors := true for key, value := range service.Spec.Selector { label, found := deploymentLabels[key] if !found || value != label { return false } } - return matchSelectors + return true }) if foundworkload { @@ -175,19 +174,18 @@ func getDeploymentForService( func getSatefulSetForService( serviceConfig apitypes.ServiceConfig, - workloadConfigs []apitypes.StatefulSetConfig, + statefulSetConfigs []apitypes.StatefulSetConfig, ) *apitypes.StatefulSetConfig { service := serviceConfig.Service - workload, foundworkload := lo.Find(workloadConfigs, func(workloadConfig apitypes.StatefulSetConfig) bool { + workload, foundworkload := lo.Find(statefulSetConfigs, func(workloadConfig apitypes.StatefulSetConfig) bool { workloadLabel := workloadConfig.StatefulSet.GetLabels() - matchSelectors := true for key, value := range service.Spec.Selector { label, found := workloadLabel[key] if !found || value != label { return false } } - return matchSelectors + return true }) if foundworkload { @@ -222,7 +220,7 @@ func processServiceConfigs( deploymentConfig := getDeploymentForService(serviceConfig, deploymentConfigs) statefulSetConfig := getSatefulSetForService(serviceConfig, statefulSetConfigs) - clusterTopologyService, error := newClusterTopologyServiceFromServiceConfig(serviceConfig, deploymentConfig, statefulSetConfig, version) + clusterTopologyService, error := newClusterTopologyServiceFromConfigs(serviceConfig, deploymentConfig, statefulSetConfig, version) if error != nil { return nil, nil, stacktrace.Propagate(error, "An error occurred creating new cluster topology service from service config '%s'", service.Name) } @@ -327,7 +325,7 @@ func newStatefulPluginsAndExternalServicesFromServiceConfig(serviceConfig apityp return serviceStatefulPlugins, externalServices, externalServiceDependencies, nil } -func newClusterTopologyServiceFromServiceConfig( +func newClusterTopologyServiceFromConfigs( serviceConfig apitypes.ServiceConfig, deploymentConfig *apitypes.DeploymentConfig, statefulSetConfig *apitypes.StatefulSetConfig, @@ -335,11 +333,17 @@ func newClusterTopologyServiceFromServiceConfig( ) (resolved.Service, error) { service := serviceConfig.Service serviceName := service.GetObjectMeta().GetName() + serviceAnnotations := service.GetObjectMeta().GetAnnotations() + + clusterTopologyService := resolved.Service{ + ServiceID: service.GetObjectMeta().GetName(), + Version: version, + ServiceSpec: &service.Spec, + } if deploymentConfig == nil && statefulSetConfig == nil { logrus.Warnf("Service %s has no workload", serviceName) } - if deploymentConfig != nil && statefulSetConfig != nil { workloads := []string{ deploymentConfig.Deployment.GetObjectMeta().GetName(), @@ -347,15 +351,6 @@ func newClusterTopologyServiceFromServiceConfig( } logrus.Error("Service %s is associated with more than one workload: %v", serviceName, workloads) } - - serviceAnnotations := service.GetObjectMeta().GetAnnotations() - - clusterTopologyService := resolved.Service{ - ServiceID: service.GetObjectMeta().GetName(), - Version: version, - ServiceSpec: &service.Spec, - } - if deploymentConfig != nil { workload := kardinal.NewDeploymentWorkloadSpec(deploymentConfig.Deployment.Spec) clusterTopologyService.WorkloadSpec = &workload @@ -365,12 +360,8 @@ func newClusterTopologyServiceFromServiceConfig( clusterTopologyService.WorkloadSpec = &workload } - if clusterTopologyService.WorkloadSpec == nil { - return clusterTopologyService, stacktrace.NewError("Service %s has no workload", serviceName) - } - // Set default for IsStateful to true if the workload is a StatefulSet, otherwise false - clusterTopologyService.IsExternal = clusterTopologyService.WorkloadSpec.IsStatefulSet() + clusterTopologyService.IsStateful = clusterTopologyService.WorkloadSpec.IsStatefulSet() // Override the IsStateful value by manual annotations isStateful, ok := serviceAnnotations["kardinal.dev.service/stateful"] diff --git a/kontrol-service/engine/flow/render.go b/kontrol-service/engine/flow/render.go index 53c5d56..a9512b3 100644 --- a/kontrol-service/engine/flow/render.go +++ b/kontrol-service/engine/flow/render.go @@ -318,7 +318,7 @@ func getStatefulSet(service *resolved.Service, namespace string) *appsv1.Statefu statefulSet := appsv1.StatefulSet{ TypeMeta: metav1.TypeMeta{ APIVersion: "apps/v1", - Kind: "statefulSet", + Kind: "StatefulSet", }, ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-%s", service.ServiceID, service.Version), From cc7fe459b9debdb4cdfefbfcc82974ec57b7ec69 Mon Sep 17 00:00:00 2001 From: lostbean Date: Thu, 3 Oct 2024 11:34:04 -0300 Subject: [PATCH 11/16] improve workload data structure checks --- kontrol-service/engine/docker.go | 2 +- kontrol-service/engine/flow/dev_flow.go | 6 ++-- kontrol-service/plugins/plugins.go | 3 +- kontrol-service/plugins/plugins_test.go | 8 ++--- kontrol-service/types/kardinal/workload.go | 24 ++++++++++---- .../types/kardinal/workload_spec.go | 32 +++++++++++++------ 6 files changed, 49 insertions(+), 26 deletions(-) diff --git a/kontrol-service/engine/docker.go b/kontrol-service/engine/docker.go index 80238a0..98efd64 100644 --- a/kontrol-service/engine/docker.go +++ b/kontrol-service/engine/docker.go @@ -56,7 +56,7 @@ func GenerateProdDevCluster(baseClusterTopologyMaybeWithTemplateOverrides *resol patches = append(patches, flow_spec.ServicePatch{ Service: devServiceName, - WorkloadSpec: &clonedWorkloadSpec, + WorkloadSpec: clonedWorkloadSpec, }) } diff --git a/kontrol-service/engine/flow/dev_flow.go b/kontrol-service/engine/flow/dev_flow.go index 6bd15e7..a61c16b 100644 --- a/kontrol-service/engine/flow/dev_flow.go +++ b/kontrol-service/engine/flow/dev_flow.go @@ -240,7 +240,7 @@ func applyPatch( } // Update service with final deployment spec - modifiedService.WorkloadSpec = &resultSpec + modifiedService.WorkloadSpec = resultSpec topology.Services[serviceIdx] = modifiedService topology.UpdateDependencies(service, modifiedService) @@ -330,12 +330,12 @@ func applyExternalServicePlugin( logrus.Infof("Calling external service '%v' plugin with parent service '%v'...", externalService.ServiceID, dependentService.ServiceID) pluginId := plugins.GetPluginId(flowId, dependentService.ServiceID, pluginIdx) - spec, _, err := pluginRunner.CreateFlow(externalServicePlugin.Name, *dependentService.ServiceSpec, *dependentService.WorkloadSpec, pluginId, externalServicePlugin.Args) + spec, _, err := pluginRunner.CreateFlow(externalServicePlugin.Name, *dependentService.ServiceSpec, dependentService.WorkloadSpec, pluginId, externalServicePlugin.Args) if err != nil { return stacktrace.Propagate(err, "error creating flow for external service '%s'", externalService.ServiceID) } - dependentService.WorkloadSpec = &spec + dependentService.WorkloadSpec = spec return nil } diff --git a/kontrol-service/plugins/plugins.go b/kontrol-service/plugins/plugins.go index 18584e4..586f707 100644 --- a/kontrol-service/plugins/plugins.go +++ b/kontrol-service/plugins/plugins.go @@ -37,7 +37,7 @@ func NewPluginRunner(gitPluginProvider GitPluginProvider, tenantId string, db *d } } -func (pr *PluginRunner) CreateFlow(pluginUrl string, serviceSpec corev1.ServiceSpec, originalWorkloadSpec kardinal.WorkloadSpec, flowUuid string, arguments map[string]string) (kardinal.WorkloadSpec, string, error) { +func (pr *PluginRunner) CreateFlow(pluginUrl string, serviceSpec corev1.ServiceSpec, originalWorkloadSpec *kardinal.WorkloadSpec, flowUuid string, arguments map[string]string) (*kardinal.WorkloadSpec, string, error) { workloadSpec := originalWorkloadSpec.DeepCopy() repoPath, err := pr.getOrCloneRepo(pluginUrl) @@ -225,7 +225,6 @@ with open('%s', 'w') as f: } func runPythonDeleteFlow(repoPath, configMap, flowUuid string) (string, error) { - scriptPath := filepath.Join(repoPath, "main.py") if _, err := os.Stat(scriptPath); os.IsNotExist(err) { diff --git a/kontrol-service/plugins/plugins_test.go b/kontrol-service/plugins/plugins_test.go index b2ad22f..95d58b9 100644 --- a/kontrol-service/plugins/plugins_test.go +++ b/kontrol-service/plugins/plugins_test.go @@ -84,7 +84,7 @@ func TestSimplePlugin(t *testing.T) { "text_to_replace": "helloworld", } - updatedDeploymentSpec, configMap, err := runner.CreateFlow(simplePlugin, serviceSpec, workloadSpec, flowUuid, arguments) + updatedDeploymentSpec, configMap, err := runner.CreateFlow(simplePlugin, serviceSpec, &workloadSpec, flowUuid, arguments) require.NoError(t, err) // Check if the deployment spec was updated correctly @@ -109,7 +109,7 @@ func TestIdentityPlugin(t *testing.T) { runner, cleanUpDbFunc := getPluginRunner(t) defer cleanUpDbFunc() - updatedServiceSpec, configMap, err := runner.CreateFlow(identityPlugin, serviceSpec, workloadSpec, flowUuid, map[string]string{}) + updatedServiceSpec, configMap, err := runner.CreateFlow(identityPlugin, serviceSpec, &workloadSpec, flowUuid, map[string]string{}) require.NoError(t, err) // Check if the deployment spec was updated correctly @@ -134,7 +134,7 @@ func TestComplexPlugin(t *testing.T) { runner, cleanUpDbFunc := getPluginRunner(t) defer cleanUpDbFunc() - updatedServiceSpec, configMap, err := runner.CreateFlow(complexPlugin, serviceSpec, workloadSpec, flowUuid, map[string]string{}) + updatedServiceSpec, configMap, err := runner.CreateFlow(complexPlugin, serviceSpec, &workloadSpec, flowUuid, map[string]string{}) require.NoError(t, err) // Check if the deployment spec was updated correctly @@ -160,7 +160,7 @@ func TestRedisPluginTest(t *testing.T) { runner, cleanUpDbFunc := getPluginRunner(t) defer cleanUpDbFunc() - updatedServiceSpec, configMap, err := runner.CreateFlow(redisPlugin, serviceSpec, workloadSpec, flowUuid, map[string]string{}) + updatedServiceSpec, configMap, err := runner.CreateFlow(redisPlugin, serviceSpec, &workloadSpec, flowUuid, map[string]string{}) require.NoError(t, err) // Check if the deployment spec was updated correctly diff --git a/kontrol-service/types/kardinal/workload.go b/kontrol-service/types/kardinal/workload.go index 5d3be28..0d996fe 100644 --- a/kontrol-service/types/kardinal/workload.go +++ b/kontrol-service/types/kardinal/workload.go @@ -18,7 +18,7 @@ func (w *Workload) IsDeployment() bool { return w.Deployment != nil } -func (w *Workload) GetDeployments() *appsv1.Deployment { +func (w *Workload) GetDeployment() *appsv1.Deployment { return w.Deployment } @@ -38,16 +38,28 @@ func NewStatefulSetWorkload(statefulSet *appsv1.StatefulSet) Workload { } } -func (w *Workload) DeepCopy() Workload { +func (w *Workload) DeepCopy() *Workload { + if w == nil { + return nil + } + if w.IsDeployment() { - return NewDeploymentWorkload(w.GetDeployments().DeepCopy()) + workload := NewDeploymentWorkload(w.GetDeployment().DeepCopy()) + return &workload + } else if w.IsStatefulSet() { + workload := NewStatefulSetWorkload(w.GetStatefulSet().DeepCopy()) + return &workload + } else { + panic("Invalid Workload") } - return NewStatefulSetWorkload(w.GetStatefulSet().DeepCopy()) } func (w *Workload) GetTemplateSpec() v1.PodSpec { if w.IsDeployment() { - return w.GetDeployments().Spec.Template.Spec + return w.GetDeployment().Spec.Template.Spec + } else if w.IsStatefulSet() { + return w.GetStatefulSet().Spec.Template.Spec + } else { + panic("Invalid Workload") } - return w.GetStatefulSet().Spec.Template.Spec } diff --git a/kontrol-service/types/kardinal/workload_spec.go b/kontrol-service/types/kardinal/workload_spec.go index 5152cad..706bdf6 100644 --- a/kontrol-service/types/kardinal/workload_spec.go +++ b/kontrol-service/types/kardinal/workload_spec.go @@ -38,24 +38,36 @@ func NewStatefulSetWorkloadSpec(spec appsv1.StatefulSetSpec) WorkloadSpec { } } -func (w *Workload) WorkloadSpec() WorkloadSpec { +func (w *Workload) WorkloadSpec() *WorkloadSpec { + if w == nil { + return nil + } + if w.IsDeployment() { - return NewDeploymentWorkloadSpec(w.GetDeployments().Spec) + spec := NewDeploymentWorkloadSpec(w.GetDeployment().Spec) + return &spec } else if w.IsStatefulSet() { - return NewStatefulSetWorkloadSpec(w.GetStatefulSet().Spec) + spec := NewStatefulSetWorkloadSpec(w.GetStatefulSet().Spec) + return &spec + } else { + panic("Invalid workload") } - - return WorkloadSpec{} } -func (w *WorkloadSpec) DeepCopy() WorkloadSpec { +func (w *WorkloadSpec) DeepCopy() *WorkloadSpec { + if w == nil { + return nil + } + if w.IsDeployment() { - return NewDeploymentWorkloadSpec(*w.GetDeploymentSpec().DeepCopy()) + spec := NewDeploymentWorkloadSpec(*w.GetDeploymentSpec().DeepCopy()) + return &spec } else if w.IsStatefulSet() { - return NewStatefulSetWorkloadSpec(*w.GetStatefulSetSpec().DeepCopy()) + spec := NewStatefulSetWorkloadSpec(*w.GetStatefulSetSpec().DeepCopy()) + return &spec + } else { + panic("Invalid WorkloadSpec") } - - return WorkloadSpec{} } func (w *WorkloadSpec) GetTemplateSpec() *v1.PodSpec { From caff840c9f8800a4d1e4b09fb92b62ac4e9407d7 Mon Sep 17 00:00:00 2001 From: lostbean Date: Thu, 3 Oct 2024 11:45:04 -0300 Subject: [PATCH 12/16] fail if no pod spec --- kontrol-service/plugins/plugins.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/kontrol-service/plugins/plugins.go b/kontrol-service/plugins/plugins.go index 586f707..29a322e 100644 --- a/kontrol-service/plugins/plugins.go +++ b/kontrol-service/plugins/plugins.go @@ -42,38 +42,38 @@ func (pr *PluginRunner) CreateFlow(pluginUrl string, serviceSpec corev1.ServiceS repoPath, err := pr.getOrCloneRepo(pluginUrl) if err != nil { - return workloadSpec, "", fmt.Errorf("failed to get or clone repository: %v", err) + return nil, "", fmt.Errorf("failed to get or clone repository: %v", err) } serviceSpecJSON, err := json.Marshal(serviceSpec) if err != nil { - return workloadSpec, "", fmt.Errorf("failed to marshal service spec: %v", err) + return nil, "", fmt.Errorf("failed to marshal service spec: %v", err) } deploymentSpecJSON, err := json.Marshal(workloadSpec.GetTemplateSpec()) if err != nil { - return workloadSpec, "", fmt.Errorf("failed to marshal deployment spec: %v", err) + return nil, "", fmt.Errorf("failed to marshal deployment spec: %v", err) } result, err := runPythonCreateFlow(repoPath, string(serviceSpecJSON), string(deploymentSpecJSON), flowUuid, arguments) if err != nil { - return workloadSpec, "", err + return nil, "", err } var resultMap map[string]json.RawMessage err = json.Unmarshal([]byte(result), &resultMap) if err != nil { - return workloadSpec, "", fmt.Errorf("failed to parse result: %v", err) + return nil, "", fmt.Errorf("failed to parse result: %v", err) } if resultMap["pod_spec"] == nil { - logrus.Warnf("No pod_spec found in plugin result") + return nil, "", fmt.Errorf("no pod_spec found in plugin result") } else { var newDeploymentSpec v1.PodSpec err = json.Unmarshal(resultMap["pod_spec"], &newDeploymentSpec) if err != nil { logrus.Errorf("Failed to unmarshal pod spec: %v", string(resultMap["pod_spec"])) - return workloadSpec, "", fmt.Errorf("failed to unmarshal deployment spec: %v", err) + return nil, "", fmt.Errorf("failed to unmarshal deployment spec: %v", err) } workloadSpec.UpdateTemplateSpec(newDeploymentSpec) } @@ -82,18 +82,18 @@ func (pr *PluginRunner) CreateFlow(pluginUrl string, serviceSpec corev1.ServiceS var configMap map[string]interface{} err = json.Unmarshal(configMapJSON, &configMap) if err != nil { - return workloadSpec, "", fmt.Errorf("invalid config map: %v", err) + return nil, "", fmt.Errorf("invalid config map: %v", err) } configMapBytes, err := json.Marshal(configMap) if err != nil { - return workloadSpec, "", fmt.Errorf("failed to re-marshal config map: %v", err) + return nil, "", fmt.Errorf("failed to re-marshal config map: %v", err) } logrus.Infof("Storing config map for plugin called with uuid '%v':\n %s\n...", flowUuid, string(configMapBytes)) _, err = pr.db.CreatePluginConfig(flowUuid, string(configMapBytes), pr.tenantId) if err != nil { - return workloadSpec, "", fmt.Errorf("failed to store the config map: %v", err) + return nil, "", fmt.Errorf("failed to store the config map: %v", err) } return workloadSpec, string(configMapBytes), nil From 251d268a44c9f4ee003eb62ee4e26d08161db982 Mon Sep 17 00:00:00 2001 From: lostbean Date: Thu, 3 Oct 2024 12:47:33 -0300 Subject: [PATCH 13/16] fix test --- kontrol-service/engine/flow/dev_flow_test.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/kontrol-service/engine/flow/dev_flow_test.go b/kontrol-service/engine/flow/dev_flow_test.go index 6fa52a1..1f647ff 100644 --- a/kontrol-service/engine/flow/dev_flow_test.go +++ b/kontrol-service/engine/flow/dev_flow_test.go @@ -9,6 +9,7 @@ import ( "github.com/samber/lo" "github.com/stretchr/testify/require" + apps "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" netv1 "k8s.io/api/networking/v1" "kardinal.kontrol-service/types/cluster_topology/resolved" @@ -19,7 +20,13 @@ import ( const dummyPluginName = "https://github.com/h4ck3rk3y/identity-plugin.git" func clusterTopologyExample() resolved.ClusterTopology { - dummySpec := &kardinal.WorkloadSpec{} + dummySpec := &kardinal.WorkloadSpec{ + DeploymentSpec: &apps.DeploymentSpec{ + Template: v1.PodTemplateSpec{ + Spec: v1.PodSpec{}, + }, + }, + } testPlugins := []*resolved.StatefulPlugin{ { Name: dummyPluginName, @@ -377,7 +384,13 @@ func clusterTopologyExample() resolved.ClusterTopology { } func getNewOBDClusterTopologyExample() resolved.ClusterTopology { - dummySpec := &kardinal.WorkloadSpec{} + dummySpec := &kardinal.WorkloadSpec{ + DeploymentSpec: &apps.DeploymentSpec{ + Template: v1.PodTemplateSpec{ + Spec: v1.PodSpec{}, + }, + }, + } httpProtocol := "HTTP" // Create services From 57c098cfb5b318293340afa25653466848ca65fb Mon Sep 17 00:00:00 2001 From: lostbean Date: Thu, 3 Oct 2024 13:33:08 -0300 Subject: [PATCH 14/16] another test fix --- kontrol-service/plugins/plugins_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kontrol-service/plugins/plugins_test.go b/kontrol-service/plugins/plugins_test.go index 95d58b9..1c9bb5f 100644 --- a/kontrol-service/plugins/plugins_test.go +++ b/kontrol-service/plugins/plugins_test.go @@ -113,7 +113,7 @@ func TestIdentityPlugin(t *testing.T) { require.NoError(t, err) // Check if the deployment spec was updated correctly - require.Equal(t, workloadSpec, updatedServiceSpec) + require.Equal(t, workloadSpec, *updatedServiceSpec) // Verify the config map var configMapData map[string]interface{} From 709e7113bd3b2d77b9d45366714e4b75eb849af4 Mon Sep 17 00:00:00 2001 From: lostbean Date: Thu, 3 Oct 2024 11:35:45 -0300 Subject: [PATCH 15/16] back to original repo --- ci/obd-demo.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/obd-demo.yaml b/ci/obd-demo.yaml index bafefc1..0ecad13 100644 --- a/ci/obd-demo.yaml +++ b/ci/obd-demo.yaml @@ -144,7 +144,7 @@ metadata: annotations: kardinal.dev.service/dependencies: "productcatalogservice:http,cartservice:http" kardinal.dev.service/plugins: | - - name: https://github.com/lostbean/free-currency-api-plugin.git + - name: https://github.com/kurtosis-tech/free-currency-api-plugin.git type: external servicename: free-currency-api args: @@ -211,7 +211,7 @@ metadata: annotations: kardinal.dev.service/stateful: "true" kardinal.dev.service/plugins: | - - name: github.com/lostbean/postgres-seed-plugin + - name: github.com/kurtosis-tech/postgres-seed-plugin args: seed_script: | -- create the table From 84851011c4722c80848fce3da877ad41ff8e1b75 Mon Sep 17 00:00:00 2001 From: lostbean Date: Thu, 3 Oct 2024 14:32:37 -0300 Subject: [PATCH 16/16] update to main kardinal repo --- flake.lock | 8 ++++---- flake.nix | 2 +- kontrol-service/go.mod | 4 ++-- kontrol-service/go.sum | 8 ++++---- kontrol-service/gomod2nix.toml | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/flake.lock b/flake.lock index 17c3a16..ba0e62b 100644 --- a/flake.lock +++ b/flake.lock @@ -91,16 +91,16 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1727887180, - "narHash": "sha256-wG066JPIYqCx9MBLg23s8ynH5YihOOf+y3u4JIIqdNc=", + "lastModified": 1727976041, + "narHash": "sha256-WdQWRPV2o+0idLAcEnlUh73tKtxxXeXHUIgDySgRIUg=", "owner": "kurtosis-tech", "repo": "kardinal", - "rev": "0d4cf56200c22b4c5b2e60bccbb5499a84b3c291", + "rev": "a1632d5aecd857f8de5b77db342c39daff91bcb2", "type": "github" }, "original": { "owner": "kurtosis-tech", - "ref": "0d4cf56200c2", + "ref": "a1632d5aecd8", "repo": "kardinal", "type": "github" } diff --git a/flake.nix b/flake.nix index 3000506..f04480e 100644 --- a/flake.nix +++ b/flake.nix @@ -5,7 +5,7 @@ gomod2nix.url = "github:nix-community/gomod2nix"; gomod2nix.inputs.nixpkgs.follows = "nixpkgs"; gomod2nix.inputs.flake-utils.follows = "flake-utils"; - kardinal.url = "github:kurtosis-tech/kardinal/0d4cf56200c2"; + kardinal.url = "github:kurtosis-tech/kardinal/a1632d5aecd8"; }; outputs = { self, diff --git a/kontrol-service/go.mod b/kontrol-service/go.mod index 586497e..b88f6a2 100644 --- a/kontrol-service/go.mod +++ b/kontrol-service/go.mod @@ -7,8 +7,8 @@ toolchain go1.22.3 require ( github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/dominikbraun/graph v0.23.0 - github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20241002163940-0d4cf56200c2 - github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20241002163940-0d4cf56200c2 + github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20241003172041-a1632d5aecd8 + github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20241003172041-a1632d5aecd8 github.com/kurtosis-tech/stacktrace v0.0.0-20211028211901-1c67a77b5409 github.com/labstack/echo/v4 v4.12.0 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 diff --git a/kontrol-service/go.sum b/kontrol-service/go.sum index fa2283c..8473ae3 100644 --- a/kontrol-service/go.sum +++ b/kontrol-service/go.sum @@ -77,10 +77,10 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20241002163940-0d4cf56200c2 h1:stGS2jjEvCO817NYYtk7JTJEmmfAPiDDZWmyWy6GJjg= -github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20241002163940-0d4cf56200c2/go.mod h1:dQ+ZYcpSrex3FlfyYAvGuhIFHim+oJuJvslNp8rwuFo= -github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20241002163940-0d4cf56200c2 h1:DwNqcAwVIs9pTAK76Irb8JItGXYo8LEaxmZzj/My/6E= -github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20241002163940-0d4cf56200c2/go.mod h1:uUIEjxgSYw58hJgD1AwGOBE3LGPwLDiYtNmLGmnO8vI= +github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20241003172041-a1632d5aecd8 h1:I/XvDVzAUvSAo586Qy/ioFfnyk8lXIsYGwmyeoE08W0= +github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20241003172041-a1632d5aecd8/go.mod h1:dQ+ZYcpSrex3FlfyYAvGuhIFHim+oJuJvslNp8rwuFo= +github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20241003172041-a1632d5aecd8 h1:+7d/CazuTvkgdY+ppb+vEjvvq0Un0qbUYfnlt3atAKo= +github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20241003172041-a1632d5aecd8/go.mod h1:uUIEjxgSYw58hJgD1AwGOBE3LGPwLDiYtNmLGmnO8vI= github.com/kurtosis-tech/stacktrace v0.0.0-20211028211901-1c67a77b5409 h1:YQTATifMUwZEtZYb0LVA7DK2pj8s71iY8rzweuUQ5+g= github.com/kurtosis-tech/stacktrace v0.0.0-20211028211901-1c67a77b5409/go.mod h1:y5weVs5d9wXXHcDA1awRxkIhhHC1xxYJN8a7aXnE6S8= github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0= diff --git a/kontrol-service/gomod2nix.toml b/kontrol-service/gomod2nix.toml index 2a03847..2629785 100644 --- a/kontrol-service/gomod2nix.toml +++ b/kontrol-service/gomod2nix.toml @@ -278,10 +278,10 @@ schema = 3 version = "v0.2.0" hash = "sha256-fadcWxZOORv44oak3jTxm6YcITcFxdGt4bpn869HxUE=" [mod."github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api"] - version = "v0.0.0-20241002163940-0d4cf56200c2" + version = "v0.0.0-20241003172041-a1632d5aecd8" hash = "sha256-UhlNzM0NsEB3YStUvT6KNWMKsw7bQvvhFSdxiVryG+s=" [mod."github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api"] - version = "v0.0.0-20241002163940-0d4cf56200c2" + version = "v0.0.0-20241003172041-a1632d5aecd8" hash = "sha256-jJPe/rGOg0G1D64rOWk303FF3+uYS5vHfs3lOXhR4tQ=" [mod."github.com/kurtosis-tech/stacktrace"] version = "v0.0.0-20211028211901-1c67a77b5409"