diff --git a/kontrol-service/api/server.go b/kontrol-service/api/server.go index 7800248..3783e6f 100644 --- a/kontrol-service/api/server.go +++ b/kontrol-service/api/server.go @@ -197,19 +197,76 @@ func (sv *Server) PostTenantUuidFlowCreate(_ context.Context, request api.PostTe patches = append(patches, patch) } - flowId, entries, err := applyProdDevFlow(sv, request.Uuid, patches, templateSpec) + requestTenantUuid := request.Uuid + requestFlowId := request.Body.FlowId + + flowId, flowIdAlreadyExist, err := sv.checkOrCreateFlowID(requestTenantUuid, requestFlowId) + if err != nil { + var apiErrResponse api.PostTenantUuidFlowCreateResponseObject + errMsg := fmt.Sprintf("An error occurred checking or creating flow ID %s", *request.Body.FlowId) + if flowIdAlreadyExist { + errResp := api.RequestErrorJSONResponse{ + Error: err.Error(), + Msg: &errMsg, + } + apiErrResponse = api.PostTenantUuidFlowCreate400JSONResponse{RequestErrorJSONResponse: errResp} + } else { + errResp := api.ErrorJSONResponse{ + Error: err.Error(), + Msg: &errMsg, + } + apiErrResponse = api.PostTenantUuidFlowCreate500JSONResponse{ErrorJSONResponse: errResp} + } + + return apiErrResponse, nil + } + + entries, err := applyProdDevFlow(flowId, sv, request.Uuid, patches, templateSpec) if err != nil { errMsg := "An error occurred creating flow" errResp := api.ErrorJSONResponse{ Error: err.Error(), Msg: &errMsg, } - return api.PostTenantUuidFlowCreate500JSONResponse{errResp}, nil + return api.PostTenantUuidFlowCreate500JSONResponse{ErrorJSONResponse: errResp}, nil } - resp := apitypes.Flow{FlowId: *flowId, AccessEntry: toApiIngressAccessEntries(entries)} + resp := apitypes.Flow{FlowId: flowId, AccessEntry: toApiIngressAccessEntries(entries)} return api.PostTenantUuidFlowCreate200JSONResponse(resp), nil } +func (sv *Server) checkOrCreateFlowID(tenantUuid apitypes.Uuid, requestFlowId *string) (string, bool, error) { + + var flowIdAlreadyExist bool + + clusterTopology, allFlows, _, _, _, _, _, err := getTenantTopologies(sv, tenantUuid) + if err != nil { + return "", flowIdAlreadyExist, err + } + + // Create the flow ID if it was not provided + if requestFlowId == nil || *requestFlowId == "" { + + // The baseline flow ID is not stored, it's inferred from the namespace name, currently these are the same + baselineFlowId := clusterTopology.Namespace + + randId := getRandID() + + newFlowId := fmt.Sprintf("%s-%s", baselineFlowId, randId) + return newFlowId, flowIdAlreadyExist, nil + } + + // check received flowID from the request + _, found := lo.FindKeyBy(allFlows, func(key string, value resolved.ClusterTopology) bool { + return key == *requestFlowId + }) + if found { + flowIdAlreadyExist = true + return "", flowIdAlreadyExist, stacktrace.NewError("flow id '%s' already exists", *requestFlowId) + } + + return *requestFlowId, flowIdAlreadyExist, nil +} + func (sv *Server) GetTenantUuidTopology(_ context.Context, request api.GetTenantUuidTopologyRequestObject) (api.GetTenantUuidTopologyResponseObject, error) { logrus.Infof("getting topology for tenant '%s'", request.Uuid) @@ -515,19 +572,18 @@ func applyProdOnlyFlow( // ============================================================================================================ func applyProdDevFlow( + flowID string, sv *Server, tenantUuidStr string, patches []flow_spec.ServicePatchSpec, templateSpec *apitypes.TemplateSpec, -) (*string, []resolved.IngressAccessEntry, error) { - randId := getRandFlowID() - flowID := fmt.Sprintf("dev-%s", randId) +) ([]resolved.IngressAccessEntry, error) { logrus.Debugf("generating base cluster topology for tenant %s on flowID %s", tenantUuidStr, flowID) baseTopology, _, tenantTemplates, serviceConfigs, 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) + return nil, fmt.Errorf("no base cluster topology found for tenant %s, did you deploy the cluster?", tenantUuidStr) } baseClusterTopologyMaybeWithTemplateOverrides := *baseTopology @@ -536,7 +592,7 @@ func applyProdDevFlow( template, found := tenantTemplates[templateSpec.TemplateName] if !found { - return nil, nil, fmt.Errorf("template with name '%v' doesn't exist for tenant uuid '%v'", templateSpec.TemplateName, tenantUuidStr) + return nil, fmt.Errorf("template with name '%v' doesn't exist for tenant uuid '%v'", templateSpec.TemplateName, tenantUuidStr) } serviceConfigs = template.ApplyTemplateOverrides(serviceConfigs, templateSpec) @@ -545,7 +601,7 @@ func applyProdDevFlow( baseClusterTopologyWithTemplateOverridesPtr, err := engine.GenerateProdOnlyCluster(baselineFlowID, serviceConfigs, 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) + return nil, fmt.Errorf("an error occurred while creating base cluster topology from templates:\n %s", err) } baseClusterTopologyMaybeWithTemplateOverrides = *baseClusterTopologyWithTemplateOverridesPtr } @@ -560,24 +616,24 @@ func applyProdDevFlow( pluginRunner := plugins.NewPluginRunner(plugins.NewGitPluginProviderImpl(), tenantUuidStr, sv.db) devClusterTopology, err := engine.GenerateProdDevCluster(&baseClusterTopologyMaybeWithTemplateOverrides, baseTopology, pluginRunner, flowSpec) if err != nil { - return nil, nil, err + return nil, err } devClusterTopologyJson, err := json.Marshal(devClusterTopology) if err != nil { logrus.Errorf("an error occured while encoding the cluster topology for tenant %s and flow %s, error was \n: '%v'", tenantUuidStr, flowID, err.Error()) - return nil, nil, err + return nil, err } _, err = sv.db.CreateFlow(tenantUuidStr, flowID, devClusterTopologyJson) if err != nil { logrus.Errorf("an error occured while creating flow %s. error was \n: '%v'", flowID, err.Error()) - return nil, nil, err + return nil, err } flowHostMapping := devClusterTopology.GetFlowHostMapping() - return &flowID, flowHostMapping[flowID], nil + return flowHostMapping[flowID], nil } // Returns the following given a tenant ID: diff --git a/kontrol-service/api/utils.go b/kontrol-service/api/utils.go index a0d0902..4b14810 100644 --- a/kontrol-service/api/utils.go +++ b/kontrol-service/api/utils.go @@ -30,10 +30,6 @@ func getRandID() string { return string(b) } -func getRandFlowID() string { - return getRandID() -} - func getRandTemplateID() string { return templatePrefix + getRandID() } diff --git a/kontrol-service/engine/flow/render.go b/kontrol-service/engine/flow/render.go index 6646776..9c072ae 100644 --- a/kontrol-service/engine/flow/render.go +++ b/kontrol-service/engine/flow/render.go @@ -882,7 +882,7 @@ func generateDynamicLuaScript(allServices []*resolved.Service, flowId string, na service = fallbackService } if service == nil { - logrus.Errorf("No service found for '%s' for version '%s' or baseline '%s'. No routing can configured.", serviceID, flowId, &baselineFlowVersion) + logrus.Errorf("No service found for '%s' for version '%s' or baseline '%s'. No routing can configured.", serviceID, flowId, baselineFlowVersion) continue } diff --git a/kontrol-service/go.mod b/kontrol-service/go.mod index d02291e..2053b88 100644 --- a/kontrol-service/go.mod +++ b/kontrol-service/go.mod @@ -7,7 +7,7 @@ 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/cli-kontrol-api v0.0.0-20240930151959-22270454aa6b github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240926004715-b5a991623aeb github.com/kurtosis-tech/stacktrace v0.0.0-20211028211901-1c67a77b5409 github.com/labstack/echo/v4 v4.12.0 diff --git a/kontrol-service/go.sum b/kontrol-service/go.sum index 0f8b270..7070f7d 100644 --- a/kontrol-service/go.sum +++ b/kontrol-service/go.sum @@ -77,8 +77,8 @@ 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/cli-kontrol-api v0.0.0-20240930151959-22270454aa6b h1:pJlgnXZCdSVl1ts0gDagES1TRWXzA/WOrKjl0SCSES0= +github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240930151959-22270454aa6b/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/stacktrace v0.0.0-20211028211901-1c67a77b5409 h1:YQTATifMUwZEtZYb0LVA7DK2pj8s71iY8rzweuUQ5+g= diff --git a/kontrol-service/gomod2nix.toml b/kontrol-service/gomod2nix.toml index 3c031b1..b3270c4 100644 --- a/kontrol-service/gomod2nix.toml +++ b/kontrol-service/gomod2nix.toml @@ -278,8 +278,8 @@ 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-20240930151959-22270454aa6b" + hash = "sha256-Mm7+UU6tK65VA4BY8UxpjTay8DpYjAmbwz8Szj5X2aY=" [mod."github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api"] version = "v0.0.0-20240926004715-b5a991623aeb" hash = "sha256-u6fSYBRONpUBP/Mb9hWgzzlbcM0NQ6hROygvDn2tbBM="