diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ba87543e3e..efc0d672c1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,10 @@ IMPROVEMENTS: +* cli: Added option to change the name of the file created by the `nomad init` command [[GH-6520]](https://github.com/hashicorp/nomad/pull/6520) * scheduler: Removed penalty for allocation's previous node if the allocation did not fail. [[GH-6781](https://github.com/hashicorp/nomad/issues/6781)] * scheduler: Reduced logging verbosity during preemption [[GH-6849](https://github.com/hashicorp/nomad/issues/6849)] + BUG FIXES: * cli: Fixed a bug where `nomad monitor -node-id` would cause a cli panic when no nodes where found. [[GH-6828](https://github.com/hashicorp/nomad/issues/6828)] diff --git a/command/job_init.go b/command/job_init.go index e492fa8048e..94522ae7e07 100644 --- a/command/job_init.go +++ b/command/job_init.go @@ -23,11 +23,11 @@ type JobInitCommand struct { func (c *JobInitCommand) Help() string { helpText := ` -Usage: nomad job init -Alias: nomad init +Usage: nomad job init +Alias: nomad init - Creates an example job file that can be used as a starting - point to customize further. + Creates an example job file that can be used as a starting point to customize + further. If no filename is given, the default of "example.nomad" will be used. Init Options: @@ -71,20 +71,27 @@ func (c *JobInitCommand) Run(args []string) int { } // Check for misuse - if len(flags.Args()) != 0 { - c.Ui.Error("This command takes no arguments") + // Check that we either got no filename or exactly one. + args = flags.Args() + if len(args) > 1 { + c.Ui.Error("This command takes either no arguments or one: ") c.Ui.Error(commandErrorText(c)) return 1 } + filename := DefaultInitName + if len(args) == 1 { + filename = args[0] + } + // Check if the file already exists - _, err := os.Stat(DefaultInitName) + _, err := os.Stat(filename) if err != nil && !os.IsNotExist(err) { - c.Ui.Error(fmt.Sprintf("Failed to stat '%s': %v", DefaultInitName, err)) + c.Ui.Error(fmt.Sprintf("Failed to stat '%s': %v", filename, err)) return 1 } if !os.IsNotExist(err) { - c.Ui.Error(fmt.Sprintf("Job '%s' already exists", DefaultInitName)) + c.Ui.Error(fmt.Sprintf("Job '%s' already exists", filename)) return 1 } @@ -107,13 +114,13 @@ func (c *JobInitCommand) Run(args []string) int { } // Write out the example - err = ioutil.WriteFile(DefaultInitName, jobSpec, 0660) + err = ioutil.WriteFile(filename, jobSpec, 0660) if err != nil { - c.Ui.Error(fmt.Sprintf("Failed to write '%s': %v", DefaultInitName, err)) + c.Ui.Error(fmt.Sprintf("Failed to write '%s': %v", filename, err)) return 1 } // Success - c.Ui.Output(fmt.Sprintf("Example job file written to %s", DefaultInitName)) + c.Ui.Output(fmt.Sprintf("Example job file written to %s", filename)) return 0 } diff --git a/command/job_init_test.go b/command/job_init_test.go index b015feb4526..023d4e2e2c5 100644 --- a/command/job_init_test.go +++ b/command/job_init_test.go @@ -88,3 +88,58 @@ func TestInitCommand_defaultJob(t *testing.T) { t.Error("default job contains tab character - please convert to spaces") } } + +func TestInitCommand_customFilename(t *testing.T) { + t.Parallel() + ui := new(cli.MockUi) + cmd := &JobInitCommand{Meta: Meta{Ui: ui}} + filename := "custom.nomad" + + // Ensure we change the cwd back + origDir, err := os.Getwd() + if err != nil { + t.Fatalf("err: %s", err) + } + defer os.Chdir(origDir) + + // Create a temp dir and change into it + dir, err := ioutil.TempDir("", "nomad") + if err != nil { + t.Fatalf("err: %s", err) + } + defer os.RemoveAll(dir) + if err := os.Chdir(dir); err != nil { + t.Fatalf("err: %s", err) + } + + // Works if the file doesn't exist + if code := cmd.Run([]string{filename}); code != 0 { + t.Fatalf("expect exit code 0, got: %d", code) + } + content, err := ioutil.ReadFile(filename) + if err != nil { + t.Fatalf("err: %s", err) + } + defaultJob, _ := Asset("command/assets/example.nomad") + if string(content) != string(defaultJob) { + t.Fatalf("unexpected file content\n\n%s", string(content)) + } + + // Works with -short flag + os.Remove(filename) + if code := cmd.Run([]string{"-short", filename}); code != 0 { + require.Zero(t, code, "unexpected exit code: %d", code) + } + content, err = ioutil.ReadFile(filename) + require.NoError(t, err) + shortJob, _ := Asset("command/assets/example-short.nomad") + require.Equal(t, string(content), string(shortJob)) + + // Fails if the file exists + if code := cmd.Run([]string{filename}); code != 1 { + t.Fatalf("expect exit code 1, got: %d", code) + } + if out := ui.ErrorWriter.String(); !strings.Contains(out, "exists") { + t.Fatalf("expect file exists error, got: %s", out) + } +} diff --git a/website/source/docs/commands/job/init.html.md.erb b/website/source/docs/commands/job/init.html.md similarity index 78% rename from website/source/docs/commands/job/init.html.md.erb rename to website/source/docs/commands/job/init.html.md index 2973c8ada74..f939cc02f5c 100644 --- a/website/source/docs/commands/job/init.html.md.erb +++ b/website/source/docs/commands/job/init.html.md @@ -14,15 +14,18 @@ The `job init` command creates an example [job specification][jobspec] in the current directory that demonstrates some common configurations for tasks, task groups, runtime constraints, and resource allocation. -Please refer to the [jobspec] and [drivers] pages to learn how to customize the -template. - ## Usage ```plaintext -nomad job init [options] +nomad job init [options] [filename] ``` +You may optionally supply a filename for the example job to be written to. The +default filename for the generated file is "example.nomad". + +Please refer to the [jobspec] and [drivers] pages to learn how to customize the +template. + ## Init Options - `-short`: If set, a minimal jobspec without comments is emitted. @@ -38,4 +41,4 @@ Example job file written to example.nomad ``` [jobspec]: /docs/job-specification/index.html "Nomad Job Specification" -[drivers]: /docs/drivers/index.html +[drivers]: /docs/drivers/index.html "Nomad Task Drivers documentation"