-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add quota client * add error handling
- Loading branch information
Showing
7 changed files
with
350 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package quota | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/go-openapi/runtime" | ||
v2client "github.com/mittwald/goharbor-client/v3/apiv2/internal/api/client" | ||
"github.com/mittwald/goharbor-client/v3/apiv2/internal/legacyapi/client" | ||
"github.com/mittwald/goharbor-client/v3/apiv2/internal/legacyapi/client/products" | ||
legacymodel "github.com/mittwald/goharbor-client/v3/apiv2/model/legacy" | ||
) | ||
|
||
// RESTClient is a subclient for handling project related actions. | ||
type RESTClient struct { | ||
// The legacy swagger client | ||
LegacyClient *client.Harbor | ||
|
||
// 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(legacyClient *client.Harbor, v2Client *v2client.Harbor, authInfo runtime.ClientAuthInfoWriter) *RESTClient { | ||
return &RESTClient{ | ||
LegacyClient: legacyClient, | ||
V2Client: v2Client, | ||
AuthInfo: authInfo, | ||
} | ||
} | ||
|
||
type Client interface { | ||
GetQuotaByProjectID(ctx context.Context, projectID int64) (*legacymodel.Quota, error) | ||
UpdateStorageQuotaByProjectID(ctx context.Context, projectID int64, storageLimit int64) error | ||
} | ||
|
||
// GetQuotaByProjectID returns a quota object containing all configured quotas for a project. | ||
func (c *RESTClient) GetQuotaByProjectID(ctx context.Context, projectID int64) (*legacymodel.Quota, error) { | ||
quota, err := c.LegacyClient.Products.GetQuotasID(&products.GetQuotasIDParams{ | ||
ID: projectID, | ||
Context: ctx, | ||
}, c.AuthInfo) | ||
if err != nil { | ||
return nil, handleSwaggerQuotaErrors(err) | ||
} | ||
|
||
return quota.Payload, nil | ||
} | ||
|
||
// UpdateStorageQuotaByProjectID updates the storageLimit quota of a project. | ||
func (c *RESTClient) UpdateStorageQuotaByProjectID(ctx context.Context, projectID int64, storageLimit int64) error { | ||
params := &products.PutQuotasIDParams{ | ||
Hard: &legacymodel.QuotaUpdateReq{ | ||
Hard: map[string]int64{ | ||
"storage": storageLimit, | ||
}, | ||
}, | ||
ID: projectID, | ||
Context: ctx, | ||
} | ||
|
||
_, err := c.LegacyClient.Products.PutQuotasID(params, c.AuthInfo) | ||
if err != nil { | ||
return handleSwaggerQuotaErrors(err) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package quota | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/go-openapi/runtime" | ||
) | ||
|
||
const ( | ||
// ErrQuotaIllegalIDFormatMsg is the error for message for ErrQuotaIllegalIDFormat errors. | ||
ErrQuotaIllegalIDFormatMsg = "illegal format in quota update request" | ||
|
||
// ErrQuotaUnauthorizedMsg is the error for message for ErrQuotaUnauthorized errors. | ||
ErrQuotaUnauthorizedMsg = "unauthorized" | ||
|
||
// ErrQuotaInternalServerErrorsMsg is the error message for ErrQuotaInternalServerErrors errors. | ||
ErrQuotaInternalServerErrorsMsg = "unexpected internal errors" | ||
|
||
// ErrQuotaNoPermissionMsg is the error message for ErrQuotaNoPermission errors. | ||
ErrQuotaNoPermissionMsg = "user does not have permission to the quota" | ||
|
||
// ErrQuotaUnknownResourceMsg is the errors message for ErrQuotaUnknownResource errors. | ||
ErrQuotaUnknownResourceMsg = "quota does not exist" | ||
) | ||
|
||
// ErrQuotaIllegalIDFormat describes an error due to an illegal request format. | ||
type ErrQuotaIllegalIDFormat struct{} | ||
|
||
// Error returns the error message. | ||
func (e *ErrQuotaIllegalIDFormat) Error() string { | ||
return ErrQuotaIllegalIDFormatMsg | ||
} | ||
|
||
// ErrQuotaUnauthorized describes an unauthorized request. | ||
type ErrQuotaUnauthorized struct{} | ||
|
||
// Error returns the error message. | ||
func (e *ErrQuotaUnauthorized) Error() string { | ||
return ErrQuotaUnauthorizedMsg | ||
} | ||
|
||
// ErrQuotaNoPermission describes an error in the request due to the lack of permissions. | ||
type ErrQuotaNoPermission struct{} | ||
|
||
// Error returns the error message. | ||
func (e *ErrQuotaNoPermission) Error() string { | ||
return ErrQuotaNoPermissionMsg | ||
} | ||
|
||
// ErrQuotaUnknownResource describes an error when the specified quota could not be found. | ||
type ErrQuotaUnknownResource struct{} | ||
|
||
// Error returns the error message. | ||
func (e *ErrQuotaUnknownResource) Error() string { | ||
return ErrQuotaUnknownResourceMsg | ||
} | ||
|
||
// ErrQuotaInternalServerErrors describes miscellaneous internal server errors. | ||
type ErrQuotaInternalServerErrors struct{} | ||
|
||
// Error returns the error message. | ||
func (e *ErrQuotaInternalServerErrors) Error() string { | ||
return ErrQuotaInternalServerErrorsMsg | ||
} | ||
|
||
// handleSwaggerQuotaErrors takes a swagger generated error as input, | ||
// which usually does not contain any form of error message, | ||
// and outputs a new error with proper message. | ||
func handleSwaggerQuotaErrors(in error) error { | ||
t, ok := in.(*runtime.APIError) | ||
if ok { | ||
switch t.Code { | ||
case http.StatusBadRequest: | ||
return &ErrQuotaIllegalIDFormat{} | ||
case http.StatusUnauthorized: | ||
return &ErrQuotaUnauthorized{} | ||
case http.StatusForbidden: | ||
return &ErrQuotaNoPermission{} | ||
case http.StatusNotFound: | ||
return &ErrQuotaUnknownResource{} | ||
case http.StatusInternalServerError: | ||
return &ErrQuotaInternalServerErrors{} | ||
} | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// +build integration | ||
|
||
package quota | ||
|
||
import ( | ||
"context" | ||
"net/url" | ||
"testing" | ||
|
||
runtimeclient "github.com/go-openapi/runtime/client" | ||
"github.com/go-openapi/strfmt" | ||
v2client "github.com/mittwald/goharbor-client/v3/apiv2/internal/api/client" | ||
"github.com/mittwald/goharbor-client/v3/apiv2/internal/legacyapi/client" | ||
"github.com/mittwald/goharbor-client/v3/apiv2/project" | ||
integrationtest "github.com/mittwald/goharbor-client/v3/apiv2/testing" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
var ( | ||
u, _ = url.Parse(integrationtest.Host) | ||
legacySwaggerClient = client.New(runtimeclient.New(u.Host, u.Path, []string{u.Scheme}), strfmt.Default) | ||
v2SwaggerClient = v2client.New(runtimeclient.New(u.Host, u.Path, []string{u.Scheme}), strfmt.Default) | ||
authInfo = runtimeclient.BasicAuth(integrationtest.User, integrationtest.Password) | ||
storageLimitPositive int64 = 1 | ||
storageLimitNegative int64 = -1 | ||
testProjectName = "test-project" | ||
) | ||
|
||
func TestAPIGetQuotaByProjectID_PositiveQuota(t *testing.T) { | ||
ctx := context.Background() | ||
c := NewClient(legacySwaggerClient, v2SwaggerClient, authInfo) | ||
|
||
pc := project.NewClient(legacySwaggerClient, v2SwaggerClient, authInfo) | ||
p, err := pc.NewProject(ctx, testProjectName, &storageLimitPositive) | ||
defer pc.DeleteProject(ctx, p) | ||
|
||
project, err := pc.GetProjectByName(ctx, testProjectName) | ||
require.NoError(t, err) | ||
|
||
q, err := c.GetQuotaByProjectID(ctx, int64(project.ProjectID)) | ||
require.NoError(t, err) | ||
require.NotNil(t, q) | ||
|
||
require.Equal(t, q.Hard["storage"], storageLimitPositive) | ||
} | ||
|
||
func TestAPIGetQuotaByProjectID_NegativeQuota(t *testing.T) { | ||
ctx := context.Background() | ||
c := NewClient(legacySwaggerClient, v2SwaggerClient, authInfo) | ||
|
||
pc := project.NewClient(legacySwaggerClient, v2SwaggerClient, authInfo) | ||
p, err := pc.NewProject(ctx, testProjectName, &storageLimitNegative) | ||
defer pc.DeleteProject(ctx, p) | ||
|
||
project, err := pc.GetProjectByName(ctx, testProjectName) | ||
require.NoError(t, err) | ||
|
||
q, err := c.GetQuotaByProjectID(ctx, int64(project.ProjectID)) | ||
require.NoError(t, err) | ||
require.NotNil(t, q) | ||
require.Equal(t, q.Hard["storage"], storageLimitNegative) | ||
} |
Oops, something went wrong.