From c0e68605f48f3f686957d7d70569c1181faba68b Mon Sep 17 00:00:00 2001 From: Vikyath Harekal Date: Tue, 8 Apr 2025 13:32:36 +0000 Subject: [PATCH] feat: [CDE-666]: Changes for suspend/resume flow (#3644) * feat: [CDE-666]: fix lint * feat: [CDE-666]: Changes for suspend/resume flow --- app/gitspace/infrastructure/find.go | 19 +++++++++ .../infrastructure/trigger_infra_event.go | 39 ++++++++++++++++--- app/store/database.go | 4 ++ app/store/database/infra_provisioned.go | 34 ++++++++++++++++ infraprovider/docker_provider.go | 1 + infraprovider/infra_provider.go | 1 + types/enum/gitspace_instance_state_type.go | 1 + types/gitspace.go | 4 +- 8 files changed, 95 insertions(+), 8 deletions(-) diff --git a/app/gitspace/infrastructure/find.go b/app/gitspace/infrastructure/find.go index a8d45a01e..8fe3943d2 100644 --- a/app/gitspace/infrastructure/find.go +++ b/app/gitspace/infrastructure/find.go @@ -169,6 +169,25 @@ func (i InfraProvisioner) GetInfraFromStoredInfo( return &infra, nil } +func (i InfraProvisioner) GetStoppedInfraFromStoredInfo( + ctx context.Context, + gitspaceConfig types.GitspaceConfig, +) (*types.Infrastructure, error) { + infraProvisioned, err := i.infraProvisionedStore.FindStoppedInfraForGitspaceConfigIdentifier( + ctx, + gitspaceConfig.Identifier, + ) + if err != nil { + return nil, fmt.Errorf("failed to find infraProvisioned: %w", err) + } + var infra types.Infrastructure + err = json.Unmarshal([]byte(*infraProvisioned.ResponseMetadata), &infra) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal response metadata: %w", err) + } + return &infra, nil +} + // Methods to find infra provider resources. func (i InfraProvisioner) getConfigFromResource( ctx context.Context, diff --git a/app/gitspace/infrastructure/trigger_infra_event.go b/app/gitspace/infrastructure/trigger_infra_event.go index f869fc2af..3d0427bba 100644 --- a/app/gitspace/infrastructure/trigger_infra_event.go +++ b/app/gitspace/infrastructure/trigger_infra_event.go @@ -89,6 +89,7 @@ func (i InfraProvisioner) TriggerInfraEventWithOpts( infra *types.Infrastructure, opts InfraEventOpts, ) error { + logger := log.Logger.With().Logger() infraProviderEntity, err := i.getConfigFromResource(ctx, gitspaceConfig.InfraProviderResource) if err != nil { return err @@ -106,11 +107,33 @@ func (i InfraProvisioner) TriggerInfraEventWithOpts( switch eventType { case enum.InfraEventProvision: - if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew { - return i.provisionNewInfrastructure(ctx, infraProvider, infraProviderEntity.Type, - gitspaceConfig, opts.RequiredGitspacePorts) + var stoppedInfra *types.Infrastructure + stoppedInfra, err = i.GetStoppedInfraFromStoredInfo(ctx, gitspaceConfig) + if err != nil { + logger.Info(). + Str("error", err.Error()). + Msgf( + "could not find stopped infra provisioned entity for instance %s", + gitspaceConfig.Identifier, + ) } - return i.provisionExistingInfrastructure(ctx, infraProvider, gitspaceConfig, opts.RequiredGitspacePorts) + if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew { + return i.provisionNewInfrastructure( + ctx, + infraProvider, + infraProviderEntity.Type, + gitspaceConfig, + opts.RequiredGitspacePorts, + stoppedInfra, + ) + } + return i.provisionExistingInfrastructure( + ctx, + infraProvider, + gitspaceConfig, + opts.RequiredGitspacePorts, + stoppedInfra, + ) case enum.InfraEventDeprovision: if infraProvider.ProvisioningType() == enum.InfraProvisioningTypeNew { @@ -142,6 +165,7 @@ func (i InfraProvisioner) provisionNewInfrastructure( infraProviderType enum.InfraProviderType, gitspaceConfig types.GitspaceConfig, requiredGitspacePorts []types.GitspacePort, + stoppedInfra *types.Infrastructure, ) error { // Logic for new provisioning... infraProvisionedLatest, _ := i.infraProvisionedStore.FindLatestByGitspaceInstanceID( @@ -181,11 +205,13 @@ func (i InfraProvisioner) provisionNewInfrastructure( SpacePath: gitspaceConfig.SpacePath, GitspaceConfigIdentifier: gitspaceConfig.Identifier, GitspaceInstanceIdentifier: gitspaceConfig.GitspaceInstance.Identifier, - GitspaceInstanceID: gitspaceConfig.GitspaceInstance.ID, ProviderType: infraProviderType, InputParameters: allParams, ConfigMetadata: configMetadata, } + if stoppedInfra != nil { + infrastructure.InstanceInfo = stoppedInfra.InstanceInfo + } responseMetadata, err := json.Marshal(infrastructure) if err != nil { return fmt.Errorf("unable to marshal infra object %+v: %w", responseMetadata, err) @@ -222,6 +248,7 @@ func (i InfraProvisioner) provisionNewInfrastructure( requiredGitspacePorts, allParams, configMetadata, + infrastructure, ) if err != nil { infraProvisioned.InfraStatus = enum.InfraStatusUnknown @@ -246,6 +273,7 @@ func (i InfraProvisioner) provisionExistingInfrastructure( infraProvider infraprovider.InfraProvider, gitspaceConfig types.GitspaceConfig, requiredGitspacePorts []types.GitspacePort, + stoppedInfra *types.Infrastructure, ) error { allParams, configMetadata, err := i.getAllParamsFromDB(ctx, gitspaceConfig.InfraProviderResource, infraProvider) if err != nil { @@ -268,6 +296,7 @@ func (i InfraProvisioner) provisionExistingInfrastructure( requiredGitspacePorts, allParams, configMetadata, + *stoppedInfra, ) if err != nil { return fmt.Errorf( diff --git a/app/store/database.go b/app/store/database.go index 7766c4043..546396e35 100644 --- a/app/store/database.go +++ b/app/store/database.go @@ -1326,6 +1326,10 @@ type ( spaceID int64, gitspaceInstanceIdentifier string, ) (*types.InfraProvisioned, error) + FindStoppedInfraForGitspaceConfigIdentifier( + ctc context.Context, + gitspaceConfigIdentifier string, + ) (*types.InfraProvisioned, error) Create(ctx context.Context, infraProvisioned *types.InfraProvisioned) error Delete(ctx context.Context, id int64) error Update(ctx context.Context, infraProvisioned *types.InfraProvisioned) error diff --git a/app/store/database/infra_provisioned.go b/app/store/database/infra_provisioned.go index 108fbda07..168826e07 100644 --- a/app/store/database/infra_provisioned.go +++ b/app/store/database/infra_provisioned.go @@ -206,6 +206,40 @@ func (i infraProvisionedStore) FindLatestByGitspaceInstanceIdentifier( return entity.toDTO(), nil } +func (i infraProvisionedStore) FindStoppedInfraForGitspaceConfigIdentifier( + ctx context.Context, + gitspaceConfigIdentifier string, +) (*types.InfraProvisioned, error) { + gitsSubQuery := fmt.Sprintf(` + SELECT gits.gits_id + FROM %s gits + JOIN %s conf ON gits.gits_gitspace_config_id = conf.gconf_id + WHERE conf.gconf_uid = '%s' AND gits.gits_state = 'starting' + LIMIT 1`, + gitspaceInstanceTable, gitspaceConfigsTable, gitspaceConfigIdentifier) + + // Build the main query + stmt := database.Builder. + Select(infraProvisionedSelectColumns). + From(infraProvisionedTable). + Where("iprov_infra_status = ?", enum.InfraStatusStopped). + Join(fmt.Sprintf("(%s) AS gits ON iprov_gitspace_id = gits.gits_id", gitsSubQuery)) + + sql, args, err := stmt.ToSql() + if err != nil { + return nil, errors.Wrap(err, "Failed to convert squirrel builder to sql") + } + + entity := new(infraProvisioned) + db := dbtx.GetAccessor(ctx, i.db) + if err := db.GetContext(ctx, entity, sql, args...); err != nil { + return nil, database.ProcessSQLErrorf( + ctx, err, "Failed to find last stopped infraprovisioned for config %s", gitspaceConfigIdentifier) + } + + return entity.toDTO(), nil +} + func (i infraProvisionedStore) Create(ctx context.Context, infraProvisioned *types.InfraProvisioned) error { stmt := database.Builder. Insert(infraProvisionedTable). diff --git a/infraprovider/docker_provider.go b/infraprovider/docker_provider.go index c97bd5ca0..1ded15ee6 100644 --- a/infraprovider/docker_provider.go +++ b/infraprovider/docker_provider.go @@ -61,6 +61,7 @@ func (d DockerProvider) Provision( requiredGitspacePorts []types.GitspacePort, inputParameters []types.InfraProviderParameter, _ map[string]any, + _ types.Infrastructure, ) error { dockerClient, err := d.dockerClientFactory.NewDockerClient(ctx, types.Infrastructure{ ProviderType: enum.InfraProviderTypeDocker, diff --git a/infraprovider/infra_provider.go b/infraprovider/infra_provider.go index 3aa494cdf..bf0733604 100644 --- a/infraprovider/infra_provider.go +++ b/infraprovider/infra_provider.go @@ -34,6 +34,7 @@ type InfraProvider interface { requiredGitspacePorts []types.GitspacePort, inputParameters []types.InfraProviderParameter, configMetadata map[string]any, + infrastructure types.Infrastructure, ) error // Find finds infrastructure provisioned against a gitspace. diff --git a/types/enum/gitspace_instance_state_type.go b/types/enum/gitspace_instance_state_type.go index be61fd11c..703a8b649 100644 --- a/types/enum/gitspace_instance_state_type.go +++ b/types/enum/gitspace_instance_state_type.go @@ -37,6 +37,7 @@ const ( GitspaceInstanceStateUninitialized GitspaceInstanceStateType = "uninitialized" GitspaceInstanceStateUnknown GitspaceInstanceStateType = "unknown" GitspaceInstanceStateError GitspaceInstanceStateType = "error" + GitspaceInstanceStateStopped GitspaceInstanceStateType = "stopped" GitspaceInstanceStateDeleted GitspaceInstanceStateType = "deleted" GitspaceInstanceStateCleaned GitspaceInstanceStateType = "cleaned" diff --git a/types/gitspace.go b/types/gitspace.go index 053e3af74..6e7bfb203 100644 --- a/types/gitspace.go +++ b/types/gitspace.go @@ -116,7 +116,7 @@ func (g *GitspaceInstance) GetGitspaceState() (enum.GitspaceStateType, error) { switch instanceState { case enum.GitspaceInstanceStateRunning: return enum.GitspaceStateRunning, nil - case enum.GitspaceInstanceStateDeleted: + case enum.GitspaceInstanceStateStopped, enum.GitspaceInstanceStateDeleted, enum.GitspaceInstanceStateCleaned: return enum.GitspaceStateStopped, nil case emptyGitspaceInstanceState, enum.GitspaceInstanceStateUninitialized: return enum.GitspaceStateUninitialized, nil @@ -128,8 +128,6 @@ func (g *GitspaceInstance) GetGitspaceState() (enum.GitspaceStateType, error) { case enum.GitspaceInstanceStateStopping, enum.GitSpaceInstanceStateCleaning: return enum.GitspaceStateStopping, nil - case enum.GitspaceInstanceStateCleaned: - return enum.GitspaceStateStopped, nil default: return enum.GitspaceStateError, fmt.Errorf("unsupported gitspace instance state %s", string(instanceState)) }