diff --git a/api/api.go b/api/api.go index 7693bde43a23..d1f985dbefe7 100644 --- a/api/api.go +++ b/api/api.go @@ -596,6 +596,9 @@ func (r *request) setWriteOptions(q *WriteOptions) { if q.AuthToken != "" { r.token = q.AuthToken } + if q.IdempotencyToken != "" { + r.params.Set("idempotency_token", q.IdempotencyToken) + } r.ctx = q.Context() } diff --git a/api/api_test.go b/api/api_test.go index dda4a571a13b..a845f6410547 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -255,9 +255,10 @@ func TestSetWriteOptions(t *testing.T) { r, _ := c.newRequest("GET", "/v1/jobs") q := &WriteOptions{ - Region: "foo", - Namespace: "bar", - AuthToken: "foobar", + Region: "foo", + Namespace: "bar", + AuthToken: "foobar", + IdempotencyToken: "idempotent", } r.setWriteOptions(q) @@ -267,6 +268,9 @@ func TestSetWriteOptions(t *testing.T) { if r.params.Get("namespace") != "bar" { t.Fatalf("bad: %v", r.params) } + if r.params.Get("idempotency_token") != "idempotent" { + t.Fatalf("bad: %v", r.params) + } if r.token != "foobar" { t.Fatalf("bad: %v", r.token) } diff --git a/command/agent/http.go b/command/agent/http.go index 1f4e48da4332..4a93ae74f764 100644 --- a/command/agent/http.go +++ b/command/agent/http.go @@ -666,6 +666,13 @@ func parseNamespace(req *http.Request, n *string) { } } +// parseIdempotencyToken is used to parse the ?idempotency_token parameter +func parseIdempotencyToken(req *http.Request, n *string) { + if idempotencyToken := req.URL.Query().Get("idempotency_token"); idempotencyToken != "" { + *n = idempotencyToken + } +} + // parseBool parses a query parameter to a boolean or returns (nil, nil) if the // parameter is not present. func parseBool(req *http.Request, field string) (*bool, error) { @@ -721,6 +728,7 @@ func (s *HTTPServer) parseWriteRequest(req *http.Request, w *structs.WriteReques parseNamespace(req, &w.Namespace) s.parseToken(req, &w.AuthToken) s.parseRegion(req, &w.Region) + parseIdempotencyToken(req, &w.IdempotencyToken) } // wrapUntrustedContent wraps handlers in a http.ResponseWriter that prevents diff --git a/command/agent/job_endpoint_test.go b/command/agent/job_endpoint_test.go index bd5668a53f4e..420e4ac2ac81 100644 --- a/command/agent/job_endpoint_test.go +++ b/command/agent/job_endpoint_test.go @@ -9,13 +9,14 @@ import ( "time" "github.com/golang/snappy" + "github.com/kr/pretty" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + api "github.com/hashicorp/nomad/api" "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/nomad/mock" "github.com/hashicorp/nomad/nomad/structs" - "github.com/kr/pretty" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestHTTP_JobsList(t *testing.T) { @@ -1454,8 +1455,9 @@ func TestHTTP_JobDispatch(t *testing.T) { respW := httptest.NewRecorder() args2 := structs.JobDispatchRequest{ WriteRequest: structs.WriteRequest{ - Region: "global", - Namespace: structs.DefaultNamespace, + Region: "global", + Namespace: structs.DefaultNamespace, + IdempotencyToken: "foo", }, } buf := encodeReq(args2)