diff --git a/cmd/harbor/root/project/preheat.go b/cmd/harbor/root/project/preheat.go index f65e1c536..664b58eca 100644 --- a/cmd/harbor/root/project/preheat.go +++ b/cmd/harbor/root/project/preheat.go @@ -28,6 +28,7 @@ func Preheat() *cobra.Command { } cmd.AddCommand( preheat.PolicyCommand(), + preheat.ExecutionCommand(), ) return cmd diff --git a/cmd/harbor/root/project/preheat/execution.go b/cmd/harbor/root/project/preheat/execution.go new file mode 100644 index 000000000..44d7a0810 --- /dev/null +++ b/cmd/harbor/root/project/preheat/execution.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 preheat + +import ( + "github.com/goharbor/harbor-cli/cmd/harbor/root/project/preheat/execution" + "github.com/spf13/cobra" +) + +func ExecutionCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "execution", + Aliases: []string{"exec"}, + Short: "Manage preheat executions", + Long: "Manage P2P preheat executions under a project", + Example: ` harbor-cli project preheat execution list [NAME|ID] [POLICY_NAME]`, + } + + cmd.AddCommand( + execution.ListExecutionCommand(), + execution.ViewExecutionCommand(), + execution.StopExecutionCommand(), + ) + + return cmd +} diff --git a/cmd/harbor/root/project/preheat/execution/list.go b/cmd/harbor/root/project/preheat/execution/list.go new file mode 100644 index 000000000..59b185af9 --- /dev/null +++ b/cmd/harbor/root/project/preheat/execution/list.go @@ -0,0 +1,118 @@ +// 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 execution + +import ( + "fmt" + + "github.com/goharbor/harbor-cli/pkg/api" + "github.com/goharbor/harbor-cli/pkg/prompt" + "github.com/goharbor/harbor-cli/pkg/utils" + "github.com/goharbor/harbor-cli/pkg/views/preheat/execution/list" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func ListExecutionCommand() *cobra.Command { + var opts api.ListFlags + var isID bool + + cmd := &cobra.Command{ + Use: "list", + Short: "List preheat executions", + Long: "List preheat executions under a project", + Example: ` harbor-cli project preheat execution list [NAME|ID] [POLICY_NAME]`, + Args: cobra.MaximumNArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + var err error + var projectName, policyName string + + if opts.Page < 1 { + return fmt.Errorf("page number must be greater than or equal to 1") + } + if opts.PageSize <= 0 || opts.PageSize > 100 { + return fmt.Errorf("page size must be greater than 0 and less than or equal to 100") + } + + if isID && len(args) == 0 { + return fmt.Errorf("project ID must be provided when using --id") + } + + if len(args) >= 1 { + log.Debugf("Project name provided: %s", args[0]) + projectName = args[0] + } else { + log.Debug("No project name provided, prompting user") + projectName, err = prompt.GetProjectNameFromUser() + if err != nil { + return fmt.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err)) + } + } + + if isID { + project, err := api.GetProject(projectName, true) + if err != nil { + return fmt.Errorf("failed to resolve project ID: %v", utils.ParseHarborErrorMsg(err)) + } + projectName = project.Payload.Name + } + + if len(args) >= 2 { + log.Debugf("Policy name provided: %s", args[1]) + policyName = args[1] + } else { + log.Debug("No policy name provided, prompting user") + policyName, err = prompt.GetPreheatPolicyNameFromUser(projectName) + if err != nil { + return fmt.Errorf("failed to get policy name: %v", utils.ParseHarborErrorMsg(err)) + } + } + + log.Debug("Fetching preheat policy executions...") + resp, err := api.ListPreheatExecutions(projectName, policyName, opts) + if err != nil { + if utils.ParseHarborErrorCode(err) == "404" { + return fmt.Errorf("no executions found for policy %s in project %s", policyName, projectName) + } + return fmt.Errorf("failed to list preheat executions: %v", utils.ParseHarborErrorMsg(err)) + } + + if len(resp.Payload) == 0 { + fmt.Println("No executions found") + return nil + } + + FormatFlag := viper.GetString("output-format") + if FormatFlag != "" { + err = utils.PrintFormat(resp.Payload, FormatFlag) + if err != nil { + return err + } + } else { + list.ListExecutions(resp.Payload) + } + return nil + }, + } + + flags := cmd.Flags() + flags.BoolVar(&isID, "id", false, "Get preheat executions by project id") + flags.Int64VarP(&opts.Page, "page", "", 1, "Page number") + flags.Int64VarP(&opts.PageSize, "page-size", "", 10, "Size of per page") + flags.StringVarP(&opts.Q, "query", "q", "", "Query string to query resources") + flags.StringVarP(&opts.Sort, "sort", "", "", "Sort the resource list in ascending or descending order") + + return cmd +} diff --git a/cmd/harbor/root/project/preheat/execution/stop.go b/cmd/harbor/root/project/preheat/execution/stop.go new file mode 100644 index 000000000..6f0c231ba --- /dev/null +++ b/cmd/harbor/root/project/preheat/execution/stop.go @@ -0,0 +1,106 @@ +// 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 execution + +import ( + "fmt" + "strconv" + + "github.com/goharbor/harbor-cli/pkg/api" + "github.com/goharbor/harbor-cli/pkg/prompt" + "github.com/goharbor/harbor-cli/pkg/utils" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +func StopExecutionCommand() *cobra.Command { + var isID bool + + cmd := &cobra.Command{ + Use: "stop [PROJECT_NAME|ID] [POLICY_NAME] [EXECUTION_ID]", + Short: "Stop preheat execution", + Long: "Stop a specific P2P preheat execution of a policy under a project", + Example: ` harbor-cli project preheat execution stop [NAME|ID] [POLICY_NAME] [EXECUTION_ID]`, + Args: cobra.MaximumNArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + var err error + var projectName, policyName string + var executionID int64 + + if isID && len(args) == 0 { + return fmt.Errorf("project ID must be provided when using --id") + } + + if len(args) >= 1 { + log.Debugf("Project name provided: %s", args[0]) + projectName = args[0] + } else { + log.Debug("No project name provided, prompting user") + projectName, err = prompt.GetProjectNameFromUser() + if err != nil { + return fmt.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err)) + } + } + if isID { + project, err := api.GetProject(projectName, true) + if err != nil { + return fmt.Errorf("failed to resolve project ID: %v", utils.ParseHarborErrorMsg(err)) + } + projectName = project.Payload.Name + } + + if len(args) >= 2 { + log.Debugf("Policy name provided: %s", args[1]) + policyName = args[1] + } else { + log.Debug("No policy name provided, prompting user") + policyName, err = prompt.GetPreheatPolicyNameFromUser(projectName) + if err != nil { + return fmt.Errorf("failed to get policy name: %v", utils.ParseHarborErrorMsg(err)) + } + } + + if len(args) >= 3 { + log.Debugf("Execution ID provided: %s", args[2]) + executionID, err = strconv.ParseInt(args[2], 10, 64) + if err != nil { + return fmt.Errorf("invalid execution ID %q: %v", args[2], err) + } + } else { + log.Debug("No execution ID provided, prompting user") + executionID, err = prompt.GetPreheatPolicyExecIDFromUser(projectName, policyName) + if err != nil { + return fmt.Errorf("failed to get execution id: %v", utils.ParseHarborErrorMsg(err)) + } + } + + log.Debug("Stopping preheat execution...") + err = api.StopPreheatExecution(projectName, policyName, executionID) + if err != nil { + if utils.ParseHarborErrorCode(err) == "404" { + return fmt.Errorf("preheat execution %d not found for policy %s in project %s", executionID, policyName, projectName) + } + return fmt.Errorf("failed to stop preheat execution: %v", utils.ParseHarborErrorMsg(err)) + } + + fmt.Printf("Preheat execution %d stopped successfully for policy '%s' in project '%s'\n", executionID, policyName, projectName) + return nil + }, + } + + flags := cmd.Flags() + flags.BoolVar(&isID, "id", false, "Get preheat policy execution by project id") + + return cmd +} diff --git a/cmd/harbor/root/project/preheat/execution/view.go b/cmd/harbor/root/project/preheat/execution/view.go new file mode 100644 index 000000000..1e0879d47 --- /dev/null +++ b/cmd/harbor/root/project/preheat/execution/view.go @@ -0,0 +1,116 @@ +// 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 execution + +import ( + "fmt" + "strconv" + + "github.com/goharbor/harbor-cli/pkg/api" + "github.com/goharbor/harbor-cli/pkg/prompt" + "github.com/goharbor/harbor-cli/pkg/utils" + "github.com/goharbor/harbor-cli/pkg/views/preheat/execution/view" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func ViewExecutionCommand() *cobra.Command { + var isID bool + + cmd := &cobra.Command{ + Use: "view [PROJECT_NAME|ID] [POLICY_NAME] [EXECUTION_ID]", + Short: "View preheat execution details", + Long: "Get details of a specific P2P preheat execution under a project", + Example: ` harbor-cli project preheat execution view [NAME|ID] [POLICY_NAME] [EXECUTION_ID]`, + Args: cobra.MaximumNArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + var err error + var projectName, policyName string + var executionID int64 + + if isID && len(args) == 0 { + return fmt.Errorf("project ID must be provided when using --id") + } + + if len(args) >= 1 { + log.Debugf("Project name provided: %s", args[0]) + projectName = args[0] + } else { + log.Debug("No project name provided, prompting user") + projectName, err = prompt.GetProjectNameFromUser() + if err != nil { + return fmt.Errorf("failed to get project name: %v", utils.ParseHarborErrorMsg(err)) + } + } + if isID { + project, err := api.GetProject(projectName, true) + if err != nil { + return fmt.Errorf("failed to resolve project ID: %v", utils.ParseHarborErrorMsg(err)) + } + projectName = project.Payload.Name + } + + if len(args) >= 2 { + log.Debugf("Policy name provided: %s", args[1]) + policyName = args[1] + } else { + log.Debug("No policy name provided, prompting user") + policyName, err = prompt.GetPreheatPolicyNameFromUser(projectName) + if err != nil { + return fmt.Errorf("failed to get policy name: %v", utils.ParseHarborErrorMsg(err)) + } + } + + if len(args) >= 3 { + log.Debugf("Execution ID provided: %s", args[2]) + executionID, err = strconv.ParseInt(args[2], 10, 64) + if err != nil { + return fmt.Errorf("invalid execution ID %q: %v", args[2], err) + } + } else { + log.Debug("No execution ID provided, prompting user") + executionID, err = prompt.GetPreheatPolicyExecIDFromUser(projectName, policyName) + if err != nil { + return fmt.Errorf("failed to get execution id: %v", utils.ParseHarborErrorMsg(err)) + } + } + + log.Debug("Fetching preheat execution details...") + resp, err := api.GetPreheatExecution(projectName, policyName, executionID) + if err != nil { + if utils.ParseHarborErrorCode(err) == "404" { + return fmt.Errorf("no execution found for execution ID %d in policy %s in project %s", executionID, policyName, projectName) + } + return fmt.Errorf("failed to view preheat execution: %v", utils.ParseHarborErrorMsg(err)) + } + + FormatFlag := viper.GetString("output-format") + if FormatFlag != "" { + err = utils.PrintFormat(resp.Payload, FormatFlag) + if err != nil { + return err + } + } else { + view.ViewExecution(resp.Payload) + } + return nil + }, + } + + flags := cmd.Flags() + flags.BoolVar(&isID, "id", false, "Get preheat policy execution by project id") + + return cmd +} diff --git a/doc/cli-docs/harbor-project-preheat-execution-list.md b/doc/cli-docs/harbor-project-preheat-execution-list.md new file mode 100644 index 000000000..63ed281f5 --- /dev/null +++ b/doc/cli-docs/harbor-project-preheat-execution-list.md @@ -0,0 +1,47 @@ +--- +title: harbor project preheat execution list +weight: 70 +--- +## harbor project preheat execution list + +### Description + +##### List preheat executions + +### Synopsis + +List preheat executions under a project + +```sh +harbor project preheat execution list [flags] +``` + +### Examples + +```sh + harbor-cli project preheat execution list [NAME|ID] [POLICY_NAME] +``` + +### Options + +```sh + -h, --help help for list + --id Get preheat executions by project id + --page int Page number (default 1) + --page-size int Size of per page (default 10) + -q, --query string Query string to query resources + --sort string Sort the resource list in ascending or descending order +``` + +### 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|csv + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor project preheat execution](harbor-project-preheat-execution.md) - Manage preheat executions + diff --git a/doc/cli-docs/harbor-project-preheat-execution-stop.md b/doc/cli-docs/harbor-project-preheat-execution-stop.md new file mode 100644 index 000000000..1456a95e6 --- /dev/null +++ b/doc/cli-docs/harbor-project-preheat-execution-stop.md @@ -0,0 +1,43 @@ +--- +title: harbor project preheat execution stop +weight: 5 +--- +## harbor project preheat execution stop + +### Description + +##### Stop preheat execution + +### Synopsis + +Stop a specific P2P preheat execution of a policy under a project + +```sh +harbor project preheat execution stop [PROJECT_NAME|ID] [POLICY_NAME] [EXECUTION_ID] [flags] +``` + +### Examples + +```sh + harbor-cli project preheat execution stop [NAME|ID] [POLICY_NAME] [EXECUTION_ID] +``` + +### Options + +```sh + -h, --help help for stop + --id Get preheat policy execution by project id +``` + +### 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|csv + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor project preheat execution](harbor-project-preheat-execution.md) - Manage preheat executions + diff --git a/doc/cli-docs/harbor-project-preheat-execution-view.md b/doc/cli-docs/harbor-project-preheat-execution-view.md new file mode 100644 index 000000000..55855719b --- /dev/null +++ b/doc/cli-docs/harbor-project-preheat-execution-view.md @@ -0,0 +1,43 @@ +--- +title: harbor project preheat execution view +weight: 50 +--- +## harbor project preheat execution view + +### Description + +##### View preheat execution details + +### Synopsis + +Get details of a specific P2P preheat execution under a project + +```sh +harbor project preheat execution view [PROJECT_NAME|ID] [POLICY_NAME] [EXECUTION_ID] [flags] +``` + +### Examples + +```sh + harbor-cli project preheat execution view [NAME|ID] [POLICY_NAME] [EXECUTION_ID] +``` + +### Options + +```sh + -h, --help help for view + --id Get preheat policy execution by project id +``` + +### 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|csv + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor project preheat execution](harbor-project-preheat-execution.md) - Manage preheat executions + diff --git a/doc/cli-docs/harbor-project-preheat-execution.md b/doc/cli-docs/harbor-project-preheat-execution.md new file mode 100644 index 000000000..673da9e26 --- /dev/null +++ b/doc/cli-docs/harbor-project-preheat-execution.md @@ -0,0 +1,41 @@ +--- +title: harbor project preheat execution +weight: 95 +--- +## harbor project preheat execution + +### Description + +##### Manage preheat executions + +### Synopsis + +Manage P2P preheat executions under a project + +### Examples + +```sh + harbor-cli project preheat execution list [NAME|ID] [POLICY_NAME] +``` + +### Options + +```sh + -h, --help help for execution +``` + +### 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|csv + -v, --verbose verbose output +``` + +### SEE ALSO + +* [harbor project preheat](harbor-project-preheat.md) - Manage project preheat resources +* [harbor project preheat execution list](harbor-project-preheat-execution-list.md) - List preheat executions +* [harbor project preheat execution stop](harbor-project-preheat-execution-stop.md) - Stop preheat execution +* [harbor project preheat execution view](harbor-project-preheat-execution-view.md) - View preheat execution details + diff --git a/doc/cli-docs/harbor-project-preheat.md b/doc/cli-docs/harbor-project-preheat.md index e847c8b53..eef5d1ffc 100644 --- a/doc/cli-docs/harbor-project-preheat.md +++ b/doc/cli-docs/harbor-project-preheat.md @@ -35,5 +35,6 @@ Manage project-scoped P2P preheat policies, executions, and tasks in Harbor ### SEE ALSO * [harbor project](harbor-project.md) - Manage projects and assign resources to them +* [harbor project preheat execution](harbor-project-preheat-execution.md) - Manage preheat executions * [harbor project preheat policy](harbor-project-preheat-policy.md) - Manage preheat policies diff --git a/doc/man-docs/man1/harbor-project-preheat-execution-list.1 b/doc/man-docs/man1/harbor-project-preheat-execution-list.1 new file mode 100644 index 000000000..2023ba4b8 --- /dev/null +++ b/doc/man-docs/man1/harbor-project-preheat-execution-list.1 @@ -0,0 +1,61 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-project-preheat-execution-list - List preheat executions + + +.SH SYNOPSIS +\fBharbor project preheat execution list [flags]\fP + + +.SH DESCRIPTION +List preheat executions under a project + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for list + +.PP +\fB--id\fP[=false] + Get preheat executions by project id + +.PP +\fB--page\fP=1 + Page number + +.PP +\fB--page-size\fP=10 + Size of per page + +.PP +\fB-q\fP, \fB--query\fP="" + Query string to query resources + +.PP +\fB--sort\fP="" + Sort the resource list in ascending or descending order + + +.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|csv + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX + harbor-cli project preheat execution list [NAME|ID] [POLICY_NAME] +.EE + + +.SH SEE ALSO +\fBharbor-project-preheat-execution(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat-execution-stop.1 b/doc/man-docs/man1/harbor-project-preheat-execution-stop.1 new file mode 100644 index 000000000..bbbea9e67 --- /dev/null +++ b/doc/man-docs/man1/harbor-project-preheat-execution-stop.1 @@ -0,0 +1,45 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-project-preheat-execution-stop - Stop preheat execution + + +.SH SYNOPSIS +\fBharbor project preheat execution stop [PROJECT_NAME|ID] [POLICY_NAME] [EXECUTION_ID] [flags]\fP + + +.SH DESCRIPTION +Stop a specific P2P preheat execution of a policy under a project + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for stop + +.PP +\fB--id\fP[=false] + Get preheat policy execution by project id + + +.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|csv + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX + harbor-cli project preheat execution stop [NAME|ID] [POLICY_NAME] [EXECUTION_ID] +.EE + + +.SH SEE ALSO +\fBharbor-project-preheat-execution(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat-execution-view.1 b/doc/man-docs/man1/harbor-project-preheat-execution-view.1 new file mode 100644 index 000000000..403516daa --- /dev/null +++ b/doc/man-docs/man1/harbor-project-preheat-execution-view.1 @@ -0,0 +1,45 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-project-preheat-execution-view - View preheat execution details + + +.SH SYNOPSIS +\fBharbor project preheat execution view [PROJECT_NAME|ID] [POLICY_NAME] [EXECUTION_ID] [flags]\fP + + +.SH DESCRIPTION +Get details of a specific P2P preheat execution under a project + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for view + +.PP +\fB--id\fP[=false] + Get preheat policy execution by project id + + +.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|csv + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX + harbor-cli project preheat execution view [NAME|ID] [POLICY_NAME] [EXECUTION_ID] +.EE + + +.SH SEE ALSO +\fBharbor-project-preheat-execution(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat-execution.1 b/doc/man-docs/man1/harbor-project-preheat-execution.1 new file mode 100644 index 000000000..494bbabaf --- /dev/null +++ b/doc/man-docs/man1/harbor-project-preheat-execution.1 @@ -0,0 +1,41 @@ +.nh +.TH "HARBOR" "1" "Harbor Community" "Harbor User Manuals" + +.SH NAME +harbor-project-preheat-execution - Manage preheat executions + + +.SH SYNOPSIS +\fBharbor project preheat execution [flags]\fP + + +.SH DESCRIPTION +Manage P2P preheat executions under a project + + +.SH OPTIONS +\fB-h\fP, \fB--help\fP[=false] + help for execution + + +.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|csv + +.PP +\fB-v\fP, \fB--verbose\fP[=false] + verbose output + + +.SH EXAMPLE +.EX + harbor-cli project preheat execution list [NAME|ID] [POLICY_NAME] +.EE + + +.SH SEE ALSO +\fBharbor-project-preheat(1)\fP, \fBharbor-project-preheat-execution-list(1)\fP, \fBharbor-project-preheat-execution-stop(1)\fP, \fBharbor-project-preheat-execution-view(1)\fP \ No newline at end of file diff --git a/doc/man-docs/man1/harbor-project-preheat.1 b/doc/man-docs/man1/harbor-project-preheat.1 index f5b24d21e..823f8388c 100644 --- a/doc/man-docs/man1/harbor-project-preheat.1 +++ b/doc/man-docs/man1/harbor-project-preheat.1 @@ -38,4 +38,4 @@ Manage project-scoped P2P preheat policies, executions, and tasks in Harbor .SH SEE ALSO -\fBharbor-project(1)\fP, \fBharbor-project-preheat-policy(1)\fP \ No newline at end of file +\fBharbor-project(1)\fP, \fBharbor-project-preheat-execution(1)\fP, \fBharbor-project-preheat-policy(1)\fP \ No newline at end of file diff --git a/pkg/api/preheat_handler.go b/pkg/api/preheat_handler.go index da52a72ce..ef4ce7981 100644 --- a/pkg/api/preheat_handler.go +++ b/pkg/api/preheat_handler.go @@ -152,3 +152,65 @@ func ListProvidersUnderProject(projectName string) ([]*models.ProviderUnderProje } return response.Payload, nil } + +func ListPreheatExecutions(projectName string, policyName string, opts ...ListFlags) (*preheat.ListExecutionsOK, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return nil, err + } + + var listFlags ListFlags + if len(opts) > 0 { + listFlags = opts[0] + } + + response, err := client.Preheat.ListExecutions(ctx, &preheat.ListExecutionsParams{ + ProjectName: projectName, + PreheatPolicyName: policyName, + Page: &listFlags.Page, + PageSize: &listFlags.PageSize, + Q: &listFlags.Q, + Sort: &listFlags.Sort, + }) + if err != nil { + return nil, err + } + return response, nil +} + +func GetPreheatExecution(projectName string, policyName string, executionID int64) (*preheat.GetExecutionOK, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return nil, err + } + + response, err := client.Preheat.GetExecution(ctx, &preheat.GetExecutionParams{ + ProjectName: projectName, + PreheatPolicyName: policyName, + ExecutionID: executionID, + }) + if err != nil { + return nil, err + } + return response, nil +} + +func StopPreheatExecution(projectName string, policyName string, executionID int64) error { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return err + } + + _, err = client.Preheat.StopExecution(ctx, &preheat.StopExecutionParams{ + ProjectName: projectName, + PreheatPolicyName: policyName, + ExecutionID: executionID, + Execution: &models.Execution{ + Status: "Stopped", + }, + }) + if err != nil { + return err + } + return nil +} diff --git a/pkg/prompt/prompt.go b/pkg/prompt/prompt.go index 68aede286..11ed7b25b 100644 --- a/pkg/prompt/prompt.go +++ b/pkg/prompt/prompt.go @@ -37,6 +37,7 @@ import ( rpolicies "github.com/goharbor/harbor-cli/pkg/views/replication/policies/select" rtasks "github.com/goharbor/harbor-cli/pkg/views/replication/task/select" + phexecutions "github.com/goharbor/harbor-cli/pkg/views/preheat/execution/select" phpolicies "github.com/goharbor/harbor-cli/pkg/views/preheat/policy/select" repoView "github.com/goharbor/harbor-cli/pkg/views/repository/select" @@ -505,3 +506,39 @@ func GetPreheatPolicyNameFromUser(projectName string) (string, error) { res := <-resultChan return res.name, res.err } + +func GetPreheatPolicyExecIDFromUser(projectName string, policyName string) (int64, error) { + type result struct { + id int64 + err error + } + executionID := make(chan result) + + go func() { + response, err := api.ListPreheatExecutions(projectName, policyName) + if err != nil { + executionID <- result{0, err} + return + } + + if len(response.Payload) == 0 { + executionID <- result{0, errors.New("no preheat executions found")} + return + } + + id, err := phexecutions.PreheatExecutionList(response.Payload) + if err != nil { + if err == phexecutions.ErrUserAborted { + executionID <- result{0, errors.New("user aborted execution selection")} + } else { + executionID <- result{0, fmt.Errorf("error during execution selection: %w", err)} + } + return + } + + executionID <- result{id, nil} + }() + + res := <-executionID + return res.id, res.err +} diff --git a/pkg/views/preheat/execution/list/view.go b/pkg/views/preheat/execution/list/view.go new file mode 100644 index 000000000..d6d951842 --- /dev/null +++ b/pkg/views/preheat/execution/list/view.go @@ -0,0 +1,68 @@ +// 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 list + +import ( + "fmt" + "os" + "strconv" + + "github.com/charmbracelet/bubbles/table" + tea "github.com/charmbracelet/bubbletea" + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" + "github.com/goharbor/harbor-cli/pkg/utils" + "github.com/goharbor/harbor-cli/pkg/views/base/tablelist" +) + +var columns = []table.Column{ + {Title: "ID", Width: tablelist.WidthS}, + {Title: "Status", Width: tablelist.WidthM}, + {Title: "Trigger", Width: tablelist.WidthM}, + {Title: "Success Rate", Width: tablelist.WidthM}, + {Title: "Start Time", Width: tablelist.WidthL}, + {Title: "End Time", Width: tablelist.WidthL}, + {Title: "Vendor", Width: tablelist.WidthM}, +} + +func ListExecutions(executions []*models.Execution) { + var rows []table.Row + for _, execution := range executions { + startTime, _ := utils.FormatCreatedTime(execution.StartTime) + endTime := "-" + if execution.Status != "Running" { + endTime, _ = utils.FormatCreatedTime(execution.EndTime) + } + + successRate := "-" + if m := execution.Metrics; m != nil && m.TaskCount > 0 { + successRate = fmt.Sprintf("%d%%", m.SuccessTaskCount*100/m.TaskCount) + } + + rows = append(rows, table.Row{ + strconv.FormatInt(execution.ID, 10), + execution.Status, + execution.Trigger, + successRate, + startTime, + endTime, + execution.VendorType, + }) + } + + m := tablelist.NewModel(columns, rows, len(rows)) + if _, err := tea.NewProgram(m).Run(); err != nil { + fmt.Println("Error running program:", err) + os.Exit(1) + } +} diff --git a/pkg/views/preheat/execution/select/view.go b/pkg/views/preheat/execution/select/view.go new file mode 100644 index 000000000..513551d52 --- /dev/null +++ b/pkg/views/preheat/execution/select/view.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 execution + +import ( + "errors" + "fmt" + "os" + "strconv" + + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" + "github.com/goharbor/harbor-cli/pkg/views/base/selection" +) + +var ErrUserAborted = errors.New("user aborted selection") + +func PreheatExecutionList(executions []*models.Execution) (int64, error) { + items := make([]list.Item, len(executions)) + for i, e := range executions { + items[i] = selection.Item(strconv.FormatInt(e.ID, 10)) + } + + m := selection.NewModel(items, "Preheat Execution") + + p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() + if err != nil { + fmt.Println("Error running program:", err) + os.Exit(1) + } + + if model, ok := p.(selection.Model); ok { + if model.Aborted { + return 0, ErrUserAborted + } + if model.Choice == "" { + return 0, errors.New("no execution selected") + } + id, err := strconv.ParseInt(model.Choice, 10, 64) + if err != nil { + return 0, fmt.Errorf("failed to parse execution ID %q: %v", model.Choice, err) + } + return id, nil + } + + return 0, errors.New("unexpected program result") +} diff --git a/pkg/views/preheat/execution/view/view.go b/pkg/views/preheat/execution/view/view.go new file mode 100644 index 000000000..6eab9dd64 --- /dev/null +++ b/pkg/views/preheat/execution/view/view.go @@ -0,0 +1,67 @@ +// 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 view + +import ( + "fmt" + "os" + "strconv" + + "github.com/charmbracelet/bubbles/table" + tea "github.com/charmbracelet/bubbletea" + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" + "github.com/goharbor/harbor-cli/pkg/utils" + "github.com/goharbor/harbor-cli/pkg/views/base/tablelist" +) + +var columns = []table.Column{ + {Title: "ID", Width: tablelist.WidthS}, + {Title: "Status", Width: tablelist.WidthM}, + {Title: "Trigger", Width: tablelist.WidthM}, + {Title: "Success Rate", Width: tablelist.WidthM}, + {Title: "Start Time", Width: tablelist.WidthL}, + {Title: "End Time", Width: tablelist.WidthL}, + {Title: "Vendor", Width: tablelist.WidthM}, +} + +func ViewExecution(exec *models.Execution) { + var rows []table.Row + + startTime, _ := utils.FormatCreatedTime(exec.StartTime) + endTime := "-" + if exec.Status != "Running" { + endTime, _ = utils.FormatCreatedTime(exec.EndTime) + } + + successRate := "-" + if m := exec.Metrics; m != nil && m.TaskCount > 0 { + successRate = fmt.Sprintf("%d%%", m.SuccessTaskCount*100/m.TaskCount) + } + + rows = append(rows, table.Row{ + strconv.FormatInt(exec.ID, 10), + exec.Status, + exec.Trigger, + successRate, + startTime, + endTime, + exec.VendorType, + }) + + m := tablelist.NewModel(columns, rows, len(rows)) + if _, err := tea.NewProgram(m).Run(); err != nil { + fmt.Println("Error running program:", err) + os.Exit(1) + } +}