From dfca3a527077c79f18f43e5e9e7a3ebc7a73e54e Mon Sep 17 00:00:00 2001 From: Pavel Larkin Date: Tue, 5 Mar 2024 13:33:14 -0800 Subject: [PATCH] Add Kopia Azure storage opts (#2658) * Add safecli dependency * add new flag implementations based on the safecli package for the Kopia CLI * apply go fmt Signed-off-by: pavel.larkin * Add common Kopia args and flags * Add Kopia storage core flags * Add kopia filesystem storage flags * cleanup storage tests * Add kopia GCS storage flags * add gcs flag tests * Add kopia azure storage flags * Fix Apply and test.Suit Signed-off-by: pavel.larkin * Remove variadic args for Common and Cache flags Signed-off-by: pavel.larkin * pkg/kopia/cli/internal/flag is implemented in the safecli@v0.0.4 now Signed-off-by: pavel.larkin * Add pkg/kopia/cli package Signed-off-by: pavel.larkin * go mod tidy Signed-off-by: pavel.larkin * Add Kopia storage helpers Signed-off-by: pavel.larkin * Implement Kopia storage Filesystem opts Signed-off-by: pavel.larkin * Add (c) headers Signed-off-by: pavel.larkin * Remove unused error Signed-off-by: pavel.larkin * Reorganize imports Signed-off-by: pavel.larkin * Add Kopia GCS storage opts Signed-off-by: pavel.larkin * Reorganize imports Signed-off-by: pavel.larkin * Add Kopia Azure storage opts Signed-off-by: pavel.larkin * Fix gcs test Signed-off-by: pavel.larkin * Convert common flags from vars to funcs Signed-off-by: pavel.larkin * Add safecli dependency * add new flag implementations based on the safecli package for the Kopia CLI * apply go fmt Signed-off-by: pavel.larkin * Fix Apply and test.Suit Signed-off-by: pavel.larkin * pkg/kopia/cli/internal/flag is implemented in the safecli@v0.0.4 now Signed-off-by: pavel.larkin * Add pkg/kopia/cli package Signed-off-by: pavel.larkin * go mod tidy Signed-off-by: pavel.larkin * Update safecli to v0.0.5 Signed-off-by: pavel.larkin * Update safecli to v0.0.6 Signed-off-by: pavel.larkin * Fix tests Signed-off-by: pavel.larkin * Add Location.IsPointInTypeSupported Signed-off-by: pavel.larkin * Add tests for Location.IsPointInTypeSupported Signed-off-by: pavel.larkin * Fix options to return errors for empty args Signed-off-by: pavel.larkin * Fix options to return errors for empty args Signed-off-by: pavel.larkin * Fix options to return errors for empty args Signed-off-by: pavel.larkin * Support empty prefix Signed-off-by: pavel.larkin * Support empty prefix Signed-off-by: pavel.larkin * Support empty prefix Signed-off-by: pavel.larkin * Fix formatting Signed-off-by: pavel.larkin * organize imports Signed-off-by: pavel.larkin * organize imports Signed-off-by: pavel.larkin --------- Signed-off-by: pavel.larkin --- pkg/kopia/cli/errors.go | 2 + .../cli/repository/storage/azure/azure.go | 31 ++++++++++ .../repository/storage/azure/azure_opts.go | 39 ++++++++++++ .../storage/azure/azure_opts_test.go | 45 ++++++++++++++ .../repository/storage/azure/azure_test.go | 59 +++++++++++++++++++ 5 files changed, 176 insertions(+) create mode 100644 pkg/kopia/cli/repository/storage/azure/azure.go create mode 100644 pkg/kopia/cli/repository/storage/azure/azure_opts.go create mode 100644 pkg/kopia/cli/repository/storage/azure/azure_opts_test.go create mode 100644 pkg/kopia/cli/repository/storage/azure/azure_test.go diff --git a/pkg/kopia/cli/errors.go b/pkg/kopia/cli/errors.go index b6eea2f9ab..483302b57f 100644 --- a/pkg/kopia/cli/errors.go +++ b/pkg/kopia/cli/errors.go @@ -36,4 +36,6 @@ var ( ErrInvalidBucketName = errors.New("bucket name cannot be empty") // ErrInvalidCredentialsFile is returned when the credentials file is empty. ErrInvalidCredentialsFile = errors.New("credentials file cannot be empty") + // ErrInvalidContainerName is returned when the containerName is empty. + ErrInvalidContainerName = errors.New("container name cannot be empty") ) diff --git a/pkg/kopia/cli/repository/storage/azure/azure.go b/pkg/kopia/cli/repository/storage/azure/azure.go new file mode 100644 index 0000000000..5929ff4e27 --- /dev/null +++ b/pkg/kopia/cli/repository/storage/azure/azure.go @@ -0,0 +1,31 @@ +// Copyright 2024 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 azure + +import ( + "github.com/kanisterio/safecli/command" + + "github.com/kanisterio/kanister/pkg/kopia/cli/internal" + "github.com/kanisterio/kanister/pkg/log" +) + +// New creates a new subcommand for the Azure storage. +func New(location internal.Location, repoPathPrefix string, _ log.Logger) command.Applier { + prefix := internal.GenerateFullRepoPath(location.Prefix(), repoPathPrefix) + return command.NewArguments(subcmdAzure, + optContainer(location.BucketName()), + optPrefix(prefix), + ) +} diff --git a/pkg/kopia/cli/repository/storage/azure/azure_opts.go b/pkg/kopia/cli/repository/storage/azure/azure_opts.go new file mode 100644 index 0000000000..1433388c09 --- /dev/null +++ b/pkg/kopia/cli/repository/storage/azure/azure_opts.go @@ -0,0 +1,39 @@ +// Copyright 2024 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 azure + +import ( + "github.com/kanisterio/safecli/command" + + "github.com/kanisterio/kanister/pkg/kopia/cli" +) + +var ( + subcmdAzure = command.NewArgument("azure") +) + +// optPrefix creates a new prefix option with a given prefix. +func optPrefix(prefix string) command.Applier { + return command.NewOptionWithArgument("--prefix", prefix) +} + +// optContainer creates a new container option with a given container name. +// If the name is empty, it returns ErrInvalidContainerName. +func optContainer(name string) command.Applier { + if name == "" { + return command.NewErrorArgument(cli.ErrInvalidContainerName) + } + return command.NewOptionWithArgument("--container", name) +} diff --git a/pkg/kopia/cli/repository/storage/azure/azure_opts_test.go b/pkg/kopia/cli/repository/storage/azure/azure_opts_test.go new file mode 100644 index 0000000000..bc46a8b7a0 --- /dev/null +++ b/pkg/kopia/cli/repository/storage/azure/azure_opts_test.go @@ -0,0 +1,45 @@ +// Copyright 2024 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 azure + +import ( + "testing" + + "github.com/kanisterio/safecli/command" + "github.com/kanisterio/safecli/test" + "gopkg.in/check.v1" + + "github.com/kanisterio/kanister/pkg/kopia/cli" +) + +func TestAzureOptions(t *testing.T) { check.TestingT(t) } + +var _ = check.Suite(&test.ArgumentSuite{Cmd: "cmd", Arguments: []test.ArgumentTest{ + { + Name: "optContainer", + Argument: optContainer("containername"), + ExpectedCLI: []string{"cmd", "--container=containername"}, + }, + { + Name: "optContainer with empty containername should return error", + Argument: optContainer(""), + ExpectedErr: cli.ErrInvalidContainerName, + }, + { + Name: "optPrefix", + Argument: command.NewArguments(optPrefix("prefix"), optPrefix("")), + ExpectedCLI: []string{"cmd", "--prefix=prefix", "--prefix="}, + }, +}}) diff --git a/pkg/kopia/cli/repository/storage/azure/azure_test.go b/pkg/kopia/cli/repository/storage/azure/azure_test.go new file mode 100644 index 0000000000..6f426edf46 --- /dev/null +++ b/pkg/kopia/cli/repository/storage/azure/azure_test.go @@ -0,0 +1,59 @@ +// Copyright 2024 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 azure + +import ( + "testing" + + "github.com/kanisterio/safecli/command" + "github.com/kanisterio/safecli/test" + "gopkg.in/check.v1" + + "github.com/kanisterio/kanister/pkg/kopia/cli" + "github.com/kanisterio/kanister/pkg/kopia/cli/internal" +) + +func TestNewAzure(t *testing.T) { check.TestingT(t) } + +func newAzure(prefix, repoPath, bucket string) command.Applier { + l := internal.Location{ + "prefix": []byte(prefix), + "bucket": []byte(bucket), + } + return New(l, repoPath, nil) +} + +var _ = check.Suite(&test.ArgumentSuite{Cmd: "cmd", Arguments: []test.ArgumentTest{ + { + Name: "NewAzure", + Argument: newAzure("prefix", "repoPath", "bucket"), + ExpectedCLI: []string{"cmd", "azure", "--container=bucket", "--prefix=prefix/repoPath/"}, + }, + { + Name: "NewAzure with empty repoPath", + Argument: newAzure("prefix", "", "bucket"), + ExpectedCLI: []string{"cmd", "azure", "--container=bucket", "--prefix=prefix/"}, + }, + { + Name: "NewAzure with empty local prefix and repo prefix should return error", + Argument: newAzure("", "", "bucket"), + ExpectedCLI: []string{"cmd", "azure", "--container=bucket", "--prefix="}, + }, + { + Name: "NewAzure with empty bucket should return ErrInvalidContainerName", + Argument: newAzure("", "", ""), + ExpectedErr: cli.ErrInvalidContainerName, + }, +}})