func TestReconciler_FailedDeployment_NoPlacements(t *testing.T) {
	job := mock.Job()
	job.TaskGroups[0].Update = noCanaryUpdate

	// Create an existing failed deployment that has some placed allocs
	d := structs.NewDeployment(job)
	d.Status = structs.DeploymentStatusFailed
	d.TaskGroups[job.TaskGroups[0].Name] = &structs.DeploymentState{
		Promoted:     true,
		DesiredTotal: 10,
		PlacedAllocs: 4,
	}

	// Create 6 allocations from the old job
	var allocs []*structs.Allocation
	for i := 4; i < 10; i++ {
		alloc := mock.Alloc()
		alloc.Job = job
		alloc.JobID = job.ID
		alloc.NodeID = structs.GenerateUUID()
		alloc.Name = structs.AllocName(job.ID, job.TaskGroups[0].Name, uint(i))
		alloc.TaskGroup = job.TaskGroups[0].Name
		allocs = append(allocs, alloc)
	}

	// Create the healthy replacements
	handled := make(map[string]allocUpdateType)
	for i := 0; i < 4; i++ {
		new := mock.Alloc()
		new.Job = job
		new.JobID = job.ID
		new.NodeID = structs.GenerateUUID()
		new.Name = structs.AllocName(job.ID, job.TaskGroups[0].Name, uint(i))
		new.TaskGroup = job.TaskGroups[0].Name
		new.DeploymentID = d.ID
		new.DeploymentStatus = &structs.AllocDeploymentStatus{
			Healthy: helper.BoolToPtr(true),
		}
		allocs = append(allocs, new)
		handled[new.ID] = allocUpdateFnIgnore
	}

	// Build a map of tainted nodes
	tainted := make(map[string]*structs.Node, 2)
	for i := 0; i < 2; i++ {
		n := mock.Node()
		n.ID = allocs[6+i].NodeID
		if i == 0 {
			n.Status = structs.NodeStatusDown
		} else {
			n.Drain = true
		}
		tainted[n.ID] = n
	}

	mockUpdateFn := allocUpdateFnMock(handled, allocUpdateFnDestructive)
	reconciler := NewAllocReconciler(testLogger(), mockUpdateFn, false, job.ID, job, d, allocs, tainted)
	r := reconciler.Compute()

	// Assert the correct results
	assertResults(t, r, &resultExpectation{
		createDeployment:  nil,
		deploymentUpdates: nil,
		place:             0,
		inplace:           0,
		stop:              2,
		followupEvalWait:  0, // Since the deployment is failed, there should be no followup
		desiredTGUpdates: map[string]*structs.DesiredUpdates{
			job.TaskGroups[0].Name: {
				Stop:   2,
				Ignore: 8,
			},
		},
	})

	assertNamesHaveIndexes(t, intRange(0, 1), stopResultsToNames(r.stop))
}
// Tests the reconciler handles a failed deployment and does no placements
Tests the reconciler handles a failed deployment and does no placements
// Tests the reconciler handles a failed deployment and does no placements
func TestReconciler_FailedDeployment_NoPlacements(t *testing.T) {
	job := mock.Job()
	job.TaskGroups[0].Update = noCanaryUpdate
	d := structs.NewDeployment(job)
	d.Status = structs.DeploymentStatusFailed
	d.TaskGroups[job.TaskGroups[0].Name] = &structs.DeploymentState{
		Promoted:     true,
		DesiredTotal: 10,
		PlacedAllocs: 4,
	}
	var allocs []*structs.Allocation
	for i := 4; i < 10; i++ {
		alloc := mock.Alloc()
		alloc.Job = job
		alloc.JobID = job.ID
		alloc.NodeID = structs.GenerateUUID()
		alloc.Name = structs.AllocName(job.ID, job.TaskGroups[0].Name, uint(i))
		alloc.TaskGroup = job.TaskGroups[0].Name
		allocs = append(allocs, alloc)
	}
	handled := make(map[string]allocUpdateType)
	for i := 0; i < 4; i++ {
		new := mock.Alloc()
		new.Job = job
		new.JobID = job.ID
		new.NodeID = structs.GenerateUUID()
		new.Name = structs.AllocName(job.ID, job.TaskGroups[0].Name, uint(i))
		new.TaskGroup = job.TaskGroups[0].Name
		new.DeploymentID = d.ID
		new.DeploymentStatus = &structs.AllocDeploymentStatus{
			Healthy: helper.BoolToPtr(true),
		}
		allocs = append(allocs, new)
		handled[new.ID] = allocUpdateFnIgnore
	}
	tainted := make(map[string]*structs.Node, 2)
	for i := 0; i < 2; i++ {
		n := mock.Node()
		n.ID = allocs[6+i].NodeID
		if i == 0 {
			n.Status = structs.NodeStatusDown
		} else {
			n.Drain = true
		}
		tainted[n.ID] = n
	}
	mockUpdateFn := allocUpdateFnMock(handled, allocUpdateFnDestructive)
	reconciler := NewAllocReconciler(testLogger(), mockUpdateFn, false, job.ID, job, d, allocs, tainted)
	r := reconciler.Compute()
	assertResults(t, r, &resultExpectation{
		createDeployment:  nil,
		deploymentUpdates: nil,
		place:             0,
		inplace:           0,
		stop:              2,
		followupEvalWait:  0, 
		desiredTGUpdates: map[string]*structs.DesiredUpdates{
			job.TaskGroups[0].Name: {
				Stop:   2,
				Ignore: 8,
			},
		},
	})
	assertNamesHaveIndexes(t, intRange(0, 1), stopResultsToNames(r.stop))
}
func TestReconciler_FailedDeployment_NoPlacements ( t * testing . T ) { job := mock . Job ( ) job . TaskGroups [ 0 ] . Update = noCanaryUpdate d := structs . NewDeployment ( job ) d . Status = structs . DeploymentStatusFailed d . TaskGroups [ job . TaskGroups [ 0 ] . Name ] = & structs . DeploymentState { Promoted : true , DesiredTotal : 10 , PlacedAllocs : 4 , } var allocs [ ] * structs . Allocation for i := 4 ; i < 10 ; i ++ { alloc := mock . Alloc ( ) alloc . Job = job alloc . JobID = job . ID alloc . NodeID = structs . GenerateUUID ( ) alloc . Name = structs . AllocName ( job . ID , job . TaskGroups [ 0 ] . Name , uint ( i ) ) alloc . TaskGroup = job . TaskGroups [ 0 ] . Name allocs = append ( allocs , alloc ) } handled := make ( map [ string ] allocUpdateType ) for i := 0 ; i < 4 ; i ++ { new := mock . Alloc ( ) new . Job = job new . JobID = job . ID new . NodeID = structs . GenerateUUID ( ) new . Name = structs . AllocName ( job . ID , job . TaskGroups [ 0 ] . Name , uint ( i ) ) new . TaskGroup = job . TaskGroups [ 0 ] . Name new . DeploymentID = d . ID new . DeploymentStatus = & structs . AllocDeploymentStatus { Healthy : helper . BoolToPtr ( true ) , } allocs = append ( allocs , new ) handled [ new . ID ] = allocUpdateFnIgnore } tainted := make ( map [ string ] * structs . Node , 2 ) for i := 0 ; i < 2 ; i ++ { n := mock . Node ( ) n . ID = allocs [ 6 + i ] . NodeID if i == 0 { n . Status = structs . NodeStatusDown } else { n . Drain = true } tainted [ n . ID ] = n } mockUpdateFn := allocUpdateFnMock ( handled , allocUpdateFnDestructive ) reconciler := NewAllocReconciler ( testLogger ( ) , mockUpdateFn , false , job . ID , job , d , allocs , tainted ) r := reconciler . Compute ( ) assertResults ( t , r , & resultExpectation { createDeployment : nil , deploymentUpdates : nil , place : 0 , inplace : 0 , stop : 2 , followupEvalWait : 0 , desiredTGUpdates : map [ string ] * structs . DesiredUpdates { job . TaskGroups [ 0 ] . Name : { Stop : 2 , Ignore : 8 , } , } , } ) assertNamesHaveIndexes ( t , intRange ( 0 , 1 ) , stopResultsToNames ( r . stop ) ) }
Tests the reconciler handles a failed deployment and does no placements
Tests the reconciler handles a failed deployment and does no placements
// Create an existing failed deployment that has some placed allocs // Create 6 allocations from the old job // Create the healthy replacements // Build a map of tainted nodes // Assert the correct results // Since the deployment is failed, there should be no followup