github.com/ThomasObenaus/nomad@v0.11.1/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    -consul-token
    35     The Consul token used to verify that the caller has access to the Service
    36     Identity policies associated in the targeted version of the job.
    37  
    38    -vault-token 
    39     The Vault token used to verify that the caller has access to the Vault 
    40     policies in the targeted version of the job.
    41  
    42    -verbose
    43      Display full information.
    44  `
    45  	return strings.TrimSpace(helpText)
    46  }
    47  
    48  func (c *JobRevertCommand) Synopsis() string {
    49  	return "Revert to a prior version of the job"
    50  }
    51  
    52  func (c *JobRevertCommand) AutocompleteFlags() complete.Flags {
    53  	return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
    54  		complete.Flags{
    55  			"-detach":  complete.PredictNothing,
    56  			"-verbose": complete.PredictNothing,
    57  		})
    58  }
    59  
    60  func (c *JobRevertCommand) AutocompleteArgs() complete.Predictor {
    61  	return complete.PredictFunc(func(a complete.Args) []string {
    62  		client, err := c.Meta.Client()
    63  		if err != nil {
    64  			return nil
    65  		}
    66  
    67  		resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Jobs, nil)
    68  		if err != nil {
    69  			return []string{}
    70  		}
    71  		return resp.Matches[contexts.Jobs]
    72  	})
    73  }
    74  
    75  func (c *JobRevertCommand) Name() string { return "job revert" }
    76  
    77  func (c *JobRevertCommand) Run(args []string) int {
    78  	var detach, verbose bool
    79  	var consulToken, vaultToken string
    80  
    81  	flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
    82  	flags.Usage = func() { c.Ui.Output(c.Help()) }
    83  	flags.BoolVar(&detach, "detach", false, "")
    84  	flags.BoolVar(&verbose, "verbose", false, "")
    85  	flags.StringVar(&consulToken, "consul-token", "", "")
    86  	flags.StringVar(&vaultToken, "vault-token", "", "")
    87  
    88  	if err := flags.Parse(args); err != nil {
    89  		return 1
    90  	}
    91  
    92  	// Truncate the id unless full length is requested
    93  	length := shortId
    94  	if verbose {
    95  		length = fullId
    96  	}
    97  
    98  	// Check that we got two args
    99  	args = flags.Args()
   100  	if l := len(args); l != 2 {
   101  		c.Ui.Error("This command takes two arguments: <job> <version>")
   102  		c.Ui.Error(commandErrorText(c))
   103  		return 1
   104  	}
   105  
   106  	// Get the HTTP client
   107  	client, err := c.Meta.Client()
   108  	if err != nil {
   109  		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
   110  		return 1
   111  	}
   112  
   113  	// Parse the Consul token
   114  	if consulToken == "" {
   115  		// Check the environment variable
   116  		consulToken = os.Getenv("CONSUL_HTTP_TOKEN")
   117  	}
   118  
   119  	// Parse the Vault token
   120  	if vaultToken == "" {
   121  		// Check the environment variable
   122  		vaultToken = os.Getenv("VAULT_TOKEN")
   123  	}
   124  
   125  	jobID := args[0]
   126  	revertVersion, ok, err := parseVersion(args[1])
   127  	if !ok {
   128  		c.Ui.Error("The job version to revert to must be specified using the -job-version flag")
   129  		return 1
   130  	}
   131  	if err != nil {
   132  		c.Ui.Error(fmt.Sprintf("Failed to parse job-version flag: %v", err))
   133  		return 1
   134  	}
   135  
   136  	// Check if the job exists
   137  	jobs, _, err := client.Jobs().PrefixList(jobID)
   138  	if err != nil {
   139  		c.Ui.Error(fmt.Sprintf("Error listing jobs: %s", err))
   140  		return 1
   141  	}
   142  	if len(jobs) == 0 {
   143  		c.Ui.Error(fmt.Sprintf("No job(s) with prefix or id %q found", jobID))
   144  		return 1
   145  	}
   146  	if len(jobs) > 1 && strings.TrimSpace(jobID) != jobs[0].ID {
   147  		c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs)))
   148  		return 1
   149  	}
   150  
   151  	// Prefix lookup matched a single job
   152  	resp, _, err := client.Jobs().Revert(jobs[0].ID, revertVersion, nil, nil, consulToken, vaultToken)
   153  	if err != nil {
   154  		c.Ui.Error(fmt.Sprintf("Error retrieving job versions: %s", err))
   155  		return 1
   156  	}
   157  
   158  	// Nothing to do
   159  	evalCreated := resp.EvalID != ""
   160  	if detach || !evalCreated {
   161  		return 0
   162  	}
   163  
   164  	mon := newMonitor(c.Ui, client, length)
   165  	return mon.monitor(resp.EvalID, false)
   166  }