2023-04-10 15:36:59 +00:00
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
2015-09-21 00:06:02 +00:00
package command
import (
"fmt"
"os"
2015-09-23 00:06:23 +00:00
"strings"
2018-05-11 03:19:08 +00:00
2023-02-02 15:37:40 +00:00
"github.com/hashicorp/nomad/api"
2023-02-10 17:02:29 +00:00
"github.com/hashicorp/nomad/command/asset"
2018-05-11 03:19:08 +00:00
"github.com/posener/complete"
2015-09-23 00:06:23 +00:00
)
const (
// DefaultInitName is the default name we use when
// initializing the example file
2023-02-02 17:47:47 +00:00
DefaultInitName = "example.nomad.hcl"
2015-09-21 00:06:02 +00:00
)
2018-03-21 00:37:28 +00:00
// JobInitCommand generates a new job template that you can customize to your
2015-09-21 00:06:02 +00:00
// liking, like vagrant init
2018-03-21 00:37:28 +00:00
type JobInitCommand struct {
2015-09-21 00:06:02 +00:00
Meta
}
2018-03-21 00:37:28 +00:00
func ( c * JobInitCommand ) Help ( ) string {
2015-09-23 00:06:23 +00:00
helpText := `
2019-12-19 19:59:12 +00:00
Usage : nomad job init < filename >
Alias : nomad init < filename >
2015-09-23 00:06:23 +00:00
2019-12-19 19:59:12 +00:00
Creates an example job file that can be used as a starting point to customize
2023-02-02 17:47:47 +00:00
further . If no filename is given , the default of "example.nomad.hcl" will be used .
2018-05-01 16:51:13 +00:00
Init Options :
- short
If the short flag is set , a minimal jobspec without comments is emitted .
2019-08-14 18:07:52 +00:00
- connect
If the connect flag is set , the jobspec includes Consul Connect integration .
2023-02-02 15:37:40 +00:00
- template
Specifies a predefined template to initialize . Must be a Nomad Variable that
2023-03-09 17:17:15 +00:00
lives at nomad / job - templates / < template >
2023-02-02 15:37:40 +00:00
- list - templates
Display a list of possible job templates to pass to - template . Reads from
2023-03-09 17:17:15 +00:00
all variables pathed at nomad / job - templates / < template >
2015-09-23 00:06:23 +00:00
`
return strings . TrimSpace ( helpText )
2015-09-21 00:06:02 +00:00
}
2018-03-21 00:37:28 +00:00
func ( c * JobInitCommand ) Synopsis ( ) string {
2015-09-23 00:06:23 +00:00
return "Create an example job file"
}
2015-09-21 00:06:02 +00:00
2018-05-11 03:19:08 +00:00
func ( c * JobInitCommand ) AutocompleteFlags ( ) complete . Flags {
return mergeAutocompleteFlags ( c . Meta . AutocompleteFlags ( FlagSetClient ) ,
complete . Flags {
"-short" : complete . PredictNothing ,
} )
}
2018-05-11 19:19:16 +00:00
func ( c * JobInitCommand ) AutocompleteArgs ( ) complete . Predictor {
return complete . PredictNothing
}
2018-04-18 16:02:11 +00:00
func ( c * JobInitCommand ) Name ( ) string { return "job init" }
2018-03-21 00:37:28 +00:00
func ( c * JobInitCommand ) Run ( args [ ] string ) int {
2018-05-01 16:51:13 +00:00
var short bool
2019-08-14 18:07:52 +00:00
var connect bool
2023-02-02 15:37:40 +00:00
var template string
var listTemplates bool
2018-05-01 16:51:13 +00:00
flags := c . Meta . FlagSet ( c . Name ( ) , FlagSetClient )
flags . Usage = func ( ) { c . Ui . Output ( c . Help ( ) ) }
flags . BoolVar ( & short , "short" , false , "" )
2019-08-14 18:07:52 +00:00
flags . BoolVar ( & connect , "connect" , false , "" )
2023-02-02 15:37:40 +00:00
flags . StringVar ( & template , "template" , "" , "The name of the job template variable to initialize" )
flags . BoolVar ( & listTemplates , "list-templates" , false , "" )
2018-05-01 16:51:13 +00:00
if err := flags . Parse ( args ) ; err != nil {
return 1
}
2015-09-30 21:21:50 +00:00
// Check for misuse
2019-12-19 19:59:12 +00:00
// 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: <filename>" )
2018-04-18 16:02:11 +00:00
c . Ui . Error ( commandErrorText ( c ) )
2015-09-30 21:21:50 +00:00
return 1
}
2019-12-19 19:59:12 +00:00
filename := DefaultInitName
if len ( args ) == 1 {
filename = args [ 0 ]
}
2015-09-23 00:06:23 +00:00
// Check if the file already exists
2019-12-19 19:59:12 +00:00
_ , err := os . Stat ( filename )
2015-09-30 21:21:50 +00:00
if err != nil && ! os . IsNotExist ( err ) {
2019-12-19 19:59:12 +00:00
c . Ui . Error ( fmt . Sprintf ( "Failed to stat '%s': %v" , filename , err ) )
2015-09-21 00:06:02 +00:00
return 1
}
2023-02-02 15:37:40 +00:00
if ! os . IsNotExist ( err ) && ! listTemplates {
2019-12-19 19:59:12 +00:00
c . Ui . Error ( fmt . Sprintf ( "Job '%s' already exists" , filename ) )
2015-09-30 21:21:50 +00:00
return 1
}
2015-09-21 00:06:02 +00:00
2018-05-01 16:51:13 +00:00
var jobSpec [ ] byte
2023-02-02 15:37:40 +00:00
if listTemplates {
// Get the HTTP client
client , err := c . Meta . Client ( )
if err != nil {
c . Ui . Error ( fmt . Sprintf ( "Error initializing client: %s" , err ) )
return 1
}
qo := & api . QueryOptions {
Namespace : c . Meta . namespace ,
}
// Get and list all variables at nomad/job-templates
vars , _ , err := client . Variables ( ) . PrefixList ( "nomad/job-templates/" , qo )
if err != nil {
c . Ui . Error ( fmt . Sprintf ( "Error retrieving job templates from the server; unable to read variables at path nomad/job-templates/. Error: %s" , err ) )
return 1
}
if len ( vars ) == 0 {
c . Ui . Error ( "No variables in nomad/job-templates" )
return 1
} else {
c . Ui . Output ( "Use nomad job init -template=<template> with any of the following:" )
for _ , v := range vars {
c . Ui . Output ( fmt . Sprintf ( " %s" , strings . TrimPrefix ( v . Path , "nomad/job-templates/" ) ) )
}
}
return 0
} else if template != "" {
// Get the HTTP client
client , err := c . Meta . Client ( )
if err != nil {
c . Ui . Error ( fmt . Sprintf ( "Error initializing: %s" , err ) )
return 1
}
qo := & api . QueryOptions {
Namespace : c . Meta . namespace ,
}
sv , _ , err := client . Variables ( ) . Read ( "nomad/job-templates/" + template , qo )
if err != nil {
if err . Error ( ) == "variable not found" {
c . Ui . Warn ( errVariableNotFound )
return 1
}
c . Ui . Error ( fmt . Sprintf ( "Error retrieving variable: %s" , err ) )
return 1
}
if v , ok := sv . Items [ "template" ] ; ok {
c . Ui . Output ( fmt . Sprintf ( "Initializing a job template from %s" , template ) )
jobSpec = [ ] byte ( v )
} else {
c . Ui . Error ( fmt . Sprintf ( "Job template %q is malformed and is missing a template field. Please visit the jobs/run/templates route in the Nomad UI to add it" , template ) )
return 1
}
} else {
switch {
case connect && ! short :
2023-02-10 17:02:29 +00:00
jobSpec = asset . JobConnect
2023-02-02 15:37:40 +00:00
case connect && short :
2023-02-10 17:02:29 +00:00
jobSpec = asset . JobConnectShort
2023-02-02 15:37:40 +00:00
case ! connect && short :
2023-02-10 17:02:29 +00:00
jobSpec = asset . JobExampleShort
2023-02-02 15:37:40 +00:00
default :
2023-02-10 17:02:29 +00:00
jobSpec = asset . JobExample
2023-02-02 15:37:40 +00:00
}
2018-05-01 16:51:13 +00:00
}
2015-09-23 00:06:23 +00:00
// Write out the example
2023-03-08 15:20:04 +00:00
err = os . WriteFile ( filename , jobSpec , 0660 )
2015-09-21 00:06:02 +00:00
if err != nil {
2019-12-19 19:59:12 +00:00
c . Ui . Error ( fmt . Sprintf ( "Failed to write '%s': %v" , filename , err ) )
2015-09-21 00:06:02 +00:00
return 1
}
2015-09-23 00:06:23 +00:00
// Success
2019-12-19 19:59:12 +00:00
c . Ui . Output ( fmt . Sprintf ( "Example job file written to %s" , filename ) )
2015-09-21 00:06:02 +00:00
return 0
}