Skip to content

Commit

Permalink
add purge client (#158)
Browse files Browse the repository at this point in the history
  • Loading branch information
elenz97 authored Jan 2, 2023
1 parent f56e06d commit 094f5e7
Show file tree
Hide file tree
Showing 10 changed files with 586 additions and 3 deletions.
32 changes: 32 additions & 0 deletions apiv2/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"net/url"
"strings"

"github.com/mittwald/goharbor-client/v5/apiv2/pkg/clients/purge"

"github.com/mittwald/goharbor-client/v5/apiv2/pkg/clients/label"

"github.com/mittwald/goharbor-client/v5/apiv2/pkg/clients/artifact"
Expand Down Expand Up @@ -52,6 +54,7 @@ type Client interface {
ping.Client
project.Client
projectmeta.Client
purge.Client
quota.Client
registry.Client
replication.Client
Expand All @@ -75,6 +78,7 @@ type RESTClient struct {
ping *ping.RESTClient
project *project.RESTClient
projectmeta *projectmeta.RESTClient
purge *purge.RESTClient
quota *quota.RESTClient
registry *registry.RESTClient
replication *replication.RESTClient
Expand Down Expand Up @@ -103,6 +107,7 @@ func NewRESTClient(v2Client *v2client.Harbor, opts *config.Options, authInfo run
ping: ping.NewClient(v2Client, opts, authInfo),
project: project.NewClient(v2Client, opts, authInfo),
projectmeta: projectmeta.NewClient(v2Client, opts, authInfo),
purge: purge.NewClient(v2Client, opts, authInfo),
quota: quota.NewClient(v2Client, opts, authInfo),
registry: registry.NewClient(v2Client, opts, authInfo),
replication: replication.NewClient(v2Client, opts, authInfo),
Expand Down Expand Up @@ -320,6 +325,33 @@ func (c *RESTClient) DeleteProjectMetadataValue(ctx context.Context, projectName
return c.projectmeta.DeleteProjectMetadataValue(ctx, projectNameOrID, key)
}

// Purge Client

func (c *RESTClient) CreatePurgeSchedule(ctx context.Context, schedule *modelv2.Schedule) error {
return c.purge.CreatePurgeSchedule(ctx, schedule)
}
func (c *RESTClient) RunPurge(ctx context.Context, dryRun bool) error {
return c.purge.RunPurge(ctx, dryRun)
}
func (c *RESTClient) ListPurgeHistory(ctx context.Context) ([]*modelv2.ExecHistory, error) {
return c.purge.ListPurgeHistory(ctx)
}
func (c *RESTClient) GetPurgeJob(ctx context.Context, id int64) (*modelv2.ExecHistory, error) {
return c.purge.GetPurgeJob(ctx, id)
}
func (c *RESTClient) GetPurgeJobLog(ctx context.Context, id int64) (string, error) {
return c.purge.GetPurgeJobLog(ctx, id)
}
func (c *RESTClient) GetPurgeSchedule(ctx context.Context) (*modelv2.ExecHistory, error) {
return c.purge.GetPurgeSchedule(ctx)
}
func (c *RESTClient) StopPurge(ctx context.Context, id int64) error {
return c.purge.StopPurge(ctx, id)
}
func (c *RESTClient) UpdatePurgeSchedule(ctx context.Context, schedule *modelv2.Schedule) error {
return c.purge.UpdatePurgeSchedule(ctx, schedule)
}

// Quota Client

func (c *RESTClient) ListQuotas(ctx context.Context, referenceType, referenceID *string) ([]*modelv2.Quota, error) {
Expand Down
2 changes: 1 addition & 1 deletion apiv2/pkg/clients/gc/gc.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/mittwald/goharbor-client/v5/apiv2/model"
)

// RESTClient is a subclient for handling system related actions.
// RESTClient is a subclient for handling garbage collection related actions.
type RESTClient struct {
// Options contains optional configuration when making API calls.
Options *config.Options
Expand Down
207 changes: 207 additions & 0 deletions apiv2/pkg/clients/purge/purge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
package purge

import (
"context"
"encoding/json"

"github.com/go-openapi/runtime"
v2client "github.com/mittwald/goharbor-client/v5/apiv2/internal/api/client"
"github.com/mittwald/goharbor-client/v5/apiv2/internal/api/client/purge"
"github.com/mittwald/goharbor-client/v5/apiv2/model"
"github.com/mittwald/goharbor-client/v5/apiv2/pkg/config"
"github.com/pkg/errors"
)

// RESTClient is a subclient for handling purge related actions.
type RESTClient struct {
// Options contains optional configuration when making API calls.
Options *config.Options

// The new client of the harbor v2 API
V2Client *v2client.Harbor

// AuthInfo contains the auth information that is provided on API calls.
AuthInfo runtime.ClientAuthInfoWriter
}

func NewClient(v2Client *v2client.Harbor, opts *config.Options, authInfo runtime.ClientAuthInfoWriter) *RESTClient {
return &RESTClient{
Options: opts,
V2Client: v2Client,
AuthInfo: authInfo,
}
}

type Client interface {
CreatePurgeSchedule(ctx context.Context, schedule *model.Schedule) error
RunPurge(ctx context.Context, dryRun bool) error
ListPurgeHistory(ctx context.Context) ([]*model.ExecHistory, error)
GetPurgeJob(ctx context.Context, id int64) (*model.ExecHistory, error)
GetPurgeJobLog(ctx context.Context, id int64) (string, error)
GetPurgeSchedule(ctx context.Context) (*model.ExecHistory, error)
StopPurge(ctx context.Context, id int64) error
UpdatePurgeSchedule(ctx context.Context, schedule *model.Schedule) error
}

// CreatePurgeSchedule creates a new purge schedule.
func (c *RESTClient) CreatePurgeSchedule(ctx context.Context, schedule *model.Schedule) error {
params := &purge.CreatePurgeScheduleParams{
Schedule: schedule,
Context: ctx,
}
params.WithTimeout(c.Options.Timeout)

_, err := c.V2Client.Purge.CreatePurgeSchedule(params, c.AuthInfo)
if err != nil {
return handleSwaggerPurgeErrors(err)
}

return nil
}

// RunPurge runs a manual purge job.
func (c *RESTClient) RunPurge(ctx context.Context, dryRun bool) error {
schedule, err := c.GetPurgeSchedule(ctx)
if err != nil {
return handleSwaggerPurgeErrors(err)
}
if schedule.Schedule == nil {
return errors.New("no schedule found")
}
s := schedule.Schedule
s.Type = "Manual"

// schedule.JobParameters is a string containing json
parameters := make(map[string]interface{})
err = json.Unmarshal([]byte(schedule.JobParameters), &parameters)
parameters["dry_run"] = dryRun

if err != nil {
return errors.Wrap(err, "failed to unmarshal job parameters")
}

params := &purge.CreatePurgeScheduleParams{
Schedule: &model.Schedule{
ID: schedule.ID,
Parameters: parameters,
Schedule: s,
},
Context: ctx,
}
params.WithTimeout(c.Options.Timeout)

_, err = c.V2Client.Purge.CreatePurgeSchedule(params, c.AuthInfo)
if err != nil {
return handleSwaggerPurgeErrors(err)
}

return nil
}

// ListPurgeHistory lists all purge history entries.
// While the APIs purge service exposes a method called
// 'GetPurgeHistory', it technically returns a list of purge schedules.
func (c *RESTClient) ListPurgeHistory(ctx context.Context) ([]*model.ExecHistory, error) {
var history []*model.ExecHistory
page := c.Options.Page

params := purge.NewGetPurgeHistoryParams()
params.WithPage(&page)
params.WithContext(ctx)
params.WithTimeout(c.Options.Timeout)
params.WithPageSize(&c.Options.PageSize)
params.WithQ(&c.Options.Query)
params.WithSort(&c.Options.Sort)

for {
resp, err := c.V2Client.Purge.GetPurgeHistory(params, c.AuthInfo)
if err != nil {
return nil, handleSwaggerPurgeErrors(err)
}

if len(resp.Payload) == 0 {
break
}

totalCount := resp.XTotalCount

history = append(history, resp.Payload...)

if int64(len(history)) >= totalCount {
break
}

page++
}

return history, nil
}
func (c *RESTClient) GetPurgeJob(ctx context.Context, id int64) (*model.ExecHistory, error) {
params := &purge.GetPurgeJobParams{
PurgeID: id,
Context: ctx,
}
params.WithTimeout(c.Options.Timeout)

resp, err := c.V2Client.Purge.GetPurgeJob(params, c.AuthInfo)
if err != nil {
return nil, handleSwaggerPurgeErrors(err)
}

return resp.Payload, nil
}
func (c *RESTClient) GetPurgeJobLog(ctx context.Context, id int64) (string, error) {
params := &purge.GetPurgeJobLogParams{
PurgeID: id,
Context: ctx,
}
params.WithTimeout(c.Options.Timeout)

resp, err := c.V2Client.Purge.GetPurgeJobLog(params, c.AuthInfo)
if err != nil {
return "", handleSwaggerPurgeErrors(err)
}

return resp.Payload, nil
}
func (c *RESTClient) GetPurgeSchedule(ctx context.Context) (*model.ExecHistory, error) {
params := &purge.GetPurgeScheduleParams{
Context: ctx,
}
params.WithTimeout(c.Options.Timeout)

resp, err := c.V2Client.Purge.GetPurgeSchedule(params, c.AuthInfo)
if err != nil {
return nil, handleSwaggerPurgeErrors(err)
}

return resp.Payload, nil
}
func (c *RESTClient) StopPurge(ctx context.Context, id int64) error {
params := &purge.StopPurgeParams{
PurgeID: id,
Context: ctx,
}
params.WithTimeout(c.Options.Timeout)

_, err := c.V2Client.Purge.StopPurge(params, c.AuthInfo)
if err != nil {
return handleSwaggerPurgeErrors(err)
}

return nil
}
func (c *RESTClient) UpdatePurgeSchedule(ctx context.Context, schedule *model.Schedule) error {
params := &purge.UpdatePurgeScheduleParams{
Schedule: schedule,
Context: ctx,
}
params.WithTimeout(c.Options.Timeout)

_, err := c.V2Client.Purge.UpdatePurgeSchedule(params, c.AuthInfo)
if err != nil {
return handleSwaggerPurgeErrors(err)
}

return nil
}
34 changes: 34 additions & 0 deletions apiv2/pkg/clients/purge/purge_errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package purge

import (
"github.com/go-openapi/runtime"
"github.com/mittwald/goharbor-client/v5/apiv2/pkg/errors"
"net/http"
)

// handleSwaggerPurgeErrors takes a swagger generated error as input,
// which usually does not contain any form of error message,
// and outputs a new error with a proper message.
func handleSwaggerPurgeErrors(in error) error {
t, ok := in.(*runtime.APIError)
if ok {
switch t.Code {
case http.StatusCreated:
// Harbor sometimes returns 201 instead of 200 despite the swagger spec
// not declaring it.
return nil
case http.StatusBadRequest:
return &errors.ErrBadRequest{}
case http.StatusUnauthorized:
return &errors.ErrUnauthorized{}
case http.StatusForbidden:
return &errors.ErrQuotaNoPermission{}
case http.StatusNotFound:
return &errors.ErrQuotaUnknownResource{}
case http.StatusInternalServerError:
return &errors.ErrProjectInternalErrors{}
}
}

return in
}
Loading

0 comments on commit 094f5e7

Please sign in to comment.