mirror of https://github.com/portainer/portainer
				
				
				
			fix(edge-stack): add completed status EE-6210 (#11632)
							parent
							
								
									7479302043
								
							
						
					
					
						commit
						a9ead542b3
					
				| 
						 | 
				
			
			@ -627,6 +627,7 @@ func getEdgeStackStatusParam(r *http.Request) (*portainer.EdgeStackStatusType, e
 | 
			
		|||
		portainer.EdgeStackStatusRunning,
 | 
			
		||||
		portainer.EdgeStackStatusDeploying,
 | 
			
		||||
		portainer.EdgeStackStatusRemoving,
 | 
			
		||||
		portainer.EdgeStackStatusCompleted,
 | 
			
		||||
	}, edgeStackStatus) {
 | 
			
		||||
		return nil, errors.New("invalid edgeStackStatus parameter")
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1728,6 +1728,8 @@ const (
 | 
			
		|||
	EdgeStackStatusRollingBack
 | 
			
		||||
	// EdgeStackStatusRolledBack represents an Edge stack which has rolled back
 | 
			
		||||
	EdgeStackStatusRolledBack
 | 
			
		||||
	// EdgeStackStatusCompleted represents a completed Edge stack
 | 
			
		||||
	EdgeStackStatusCompleted
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -68,6 +68,8 @@ function getLabel(type: StatusType): ReactNode {
 | 
			
		|||
  switch (type) {
 | 
			
		||||
    case StatusType.Running:
 | 
			
		||||
      return 'deployments running';
 | 
			
		||||
    case StatusType.Completed:
 | 
			
		||||
      return 'deployments completed';
 | 
			
		||||
    case StatusType.DeploymentReceived:
 | 
			
		||||
      return 'deployments received';
 | 
			
		||||
    case StatusType.Error:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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(
 | 
			
		||||
    (s) =>
 | 
			
		||||
      s.Type === StatusType.Running ||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,6 +44,8 @@ export enum StatusType {
 | 
			
		|||
  RollingBack,
 | 
			
		||||
  /** PausedRemoving represents an Edge stack which has been rolled back */
 | 
			
		||||
  RolledBack,
 | 
			
		||||
  /** Completed represents a completed Edge stack */
 | 
			
		||||
  Completed,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface DeploymentStatus {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,7 +51,12 @@ func getServiceStatus(service service) (libstack.Status, string) {
 | 
			
		|||
		return libstack.StatusRunning, ""
 | 
			
		||||
	case "removing":
 | 
			
		||||
		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 {
 | 
			
		||||
			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, ""
 | 
			
		||||
	case statusCounts[libstack.StatusRemoving] > 0:
 | 
			
		||||
		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, ""
 | 
			
		||||
	case statusCounts[libstack.StatusStopped] == servicesCount:
 | 
			
		||||
		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 {
 | 
			
		||||
	errorMessageCh := make(chan string)
 | 
			
		||||
func (wrapper *PluginWrapper) WaitForStatus(ctx context.Context, name string, status libstack.Status) <-chan libstack.WaitResult {
 | 
			
		||||
	waitResultCh := make(chan libstack.WaitResult)
 | 
			
		||||
	waitResult := libstack.WaitResult{
 | 
			
		||||
		Status: status,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
	OUTER:
 | 
			
		||||
		for {
 | 
			
		||||
			select {
 | 
			
		||||
			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:
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +140,7 @@ func (wrapper *PluginWrapper) WaitForStatus(ctx context.Context, name string, st
 | 
			
		|||
					Msg("no output from docker compose ps")
 | 
			
		||||
 | 
			
		||||
				if status == libstack.StatusRemoved {
 | 
			
		||||
					errorMessageCh <- ""
 | 
			
		||||
					waitResultCh <- waitResult
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -165,18 +176,25 @@ func (wrapper *PluginWrapper) WaitForStatus(ctx context.Context, name string, st
 | 
			
		|||
			}
 | 
			
		||||
 | 
			
		||||
			if len(services) == 0 && status == libstack.StatusRemoved {
 | 
			
		||||
				errorMessageCh <- ""
 | 
			
		||||
				waitResultCh <- waitResult
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			aggregateStatus, errorMessage := aggregateStatuses(services)
 | 
			
		||||
			if aggregateStatus == status {
 | 
			
		||||
				errorMessageCh <- ""
 | 
			
		||||
				waitResultCh <- waitResult
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if status == libstack.StatusRunning && aggregateStatus == libstack.StatusCompleted {
 | 
			
		||||
				waitResult.Status = libstack.StatusCompleted
 | 
			
		||||
				waitResultCh <- waitResult
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if errorMessage != "" {
 | 
			
		||||
				errorMessageCh <- errorMessage
 | 
			
		||||
				waitResult.ErrorMsg = errorMessage
 | 
			
		||||
				waitResultCh <- waitResult
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -188,5 +206,5 @@ func (wrapper *PluginWrapper) WaitForStatus(ctx context.Context, name string, st
 | 
			
		|||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	return errorMessageCh
 | 
			
		||||
	return waitResultCh
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -108,9 +108,9 @@ func waitForStatus(deployer libstack.Deployer, ctx context.Context, stackName st
 | 
			
		|||
 | 
			
		||||
	statusCh := deployer.WaitForStatus(ctx, stackName, requiredStatus)
 | 
			
		||||
	result := <-statusCh
 | 
			
		||||
	if result == "" {
 | 
			
		||||
		return requiredStatus, "", nil
 | 
			
		||||
	if result.ErrorMsg == "" {
 | 
			
		||||
		return result.Status, "", nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return libstack.StatusError, result, nil
 | 
			
		||||
	return libstack.StatusError, result.ErrorMsg, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,21 +13,27 @@ type Deployer interface {
 | 
			
		|||
	Remove(ctx context.Context, projectName string, filePaths []string, options Options) error
 | 
			
		||||
	Pull(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
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	StatusUnknown  Status = "unknown"
 | 
			
		||||
	StatusStarting Status = "starting"
 | 
			
		||||
	StatusRunning  Status = "running"
 | 
			
		||||
	StatusStopped  Status = "stopped"
 | 
			
		||||
	StatusError    Status = "error"
 | 
			
		||||
	StatusRemoving Status = "removing"
 | 
			
		||||
	StatusRemoved  Status = "removed"
 | 
			
		||||
	StatusUnknown   Status = "unknown"
 | 
			
		||||
	StatusStarting  Status = "starting"
 | 
			
		||||
	StatusRunning   Status = "running"
 | 
			
		||||
	StatusStopped   Status = "stopped"
 | 
			
		||||
	StatusError     Status = "error"
 | 
			
		||||
	StatusRemoving  Status = "removing"
 | 
			
		||||
	StatusRemoved   Status = "removed"
 | 
			
		||||
	StatusCompleted Status = "completed"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type WaitResult struct {
 | 
			
		||||
	Status   Status
 | 
			
		||||
	ErrorMsg string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Options struct {
 | 
			
		||||
	WorkingDir  string
 | 
			
		||||
	Host        string
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue