Add leader task to api and server side

This commit is contained in:
Alex Dadgar 2017-02-10 16:57:47 -08:00
parent a8f7492d8e
commit 3ba8faeae3
8 changed files with 35 additions and 5 deletions

View File

@ -163,6 +163,7 @@ type Task struct {
Vault *Vault
Templates []*Template
DispatchPayload *DispatchPayloadConfig
Leader bool
}
// TaskArtifact is used to download artifacts before running a task.

View File

@ -568,6 +568,7 @@ func parseTasks(jobName string, taskGroupName string, result *[]*structs.Task, l
"driver",
"env",
"kill_timeout",
"leader",
"logs",
"meta",
"resources",

View File

@ -181,6 +181,7 @@ func TestParse(t *testing.T) {
Perms: "777",
},
},
Leader: true,
},
&structs.Task{
Name: "storagelocker",

View File

@ -50,6 +50,7 @@ job "binstore-storagelocker" {
task "binstore" {
driver = "docker"
user = "bob"
leader = true
config {
image = "hashicorp/binstore"

View File

@ -403,7 +403,7 @@ func (t *Task) Diff(other *Task, contextual bool) (*TaskDiff, error) {
diff.Objects = append(diff.Objects, vDiff)
}
// Artifacts diff
// Template diff
tmplDiffs := primitiveObjectSetDiff(
interfaceSlice(t.Templates),
interfaceSlice(other.Templates),

View File

@ -1880,6 +1880,7 @@ func TestTaskDiff(t *testing.T) {
"foo": "bar",
},
KillTimeout: 1 * time.Second,
Leader: true,
},
New: &Task{
Name: "foo",
@ -1892,6 +1893,7 @@ func TestTaskDiff(t *testing.T) {
"foo": "bar",
},
KillTimeout: 1 * time.Second,
Leader: true,
},
Expected: &TaskDiff{
Type: DiffTypeNone,
@ -1911,6 +1913,7 @@ func TestTaskDiff(t *testing.T) {
"foo": "bar",
},
KillTimeout: 1 * time.Second,
Leader: true,
},
New: &Task{
Name: "foo",
@ -1923,6 +1926,7 @@ func TestTaskDiff(t *testing.T) {
"foo": "baz",
},
KillTimeout: 2 * time.Second,
Leader: false,
},
Expected: &TaskDiff{
Type: DiffTypeEdited,
@ -1946,6 +1950,12 @@ func TestTaskDiff(t *testing.T) {
Old: "1000000000",
New: "2000000000",
},
{
Type: DiffTypeEdited,
Name: "Leader",
Old: "true",
New: "false",
},
{
Type: DiffTypeEdited,
Name: "Meta[foo]",

View File

@ -1931,8 +1931,9 @@ func (tg *TaskGroup) Validate() error {
mErr.Errors = append(mErr.Errors, fmt.Errorf("Task Group %v should have an ephemeral disk object", tg.Name))
}
// Check for duplicate tasks
// Check for duplicate tasks and that there is only leader task if any
tasks := make(map[string]int)
leaderTasks := 0
for idx, task := range tg.Tasks {
if task.Name == "" {
mErr.Errors = append(mErr.Errors, fmt.Errorf("Task %d missing name", idx+1))
@ -1941,6 +1942,14 @@ func (tg *TaskGroup) Validate() error {
} else {
tasks[task.Name] = idx
}
if task.Leader {
leaderTasks++
}
}
if leaderTasks > 1 {
mErr.Errors = append(mErr.Errors, fmt.Errorf("Only one task may be marked as leader"))
}
// Validate the tasks
@ -2289,6 +2298,10 @@ type Task struct {
// Artifacts is a list of artifacts to download and extract before running
// the task.
Artifacts []*TaskArtifact
// Leader marks the task as the leader within the group. When the leader
// task exits, other tasks will be gracefully terminated.
Leader bool
}
func (t *Task) Copy() *Task {

View File

@ -419,8 +419,8 @@ func TestTaskGroup_Validate(t *testing.T) {
Name: "web",
Count: 1,
Tasks: []*Task{
&Task{Name: "web"},
&Task{Name: "web"},
&Task{Name: "web", Leader: true},
&Task{Name: "web", Leader: true},
&Task{},
},
RestartPolicy: &RestartPolicy{
@ -442,7 +442,10 @@ func TestTaskGroup_Validate(t *testing.T) {
if !strings.Contains(mErr.Errors[2].Error(), "Task 3 missing name") {
t.Fatalf("err: %s", err)
}
if !strings.Contains(mErr.Errors[3].Error(), "Task web validation failed") {
if !strings.Contains(mErr.Errors[3].Error(), "Only one task may be marked as leader") {
t.Fatalf("err: %s", err)
}
if !strings.Contains(mErr.Errors[4].Error(), "Task web validation failed") {
t.Fatalf("err: %s", err)
}
}