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  }