From 75259d1071e2e887d79a8d09ca46116405910bac Mon Sep 17 00:00:00 2001 From: thxCode Date: Tue, 15 Aug 2023 14:55:25 +0800 Subject: [PATCH 1/2] refactor: deployer - private internal functions - comment the usage of options Signed-off-by: thxCode --- pkg/deployer/terraform/deployer.go | 212 ++++++++++++----------------- pkg/deployer/terraform/syncer.go | 53 ++++++++ pkg/deployer/types/types.go | 4 +- 3 files changed, 141 insertions(+), 128 deletions(-) create mode 100644 pkg/deployer/terraform/syncer.go diff --git a/pkg/deployer/terraform/deployer.go b/pkg/deployer/terraform/deployer.go index 80c7a5dd6..34790b890 100644 --- a/pkg/deployer/terraform/deployer.go +++ b/pkg/deployer/terraform/deployer.go @@ -49,54 +49,17 @@ import ( // DeployerType the type of deployer. const DeployerType = types.DeployerTypeTF -// Deployer terraform deployer to deploy the service. -type Deployer struct { - logger log.Logger - modelClient model.ClientSet - clientSet *kubernetes.Clientset -} - -type CreateRevisionOptions struct { - // JobType indicates the type of the job. - JobType string - Tags []string - Service *model.Service -} - -// CreateSecretsOptions options for creating deployment job secrets. -type CreateSecretsOptions struct { - SkipTLSVerify bool - ServiceRevision *model.ServiceRevision - Connectors model.Connectors - ProjectID object.ID - EnvironmentID object.ID - SubjectID object.ID - // Metadata. - ProjectName string - EnvironmentName string - ServiceName string - ServiceID object.ID - ManagedNamespaceName string -} +const ( + // _backendAPI the API path to terraform deploy backend. + // Terraform will get and update deployment states from this API. + _backendAPI = "/v1/projects/%s/environments/%s/services/%s/revisions/%s/terraform-states" -// CreateJobOptions options for do job action. -type CreateJobOptions struct { - Type string - SkipTLSVerify bool - Service *model.Service - // ServiceRevision indicates the service revision to create the deploy job. - ServiceRevision *model.ServiceRevision -} + // _variablePrefix the prefix of the variable name. + _variablePrefix = "_seal_var_" -// _backendAPI the API path to terraform deploy backend. -// Terraform will get and update deployment states from this API. -const _backendAPI = "/v1/projects/%s/environments/%s/services/%s/revisions/%s/terraform-states" - -// _variablePrefix the prefix of the variable name. -const _variablePrefix = "_seal_var_" - -// _servicePrefix the prefix of the service output name. -const _servicePrefix = "_seal_service_" + // _servicePrefix the prefix of the service output name. + _servicePrefix = "_seal_service_" +) var ( // _variableReg the regexp to match the variable. @@ -105,6 +68,13 @@ var ( _serviceReg = regexp.MustCompile(`\${service\.([^.}]+)\.([^.}]+)}`) ) +// Deployer terraform deployer to deploy the service. +type Deployer struct { + logger log.Logger + modelClient model.ClientSet + clientSet *kubernetes.Clientset +} + func NewDeployer(_ context.Context, opts deptypes.CreateOptions) (deptypes.Deployer, error) { clientSet, err := kubernetes.NewForConfig(opts.KubeConfig) if err != nil { @@ -122,9 +92,10 @@ func (d Deployer) Type() deptypes.Type { return DeployerType } -// Apply deploys the service. +// Apply creates a new service revision by the given service, +// and drives the Kubernetes Job to create resources of the service. func (d Deployer) Apply(ctx context.Context, service *model.Service, opts deptypes.ApplyOptions) (err error) { - revision, err := d.CreateServiceRevision(ctx, CreateRevisionOptions{ + revision, err := d.createRevision(ctx, createRevisionOptions{ JobType: JobTypeApply, Tags: opts.Tags, Service: service, @@ -142,7 +113,7 @@ func (d Deployer) Apply(ctx context.Context, service *model.Service, opts deptyp _ = d.updateRevisionStatus(ctx, revision, status.ServiceRevisionStatusFailed, err.Error()) }() - return d.CreateK8sJob(ctx, CreateJobOptions{ + return d.createK8sJob(ctx, createK8sJobOptions{ Type: JobTypeApply, SkipTLSVerify: opts.SkipTLSVerify, Service: service, @@ -150,15 +121,10 @@ func (d Deployer) Apply(ctx context.Context, service *model.Service, opts deptyp }) } -// Destroy will destroy the resource of the service. -// 1. Get the latest revision, and checkAppRevision it if it is running. -// 2. If not running, then destroy resources. -func (d Deployer) Destroy( - ctx context.Context, - service *model.Service, - destroyOpts deptypes.DestroyOptions, -) (err error) { - sr, err := d.CreateServiceRevision(ctx, CreateRevisionOptions{ +// Destroy creates a new service revision by the given service, +// and drives the Kubernetes Job to clean the resources of the service. +func (d Deployer) Destroy(ctx context.Context, service *model.Service, opts deptypes.DestroyOptions) (err error) { + revision, err := d.createRevision(ctx, createRevisionOptions{ JobType: JobTypeDestroy, Service: service, }) @@ -170,8 +136,9 @@ func (d Deployer) Destroy( if err == nil { return } + // Report to service revision. - _ = d.updateRevisionStatus(ctx, sr, status.ServiceRevisionStatusFailed, err.Error()) + _ = d.updateRevisionStatus(ctx, revision, status.ServiceRevisionStatusFailed, err.Error()) }() // If no resource exists, skip job and set revision status succeed. @@ -183,19 +150,30 @@ func (d Deployer) Destroy( } if !exist { - return d.updateRevisionStatus(ctx, sr, status.ServiceRevisionStatusSucceeded, sr.StatusMessage) + return d.updateRevisionStatus(ctx, revision, status.ServiceRevisionStatusSucceeded, revision.StatusMessage) } - return d.CreateK8sJob(ctx, CreateJobOptions{ + return d.createK8sJob(ctx, createK8sJobOptions{ Type: JobTypeDestroy, - SkipTLSVerify: destroyOpts.SkipTLSVerify, + SkipTLSVerify: opts.SkipTLSVerify, Service: service, - ServiceRevision: sr, + ServiceRevision: revision, }) } -// CreateK8sJob will create a k8s job to deploy、destroy or rollback the service. -func (d Deployer) CreateK8sJob(ctx context.Context, opts CreateJobOptions) error { +type createK8sJobOptions struct { + // Type indicates the type of the job. + Type string + // SkipTLSVerify indicates to skip TLS verification. + SkipTLSVerify bool + // Service indicates the service to create the deployment job. + Service *model.Service + // ServiceRevision indicates the service revision to create the deployment job. + ServiceRevision *model.ServiceRevision +} + +// createK8sJob creates a k8s job to deploy, destroy or rollback the service. +func (d Deployer) createK8sJob(ctx context.Context, opts createK8sJobOptions) error { connectors, err := d.getConnectors(ctx, opts.Service) if err != nil { return err @@ -228,7 +206,7 @@ func (d Deployer) CreateK8sJob(ctx context.Context, opts CreateJobOptions) error } // Prepare tfConfig for deployment. - secretOpts := CreateSecretsOptions{ + secretOpts := createK8sSecretsOptions{ SkipTLSVerify: opts.SkipTLSVerify, ServiceRevision: opts.ServiceRevision, Connectors: connectors, @@ -342,14 +320,29 @@ func (d Deployer) updateRevisionStatus(ctx context.Context, ar *model.ServiceRev return nil } -// createK8sSecrets will create the k8s secrets for deployment. -func (d Deployer) createK8sSecrets(ctx context.Context, opts CreateSecretsOptions) error { +type createK8sSecretsOptions struct { + SkipTLSVerify bool + ServiceRevision *model.ServiceRevision + Connectors model.Connectors + ProjectID object.ID + EnvironmentID object.ID + SubjectID object.ID + // Metadata. + ProjectName string + EnvironmentName string + ServiceName string + ServiceID object.ID + ManagedNamespaceName string +} + +// createK8sSecrets creates the k8s secrets for deployment. +func (d Deployer) createK8sSecrets(ctx context.Context, opts createK8sSecretsOptions) error { secretData := make(map[string][]byte) // SecretName terraform tfConfig name. secretName := _jobSecretPrefix + string(opts.ServiceRevision.ID) // Prepare terraform config files bytes for deployment. - terraformData, err := d.LoadConfigsBytes(ctx, opts) + terraformData, err := d.loadConfigsBytes(ctx, opts) if err != nil { return err } @@ -359,7 +352,7 @@ func (d Deployer) createK8sSecrets(ctx context.Context, opts CreateSecretsOption } // Mount the provider configs(e.g. kubeconfig) to secret. - providerData, err := d.GetProviderSecretData(opts.Connectors) + providerData, err := d.getProviderSecretData(opts.Connectors) if err != nil { return err } @@ -376,13 +369,22 @@ func (d Deployer) createK8sSecrets(ctx context.Context, opts CreateSecretsOption return nil } -// CreateServiceRevision will create a new service revision. +type createRevisionOptions struct { + // JobType indicates the type of the job. + JobType string + // Tags indicates the tags for the revision. + Tags []string + // Service indicates the service to create the revision. + Service *model.Service +} + +// createRevision creates a new service revision. // Get the latest revision, and check it if it is running. // If not running, then apply the latest revision. // If running, then wait for the latest revision to be applied. -func (d Deployer) CreateServiceRevision( +func (d Deployer) createRevision( ctx context.Context, - opts CreateRevisionOptions, + opts createRevisionOptions, ) (*model.ServiceRevision, error) { tv, err := d.modelClient.TemplateVersions().Query(). Where(templateversion.ID(opts.Service.TemplateID)). @@ -488,12 +490,12 @@ func (d Deployer) getRequiredProviders( return requiredProviders, nil } -// LoadConfigsBytes returns terraform main.tf and terraform.tfvars for deployment. -func (d Deployer) LoadConfigsBytes(ctx context.Context, opts CreateSecretsOptions) (map[string][]byte, error) { +// loadConfigsBytes returns terraform main.tf and terraform.tfvars for deployment. +func (d Deployer) loadConfigsBytes(ctx context.Context, opts createK8sSecretsOptions) (map[string][]byte, error) { logger := log.WithName("deployer").WithName("tf") // Prepare terraform tfConfig. // get module configs from service revision. - moduleConfig, providerRequirements, err := d.GetModuleConfig(ctx, opts) + moduleConfig, providerRequirements, err := d.getModuleConfig(ctx, opts) if err != nil { return nil, err } @@ -615,8 +617,8 @@ func (d Deployer) LoadConfigsBytes(ctx context.Context, opts CreateSecretsOption return secretMaps, nil } -// GetProviderSecretData returns provider kubeconfig secret data mount into terraform container. -func (d Deployer) GetProviderSecretData(connectors model.Connectors) (map[string][]byte, error) { +// getProviderSecretData returns provider kubeconfig secret data mount into terraform container. +func (d Deployer) getProviderSecretData(connectors model.Connectors) (map[string][]byte, error) { secretData := make(map[string][]byte) for _, c := range connectors { @@ -638,11 +640,11 @@ func (d Deployer) GetProviderSecretData(connectors model.Connectors) (map[string return secretData, nil } -// GetModuleConfig returns module configs and required connectors to +// getModuleConfig returns module configs and required connectors to // get terraform module config block from service revision. -func (d Deployer) GetModuleConfig( +func (d Deployer) getModuleConfig( ctx context.Context, - opts CreateSecretsOptions, + opts createK8sSecretsOptions, ) (*config.ModuleConfig, []types.ProviderRequirement, error) { var ( requiredProviders = make([]types.ProviderRequirement, 0) @@ -711,7 +713,7 @@ func (d Deployer) getConnectors(ctx context.Context, ai *model.Service) (model.C func (d Deployer) parseModuleAttributes( ctx context.Context, templateConfig *config.ModuleConfig, - opts CreateSecretsOptions, + opts createK8sSecretsOptions, ) (variables model.Variables, outputs map[string]parser.OutputState, err error) { var ( templateVariables []string @@ -965,50 +967,6 @@ func (d Deployer) getServiceDependencyOutputs( return outputs, nil } -func SyncServiceRevisionStatus(ctx context.Context, bm revisionbus.BusMessage) (err error) { - var ( - mc = bm.TransactionalModelClient - revision = bm.Refer - ) - - // Report to service. - entity, err := mc.Services().Query(). - Where(service.ID(revision.ServiceID)). - Select( - service.FieldID, - service.FieldStatus, - ). - Only(ctx) - if err != nil { - return err - } - - switch revision.Status { - case status.ServiceRevisionStatusSucceeded: - if status.ServiceStatusDeleted.IsUnknown(entity) { - return mc.Services().DeleteOne(entity). - Exec(ctx) - } - - status.ServiceStatusDeployed.True(entity, "") - status.ServiceStatusReady.Unknown(entity, "") - case status.ServiceRevisionStatusFailed: - if status.ServiceStatusDeleted.IsUnknown(entity) { - status.ServiceStatusDeleted.False(entity, "") - } else { - status.ServiceStatusDeployed.False(entity, "") - } - - entity.Status.SummaryStatusMessage = revision.StatusMessage - } - - entity.Status.SetSummary(status.WalkService(&entity.Status)) - - return mc.Services().UpdateOne(entity). - SetStatus(entity.Status). - Exec(ctx) -} - // parseAttributeReplace parses attribute variable ${var.name} replaces it with ${var._variablePrefix+name}, // service reference ${service.name.output} replaces it with ${var._servicePrefix+name} // and returns variable names and service names. @@ -1103,7 +1061,7 @@ func getVarConfigOptions(variables model.Variables, serviceOutputs map[string]pa func getModuleConfig( revision *model.ServiceRevision, modVer *model.TemplateVersion, - ops CreateSecretsOptions, + ops createK8sSecretsOptions, ) (*config.ModuleConfig, error) { var ( props = make(property.Properties, len(revision.Attributes)) diff --git a/pkg/deployer/terraform/syncer.go b/pkg/deployer/terraform/syncer.go new file mode 100644 index 000000000..d67eb8117 --- /dev/null +++ b/pkg/deployer/terraform/syncer.go @@ -0,0 +1,53 @@ +package terraform + +import ( + "context" + + revisionbus "github.com/seal-io/seal/pkg/bus/servicerevision" + "github.com/seal-io/seal/pkg/dao/model/service" + "github.com/seal-io/seal/pkg/dao/types/status" +) + +// SyncServiceRevisionStatus updates the status of the service according to its recent finished service revision +func SyncServiceRevisionStatus(ctx context.Context, bm revisionbus.BusMessage) (err error) { + var ( + mc = bm.TransactionalModelClient + revision = bm.Refer + ) + + // Report to service. + entity, err := mc.Services().Query(). + Where(service.ID(revision.ServiceID)). + Select( + service.FieldID, + service.FieldStatus). + Only(ctx) + if err != nil { + return err + } + + switch revision.Status { + case status.ServiceRevisionStatusSucceeded: + if status.ServiceStatusDeleted.IsUnknown(entity) { + return mc.Services().DeleteOne(entity). + Exec(ctx) + } + + status.ServiceStatusDeployed.True(entity, "") + status.ServiceStatusReady.Unknown(entity, "") + case status.ServiceRevisionStatusFailed: + if status.ServiceStatusDeleted.IsUnknown(entity) { + status.ServiceStatusDeleted.False(entity, "") + } else { + status.ServiceStatusDeployed.False(entity, "") + } + + entity.Status.SummaryStatusMessage = revision.StatusMessage + } + + entity.Status.SetSummary(status.WalkService(&entity.Status)) + + return mc.Services().UpdateOne(entity). + SetStatus(entity.Status). + Exec(ctx) +} diff --git a/pkg/deployer/types/types.go b/pkg/deployer/types/types.go index b0177c143..d9b19e94d 100644 --- a/pkg/deployer/types/types.go +++ b/pkg/deployer/types/types.go @@ -25,12 +25,14 @@ type Deployer interface { // ApplyOptions holds the options of Deployer's Apply action. type ApplyOptions struct { + // SkipTLSVerify indicates to skip TLS verification. SkipTLSVerify bool - // Tags is the service revision tags. + // Tags holds the tags for create service revision. Tags []string } // DestroyOptions holds the options of Deployer's Destroy action. type DestroyOptions struct { + // SkipTLSVerify indicates to skip TLS verification. SkipTLSVerify bool } From a1572104c0e4e5dba5df1914036410d5862f8657 Mon Sep 17 00:00:00 2001 From: thxCode Date: Tue, 15 Aug 2023 19:21:22 +0800 Subject: [PATCH 2/2] refactor: deployer apply and destroy Signed-off-by: thxCode --- pkg/deployer/terraform/deployer.go | 187 ++++++++++++++++------------- pkg/deployer/terraform/syncer.go | 2 +- 2 files changed, 103 insertions(+), 86 deletions(-) diff --git a/pkg/deployer/terraform/deployer.go b/pkg/deployer/terraform/deployer.go index 34790b890..a4a432c7c 100644 --- a/pkg/deployer/terraform/deployer.go +++ b/pkg/deployer/terraform/deployer.go @@ -96,9 +96,9 @@ func (d Deployer) Type() deptypes.Type { // and drives the Kubernetes Job to create resources of the service. func (d Deployer) Apply(ctx context.Context, service *model.Service, opts deptypes.ApplyOptions) (err error) { revision, err := d.createRevision(ctx, createRevisionOptions{ - JobType: JobTypeApply, - Tags: opts.Tags, - Service: service, + ServiceID: service.ID, + JobType: JobTypeApply, + Tags: opts.Tags, }) if err != nil { return err @@ -116,7 +116,6 @@ func (d Deployer) Apply(ctx context.Context, service *model.Service, opts deptyp return d.createK8sJob(ctx, createK8sJobOptions{ Type: JobTypeApply, SkipTLSVerify: opts.SkipTLSVerify, - Service: service, ServiceRevision: revision, }) } @@ -125,8 +124,8 @@ func (d Deployer) Apply(ctx context.Context, service *model.Service, opts deptyp // and drives the Kubernetes Job to clean the resources of the service. func (d Deployer) Destroy(ctx context.Context, service *model.Service, opts deptypes.DestroyOptions) (err error) { revision, err := d.createRevision(ctx, createRevisionOptions{ - JobType: JobTypeDestroy, - Service: service, + ServiceID: service.ID, + JobType: JobTypeDestroy, }) if err != nil { return err @@ -156,7 +155,6 @@ func (d Deployer) Destroy(ctx context.Context, service *model.Service, opts dept return d.createK8sJob(ctx, createK8sJobOptions{ Type: JobTypeDestroy, SkipTLSVerify: opts.SkipTLSVerify, - Service: service, ServiceRevision: revision, }) } @@ -166,25 +164,30 @@ type createK8sJobOptions struct { Type string // SkipTLSVerify indicates to skip TLS verification. SkipTLSVerify bool - // Service indicates the service to create the deployment job. - Service *model.Service // ServiceRevision indicates the service revision to create the deployment job. ServiceRevision *model.ServiceRevision } // createK8sJob creates a k8s job to deploy, destroy or rollback the service. func (d Deployer) createK8sJob(ctx context.Context, opts createK8sJobOptions) error { - connectors, err := d.getConnectors(ctx, opts.Service) + revision := opts.ServiceRevision + + connectors, err := d.getConnectors(ctx, revision.EnvironmentID) + if err != nil { + return err + } + + proj, err := d.modelClient.Projects().Get(ctx, revision.ProjectID) if err != nil { return err } - project, err := d.modelClient.Projects().Get(ctx, opts.Service.ProjectID) + env, err := dao.GetEnvironmentByID(ctx, d.modelClient, revision.EnvironmentID) if err != nil { return err } - environment, err := dao.GetEnvironmentByID(ctx, d.modelClient, opts.Service.EnvironmentID) + svc, err := d.modelClient.Services().Get(ctx, revision.ServiceID) if err != nil { return err } @@ -195,7 +198,7 @@ func (d Deployer) createK8sJob(ctx context.Context, opts createK8sJobOptions) er if sj.ID != "" { subjectID = sj.ID } else { - subjectID, err = pkgservice.GetSubjectID(opts.Service) + subjectID, err = pkgservice.GetSubjectID(svc) if err != nil { return err } @@ -210,15 +213,15 @@ func (d Deployer) createK8sJob(ctx context.Context, opts createK8sJobOptions) er SkipTLSVerify: opts.SkipTLSVerify, ServiceRevision: opts.ServiceRevision, Connectors: connectors, - ProjectID: opts.Service.ProjectID, - EnvironmentID: opts.Service.EnvironmentID, + ProjectID: proj.ID, + EnvironmentID: env.ID, SubjectID: subjectID, // Metadata. - ProjectName: project.Name, - EnvironmentName: environment.Name, - ServiceName: opts.Service.Name, - ServiceID: opts.Service.ID, - ManagedNamespaceName: pkgenv.GetManagedNamespaceName(environment), + ProjectName: proj.Name, + EnvironmentName: env.Name, + ServiceName: svc.Name, + ServiceID: svc.ID, + ManagedNamespaceName: pkgenv.GetManagedNamespaceName(env), } if err = d.createK8sSecrets(ctx, secretOpts); err != nil { return err @@ -370,12 +373,12 @@ func (d Deployer) createK8sSecrets(ctx context.Context, opts createK8sSecretsOpt } type createRevisionOptions struct { + // ServiceID indicates the ID of service which is for create the revision. + ServiceID object.ID // JobType indicates the type of the job. JobType string // Tags indicates the tags for the revision. Tags []string - // Service indicates the service to create the revision. - Service *model.Service } // createRevision creates a new service revision. @@ -386,68 +389,84 @@ func (d Deployer) createRevision( ctx context.Context, opts createRevisionOptions, ) (*model.ServiceRevision, error) { - tv, err := d.modelClient.TemplateVersions().Query(). - Where(templateversion.ID(opts.Service.TemplateID)). + // Validate if there is a running revision. + prevEntity, err := d.modelClient.ServiceRevisions().Query(). + Where(servicerevision.And( + servicerevision.ServiceID(opts.ServiceID), + servicerevision.DeployerType(DeployerType))). + Order(model.Desc(servicerevision.FieldCreateTime)). + First(ctx) + if err != nil && !model.IsNotFound(err) { + return nil, err + } + + if prevEntity != nil && prevEntity.Status == status.ServiceRevisionStatusRunning { + return nil, errors.New("service deployment is running") + } + + // Get the corresponding service and template version. + svc, err := d.modelClient.Services().Query(). + Where(service.ID(opts.ServiceID)). + WithTemplate(func(tvq *model.TemplateVersionQuery) { + tvq.Select( + templateversion.FieldName, + templateversion.FieldVersion) + }). Select( - templateversion.FieldName, - templateversion.FieldVersion). + service.FieldID, + service.FieldProjectID, + service.FieldEnvironmentID, + service.FieldAttributes). Only(ctx) if err != nil { return nil, err } entity := &model.ServiceRevision{ - ProjectID: opts.Service.ProjectID, - ServiceID: opts.Service.ID, - EnvironmentID: opts.Service.EnvironmentID, - TemplateName: tv.Name, - TemplateVersion: tv.Version, - Attributes: opts.Service.Attributes, + ProjectID: svc.ProjectID, + EnvironmentID: svc.EnvironmentID, + ServiceID: svc.ID, + TemplateName: svc.Edges.Template.Name, + TemplateVersion: svc.Edges.Template.Version, + Attributes: svc.Attributes, Tags: opts.Tags, DeployerType: DeployerType, Status: status.ServiceRevisionStatusRunning, } - // Output of the previous revision should be inherited to the new one - // when creating a new revision. - prevEntity, err := d.modelClient.ServiceRevisions().Query(). - Where(servicerevision.And( - servicerevision.ServiceID(opts.Service.ID), - servicerevision.DeployerType(DeployerType))). - Order(model.Desc(servicerevision.FieldCreateTime)). - First(ctx) - if err != nil && !model.IsNotFound(err) { - return nil, err - } - + // Inherit the output of previous revision to create a new one. if prevEntity != nil { - if prevEntity.Status == status.ServiceRevisionStatusRunning { - return nil, errors.New("service deployment is running") - } - - // Inherit the output of previous revision. entity.Output = prevEntity.Output + } - // Get required providers. - requiredProviders, err := d.getRequiredProviders(ctx, opts.Service.ID, entity.Output) + switch { + case opts.JobType == JobTypeApply && entity.Output != "": + // Get required providers from the previous output after first deployment. + requiredProviders, err := d.getRequiredProviders(ctx, opts.ServiceID, entity.Output) if err != nil { return nil, err } entity.PreviousRequiredProviders = requiredProviders + case opts.JobType == JobTypeDestroy && entity.Output != "": + if prevEntity.Status == status.ServiceRevisionStatusFailed { + // Get required providers from the previous output after first deployment. + requiredProviders, err := d.getRequiredProviders(ctx, opts.ServiceID, entity.Output) + if err != nil { + return nil, err + } + entity.PreviousRequiredProviders = requiredProviders + } else { + // Copy required providers from the previous revision. + entity.PreviousRequiredProviders = prevEntity.PreviousRequiredProviders + // Reuse other fields from the previous revision. + entity.TemplateName = prevEntity.TemplateName + entity.TemplateVersion = prevEntity.TemplateVersion + entity.Attributes = prevEntity.Attributes + entity.InputPlan = prevEntity.InputPlan + } } - if opts.JobType == JobTypeDestroy && - prevEntity != nil && - prevEntity.Status == status.ServiceRevisionStatusSucceeded { - entity.TemplateName = prevEntity.TemplateName - entity.TemplateVersion = prevEntity.TemplateVersion - entity.Attributes = prevEntity.Attributes - entity.InputPlan = prevEntity.InputPlan - entity.Output = prevEntity.Output - entity.PreviousRequiredProviders = prevEntity.PreviousRequiredProviders - } - - // Create revision, mark status to running. + // Create revision. entity, err = d.modelClient.ServiceRevisions().Create(). Set(entity). Save(ctx) @@ -455,8 +474,6 @@ func (d Deployer) createRevision( return nil, err } - entity.Edges.Service = opts.Service - return entity, nil } @@ -684,9 +701,9 @@ func (d Deployer) getModuleConfig( return mc, requiredProviders, err } -func (d Deployer) getConnectors(ctx context.Context, ai *model.Service) (model.Connectors, error) { +func (d Deployer) getConnectors(ctx context.Context, environmentID object.ID) (model.Connectors, error) { rs, err := d.modelClient.EnvironmentConnectorRelationships().Query(). - Where(environmentconnectorrelationship.EnvironmentID(ai.EnvironmentID)). + Where(environmentconnectorrelationship.EnvironmentID(environmentID)). WithConnector(func(cq *model.ConnectorQuery) { cq.Select( connector.FieldID, @@ -1060,12 +1077,12 @@ func getVarConfigOptions(variables model.Variables, serviceOutputs map[string]pa func getModuleConfig( revision *model.ServiceRevision, - modVer *model.TemplateVersion, - ops createK8sSecretsOptions, + template *model.TemplateVersion, + opts createK8sSecretsOptions, ) (*config.ModuleConfig, error) { var ( props = make(property.Properties, len(revision.Attributes)) - typesWith = revision.Attributes.TypesWith(modVer.Schema.Variables) + typesWith = revision.Attributes.TypesWith(template.Schema.Variables) sensitiveVariables = sets.Set[string]{} ) @@ -1082,17 +1099,17 @@ func getModuleConfig( } mc := &config.ModuleConfig{ - Name: revision.Edges.Service.Name, - Source: modVer.Source, - Schema: modVer.Schema, + Name: opts.ServiceName, + Source: template.Source, + Schema: template.Schema, Attributes: attrs, } - if modVer.Schema == nil { + if template.Schema == nil { return mc, nil } - for _, v := range modVer.Schema.Variables { + for _, v := range template.Schema.Variables { // Add sensitive from schema variable. if v.Sensitive { sensitiveVariables.Insert(fmt.Sprintf(`var\.%s`, v.Name)) @@ -1103,19 +1120,19 @@ func getModuleConfig( switch v.Name { case SealMetadataProjectName: - attrValue = ops.ProjectName + attrValue = opts.ProjectName case SealMetadataEnvironmentName: - attrValue = ops.EnvironmentName + attrValue = opts.EnvironmentName case SealMetadataServiceName: - attrValue = ops.ServiceName + attrValue = opts.ServiceName case SealMetadataProjectID: - attrValue = ops.ProjectID.String() + attrValue = opts.ProjectID.String() case SealMetadataEnvironmentID: - attrValue = ops.EnvironmentID.String() + attrValue = opts.EnvironmentID.String() case SealMetadataServiceID: - attrValue = ops.ServiceID.String() + attrValue = opts.ServiceID.String() case SealMetadataNamespaceName: - attrValue = ops.ManagedNamespaceName + attrValue = opts.ManagedNamespaceName } if attrValue != "" { @@ -1128,11 +1145,11 @@ func getModuleConfig( return nil, err } - mc.Outputs = make([]config.Output, len(modVer.Schema.Outputs)) - for i, v := range modVer.Schema.Outputs { + mc.Outputs = make([]config.Output, len(template.Schema.Outputs)) + for i, v := range template.Schema.Outputs { mc.Outputs[i].Sensitive = v.Sensitive mc.Outputs[i].Name = v.Name - mc.Outputs[i].ServiceName = revision.Edges.Service.Name + mc.Outputs[i].ServiceName = opts.ServiceName mc.Outputs[i].Value = v.Value if v.Sensitive { diff --git a/pkg/deployer/terraform/syncer.go b/pkg/deployer/terraform/syncer.go index d67eb8117..b7ba1735a 100644 --- a/pkg/deployer/terraform/syncer.go +++ b/pkg/deployer/terraform/syncer.go @@ -8,7 +8,7 @@ import ( "github.com/seal-io/seal/pkg/dao/types/status" ) -// SyncServiceRevisionStatus updates the status of the service according to its recent finished service revision +// SyncServiceRevisionStatus updates the status of the service according to its recent finished service revision. func SyncServiceRevisionStatus(ctx context.Context, bm revisionbus.BusMessage) (err error) { var ( mc = bm.TransactionalModelClient