Skip to content

Commit

Permalink
Add Type S3Compliant to Kopia Repository Storage Args (#2159)
Browse files Browse the repository at this point in the history
* Add S3Compliant to Storage Args

Signed-off-by: Rajat Gupta <rajat.gupta@veeam.com>

* Add Test for s3Compliant storage args

Signed-off-by: Rajat Gupta <rajat.gupta@veeam.com>

* Add Validation for s3Compliant Location

Signed-off-by: Rajat Gupta <rajat.gupta@veeam.com>

* Format Imports

Signed-off-by: Rajat Gupta <rajat.gupta@veeam.com>

* Add Bucket Validation

Signed-off-by: Rajat Gupta <rajat.gupta@veeam.com>

* Add Tests for S3 Compliant Secrets Validation

Signed-off-by: Rajat Gupta <rajat.gupta@veeam.com>

---------

Signed-off-by: Rajat Gupta <rajat.gupta@veeam.com>
  • Loading branch information
r4rajat committed Jul 7, 2023
1 parent 9d38168 commit e1bcb16
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 4 deletions.
2 changes: 2 additions & 0 deletions pkg/kopia/command/storage/storage_args.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ func KopiaStorageArgs(params *StorageCommandParams) (logsafe.Cmd, error) {
return filesystemArgs(params.Location, params.RepoPathPrefix), nil
case repositoryserver.LocTypeS3:
return s3Args(params.Location, params.RepoPathPrefix), nil
case repositoryserver.LocTypes3Compliant:
return s3Args(params.Location, params.RepoPathPrefix), nil
case repositoryserver.LocTypeGCS:
return gcsArgs(params.Location, params.RepoPathPrefix), nil
case repositoryserver.LocTypeAzure:
Expand Down
21 changes: 21 additions & 0 deletions pkg/kopia/command/storage/storage_args_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,27 @@ func (s *StorageUtilsSuite) TestStorageArgsUtil(c *check.C) {
fmt.Sprintf(" %s=test-region", s3RegionFlag),
),
},
{
params: &StorageCommandParams{
Location: map[string][]byte{
repositoryserver.BucketKey: []byte("test-bucket"),
repositoryserver.EndpointKey: []byte("test-endpoint"),
repositoryserver.PrefixKey: []byte("test-prefix"),
repositoryserver.RegionKey: []byte("test-region"),
repositoryserver.SkipSSLVerifyKey: []byte("true"),
repositoryserver.TypeKey: []byte("s3Compliant"),
},
RepoPathPrefix: "dir/subdir/",
},
Checker: check.IsNil,
expectedCmd: fmt.Sprint(
s3SubCommand,
fmt.Sprintf(" %s=test-bucket", bucketFlag),
fmt.Sprintf(" %s=test-endpoint", s3EndpointFlag),
fmt.Sprintf(" %s=test-prefix/dir/subdir/ %s", prefixFlag, s3DisableTLSVerifyFlag),
fmt.Sprintf(" %s=test-region", s3RegionFlag),
),
},
{
params: &StorageCommandParams{
Location: map[string][]byte{
Expand Down
9 changes: 5 additions & 4 deletions pkg/secrets/repositoryserver/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ import (
type LocType string

const (
LocTypeS3 LocType = "s3"
LocTypeGCS LocType = "gcs"
LocTypeAzure LocType = "azure"
LocTypeFilestore LocType = "filestore"
LocTypeS3 LocType = "s3"
LocTypes3Compliant LocType = "s3Compliant"
LocTypeGCS LocType = "gcs"
LocTypeAzure LocType = "azure"
LocTypeFilestore LocType = "filestore"

// Location represents the storage location secret type for kopia repository server
Location corev1.SecretType = "secrets.kanister.io/storage-location"
Expand Down
53 changes: 53 additions & 0 deletions pkg/secrets/repositoryserver/s3compliant_secrets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2023 The Kanister 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 repositoryserver

import (
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"

secerrors "github.com/kanisterio/kanister/pkg/secrets/errors"
)

type s3Compliant struct {
storageLocation *corev1.Secret
}

func NewS3CompliantLocation(secret *corev1.Secret) *s3Compliant {
return &s3Compliant{
storageLocation: secret,
}
}

var _ Secret = &s3Compliant{}

func (s s3Compliant) Validate() error {
if s.storageLocation == nil {
return errors.Wrapf(secerrors.ErrValidate, secerrors.NilSecretErrorMessage)
}
if len(s.storageLocation.Data) == 0 {
return errors.Wrapf(secerrors.ErrValidate, secerrors.EmptySecretErrorMessage, s.storageLocation.Namespace, s.storageLocation.Name)
}
if _, ok := s.storageLocation.Data[BucketKey]; !ok {
return errors.Wrapf(secerrors.ErrValidate, secerrors.MissingRequiredFieldErrorMsg, BucketKey, s.storageLocation.Namespace, s.storageLocation.Name)
}
if _, ok := s.storageLocation.Data[EndpointKey]; !ok {
return errors.Wrapf(secerrors.ErrValidate, secerrors.MissingRequiredFieldErrorMsg, EndpointKey, s.storageLocation.Namespace, s.storageLocation.Name)
}
if _, ok := s.storageLocation.Data[RegionKey]; !ok {
return errors.Wrapf(secerrors.ErrValidate, secerrors.MissingRequiredFieldErrorMsg, RegionKey, s.storageLocation.Namespace, s.storageLocation.Name)
}
return nil
}
119 changes: 119 additions & 0 deletions pkg/secrets/repositoryserver/s3compliant_secrets_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// Copyright 2023 The Kanister 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 repositoryserver

import (
"github.com/pkg/errors"
. "gopkg.in/check.v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

secerrors "github.com/kanisterio/kanister/pkg/secrets/errors"
)

type S3CompliantSecretTestSuite struct{}

var _ = Suite(&S3CompliantSecretTestSuite{})

func (s *S3CompliantSecretTestSuite) TestValidateRepoServerS3CompliantCredentials(c *C) {
for i, tc := range []struct {
secret Secret
errChecker Checker
expectedError error
}{
{ // Valid S3 Compatible Secret
secret: NewS3CompliantLocation(&v1.Secret{
Type: v1.SecretType(LocTypes3Compliant),
ObjectMeta: metav1.ObjectMeta{
Name: "sec",
Namespace: "ns",
},
Data: map[string][]byte{
BucketKey: []byte("bucket"),
RegionKey: []byte("region"),
EndpointKey: []byte("endpoint"),
},
}),
errChecker: IsNil,
},
{ // Missing required field - Bucket Key
secret: NewS3CompliantLocation(&v1.Secret{
Type: v1.SecretType(LocTypes3Compliant),
ObjectMeta: metav1.ObjectMeta{
Name: "sec",
Namespace: "ns",
},
Data: map[string][]byte{
RegionKey: []byte("region"),
EndpointKey: []byte("endpoint"),
},
}),
errChecker: NotNil,
expectedError: errors.Wrapf(secerrors.ErrValidate, secerrors.MissingRequiredFieldErrorMsg, BucketKey, "ns", "sec"),
},
{ // Missing required field - Region Key
secret: NewS3CompliantLocation(&v1.Secret{
Type: v1.SecretType(LocTypes3Compliant),
ObjectMeta: metav1.ObjectMeta{
Name: "sec",
Namespace: "ns",
},
Data: map[string][]byte{
BucketKey: []byte("bucket"),
EndpointKey: []byte("endpoint"),
},
}),
errChecker: NotNil,
expectedError: errors.Wrapf(secerrors.ErrValidate, secerrors.MissingRequiredFieldErrorMsg, RegionKey, "ns", "sec"),
},
{ // Missing required field - Endpoint Key
secret: NewS3CompliantLocation(&v1.Secret{
Type: v1.SecretType(LocTypes3Compliant),
ObjectMeta: metav1.ObjectMeta{
Name: "sec",
Namespace: "ns",
},
Data: map[string][]byte{
RegionKey: []byte("region"),
BucketKey: []byte("bucket"),
},
}),
errChecker: NotNil,
expectedError: errors.Wrapf(secerrors.ErrValidate, secerrors.MissingRequiredFieldErrorMsg, EndpointKey, "ns", "sec"),
},
{ // Empty Secret
secret: NewS3CompliantLocation(&v1.Secret{
Type: v1.SecretType(LocTypes3Compliant),
ObjectMeta: metav1.ObjectMeta{
Name: "sec",
Namespace: "ns",
},
}),
errChecker: NotNil,
expectedError: errors.Wrapf(secerrors.ErrValidate, secerrors.EmptySecretErrorMessage, "ns", "sec"),
},
{ // Nil Secret
secret: NewS3CompliantLocation(nil),
errChecker: NotNil,
expectedError: errors.Wrapf(secerrors.ErrValidate, secerrors.NilSecretErrorMessage),
},
} {
err := tc.secret.Validate()
c.Check(err, tc.errChecker)
if err != nil {
c.Check(err.Error(), Equals, tc.expectedError.Error(), Commentf("test number: %d", i))
}
}
}
2 changes: 2 additions & 0 deletions pkg/secrets/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ func getLocationSecret(secret *corev1.Secret) (reposerver.Secret, error) {
switch reposerver.LocType(string(locationType)) {
case reposerver.LocTypeS3:
return reposerver.NewAWSLocation(secret), nil
case reposerver.LocTypes3Compliant:
return reposerver.NewS3CompliantLocation(secret), nil
case reposerver.LocTypeAzure:
return reposerver.NewAzureLocation(secret), nil
case reposerver.LocTypeGCS:
Expand Down

0 comments on commit e1bcb16

Please sign in to comment.