Skip to content
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

Add Kopia s3 and s3 compliant storage flags #2659

Merged
merged 87 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
680e782
Add safecli dependency
plar Feb 3, 2024
72011e7
add new flag implementations based on the safecli package for the Kop…
plar Feb 3, 2024
0f635ad
apply go fmt
plar Feb 4, 2024
d0a6dd1
Add common Kopia args and flags
plar Feb 6, 2024
ca853c1
Add Kopia storage core flags
plar Feb 6, 2024
2d44961
Add kopia filesystem storage flags
plar Feb 6, 2024
8f363ed
cleanup storage tests
plar Feb 6, 2024
0eb826a
Add kopia GCS storage flags
plar Feb 6, 2024
1326624
add gcs flag tests
plar Feb 6, 2024
c3ba3eb
Add kopia azure storage flags
plar Feb 6, 2024
0c7c121
Add kopia s3 and s3 compliant storage flags
plar Feb 6, 2024
9850f4a
Fix Apply and test.Suit
plar Feb 12, 2024
246e1c1
Remove variadic args for Common and Cache flags
plar Feb 12, 2024
419652c
Merge branch 'kopia-cli-core-infra' into kopia-cli-common-flags
plar Feb 12, 2024
24707e5
pkg/kopia/cli/internal/flag is implemented in the safecli@v0.0.4 now
plar Feb 17, 2024
c029fc1
Merge branch 'master' into kopia-cli-core-infra
plar Feb 17, 2024
cff7220
Re-implement Kopia common args and opts; Sync with the master
plar Feb 17, 2024
550d124
Add pkg/kopia/cli package
plar Feb 17, 2024
fc918a0
go mod tidy
plar Feb 17, 2024
9530c91
Merge branch 'kopia-cli-core-infra' into kopia-cli-common-flags
plar Feb 17, 2024
75fb036
Merge branch 'kopia-cli-common-flags' into kopia-cli-storage-core-flags
plar Feb 17, 2024
9fdf94b
Add Kopia storage helpers
plar Feb 17, 2024
6e7963a
Merge branch 'kopia-cli-storage-core-flags' into kopia-cli-storage-fs…
plar Feb 17, 2024
57adfc2
Implement Kopia storage Filesystem opts
plar Feb 17, 2024
18d8dd6
Add (c) headers
plar Feb 17, 2024
e1bf966
Remove unused error
plar Feb 17, 2024
e51868b
Reorganize imports
plar Feb 17, 2024
4037b32
Sync with kopia-cli-storage-fs-flags
plar Feb 17, 2024
ff01936
Add Kopia GCS storage opts
plar Feb 17, 2024
c3cd83c
Reorganize imports
plar Feb 17, 2024
dad30a1
Sync with kopia-cli-storage-gcs-flags
plar Feb 17, 2024
78c7092
Add Kopia Azure storage opts
plar Feb 17, 2024
b2f956a
Fix gcs test
plar Feb 17, 2024
b77c3d4
Merge branch 'kopia-cli-storage-gcs-flags' into kopia-cli-storage-azu…
plar Feb 17, 2024
3f1218a
Sync with kopia-cli-storage-azure-flags
plar Feb 17, 2024
b755966
Add Kopia S3 and S3 compliant storage opts
plar Feb 17, 2024
0764e28
Add Kopia S3 and S3 compliant storage opts
plar Feb 17, 2024
0360761
Cleanup tests
plar Feb 17, 2024
2c6cb6e
Convert common flags from vars to funcs
plar Feb 26, 2024
1a3ee2d
Add safecli dependency
plar Feb 3, 2024
386e7e9
add new flag implementations based on the safecli package for the Kop…
plar Feb 3, 2024
b815f63
apply go fmt
plar Feb 4, 2024
bcafabb
Fix Apply and test.Suit
plar Feb 12, 2024
6d61bb4
pkg/kopia/cli/internal/flag is implemented in the safecli@v0.0.4 now
plar Feb 17, 2024
e6ddb8f
Add pkg/kopia/cli package
plar Feb 17, 2024
4e7ffd7
go mod tidy
plar Feb 17, 2024
f16aea7
Update safecli to v0.0.5
plar Feb 27, 2024
dcd6425
Update safecli to v0.0.6
plar Feb 28, 2024
d3dfb31
Sync with upstream
plar Feb 28, 2024
d2ac987
Merge branch 'kopia-cli-common-flags' into kopia-cli-storage-core-flags
plar Feb 28, 2024
dfa748c
Merge branch 'kopia-cli-storage-core-flags' into kopia-cli-storage-fs…
plar Feb 28, 2024
e358e9b
Merge branch 'kopia-cli-storage-fs-flags' into kopia-cli-storage-gcs-…
plar Feb 28, 2024
4b781e8
Merge branch 'kopia-cli-storage-gcs-flags' into kopia-cli-storage-azu…
plar Feb 28, 2024
c60ce72
Merge branch 'kopia-cli-storage-azure-flags' into kopia-cli-storage-s…
plar Feb 28, 2024
b093421
Fix tests
plar Feb 28, 2024
6e71143
Merge branch 'kopia-cli-common-flags' into kopia-cli-storage-core-flags
plar Feb 28, 2024
de3a52b
Add Location.IsPointInTypeSupported
plar Feb 28, 2024
722b279
Add tests for Location.IsPointInTypeSupported
plar Feb 28, 2024
71a5aa5
Merge branch 'kopia-cli-storage-core-flags' into kopia-cli-storage-fs…
plar Feb 28, 2024
e0a37df
Merge branch 'kopia-cli-storage-fs-flags' into kopia-cli-storage-gcs-…
plar Feb 28, 2024
174a2b7
Merge branch 'kopia-cli-storage-gcs-flags' into kopia-cli-storage-azu…
plar Feb 28, 2024
e3c97f1
Merge branch 'kopia-cli-storage-azure-flags' into kopia-cli-storage-s…
plar Feb 28, 2024
db06c40
Fix s3 options
plar Feb 28, 2024
0962e3b
Fix s3 options
plar Feb 28, 2024
a005389
Fix options to return errors for empty args
plar Feb 29, 2024
7cabf8a
Fix options to return errors for empty args
plar Feb 29, 2024
c2bf064
Merge branch 'kopia-cli-storage-gcs-flags' into kopia-cli-storage-azu…
plar Feb 29, 2024
8e1c1f7
Fix options to return errors for empty args
plar Feb 29, 2024
ebcc539
Merge branch 'kopia-cli-storage-azure-flags' into kopia-cli-storage-s…
plar Feb 29, 2024
9500b32
Support empty prefix
plar Feb 29, 2024
4630719
Merge branch 'kopia-cli-storage-gcs-flags' into kopia-cli-storage-azu…
plar Feb 29, 2024
7772096
Support empty prefix
plar Feb 29, 2024
a4ddad6
Support empty prefix
plar Feb 29, 2024
de5741b
Merge branch 'kopia-cli-storage-gcs-flags' into kopia-cli-storage-azu…
plar Feb 29, 2024
abdc53e
Merge branch 'kopia-cli-storage-azure-flags' into kopia-cli-storage-s…
plar Feb 29, 2024
37e1dc7
Support empty prefix
plar Feb 29, 2024
44c133e
Fix formatting
plar Feb 29, 2024
1897a1e
Merge branch 'kopia-cli-core-infra' into kopia-cli-common-flags
plar Feb 29, 2024
33b1342
organize imports
plar Feb 29, 2024
83292af
Merge branch 'kopia-cli-common-flags' into kopia-cli-storage-core-flags
plar Feb 29, 2024
516a14c
organize imports
plar Feb 29, 2024
9d7d01d
Merge branch 'kopia-cli-storage-core-flags' into kopia-cli-storage-fs…
plar Feb 29, 2024
6fa6960
Merge branch 'kopia-cli-storage-fs-flags' into kopia-cli-storage-gcs-…
plar Feb 29, 2024
78c04af
Merge branch 'kopia-cli-storage-gcs-flags' into kopia-cli-storage-azu…
plar Feb 29, 2024
26178ea
Merge branch 'kopia-cli-storage-azure-flags' into kopia-cli-storage-s…
plar Feb 29, 2024
da5058d
Fix s3 tests
plar Mar 1, 2024
892c61a
Merge branch 'master' into kopia-cli-storage-s3-flags
plar Mar 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions pkg/kopia/cli/internal/log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package storage
import (
"context"
"io"
"regexp"

"github.com/kanisterio/kanister/pkg/field"
"github.com/kanisterio/kanister/pkg/log"
Expand All @@ -43,3 +44,31 @@ func (NopLogger) WithContext(ctx context.Context) log.Logger {
func (NopLogger) WithError(err error) log.Logger {
return &NopLogger{}
}

// StringLogger is a logger that stores log messages in a slice of strings.
type StringLogger []string

func (l *StringLogger) Print(msg string, fields ...field.M) {
*l = append(*l, msg)
}

func (l *StringLogger) PrintTo(w io.Writer, msg string, fields ...field.M) {
*l = append(*l, msg)
}

func (l *StringLogger) WithContext(ctx context.Context) log.Logger {
return l
}

func (l *StringLogger) WithError(err error) log.Logger {
return l
}

func (l *StringLogger) MatchString(pattern string) bool {
for _, line := range *l {
if found, _ := regexp.MatchString(pattern, line); found {
return true
}
}
return false
}
kale-amruta marked this conversation as resolved.
Show resolved Hide resolved
81 changes: 81 additions & 0 deletions pkg/kopia/cli/internal/test/arg_suit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// 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 test

import (
"github.com/kanisterio/safecli/test"
"gopkg.in/check.v1"

intlog "github.com/kanisterio/kanister/pkg/kopia/cli/internal/log"
"github.com/kanisterio/kanister/pkg/log"
)

// ArgumentTest extends test.ArgumentTest to include logger tests.
type ArgumentTest struct {
test.ArgumentTest

Logger log.Logger // Logger is the logger to use for the test. (optional)
LoggerRegex []string // LoggerRegex is a list of regexs to match against the log output. (optional)
}

// Test runs the test with the given command and checks the log output.
func (t *ArgumentTest) Test(c *check.C, cmd string) {
t.ArgumentTest.Test(c, cmd)
t.assertLog(c)
}

// assertLog checks the log output against the expected regexs.
func (t *ArgumentTest) assertLog(c *check.C) {
if t.Logger == nil {
if len(t.LoggerRegex) > 0 {
c.Fatalf("t.Logger is nil but t.LoggerRegex is %#v", t.LoggerRegex)
}
return
}

log, ok := t.Logger.(*intlog.StringLogger)
if !ok {
c.Fatalf("t.Logger is not *intlog.StringLogger")
}
if t.isEmptyLogExpected() {
cmtLog := check.Commentf("FAIL: log should be empty but got %#v", log)
c.Assert(len([]string(*log)), check.Equals, 0, cmtLog)
return
}

// Check each regex.
for _, regex := range t.LoggerRegex {
cmtLog := check.Commentf("FAIL: %v\nlog %#v expected to match %#v", t.ArgumentTest.Name, log, regex)
c.Assert(log.MatchString(regex), check.Equals, true, cmtLog)
}
}

// isEmptyLogExpected returns true if the test expects an empty log.
func (t *ArgumentTest) isEmptyLogExpected() bool {
return len(t.LoggerRegex) == 1 && t.LoggerRegex[0] == ""
}

// ArgumentSuite defines a suite of tests for a single ArgumentTest.
type ArgumentSuite struct {
Cmd string // Cmd appends to the safecli.Builder before test if not empty.
Arguments []ArgumentTest // Tests to run.
}

// TestArguments runs all tests in the suite.
func (s *ArgumentSuite) TestArguments(c *check.C) {
for _, arg := range s.Arguments {
arg.Test(c, s.Cmd)
}
}
63 changes: 63 additions & 0 deletions pkg/kopia/cli/repository/storage/s3/s3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// 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 s3

import (
"strings"

"github.com/kanisterio/safecli/command"

"github.com/kanisterio/kanister/pkg/kopia/cli/internal"
intlog "github.com/kanisterio/kanister/pkg/kopia/cli/internal/log"
"github.com/kanisterio/kanister/pkg/log"
)

// New creates a new subcommand for the S3 storage.
func New(location internal.Location, repoPathPrefix string, logger log.Logger) command.Applier {
if logger == nil {
logger = intlog.NopLogger{}
}
endpoint := resolveS3Endpoint(location.Endpoint(), logger)
prefix := internal.GenerateFullRepoPath(location.Prefix(), repoPathPrefix)
return command.NewArguments(subcmdS3,
optRegion(location.Region()),
optBucket(location.BucketName()),
optEndpoint(endpoint),
optPrefix(prefix),
optDisableTLS(location.IsInsecureEndpoint()),
optDisableTLSVerify(location.HasSkipSSLVerify()),
)
}

// resolveS3Endpoint removes the trailing slash and
// protocol from provided endpoint and
// returns the absolute endpoint string.
func resolveS3Endpoint(endpoint string, logger log.Logger) string {
if endpoint == "" {
return ""
}

if strings.HasSuffix(endpoint, "/") {
logger.Print("Removing trailing slashes from the endpoint")
endpoint = strings.TrimRight(endpoint, "/")
}

sp := strings.SplitN(endpoint, "://", 2)
if len(sp) > 1 {
logger.Print("Removing leading protocol from the endpoint")
}

return sp[len(sp)-1]
}
68 changes: 68 additions & 0 deletions pkg/kopia/cli/repository/storage/s3/s3_opts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// 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 s3

import (
"github.com/kanisterio/safecli/command"

"github.com/kanisterio/kanister/pkg/kopia/cli"
)

var (
subcmdS3 = command.NewArgument("s3")
)

// optBucket creates a new bucket option with a given name.
// If the name is empty, it returns ErrInvalidBucketName.
func optBucket(name string) command.Applier {
if name == "" {
return command.NewErrorArgument(cli.ErrInvalidBucketName)
}
return command.NewOptionWithArgument("--bucket", name)
}

// optEndpoint creates a new endpoint option with a given endpoint.
// If the endpoint is empty, the endpoint option is not set.
func optEndpoint(endpoint string) command.Applier {
if endpoint == "" {
return command.NewNoopArgument()
}
return command.NewOptionWithArgument("--endpoint", endpoint)
}

// optPrefix creates a new prefix option with a given prefix.
// If the prefix is empty, the prefix option is not set.
func optPrefix(prefix string) command.Applier {
return command.NewOptionWithArgument("--prefix", prefix)
kale-amruta marked this conversation as resolved.
Show resolved Hide resolved
}

// optRegion creates a new region option with a given region.
// If the region is empty, the region option is not set.
func optRegion(region string) command.Applier {
if region == "" {
return command.NewNoopArgument()
}
return command.NewOptionWithArgument("--region", region)
}

// optDisableTLS creates a new disable TLS option with a given value.
func optDisableTLS(disable bool) command.Applier {
return command.NewOption("--disable-tls", disable)
}

// optDisableTLSVerify creates a new disable TLS verification option with a given value.
func optDisableTLSVerify(disable bool) command.Applier {
return command.NewOption("--disable-tls-verification", disable)
}
65 changes: 65 additions & 0 deletions pkg/kopia/cli/repository/storage/s3/s3_opts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// 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 s3

import (
"testing"

"github.com/kanisterio/safecli/command"
"github.com/kanisterio/safecli/test"
"gopkg.in/check.v1"

"github.com/kanisterio/kanister/pkg/kopia/cli"
)

func TestS3Options(t *testing.T) { check.TestingT(t) }

var _ = check.Suite(&test.ArgumentSuite{Cmd: "cmd", Arguments: []test.ArgumentTest{
{
Name: "optRegion",
Argument: command.NewArguments(optRegion("region"), optRegion("")),
ExpectedCLI: []string{"cmd", "--region=region"},
},
{
Name: "optBucket with bucketname should return option",
Argument: optBucket("bucketname"),
ExpectedCLI: []string{"cmd", "--bucket=bucketname"},
},
{
Name: "optBucket with empty bucketname should return error",
Argument: optBucket(""),
ExpectedErr: cli.ErrInvalidBucketName,
},
{
Name: "optEndpoint",
Argument: command.NewArguments(optEndpoint("endpoint"), optEndpoint("")),
ExpectedCLI: []string{"cmd", "--endpoint=endpoint"},
},
{
Name: "optPrefix",
Argument: command.NewArguments(optPrefix("prefix"), optPrefix("")),
ExpectedCLI: []string{"cmd", "--prefix=prefix", "--prefix="},
},
{
Name: "optDisableTLS",
Argument: command.NewArguments(optDisableTLS(true), optDisableTLS(false)),
ExpectedCLI: []string{"cmd", "--disable-tls"},
},
{
Name: "optDisableTLSVerify",
Argument: command.NewArguments(optDisableTLSVerify(true), optDisableTLSVerify(false)),
ExpectedCLI: []string{"cmd", "--disable-tls-verification"},
},
kale-amruta marked this conversation as resolved.
Show resolved Hide resolved
}})
Loading