Merge pull request #2907 from hashicorp/b-promote-err
Expose FSM errors into deployment watcher and API
This commit is contained in:
commit
8dc8e17c1b
|
@ -89,12 +89,25 @@ type deploymentWatcherRaftShim struct {
|
|||
apply raftApplyFn
|
||||
}
|
||||
|
||||
// convertApplyErrors parses the results of a raftApply and returns the index at
|
||||
// which it was applied and any error that occured. Raft Apply returns two
|
||||
// seperate errors, Raft library errors and user returned errors from the FSM.
|
||||
// This helper, joins the errors by inspecting the applyResponse for an error.
|
||||
func (d *deploymentWatcherRaftShim) convertApplyErrors(applyResp interface{}, index uint64, err error) (uint64, error) {
|
||||
if applyResp != nil {
|
||||
if fsmErr, ok := applyResp.(error); ok && fsmErr != nil {
|
||||
return index, fsmErr
|
||||
}
|
||||
}
|
||||
return index, err
|
||||
}
|
||||
|
||||
func (d *deploymentWatcherRaftShim) UpsertEvals(evals []*structs.Evaluation) (uint64, error) {
|
||||
update := &structs.EvalUpdateRequest{
|
||||
Evals: evals,
|
||||
}
|
||||
_, index, err := d.apply(structs.EvalUpdateRequestType, update)
|
||||
return index, err
|
||||
fsmErrIntf, index, raftErr := d.apply(structs.EvalUpdateRequestType, update)
|
||||
return d.convertApplyErrors(fsmErrIntf, index, raftErr)
|
||||
}
|
||||
|
||||
func (d *deploymentWatcherRaftShim) UpsertJob(job *structs.Job) (uint64, error) {
|
||||
|
@ -102,21 +115,21 @@ func (d *deploymentWatcherRaftShim) UpsertJob(job *structs.Job) (uint64, error)
|
|||
update := &structs.JobRegisterRequest{
|
||||
Job: job,
|
||||
}
|
||||
_, index, err := d.apply(structs.JobRegisterRequestType, update)
|
||||
return index, err
|
||||
fsmErrIntf, index, raftErr := d.apply(structs.JobRegisterRequestType, update)
|
||||
return d.convertApplyErrors(fsmErrIntf, index, raftErr)
|
||||
}
|
||||
|
||||
func (d *deploymentWatcherRaftShim) UpdateDeploymentStatus(u *structs.DeploymentStatusUpdateRequest) (uint64, error) {
|
||||
_, index, err := d.apply(structs.DeploymentStatusUpdateRequestType, u)
|
||||
return index, err
|
||||
fsmErrIntf, index, raftErr := d.apply(structs.DeploymentStatusUpdateRequestType, u)
|
||||
return d.convertApplyErrors(fsmErrIntf, index, raftErr)
|
||||
}
|
||||
|
||||
func (d *deploymentWatcherRaftShim) UpdateDeploymentPromotion(req *structs.ApplyDeploymentPromoteRequest) (uint64, error) {
|
||||
_, index, err := d.apply(structs.DeploymentPromoteRequestType, req)
|
||||
return index, err
|
||||
fsmErrIntf, index, raftErr := d.apply(structs.DeploymentPromoteRequestType, req)
|
||||
return d.convertApplyErrors(fsmErrIntf, index, raftErr)
|
||||
}
|
||||
|
||||
func (d *deploymentWatcherRaftShim) UpdateDeploymentAllocHealth(req *structs.ApplyDeploymentAllocHealthRequest) (uint64, error) {
|
||||
_, index, err := d.apply(structs.DeploymentAllocHealthRequestType, req)
|
||||
return index, err
|
||||
fsmErrIntf, index, raftErr := d.apply(structs.DeploymentAllocHealthRequestType, req)
|
||||
return d.convertApplyErrors(fsmErrIntf, index, raftErr)
|
||||
}
|
||||
|
|
|
@ -1973,6 +1973,7 @@ func (s *StateStore) UpdateDeploymentPromotion(index uint64, req *structs.ApplyD
|
|||
}
|
||||
}
|
||||
|
||||
haveCanaries := false
|
||||
var unhealthyErr multierror.Error
|
||||
for {
|
||||
raw := iter.Next()
|
||||
|
@ -1997,12 +1998,18 @@ func (s *StateStore) UpdateDeploymentPromotion(index uint64, req *structs.ApplyD
|
|||
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
|
||||
|
|
|
@ -5030,6 +5030,39 @@ func TestStateStore_UpsertDeploymentPromotion_Unhealthy(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Test promoting a deployment with no canaries
|
||||
func TestStateStore_UpsertDeploymentPromotion_NoCanaries(t *testing.T) {
|
||||
state := testStateStore(t)
|
||||
|
||||
// Create a job
|
||||
j := mock.Job()
|
||||
if err := state.UpsertJob(1, j); err != nil {
|
||||
t.Fatalf("bad: %v", err)
|
||||
}
|
||||
|
||||
// Create a deployment
|
||||
d := mock.Deployment()
|
||||
d.JobID = j.ID
|
||||
if err := state.UpsertDeployment(2, d); err != nil {
|
||||
t.Fatalf("bad: %v", err)
|
||||
}
|
||||
|
||||
// Promote the canaries
|
||||
req := &structs.ApplyDeploymentPromoteRequest{
|
||||
DeploymentPromoteRequest: structs.DeploymentPromoteRequest{
|
||||
DeploymentID: d.ID,
|
||||
All: true,
|
||||
},
|
||||
}
|
||||
err := state.UpdateDeploymentPromotion(4, req)
|
||||
if err == nil {
|
||||
t.Fatalf("bad: %v", err)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "no canaries to promote") {
|
||||
t.Fatalf("expect error promoting non-existant canaries: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Test promoting all canaries in a deployment.
|
||||
func TestStateStore_UpsertDeploymentPromotion_All(t *testing.T) {
|
||||
state := testStateStore(t)
|
||||
|
|
Loading…
Reference in a new issue