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..00d4ecf7b --- /dev/null +++ b/cmd/harbor/root/jobservice/cmd.go @@ -0,0 +1,37 @@ +// 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/queues" + "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( + queues.QueuesCommand(), + ) + + return cmd +} diff --git a/cmd/harbor/root/jobservice/queues/cmd.go b/cmd/harbor/root/jobservice/queues/cmd.go new file mode 100644 index 000000000..0450d6b47 --- /dev/null +++ b/cmd/harbor/root/jobservice/queues/cmd.go @@ -0,0 +1,29 @@ +// 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 "github.com/spf13/cobra" + +// 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 +} diff --git a/cmd/harbor/root/jobservice/queues/list.go b/cmd/harbor/root/jobservice/queues/list.go new file mode 100644 index 000000000..144b3f9de --- /dev/null +++ b/cmd/harbor/root/jobservice/queues/list.go @@ -0,0 +1,56 @@ +// 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/harbor-cli/pkg/api" + "github.com/goharbor/harbor-cli/pkg/utils" + jobserviceutils "github.com/goharbor/harbor-cli/pkg/utils/jobservice" + queuesview "github.com/goharbor/harbor-cli/pkg/views/jobservice/queues" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// 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 jobserviceutils.FormatScheduleError("failed to retrieve job queues", err, "read") + } + + 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) + } + + queuesview.ListQueues(response.Payload) + return nil + }, + } + + return cmd +} diff --git a/cmd/harbor/root/jobservice/queues/pause.go b/cmd/harbor/root/jobservice/queues/pause.go new file mode 100644 index 000000000..35dfc118c --- /dev/null +++ b/cmd/harbor/root/jobservice/queues/pause.go @@ -0,0 +1,59 @@ +// 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/spf13/cobra" +) + +// 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 +} diff --git a/cmd/harbor/root/jobservice/queues/resume.go b/cmd/harbor/root/jobservice/queues/resume.go new file mode 100644 index 000000000..ec898d0c8 --- /dev/null +++ b/cmd/harbor/root/jobservice/queues/resume.go @@ -0,0 +1,58 @@ +// 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/spf13/cobra" +) + +// 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 +} diff --git a/cmd/harbor/root/jobservice/queues/stop.go b/cmd/harbor/root/jobservice/queues/stop.go new file mode 100644 index 000000000..6d755c6cd --- /dev/null +++ b/cmd/harbor/root/jobservice/queues/stop.go @@ -0,0 +1,59 @@ +// 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/spf13/cobra" +) + +// 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 +} diff --git a/cmd/harbor/root/jobservice/queues/utils.go b/cmd/harbor/root/jobservice/queues/utils.go new file mode 100644 index 000000000..3ed217071 --- /dev/null +++ b/cmd/harbor/root/jobservice/queues/utils.go @@ -0,0 +1,177 @@ +// 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" + jobserviceutils "github.com/goharbor/harbor-cli/pkg/utils/jobservice" +) + +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 jobserviceutils.FormatScheduleError( + fmt.Sprintf("failed to %s queue '%s'", action, jobType), + err, + "update", + ) + } + 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:] +} + +// selectQueueTypes shows an interactive multi-selector for queue types +func selectQueueTypes(action string) ([]string, error) { + response, err := api.ListJobQueues() + if err != nil { + return nil, jobserviceutils.FormatScheduleError("failed to retrieve job queues", err, "read") + } + + 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 +} 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..e4ab35fe1 --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-queues-list.md @@ -0,0 +1,42 @@ +--- +title: harbor jobservice queues list +weight: 65 +--- +## 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..ad897b841 --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-queues-pause.md @@ -0,0 +1,46 @@ +--- +title: harbor jobservice queues pause +weight: 80 +--- +## 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..1df0b779e --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-queues-resume.md @@ -0,0 +1,46 @@ +--- +title: harbor jobservice queues resume +weight: 90 +--- +## 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..1992d77fa --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-queues-stop.md @@ -0,0 +1,46 @@ +--- +title: harbor jobservice queues stop +weight: 60 +--- +## 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..9b27f3446 --- /dev/null +++ b/doc/cli-docs/harbor-jobservice-queues.md @@ -0,0 +1,36 @@ +--- +title: harbor jobservice queues +weight: 65 +--- +## 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.md b/doc/cli-docs/harbor-jobservice.md new file mode 100644 index 000000000..3802be7a4 --- /dev/null +++ b/doc/cli-docs/harbor-jobservice.md @@ -0,0 +1,36 @@ +--- +title: harbor jobservice +weight: 75 +--- +## 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 queues](harbor-jobservice-queues.md) - Manage job queues (list, stop, pause, resume) + 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-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.1 b/doc/man-docs/man1/harbor-jobservice.1 new file mode 100644 index 000000000..0c130a640 --- /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-queues(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..205b399ff --- /dev/null +++ b/pkg/api/jobservice_handler.go @@ -0,0 +1,52 @@ +// 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/models" + "github.com/goharbor/harbor-cli/pkg/utils" +) + +// 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 +} diff --git a/pkg/utils/jobservice/errors.go b/pkg/utils/jobservice/errors.go new file mode 100644 index 000000000..a7c222ee0 --- /dev/null +++ b/pkg/utils/jobservice/errors.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 jobservice + +import ( + "fmt" + + "github.com/goharbor/harbor-cli/pkg/utils" +) + +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/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)) +}