diff --git a/cmd/harbor/root/cmd.go b/cmd/harbor/root/cmd.go index 33509cbf8..48690b675 100644 --- a/cmd/harbor/root/cmd.go +++ b/cmd/harbor/root/cmd.go @@ -23,6 +23,7 @@ import ( "github.com/goharbor/harbor-cli/cmd/harbor/root/context" "github.com/goharbor/harbor-cli/cmd/harbor/root/cve" "github.com/goharbor/harbor-cli/cmd/harbor/root/instance" + "github.com/goharbor/harbor-cli/cmd/harbor/root/jobservice" "github.com/goharbor/harbor-cli/cmd/harbor/root/labels" "github.com/goharbor/harbor-cli/cmd/harbor/root/ldap" "github.com/goharbor/harbor-cli/cmd/harbor/root/project" @@ -203,6 +204,10 @@ harbor help cmd.GroupID = "system" root.AddCommand(cmd) + cmd = jobservice.JobService() + cmd.GroupID = "system" + root.AddCommand(cmd) + // Utils cmd = versionCommand() cmd.GroupID = "utils" diff --git a/cmd/harbor/root/jobservice/cmd.go b/cmd/harbor/root/jobservice/cmd.go new file mode 100644 index 000000000..d626fd736 --- /dev/null +++ b/cmd/harbor/root/jobservice/cmd.go @@ -0,0 +1,45 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package jobservice + +import ( + "github.com/goharbor/harbor-cli/cmd/harbor/root/jobservice/jobs" + "github.com/goharbor/harbor-cli/cmd/harbor/root/jobservice/pools" + "github.com/goharbor/harbor-cli/cmd/harbor/root/jobservice/queues" + "github.com/goharbor/harbor-cli/cmd/harbor/root/jobservice/schedules" + "github.com/goharbor/harbor-cli/cmd/harbor/root/jobservice/workers" + "github.com/spf13/cobra" +) + +// JobService creates the jobservice command +func JobService() *cobra.Command { + cmd := &cobra.Command{ + Use: "jobservice", + Short: "Manage Harbor job service (admin only)", + Long: `Manage Harbor job service components including worker pools, job queues, schedules, and job logs. +This requires system admin privileges. + +Use "harbor jobservice [command] --help" for detailed examples and flags per subcommand.`, + } + + cmd.AddCommand( + pools.PoolsCommand(), + workers.WorkersCommand(), + queues.QueuesCommand(), + schedules.SchedulesCommand(), + jobs.JobsCommand(), + ) + + return cmd +} diff --git a/cmd/harbor/root/jobservice/jobs/log.go b/cmd/harbor/root/jobservice/jobs/log.go new file mode 100644 index 000000000..eeb0ae3b9 --- /dev/null +++ b/cmd/harbor/root/jobservice/jobs/log.go @@ -0,0 +1,74 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package jobs + +import ( + "fmt" + + "github.com/goharbor/harbor-cli/pkg/api" + "github.com/spf13/cobra" +) + +// JobsCommand creates the jobs subcommand +func JobsCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "jobs", + Short: "Manage job logs (view by job ID)", + Long: "View logs for specific jobs.", + } + + cmd.AddCommand(LogCommand()) + + return cmd +} + +// LogCommand retrieves and displays job logs +func LogCommand() *cobra.Command { + var jobID string + + cmd := &cobra.Command{ + Use: "log", + Short: "View a job log (--job-id required)", + Long: "Display the log for a specific job by job ID.", + Example: "harbor jobservice jobs log --job-id abc123def456", + RunE: func(cmd *cobra.Command, args []string) error { + if jobID == "" { + return fmt.Errorf("--job-id must be specified") + } + + fmt.Printf("Retrieving log for job %s...\n\n", jobID) + + log, err := api.GetJobLog(jobID) + if err != nil { + return fmt.Errorf("failed to retrieve job log: %w", err) + } + + if log == "" { + fmt.Println("No log content available for this job.") + return nil + } + + fmt.Println("=== Job Log ===") + fmt.Println(log) + fmt.Println("=== End of Log ===") + return nil + }, + } + + flags := cmd.Flags() + flags.StringVar(&jobID, "job-id", "", "Job ID to fetch log for (required)") + cmd.MarkFlagRequired("job-id") + + return cmd +} diff --git a/cmd/harbor/root/jobservice/pools/list.go b/cmd/harbor/root/jobservice/pools/list.go new file mode 100644 index 000000000..9f04be4f8 --- /dev/null +++ b/cmd/harbor/root/jobservice/pools/list.go @@ -0,0 +1,74 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package pools + +import ( + "fmt" + + "github.com/goharbor/harbor-cli/pkg/api" + "github.com/goharbor/harbor-cli/pkg/utils" + poolviews "github.com/goharbor/harbor-cli/pkg/views/jobservice/pools" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// PoolsCommand creates the pools subcommand. +func PoolsCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "pools", + Aliases: []string{"pool"}, + Short: "Manage worker pools (list available pools)", + Long: `List and manage worker pools for the Harbor job service. + +Use 'list' to view all worker pools. + +Examples: + harbor jobservice pools list + harbor jobservice pool list`, + } + + cmd.AddCommand(ListCommand()) + return cmd +} + +// ListCommand lists all worker pools. +func ListCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Short: "List all worker pools", + Long: "Display all worker pools with their details.", + Example: "harbor jobservice pools list\nharbor jobservice pool list", + RunE: func(cmd *cobra.Command, args []string) error { + response, err := api.GetWorkerPools() + if err != nil { + return fmt.Errorf("failed to retrieve worker pools: %w", err) + } + + if response == nil || response.Payload == nil || len(response.Payload) == 0 { + fmt.Println("No worker pools found.") + return nil + } + + formatFlag := viper.GetString("output-format") + if formatFlag != "" { + return utils.PrintFormat(response.Payload, formatFlag) + } + + poolviews.ListPools(response.Payload) + return nil + }, + } + + return cmd +} diff --git a/cmd/harbor/root/jobservice/queues/list.go b/cmd/harbor/root/jobservice/queues/list.go new file mode 100644 index 000000000..d43235c77 --- /dev/null +++ b/cmd/harbor/root/jobservice/queues/list.go @@ -0,0 +1,334 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package queues + +import ( + "errors" + "fmt" + "strings" + + "github.com/charmbracelet/bubbles/key" + "github.com/charmbracelet/huh" + "github.com/goharbor/harbor-cli/pkg/api" + "github.com/goharbor/harbor-cli/pkg/utils" + "github.com/goharbor/harbor-cli/pkg/views/jobservice/queues" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// QueuesCommand creates the queues subcommand +func QueuesCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "queues", + Short: "Manage job queues (list, stop, pause, resume)", + Long: "List job queues and perform actions on them (stop/pause/resume).", + } + + cmd.AddCommand(ListCommand(), StopCommand(), PauseCommand(), ResumeCommand()) + + return cmd +} + +// ListCommand lists all job queues +func ListCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Short: "List all job queues", + Long: "Display all job queues with their pending job counts and latency.", + Example: "harbor jobservice queues list", + RunE: func(cmd *cobra.Command, args []string) error { + response, err := api.ListJobQueues() + if err != nil { + return fmt.Errorf("failed to retrieve job queues: %w", err) + } + + if response == nil || response.Payload == nil || len(response.Payload) == 0 { + fmt.Println("No job queues found.") + return nil + } + + formatFlag := viper.GetString("output-format") + if formatFlag != "" { + return utils.PrintFormat(response.Payload, formatFlag) + } + + queues.ListQueues(response.Payload) + return nil + }, + } + + return cmd +} + +// StopCommand stops a job queue +func StopCommand() *cobra.Command { + var jobTypes []string + var interactive bool + + cmd := &cobra.Command{ + Use: "stop", + Short: "Stop queue(s) (--type or --interactive)", + Long: "Stop a job queue or all queues.", + Example: "harbor jobservice queues stop --type REPLICATION\nharbor jobservice queues stop --type REPLICATION --type RETENTION\nharbor jobservice queues stop --type all", + RunE: func(cmd *cobra.Command, args []string) error { + if len(jobTypes) == 0 && !interactive { + interactive = true + } + + if interactive { + selectedTypes, err := selectQueueTypes("stop") + if err != nil { + return err + } + jobTypes = selectedTypes + } + + if len(jobTypes) == 0 { + return fmt.Errorf("at least one job type must be specified with --type or interactive mode") + } + + return executeQueueAction("stop", jobTypes) + }, + } + + flags := cmd.Flags() + flags.StringSliceVar(&jobTypes, "type", nil, "Job type(s) to stop (repeat flag or comma-separate values; use 'all' for all queues)") + flags.BoolVarP(&interactive, "interactive", "i", false, "Interactive mode to choose queue type(s) instead of passing --type") + + return cmd +} + +// PauseCommand pauses a job queue +func PauseCommand() *cobra.Command { + var jobTypes []string + var interactive bool + + cmd := &cobra.Command{ + Use: "pause", + Short: "Pause queue(s) (--type or --interactive)", + Long: "Pause a job queue or all queues.", + Example: "harbor jobservice queues pause --type REPLICATION\nharbor jobservice queues pause --type REPLICATION --type RETENTION\nharbor jobservice queues pause --type all", + RunE: func(cmd *cobra.Command, args []string) error { + if len(jobTypes) == 0 && !interactive { + interactive = true + } + + if interactive { + selectedTypes, err := selectQueueTypes("pause") + if err != nil { + return err + } + jobTypes = selectedTypes + } + + if len(jobTypes) == 0 { + return fmt.Errorf("at least one job type must be specified with --type or interactive mode") + } + + return executeQueueAction("pause", jobTypes) + }, + } + + flags := cmd.Flags() + flags.StringSliceVar(&jobTypes, "type", nil, "Job type(s) to pause (repeat flag or comma-separate values; use 'all' for all queues)") + flags.BoolVarP(&interactive, "interactive", "i", false, "Interactive mode to choose queue type(s) instead of passing --type") + + return cmd +} + +// ResumeCommand resumes a job queue +func ResumeCommand() *cobra.Command { + var jobTypes []string + var interactive bool + + cmd := &cobra.Command{ + Use: "resume", + Short: "Resume queue(s) (--type or --interactive)", + Long: "Resume a paused job queue or all queues.", + Example: "harbor jobservice queues resume --type REPLICATION\nharbor jobservice queues resume --type REPLICATION --type RETENTION\nharbor jobservice queues resume --type all", + RunE: func(cmd *cobra.Command, args []string) error { + if len(jobTypes) == 0 && !interactive { + interactive = true + } + + if interactive { + selectedTypes, err := selectQueueTypes("resume") + if err != nil { + return err + } + jobTypes = selectedTypes + } + + if len(jobTypes) == 0 { + return fmt.Errorf("at least one job type must be specified with --type or interactive mode") + } + + return executeQueueAction("resume", jobTypes) + }, + } + + flags := cmd.Flags() + flags.StringSliceVar(&jobTypes, "type", nil, "Job type(s) to resume (repeat flag or comma-separate values; use 'all' for all queues)") + flags.BoolVarP(&interactive, "interactive", "i", false, "Interactive mode to choose queue type(s) instead of passing --type") + + return cmd +} + +// selectQueueTypes shows an interactive multi-selector for queue types +func selectQueueTypes(action string) ([]string, error) { + response, err := api.ListJobQueues() + if err != nil { + return nil, fmt.Errorf("failed to retrieve job queues: %w", err) + } + + if response == nil || response.Payload == nil || len(response.Payload) == 0 { + return nil, fmt.Errorf("no job queues available") + } + + filteredQueues := make([]*struct { + JobType string + Count int64 + }, 0, len(response.Payload)) + + for _, queue := range response.Payload { + if queue == nil { + continue + } + if shouldIncludeQueueForAction(action, queue.Paused) { + filteredQueues = append(filteredQueues, &struct { + JobType string + Count int64 + }{ + JobType: queue.JobType, + Count: queue.Count, + }) + } + } + + if len(filteredQueues) == 0 { + switch action { + case "resume": + return nil, fmt.Errorf("no paused queues available to resume") + case "pause": + return nil, fmt.Errorf("all queues are already paused") + default: + return nil, fmt.Errorf("no job queues available to %s", action) + } + } + + options := make([]huh.Option[string], len(filteredQueues)+1) + options[0] = huh.NewOption("all", "all") + + for i, queue := range filteredQueues { + label := fmt.Sprintf("%s (pending: %d)", queue.JobType, queue.Count) + options[i+1] = huh.NewOption(label, queue.JobType) + } + + var selected []string + theme := huh.ThemeCharm() + keymap := huh.NewDefaultKeyMap() + keymap.Quit = key.NewBinding( + key.WithKeys("ctrl+c", "q"), + key.WithHelp("q", "quit"), + ) + + err = huh.NewForm( + huh.NewGroup( + huh.NewMultiSelect[string](). + Title(fmt.Sprintf("Select queue type(s) to %s (press q to cancel)", action)). + Options(options...). + Value(&selected), + ), + ).WithTheme(theme).WithKeyMap(keymap).Run() + + if err != nil { + if errors.Is(err, huh.ErrUserAborted) { + return nil, errors.New("operation cancelled") + } + return nil, err + } + + selected = normalizeJobTypes(selected) + if len(selected) == 0 { + return nil, fmt.Errorf("at least one queue type must be selected") + } + + return selected, nil +} + +func shouldIncludeQueueForAction(action string, paused bool) bool { + switch strings.ToLower(action) { + case "resume": + return paused + case "pause": + return !paused + default: + return true + } +} + +func executeQueueAction(action string, jobTypes []string) error { + normalizedTypes := normalizeJobTypes(jobTypes) + if len(normalizedTypes) == 0 { + return fmt.Errorf("at least one job type must be provided") + } + + for _, jobType := range normalizedTypes { + fmt.Printf("%s queue type '%s'...\n", actionLabel(action), jobType) + err := api.ActionJobQueue(strings.ToUpper(jobType), action) + if err != nil { + return fmt.Errorf("failed to %s queue '%s': %w", action, jobType, err) + } + fmt.Printf("✓ Queue '%s' %sd successfully.\n", jobType, action) + } + + return nil +} + +func normalizeJobTypes(jobTypes []string) []string { + cleanedTypes := make([]string, 0, len(jobTypes)) + seen := make(map[string]struct{}, len(jobTypes)) + + for _, rawType := range jobTypes { + for _, splitType := range strings.Split(rawType, ",") { + trimmedType := strings.TrimSpace(splitType) + if trimmedType == "" { + continue + } + + if strings.EqualFold(trimmedType, "all") { + return []string{"all"} + } + + key := strings.ToLower(trimmedType) + if _, exists := seen[key]; exists { + continue + } + + seen[key] = struct{}{} + cleanedTypes = append(cleanedTypes, trimmedType) + } + } + + return cleanedTypes +} + +func actionLabel(action string) string { + if action == "" { + return "Updating" + } + + lower := strings.ToLower(action) + return strings.ToUpper(lower[:1]) + lower[1:] +} diff --git a/cmd/harbor/root/jobservice/schedules/list.go b/cmd/harbor/root/jobservice/schedules/list.go new file mode 100644 index 000000000..88b4f931d --- /dev/null +++ b/cmd/harbor/root/jobservice/schedules/list.go @@ -0,0 +1,189 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package schedules + +import ( + "fmt" + + "github.com/goharbor/harbor-cli/pkg/api" + "github.com/goharbor/harbor-cli/pkg/utils" + "github.com/goharbor/harbor-cli/pkg/views/jobservice/schedules" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// SchedulesCommand creates the schedules subcommand +func SchedulesCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "schedules", + Short: "Manage schedules (list/status/pause-all/resume-all)", + Long: "List schedules and manage global scheduler status.", + } + + cmd.AddCommand( + ListCommand(), + StatusCommand(), + PauseAllCommand(), + ResumeAllCommand(), + ) + + return cmd +} + +// ListCommand lists all schedules +func ListCommand() *cobra.Command { + var page int64 = 1 + var pageSize int64 = 20 + + cmd := &cobra.Command{ + Use: "list", + Short: "List schedules (supports --page and --page-size)", + Long: "Display all job schedules with pagination support.", + Example: "harbor jobservice schedules list --page 1 --page-size 20", + RunE: func(cmd *cobra.Command, args []string) error { + if page < 1 { + return fmt.Errorf("page must be >= 1") + } + if pageSize < 1 || pageSize > 100 { + return fmt.Errorf("page-size must be between 1 and 100") + } + + response, err := api.ListSchedules(page, pageSize) + if err != nil { + return formatScheduleError("failed to retrieve schedules", err, "ActionList") + } + + if response == nil || response.Payload == nil || len(response.Payload) == 0 { + fmt.Println("No schedules found.") + return nil + } + + formatFlag := viper.GetString("output-format") + if formatFlag != "" { + return utils.PrintFormat(response.Payload, formatFlag) + } + + totalCount := response.XTotalCount + schedules.ListSchedules(response.Payload, page, pageSize, totalCount) + return nil + }, + } + + flags := cmd.Flags() + flags.Int64Var(&page, "page", 1, "Page number") + flags.Int64Var(&pageSize, "page-size", 20, "Number of items per page") + + return cmd +} + +// StatusCommand shows the global scheduler status +func StatusCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "status", + Short: "Show scheduler status", + Long: "Display whether the global scheduler is paused or running.", + Example: "harbor jobservice schedules status", + RunE: func(cmd *cobra.Command, args []string) error { + response, err := api.GetSchedulePaused() + if err != nil { + return formatScheduleError("failed to retrieve scheduler status", err, "authenticated") + } + + if response == nil || response.Payload == nil { + fmt.Println("Unable to determine scheduler status.") + return nil + } + + formatFlag := viper.GetString("output-format") + if formatFlag != "" { + return utils.PrintFormat(response.Payload, formatFlag) + } + + schedules.PrintScheduleStatus(response.Payload) + return nil + }, + } + + return cmd +} + +// PauseAllCommand pauses all schedules +func PauseAllCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "pause-all", + Short: "Pause all schedules", + Long: "Pause the global scheduler and all schedules.", + Example: "harbor jobservice schedules pause-all", + RunE: func(cmd *cobra.Command, args []string) error { + fmt.Println("Pausing all schedules...") + err := api.ActionJobQueue("SCHEDULER", "pause") + if err != nil { + return formatScheduleError("failed to pause all schedules", err, "ActionStop") + } + fmt.Println("✓ All schedules paused successfully.") + return nil + }, + } + + return cmd +} + +// ResumeAllCommand resumes all schedules +func ResumeAllCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "resume-all", + Short: "Resume all schedules", + Long: "Resume the global scheduler and all schedules.", + Example: "harbor jobservice schedules resume-all", + RunE: func(cmd *cobra.Command, args []string) error { + fmt.Println("Resuming all schedules...") + err := api.ActionJobQueue("SCHEDULER", "resume") + if err != nil { + return formatScheduleError("failed to resume all schedules", err, "ActionStop") + } + fmt.Println("✓ All schedules resumed successfully.") + return nil + }, + } + + return cmd +} + +func formatScheduleError(operation string, err error, requiredPermission string) error { + errorCode := utils.ParseHarborErrorCode(err) + + switch errorCode { + case "400": + return fmt.Errorf("%s: invalid request. For schedule status use job_type=all; for queue action use stop|pause|resume", operation) + case "401": + return fmt.Errorf("%s: authentication required. Please run 'harbor login' and try again", operation) + case "403": + if requiredPermission == "authenticated" { + return fmt.Errorf("%s: permission denied. Your account is authenticated but lacks access", operation) + } + return fmt.Errorf("%s: permission denied. This operation requires %s on jobservice-monitor", operation, requiredPermission) + case "404": + return fmt.Errorf("%s: resource not found or not accessible in current context", operation) + case "422": + return fmt.Errorf("%s: request validation failed. Please check request body and action values", operation) + case "500": + return fmt.Errorf("%s: Harbor internal error. Retry and check Harbor server logs", operation) + default: + msg := utils.ParseHarborErrorMsg(err) + if msg == "" { + msg = err.Error() + } + return fmt.Errorf("%s: %s", operation, msg) + } +} diff --git a/cmd/harbor/root/jobservice/workers/free.go b/cmd/harbor/root/jobservice/workers/free.go new file mode 100644 index 000000000..9e11cc65a --- /dev/null +++ b/cmd/harbor/root/jobservice/workers/free.go @@ -0,0 +1,94 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package workers + +import ( + "fmt" + + "github.com/goharbor/harbor-cli/pkg/api" + "github.com/goharbor/harbor-cli/pkg/utils" + "github.com/spf13/cobra" +) + +// FreeCommand frees a worker by stopping the running job on it. +func FreeCommand() *cobra.Command { + var jobID string + + cmd := &cobra.Command{ + Use: "free", + Short: "Free one worker (--job-id required)", + Long: "Stop a running job by job ID to free its worker.", + Example: "harbor jobservice workers free --job-id abc123", + RunE: func(cmd *cobra.Command, args []string) error { + if jobID == "" { + return fmt.Errorf("--job-id is required") + } + + err := api.StopRunningJob(jobID) + if err != nil { + return formatWorkerActionError("failed to free worker", err) + } + + fmt.Printf("Worker job %q stopped successfully.\n", jobID) + return nil + }, + } + + cmd.Flags().StringVar(&jobID, "job-id", "", "Running job ID to stop") + + return cmd +} + +// FreeAllCommand frees all busy workers by stopping all running jobs. +func FreeAllCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "free-all", + Short: "Free all busy workers (job-id=all)", + Long: "Stop all running jobs to free all busy workers.", + Example: "harbor jobservice workers free-all", + RunE: func(cmd *cobra.Command, args []string) error { + err := api.StopRunningJob("all") + if err != nil { + return formatWorkerActionError("failed to free all workers", err) + } + + fmt.Println("All busy workers were freed successfully.") + return nil + }, + } + + return cmd +} + +func formatWorkerActionError(operation string, err error) error { + errorCode := utils.ParseHarborErrorCode(err) + + switch errorCode { + case "401": + return fmt.Errorf("%s: authentication required. Please run 'harbor login' and try again", operation) + case "403": + return fmt.Errorf("%s: permission denied. This operation requires ActionStop on jobservice-monitor", operation) + case "404": + return fmt.Errorf("%s: job not found or already completed", operation) + case "500": + return fmt.Errorf("%s: Harbor internal error. Retry and check Harbor server logs", operation) + default: + msg := utils.ParseHarborErrorMsg(err) + if msg == "" { + msg = err.Error() + } + return fmt.Errorf("%s: %s", operation, msg) + } +} diff --git a/cmd/harbor/root/jobservice/workers/list.go b/cmd/harbor/root/jobservice/workers/list.go new file mode 100644 index 000000000..d60881700 --- /dev/null +++ b/cmd/harbor/root/jobservice/workers/list.go @@ -0,0 +1,99 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package workers + +import ( + "fmt" + + "github.com/goharbor/harbor-cli/pkg/api" + "github.com/goharbor/harbor-cli/pkg/utils" + workersviews "github.com/goharbor/harbor-cli/pkg/views/jobservice/workers" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// ListCommand lists all workers +func ListCommand() *cobra.Command { + var poolID string + var allPools bool + var poolAll bool + + cmd := &cobra.Command{ + Use: "list [POOL_ID]", + Short: "List workers (all pools by default; use --pool for one pool)", + Long: `List job service workers. + +Supported listing modes: + - All workers (default): no POOL_ID or --pool all + - Specific pool workers: provide [POOL_ID] or --pool + - Compatibility mode: --pool-all (same as --pool all) + +Examples: + harbor jobservice workers list + harbor jobservice workers list --pool all + harbor jobservice workers list --pool default + harbor jobservice workers list default + harbor jobservice worker list 72327cf790564e45b7c89a2d`, + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + return listWorkers(cmd, args, poolID, poolAll) + }, + } + + flags := cmd.Flags() + flags.StringVar(&poolID, "pool", "", "Worker pool ID (use 'all' for all pools)") + flags.BoolVar(&allPools, "all", false, "List workers from all pools") + flags.BoolVar(&poolAll, "pool-all", false, "List workers from all pools (compatibility alias for --pool all)") + + return cmd +} + +func listWorkers(cmd *cobra.Command, args []string, poolFlag string, poolAll bool) error { + resolvedPoolID := "all" + allPools, _ := cmd.Flags().GetBool("all") + + if allPools || poolAll { + resolvedPoolID = "all" + } + + if poolFlag != "" { + resolvedPoolID = poolFlag + } + + if len(args) > 0 { + if poolFlag != "" || allPools || poolAll { + return fmt.Errorf("pool ID provided both as argument and flag; use only one form") + } + resolvedPoolID = args[0] + } + + resp, err := api.GetWorkers(resolvedPoolID) + if err != nil { + return fmt.Errorf("failed to get workers: %w", err) + } + + if resp == nil || resp.Payload == nil || len(resp.Payload) == 0 { + fmt.Println("No workers found.") + return nil + } + + formatFlag := viper.GetString("output-format") + if formatFlag != "" { + return utils.PrintFormat(resp.Payload, formatFlag) + } + + workersviews.ListWorkers(resp.Payload) + return nil +} diff --git a/cmd/harbor/root/jobservice/workers/workers.go b/cmd/harbor/root/jobservice/workers/workers.go new file mode 100644 index 000000000..1f3f84091 --- /dev/null +++ b/cmd/harbor/root/jobservice/workers/workers.go @@ -0,0 +1,48 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package workers + +import ( + "github.com/spf13/cobra" +) + +// WorkersCommand creates the workers subcommand +func WorkersCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "workers", + Aliases: []string{"worker"}, + Short: "Manage workers (list all/by pool, free, free-all)", + Long: `Manage job service workers using the job service API. + +Use 'list' to view workers from all pools or a specific pool. +Use 'free' and 'free-all' to stop running jobs and release busy workers. + +Examples: + harbor jobservice workers list + harbor jobservice workers list --pool all + harbor jobservice workers list --pool + harbor jobservice worker list + harbor jobservice workers free --job-id + harbor jobservice workers free-all`, + } + + cmd.AddCommand( + ListCommand(), + FreeCommand(), + FreeAllCommand(), + ) + + return cmd +} diff --git a/doc/cli-docs/harbor-jobservice-jobs-log.md b/doc/cli-docs/harbor-jobservice-jobs-log.md new file mode 100644 index 000000000..dc2e75976 --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-jobs-log.md @@ -0,0 +1,43 @@ +--- +title: harbor jobservice jobs log +weight: 65 +--- +## harbor jobservice jobs log + +### Description + +##### View a job log (--job-id required) + +### Synopsis + +Display the log for a specific job by job ID. + +```sh +harbor jobservice jobs log [flags] +``` + +### Examples + +```sh +harbor jobservice jobs log --job-id abc123def456 +``` + +### Options + +```sh + -h, --help help for log + --job-id string Job ID to fetch log for (required) +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice jobs](harbor-jobservice-jobs.md) - Manage job logs (view by job ID) + diff --git a/doc/cli-docs/harbor-jobservice-jobs.md b/doc/cli-docs/harbor-jobservice-jobs.md new file mode 100644 index 000000000..550f7da02 --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-jobs.md @@ -0,0 +1,33 @@ +--- +title: harbor jobservice jobs +weight: 25 +--- +## harbor jobservice jobs + +### Description + +##### Manage job logs (view by job ID) + +### Synopsis + +View logs for specific jobs. + +### Options + +```sh + -h, --help help for jobs +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice](harbor-jobservice.md) - Manage Harbor job service (admin only) +* [harbor jobservice jobs log](harbor-jobservice-jobs-log.md) - View a job log (--job-id required) + diff --git a/doc/cli-docs/harbor-jobservice-pools-list.md b/doc/cli-docs/harbor-jobservice-pools-list.md new file mode 100644 index 000000000..2b1bb8284 --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-pools-list.md @@ -0,0 +1,43 @@ +--- +title: harbor jobservice pools list +weight: 95 +--- +## harbor jobservice pools list + +### Description + +##### List all worker pools + +### Synopsis + +Display all worker pools with their details. + +```sh +harbor jobservice pools list [flags] +``` + +### Examples + +```sh +harbor jobservice pools list +harbor jobservice pool list +``` + +### Options + +```sh + -h, --help help for list +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice pools](harbor-jobservice-pools.md) - Manage worker pools (list available pools) + diff --git a/doc/cli-docs/harbor-jobservice-pools.md b/doc/cli-docs/harbor-jobservice-pools.md new file mode 100644 index 000000000..ba58b6ea4 --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-pools.md @@ -0,0 +1,39 @@ +--- +title: harbor jobservice pools +weight: 65 +--- +## harbor jobservice pools + +### Description + +##### Manage worker pools (list available pools) + +### Synopsis + +List and manage worker pools for the Harbor job service. + +Use 'list' to view all worker pools. + +Examples: + harbor jobservice pools list + harbor jobservice pool list + +### Options + +```sh + -h, --help help for pools +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice](harbor-jobservice.md) - Manage Harbor job service (admin only) +* [harbor jobservice pools list](harbor-jobservice-pools-list.md) - List all worker pools + diff --git a/doc/cli-docs/harbor-jobservice-queues-list.md b/doc/cli-docs/harbor-jobservice-queues-list.md new file mode 100644 index 000000000..3aa79d774 --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-queues-list.md @@ -0,0 +1,42 @@ +--- +title: harbor jobservice queues list +weight: 60 +--- +## harbor jobservice queues list + +### Description + +##### List all job queues + +### Synopsis + +Display all job queues with their pending job counts and latency. + +```sh +harbor jobservice queues list [flags] +``` + +### Examples + +```sh +harbor jobservice queues list +``` + +### Options + +```sh + -h, --help help for list +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice queues](harbor-jobservice-queues.md) - Manage job queues (list, stop, pause, resume) + diff --git a/doc/cli-docs/harbor-jobservice-queues-pause.md b/doc/cli-docs/harbor-jobservice-queues-pause.md new file mode 100644 index 000000000..89566901f --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-queues-pause.md @@ -0,0 +1,46 @@ +--- +title: harbor jobservice queues pause +weight: 50 +--- +## harbor jobservice queues pause + +### Description + +##### Pause queue(s) (--type or --interactive) + +### Synopsis + +Pause a job queue or all queues. + +```sh +harbor jobservice queues pause [flags] +``` + +### Examples + +```sh +harbor jobservice queues pause --type REPLICATION +harbor jobservice queues pause --type REPLICATION --type RETENTION +harbor jobservice queues pause --type all +``` + +### Options + +```sh + -h, --help help for pause + -i, --interactive Interactive mode to choose queue type(s) instead of passing --type + --type strings Job type(s) to pause (repeat flag or comma-separate values; use 'all' for all queues) +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice queues](harbor-jobservice-queues.md) - Manage job queues (list, stop, pause, resume) + diff --git a/doc/cli-docs/harbor-jobservice-queues-resume.md b/doc/cli-docs/harbor-jobservice-queues-resume.md new file mode 100644 index 000000000..7a27ba61b --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-queues-resume.md @@ -0,0 +1,46 @@ +--- +title: harbor jobservice queues resume +weight: 65 +--- +## harbor jobservice queues resume + +### Description + +##### Resume queue(s) (--type or --interactive) + +### Synopsis + +Resume a paused job queue or all queues. + +```sh +harbor jobservice queues resume [flags] +``` + +### Examples + +```sh +harbor jobservice queues resume --type REPLICATION +harbor jobservice queues resume --type REPLICATION --type RETENTION +harbor jobservice queues resume --type all +``` + +### Options + +```sh + -h, --help help for resume + -i, --interactive Interactive mode to choose queue type(s) instead of passing --type + --type strings Job type(s) to resume (repeat flag or comma-separate values; use 'all' for all queues) +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice queues](harbor-jobservice-queues.md) - Manage job queues (list, stop, pause, resume) + diff --git a/doc/cli-docs/harbor-jobservice-queues-stop.md b/doc/cli-docs/harbor-jobservice-queues-stop.md new file mode 100644 index 000000000..8c31e14a0 --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-queues-stop.md @@ -0,0 +1,46 @@ +--- +title: harbor jobservice queues stop +weight: 70 +--- +## harbor jobservice queues stop + +### Description + +##### Stop queue(s) (--type or --interactive) + +### Synopsis + +Stop a job queue or all queues. + +```sh +harbor jobservice queues stop [flags] +``` + +### Examples + +```sh +harbor jobservice queues stop --type REPLICATION +harbor jobservice queues stop --type REPLICATION --type RETENTION +harbor jobservice queues stop --type all +``` + +### Options + +```sh + -h, --help help for stop + -i, --interactive Interactive mode to choose queue type(s) instead of passing --type + --type strings Job type(s) to stop (repeat flag or comma-separate values; use 'all' for all queues) +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice queues](harbor-jobservice-queues.md) - Manage job queues (list, stop, pause, resume) + diff --git a/doc/cli-docs/harbor-jobservice-queues.md b/doc/cli-docs/harbor-jobservice-queues.md new file mode 100644 index 000000000..1256447f5 --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-queues.md @@ -0,0 +1,36 @@ +--- +title: harbor jobservice queues +weight: 35 +--- +## harbor jobservice queues + +### Description + +##### Manage job queues (list, stop, pause, resume) + +### Synopsis + +List job queues and perform actions on them (stop/pause/resume). + +### Options + +```sh + -h, --help help for queues +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice](harbor-jobservice.md) - Manage Harbor job service (admin only) +* [harbor jobservice queues list](harbor-jobservice-queues-list.md) - List all job queues +* [harbor jobservice queues pause](harbor-jobservice-queues-pause.md) - Pause queue(s) (--type or --interactive) +* [harbor jobservice queues resume](harbor-jobservice-queues-resume.md) - Resume queue(s) (--type or --interactive) +* [harbor jobservice queues stop](harbor-jobservice-queues-stop.md) - Stop queue(s) (--type or --interactive) + diff --git a/doc/cli-docs/harbor-jobservice-schedules-list.md b/doc/cli-docs/harbor-jobservice-schedules-list.md new file mode 100644 index 000000000..7c1fd6a5f --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-schedules-list.md @@ -0,0 +1,44 @@ +--- +title: harbor jobservice schedules list +weight: 75 +--- +## harbor jobservice schedules list + +### Description + +##### List schedules (supports --page and --page-size) + +### Synopsis + +Display all job schedules with pagination support. + +```sh +harbor jobservice schedules list [flags] +``` + +### Examples + +```sh +harbor jobservice schedules list --page 1 --page-size 20 +``` + +### Options + +```sh + -h, --help help for list + --page int Page number (default 1) + --page-size int Number of items per page (default 20) +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice schedules](harbor-jobservice-schedules.md) - Manage schedules (list/status/pause-all/resume-all) + diff --git a/doc/cli-docs/harbor-jobservice-schedules-pause-all.md b/doc/cli-docs/harbor-jobservice-schedules-pause-all.md new file mode 100644 index 000000000..01ba6c41c --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-schedules-pause-all.md @@ -0,0 +1,42 @@ +--- +title: harbor jobservice schedules pause all +weight: 75 +--- +## harbor jobservice schedules pause-all + +### Description + +##### Pause all schedules + +### Synopsis + +Pause the global scheduler and all schedules. + +```sh +harbor jobservice schedules pause-all [flags] +``` + +### Examples + +```sh +harbor jobservice schedules pause-all +``` + +### Options + +```sh + -h, --help help for pause-all +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice schedules](harbor-jobservice-schedules.md) - Manage schedules (list/status/pause-all/resume-all) + diff --git a/doc/cli-docs/harbor-jobservice-schedules-resume-all.md b/doc/cli-docs/harbor-jobservice-schedules-resume-all.md new file mode 100644 index 000000000..4f52ca1cc --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-schedules-resume-all.md @@ -0,0 +1,42 @@ +--- +title: harbor jobservice schedules resume all +weight: 85 +--- +## harbor jobservice schedules resume-all + +### Description + +##### Resume all schedules + +### Synopsis + +Resume the global scheduler and all schedules. + +```sh +harbor jobservice schedules resume-all [flags] +``` + +### Examples + +```sh +harbor jobservice schedules resume-all +``` + +### Options + +```sh + -h, --help help for resume-all +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice schedules](harbor-jobservice-schedules.md) - Manage schedules (list/status/pause-all/resume-all) + diff --git a/doc/cli-docs/harbor-jobservice-schedules-status.md b/doc/cli-docs/harbor-jobservice-schedules-status.md new file mode 100644 index 000000000..1c79b0b10 --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-schedules-status.md @@ -0,0 +1,42 @@ +--- +title: harbor jobservice schedules status +weight: 25 +--- +## harbor jobservice schedules status + +### Description + +##### Show scheduler status + +### Synopsis + +Display whether the global scheduler is paused or running. + +```sh +harbor jobservice schedules status [flags] +``` + +### Examples + +```sh +harbor jobservice schedules status +``` + +### Options + +```sh + -h, --help help for status +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice schedules](harbor-jobservice-schedules.md) - Manage schedules (list/status/pause-all/resume-all) + diff --git a/doc/cli-docs/harbor-jobservice-schedules.md b/doc/cli-docs/harbor-jobservice-schedules.md new file mode 100644 index 000000000..823d58c06 --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-schedules.md @@ -0,0 +1,36 @@ +--- +title: harbor jobservice schedules +weight: 95 +--- +## harbor jobservice schedules + +### Description + +##### Manage schedules (list/status/pause-all/resume-all) + +### Synopsis + +List schedules and manage global scheduler status. + +### Options + +```sh + -h, --help help for schedules +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice](harbor-jobservice.md) - Manage Harbor job service (admin only) +* [harbor jobservice schedules list](harbor-jobservice-schedules-list.md) - List schedules (supports --page and --page-size) +* [harbor jobservice schedules pause-all](harbor-jobservice-schedules-pause-all.md) - Pause all schedules +* [harbor jobservice schedules resume-all](harbor-jobservice-schedules-resume-all.md) - Resume all schedules +* [harbor jobservice schedules status](harbor-jobservice-schedules-status.md) - Show scheduler status + diff --git a/doc/cli-docs/harbor-jobservice-workers-free-all.md b/doc/cli-docs/harbor-jobservice-workers-free-all.md new file mode 100644 index 000000000..be7a69eab --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-workers-free-all.md @@ -0,0 +1,42 @@ +--- +title: harbor jobservice workers free all +weight: 20 +--- +## harbor jobservice workers free-all + +### Description + +##### Free all busy workers (job-id=all) + +### Synopsis + +Stop all running jobs to free all busy workers. + +```sh +harbor jobservice workers free-all [flags] +``` + +### Examples + +```sh +harbor jobservice workers free-all +``` + +### Options + +```sh + -h, --help help for free-all +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice workers](harbor-jobservice-workers.md) - Manage workers (list all/by pool, free, free-all) + diff --git a/doc/cli-docs/harbor-jobservice-workers-free.md b/doc/cli-docs/harbor-jobservice-workers-free.md new file mode 100644 index 000000000..dee78d2ed --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-workers-free.md @@ -0,0 +1,43 @@ +--- +title: harbor jobservice workers free +weight: 20 +--- +## harbor jobservice workers free + +### Description + +##### Free one worker (--job-id required) + +### Synopsis + +Stop a running job by job ID to free its worker. + +```sh +harbor jobservice workers free [flags] +``` + +### Examples + +```sh +harbor jobservice workers free --job-id abc123 +``` + +### Options + +```sh + -h, --help help for free + --job-id string Running job ID to stop +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice workers](harbor-jobservice-workers.md) - Manage workers (list all/by pool, free, free-all) + diff --git a/doc/cli-docs/harbor-jobservice-workers-list.md b/doc/cli-docs/harbor-jobservice-workers-list.md new file mode 100644 index 000000000..761f9a038 --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-workers-list.md @@ -0,0 +1,51 @@ +--- +title: harbor jobservice workers list +weight: 95 +--- +## harbor jobservice workers list + +### Description + +##### List workers (all pools by default; use --pool for one pool) + +### Synopsis + +List job service workers. + +Supported listing modes: + - All workers (default): no POOL_ID or --pool all + - Specific pool workers: provide [POOL_ID] or --pool + - Compatibility mode: --pool-all (same as --pool all) + +Examples: + harbor jobservice workers list + harbor jobservice workers list --pool all + harbor jobservice workers list --pool default + harbor jobservice workers list default + harbor jobservice worker list 72327cf790564e45b7c89a2d + +```sh +harbor jobservice workers list [POOL_ID] [flags] +``` + +### Options + +```sh + --all List workers from all pools + -h, --help help for list + --pool string Worker pool ID (use 'all' for all pools) + --pool-all List workers from all pools (compatibility alias for --pool all) +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice workers](harbor-jobservice-workers.md) - Manage workers (list all/by pool, free, free-all) + diff --git a/doc/cli-docs/harbor-jobservice-workers.md b/doc/cli-docs/harbor-jobservice-workers.md new file mode 100644 index 000000000..5e7bbca73 --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-workers.md @@ -0,0 +1,46 @@ +--- +title: harbor jobservice workers +weight: 50 +--- +## harbor jobservice workers + +### Description + +##### Manage workers (list all/by pool, free, free-all) + +### Synopsis + +Manage job service workers using the job service API. + +Use 'list' to view workers from all pools or a specific pool. +Use 'free' and 'free-all' to stop running jobs and release busy workers. + +Examples: + harbor jobservice workers list + harbor jobservice workers list --pool all + harbor jobservice workers list --pool + harbor jobservice worker list + harbor jobservice workers free --job-id + harbor jobservice workers free-all + +### Options + +```sh + -h, --help help for workers +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor jobservice](harbor-jobservice.md) - Manage Harbor job service (admin only) +* [harbor jobservice workers free](harbor-jobservice-workers-free.md) - Free one worker (--job-id required) +* [harbor jobservice workers free-all](harbor-jobservice-workers-free-all.md) - Free all busy workers (job-id=all) +* [harbor jobservice workers list](harbor-jobservice-workers-list.md) - List workers (all pools by default; use --pool for one pool) + diff --git a/doc/cli-docs/harbor-jobservice.md b/doc/cli-docs/harbor-jobservice.md new file mode 100644 index 000000000..bd2305b50 --- /dev/null +++ b/doc/cli-docs/harbor-jobservice.md @@ -0,0 +1,40 @@ +--- +title: harbor jobservice +weight: 80 +--- +## harbor jobservice + +### Description + +##### Manage Harbor job service (admin only) + +### Synopsis + +Manage Harbor job service components including worker pools, job queues, schedules, and job logs. +This requires system admin privileges. + +Use "harbor jobservice [command] --help" for detailed examples and flags per subcommand. + +### Options + +```sh + -h, --help help for jobservice +``` + +### Options inherited from parent commands + +```sh + -c, --config string config file (default is $HOME/.config/harbor-cli/config.yaml) + -o, --output-format string Output format. One of: json|yaml + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor](harbor.md) - Official Harbor CLI +* [harbor jobservice jobs](harbor-jobservice-jobs.md) - Manage job logs (view by job ID) +* [harbor jobservice pools](harbor-jobservice-pools.md) - Manage worker pools (list available pools) +* [harbor jobservice queues](harbor-jobservice-queues.md) - Manage job queues (list, stop, pause, resume) +* [harbor jobservice schedules](harbor-jobservice-schedules.md) - Manage schedules (list/status/pause-all/resume-all) +* [harbor jobservice workers](harbor-jobservice-workers.md) - Manage workers (list all/by pool, free, free-all) + diff --git a/doc/cli-docs/harbor.md b/doc/cli-docs/harbor.md index fe1916f83..13b4f5420 100644 --- a/doc/cli-docs/harbor.md +++ b/doc/cli-docs/harbor.md @@ -42,6 +42,7 @@ harbor help * [harbor health](harbor-health.md) - Get the health status of Harbor components * [harbor info](harbor-info.md) - Display detailed Harbor system, statistics, and CLI environment information * [harbor instance](harbor-instance.md) - Manage preheat provider instances in Harbor +* [harbor jobservice](harbor-jobservice.md) - Manage Harbor job service (admin only) * [harbor label](harbor-label.md) - Manage labels in Harbor * [harbor ldap](harbor-ldap.md) - Manage ldap users and groups * [harbor login](harbor-login.md) - Log in to Harbor registry diff --git a/doc/man-docs/man1/harbor-jobservice-jobs-log.1 b/doc/man-docs/man1/harbor-jobservice-jobs-log.1 new file mode 100644 index 000000000..6c0a20127 --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-jobs-log.1 @@ -0,0 +1,45 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-jobs-log - View a job log (--job-id required) + + +.SH SYNOPSIS +\fBharbor jobservice jobs log [flags]\fP + + +.SH DESCRIPTION +Display the log for a specific job by job ID. + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for log + +.PP +\fB--job-id\fP="" + Job ID to fetch log for (required) + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX +harbor jobservice jobs log --job-id abc123def456 +.EE + + +.SH SEE ALSO +\fBharbor-jobservice-jobs(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-jobs.1 b/doc/man-docs/man1/harbor-jobservice-jobs.1 new file mode 100644 index 000000000..2886872e4 --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-jobs.1 @@ -0,0 +1,35 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-jobs - Manage job logs (view by job ID) + + +.SH SYNOPSIS +\fBharbor jobservice jobs [flags]\fP + + +.SH DESCRIPTION +View logs for specific jobs. + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for jobs + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH SEE ALSO +\fBharbor-jobservice(1)\fP, \fBharbor-jobservice-jobs-log(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-pools-list.1 b/doc/man-docs/man1/harbor-jobservice-pools-list.1 new file mode 100644 index 000000000..2c7508e8c --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-pools-list.1 @@ -0,0 +1,42 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-pools-list - List all worker pools + + +.SH SYNOPSIS +\fBharbor jobservice pools list [flags]\fP + + +.SH DESCRIPTION +Display all worker pools with their details. + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for list + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX +harbor jobservice pools list +harbor jobservice pool list +.EE + + +.SH SEE ALSO +\fBharbor-jobservice-pools(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-pools.1 b/doc/man-docs/man1/harbor-jobservice-pools.1 new file mode 100644 index 000000000..dba187585 --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-pools.1 @@ -0,0 +1,43 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-pools - Manage worker pools (list available pools) + + +.SH SYNOPSIS +\fBharbor jobservice pools [flags]\fP + + +.SH DESCRIPTION +List and manage worker pools for the Harbor job service. + +.PP +Use 'list' to view all worker pools. + +.PP +Examples: + harbor jobservice pools list + harbor jobservice pool list + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for pools + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH SEE ALSO +\fBharbor-jobservice(1)\fP, \fBharbor-jobservice-pools-list(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-queues-list.1 b/doc/man-docs/man1/harbor-jobservice-queues-list.1 new file mode 100644 index 000000000..9f2b8a562 --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-queues-list.1 @@ -0,0 +1,41 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-queues-list - List all job queues + + +.SH SYNOPSIS +\fBharbor jobservice queues list [flags]\fP + + +.SH DESCRIPTION +Display all job queues with their pending job counts and latency. + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for list + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX +harbor jobservice queues list +.EE + + +.SH SEE ALSO +\fBharbor-jobservice-queues(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-queues-pause.1 b/doc/man-docs/man1/harbor-jobservice-queues-pause.1 new file mode 100644 index 000000000..f2822f28f --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-queues-pause.1 @@ -0,0 +1,51 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-queues-pause - Pause queue(s) (--type or --interactive) + + +.SH SYNOPSIS +\fBharbor jobservice queues pause [flags]\fP + + +.SH DESCRIPTION +Pause a job queue or all queues. + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for pause + +.PP +\fB-i\fP, \fB--interactive\fP[=false] + Interactive mode to choose queue type(s) instead of passing --type + +.PP +\fB--type\fP=[] + Job type(s) to pause (repeat flag or comma-separate values; use 'all' for all queues) + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX +harbor jobservice queues pause --type REPLICATION +harbor jobservice queues pause --type REPLICATION --type RETENTION +harbor jobservice queues pause --type all +.EE + + +.SH SEE ALSO +\fBharbor-jobservice-queues(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-queues-resume.1 b/doc/man-docs/man1/harbor-jobservice-queues-resume.1 new file mode 100644 index 000000000..07e9136a1 --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-queues-resume.1 @@ -0,0 +1,51 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-queues-resume - Resume queue(s) (--type or --interactive) + + +.SH SYNOPSIS +\fBharbor jobservice queues resume [flags]\fP + + +.SH DESCRIPTION +Resume a paused job queue or all queues. + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for resume + +.PP +\fB-i\fP, \fB--interactive\fP[=false] + Interactive mode to choose queue type(s) instead of passing --type + +.PP +\fB--type\fP=[] + Job type(s) to resume (repeat flag or comma-separate values; use 'all' for all queues) + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX +harbor jobservice queues resume --type REPLICATION +harbor jobservice queues resume --type REPLICATION --type RETENTION +harbor jobservice queues resume --type all +.EE + + +.SH SEE ALSO +\fBharbor-jobservice-queues(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-queues-stop.1 b/doc/man-docs/man1/harbor-jobservice-queues-stop.1 new file mode 100644 index 000000000..ddb3c26ae --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-queues-stop.1 @@ -0,0 +1,51 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-queues-stop - Stop queue(s) (--type or --interactive) + + +.SH SYNOPSIS +\fBharbor jobservice queues stop [flags]\fP + + +.SH DESCRIPTION +Stop a job queue or all queues. + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for stop + +.PP +\fB-i\fP, \fB--interactive\fP[=false] + Interactive mode to choose queue type(s) instead of passing --type + +.PP +\fB--type\fP=[] + Job type(s) to stop (repeat flag or comma-separate values; use 'all' for all queues) + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX +harbor jobservice queues stop --type REPLICATION +harbor jobservice queues stop --type REPLICATION --type RETENTION +harbor jobservice queues stop --type all +.EE + + +.SH SEE ALSO +\fBharbor-jobservice-queues(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-queues.1 b/doc/man-docs/man1/harbor-jobservice-queues.1 new file mode 100644 index 000000000..792562ea2 --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-queues.1 @@ -0,0 +1,35 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-queues - Manage job queues (list, stop, pause, resume) + + +.SH SYNOPSIS +\fBharbor jobservice queues [flags]\fP + + +.SH DESCRIPTION +List job queues and perform actions on them (stop/pause/resume). + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for queues + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH SEE ALSO +\fBharbor-jobservice(1)\fP, \fBharbor-jobservice-queues-list(1)\fP, \fBharbor-jobservice-queues-pause(1)\fP, \fBharbor-jobservice-queues-resume(1)\fP, \fBharbor-jobservice-queues-stop(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-schedules-list.1 b/doc/man-docs/man1/harbor-jobservice-schedules-list.1 new file mode 100644 index 000000000..6cdf50b8d --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-schedules-list.1 @@ -0,0 +1,49 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-schedules-list - List schedules (supports --page and --page-size) + + +.SH SYNOPSIS +\fBharbor jobservice schedules list [flags]\fP + + +.SH DESCRIPTION +Display all job schedules with pagination support. + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for list + +.PP +\fB--page\fP=1 + Page number + +.PP +\fB--page-size\fP=20 + Number of items per page + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX +harbor jobservice schedules list --page 1 --page-size 20 +.EE + + +.SH SEE ALSO +\fBharbor-jobservice-schedules(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-schedules-pause-all.1 b/doc/man-docs/man1/harbor-jobservice-schedules-pause-all.1 new file mode 100644 index 000000000..8715a2c0d --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-schedules-pause-all.1 @@ -0,0 +1,41 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-schedules-pause-all - Pause all schedules + + +.SH SYNOPSIS +\fBharbor jobservice schedules pause-all [flags]\fP + + +.SH DESCRIPTION +Pause the global scheduler and all schedules. + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for pause-all + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX +harbor jobservice schedules pause-all +.EE + + +.SH SEE ALSO +\fBharbor-jobservice-schedules(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-schedules-resume-all.1 b/doc/man-docs/man1/harbor-jobservice-schedules-resume-all.1 new file mode 100644 index 000000000..647494f79 --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-schedules-resume-all.1 @@ -0,0 +1,41 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-schedules-resume-all - Resume all schedules + + +.SH SYNOPSIS +\fBharbor jobservice schedules resume-all [flags]\fP + + +.SH DESCRIPTION +Resume the global scheduler and all schedules. + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for resume-all + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX +harbor jobservice schedules resume-all +.EE + + +.SH SEE ALSO +\fBharbor-jobservice-schedules(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-schedules-status.1 b/doc/man-docs/man1/harbor-jobservice-schedules-status.1 new file mode 100644 index 000000000..eb1dfe9db --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-schedules-status.1 @@ -0,0 +1,41 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-schedules-status - Show scheduler status + + +.SH SYNOPSIS +\fBharbor jobservice schedules status [flags]\fP + + +.SH DESCRIPTION +Display whether the global scheduler is paused or running. + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for status + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX +harbor jobservice schedules status +.EE + + +.SH SEE ALSO +\fBharbor-jobservice-schedules(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-schedules.1 b/doc/man-docs/man1/harbor-jobservice-schedules.1 new file mode 100644 index 000000000..ae580e717 --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-schedules.1 @@ -0,0 +1,35 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-schedules - Manage schedules (list/status/pause-all/resume-all) + + +.SH SYNOPSIS +\fBharbor jobservice schedules [flags]\fP + + +.SH DESCRIPTION +List schedules and manage global scheduler status. + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for schedules + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH SEE ALSO +\fBharbor-jobservice(1)\fP, \fBharbor-jobservice-schedules-list(1)\fP, \fBharbor-jobservice-schedules-pause-all(1)\fP, \fBharbor-jobservice-schedules-resume-all(1)\fP, \fBharbor-jobservice-schedules-status(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-workers-free-all.1 b/doc/man-docs/man1/harbor-jobservice-workers-free-all.1 new file mode 100644 index 000000000..ce6a9e03e --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-workers-free-all.1 @@ -0,0 +1,41 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-workers-free-all - Free all busy workers (job-id=all) + + +.SH SYNOPSIS +\fBharbor jobservice workers free-all [flags]\fP + + +.SH DESCRIPTION +Stop all running jobs to free all busy workers. + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for free-all + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX +harbor jobservice workers free-all +.EE + + +.SH SEE ALSO +\fBharbor-jobservice-workers(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-workers-free.1 b/doc/man-docs/man1/harbor-jobservice-workers-free.1 new file mode 100644 index 000000000..9d2ceea91 --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-workers-free.1 @@ -0,0 +1,45 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-workers-free - Free one worker (--job-id required) + + +.SH SYNOPSIS +\fBharbor jobservice workers free [flags]\fP + + +.SH DESCRIPTION +Stop a running job by job ID to free its worker. + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for free + +.PP +\fB--job-id\fP="" + Running job ID to stop + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX +harbor jobservice workers free --job-id abc123 +.EE + + +.SH SEE ALSO +\fBharbor-jobservice-workers(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-workers-list.1 b/doc/man-docs/man1/harbor-jobservice-workers-list.1 new file mode 100644 index 000000000..04c106b7f --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-workers-list.1 @@ -0,0 +1,61 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-workers-list - List workers (all pools by default; use --pool for one pool) + + +.SH SYNOPSIS +\fBharbor jobservice workers list [POOL_ID] [flags]\fP + + +.SH DESCRIPTION +List job service workers. + +.PP +Supported listing modes: + - All workers (default): no POOL_ID or --pool all + - Specific pool workers: provide [POOL_ID] or --pool + - Compatibility mode: --pool-all (same as --pool all) + +.PP +Examples: + harbor jobservice workers list + harbor jobservice workers list --pool all + harbor jobservice workers list --pool default + harbor jobservice workers list default + harbor jobservice worker list 72327cf790564e45b7c89a2d + + +.SH OPTIONS +\fB--all\fP[=false] + List workers from all pools + +.PP +\fB-h\fP, \fB--help\fP[=false] + help for list + +.PP +\fB--pool\fP="" + Worker pool ID (use 'all' for all pools) + +.PP +\fB--pool-all\fP[=false] + List workers from all pools (compatibility alias for --pool all) + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH SEE ALSO +\fBharbor-jobservice-workers(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice-workers.1 b/doc/man-docs/man1/harbor-jobservice-workers.1 new file mode 100644 index 000000000..eb9d39e35 --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice-workers.1 @@ -0,0 +1,48 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice-workers - Manage workers (list all/by pool, free, free-all) + + +.SH SYNOPSIS +\fBharbor jobservice workers [flags]\fP + + +.SH DESCRIPTION +Manage job service workers using the job service API. + +.PP +Use 'list' to view workers from all pools or a specific pool. +Use 'free' and 'free-all' to stop running jobs and release busy workers. + +.PP +Examples: + harbor jobservice workers list + harbor jobservice workers list --pool all + harbor jobservice workers list --pool + harbor jobservice worker list + harbor jobservice workers free --job-id + harbor jobservice workers free-all + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for workers + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH SEE ALSO +\fBharbor-jobservice(1)\fP, \fBharbor-jobservice-workers-free(1)\fP, \fBharbor-jobservice-workers-free-all(1)\fP, \fBharbor-jobservice-workers-list(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-jobservice.1 b/doc/man-docs/man1/harbor-jobservice.1 new file mode 100644 index 000000000..07ac4df00 --- /dev/null +++ b/doc/man-docs/man1/harbor-jobservice.1 @@ -0,0 +1,39 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-jobservice - Manage Harbor job service (admin only) + + +.SH SYNOPSIS +\fBharbor jobservice [flags]\fP + + +.SH DESCRIPTION +Manage Harbor job service components including worker pools, job queues, schedules, and job logs. +This requires system admin privileges. + +.PP +Use "harbor jobservice [command] --help" for detailed examples and flags per subcommand. + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for jobservice + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +\fB-c\fP, \fB--config\fP="" + config file (default is $HOME/.config/harbor-cli/config.yaml) + +.PP +\fB-o\fP, \fB--output-format\fP="" + Output format. One of: json|yaml + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH SEE ALSO +\fBharbor(1)\fP, \fBharbor-jobservice-jobs(1)\fP, \fBharbor-jobservice-pools(1)\fP, \fBharbor-jobservice-queues(1)\fP, \fBharbor-jobservice-schedules(1)\fP, \fBharbor-jobservice-workers(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor.1 b/doc/man-docs/man1/harbor.1 index cd0884420..f39b7dfbe 100644 --- a/doc/man-docs/man1/harbor.1 +++ b/doc/man-docs/man1/harbor.1 @@ -43,4 +43,4 @@ harbor help .SH SEE ALSO -\fBharbor-artifact(1)\fP, \fBharbor-config(1)\fP, \fBharbor-context(1)\fP, \fBharbor-cve-allowlist(1)\fP, \fBharbor-health(1)\fP, \fBharbor-info(1)\fP, \fBharbor-instance(1)\fP, \fBharbor-label(1)\fP, \fBharbor-ldap(1)\fP, \fBharbor-login(1)\fP, \fBharbor-logs(1)\fP, \fBharbor-password(1)\fP, \fBharbor-project(1)\fP, \fBharbor-quota(1)\fP, \fBharbor-registry(1)\fP, \fBharbor-replication(1)\fP, \fBharbor-repo(1)\fP, \fBharbor-robot(1)\fP, \fBharbor-scan-all(1)\fP, \fBharbor-scanner(1)\fP, \fBharbor-schedule(1)\fP, \fBharbor-tag(1)\fP, \fBharbor-user(1)\fP, \fBharbor-version(1)\fP, \fBharbor-vulnerability(1)\fP, \fBharbor-webhook(1)\fP \ No newline at end of file +\fBharbor-artifact(1)\fP, \fBharbor-config(1)\fP, \fBharbor-context(1)\fP, \fBharbor-cve-allowlist(1)\fP, \fBharbor-health(1)\fP, \fBharbor-info(1)\fP, \fBharbor-instance(1)\fP, \fBharbor-jobservice(1)\fP, \fBharbor-label(1)\fP, \fBharbor-ldap(1)\fP, \fBharbor-login(1)\fP, \fBharbor-logs(1)\fP, \fBharbor-password(1)\fP, \fBharbor-project(1)\fP, \fBharbor-quota(1)\fP, \fBharbor-registry(1)\fP, \fBharbor-replication(1)\fP, \fBharbor-repo(1)\fP, \fBharbor-robot(1)\fP, \fBharbor-scan-all(1)\fP, \fBharbor-scanner(1)\fP, \fBharbor-schedule(1)\fP, \fBharbor-tag(1)\fP, \fBharbor-user(1)\fP, \fBharbor-version(1)\fP, \fBharbor-vulnerability(1)\fP, \fBharbor-webhook(1)\fP \ No newline at end of file diff --git a/pkg/api/jobservice_handler.go b/pkg/api/jobservice_handler.go new file mode 100644 index 000000000..74b185b62 --- /dev/null +++ b/pkg/api/jobservice_handler.go @@ -0,0 +1,150 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package api + +import ( + "github.com/goharbor/go-client/pkg/sdk/v2.0/client/jobservice" + "github.com/goharbor/go-client/pkg/sdk/v2.0/client/schedule" + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" + "github.com/goharbor/harbor-cli/pkg/utils" +) + +// GetWorkerPools retrieves all worker pools +func GetWorkerPools() (*jobservice.GetWorkerPoolsOK, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return nil, err + } + + response, err := client.Jobservice.GetWorkerPools(ctx, &jobservice.GetWorkerPoolsParams{}) + if err != nil { + return nil, err + } + + return response, nil +} + +// GetWorkers retrieves workers for a pool +func GetWorkers(poolID string) (*jobservice.GetWorkersOK, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return nil, err + } + + response, err := client.Jobservice.GetWorkers(ctx, &jobservice.GetWorkersParams{ + PoolID: poolID, + }) + if err != nil { + return nil, err + } + + return response, nil +} + +// StopRunningJob stops a running job by job ID. Use jobID=all to stop all running jobs. +func StopRunningJob(jobID string) error { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return err + } + + _, err = client.Jobservice.StopRunningJob(ctx, &jobservice.StopRunningJobParams{ + JobID: jobID, + }) + return err +} + +// ListJobQueues retrieves all job queues +func ListJobQueues() (*jobservice.ListJobQueuesOK, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return nil, err + } + + response, err := client.Jobservice.ListJobQueues(ctx, &jobservice.ListJobQueuesParams{}) + if err != nil { + return nil, err + } + + return response, nil +} + +// ActionJobQueue performs an action on a job queue (stop/pause/resume) +func ActionJobQueue(jobType, action string) error { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return err + } + + _, err = client.Jobservice.ActionPendingJobs(ctx, &jobservice.ActionPendingJobsParams{ + JobType: jobType, + ActionRequest: &models.ActionRequest{ + Action: action, + }, + }) + + return err +} + +// GetJobLog retrieves the log for a job by ID +func GetJobLog(jobID string) (string, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return "", err + } + + response, err := client.Jobservice.ActionGetJobLog(ctx, &jobservice.ActionGetJobLogParams{ + JobID: jobID, + }) + if err != nil { + return "", err + } + + return response.Payload, nil +} + +// ListSchedules retrieves schedules with pagination +func ListSchedules(page, pageSize int64) (*schedule.ListSchedulesOK, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return nil, err + } + + response, err := client.Schedule.ListSchedules(ctx, &schedule.ListSchedulesParams{ + Page: &page, + PageSize: &pageSize, + }) + if err != nil { + return nil, err + } + + return response, nil +} + +// GetSchedulePaused retrieves the global scheduler paused status +func GetSchedulePaused() (*schedule.GetSchedulePausedOK, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return nil, err + } + + response, err := client.Schedule.GetSchedulePaused(ctx, &schedule.GetSchedulePausedParams{ + JobType: "all", + }) + if err != nil { + return nil, err + } + + return response, nil +} diff --git a/pkg/views/jobservice/pools/view.go b/pkg/views/jobservice/pools/view.go new file mode 100644 index 000000000..b7007941d --- /dev/null +++ b/pkg/views/jobservice/pools/view.go @@ -0,0 +1,51 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package pools + +import ( + "fmt" + + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" +) + +// ListPools displays worker pools in a formatted table. +func ListPools(items []*models.WorkerPool) { + if len(items) == 0 { + fmt.Println("No worker pools found.") + return + } + + fmt.Printf("%-20s %-8s %-30s %-30s %-12s %-30s\n", "POOL_ID", "PID", "START_AT", "HEARTBEAT_AT", "CONCURRENCY", "HOST") + fmt.Printf("%-20s %-8s %-30s %-30s %-12s %-30s\n", "-------", "---", "--------", "------------", "-----------", "----") + + for _, pool := range items { + if pool == nil { + continue + } + + startAt := fmt.Sprintf("%v", pool.StartAt) + heartbeatAt := fmt.Sprintf("%v", pool.HeartbeatAt) + + fmt.Printf("%-20s %-8d %-30s %-30s %-12d %-30s\n", + pool.WorkerPoolID, + pool.Pid, + startAt, + heartbeatAt, + pool.Concurrency, + pool.Host, + ) + } + + fmt.Printf("\nTotal: %d worker pool(s)\n", len(items)) +} diff --git a/pkg/views/jobservice/queues/view.go b/pkg/views/jobservice/queues/view.go new file mode 100644 index 000000000..1f4ae8344 --- /dev/null +++ b/pkg/views/jobservice/queues/view.go @@ -0,0 +1,40 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package queues + +import ( + "fmt" + + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" +) + +// ListQueues displays job queues in a formatted table. +func ListQueues(items []*models.JobQueue) { + if len(items) == 0 { + fmt.Println("No job queues found.") + return + } + + fmt.Printf("%-25s %-12s %-12s %-10s\n", "JOB_TYPE", "COUNT", "LATENCY(s)", "PAUSED") + fmt.Printf("%-25s %-12s %-12s %-10s\n", "--------", "-----", "----------", "------") + + for _, queue := range items { + if queue == nil { + continue + } + fmt.Printf("%-25s %-12d %-12d %-10t\n", queue.JobType, queue.Count, queue.Latency, queue.Paused) + } + + fmt.Printf("\nTotal: %d queue(s)\n", len(items)) +} diff --git a/pkg/views/jobservice/schedules/view.go b/pkg/views/jobservice/schedules/view.go new file mode 100644 index 000000000..6ccee13e4 --- /dev/null +++ b/pkg/views/jobservice/schedules/view.go @@ -0,0 +1,55 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package schedules + +import ( + "fmt" + + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" +) + +// ListSchedules displays schedule tasks with pagination metadata. +func ListSchedules(items []*models.ScheduleTask, page, pageSize, totalCount int64) { + if len(items) == 0 { + fmt.Println("No schedules found.") + return + } + + fmt.Printf("%-8s %-18s %-22s %-30s %-20s\n", "ID", "VENDOR_TYPE", "VENDOR_ID", "CRON", "UPDATE_TIME") + fmt.Printf("%-8s %-18s %-22s %-30s %-20s\n", "--", "-----------", "---------", "----", "-----------") + + for _, task := range items { + if task == nil { + continue + } + fmt.Printf("%-8d %-18s %-22d %-30s %-20s\n", task.ID, task.VendorType, task.VendorID, task.Cron, task.UpdateTime.String()) + } + + fmt.Printf("\nPage: %d Page Size: %d Returned: %d Total: %d\n", page, pageSize, len(items), totalCount) +} + +// PrintScheduleStatus displays the scheduler paused/running state. +func PrintScheduleStatus(status *models.SchedulerStatus) { + if status == nil { + fmt.Println("Scheduler status: unknown") + return + } + + if status.Paused { + fmt.Println("Scheduler status: paused") + return + } + + fmt.Println("Scheduler status: running") +} diff --git a/pkg/views/jobservice/workers/view.go b/pkg/views/jobservice/workers/view.go new file mode 100644 index 000000000..4acbf0213 --- /dev/null +++ b/pkg/views/jobservice/workers/view.go @@ -0,0 +1,73 @@ +// Copyright Project Harbor Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package workers + +import ( + "fmt" + + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" +) + +// ListWorkers displays workers in a formatted table +func ListWorkers(workers []*models.Worker) { + if len(workers) == 0 { + fmt.Println("No workers found.") + return + } + + fmt.Printf("%-40s %-20s %-20s %-40s %-30s %-30s\n", + "ID", "POOL_ID", "JOB_NAME", "JOB_ID", "START_AT", "CHECKIN_AT") + fmt.Printf("%-40s %-20s %-20s %-40s %-30s %-30s\n", + "--", "-------", "--------", "------", "--------", "---------") + + busyCount := 0 + for _, worker := range workers { + id := worker.ID + if id == "" { + id = "-" + } + + poolID := worker.PoolID + if poolID == "" { + poolID = "-" + } + + jobName := worker.JobName + if jobName == "" { + jobName = "-" + } + + jobID := worker.JobID + if jobID == "" { + jobID = "-" + } else { + busyCount++ + } + + startAt := "-" + if worker.StartAt != nil { + startAt = fmt.Sprintf("%v", worker.StartAt) + } + + checkinAt := "-" + if worker.CheckinAt != nil { + checkinAt = fmt.Sprintf("%v", worker.CheckinAt) + } + + fmt.Printf("%-40s %-20s %-20s %-40s %-30s %-30s\n", + id, poolID, jobName, jobID, startAt, checkinAt) + } + + fmt.Printf("\nTotal: %d worker(s), Busy: %d\n", len(workers), busyCount) +}