github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/command/job_revert.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "os" 6 "strings" 7 8 "github.com/hashicorp/nomad/api" 9 "github.com/hashicorp/nomad/api/contexts" 10 "github.com/posener/complete" 11 ) 12 13 type JobRevertCommand struct { 14 Meta 15 } 16 17 func (c *JobRevertCommand) Help() string { 18 helpText := ` 19 Usage: nomad job revert [options] <job> <version> 20 21 Revert is used to revert a job to a prior version of the job. The available 22 versions to revert to can be found using "nomad job history" command. 23 24 When ACLs are enabled, this command requires a token with the 'submit-job' 25 and 'list-jobs' capabilities for the job's namespace. 26 27 General Options: 28 29 ` + generalOptionsUsage(usageOptsDefault) + ` 30 31 Revert Options: 32 33 -detach 34 Return immediately instead of entering monitor mode. After job revert, 35 the evaluation ID will be printed to the screen, which can be used to 36 examine the evaluation using the eval-status command. 37 38 -consul-token 39 The Consul token used to verify that the caller has access to the Service 40 Identity policies associated in the targeted version of the job. 41 42 -vault-token 43 The Vault token used to verify that the caller has access to the Vault 44 policies in the targeted version of the job. 45 46 -verbose 47 Display full information. 48 ` 49 return strings.TrimSpace(helpText) 50 } 51 52 func (c *JobRevertCommand) Synopsis() string { 53 return "Revert to a prior version of the job" 54 } 55 56 func (c *JobRevertCommand) AutocompleteFlags() complete.Flags { 57 return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient), 58 complete.Flags{ 59 "-detach": complete.PredictNothing, 60 "-verbose": complete.PredictNothing, 61 }) 62 } 63 64 func (c *JobRevertCommand) AutocompleteArgs() complete.Predictor { 65 return complete.PredictFunc(func(a complete.Args) []string { 66 client, err := c.Meta.Client() 67 if err != nil { 68 return nil 69 } 70 71 resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Jobs, nil) 72 if err != nil { 73 return []string{} 74 } 75 return resp.Matches[contexts.Jobs] 76 }) 77 } 78 79 func (c *JobRevertCommand) Name() string { return "job revert" } 80 81 func (c *JobRevertCommand) Run(args []string) int { 82 var detach, verbose bool 83 var consulToken, vaultToken string 84 85 flags := c.Meta.FlagSet(c.Name(), FlagSetClient) 86 flags.Usage = func() { c.Ui.Output(c.Help()) } 87 flags.BoolVar(&detach, "detach", false, "") 88 flags.BoolVar(&verbose, "verbose", false, "") 89 flags.StringVar(&consulToken, "consul-token", "", "") 90 flags.StringVar(&vaultToken, "vault-token", "", "") 91 92 if err := flags.Parse(args); err != nil { 93 return 1 94 } 95 96 // Truncate the id unless full length is requested 97 length := shortId 98 if verbose { 99 length = fullId 100 } 101 102 // Check that we got two args 103 args = flags.Args() 104 if l := len(args); l != 2 { 105 c.Ui.Error("This command takes two arguments: <job> <version>") 106 c.Ui.Error(commandErrorText(c)) 107 return 1 108 } 109 110 // Get the HTTP client 111 client, err := c.Meta.Client() 112 if err != nil { 113 c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) 114 return 1 115 } 116 117 // Parse the Consul token 118 if consulToken == "" { 119 // Check the environment variable 120 consulToken = os.Getenv("CONSUL_HTTP_TOKEN") 121 } 122 123 // Parse the Vault token 124 if vaultToken == "" { 125 // Check the environment variable 126 vaultToken = os.Getenv("VAULT_TOKEN") 127 } 128 129 jobID := args[0] 130 revertVersion, ok, err := parseVersion(args[1]) 131 if !ok { 132 c.Ui.Error("The job version to revert to must be specified using the -job-version flag") 133 return 1 134 } 135 if err != nil { 136 c.Ui.Error(fmt.Sprintf("Failed to parse job-version flag: %v", err)) 137 return 1 138 } 139 140 // Check if the job exists 141 jobs, _, err := client.Jobs().PrefixList(jobID) 142 if err != nil { 143 c.Ui.Error(fmt.Sprintf("Error listing jobs: %s", err)) 144 return 1 145 } 146 if len(jobs) == 0 { 147 c.Ui.Error(fmt.Sprintf("No job(s) with prefix or id %q found", jobID)) 148 return 1 149 } 150 if len(jobs) > 1 && (c.allNamespaces() || strings.TrimSpace(jobID) != jobs[0].ID) { 151 c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) 152 return 1 153 } 154 155 // Prefix lookup matched a single job 156 q := &api.WriteOptions{Namespace: jobs[0].JobSummary.Namespace} 157 resp, _, err := client.Jobs().Revert(jobs[0].ID, revertVersion, nil, q, consulToken, vaultToken) 158 if err != nil { 159 c.Ui.Error(fmt.Sprintf("Error retrieving job versions: %s", err)) 160 return 1 161 } 162 163 // Nothing to do 164 evalCreated := resp.EvalID != "" 165 if detach || !evalCreated { 166 return 0 167 } 168 169 mon := newMonitor(c.Ui, client, length) 170 return mon.monitor(resp.EvalID) 171 }