func (s *StateStore) UpdateDeploymentPromotion(index uint64, req *structs.ApplyDeploymentPromoteRequest) error {
	txn := s.db.Txn(true)
	defer txn.Abort()

	// Retrieve deployment and ensure it is not terminal and is active
	ws := memdb.NewWatchSet()
	deployment, err := s.deploymentByIDImpl(ws, req.DeploymentID, txn)
	if err != nil {
		return err
	} else if deployment == nil {
		return fmt.Errorf("Deployment ID %q couldn't be updated as it does not exist", req.DeploymentID)
	} else if !deployment.Active() {
		return fmt.Errorf("Deployment %q has terminal status %q:", deployment.ID, deployment.Status)
	}

	// Retrieve effected allocations
	iter, err := txn.Get("allocs", "deployment", req.DeploymentID)
	if err != nil {
		return err
	}

	groupIndex := make(map[string]struct{}, len(req.Groups))
	for _, g := range req.Groups {
		groupIndex[g] = struct{}{}
	}

	canaryIndex := make(map[string]struct{}, len(deployment.TaskGroups))
	for _, state := range deployment.TaskGroups {
		for _, c := range state.PlacedCanaries {
			canaryIndex[c] = struct{}{}
		}
	}

	haveCanaries := false
	var unhealthyErr multierror.Error
	for {
		raw := iter.Next()
		if raw == nil {
			break
		}

		alloc := raw.(*structs.Allocation)

		// Check that the alloc is a canary
		if _, ok := canaryIndex[alloc.ID]; !ok {
			continue
		}

		// Check that the canary is part of a group being promoted
		if _, ok := groupIndex[alloc.TaskGroup]; !req.All && !ok {
			continue
		}

		// Ensure the canaries are healthy
		if !alloc.DeploymentStatus.IsHealthy() {
			multierror.Append(&unhealthyErr, fmt.Errorf("Canary allocation %q for group %q is not healthy", alloc.ID, alloc.TaskGroup))
			continue
		}

		haveCanaries = true
	}

	if err := unhealthyErr.ErrorOrNil(); err != nil {
		return err
	}

	if !haveCanaries {
		return fmt.Errorf("no canaries to promote")
	}

	// Update deployment
	copy := deployment.Copy()
	copy.ModifyIndex = index
	for tg, status := range copy.TaskGroups {
		_, ok := groupIndex[tg]
		if !req.All && !ok {
			continue
		}

		status.Promoted = true
	}

	// If the deployment no longer needs promotion, update its status
	if !copy.RequiresPromotion() && copy.Status == structs.DeploymentStatusRunning {
		copy.StatusDescription = structs.DeploymentStatusDescriptionRunning
	}

	// Insert the deployment
	if err := s.upsertDeploymentImpl(index, copy, txn); err != nil {
		return err
	}

	// Upsert the optional eval
	if req.Eval != nil {
		if err := s.nestedUpsertEval(txn, index, req.Eval); err != nil {
			return err
		}
	}

	txn.Commit()
	return nil
}
// UpdateDeploymentPromotion is used to promote canaries in a deployment and
// potentially make a evaluation
UpdateDeploymentPromotion is used to promote canaries in a deployment and
potentially make a evaluation
// UpdateDeploymentPromotion is used to promote canaries in a deployment and // potentially make a evaluation
func (s *StateStore) UpdateDeploymentPromotion(index uint64, req *structs.ApplyDeploymentPromoteRequest) error {
	txn := s.db.Txn(true)
	defer txn.Abort()
	ws := memdb.NewWatchSet()
	deployment, err := s.deploymentByIDImpl(ws, req.DeploymentID, txn)
	if err != nil {
		return err
	} else if deployment == nil {
		return fmt.Errorf("Deployment ID %q couldn't be updated as it does not exist", req.DeploymentID)
	} else if !deployment.Active() {
		return fmt.Errorf("Deployment %q has terminal status %q:", deployment.ID, deployment.Status)
	}
	iter, err := txn.Get("allocs", "deployment", req.DeploymentID)
	if err != nil {
		return err
	}
	groupIndex := make(map[string]struct{}, len(req.Groups))
	for _, g := range req.Groups {
		groupIndex[g] = struct{}{}
	}
	canaryIndex := make(map[string]struct{}, len(deployment.TaskGroups))
	for _, state := range deployment.TaskGroups {
		for _, c := range state.PlacedCanaries {
			canaryIndex[c] = struct{}{}
		}
	}
	haveCanaries := false
	var unhealthyErr multierror.Error
	for {
		raw := iter.Next()
		if raw == nil {
			break
		}
		alloc := raw.(*structs.Allocation)
		if _, ok := canaryIndex[alloc.ID]; !ok {
			continue
		}
		if _, ok := groupIndex[alloc.TaskGroup]; !req.All && !ok {
			continue
		}
		if !alloc.DeploymentStatus.IsHealthy() {
			multierror.Append(&unhealthyErr, fmt.Errorf("Canary allocation %q for group %q is not healthy", alloc.ID, alloc.TaskGroup))
			continue
		}
		haveCanaries = true
	}
	if err := unhealthyErr.ErrorOrNil(); err != nil {
		return err
	}
	if !haveCanaries {
		return fmt.Errorf("no canaries to promote")
	}
	copy := deployment.Copy()
	copy.ModifyIndex = index
	for tg, status := range copy.TaskGroups {
		_, ok := groupIndex[tg]
		if !req.All && !ok {
			continue
		}
		status.Promoted = true
	}
	if !copy.RequiresPromotion() && copy.Status == structs.DeploymentStatusRunning {
		copy.StatusDescription = structs.DeploymentStatusDescriptionRunning
	}
	if err := s.upsertDeploymentImpl(index, copy, txn); err != nil {
		return err
	}
	if req.Eval != nil {
		if err := s.nestedUpsertEval(txn, index, req.Eval); err != nil {
			return err
		}
	}
	txn.Commit()
	return nil
}
func ( s * StateStore ) UpdateDeploymentPromotion ( index uint64 , req * structs . ApplyDeploymentPromoteRequest ) error { txn := s . db . Txn ( true ) defer txn . Abort ( ) ws := memdb . NewWatchSet ( ) deployment , err := s . deploymentByIDImpl ( ws , req . DeploymentID , txn ) if err != nil { return err } else if deployment == nil { return fmt . Errorf ( " " , req . DeploymentID ) } else if ! deployment . Active ( ) { return fmt . Errorf ( " " , deployment . ID , deployment . Status ) } iter , err := txn . Get ( " " , " " , req . DeploymentID ) if err != nil { return err } groupIndex := make ( map [ string ] struct { } , len ( req . Groups ) ) for _ , g := range req . Groups { groupIndex [ g ] = struct { } { } } canaryIndex := make ( map [ string ] struct { } , len ( deployment . TaskGroups ) ) for _ , state := range deployment . TaskGroups { for _ , c := range state . PlacedCanaries { canaryIndex [ c ] = struct { } { } } } haveCanaries := false var unhealthyErr multierror . Error for { raw := iter . Next ( ) if raw == nil { break } alloc := raw . ( * structs . Allocation ) if _ , ok := canaryIndex [ alloc . ID ] ; ! ok { continue } if _ , ok := groupIndex [ alloc . TaskGroup ] ; ! req . All && ! ok { continue } if ! alloc . DeploymentStatus . IsHealthy ( ) { multierror . Append ( & unhealthyErr , fmt . Errorf ( " " , alloc . ID , alloc . TaskGroup ) ) continue } haveCanaries = true } if err := unhealthyErr . ErrorOrNil ( ) ; err != nil { return err } if ! haveCanaries { return fmt . Errorf ( " " ) } copy := deployment . Copy ( ) copy . ModifyIndex = index for tg , status := range copy . TaskGroups { _ , ok := groupIndex [ tg ] if ! req . All && ! ok { continue } status . Promoted = true } if ! copy . RequiresPromotion ( ) && copy . Status == structs . DeploymentStatusRunning { copy . StatusDescription = structs . DeploymentStatusDescriptionRunning } if err := s . upsertDeploymentImpl ( index , copy , txn ) ; err != nil { return err } if req . Eval != nil { if err := s . nestedUpsertEval ( txn , index , req . Eval ) ; err != nil { return err } } txn . Commit ( ) return nil }
UpdateDeploymentPromotion is used to promote canaries in a deployment and
potentially make a evaluation
UpdateDeploymentPromotion is used to promote canaries in a deployment and potentially make a evaluation
// Retrieve deployment and ensure it is not terminal and is active // Retrieve effected allocations // Check that the alloc is a canary // Check that the canary is part of a group being promoted // Ensure the canaries are healthy // Update deployment // If the deployment no longer needs promotion, update its status // Insert the deployment // Upsert the optional eval