consul: restore consul token when reverting a job (#15996)

* consul: reset consul token on job during registration of a reversion

* e2e: add test for reverting a job with a consul service

* cl: fixup cl entry
This commit is contained in:
Seth Hoenig 2023-02-01 14:02:45 -06:00 committed by GitHub
parent 9e8325d63c
commit ca7ead191e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 143 additions and 9 deletions

3
.changelog/15996.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
consul: Fixed a bug where consul token was not respected when reverting a job
```

View File

@ -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
}
}
}
}

View File

@ -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)
}

View File

@ -7,6 +7,7 @@ import (
"io/ioutil"
"os/exec"
"regexp"
"strconv"
"strings"
"testing"
"time"
@ -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
@ -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 register(jobID, jobFilePath, exec.CommandContext(ctx, "nomad", baseArgs...))
return execCmd(jobID, jobFilePath, exec.CommandContext(ctx, "nomad", baseArgs...))
}
func register(jobID, jobFilePath string, cmd *exec.Cmd) error {
// 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 execCmd(jobID, jobFilePath string, cmd *exec.Cmd) error {
stdin, err := cmd.StdinPipe()
if err != nil {
return fmt.Errorf("could not open stdin?: %w", err)
@ -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()

View File

@ -643,8 +643,8 @@ func (j *Job) Revert(args *structs.JobRevertRequest, reply *structs.JobRegisterR
// Build the register request
revJob := jobV.Copy()
// Use Vault Token from revert request to perform registration of reverted job.
revJob.VaultToken = args.VaultToken
revJob.VaultToken = args.VaultToken // use vault token from revert to perform (re)registration
revJob.ConsulToken = args.ConsulToken // use consul token from revert to perform (re)registration
reg := &structs.JobRegisterRequest{
Job: revJob,
WriteRequest: args.WriteRequest,