From 937f0ebbbc986dee5f672c97d273a9075dbbff28 Mon Sep 17 00:00:00 2001 From: Michael Schurter Date: Fri, 22 Apr 2022 15:57:27 -0700 Subject: [PATCH] docs: update json jobs docs (#12766) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: update json jobs docs Did you know that Nomad has not 1 but 2 JSON formats for jobs? 2½ if you want to acknowledge that sometimes our JSON job representations have a Job top-level wrapper and sometimes do not. The 2½ formats are: ``` 1. HCL JSON 2. Input API JSON (top-level Job field) 2.5. Output API JSON (lacks top-level Job field) ``` `#2` is what our docs consider our API JSON. `#2.5` seems to be an accident of history we can't fix with breaking API compatibility. `#1` is an even more interesting accident of history: the `jobspec2` package automatically detects if the input to Parse is JSON and switches to a JSON parser. This behavior is undocumented, the format is unspecified, and there is no official HashiCorp tooling to produce this JSON from HCL. The plot thickens when you discover popular third party tools like hcl2json.com and https://github.com/tmccombs/hcl2json seem to produce JSON that `nomad run` accepts! Since we have no telemetry around whether or not anyone passes HCL JSON to `nomad run`, and people don't file bugs around features that Just Work, I'm choosing to leave that code path in place and *acknowledged but not suggested* in documentation. See https://github.com/hashicorp/hcl/issues/498 for a more comprehensive discussion of what officially supporting HCL JSON in Nomad would look like. (I also added some of the missing fields to the (Input API flavor) JSON Job documentation, but it still needs a lot of work to be comprehensive.) Co-authored-by: Tim Gross --- website/content/api-docs/json-jobs.mdx | 275 ++++++++++++------ website/content/docs/commands/job/run.mdx | 19 +- .../docs/job-specification/hcl2/index.mdx | 32 +- 3 files changed, 220 insertions(+), 106 deletions(-) diff --git a/website/content/api-docs/json-jobs.mdx b/website/content/api-docs/json-jobs.mdx index 4ceaefc00a..1aa1a7bd90 100644 --- a/website/content/api-docs/json-jobs.mdx +++ b/website/content/api-docs/json-jobs.mdx @@ -8,149 +8,221 @@ description: |- # JSON Job Specification -This guide covers the JSON syntax for submitting jobs to Nomad. A useful command -for generating valid JSON versions of HCL jobs is: +Nomad's HTTP API uses JSON formatted job specifications except for the +[`/job/parse` API][job-parse] which exists to convert HCL to JSON. + +The Nomad CLI includes a number of useful commands for working with JSON jobs. + +The [`nomad job run -output`][job-output] flag converts HCL jobs to JSON +without submitting the job: ```shell-session $ nomad job run -output my-job.nomad ``` +The [`nomad job inspect`][job-inspect] command retrieves the JSON specification +for an existing job: + +```shell-session +$ nomad job inspect example +``` + +The [`nomad job run -json`][job-run-json] flag submits a JSON formatted job: + +```shell-session +$ nomad job run -json example.json +``` + +[job-inspect]: /docs/commands/job/inspect +[job-output]: /docs/commands/job/run#output +[job-parse]: /api-docs/jobs#parse-job +[job-run-json]: /docs/commands/job/run#json + ## Syntax -Below is the JSON representation of the job outputted by `$ nomad init`: +Below is the JSON representation of the example job as well as the commands to +reproduce it: + +```shell-session +$ nomad init +Example job file written to example.nomad +$ nomad job run -output example.nomad +``` ```json { "Job": { + "Region": null, + "Namespace": null, "ID": "example", "Name": "example", "Type": "service", - "Priority": 50, - "Datacenters": ["dc1"], + "Priority": null, + "AllAtOnce": null, + "Datacenters": [ + "dc1" + ], + "Constraints": null, + "Affinities": null, "TaskGroups": [ { "Name": "cache", "Count": 1, - "Migrate": { - "HealthCheck": "checks", - "HealthyDeadline": 300000000000, - "MaxParallel": 1, - "MinHealthyTime": 10000000000 - }, + "Constraints": null, + "Affinities": null, "Tasks": [ { "Name": "redis", "Driver": "docker", "User": "", + "Lifecycle": null, "Config": { "image": "redis:3.2", - "port_map": [ - { - "db": 6379 - } + "ports": [ + "db" ] }, - "Services": [ - { - "Id": "", - "Name": "redis-cache", - "Tags": ["global", "cache"], - "Meta": { - "meta": "for my service" - }, - "PortLabel": "db", - "AddressMode": "", - "Checks": [ - { - "Id": "", - "Name": "alive", - "Type": "tcp", - "Command": "", - "Args": null, - "Header": {}, - "Method": "", - "Path": "", - "Protocol": "", - "PortLabel": "", - "Interval": 10000000000, - "Timeout": 2000000000, - "InitialStatus": "", - "TLSSkipVerify": false, - "CheckRestart": { - "Limit": 3, - "Grace": 30000000000, - "IgnoreWarnings": false - } - } - ] - } - ], + "Constraints": null, + "Affinities": null, + "Env": null, + "Services": null, "Resources": { "CPU": 500, + "Cores": null, "MemoryMB": 256, - "Networks": [ - { - "Device": "", - "CIDR": "", - "IP": "", - "MBits": 10, - "DynamicPorts": [ - { - "Label": "db", - "Value": 0 - } - ] - } - ] + "MemoryMaxMB": null, + "DiskMB": null, + "Networks": null, + "Devices": null, + "IOPS": null }, - "Leader": false + "RestartPolicy": null, + "Meta": null, + "KillTimeout": null, + "LogConfig": null, + "Artifacts": null, + "Vault": null, + "Templates": null, + "DispatchPayload": null, + "VolumeMounts": null, + "Leader": false, + "ShutdownDelay": 0, + "KillSignal": "", + "Kind": "", + "ScalingPolicies": null } ], + "Spreads": null, + "Volumes": null, "RestartPolicy": { "Interval": 1800000000000, "Attempts": 2, "Delay": 15000000000, "Mode": "fail" }, - "ReschedulePolicy": { - "Attempts": 10, - "Delay": 30000000000, - "DelayFunction": "exponential", - "Interval": 0, - "MaxDelay": 3600000000000, - "Unlimited": true - }, + "ReschedulePolicy": null, "EphemeralDisk": { + "Sticky": null, + "Migrate": null, "SizeMB": 300 - } + }, + "Update": null, + "Migrate": null, + "Networks": [ + { + "Mode": "", + "Device": "", + "CIDR": "", + "IP": "", + "DNS": null, + "ReservedPorts": null, + "DynamicPorts": [ + { + "Label": "db", + "Value": 0, + "To": 6379, + "HostNetwork": "" + } + ], + "Hostname": "", + "MBits": null + } + ], + "Meta": null, + "Services": [ + { + "Id": "", + "Name": "redis-cache", + "Tags": [ + "global", + "cache" + ], + "CanaryTags": null, + "EnableTagOverride": false, + "PortLabel": "db", + "AddressMode": "", + "Checks": null, + "CheckRestart": null, + "Connect": null, + "Meta": null, + "CanaryMeta": null, + "TaskName": "", + "OnUpdate": "", + "Provider": "" + } + ], + "ShutdownDelay": null, + "StopAfterClientDisconnect": null, + "MaxClientDisconnect": null, + "Scaling": null, + "Consul": null } ], "Update": { + "Stagger": null, "MaxParallel": 1, + "HealthCheck": null, "MinHealthyTime": 10000000000, "HealthyDeadline": 180000000000, + "ProgressDeadline": 600000000000, + "Canary": 0, "AutoRevert": false, - "Canary": 0 - } + "AutoPromote": null + }, + "Multiregion": null, + "Spreads": null, + "Periodic": null, + "ParameterizedJob": null, + "Reschedule": null, + "Migrate": { + "MaxParallel": 1, + "HealthCheck": "checks", + "MinHealthyTime": 10000000000, + "HealthyDeadline": 300000000000 + }, + "Meta": null, + "ConsulToken": null, + "VaultToken": null, + "Stop": null, + "ParentID": null, + "Dispatched": false, + "DispatchIdempotencyToken": null, + "Payload": null, + "ConsulNamespace": null, + "VaultNamespace": null, + "NomadTokenID": null, + "Status": null, + "StatusDescription": null, + "Stable": null, + "Version": null, + "SubmitTime": null, + "CreateIndex": null, + "ModifyIndex": null, + "JobModifyIndex": null } } ``` -The example JSON could be submitted as a job using the following: - -```shell-session -$ curl -XPUT -d @example.json http://127.0.0.1:4646/v1/job/example -{ - "EvalID": "5d6ded54-0b2a-8858-6583-be5f476dec9d", - "EvalCreateIndex": 12, - "JobModifyIndex": 11, - "Warnings": "", - "Index": 12, - "LastContact": 0, - "KnownLeader": false -} -``` - ## Syntax Reference Following is a syntax reference for the possible keys that are supported and @@ -183,6 +255,15 @@ The `Job` object supports the following keys: - `Meta` - Annotates the job with opaque metadata. +- `ConsulToken` - Specifies the Consul token that proves the submitter of the + job has access to the Service Identity policies associated with the job's + Consul Connect enabled services. This field is only used to transfer the + token and is not stored after job submission. + +- `VaultToken` - Specifies the Vault token that proves the submitter of the job + has access to the specified policies in the `vault` stanza. This field is + only used to transfer the token and is not stored after job submission. + - `Namespace` - The namespace to execute the job in, defaults to "default". Prior to Nomad 1.0 namespaces were Enterprise-only. @@ -200,6 +281,9 @@ The `Job` object supports the following keys: dispatching against the parameterized job. The options for this field are "optional", "required" and "forbidden". The default value is "optional". +- `DispatchIdempotencyToken` - Optional identifier used to prevent more than one + instance of the job from being dispatched. + - `Payload` - The payload may not be set when submitting a job but may appear in a dispatched job. The `Payload` will be a base64 encoded string containing the payload that the job was dispatched with. The `payload` has a **maximum size @@ -438,6 +522,15 @@ The `Task` object supports the following keys: defined in the resources block. This could be a label of either a dynamic or a static port. + - `Provider`: Specifies the service registration provider to use for service + registrations. Valid options are either `consul` or `nomad`. All services + within a single task group must utilise the same provider value. + + - `Address`: Specifies a custom address to advertise in Consul or Nomad + service registration. If set, `AddressMode` must be in `auto` mode. Useful + with interpolation - for example to advertise the public IP address of an + AWS EC2 instance set this to `${attr.unique.platform.aws.public-ipv4}`. + - `AddressMode`: Specifies what address (host or driver-specific) this service should advertise. This setting is supported in Docker since Nomad 0.6 and rkt since Nomad 0.7. Valid options are: diff --git a/website/content/docs/commands/job/run.mdx b/website/content/docs/commands/job/run.mdx index d450e8a2c1..03d191c436 100644 --- a/website/content/docs/commands/job/run.mdx +++ b/website/content/docs/commands/job/run.mdx @@ -74,6 +74,10 @@ that volume. - `-eval-priority`: Override the priority of the evaluations produced as a result of this job submission. By default, this is set to the priority of the job. +- `-json`: Parses the job file as JSON. If the outer object has a Job field, + such as from "nomad job inspect" or "nomad run -output", the value of the + field is used as the job. See [JSON Jobs] for details. + - `-hcl1`: If set, HCL1 parser is used for parsing the job spec. - `-hcl2-strict`: Whether an error should be produced from the HCL2 parser where @@ -225,11 +229,18 @@ $ nomad job run example.nomad ==> 2021-06-14T09:25:09-07:00: Evaluation "88a91284" finished with status "complete" ``` -[`go-getter`]: https://github.com/hashicorp/go-getter -[deployment status]: /docs/commands/deployment#status [`batch`]: /docs/schedulers#batch -[`system`]: /docs/schedulers#system -[`job plan` command]: /docs/commands/job/plan +[`consul` stanza `allow_unauthenticated`]: /docs/configuration/consul#allow_unauthenticated +[deployment status]: /docs/commands/deployment#status [eval status]: /docs/commands/eval-status +[`go-getter`]: https://github.com/hashicorp/go-getter +[`job plan` command]: /docs/commands/job/plan [job specification]: /docs/job-specification +<<<<<<< HEAD [`allow_unauthenticated`]: /docs/configuration/consul#allow_unauthenticated +======= +[JSON jobs]: /api-docs/json-jobs +[`system`]: /docs/schedulers#system +[`vault` stanza `allow_unauthenticated`]: /docs/configuration/vault#allow_unauthenticated +[`vault_token`]: /docs/job-specification/job#vault_token +>>>>>>> e4d6d5103 (docs: update json jobs docs (#12766)) diff --git a/website/content/docs/job-specification/hcl2/index.mdx b/website/content/docs/job-specification/hcl2/index.mdx index 0b44bc7fd2..53d10bad25 100644 --- a/website/content/docs/job-specification/hcl2/index.mdx +++ b/website/content/docs/job-specification/hcl2/index.mdx @@ -18,13 +18,6 @@ adding expressions and input variables support to improve job spec reusability and readability. Also, the new HCL2 parser improves the error messages for invalid jobs. - - ## HCL Parsing Context The [Nomad API uses JSON][jobs-api], not HCL, to represent Nomad jobs. @@ -38,11 +31,28 @@ context from the local environment of the CLI (e.g., files, environment variable [jobs-api]: /api-docs/jobs -## Syntax +## JSON Jobs + +Since HCL is a superset of JSON, `nomad job run example.json` will attempt to +parse a JSON job using the HCL parser. However, the JSON format accepted by +the HCL parser is not the same as the [API's JSON format][json-jobs-api]. The +HCL parser's JSON format is unspecified, so the API format is preferred. You can +use the API format with the [`-json` command line flag][run-json]: + +```shell-session +$ # Generate an HCL formatted job +$ nomad init + +$ # Convert HCL to API JSON format +$ nomad job run -output example.nomad > example.json + +$ # Submit with the -json flag +$ nomad job run -json example.json +``` + -The main purpose of the HCL language in Nomad is defining jobs. All other -language features exist only to make the definition of builds more flexible and -convenient. +[json-jobs-api]: /api-docs/json-jobs +[run-json]: /docs/commands/job/run#json ## Arguments, Blocks, and Expressions