mirror of https://github.com/harness/drone.git
feat: [CDE-137]: made gitspace actions async and refactored orchestrator to handle errors correctly (#2194)
* feat: [CDE-137]: made gitspace actions async and refactored orchestrator to handle errors correctlyunified-ui
parent
87157de7fa
commit
61f1bc55fe
|
@ -66,14 +66,14 @@ func (c *Controller) Action(
|
|||
switch in.Action {
|
||||
case enum.GitspaceActionTypeStart:
|
||||
c.emitGitspaceConfigEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStart)
|
||||
gitspace, err := c.startGitspace(ctx, gitspaceConfig)
|
||||
gitspace, err := c.startGitspaceAction(ctx, gitspaceConfig)
|
||||
if err != nil {
|
||||
c.emitGitspaceConfigEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStartFailed)
|
||||
}
|
||||
return gitspace, err
|
||||
case enum.GitspaceActionTypeStop:
|
||||
c.emitGitspaceConfigEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStop)
|
||||
gitspace, err := c.stopGitspace(ctx, gitspaceConfig)
|
||||
gitspace, err := c.stopGitspaceAction(ctx, gitspaceConfig)
|
||||
if err != nil {
|
||||
c.emitGitspaceConfigEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStopFailed)
|
||||
}
|
||||
|
@ -83,7 +83,10 @@ func (c *Controller) Action(
|
|||
}
|
||||
}
|
||||
|
||||
func (c *Controller) startGitspace(ctx context.Context, config *types.GitspaceConfig) (*types.GitspaceConfig, error) {
|
||||
func (c *Controller) startGitspaceAction(
|
||||
ctx context.Context,
|
||||
config *types.GitspaceConfig,
|
||||
) (*types.GitspaceConfig, error) {
|
||||
savedGitspaceInstance, err := c.gitspaceInstanceStore.FindLatestByGitspaceConfigID(ctx, config.ID, config.SpaceID)
|
||||
const resourceNotFoundErr = "Failed to find gitspace: resource not found"
|
||||
if err != nil && err.Error() != resourceNotFoundErr { // TODO fix this
|
||||
|
@ -109,12 +112,24 @@ func (c *Controller) startGitspace(ctx context.Context, config *types.GitspaceCo
|
|||
return nil, fmt.Errorf("failed to find gitspace with config ID : %s %w", config.Identifier, err)
|
||||
}
|
||||
config.GitspaceInstance = newGitspaceInstance
|
||||
updatedGitspace, err := c.orchestrator.StartGitspace(ctx, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find start gitspace : %s %w", config.Identifier, err)
|
||||
config.State, _ = enum.GetGitspaceStateFromInstance(newGitspaceInstance.State)
|
||||
ctx2 := context.WithoutCancel(ctx)
|
||||
go func() {
|
||||
_, _ = c.startAsyncOperation(ctx2, config)
|
||||
}()
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (c *Controller) startAsyncOperation(
|
||||
ctx context.Context,
|
||||
config *types.GitspaceConfig,
|
||||
) (*types.GitspaceConfig, error) {
|
||||
updatedGitspace, orchestrateErr := c.orchestrator.StartGitspace(ctx, config)
|
||||
if err := c.gitspaceInstanceStore.Update(ctx, updatedGitspace); err != nil {
|
||||
return nil, fmt.Errorf("failed to update gitspace %w %w", err, orchestrateErr)
|
||||
}
|
||||
if err = c.gitspaceInstanceStore.Update(ctx, updatedGitspace); err != nil {
|
||||
return nil, fmt.Errorf("failed to update gitspace %w", err)
|
||||
if orchestrateErr != nil {
|
||||
return nil, fmt.Errorf("failed to find start gitspace : %s %w", config.Identifier, orchestrateErr)
|
||||
}
|
||||
config.GitspaceInstance = updatedGitspace
|
||||
config.State, _ = enum.GetGitspaceStateFromInstance(updatedGitspace.State)
|
||||
|
@ -156,8 +171,9 @@ func (c *Controller) gitspaceBusyOperation(
|
|||
if config.GitspaceInstance == nil {
|
||||
return config, nil
|
||||
}
|
||||
const timedOutInSeconds = 5
|
||||
if config.GitspaceInstance.State.IsBusyStatus() &&
|
||||
time.Since(time.UnixMilli(config.Updated)) <= (10*60*1000) {
|
||||
time.Since(time.UnixMilli(config.GitspaceInstance.Updated)).Milliseconds() <= (timedOutInSeconds*60*1000) {
|
||||
return nil, fmt.Errorf("gitspace start/stop is already pending for : %q", config.Identifier)
|
||||
} else if config.GitspaceInstance.State.IsBusyStatus() {
|
||||
config.GitspaceInstance.State = enum.GitspaceInstanceStateError
|
||||
|
@ -168,7 +184,10 @@ func (c *Controller) gitspaceBusyOperation(
|
|||
return config, nil
|
||||
}
|
||||
|
||||
func (c *Controller) stopGitspace(ctx context.Context, config *types.GitspaceConfig) (*types.GitspaceConfig, error) {
|
||||
func (c *Controller) stopGitspaceAction(
|
||||
ctx context.Context,
|
||||
config *types.GitspaceConfig,
|
||||
) (*types.GitspaceConfig, error) {
|
||||
savedGitspace, err := c.gitspaceInstanceStore.FindLatestByGitspaceConfigID(ctx, config.ID, config.SpaceID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find gitspace with config ID : %s %w", config.Identifier, err)
|
||||
|
@ -186,17 +205,35 @@ func (c *Controller) stopGitspace(ctx context.Context, config *types.GitspaceCon
|
|||
if err = c.gitspaceInstanceStore.Update(ctx, config.GitspaceInstance); err != nil {
|
||||
return nil, fmt.Errorf("failed to update gitspace config for stopping %s %w", config.Identifier, err)
|
||||
}
|
||||
if updatedGitspace, stopErr := c.orchestrator.StopGitspace(ctx, config); stopErr != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"failed to stop gitspace instance with ID %s %w", savedGitspace.Identifier, stopErr)
|
||||
} else if updatedGitspace != nil {
|
||||
if stopErr = c.gitspaceInstanceStore.Update(ctx, updatedGitspace); stopErr != nil {
|
||||
config.State, _ = enum.GetGitspaceStateFromInstance(savedGitspace.State)
|
||||
ctx2 := context.WithoutCancel(ctx)
|
||||
go func() {
|
||||
_, _ = c.stopAsyncOperation(ctx2, config)
|
||||
}()
|
||||
return config, err
|
||||
}
|
||||
|
||||
func (c *Controller) stopAsyncOperation(
|
||||
ctx context.Context,
|
||||
config *types.GitspaceConfig,
|
||||
) (*types.GitspaceConfig, error) {
|
||||
savedGitspace := config.GitspaceInstance
|
||||
updatedGitspace, orchestrateErr := c.orchestrator.StopGitspace(ctx, config)
|
||||
if updatedGitspace != nil {
|
||||
if err := c.gitspaceInstanceStore.Update(ctx, updatedGitspace); err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"unable to update the gitspace with config id %s %w", savedGitspace.Identifier, stopErr)
|
||||
"unable to update the gitspace with config id %s %w %w",
|
||||
savedGitspace.Identifier,
|
||||
err,
|
||||
orchestrateErr)
|
||||
}
|
||||
if orchestrateErr != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"failed to stop gitspace instance with ID %s %w", savedGitspace.Identifier, orchestrateErr)
|
||||
}
|
||||
config.GitspaceInstance = updatedGitspace
|
||||
config.State, _ = enum.GetGitspaceStateFromInstance(updatedGitspace.State)
|
||||
}
|
||||
config.GitspaceInstance = updatedGitspace
|
||||
config.State, _ = enum.GetGitspaceStateFromInstance(updatedGitspace.State)
|
||||
return config, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,8 @@ func (o orchestrator) StartGitspace(
|
|||
ctx context.Context,
|
||||
gitspaceConfig *types.GitspaceConfig,
|
||||
) (*types.GitspaceInstance, error) {
|
||||
gitspaceInstance := gitspaceConfig.GitspaceInstance
|
||||
gitspaceInstance.State = enum.GitspaceInstanceStateError
|
||||
devcontainerConfig, err := o.scm.DevcontainerConfig(ctx, gitspaceConfig)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("devcontainerConfig fetch failed.")
|
||||
|
@ -69,24 +71,19 @@ func (o orchestrator) StartGitspace(
|
|||
|
||||
infraProviderResource, err := o.infraProviderResourceStore.Find(ctx, gitspaceConfig.InfraProviderResourceID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get the infraProviderResource for ID %d: %w",
|
||||
return gitspaceInstance, fmt.Errorf("cannot get the infraProviderResource for ID %d: %w",
|
||||
gitspaceConfig.InfraProviderResourceID, err)
|
||||
}
|
||||
|
||||
infra, err := o.infraProvisioner.Provision(ctx, infraProviderResource, gitspaceConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot provision infrastructure for ID %d: %w",
|
||||
return gitspaceInstance, fmt.Errorf("cannot provision infrastructure for ID %d: %w",
|
||||
gitspaceConfig.InfraProviderResourceID, err)
|
||||
}
|
||||
|
||||
gitspaceInstance := gitspaceConfig.GitspaceInstance
|
||||
|
||||
err = o.containerOrchestrator.Status(ctx, infra)
|
||||
gitspaceInstance.State = enum.GitspaceInstanceStateError
|
||||
if err != nil {
|
||||
return gitspaceInstance, fmt.Errorf("couldn't call the agent health API: %w", err)
|
||||
}
|
||||
|
||||
startResponse, err := o.containerOrchestrator.StartGitspace(ctx, gitspaceConfig, devcontainerConfig, infra)
|
||||
if err != nil {
|
||||
return gitspaceInstance, fmt.Errorf("couldn't call the agent start API: %w", err)
|
||||
|
@ -141,6 +138,8 @@ func (o orchestrator) StopGitspace(
|
|||
ctx context.Context,
|
||||
gitspaceConfig *types.GitspaceConfig,
|
||||
) (*types.GitspaceInstance, error) {
|
||||
gitspaceInstance := gitspaceConfig.GitspaceInstance
|
||||
gitspaceInstance.State = enum.GitspaceInstanceStateError
|
||||
infraProviderResource, err := o.infraProviderResourceStore.Find(ctx, gitspaceConfig.InfraProviderResourceID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
|
@ -149,21 +148,19 @@ func (o orchestrator) StopGitspace(
|
|||
|
||||
infra, err := o.infraProvisioner.Find(ctx, infraProviderResource, gitspaceConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot find the provisioned infra: %w", err)
|
||||
return gitspaceInstance, fmt.Errorf("cannot find the provisioned infra: %w", err)
|
||||
}
|
||||
|
||||
err = o.containerOrchestrator.StopGitspace(ctx, gitspaceConfig, infra)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error stopping the Gitspace container: %w", err)
|
||||
return gitspaceInstance, fmt.Errorf("error stopping the Gitspace container: %w", err)
|
||||
}
|
||||
|
||||
_, err = o.infraProvisioner.Stop(ctx, infraProviderResource, gitspaceConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
return gitspaceInstance, fmt.Errorf(
|
||||
"cannot stop provisioned infrastructure with ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
|
||||
}
|
||||
|
||||
gitspaceInstance := gitspaceConfig.GitspaceInstance
|
||||
gitspaceInstance.State = enum.GitspaceInstanceStateDeleted
|
||||
return gitspaceInstance, err
|
||||
}
|
||||
|
@ -173,13 +170,15 @@ func (o orchestrator) DeleteGitspace(
|
|||
gitspaceConfig *types.GitspaceConfig,
|
||||
) (*types.GitspaceInstance, error) {
|
||||
gitspaceInstance := gitspaceConfig.GitspaceInstance
|
||||
currentState := gitspaceInstance.State
|
||||
gitspaceInstance.State = enum.GitspaceInstanceStateError
|
||||
infraProviderResource, err := o.infraProviderResourceStore.Find(ctx, gitspaceConfig.InfraProviderResourceID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"cannot get the infraProviderResource with ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
|
||||
}
|
||||
if gitspaceInstance.State == enum.GitspaceInstanceStateRunning ||
|
||||
gitspaceInstance.State == enum.GitspaceInstanceStateUnknown {
|
||||
if currentState == enum.GitspaceInstanceStateRunning ||
|
||||
currentState == enum.GitspaceInstanceStateUnknown {
|
||||
infra, err := o.infraProvisioner.Find(ctx, infraProviderResource, gitspaceConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot find the provisioned infra: %w", err)
|
||||
|
|
|
@ -42,7 +42,7 @@ const (
|
|||
|
||||
func GetGitspaceStateFromInstance(
|
||||
instanceState GitspaceInstanceStateType) (GitspaceStateType, error) {
|
||||
switch instanceState { //nolint:exhaustive
|
||||
switch instanceState {
|
||||
case GitspaceInstanceStateRunning:
|
||||
return GitspaceStateRunning, nil
|
||||
case GitspaceInstanceStateDeleted:
|
||||
|
@ -53,6 +53,9 @@ func GetGitspaceStateFromInstance(
|
|||
return GitspaceStateStopping, nil
|
||||
case GitspaceInstanceStateUninitialized:
|
||||
return GitspaceStateUninitialized, nil
|
||||
case GitspaceInstanceStateError,
|
||||
GitspaceInstanceStateUnknown:
|
||||
return GitspaceStateError, nil
|
||||
default:
|
||||
return GitspaceStateError, fmt.Errorf("unsupported gitspace instance state %s", string(instanceState))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue