mirror of https://github.com/harness/drone.git
feat: [CDE-430]: Providing a user friendly error message whenever an instance goes to error state. (#2977)
* feat: [CDE-430]: Providing a user friendly error message whenever an instance goes to error state.pull/3586/head
parent
42c76929c5
commit
1781c3be70
|
@ -226,7 +226,11 @@ func PullImage(
|
||||||
|
|
||||||
pullResponse, err := dockerClient.ImagePull(ctx, imageName, image.PullOptions{})
|
pullResponse, err := dockerClient.ImagePull(ctx, imageName, image.PullOptions{})
|
||||||
defer func() {
|
defer func() {
|
||||||
if closingErr := pullResponse.Close(); closingErr != nil {
|
if pullResponse == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
closingErr := pullResponse.Close()
|
||||||
|
if closingErr != nil {
|
||||||
log.Warn().Err(closingErr).Msg("failed to close image pull response")
|
log.Warn().Err(closingErr).Msg("failed to close image pull response")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
|
@ -23,25 +23,25 @@ import (
|
||||||
|
|
||||||
type Orchestrator interface {
|
type Orchestrator interface {
|
||||||
// TriggerStartGitspace fetches the infra resources configured for the gitspace and triggers the infra provisioning.
|
// TriggerStartGitspace fetches the infra resources configured for the gitspace and triggers the infra provisioning.
|
||||||
TriggerStartGitspace(ctx context.Context, gitspaceConfig types.GitspaceConfig) error
|
TriggerStartGitspace(ctx context.Context, gitspaceConfig types.GitspaceConfig) *types.GitspaceError
|
||||||
|
|
||||||
// ResumeStartGitspace saves the provisioned infra, resolves the code repo details & creates the Gitspace container.
|
// ResumeStartGitspace saves the provisioned infra, resolves the code repo details & creates the Gitspace container.
|
||||||
ResumeStartGitspace(
|
ResumeStartGitspace(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
gitspaceConfig types.GitspaceConfig,
|
gitspaceConfig types.GitspaceConfig,
|
||||||
provisionedInfra types.Infrastructure,
|
provisionedInfra types.Infrastructure,
|
||||||
) (types.GitspaceInstance, error)
|
) (types.GitspaceInstance, *types.GitspaceError)
|
||||||
|
|
||||||
// TriggerStopGitspace stops the Gitspace container and triggers infra deprovisioning to deprovision
|
// TriggerStopGitspace stops the Gitspace container and triggers infra deprovisioning to deprovision
|
||||||
// all the infra resources which are not required to restart the Gitspace.
|
// all the infra resources which are not required to restart the Gitspace.
|
||||||
TriggerStopGitspace(ctx context.Context, gitspaceConfig types.GitspaceConfig) error
|
TriggerStopGitspace(ctx context.Context, gitspaceConfig types.GitspaceConfig) *types.GitspaceError
|
||||||
|
|
||||||
// ResumeStopGitspace saves the deprovisioned infra details.
|
// ResumeStopGitspace saves the deprovisioned infra details.
|
||||||
ResumeStopGitspace(
|
ResumeStopGitspace(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
gitspaceConfig types.GitspaceConfig,
|
gitspaceConfig types.GitspaceConfig,
|
||||||
stoppedInfra types.Infrastructure,
|
stoppedInfra types.Infrastructure,
|
||||||
) (enum.GitspaceInstanceStateType, error)
|
) (enum.GitspaceInstanceStateType, *types.GitspaceError)
|
||||||
|
|
||||||
// TriggerCleanupInstanceResources cleans up all the resources exclusive to gitspace instance.
|
// TriggerCleanupInstanceResources cleans up all the resources exclusive to gitspace instance.
|
||||||
TriggerCleanupInstanceResources(ctx context.Context, gitspaceConfig types.GitspaceConfig) error
|
TriggerCleanupInstanceResources(ctx context.Context, gitspaceConfig types.GitspaceConfig) error
|
||||||
|
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/harness/gitness/types"
|
"github.com/harness/gitness/types"
|
||||||
"github.com/harness/gitness/types/enum"
|
"github.com/harness/gitness/types/enum"
|
||||||
|
|
||||||
|
"github.com/gotidy/ptr"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -37,19 +38,25 @@ func (o orchestrator) ResumeStartGitspace(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
gitspaceConfig types.GitspaceConfig,
|
gitspaceConfig types.GitspaceConfig,
|
||||||
provisionedInfra types.Infrastructure,
|
provisionedInfra types.Infrastructure,
|
||||||
) (types.GitspaceInstance, error) {
|
) (types.GitspaceInstance, *types.GitspaceError) {
|
||||||
gitspaceInstance := gitspaceConfig.GitspaceInstance
|
gitspaceInstance := gitspaceConfig.GitspaceInstance
|
||||||
gitspaceInstance.State = enum.GitspaceInstanceStateError
|
gitspaceInstance.State = enum.GitspaceInstanceStateError
|
||||||
|
|
||||||
secretResolver, err := o.getSecretResolver(gitspaceInstance.AccessType)
|
secretResolver, err := o.getSecretResolver(gitspaceInstance.AccessType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msgf("could not find secret resolver for type: %s", gitspaceInstance.AccessType)
|
log.Err(err).Msgf("could not find secret resolver for type: %s", gitspaceInstance.AccessType)
|
||||||
return *gitspaceInstance, err
|
return *gitspaceInstance, &types.GitspaceError{
|
||||||
|
Error: err,
|
||||||
|
ErrorMessage: ptr.String(err.Error()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rootSpaceID, _, err := paths.DisectRoot(gitspaceConfig.SpacePath)
|
rootSpaceID, _, err := paths.DisectRoot(gitspaceConfig.SpacePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msgf("unable to find root space id from space path: %s", gitspaceConfig.SpacePath)
|
log.Err(err).Msgf("unable to find root space id from space path: %s", gitspaceConfig.SpacePath)
|
||||||
return *gitspaceInstance, err
|
return *gitspaceInstance, &types.GitspaceError{
|
||||||
|
Error: err,
|
||||||
|
ErrorMessage: ptr.String(err.Error()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
resolvedSecret, err := secretResolver.Resolve(ctx, secret.ResolutionContext{
|
resolvedSecret, err := secretResolver.Resolve(ctx, secret.ResolutionContext{
|
||||||
UserIdentifier: gitspaceConfig.GitspaceUser.Identifier,
|
UserIdentifier: gitspaceConfig.GitspaceUser.Identifier,
|
||||||
|
@ -60,13 +67,19 @@ func (o orchestrator) ResumeStartGitspace(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msgf("could not resolve secret type: %s, ref: %s",
|
log.Err(err).Msgf("could not resolve secret type: %s, ref: %s",
|
||||||
gitspaceInstance.AccessType, *gitspaceInstance.AccessKeyRef)
|
gitspaceInstance.AccessType, *gitspaceInstance.AccessKeyRef)
|
||||||
return *gitspaceInstance, err
|
return *gitspaceInstance, &types.GitspaceError{
|
||||||
|
Error: err,
|
||||||
|
ErrorMessage: ptr.String(err.Error()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
gitspaceInstance.AccessKey = &resolvedSecret.SecretValue
|
gitspaceInstance.AccessKey = &resolvedSecret.SecretValue
|
||||||
|
|
||||||
ideSvc, err := o.getIDEService(gitspaceConfig)
|
ideSvc, err := o.getIDEService(gitspaceConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return *gitspaceInstance, err
|
return *gitspaceInstance, &types.GitspaceError{
|
||||||
|
Error: err,
|
||||||
|
ErrorMessage: ptr.String(err.Error()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
idePort := ideSvc.Port()
|
idePort := ideSvc.Port()
|
||||||
|
@ -75,35 +88,47 @@ func (o orchestrator) ResumeStartGitspace(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningFailed)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningFailed)
|
||||||
|
|
||||||
return *gitspaceInstance, fmt.Errorf(
|
return *gitspaceInstance, &types.GitspaceError{
|
||||||
"cannot provision infrastructure for ID %s: %w", gitspaceConfig.InfraProviderResource.UID, err)
|
Error: fmt.Errorf("cannot provision infrastructure for ID %s: %w",
|
||||||
|
gitspaceConfig.InfraProviderResource.UID, err),
|
||||||
|
ErrorMessage: ptr.String(err.Error()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if provisionedInfra.Status != enum.InfraStatusProvisioned {
|
if provisionedInfra.Status != enum.InfraStatusProvisioned {
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningFailed)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningFailed)
|
||||||
|
infraStateErr := fmt.Errorf(
|
||||||
return *gitspaceInstance, fmt.Errorf(
|
|
||||||
"infra state is %v, should be %v for gitspace instance identifier %s",
|
"infra state is %v, should be %v for gitspace instance identifier %s",
|
||||||
provisionedInfra.Status,
|
provisionedInfra.Status,
|
||||||
enum.InfraStatusProvisioned,
|
enum.InfraStatusProvisioned,
|
||||||
gitspaceConfig.GitspaceInstance.Identifier,
|
gitspaceConfig.GitspaceInstance.Identifier,
|
||||||
)
|
)
|
||||||
|
return *gitspaceInstance, &types.GitspaceError{
|
||||||
|
Error: infraStateErr,
|
||||||
|
ErrorMessage: ptr.String(infraStateErr.Error()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningCompleted)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningCompleted)
|
||||||
|
|
||||||
scmResolvedDetails, err := o.scm.GetSCMRepoDetails(ctx, gitspaceConfig)
|
scmResolvedDetails, err := o.scm.GetSCMRepoDetails(ctx, gitspaceConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return *gitspaceInstance, fmt.Errorf(
|
return *gitspaceInstance, &types.GitspaceError{
|
||||||
"failed to fetch code repo details for gitspace config ID %w %d", err, gitspaceConfig.ID)
|
Error: fmt.Errorf("failed to fetch code repo details for gitspace config ID %d: %w",
|
||||||
|
gitspaceConfig.ID, err),
|
||||||
|
ErrorMessage: ptr.String(err.Error()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectStart)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectStart)
|
||||||
|
|
||||||
err = o.containerOrchestrator.Status(ctx, provisionedInfra)
|
err = o.containerOrchestrator.Status(ctx, provisionedInfra)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectFailed)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectFailed)
|
||||||
|
agentUnreachableErr := fmt.Errorf("couldn't call the agent health API: %w", err)
|
||||||
return *gitspaceInstance, fmt.Errorf("couldn't call the agent health API: %w", err)
|
return *gitspaceInstance, &types.GitspaceError{
|
||||||
|
Error: agentUnreachableErr,
|
||||||
|
ErrorMessage: ptr.String(agentUnreachableErr.Error()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectCompleted)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentConnectCompleted)
|
||||||
|
@ -118,7 +143,10 @@ func (o orchestrator) ResumeStartGitspace(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceCreationFailed)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceCreationFailed)
|
||||||
|
|
||||||
return *gitspaceInstance, fmt.Errorf("couldn't call the agent start API: %w", err)
|
return *gitspaceInstance, &types.GitspaceError{
|
||||||
|
Error: fmt.Errorf("couldn't call the agent start API: %w", err),
|
||||||
|
ErrorMessage: ptr.String(err.Error()), // TODO: Fetch explicit error msg from container orchestrator
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceCreationCompleted)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeAgentGitspaceCreationCompleted)
|
||||||
|
@ -200,26 +228,32 @@ func (o orchestrator) ResumeStopGitspace(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
gitspaceConfig types.GitspaceConfig,
|
gitspaceConfig types.GitspaceConfig,
|
||||||
stoppedInfra types.Infrastructure,
|
stoppedInfra types.Infrastructure,
|
||||||
) (enum.GitspaceInstanceStateType, error) {
|
) (enum.GitspaceInstanceStateType, *types.GitspaceError) {
|
||||||
instanceState := enum.GitspaceInstanceStateError
|
instanceState := enum.GitspaceInstanceStateError
|
||||||
|
|
||||||
err := o.infraProvisioner.ResumeStop(ctx, gitspaceConfig, stoppedInfra)
|
err := o.infraProvisioner.ResumeStop(ctx, gitspaceConfig, stoppedInfra)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopFailed)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopFailed)
|
||||||
|
infraStopErr := fmt.Errorf("cannot stop provisioned infrastructure with ID %s: %w",
|
||||||
return instanceState, fmt.Errorf(
|
gitspaceConfig.InfraProviderResource.UID, err)
|
||||||
"cannot stop provisioned infrastructure with ID %s: %w", gitspaceConfig.InfraProviderResource.UID, err)
|
return instanceState, &types.GitspaceError{
|
||||||
|
Error: infraStopErr,
|
||||||
|
ErrorMessage: ptr.String(infraStopErr.Error()), // TODO: Fetch explicit error msg
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if stoppedInfra.Status != enum.InfraStatusDestroyed &&
|
if stoppedInfra.Status != enum.InfraStatusDestroyed &&
|
||||||
stoppedInfra.Status != enum.InfraStatusStopped {
|
stoppedInfra.Status != enum.InfraStatusStopped {
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopFailed)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopFailed)
|
||||||
|
incorrectInfraStateErr := fmt.Errorf(
|
||||||
return instanceState, fmt.Errorf(
|
|
||||||
"infra state is %v, should be %v for gitspace instance identifier %s",
|
"infra state is %v, should be %v for gitspace instance identifier %s",
|
||||||
stoppedInfra.Status,
|
stoppedInfra.Status,
|
||||||
enum.InfraStatusDestroyed,
|
enum.InfraStatusDestroyed,
|
||||||
gitspaceConfig.GitspaceInstance.Identifier)
|
gitspaceConfig.GitspaceInstance.Identifier)
|
||||||
|
return instanceState, &types.GitspaceError{
|
||||||
|
Error: incorrectInfraStateErr,
|
||||||
|
ErrorMessage: ptr.String(incorrectInfraStateErr.Error()), // TODO: Fetch explicit error msg
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopCompleted)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopCompleted)
|
||||||
|
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"github.com/harness/gitness/types"
|
"github.com/harness/gitness/types"
|
||||||
"github.com/harness/gitness/types/enum"
|
"github.com/harness/gitness/types/enum"
|
||||||
|
|
||||||
|
"github.com/gotidy/ptr"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
@ -80,13 +81,16 @@ func NewOrchestrator(
|
||||||
func (o orchestrator) TriggerStartGitspace(
|
func (o orchestrator) TriggerStartGitspace(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
gitspaceConfig types.GitspaceConfig,
|
gitspaceConfig types.GitspaceConfig,
|
||||||
) error {
|
) *types.GitspaceError {
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeFetchDevcontainerStart)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeFetchDevcontainerStart)
|
||||||
scmResolvedDetails, err := o.scm.GetSCMRepoDetails(ctx, gitspaceConfig)
|
scmResolvedDetails, err := o.scm.GetSCMRepoDetails(ctx, gitspaceConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeFetchDevcontainerFailed)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeFetchDevcontainerFailed)
|
||||||
return fmt.Errorf(
|
return &types.GitspaceError{
|
||||||
"failed to fetch code repo details for gitspace config ID %w %d", err, gitspaceConfig.ID)
|
Error: fmt.Errorf("failed to fetch code repo details for gitspace config ID %d: %w",
|
||||||
|
gitspaceConfig.ID, err),
|
||||||
|
ErrorMessage: ptr.String(err.Error()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
devcontainerConfig := scmResolvedDetails.DevcontainerConfig
|
devcontainerConfig := scmResolvedDetails.DevcontainerConfig
|
||||||
|
|
||||||
|
@ -94,7 +98,11 @@ func (o orchestrator) TriggerStartGitspace(
|
||||||
|
|
||||||
requiredGitspacePorts, err := o.getPortsRequiredForGitspace(gitspaceConfig, devcontainerConfig)
|
requiredGitspacePorts, err := o.getPortsRequiredForGitspace(gitspaceConfig, devcontainerConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot get the ports required for gitspace during start: %w", err)
|
err = fmt.Errorf("cannot get the ports required for gitspace during start: %w", err)
|
||||||
|
return &types.GitspaceError{
|
||||||
|
Error: err,
|
||||||
|
ErrorMessage: ptr.String(err.Error()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningStart)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningStart)
|
||||||
|
@ -102,9 +110,11 @@ func (o orchestrator) TriggerStartGitspace(
|
||||||
err = o.infraProvisioner.TriggerProvision(ctx, gitspaceConfig, requiredGitspacePorts)
|
err = o.infraProvisioner.TriggerProvision(ctx, gitspaceConfig, requiredGitspacePorts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningFailed)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraProvisioningFailed)
|
||||||
|
return &types.GitspaceError{
|
||||||
return fmt.Errorf(
|
Error: fmt.Errorf("cannot trigger provision infrastructure for ID %s: %w",
|
||||||
"cannot trigger provision infrastructure for ID %s: %w", gitspaceConfig.InfraProviderResource.UID, err)
|
gitspaceConfig.InfraProviderResource.UID, err),
|
||||||
|
ErrorMessage: ptr.String(err.Error()), // TODO: Fetch explicit error msg from infra provisioner.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -113,20 +123,26 @@ func (o orchestrator) TriggerStartGitspace(
|
||||||
func (o orchestrator) TriggerStopGitspace(
|
func (o orchestrator) TriggerStopGitspace(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
gitspaceConfig types.GitspaceConfig,
|
gitspaceConfig types.GitspaceConfig,
|
||||||
) error {
|
) *types.GitspaceError {
|
||||||
infra, err := o.getProvisionedInfra(ctx, gitspaceConfig,
|
infra, err := o.getProvisionedInfra(ctx, gitspaceConfig,
|
||||||
[]enum.InfraStatus{enum.InfraStatusProvisioned, enum.InfraStatusStopped})
|
[]enum.InfraStatus{enum.InfraStatusProvisioned, enum.InfraStatusStopped})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf(
|
infraNotFoundErr := fmt.Errorf("unable to find provisioned infra while triggering stop for gitspace "+
|
||||||
"unable to find provisioned infra while triggering stop for gitspace instance %s: %w",
|
"instance %s: %w", gitspaceConfig.GitspaceInstance.Identifier, err)
|
||||||
gitspaceConfig.GitspaceInstance.Identifier, err)
|
return &types.GitspaceError{
|
||||||
|
Error: infraNotFoundErr,
|
||||||
|
ErrorMessage: ptr.String(infraNotFoundErr.Error()), // TODO: Fetch explicit error msg
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if gitspaceConfig.GitspaceInstance.State == enum.GitspaceInstanceStateRunning ||
|
if gitspaceConfig.GitspaceInstance.State == enum.GitspaceInstanceStateRunning ||
|
||||||
gitspaceConfig.GitspaceInstance.State == enum.GitspaceInstanceStateStopping {
|
gitspaceConfig.GitspaceInstance.State == enum.GitspaceInstanceStateStopping {
|
||||||
err = o.stopGitspaceContainer(ctx, gitspaceConfig, *infra)
|
err = o.stopGitspaceContainer(ctx, gitspaceConfig, *infra)
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return &types.GitspaceError{
|
||||||
|
Error: err,
|
||||||
|
ErrorMessage: ptr.String(err.Error()), // TODO: Fetch explicit error msg
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopStart)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopStart)
|
||||||
|
@ -134,9 +150,12 @@ func (o orchestrator) TriggerStopGitspace(
|
||||||
err = o.infraProvisioner.TriggerStop(ctx, gitspaceConfig.InfraProviderResource, *infra)
|
err = o.infraProvisioner.TriggerStop(ctx, gitspaceConfig.InfraProviderResource, *infra)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopFailed)
|
o.emitGitspaceEvent(ctx, gitspaceConfig, enum.GitspaceEventTypeInfraStopFailed)
|
||||||
|
infraStopErr := fmt.Errorf("cannot trigger stop infrastructure with ID %s: %w",
|
||||||
return fmt.Errorf(
|
gitspaceConfig.InfraProviderResource.UID, err)
|
||||||
"cannot trigger stop infrastructure with ID %s: %w", gitspaceConfig.InfraProviderResource.UID, err)
|
return &types.GitspaceError{
|
||||||
|
Error: infraStopErr,
|
||||||
|
ErrorMessage: ptr.String(infraStopErr.Error()), // TODO: Fetch explicit error msg
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -61,7 +61,7 @@ func (c *Service) submitAsyncOps(
|
||||||
config *types.GitspaceConfig,
|
config *types.GitspaceConfig,
|
||||||
action enum.GitspaceActionType,
|
action enum.GitspaceActionType,
|
||||||
) {
|
) {
|
||||||
errChannel := make(chan error)
|
errChannel := make(chan *types.GitspaceError)
|
||||||
|
|
||||||
submitCtx := context.WithoutCancel(ctx)
|
submitCtx := context.WithoutCancel(ctx)
|
||||||
gitspaceTimedOutInMins := time.Duration(c.config.Gitspace.ProvisionTimeoutInMins) * time.Minute
|
gitspaceTimedOutInMins := time.Duration(c.config.Gitspace.ProvisionTimeoutInMins) * time.Minute
|
||||||
|
@ -69,20 +69,22 @@ func (c *Service) submitAsyncOps(
|
||||||
|
|
||||||
go c.asyncOperation(ttlExecuteContext, *config, action, errChannel)
|
go c.asyncOperation(ttlExecuteContext, *config, action, errChannel)
|
||||||
|
|
||||||
var err error
|
var err *types.GitspaceError
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
select {
|
select {
|
||||||
case <-ttlExecuteContext.Done():
|
case <-ttlExecuteContext.Done():
|
||||||
if ttlExecuteContext.Err() != nil {
|
if ttlExecuteContext.Err() != nil {
|
||||||
err = ttlExecuteContext.Err()
|
err = &types.GitspaceError{
|
||||||
|
Error: ttlExecuteContext.Err(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case err = <-errChannel:
|
case err = <-errChannel:
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msgf("error during async execution for %s", config.GitspaceInstance.Identifier)
|
log.Err(err.Error).Msgf("error during async execution for %s", config.GitspaceInstance.Identifier)
|
||||||
|
|
||||||
config.GitspaceInstance.State = enum.GitspaceInstanceStateError
|
config.GitspaceInstance.State = enum.GitspaceInstanceStateError
|
||||||
|
config.GitspaceInstance.ErrorMessage = err.ErrorMessage
|
||||||
updateErr := c.UpdateInstance(submitCtx, config.GitspaceInstance)
|
updateErr := c.UpdateInstance(submitCtx, config.GitspaceInstance)
|
||||||
if updateErr != nil {
|
if updateErr != nil {
|
||||||
log.Err(updateErr).Msgf(
|
log.Err(updateErr).Msgf(
|
||||||
|
@ -105,11 +107,11 @@ func (c *Service) asyncOperation(
|
||||||
ctxWithTimedOut context.Context,
|
ctxWithTimedOut context.Context,
|
||||||
config types.GitspaceConfig,
|
config types.GitspaceConfig,
|
||||||
action enum.GitspaceActionType,
|
action enum.GitspaceActionType,
|
||||||
errChannel chan error,
|
errChannel chan *types.GitspaceError,
|
||||||
) {
|
) {
|
||||||
defer close(errChannel)
|
defer close(errChannel)
|
||||||
|
|
||||||
var orchestrateErr error
|
var orchestrateErr *types.GitspaceError
|
||||||
|
|
||||||
switch action {
|
switch action {
|
||||||
case enum.GitspaceActionTypeStart:
|
case enum.GitspaceActionTypeStart:
|
||||||
|
@ -117,7 +119,7 @@ func (c *Service) asyncOperation(
|
||||||
err := c.UpdateInstance(ctxWithTimedOut, config.GitspaceInstance)
|
err := c.UpdateInstance(ctxWithTimedOut, config.GitspaceInstance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msgf(
|
log.Err(err).Msgf(
|
||||||
"failed to update gitspace instance during exec %q", config.GitspaceInstance.Identifier)
|
"failed to update gitspace instance during exec %s", config.GitspaceInstance.Identifier)
|
||||||
}
|
}
|
||||||
orchestrateErr = c.orchestrator.TriggerStartGitspace(ctxWithTimedOut, config)
|
orchestrateErr = c.orchestrator.TriggerStartGitspace(ctxWithTimedOut, config)
|
||||||
case enum.GitspaceActionTypeStop:
|
case enum.GitspaceActionTypeStop:
|
||||||
|
@ -125,13 +127,15 @@ func (c *Service) asyncOperation(
|
||||||
err := c.UpdateInstance(ctxWithTimedOut, config.GitspaceInstance)
|
err := c.UpdateInstance(ctxWithTimedOut, config.GitspaceInstance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msgf(
|
log.Err(err).Msgf(
|
||||||
"failed to update gitspace instance during exec %q", config.GitspaceInstance.Identifier)
|
"failed to update gitspace instance during exec %s", config.GitspaceInstance.Identifier)
|
||||||
}
|
}
|
||||||
orchestrateErr = c.orchestrator.TriggerStopGitspace(ctxWithTimedOut, config)
|
orchestrateErr = c.orchestrator.TriggerStopGitspace(ctxWithTimedOut, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
if orchestrateErr != nil {
|
if orchestrateErr != nil {
|
||||||
errChannel <- fmt.Errorf("failed to start/stop gitspace: %s %w", config.Identifier, orchestrateErr)
|
orchestrateErr.Error =
|
||||||
|
fmt.Errorf("failed to start/stop gitspace: %s %w", config.Identifier, orchestrateErr.Error)
|
||||||
|
errChannel <- orchestrateErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,8 +69,8 @@ func (s *Service) handleGitspaceInfraEvent(
|
||||||
updatedInstance, resumeStartErr := s.orchestrator.ResumeStartGitspace(ctx, *config, payload.Infra)
|
updatedInstance, resumeStartErr := s.orchestrator.ResumeStartGitspace(ctx, *config, payload.Infra)
|
||||||
if resumeStartErr != nil {
|
if resumeStartErr != nil {
|
||||||
s.emitGitspaceConfigEvent(ctx, config, enum.GitspaceEventTypeGitspaceActionStartFailed)
|
s.emitGitspaceConfigEvent(ctx, config, enum.GitspaceEventTypeGitspaceActionStartFailed)
|
||||||
|
updatedInstance.ErrorMessage = resumeStartErr.ErrorMessage
|
||||||
err = fmt.Errorf("failed to resume start gitspace: %w", resumeStartErr)
|
err = fmt.Errorf("failed to resume start gitspace: %w", resumeStartErr.Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
instance = &updatedInstance
|
instance = &updatedInstance
|
||||||
|
@ -79,8 +79,8 @@ func (s *Service) handleGitspaceInfraEvent(
|
||||||
instanceState, resumeStopErr := s.orchestrator.ResumeStopGitspace(ctx, *config, payload.Infra)
|
instanceState, resumeStopErr := s.orchestrator.ResumeStopGitspace(ctx, *config, payload.Infra)
|
||||||
if resumeStopErr != nil {
|
if resumeStopErr != nil {
|
||||||
s.emitGitspaceConfigEvent(ctx, config, enum.GitspaceEventTypeGitspaceActionStopFailed)
|
s.emitGitspaceConfigEvent(ctx, config, enum.GitspaceEventTypeGitspaceActionStopFailed)
|
||||||
|
instance.ErrorMessage = resumeStopErr.ErrorMessage
|
||||||
err = fmt.Errorf("failed to resume stop gitspace: %w", resumeStopErr)
|
err = fmt.Errorf("failed to resume stop gitspace: %w", resumeStopErr.Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
instance.State = instanceState
|
instance.State = instanceState
|
||||||
|
|
|
@ -54,7 +54,8 @@ const (
|
||||||
gits_last_heartbeat,
|
gits_last_heartbeat,
|
||||||
gits_active_time_started,
|
gits_active_time_started,
|
||||||
gits_active_time_ended,
|
gits_active_time_ended,
|
||||||
gits_has_git_changes`
|
gits_has_git_changes,
|
||||||
|
gits_error_message`
|
||||||
gitspaceInstanceSelectColumns = "gits_id," + gitspaceInstanceInsertColumns
|
gitspaceInstanceSelectColumns = "gits_id," + gitspaceInstanceInsertColumns
|
||||||
gitspaceInstanceTable = `gitspaces`
|
gitspaceInstanceTable = `gitspaces`
|
||||||
)
|
)
|
||||||
|
@ -80,6 +81,7 @@ type gitspaceInstance struct {
|
||||||
ActiveTimeStarted null.Int `db:"gits_active_time_started"`
|
ActiveTimeStarted null.Int `db:"gits_active_time_started"`
|
||||||
ActiveTimeEnded null.Int `db:"gits_active_time_ended"`
|
ActiveTimeEnded null.Int `db:"gits_active_time_ended"`
|
||||||
HasGitChanges null.Bool `db:"gits_has_git_changes"`
|
HasGitChanges null.Bool `db:"gits_has_git_changes"`
|
||||||
|
ErrorMessage null.String `db:"gits_error_message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGitspaceInstanceStore returns a new GitspaceInstanceStore.
|
// NewGitspaceInstanceStore returns a new GitspaceInstanceStore.
|
||||||
|
@ -213,6 +215,7 @@ func (g gitspaceInstanceStore) Create(ctx context.Context, gitspaceInstance *typ
|
||||||
gitspaceInstance.ActiveTimeStarted,
|
gitspaceInstance.ActiveTimeStarted,
|
||||||
gitspaceInstance.ActiveTimeEnded,
|
gitspaceInstance.ActiveTimeEnded,
|
||||||
gitspaceInstance.HasGitChanges,
|
gitspaceInstance.HasGitChanges,
|
||||||
|
gitspaceInstance.ErrorMessage,
|
||||||
).
|
).
|
||||||
Suffix(ReturningClause + "gits_id")
|
Suffix(ReturningClause + "gits_id")
|
||||||
sql, args, err := stmt.ToSql()
|
sql, args, err := stmt.ToSql()
|
||||||
|
@ -242,6 +245,7 @@ func (g gitspaceInstanceStore) Update(
|
||||||
Set("gits_active_time_ended", gitspaceInstance.ActiveTimeEnded).
|
Set("gits_active_time_ended", gitspaceInstance.ActiveTimeEnded).
|
||||||
Set("gits_total_time_used", gitspaceInstance.TotalTimeUsed).
|
Set("gits_total_time_used", gitspaceInstance.TotalTimeUsed).
|
||||||
Set("gits_has_git_changes", gitspaceInstance.HasGitChanges).
|
Set("gits_has_git_changes", gitspaceInstance.HasGitChanges).
|
||||||
|
Set("gits_error_message", gitspaceInstance.ErrorMessage).
|
||||||
Set("gits_updated", gitspaceInstance.Updated).
|
Set("gits_updated", gitspaceInstance.Updated).
|
||||||
Where("gits_id = ?", gitspaceInstance.ID)
|
Where("gits_id = ?", gitspaceInstance.ID)
|
||||||
sql, args, err := stmt.ToSql()
|
sql, args, err := stmt.ToSql()
|
||||||
|
@ -408,6 +412,7 @@ func mapDBToGitspaceInstance(
|
||||||
ActiveTimeEnded: in.ActiveTimeEnded.Ptr(),
|
ActiveTimeEnded: in.ActiveTimeEnded.Ptr(),
|
||||||
ActiveTimeStarted: in.ActiveTimeStarted.Ptr(),
|
ActiveTimeStarted: in.ActiveTimeStarted.Ptr(),
|
||||||
HasGitChanges: in.HasGitChanges.Ptr(),
|
HasGitChanges: in.HasGitChanges.Ptr(),
|
||||||
|
ErrorMessage: in.ErrorMessage.Ptr(),
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
@ -443,18 +448,24 @@ func validateActiveTimeDetails(gitspaceInstance *types.GitspaceInstance) {
|
||||||
gitspaceInstance.TotalTimeUsed != 0) {
|
gitspaceInstance.TotalTimeUsed != 0) {
|
||||||
log.Warn().Msgf(
|
log.Warn().Msgf(
|
||||||
"instance is missing active time start or has incorrect end/total timestamps, details: "+
|
"instance is missing active time start or has incorrect end/total timestamps, details: "+
|
||||||
" identifier %s state %s active time start %d active time end %d total time used %d",
|
" identifier %s state %s active time start %d active time end %d total time used %d", // nolint:goconst
|
||||||
gitspaceInstance.Identifier, gitspaceInstance.State, gitspaceInstance.ActiveTimeStarted,
|
gitspaceInstance.Identifier, gitspaceInstance.State, gitspaceInstance.ActiveTimeStarted,
|
||||||
gitspaceInstance.ActiveTimeEnded, gitspaceInstance.TotalTimeUsed)
|
gitspaceInstance.ActiveTimeEnded, gitspaceInstance.TotalTimeUsed)
|
||||||
}
|
}
|
||||||
if (gitspaceInstance.State == enum.GitspaceInstanceStateDeleted ||
|
if (gitspaceInstance.State == enum.GitspaceInstanceStateDeleted ||
|
||||||
gitspaceInstance.State == enum.GitspaceInstanceStateStopping ||
|
gitspaceInstance.State == enum.GitspaceInstanceStateStopping) &&
|
||||||
gitspaceInstance.State == enum.GitspaceInstanceStateError) &&
|
|
||||||
(gitspaceInstance.ActiveTimeStarted == nil ||
|
(gitspaceInstance.ActiveTimeStarted == nil ||
|
||||||
gitspaceInstance.ActiveTimeEnded == nil ||
|
gitspaceInstance.ActiveTimeEnded == nil ||
|
||||||
gitspaceInstance.TotalTimeUsed == 0) {
|
gitspaceInstance.TotalTimeUsed == 0) {
|
||||||
log.Warn().Msgf("instance is missing active time start/end/total timestamp, details: "+
|
log.Warn().Msgf("instance is missing active time start/end/total timestamp, details: "+
|
||||||
" identifier %s state %s active time start %d active time end %d total time used %d",
|
" identifier %s state %s active time start %d active time end %d total time used %d", // nolint:goconst
|
||||||
|
gitspaceInstance.Identifier, gitspaceInstance.State, gitspaceInstance.ActiveTimeStarted,
|
||||||
|
gitspaceInstance.ActiveTimeEnded, gitspaceInstance.TotalTimeUsed)
|
||||||
|
}
|
||||||
|
if gitspaceInstance.State == enum.GitspaceInstanceStateError &&
|
||||||
|
(gitspaceInstance.ActiveTimeStarted == nil) != (gitspaceInstance.ActiveTimeEnded == nil) {
|
||||||
|
log.Warn().Msgf("instance has incorrect active time start/end/total timestamp, details: "+
|
||||||
|
" identifier %s state %s active time start %d active time end %d total time used %d", // nolint:goconst
|
||||||
gitspaceInstance.Identifier, gitspaceInstance.State, gitspaceInstance.ActiveTimeStarted,
|
gitspaceInstance.Identifier, gitspaceInstance.State, gitspaceInstance.ActiveTimeStarted,
|
||||||
gitspaceInstance.ActiveTimeEnded, gitspaceInstance.TotalTimeUsed)
|
gitspaceInstance.ActiveTimeEnded, gitspaceInstance.TotalTimeUsed)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE gitspaces DROP COLUMN gits_error_message;
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE gitspaces ADD COLUMN gits_error_message TEXT;
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE gitspaces DROP COLUMN gits_error_message;
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE gitspaces ADD COLUMN gits_error_message TEXT;
|
|
@ -78,6 +78,7 @@ type GitspaceInstance struct {
|
||||||
ActiveTimeStarted *int64 `json:"active_time_started,omitempty"`
|
ActiveTimeStarted *int64 `json:"active_time_started,omitempty"`
|
||||||
ActiveTimeEnded *int64 `json:"active_time_ended,omitempty"`
|
ActiveTimeEnded *int64 `json:"active_time_ended,omitempty"`
|
||||||
HasGitChanges *bool `json:"has_git_changes,omitempty"`
|
HasGitChanges *bool `json:"has_git_changes,omitempty"`
|
||||||
|
ErrorMessage *string `json:"error_message,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GitspaceFilter struct {
|
type GitspaceFilter struct {
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
// GitspaceError wraps any error and provides a user-friendly error message which can be relayed back to UI.
|
||||||
|
type GitspaceError struct {
|
||||||
|
Error error
|
||||||
|
ErrorMessage *string
|
||||||
|
}
|
Loading…
Reference in New Issue