github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/command/job_periodic_force.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/hashicorp/nomad/api" 8 "github.com/posener/complete" 9 ) 10 11 type JobPeriodicForceCommand struct { 12 Meta 13 } 14 15 func (c *JobPeriodicForceCommand) Help() string { 16 helpText := ` 17 Usage: nomad job periodic force <job id> 18 19 This command is used to force the creation of a new instance of a periodic job. 20 This is used to immediately run a periodic job, even if it violates the job's 21 prohibit_overlap setting. 22 23 When ACLs are enabled, this command requires a token with the 'submit-job' 24 and 'list-jobs' capabilities for the job's namespace. 25 26 General Options: 27 28 ` + generalOptionsUsage(usageOptsDefault) + ` 29 30 Periodic Force Options: 31 32 -detach 33 Return immediately instead of entering monitor mode. After the force, 34 the evaluation ID will be printed to the screen, which can be used to 35 examine the evaluation using the eval-status command. 36 37 -verbose 38 Display full information. 39 ` 40 41 return strings.TrimSpace(helpText) 42 } 43 44 func (c *JobPeriodicForceCommand) Synopsis() string { 45 return "Force the launch of a periodic job" 46 } 47 48 func (c *JobPeriodicForceCommand) 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 *JobPeriodicForceCommand) 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.Jobs().PrefixList(a.Last) 64 if err != nil { 65 return []string{} 66 } 67 68 // filter this by periodic jobs 69 matches := make([]string, 0, len(resp)) 70 for _, job := range resp { 71 if job.Periodic { 72 matches = append(matches, job.ID) 73 } 74 } 75 return matches 76 }) 77 } 78 79 func (c *JobPeriodicForceCommand) Name() string { return "job periodic force" } 80 81 func (c *JobPeriodicForceCommand) Run(args []string) int { 82 var detach, verbose bool 83 84 flags := c.Meta.FlagSet(c.Name(), FlagSetClient) 85 flags.Usage = func() { c.Ui.Output(c.Help()) } 86 flags.BoolVar(&detach, "detach", false, "") 87 flags.BoolVar(&verbose, "verbose", false, "") 88 89 if err := flags.Parse(args); err != nil { 90 return 1 91 } 92 93 // Check that we got exactly one argument 94 args = flags.Args() 95 if l := len(args); l != 1 { 96 c.Ui.Error("This command takes one argument: <job id>") 97 c.Ui.Error(commandErrorText(c)) 98 return 1 99 } 100 101 // Truncate the id unless full length is requested 102 length := shortId 103 if verbose { 104 length = fullId 105 } 106 107 // Get the HTTP client 108 client, err := c.Meta.Client() 109 if err != nil { 110 c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) 111 return 1 112 } 113 114 // Check if the job exists 115 jobID := args[0] 116 jobs, _, err := client.Jobs().PrefixList(jobID) 117 if err != nil { 118 c.Ui.Error(fmt.Sprintf("Error forcing periodic job: %s", err)) 119 return 1 120 } 121 // filter non-periodic jobs 122 periodicJobs := make([]*api.JobListStub, 0, len(jobs)) 123 for _, j := range jobs { 124 if j.Periodic { 125 periodicJobs = append(periodicJobs, j) 126 } 127 } 128 if len(periodicJobs) == 0 { 129 c.Ui.Error(fmt.Sprintf("No periodic job(s) with prefix or id %q found", jobID)) 130 return 1 131 } 132 // preriodicJobs is sorted by job ID 133 // so if there is a job whose ID is equal to jobID then it must be the first item 134 if len(periodicJobs) > 1 && periodicJobs[0].ID != jobID { 135 c.Ui.Error(fmt.Sprintf("Prefix matched multiple periodic jobs\n\n%s", createStatusListOutput(periodicJobs, c.allNamespaces()))) 136 return 1 137 } 138 jobID = periodicJobs[0].ID 139 q := &api.WriteOptions{Namespace: periodicJobs[0].JobSummary.Namespace} 140 141 // force the evaluation 142 evalID, _, err := client.Jobs().PeriodicForce(jobID, q) 143 if err != nil { 144 c.Ui.Error(fmt.Sprintf("Error forcing periodic job %q: %s", jobID, err)) 145 return 1 146 } 147 148 if detach { 149 c.Ui.Output("Force periodic successful") 150 c.Ui.Output("Evaluation ID: " + evalID) 151 return 0 152 } 153 154 // Detach was not specified, so start monitoring 155 mon := newMonitor(c.Ui, client, length) 156 return mon.monitor(evalID) 157 }