-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Added retention command #184
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package retention | ||
|
||
import ( | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
func Retention() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "retention", | ||
Short: "Manage retention rule in the project", | ||
Long: `Manage retention rules in the project in Harbor`, | ||
Example: `harbor retention create`, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. some example usecases here would be beneficial. |
||
} | ||
cmd.AddCommand( | ||
CreateRetentionCommand(), | ||
ListExecutionRetentionCommand(), | ||
DeleteRetentionCommand(), | ||
) | ||
|
||
return cmd | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package retention | ||
|
||
import ( | ||
"github.com/goharbor/harbor-cli/pkg/api" | ||
"github.com/goharbor/harbor-cli/pkg/prompt" | ||
"github.com/goharbor/harbor-cli/pkg/views/retention/create" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
func CreateRetentionCommand() *cobra.Command { | ||
var opts create.CreateView | ||
|
||
cmd := &cobra.Command{ | ||
Use: "create", | ||
Short: "create retention tag rule", | ||
Long: "create retention tag rule to the project in harbor", | ||
Example: "harbor retention create", | ||
Run: func(cmd *cobra.Command, args []string) { | ||
var err error | ||
createView := &create.CreateView{ | ||
ScopeSelectors: create.RetentionSelector{ | ||
Decoration: opts.ScopeSelectors.Decoration, | ||
Pattern: opts.ScopeSelectors.Pattern, | ||
}, | ||
TagSelectors: create.RetentionSelector{ | ||
Decoration: opts.TagSelectors.Decoration, | ||
Pattern: opts.TagSelectors.Pattern, | ||
Extras: opts.TagSelectors.Extras, | ||
}, | ||
Scope: create.RetentionPolicyScope{ | ||
Level: opts.Scope.Level, | ||
Ref: opts.Scope.Ref, | ||
}, | ||
Template: opts.Template, | ||
Params: opts.Params, | ||
Action: opts.Action, | ||
Algorithm: opts.Algorithm, | ||
} | ||
|
||
projectId := int32(prompt.GetProjectIDFromUser()) | ||
err = createRetentionView(createView,projectId) | ||
|
||
if err != nil { | ||
log.Errorf("failed to create retention tag rule: %v", err) | ||
} | ||
|
||
}, | ||
} | ||
|
||
flags := cmd.Flags() | ||
flags.StringVarP(&opts.ScopeSelectors.Decoration, "repodecoration", "", "", "repository which either apply or exclude from the rule") | ||
flags.StringVarP(&opts.ScopeSelectors.Pattern, "repolist", "", "", "list of repository to which to either apply or exclude from the rule") | ||
flags.StringVarP(&opts.TagSelectors.Decoration, "tagdecoration", "", "", "tags which either apply or exclude from the rule") | ||
flags.StringVarP(&opts.TagSelectors.Pattern, "taglist", "", "", "list of tags to which to either apply or exclude from the rule") | ||
flags.StringVarP(&opts.Scope.Level,"level","","project","scope of retention policy") | ||
flags.StringVarP(&opts.Action,"action","","retain","Action of the retention policy") | ||
flags.StringVarP(&opts.Algorithm,"algorithm","","or","Algorithm of retention policy") | ||
|
||
return cmd | ||
} | ||
|
||
func createRetentionView(createView *create.CreateView,projectId int32) error { | ||
if createView == nil { | ||
createView = &create.CreateView{} | ||
} | ||
|
||
create.CreateRetentionView(createView) | ||
return api.CreateRetention(*createView,projectId) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package retention | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
|
||
"github.com/goharbor/harbor-cli/pkg/api" | ||
"github.com/goharbor/harbor-cli/pkg/prompt" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
func DeleteRetentionCommand() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "delete", | ||
Short: "delete retention rule", | ||
Args: cobra.MaximumNArgs(1), | ||
Run: func(cmd *cobra.Command, args []string) { | ||
var err error | ||
var retentionId int | ||
var strretenId string | ||
if len(args) > 0 { | ||
retentionId,_ = strconv.Atoi(args[0]) | ||
err = api.DeleteRetention(int64(retentionId)) | ||
} else { | ||
projectId := fmt.Sprintf("%d",prompt.GetProjectIDFromUser()) | ||
strretenId,err = api.GetRetentionId(projectId) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
retentionId,_ = strconv.Atoi(strretenId) | ||
err = api.DeleteRetention(int64(retentionId)) | ||
} | ||
if err != nil { | ||
log.Errorf("failed to delete retention rule: %v", err) | ||
} | ||
}, | ||
} | ||
|
||
return cmd | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package retention | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
|
||
"github.com/goharbor/go-client/pkg/sdk/v2.0/client/retention" | ||
"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/retention/list" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/spf13/cobra" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
func ListExecutionRetentionCommand() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "list", | ||
Short: "list retention execution of the project", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is an absolute wrong approach here. As an user I would expect ./harbor project retention list to return me the list of retention rules that I made. Instead of retention executions. FIX THIS.
Comment on lines
+19
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is absolute wrong approach here. As an user I would expect ./harbor tag retention list to return me the list of retention rules that I made. Instead of retention executions. FIX THIS. |
||
Args: cobra.MaximumNArgs(1), | ||
Example: `harbor retention list [retentionid]`, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
var err error | ||
var resp retention.ListRetentionExecutionsOK | ||
var retentionID int | ||
var strretenId string | ||
if len(args) > 0 { | ||
retentionID,_ = strconv.Atoi(args[0]) | ||
resp, err = api.ListRetention(int32(retentionID)) | ||
} else { | ||
projectId := fmt.Sprintf("%d",prompt.GetProjectIDFromUser()) | ||
strretenId,err = api.GetRetentionId(projectId) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
retentionID,_ := strconv.Atoi(strretenId) | ||
resp, err = api.ListRetention(int32(retentionID)) | ||
} | ||
|
||
if err != nil { | ||
log.Errorf("failed to list retention execution: %v", err) | ||
} | ||
FormatFlag := viper.GetString("output-format") | ||
if FormatFlag != "" { | ||
utils.PrintPayloadInJSONFormat(resp) | ||
return | ||
} | ||
|
||
list.ListRetentionRules(resp.Payload) | ||
|
||
}, | ||
} | ||
|
||
return cmd | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package api | ||
|
||
import ( | ||
"errors" | ||
"strconv" | ||
|
||
"github.com/goharbor/go-client/pkg/sdk/v2.0/client/project" | ||
"github.com/goharbor/go-client/pkg/sdk/v2.0/client/retention" | ||
"github.com/goharbor/go-client/pkg/sdk/v2.0/models" | ||
"github.com/goharbor/harbor-cli/pkg/utils" | ||
"github.com/goharbor/harbor-cli/pkg/views/retention/create" | ||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
func CreateRetention(opts create.CreateView, projectId int32) error { | ||
ctx, client, err := utils.ContextWithClient() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
tagSelector := &models.RetentionSelector{ | ||
Decoration: opts.TagSelectors.Decoration, | ||
Pattern: opts.TagSelectors.Pattern, | ||
Extras: opts.TagSelectors.Extras, | ||
} | ||
scope := models.RetentionSelector{ | ||
Decoration: opts.ScopeSelectors.Decoration, | ||
Pattern: opts.ScopeSelectors.Pattern, | ||
} | ||
scopeSelector := map[string][]models.RetentionSelector{ | ||
"repository": { | ||
scope, | ||
}, | ||
} | ||
param := make(map[string] interface{}) | ||
if opts.Template == "always" { | ||
param = nil | ||
} else { | ||
value, err := strconv.Atoi(opts.Params.Value) | ||
if err != nil { | ||
return err | ||
} | ||
param[opts.Template] = value | ||
} | ||
|
||
var rule []*models.RetentionRule | ||
rule = append(rule, &models.RetentionRule{ | ||
Action: opts.Action, | ||
ScopeSelectors: scopeSelector, | ||
TagSelectors: []*models.RetentionSelector{tagSelector}, | ||
Template: opts.Template, | ||
Params: param, | ||
}) | ||
|
||
triggerSettings := map[string]string{ | ||
"cron": "", | ||
} | ||
|
||
_, err = client.Retention.CreateRetention(ctx, &retention.CreateRetentionParams{Policy: &models.RetentionPolicy{Scope: &models.RetentionPolicyScope{Level: opts.Scope.Level,Ref: int64(projectId)},Trigger: &models.RetentionRuleTrigger{Kind: models.ScheduleObjTypeSchedule,Settings: triggerSettings},Algorithm: opts.Algorithm,Rules: rule}}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
log.Info("Added Tag Retention Rule") | ||
return nil | ||
} | ||
|
||
func ListRetention(projectID int32)(retention.ListRetentionExecutionsOK,error){ | ||
ctx, client, err := utils.ContextWithClient() | ||
if err != nil { | ||
return retention.ListRetentionExecutionsOK{}, err | ||
} | ||
response,err := client.Retention.ListRetentionExecutions(ctx,&retention.ListRetentionExecutionsParams{ID: int64(projectID)}) | ||
if err != nil { | ||
return retention.ListRetentionExecutionsOK{}, err | ||
} | ||
|
||
return *response, nil | ||
} | ||
|
||
func GetRetentionId(projectId string) (string,error) { | ||
ctx, client, err := utils.ContextWithClient() | ||
if err != nil { | ||
return "",err | ||
} | ||
|
||
response, err := client.Project.GetProject(ctx, &project.GetProjectParams{ProjectNameOrID: projectId}) | ||
if err != nil { | ||
log.Errorf("failed to get project: %v", err) | ||
return "", err | ||
} | ||
|
||
if response.Payload.Metadata == nil || response.Payload.Metadata.RetentionID == nil { | ||
return "", errors.New("no retention policy present for the project") | ||
} | ||
retentionid := *response.Payload.Metadata.RetentionID | ||
|
||
return retentionid,nil | ||
} | ||
|
||
func DeleteRetention(RetentionID int64) error{ | ||
ctx, client, err := utils.ContextWithClient() | ||
if err != nil { | ||
return err | ||
} | ||
_, err = client.Retention.DeleteRetention(ctx,&retention.DeleteRetentionParams{ID: RetentionID}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
log.Info("retention rule deleted successfully") | ||
|
||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can use the Long explanation to explain what does this command do.
Since retention is a TAG RETENTION policy, we should communicate this well to the user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also mention, "user can only create 15 tag retention rules per project".