737 lines
18 KiB
Go
737 lines
18 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/influxdata/influxdb/v2/kit/platform"
|
|
|
|
"github.com/influxdata/influxdb/v2"
|
|
"github.com/influxdata/influxdb/v2/http"
|
|
"github.com/influxdata/influxdb/v2/tenant"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
type taskSVCsFn func() (influxdb.TaskService, influxdb.OrganizationService, error)
|
|
|
|
func newTaskSVCs() (influxdb.TaskService, influxdb.OrganizationService, error) {
|
|
httpClient, err := newHTTPClient()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return &http.TaskService{Client: httpClient}, &tenant.OrgClientService{Client: httpClient}, nil
|
|
}
|
|
|
|
func cmdTask(f *globalFlags, opt genericCLIOpts) *cobra.Command {
|
|
builder := newCmdTaskBuilder(newTaskSVCs, f, opt)
|
|
return builder.cmd()
|
|
}
|
|
|
|
type cmdTaskBuilder struct {
|
|
opts genericCLIOpts
|
|
globalFlags *globalFlags
|
|
|
|
svcFn taskSVCsFn
|
|
|
|
taskID string
|
|
runID string
|
|
taskPrintFlags taskPrintFlags
|
|
// todo: fields of these flags structs could be pulled out for a more streamlined builder struct
|
|
taskCreateFlags taskCreateFlags
|
|
taskFindFlags taskFindFlags
|
|
taskRerunFailedFlags taskRerunFailedFlags
|
|
taskUpdateFlags taskUpdateFlags
|
|
taskRunFindFlags taskRunFindFlags
|
|
org organization
|
|
}
|
|
|
|
func newCmdTaskBuilder(svcsFn taskSVCsFn, f *globalFlags, opts genericCLIOpts) *cmdTaskBuilder {
|
|
return &cmdTaskBuilder{
|
|
globalFlags: f,
|
|
opts: opts,
|
|
svcFn: svcsFn,
|
|
}
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) cmd() *cobra.Command {
|
|
cmd := b.newCmd("task", nil)
|
|
cmd.Short = "Task management commands"
|
|
cmd.TraverseChildren = true
|
|
cmd.Run = seeHelp
|
|
cmd.AddCommand(
|
|
b.taskLogCmd(),
|
|
b.taskRunCmd(),
|
|
b.taskCreateCmd(),
|
|
b.taskDeleteCmd(),
|
|
b.taskFindCmd(),
|
|
b.taskUpdateCmd(),
|
|
b.taskRetryFailedCmd(),
|
|
)
|
|
|
|
return cmd
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) newCmd(use string, runE func(*cobra.Command, []string) error) *cobra.Command {
|
|
cmd := b.opts.newCmd(use, runE, true)
|
|
b.globalFlags.registerFlags(b.opts.viper, cmd)
|
|
return cmd
|
|
}
|
|
|
|
type taskPrintFlags struct {
|
|
json bool
|
|
hideHeaders bool
|
|
}
|
|
|
|
type taskCreateFlags struct {
|
|
file string
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskCreateCmd() *cobra.Command {
|
|
cmd := b.newCmd("create [script literal or -f /path/to/script.flux]", b.taskCreateF)
|
|
cmd.Args = cobra.MaximumNArgs(1)
|
|
cmd.Short = "Create task"
|
|
cmd.Long = `Create a task with a Flux script provided via the first argument or a file or stdin`
|
|
|
|
cmd.Flags().StringVarP(&b.taskCreateFlags.file, "file", "f", "", "Path to Flux script file")
|
|
b.org.register(b.opts.viper, cmd, false)
|
|
registerPrintOptions(b.opts.viper, cmd, &b.taskPrintFlags.hideHeaders, &b.taskPrintFlags.json)
|
|
|
|
return cmd
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskCreateF(_ *cobra.Command, args []string) error {
|
|
if err := b.org.validOrgFlags(&flags); err != nil {
|
|
return err
|
|
}
|
|
|
|
tskSvc, orgSvc, err := b.svcFn()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
flux, err := readFluxQuery(args, b.taskCreateFlags.file)
|
|
if err != nil {
|
|
return fmt.Errorf("error parsing flux script: %s", err)
|
|
}
|
|
|
|
tc := influxdb.TaskCreate{
|
|
Flux: flux,
|
|
Organization: b.org.name,
|
|
}
|
|
if b.org.id != "" || b.org.name != "" {
|
|
oid, err := b.org.getID(orgSvc)
|
|
if err != nil {
|
|
return fmt.Errorf("error parsing organization ID: %s", err)
|
|
}
|
|
tc.OrganizationID = oid
|
|
}
|
|
|
|
tsk, err := tskSvc.CreateTask(context.Background(), tc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return b.printTasks(taskPrintOpts{task: tsk})
|
|
}
|
|
|
|
type taskFindFlags struct {
|
|
user string
|
|
limit int
|
|
headers bool
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskFindCmd() *cobra.Command {
|
|
cmd := b.opts.newCmd("list", b.taskFindF, true)
|
|
cmd.Short = "List tasks"
|
|
cmd.Aliases = []string{"find", "ls"}
|
|
|
|
b.org.register(b.opts.viper, cmd, false)
|
|
b.globalFlags.registerFlags(b.opts.viper, cmd)
|
|
registerPrintOptions(b.opts.viper, cmd, &b.taskPrintFlags.hideHeaders, &b.taskPrintFlags.json)
|
|
cmd.Flags().StringVarP(&b.taskID, "id", "i", "", "task ID")
|
|
cmd.Flags().StringVarP(&b.taskFindFlags.user, "user-id", "n", "", "task owner ID")
|
|
cmd.Flags().IntVarP(&b.taskFindFlags.limit, "limit", "", influxdb.TaskDefaultPageSize, "the number of tasks to find")
|
|
cmd.Flags().BoolVar(&b.taskFindFlags.headers, "headers", true, "To print the table headers; defaults true")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskFindF(cmd *cobra.Command, args []string) error {
|
|
|
|
if err := b.org.validOrgFlags(&flags); err != nil {
|
|
return err
|
|
}
|
|
|
|
tskSvc, _, err := b.svcFn()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
filter := influxdb.TaskFilter{}
|
|
if b.taskFindFlags.user != "" {
|
|
id, err := platform.IDFromString(b.taskFindFlags.user)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
filter.User = id
|
|
}
|
|
|
|
if b.org.name != "" {
|
|
filter.Organization = b.org.name
|
|
}
|
|
if b.org.id != "" {
|
|
id, err := platform.IDFromString(b.org.id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
filter.OrganizationID = id
|
|
}
|
|
|
|
if b.taskFindFlags.limit < 1 || b.taskFindFlags.limit > influxdb.TaskMaxPageSize {
|
|
return fmt.Errorf("limit must be between 1 and %d", influxdb.TaskMaxPageSize)
|
|
}
|
|
filter.Limit = b.taskFindFlags.limit
|
|
|
|
var tasks []*influxdb.Task
|
|
|
|
if b.taskID != "" {
|
|
id, err := platform.IDFromString(b.taskID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
task, err := tskSvc.FindTaskByID(context.Background(), *id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
tasks = append(tasks, task)
|
|
} else {
|
|
tasks, _, err = tskSvc.FindTasks(context.Background(), filter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return b.printTasks(taskPrintOpts{tasks: tasks})
|
|
}
|
|
|
|
type taskRerunFailedFlags struct {
|
|
before string
|
|
after string
|
|
dryRun bool
|
|
taskLimit int
|
|
runLimit int
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskRetryFailedCmd() *cobra.Command {
|
|
cmd := b.opts.newCmd("retry-failed", b.taskRetryFailedF, true)
|
|
cmd.Short = "Retry failed runs"
|
|
cmd.Aliases = []string{"rtf"}
|
|
|
|
b.org.register(b.opts.viper, cmd, false)
|
|
b.globalFlags.registerFlags(b.opts.viper, cmd)
|
|
registerPrintOptions(b.opts.viper, cmd, &b.taskPrintFlags.hideHeaders, &b.taskPrintFlags.json)
|
|
cmd.Flags().StringVarP(&b.taskID, "id", "i", "", "task ID")
|
|
cmd.Flags().StringVar(&b.taskRerunFailedFlags.before, "before", "", "runs before this time")
|
|
cmd.Flags().StringVar(&b.taskRerunFailedFlags.after, "after", "", "runs after this time")
|
|
cmd.Flags().BoolVar(&b.taskRerunFailedFlags.dryRun, "dry-run", false,
|
|
"print info about runs that would be retried")
|
|
cmd.Flags().IntVar(&b.taskRerunFailedFlags.taskLimit, "task-limit", 100, "max number of tasks to retry failed runs for")
|
|
cmd.Flags().IntVar(&b.taskRerunFailedFlags.runLimit, "run-limit", 100, "max number of failed runs to retry per task")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskRetryFailedF(*cobra.Command, []string) error {
|
|
if err := b.org.validOrgFlags(&flags); err != nil {
|
|
return err
|
|
}
|
|
|
|
if b.taskRerunFailedFlags.taskLimit < 1 || b.taskRerunFailedFlags.taskLimit > 500 {
|
|
return fmt.Errorf("task-limit must be between 1 and 500 (inclusive)")
|
|
}
|
|
if b.taskRerunFailedFlags.runLimit < 1 || b.taskRerunFailedFlags.runLimit > 500 {
|
|
return fmt.Errorf("run-limit must be between 1 and 500 (inclusive)")
|
|
}
|
|
|
|
tskSvc, _, err := b.svcFn()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var failedRuns []*influxdb.Run
|
|
if b.taskID == "" {
|
|
failedRuns, err = b.getFailedRunsForOrg(b.taskRerunFailedFlags.taskLimit, b.taskRerunFailedFlags.runLimit)
|
|
} else {
|
|
failedRuns, err = b.getFailedRunsForTaskID(b.taskRerunFailedFlags.runLimit)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, run := range failedRuns {
|
|
if b.taskRerunFailedFlags.dryRun {
|
|
fmt.Printf("Would retry for %s run for Task %s.\n", run.ID, run.TaskID)
|
|
} else {
|
|
newRun, err := tskSvc.RetryRun(context.Background(), run.TaskID, run.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("Retry for task %s's run %s queued as run %s.\n", run.TaskID, run.ID, newRun.ID)
|
|
}
|
|
}
|
|
if b.taskRerunFailedFlags.dryRun {
|
|
uniqueIDs := make(map[platform.ID]struct{})
|
|
for _, r := range failedRuns {
|
|
uniqueIDs[r.TaskID] = struct{}{}
|
|
}
|
|
fmt.Printf("Dry run complete. Found %d tasks with a total of %d runs to be retried\n"+
|
|
"Rerun without '--dry-run' to execute", len(uniqueIDs), len(failedRuns))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) getFailedRunsForTaskID(limit int) ([]*influxdb.Run, error) {
|
|
// use RunFilter to search for failed runs
|
|
tskSvc, _, err := b.svcFn()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
runFilter := influxdb.RunFilter{Limit: limit}
|
|
id, err := platform.IDFromString(b.taskID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
runFilter.Task = *id
|
|
runFilter.BeforeTime = b.taskRerunFailedFlags.before
|
|
runFilter.AfterTime = b.taskRerunFailedFlags.after
|
|
allRuns, _, err := tskSvc.FindRuns(context.Background(), runFilter)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var allFailedRuns []*influxdb.Run
|
|
for _, run := range allRuns {
|
|
if run.Status == "failed" {
|
|
allFailedRuns = append(allFailedRuns, run)
|
|
}
|
|
}
|
|
return allFailedRuns, nil
|
|
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) getFailedRunsForOrg(taskLimit int, runLimit int) ([]*influxdb.Run, error) {
|
|
// use TaskFilter to get all Tasks in org then search for failed runs in each task
|
|
taskFilter := influxdb.TaskFilter{Limit: taskLimit}
|
|
runFilter := influxdb.RunFilter{Limit: runLimit}
|
|
runFilter.BeforeTime = b.taskRerunFailedFlags.before
|
|
runFilter.AfterTime = b.taskRerunFailedFlags.after
|
|
tskSvc, _, err := b.svcFn()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if b.org.name != "" {
|
|
taskFilter.Organization = b.org.name
|
|
}
|
|
if b.org.id != "" {
|
|
orgID, err := platform.IDFromString(b.org.id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
taskFilter.OrganizationID = orgID
|
|
}
|
|
|
|
allTasks, _, err := tskSvc.FindTasks(context.Background(), taskFilter)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var allFailedRuns []*influxdb.Run
|
|
for _, t := range allTasks {
|
|
runFilter.Task = t.ID
|
|
runsPerTask, _, err := tskSvc.FindRuns(context.Background(), runFilter)
|
|
var failedRunsPerTask []*influxdb.Run
|
|
for _, r := range runsPerTask {
|
|
if r.Status == "failed" {
|
|
failedRunsPerTask = append(failedRunsPerTask, r)
|
|
}
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
allFailedRuns = append(allFailedRuns, failedRunsPerTask...)
|
|
}
|
|
return allFailedRuns, nil
|
|
}
|
|
|
|
type taskUpdateFlags struct {
|
|
status string
|
|
file string
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskUpdateCmd() *cobra.Command {
|
|
cmd := b.opts.newCmd("update", b.taskUpdateF, true)
|
|
cmd.Short = "Update task"
|
|
cmd.Long = `Update task status or script. Provide a Flux script via the first argument or a file. Use '-' argument to read from stdin.`
|
|
|
|
b.globalFlags.registerFlags(b.opts.viper, cmd)
|
|
registerPrintOptions(b.opts.viper, cmd, &b.taskPrintFlags.hideHeaders, &b.taskPrintFlags.json)
|
|
cmd.Flags().StringVarP(&b.taskID, "id", "i", "", "task ID (required)")
|
|
cmd.Flags().StringVarP(&b.taskUpdateFlags.status, "status", "", "", "update task status")
|
|
cmd.Flags().StringVarP(&b.taskUpdateFlags.file, "file", "f", "", "Path to Flux script file")
|
|
cmd.MarkFlagRequired("id")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskUpdateF(cmd *cobra.Command, args []string) error {
|
|
tskSvc, _, err := b.svcFn()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var id platform.ID
|
|
if err := id.DecodeFromString(b.taskID); err != nil {
|
|
return err
|
|
}
|
|
|
|
var update influxdb.TaskUpdate
|
|
if b.taskUpdateFlags.status != "" {
|
|
update.Status = &b.taskUpdateFlags.status
|
|
}
|
|
|
|
// update flux script only if first arg or file is supplied
|
|
if (len(args) > 0 && len(args[0]) > 0) || len(b.taskUpdateFlags.file) > 0 {
|
|
flux, err := readFluxQuery(args, b.taskUpdateFlags.file)
|
|
if err != nil {
|
|
return fmt.Errorf("error parsing flux script: %s", err)
|
|
}
|
|
update.Flux = &flux
|
|
}
|
|
|
|
tsk, err := tskSvc.UpdateTask(context.Background(), id, update)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return b.printTasks(taskPrintOpts{task: tsk})
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskDeleteCmd() *cobra.Command {
|
|
cmd := b.opts.newCmd("delete", b.taskDeleteF, true)
|
|
cmd.Short = "Delete task"
|
|
|
|
b.globalFlags.registerFlags(b.opts.viper, cmd)
|
|
registerPrintOptions(b.opts.viper, cmd, &b.taskPrintFlags.hideHeaders, &b.taskPrintFlags.json)
|
|
cmd.Flags().StringVarP(&b.taskID, "id", "i", "", "task id (required)")
|
|
cmd.MarkFlagRequired("id")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskDeleteF(cmd *cobra.Command, args []string) error {
|
|
tskSvc, _, err := b.svcFn()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var id platform.ID
|
|
err = id.DecodeFromString(b.taskID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ctx := context.TODO()
|
|
tsk, err := tskSvc.FindTaskByID(ctx, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err = tskSvc.DeleteTask(ctx, id); err != nil {
|
|
return err
|
|
}
|
|
|
|
return b.printTasks(taskPrintOpts{task: tsk})
|
|
|
|
}
|
|
|
|
type taskPrintOpts struct {
|
|
task *influxdb.Task
|
|
tasks []*influxdb.Task
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) printTasks(printOpts taskPrintOpts) error {
|
|
if b.taskPrintFlags.json {
|
|
var v interface{} = printOpts.tasks
|
|
if printOpts.task != nil {
|
|
v = printOpts.task
|
|
}
|
|
return b.opts.writeJSON(v)
|
|
}
|
|
tabW := b.opts.newTabWriter()
|
|
defer tabW.Flush()
|
|
|
|
tabW.HideHeaders(b.taskPrintFlags.hideHeaders)
|
|
|
|
tabW.WriteHeaders(
|
|
"ID",
|
|
"Name",
|
|
"Organization ID",
|
|
"Organization",
|
|
"Status",
|
|
"Every",
|
|
"Cron",
|
|
)
|
|
|
|
if printOpts.task != nil {
|
|
printOpts.tasks = append(printOpts.tasks, printOpts.task)
|
|
}
|
|
|
|
for _, t := range printOpts.tasks {
|
|
tabW.Write(map[string]interface{}{
|
|
"ID": t.ID.String(),
|
|
"Name": t.Name,
|
|
"Organization ID": t.OrganizationID.String(),
|
|
"Organization": t.Organization,
|
|
"Status": t.Status,
|
|
"Every": t.Every,
|
|
"Cron": t.Cron,
|
|
})
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskLogCmd() *cobra.Command {
|
|
cmd := b.opts.newCmd("log", nil, false)
|
|
cmd.Run = seeHelp
|
|
cmd.Short = "Log related commands"
|
|
cmd.AddCommand(
|
|
b.taskLogFindCmd(),
|
|
)
|
|
|
|
return cmd
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskLogFindCmd() *cobra.Command {
|
|
cmd := b.opts.newCmd("list", b.taskLogFindF, true)
|
|
cmd.Short = "List logs for task"
|
|
cmd.Aliases = []string{"find", "ls"}
|
|
|
|
b.globalFlags.registerFlags(b.opts.viper, cmd)
|
|
registerPrintOptions(b.opts.viper, cmd, &b.taskPrintFlags.hideHeaders, &b.taskPrintFlags.json)
|
|
cmd.Flags().StringVarP(&b.taskID, "task-id", "", "", "task id (required)")
|
|
cmd.Flags().StringVarP(&b.runID, "run-id", "", "", "run id")
|
|
cmd.MarkFlagRequired("task-id")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskLogFindF(cmd *cobra.Command, args []string) error {
|
|
tskSvc, _, err := b.svcFn()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var filter influxdb.LogFilter
|
|
id, err := platform.IDFromString(b.taskID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
filter.Task = *id
|
|
|
|
if b.runID != "" {
|
|
id, err := platform.IDFromString(b.runID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
filter.Run = id
|
|
}
|
|
|
|
ctx := context.TODO()
|
|
logs, _, err := tskSvc.FindLogs(ctx, filter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if b.taskPrintFlags.json {
|
|
return b.opts.writeJSON(logs)
|
|
}
|
|
|
|
tabW := b.opts.newTabWriter()
|
|
defer tabW.Flush()
|
|
|
|
tabW.HideHeaders(b.taskPrintFlags.hideHeaders)
|
|
|
|
tabW.WriteHeaders("RunID", "Time", "Message")
|
|
for _, log := range logs {
|
|
tabW.Write(map[string]interface{}{
|
|
"RunID": log.RunID,
|
|
"Time": log.Time,
|
|
"Message": log.Message,
|
|
})
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskRunCmd() *cobra.Command {
|
|
cmd := b.opts.newCmd("run", nil, false)
|
|
cmd.Run = seeHelp
|
|
cmd.Short = "List runs for a task"
|
|
cmd.AddCommand(
|
|
b.taskRunFindCmd(),
|
|
b.taskRunRetryCmd(),
|
|
)
|
|
|
|
return cmd
|
|
}
|
|
|
|
type taskRunFindFlags struct {
|
|
afterTime string
|
|
beforeTime string
|
|
limit int
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskRunFindCmd() *cobra.Command {
|
|
cmd := b.opts.newCmd("list", b.taskRunFindF, true)
|
|
cmd.Short = "List runs for a task"
|
|
cmd.Aliases = []string{"find", "ls"}
|
|
|
|
b.globalFlags.registerFlags(b.opts.viper, cmd)
|
|
registerPrintOptions(b.opts.viper, cmd, &b.taskPrintFlags.hideHeaders, &b.taskPrintFlags.json)
|
|
cmd.Flags().StringVarP(&b.taskID, "task-id", "", "", "task id (required)")
|
|
cmd.Flags().StringVarP(&b.runID, "run-id", "", "", "run id")
|
|
cmd.Flags().StringVarP(&b.taskRunFindFlags.afterTime, "after", "", "", "after time for filtering")
|
|
cmd.Flags().StringVarP(&b.taskRunFindFlags.beforeTime, "before", "", "", "before time for filtering")
|
|
cmd.Flags().IntVarP(&b.taskRunFindFlags.limit, "limit", "", 100, "limit the results; default is 100")
|
|
|
|
cmd.MarkFlagRequired("task-id")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskRunFindF(cmd *cobra.Command, args []string) error {
|
|
tskSvc, _, err := b.svcFn()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
filter := influxdb.RunFilter{
|
|
Limit: b.taskRunFindFlags.limit,
|
|
AfterTime: b.taskRunFindFlags.afterTime,
|
|
BeforeTime: b.taskRunFindFlags.beforeTime,
|
|
}
|
|
taskID, err := platform.IDFromString(b.taskID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
filter.Task = *taskID
|
|
|
|
var runs []*influxdb.Run
|
|
if b.runID != "" {
|
|
id, err := platform.IDFromString(b.runID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
run, err := tskSvc.FindRunByID(context.Background(), filter.Task, *id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
runs = append(runs, run)
|
|
} else {
|
|
runs, _, err = tskSvc.FindRuns(context.Background(), filter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if b.taskPrintFlags.json {
|
|
if runs == nil {
|
|
// guarantee we never return a null value from CLI
|
|
runs = make([]*influxdb.Run, 0)
|
|
}
|
|
return b.opts.writeJSON(runs)
|
|
}
|
|
|
|
tabW := b.opts.newTabWriter()
|
|
defer tabW.Flush()
|
|
|
|
tabW.HideHeaders(b.taskPrintFlags.hideHeaders)
|
|
|
|
tabW.WriteHeaders(
|
|
"ID",
|
|
"TaskID",
|
|
"Status",
|
|
"ScheduledFor",
|
|
"StartedAt",
|
|
"FinishedAt",
|
|
"RequestedAt",
|
|
)
|
|
|
|
for _, r := range runs {
|
|
scheduledFor := r.ScheduledFor.Format(time.RFC3339)
|
|
startedAt := r.StartedAt.Format(time.RFC3339Nano)
|
|
finishedAt := r.FinishedAt.Format(time.RFC3339Nano)
|
|
requestedAt := r.RequestedAt.Format(time.RFC3339Nano)
|
|
|
|
tabW.Write(map[string]interface{}{
|
|
"ID": r.ID,
|
|
"TaskID": r.TaskID,
|
|
"Status": r.Status,
|
|
"ScheduledFor": scheduledFor,
|
|
"StartedAt": startedAt,
|
|
"FinishedAt": finishedAt,
|
|
"RequestedAt": requestedAt,
|
|
})
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
var runRetryFlags struct {
|
|
taskID, runID string
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) taskRunRetryCmd() *cobra.Command {
|
|
cmd := b.opts.newCmd("retry", b.runRetryF, true)
|
|
cmd.Short = "retry a run"
|
|
|
|
b.globalFlags.registerFlags(b.opts.viper, cmd)
|
|
cmd.Flags().StringVarP(&runRetryFlags.taskID, "task-id", "i", "", "task id (required)")
|
|
cmd.Flags().StringVarP(&runRetryFlags.runID, "run-id", "r", "", "run id (required)")
|
|
cmd.MarkFlagRequired("task-id")
|
|
cmd.MarkFlagRequired("run-id")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func (b *cmdTaskBuilder) runRetryF(*cobra.Command, []string) error {
|
|
tskSvc, _, err := b.svcFn()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var taskID, runID platform.ID
|
|
if err := taskID.DecodeFromString(runRetryFlags.taskID); err != nil {
|
|
return err
|
|
}
|
|
if err := runID.DecodeFromString(runRetryFlags.runID); err != nil {
|
|
return err
|
|
}
|
|
|
|
ctx := context.TODO()
|
|
newRun, err := tskSvc.RetryRun(ctx, taskID, runID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Retry for task %s's run %s queued as run %s.\n", taskID, runID, newRun.ID)
|
|
|
|
return nil
|
|
}
|