github.com/ferranbt/nomad@v0.9.3-0.20190607002617-85c449b7667c/command/job_revert.go (about)

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