Skip to content

Commit

Permalink
e2e: add test for reverting a job with a consul service
Browse files Browse the repository at this point in the history
  • Loading branch information
shoenig committed Jan 31, 2023
1 parent c78a4f2 commit 12fc856
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 6 deletions.
3 changes: 3 additions & 0 deletions .changelog/15996.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
consul: Fixed a bug where -consul-token was not respected when reverting a job
```
36 changes: 36 additions & 0 deletions e2e/consul/input/service_reversion.nomad
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
variable "service" {
type = string
}

job "service-reversion" {
datacenters = ["dc1"]
type = "service"

constraint {
attribute = "${attr.kernel.name}"
value = "linux"
}

group "sleep" {

service {
name = "${var.service}"
}

task "busybox" {
driver = "docker"

config {
image = "busybox:1"
command = "sleep"
args = ["infinity"]
}

resources {
cpu = 16
memory = 32
disk = 64
}
}
}
}
85 changes: 85 additions & 0 deletions e2e/consul/service_revert_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package consul

import (
"context"
"testing"

"github.com/hashicorp/nomad/e2e/e2eutil"
"github.com/hashicorp/nomad/helper/uuid"
"github.com/hashicorp/nomad/nomad/structs"
"github.com/shoenig/test/must"
)

func TestConsul(t *testing.T) {
// todo: migrate the remaining consul tests

nomad := e2eutil.NomadClient(t)

e2eutil.WaitForLeader(t, nomad)
e2eutil.WaitForNodesReady(t, nomad, 1)

t.Run("testServiceReversion", testServiceReversion)
}

// testServiceReversion asserts we can
// - submit a job with a service
// - update that job and modify service
// - revert the job, restoring the original service
func testServiceReversion(t *testing.T) {
const jobFile = "./input/service_reversion.nomad"
jobID := "service-reversion-" + uuid.Short()
jobIDs := []string{jobID}

// Defer a cleanup function to remove the job. This will trigger if the
// test fails, unless the cancel function is called.
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
defer e2eutil.CleanupJobsAndGCWithContext(t, ctx, &jobIDs)

// initial register of job, with service="one"
vars := []string{"-var", "service=one"}
err := e2eutil.RegisterWithArgs(jobID, jobFile, vars...)
must.NoError(t, err)

// wait for job to be running
err = e2eutil.WaitForAllocStatusExpected(jobID, "", []string{structs.AllocClientStatusRunning})
must.NoError(t, err)

// get our consul client
consulClient := e2eutil.ConsulClient(t)

assertService := func(name string, count int) {
services, _, consulErr := consulClient.Catalog().Service(name, "", nil)
must.NoError(t, consulErr)
must.Len(t, count, services, must.Sprintf("expected %d instances of %s, got %d", count, name, len(services)))
}

// query services, assert 1 instance of "one"
assertService("one", 1)
assertService("two", 0)

// second register of job, with service="two"
vars = []string{"-var", "service=two"}
err = e2eutil.RegisterWithArgs(jobID, jobFile, vars...)
must.NoError(t, err)

// wait for job to be running
err = e2eutil.WaitForAllocStatusExpected(jobID, "", []string{structs.AllocClientStatusRunning})
must.NoError(t, err)

// query services, assert 0 instance of "one" (replaced), 1 of "two"
assertService("one", 0)
assertService("two", 1)

// now revert our job back to version 0
err = e2eutil.Revert(jobID, jobFile, 0)
must.NoError(t, err)

// wait for job to be running
err = e2eutil.WaitForAllocStatusExpected(jobID, "", []string{structs.AllocClientStatusRunning})
must.NoError(t, err)

// query services, assert 1 instance of "one" (reverted), 1 of "two" (removed)
assertService("one", 1)
assertService("two", 0)
}
22 changes: 16 additions & 6 deletions e2e/e2eutil/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io/ioutil"
"os/exec"
"regexp"
"strconv"
"strings"
"testing"
"time"
Expand All @@ -19,7 +20,7 @@ import (
func Register(jobID, jobFilePath string) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
return register(jobID, jobFilePath, exec.CommandContext(ctx, "nomad", "job", "run", "-detach", "-"))
return execCmd(jobID, jobFilePath, exec.CommandContext(ctx, "nomad", "job", "run", "-detach", "-"))
}

// RegisterWithArgs registers a jobspec from a file but with a unique ID. The
Expand All @@ -34,11 +35,18 @@ func RegisterWithArgs(jobID, jobFilePath string, args ...string) error {
baseArgs = append(baseArgs, "-")
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
return execCmd(jobID, jobFilePath, exec.CommandContext(ctx, "nomad", baseArgs...))
}

return register(jobID, jobFilePath, exec.CommandContext(ctx, "nomad", baseArgs...))
// Revert reverts the job to the given version.
func Revert(jobID, jobFilePath string, version int) error {
args := []string{"job", "revert", "-detach", jobID, strconv.Itoa(version)}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
return execCmd(jobID, jobFilePath, exec.CommandContext(ctx, "nomad", args...))
}

func register(jobID, jobFilePath string, cmd *exec.Cmd) error {
func execCmd(jobID, jobFilePath string, cmd *exec.Cmd) error {
stdin, err := cmd.StdinPipe()
if err != nil {
return fmt.Errorf("could not open stdin?: %w", err)
Expand All @@ -49,14 +57,16 @@ func register(jobID, jobFilePath string, cmd *exec.Cmd) error {
return fmt.Errorf("could not open job file: %w", err)
}

// hack off the first line to replace with our unique ID
// hack off the job block to replace with our unique ID
var re = regexp.MustCompile(`(?m)^job ".*" \{`)
jobspec := re.ReplaceAllString(string(content),
fmt.Sprintf("job \"%s\" {", jobID))

go func() {
defer stdin.Close()
io.WriteString(stdin, jobspec)
defer func() {
_ = stdin.Close()
}()
_, _ = io.WriteString(stdin, jobspec)
}()

out, err := cmd.CombinedOutput()
Expand Down

0 comments on commit 12fc856

Please sign in to comment.