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 {
|
switch in.Action {
|
||||||
case enum.GitspaceActionTypeStart:
|
case enum.GitspaceActionTypeStart:
|
||||||
c.emitGitspaceConfigEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStart)
|
c.emitGitspaceConfigEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStart)
|
||||||
gitspace, err := c.startGitspace(ctx, gitspaceConfig)
|
gitspace, err := c.startGitspaceAction(ctx, gitspaceConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.emitGitspaceConfigEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStartFailed)
|
c.emitGitspaceConfigEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStartFailed)
|
||||||
}
|
}
|
||||||
return gitspace, err
|
return gitspace, err
|
||||||
case enum.GitspaceActionTypeStop:
|
case enum.GitspaceActionTypeStop:
|
||||||
c.emitGitspaceConfigEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStop)
|
c.emitGitspaceConfigEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStop)
|
||||||
gitspace, err := c.stopGitspace(ctx, gitspaceConfig)
|
gitspace, err := c.stopGitspaceAction(ctx, gitspaceConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.emitGitspaceConfigEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStopFailed)
|
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)
|
savedGitspaceInstance, err := c.gitspaceInstanceStore.FindLatestByGitspaceConfigID(ctx, config.ID, config.SpaceID)
|
||||||
const resourceNotFoundErr = "Failed to find gitspace: resource not found"
|
const resourceNotFoundErr = "Failed to find gitspace: resource not found"
|
||||||
if err != nil && err.Error() != resourceNotFoundErr { // TODO fix this
|
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)
|
return nil, fmt.Errorf("failed to find gitspace with config ID : %s %w", config.Identifier, err)
|
||||||
}
|
}
|
||||||
config.GitspaceInstance = newGitspaceInstance
|
config.GitspaceInstance = newGitspaceInstance
|
||||||
updatedGitspace, err := c.orchestrator.StartGitspace(ctx, config)
|
config.State, _ = enum.GetGitspaceStateFromInstance(newGitspaceInstance.State)
|
||||||
if err != nil {
|
ctx2 := context.WithoutCancel(ctx)
|
||||||
return nil, fmt.Errorf("failed to find start gitspace : %s %w", config.Identifier, err)
|
go func() {
|
||||||
|
_, _ = c.startAsyncOperation(ctx2, config)
|
||||||
|
}()
|
||||||
|
return config, nil
|
||||||
}
|
}
|
||||||
if err = c.gitspaceInstanceStore.Update(ctx, updatedGitspace); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to update gitspace %w", err)
|
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 orchestrateErr != nil {
|
||||||
|
return nil, fmt.Errorf("failed to find start gitspace : %s %w", config.Identifier, orchestrateErr)
|
||||||
}
|
}
|
||||||
config.GitspaceInstance = updatedGitspace
|
config.GitspaceInstance = updatedGitspace
|
||||||
config.State, _ = enum.GetGitspaceStateFromInstance(updatedGitspace.State)
|
config.State, _ = enum.GetGitspaceStateFromInstance(updatedGitspace.State)
|
||||||
|
@ -156,8 +171,9 @@ func (c *Controller) gitspaceBusyOperation(
|
||||||
if config.GitspaceInstance == nil {
|
if config.GitspaceInstance == nil {
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
const timedOutInSeconds = 5
|
||||||
if config.GitspaceInstance.State.IsBusyStatus() &&
|
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)
|
return nil, fmt.Errorf("gitspace start/stop is already pending for : %q", config.Identifier)
|
||||||
} else if config.GitspaceInstance.State.IsBusyStatus() {
|
} else if config.GitspaceInstance.State.IsBusyStatus() {
|
||||||
config.GitspaceInstance.State = enum.GitspaceInstanceStateError
|
config.GitspaceInstance.State = enum.GitspaceInstanceStateError
|
||||||
|
@ -168,7 +184,10 @@ func (c *Controller) gitspaceBusyOperation(
|
||||||
return config, nil
|
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)
|
savedGitspace, err := c.gitspaceInstanceStore.FindLatestByGitspaceConfigID(ctx, config.ID, config.SpaceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to find gitspace with config ID : %s %w", config.Identifier, err)
|
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 {
|
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)
|
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 {
|
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(
|
return nil, fmt.Errorf(
|
||||||
"failed to stop gitspace instance with ID %s %w", savedGitspace.Identifier, stopErr)
|
"unable to update the gitspace with config id %s %w %w",
|
||||||
} else if updatedGitspace != nil {
|
savedGitspace.Identifier,
|
||||||
if stopErr = c.gitspaceInstanceStore.Update(ctx, updatedGitspace); stopErr != nil {
|
err,
|
||||||
|
orchestrateErr)
|
||||||
|
}
|
||||||
|
if orchestrateErr != nil {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"unable to update the gitspace with config id %s %w", savedGitspace.Identifier, stopErr)
|
"failed to stop gitspace instance with ID %s %w", savedGitspace.Identifier, orchestrateErr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
config.GitspaceInstance = updatedGitspace
|
config.GitspaceInstance = updatedGitspace
|
||||||
config.State, _ = enum.GetGitspaceStateFromInstance(updatedGitspace.State)
|
config.State, _ = enum.GetGitspaceStateFromInstance(updatedGitspace.State)
|
||||||
}
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,8 @@ func (o orchestrator) StartGitspace(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
gitspaceConfig *types.GitspaceConfig,
|
gitspaceConfig *types.GitspaceConfig,
|
||||||
) (*types.GitspaceInstance, error) {
|
) (*types.GitspaceInstance, error) {
|
||||||
|
gitspaceInstance := gitspaceConfig.GitspaceInstance
|
||||||
|
gitspaceInstance.State = enum.GitspaceInstanceStateError
|
||||||
devcontainerConfig, err := o.scm.DevcontainerConfig(ctx, gitspaceConfig)
|
devcontainerConfig, err := o.scm.DevcontainerConfig(ctx, gitspaceConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn().Err(err).Msg("devcontainerConfig fetch failed.")
|
log.Warn().Err(err).Msg("devcontainerConfig fetch failed.")
|
||||||
|
@ -69,24 +71,19 @@ func (o orchestrator) StartGitspace(
|
||||||
|
|
||||||
infraProviderResource, err := o.infraProviderResourceStore.Find(ctx, gitspaceConfig.InfraProviderResourceID)
|
infraProviderResource, err := o.infraProviderResourceStore.Find(ctx, gitspaceConfig.InfraProviderResourceID)
|
||||||
if err != nil {
|
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)
|
gitspaceConfig.InfraProviderResourceID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
infra, err := o.infraProvisioner.Provision(ctx, infraProviderResource, gitspaceConfig)
|
infra, err := o.infraProvisioner.Provision(ctx, infraProviderResource, gitspaceConfig)
|
||||||
if err != nil {
|
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)
|
gitspaceConfig.InfraProviderResourceID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gitspaceInstance := gitspaceConfig.GitspaceInstance
|
|
||||||
|
|
||||||
err = o.containerOrchestrator.Status(ctx, infra)
|
err = o.containerOrchestrator.Status(ctx, infra)
|
||||||
gitspaceInstance.State = enum.GitspaceInstanceStateError
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gitspaceInstance, fmt.Errorf("couldn't call the agent health API: %w", err)
|
return gitspaceInstance, fmt.Errorf("couldn't call the agent health API: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
startResponse, err := o.containerOrchestrator.StartGitspace(ctx, gitspaceConfig, devcontainerConfig, infra)
|
startResponse, err := o.containerOrchestrator.StartGitspace(ctx, gitspaceConfig, devcontainerConfig, infra)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gitspaceInstance, fmt.Errorf("couldn't call the agent start API: %w", err)
|
return gitspaceInstance, fmt.Errorf("couldn't call the agent start API: %w", err)
|
||||||
|
@ -141,6 +138,8 @@ func (o orchestrator) StopGitspace(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
gitspaceConfig *types.GitspaceConfig,
|
gitspaceConfig *types.GitspaceConfig,
|
||||||
) (*types.GitspaceInstance, error) {
|
) (*types.GitspaceInstance, error) {
|
||||||
|
gitspaceInstance := gitspaceConfig.GitspaceInstance
|
||||||
|
gitspaceInstance.State = enum.GitspaceInstanceStateError
|
||||||
infraProviderResource, err := o.infraProviderResourceStore.Find(ctx, gitspaceConfig.InfraProviderResourceID)
|
infraProviderResource, err := o.infraProviderResourceStore.Find(ctx, gitspaceConfig.InfraProviderResourceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
|
@ -149,21 +148,19 @@ func (o orchestrator) StopGitspace(
|
||||||
|
|
||||||
infra, err := o.infraProvisioner.Find(ctx, infraProviderResource, gitspaceConfig)
|
infra, err := o.infraProvisioner.Find(ctx, infraProviderResource, gitspaceConfig)
|
||||||
if err != nil {
|
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)
|
err = o.containerOrchestrator.StopGitspace(ctx, gitspaceConfig, infra)
|
||||||
if err != nil {
|
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)
|
_, err = o.infraProvisioner.Stop(ctx, infraProviderResource, gitspaceConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return gitspaceInstance, fmt.Errorf(
|
||||||
"cannot stop provisioned infrastructure with ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
|
"cannot stop provisioned infrastructure with ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gitspaceInstance := gitspaceConfig.GitspaceInstance
|
|
||||||
gitspaceInstance.State = enum.GitspaceInstanceStateDeleted
|
gitspaceInstance.State = enum.GitspaceInstanceStateDeleted
|
||||||
return gitspaceInstance, err
|
return gitspaceInstance, err
|
||||||
}
|
}
|
||||||
|
@ -173,13 +170,15 @@ func (o orchestrator) DeleteGitspace(
|
||||||
gitspaceConfig *types.GitspaceConfig,
|
gitspaceConfig *types.GitspaceConfig,
|
||||||
) (*types.GitspaceInstance, error) {
|
) (*types.GitspaceInstance, error) {
|
||||||
gitspaceInstance := gitspaceConfig.GitspaceInstance
|
gitspaceInstance := gitspaceConfig.GitspaceInstance
|
||||||
|
currentState := gitspaceInstance.State
|
||||||
|
gitspaceInstance.State = enum.GitspaceInstanceStateError
|
||||||
infraProviderResource, err := o.infraProviderResourceStore.Find(ctx, gitspaceConfig.InfraProviderResourceID)
|
infraProviderResource, err := o.infraProviderResourceStore.Find(ctx, gitspaceConfig.InfraProviderResourceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"cannot get the infraProviderResource with ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
|
"cannot get the infraProviderResource with ID %d: %w", gitspaceConfig.InfraProviderResourceID, err)
|
||||||
}
|
}
|
||||||
if gitspaceInstance.State == enum.GitspaceInstanceStateRunning ||
|
if currentState == enum.GitspaceInstanceStateRunning ||
|
||||||
gitspaceInstance.State == enum.GitspaceInstanceStateUnknown {
|
currentState == enum.GitspaceInstanceStateUnknown {
|
||||||
infra, err := o.infraProvisioner.Find(ctx, infraProviderResource, gitspaceConfig)
|
infra, err := o.infraProvisioner.Find(ctx, infraProviderResource, gitspaceConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot find the provisioned infra: %w", err)
|
return nil, fmt.Errorf("cannot find the provisioned infra: %w", err)
|
||||||
|
|
|
@ -42,7 +42,7 @@ const (
|
||||||
|
|
||||||
func GetGitspaceStateFromInstance(
|
func GetGitspaceStateFromInstance(
|
||||||
instanceState GitspaceInstanceStateType) (GitspaceStateType, error) {
|
instanceState GitspaceInstanceStateType) (GitspaceStateType, error) {
|
||||||
switch instanceState { //nolint:exhaustive
|
switch instanceState {
|
||||||
case GitspaceInstanceStateRunning:
|
case GitspaceInstanceStateRunning:
|
||||||
return GitspaceStateRunning, nil
|
return GitspaceStateRunning, nil
|
||||||
case GitspaceInstanceStateDeleted:
|
case GitspaceInstanceStateDeleted:
|
||||||
|
@ -53,6 +53,9 @@ func GetGitspaceStateFromInstance(
|
||||||
return GitspaceStateStopping, nil
|
return GitspaceStateStopping, nil
|
||||||
case GitspaceInstanceStateUninitialized:
|
case GitspaceInstanceStateUninitialized:
|
||||||
return GitspaceStateUninitialized, nil
|
return GitspaceStateUninitialized, nil
|
||||||
|
case GitspaceInstanceStateError,
|
||||||
|
GitspaceInstanceStateUnknown:
|
||||||
|
return GitspaceStateError, nil
|
||||||
default:
|
default:
|
||||||
return GitspaceStateError, fmt.Errorf("unsupported gitspace instance state %s", string(instanceState))
|
return GitspaceStateError, fmt.Errorf("unsupported gitspace instance state %s", string(instanceState))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue