fix(edge-stack): add completed status EE-6210 (#11632)

pull/11743/head
cmeng 2024-04-30 13:44:08 +12:00 committed by GitHub
parent 7479302043
commit a9ead542b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 62 additions and 21 deletions

View File

@ -627,6 +627,7 @@ func getEdgeStackStatusParam(r *http.Request) (*portainer.EdgeStackStatusType, e
portainer.EdgeStackStatusRunning, portainer.EdgeStackStatusRunning,
portainer.EdgeStackStatusDeploying, portainer.EdgeStackStatusDeploying,
portainer.EdgeStackStatusRemoving, portainer.EdgeStackStatusRemoving,
portainer.EdgeStackStatusCompleted,
}, edgeStackStatus) { }, edgeStackStatus) {
return nil, errors.New("invalid edgeStackStatus parameter") return nil, errors.New("invalid edgeStackStatus parameter")
} }

View File

@ -1728,6 +1728,8 @@ const (
EdgeStackStatusRollingBack EdgeStackStatusRollingBack
// EdgeStackStatusRolledBack represents an Edge stack which has rolled back // EdgeStackStatusRolledBack represents an Edge stack which has rolled back
EdgeStackStatusRolledBack EdgeStackStatusRolledBack
// EdgeStackStatusCompleted represents a completed Edge stack
EdgeStackStatusCompleted
) )
const ( const (

View File

@ -68,6 +68,8 @@ function getLabel(type: StatusType): ReactNode {
switch (type) { switch (type) {
case StatusType.Running: case StatusType.Running:
return 'deployments running'; return 'deployments running';
case StatusType.Completed:
return 'deployments completed';
case StatusType.DeploymentReceived: case StatusType.DeploymentReceived:
return 'deployments received'; return 'deployments received';
case StatusType.Error: case StatusType.Error:

View File

@ -84,6 +84,16 @@ function getStatus(
}; };
} }
const allCompleted = envStatus.every((s) => s.Type === StatusType.Completed);
if (allCompleted) {
return {
label: 'Completed',
icon: CheckCircle,
mode: 'success',
};
}
const allRunning = envStatus.every( const allRunning = envStatus.every(
(s) => (s) =>
s.Type === StatusType.Running || s.Type === StatusType.Running ||

View File

@ -44,6 +44,8 @@ export enum StatusType {
RollingBack, RollingBack,
/** PausedRemoving represents an Edge stack which has been rolled back */ /** PausedRemoving represents an Edge stack which has been rolled back */
RolledBack, RolledBack,
/** Completed represents a completed Edge stack */
Completed,
} }
export interface DeploymentStatus { export interface DeploymentStatus {

View File

@ -51,7 +51,12 @@ func getServiceStatus(service service) (libstack.Status, string) {
return libstack.StatusRunning, "" return libstack.StatusRunning, ""
case "removing": case "removing":
return libstack.StatusRemoving, "" return libstack.StatusRemoving, ""
case "exited", "dead": case "exited":
if service.ExitCode != 0 {
return libstack.StatusError, fmt.Sprintf("service %s exited with code %d", service.Name, service.ExitCode)
}
return libstack.StatusCompleted, ""
case "dead":
if service.ExitCode != 0 { if service.ExitCode != 0 {
return libstack.StatusError, fmt.Sprintf("service %s exited with code %d", service.Name, service.ExitCode) return libstack.StatusError, fmt.Sprintf("service %s exited with code %d", service.Name, service.ExitCode)
} }
@ -94,7 +99,9 @@ func aggregateStatuses(services []service) (libstack.Status, string) {
return libstack.StatusStarting, "" return libstack.StatusStarting, ""
case statusCounts[libstack.StatusRemoving] > 0: case statusCounts[libstack.StatusRemoving] > 0:
return libstack.StatusRemoving, "" return libstack.StatusRemoving, ""
case statusCounts[libstack.StatusRunning] == servicesCount: case statusCounts[libstack.StatusCompleted] == servicesCount:
return libstack.StatusCompleted, ""
case statusCounts[libstack.StatusRunning]+statusCounts[libstack.StatusCompleted] == servicesCount:
return libstack.StatusRunning, "" return libstack.StatusRunning, ""
case statusCounts[libstack.StatusStopped] == servicesCount: case statusCounts[libstack.StatusStopped] == servicesCount:
return libstack.StatusStopped, "" return libstack.StatusStopped, ""
@ -106,15 +113,19 @@ func aggregateStatuses(services []service) (libstack.Status, string) {
} }
func (wrapper *PluginWrapper) WaitForStatus(ctx context.Context, name string, status libstack.Status) <-chan string { func (wrapper *PluginWrapper) WaitForStatus(ctx context.Context, name string, status libstack.Status) <-chan libstack.WaitResult {
errorMessageCh := make(chan string) waitResultCh := make(chan libstack.WaitResult)
waitResult := libstack.WaitResult{
Status: status,
}
go func() { go func() {
OUTER: OUTER:
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
errorMessageCh <- fmt.Sprintf("failed to wait for status: %s", ctx.Err().Error()) waitResult.ErrorMsg = fmt.Sprintf("failed to wait for status: %s", ctx.Err().Error())
waitResultCh <- waitResult
default: default:
} }
@ -129,7 +140,7 @@ func (wrapper *PluginWrapper) WaitForStatus(ctx context.Context, name string, st
Msg("no output from docker compose ps") Msg("no output from docker compose ps")
if status == libstack.StatusRemoved { if status == libstack.StatusRemoved {
errorMessageCh <- "" waitResultCh <- waitResult
return return
} }
@ -165,18 +176,25 @@ func (wrapper *PluginWrapper) WaitForStatus(ctx context.Context, name string, st
} }
if len(services) == 0 && status == libstack.StatusRemoved { if len(services) == 0 && status == libstack.StatusRemoved {
errorMessageCh <- "" waitResultCh <- waitResult
return return
} }
aggregateStatus, errorMessage := aggregateStatuses(services) aggregateStatus, errorMessage := aggregateStatuses(services)
if aggregateStatus == status { if aggregateStatus == status {
errorMessageCh <- "" waitResultCh <- waitResult
return
}
if status == libstack.StatusRunning && aggregateStatus == libstack.StatusCompleted {
waitResult.Status = libstack.StatusCompleted
waitResultCh <- waitResult
return return
} }
if errorMessage != "" { if errorMessage != "" {
errorMessageCh <- errorMessage waitResult.ErrorMsg = errorMessage
waitResultCh <- waitResult
return return
} }
@ -188,5 +206,5 @@ func (wrapper *PluginWrapper) WaitForStatus(ctx context.Context, name string, st
} }
}() }()
return errorMessageCh return waitResultCh
} }

View File

@ -108,9 +108,9 @@ func waitForStatus(deployer libstack.Deployer, ctx context.Context, stackName st
statusCh := deployer.WaitForStatus(ctx, stackName, requiredStatus) statusCh := deployer.WaitForStatus(ctx, stackName, requiredStatus)
result := <-statusCh result := <-statusCh
if result == "" { if result.ErrorMsg == "" {
return requiredStatus, "", nil return result.Status, "", nil
} }
return libstack.StatusError, result, nil return libstack.StatusError, result.ErrorMsg, nil
} }

View File

@ -13,7 +13,7 @@ type Deployer interface {
Remove(ctx context.Context, projectName string, filePaths []string, options Options) error Remove(ctx context.Context, projectName string, filePaths []string, options Options) error
Pull(ctx context.Context, filePaths []string, options Options) error Pull(ctx context.Context, filePaths []string, options Options) error
Validate(ctx context.Context, filePaths []string, options Options) error Validate(ctx context.Context, filePaths []string, options Options) error
WaitForStatus(ctx context.Context, name string, status Status) <-chan string WaitForStatus(ctx context.Context, name string, status Status) <-chan WaitResult
} }
type Status string type Status string
@ -26,8 +26,14 @@ const (
StatusError Status = "error" StatusError Status = "error"
StatusRemoving Status = "removing" StatusRemoving Status = "removing"
StatusRemoved Status = "removed" StatusRemoved Status = "removed"
StatusCompleted Status = "completed"
) )
type WaitResult struct {
Status Status
ErrorMsg string
}
type Options struct { type Options struct {
WorkingDir string WorkingDir string
Host string Host string