diff --git a/pkg/controllers/repositoryserver/repositoryserver_controller_test.go b/pkg/controllers/repositoryserver/repositoryserver_controller_test.go index 01da2a12f6..11130aa423 100644 --- a/pkg/controllers/repositoryserver/repositoryserver_controller_test.go +++ b/pkg/controllers/repositoryserver/repositoryserver_controller_test.go @@ -484,7 +484,7 @@ func (s *RepoServerControllerSuite) waitForRepoServerInfoUpdateInCR(repoServerNa } func (s *RepoServerControllerSuite) waitOnRepositoryServerState(c *C, reposerverName string) (crv1alpha1.RepositoryServerProgress, error) { - ctxTimeout := 5 * time.Minute + ctxTimeout := 10 * time.Minute ctx, cancel := context.WithTimeout(context.Background(), ctxTimeout) defer cancel() var repoServerState crv1alpha1.RepositoryServerProgress diff --git a/pkg/kopia/cli/args/ephemeral_args.go b/pkg/kopia/cli/args/ephemeral_args.go index d9195eb257..22ea95c2ae 100644 --- a/pkg/kopia/cli/args/ephemeral_args.go +++ b/pkg/kopia/cli/args/ephemeral_args.go @@ -18,6 +18,7 @@ import ( "fmt" "github.com/kanisterio/kanister/pkg/logsafe" + "github.com/kanisterio/safecli/command" ) diff --git a/pkg/kopia/cli/internal/args/args.go b/pkg/kopia/cli/internal/args/args.go index cad732dc9d..bf6606334b 100644 --- a/pkg/kopia/cli/internal/args/args.go +++ b/pkg/kopia/cli/internal/args/args.go @@ -15,9 +15,9 @@ package args import ( - "github.com/kanisterio/safecli/command" - "github.com/kanisterio/kanister/pkg/kopia/cli" + + "github.com/kanisterio/safecli/command" ) // ID creates a new ID argument. diff --git a/pkg/kopia/cli/internal/opts/cache_opts.go b/pkg/kopia/cli/internal/opts/cache_opts.go index fb1222b4af..2c3343518a 100644 --- a/pkg/kopia/cli/internal/opts/cache_opts.go +++ b/pkg/kopia/cli/internal/opts/cache_opts.go @@ -17,9 +17,9 @@ package opts import ( "strconv" - "github.com/kanisterio/safecli/command" - "github.com/kanisterio/kanister/pkg/kopia/cli/args" + + "github.com/kanisterio/safecli/command" ) const ( diff --git a/pkg/kopia/cli/repository/storage/gcs/gcs_opts.go b/pkg/kopia/cli/repository/storage/gcs/gcs_opts.go index d04c89480c..1c6f7577dd 100644 --- a/pkg/kopia/cli/repository/storage/gcs/gcs_opts.go +++ b/pkg/kopia/cli/repository/storage/gcs/gcs_opts.go @@ -15,8 +15,9 @@ package gcs import ( - "github.com/kanisterio/kanister/pkg/kopia/cli" "github.com/kanisterio/safecli/command" + + "github.com/kanisterio/kanister/pkg/kopia/cli" ) var ( diff --git a/pkg/kopia/cli/repository/storage/gcs/gcs_opts_test.go b/pkg/kopia/cli/repository/storage/gcs/gcs_opts_test.go index d45adab333..071d751a44 100644 --- a/pkg/kopia/cli/repository/storage/gcs/gcs_opts_test.go +++ b/pkg/kopia/cli/repository/storage/gcs/gcs_opts_test.go @@ -19,9 +19,10 @@ import ( "gopkg.in/check.v1" - "github.com/kanisterio/kanister/pkg/kopia/cli" "github.com/kanisterio/safecli/command" "github.com/kanisterio/safecli/test" + + "github.com/kanisterio/kanister/pkg/kopia/cli" ) func TestGCSOptions(t *testing.T) { check.TestingT(t) } diff --git a/pkg/kopia/command/parse_command_output.go b/pkg/kopia/command/parse_command_output.go index 1789d64138..8dc25a09e7 100644 --- a/pkg/kopia/command/parse_command_output.go +++ b/pkg/kopia/command/parse_command_output.go @@ -23,10 +23,11 @@ import ( "strings" "github.com/dustin/go-humanize" + + "github.com/kanisterio/errkit" "github.com/kopia/kopia/repo/manifest" "github.com/kopia/kopia/snapshot" "github.com/kopia/kopia/snapshot/policy" - "github.com/pkg/errors" "github.com/kanisterio/kanister/pkg/field" "github.com/kanisterio/kanister/pkg/log" @@ -48,7 +49,7 @@ const ( // SnapshotIDsFromSnapshot extracts root ID of a snapshot from the logs func SnapshotIDsFromSnapshot(output string) (snapID, rootID string, err error) { if output == "" { - return snapID, rootID, errors.New("Received empty output") + return snapID, rootID, errkit.New("Received empty output") } logs := regexp.MustCompile("[\r\n]").Split(output, -1) @@ -62,7 +63,7 @@ func SnapshotIDsFromSnapshot(output string) (snapID, rootID string, err error) { return snapID, rootID, nil } } - return snapID, rootID, errors.New("Failed to find Root ID from output") + return snapID, rootID, errkit.New("Failed to find Root ID from output") } // LatestSnapshotInfoFromManifestList returns snapshot ID and backup path of the latest snapshot from `manifests list` output @@ -73,7 +74,7 @@ func LatestSnapshotInfoFromManifestList(output string) (string, string, error) { err := json.Unmarshal([]byte(output), &manifestList) if err != nil { - return snapID, backupPath, errors.Wrap(err, "Failed to unmarshal manifest list") + return snapID, backupPath, errkit.Wrap(err, "Failed to unmarshal manifest list") } for _, manifest := range manifestList { for key, value := range manifest.Labels { @@ -86,10 +87,10 @@ func LatestSnapshotInfoFromManifestList(output string) (string, string, error) { } } if snapID == "" { - return "", "", errors.New("Failed to get latest snapshot ID from manifest list") + return "", "", errkit.New("Failed to get latest snapshot ID from manifest list") } if backupPath == "" { - return "", "", errors.New("Failed to get latest snapshot backup path from manifest list") + return "", "", errkit.New("Failed to get latest snapshot backup path from manifest list") } return snapID, backupPath, nil } @@ -109,15 +110,15 @@ func SnapshotInfoFromSnapshotCreateOutput(output string) (string, string, error) if snapManifest.RootEntry != nil { rootID = snapManifest.RootEntry.ObjectID.String() if snapManifest.RootEntry.DirSummary != nil && snapManifest.RootEntry.DirSummary.FatalErrorCount > 0 { - return "", "", errors.New(fmt.Sprintf("Error occurred during snapshot creation. Output %s", output)) + return "", "", errkit.New(fmt.Sprintf("Error occurred during snapshot creation. Output %s", output)) } } } if snapID == "" { - return "", "", errors.New(fmt.Sprintf("Failed to get snapshot ID from create snapshot output %s", output)) + return "", "", errkit.New(fmt.Sprintf("Failed to get snapshot ID from create snapshot output %s", output)) } if rootID == "" { - return "", "", errors.New(fmt.Sprintf("Failed to get root ID from create snapshot output %s", output)) + return "", "", errkit.New(fmt.Sprintf("Failed to get root ID from create snapshot output %s", output)) } return snapID, rootID, nil } @@ -126,12 +127,12 @@ func SnapshotInfoFromSnapshotCreateOutput(output string) (string, string, error) // is formatted as the output of a kopia snapshot list --all command. func SnapSizeStatsFromSnapListAll(output string) (totalSizeB int64, numSnapshots int, err error) { if output == "" { - return 0, 0, errors.New("Received empty output") + return 0, 0, errkit.New("Received empty output") } snapList, err := ParseSnapshotManifestList(output) if err != nil { - return 0, 0, errors.Wrap(err, "Parsing snapshot list output as snapshot manifest list") + return 0, 0, errkit.Wrap(err, "Parsing snapshot list output as snapshot manifest list") } totalSizeB = sumSnapshotSizes(snapList) @@ -163,7 +164,7 @@ func ParseSnapshotManifestList(output string) ([]*snapshot.Manifest, error) { snapInfoList := []*snapshot.Manifest{} if err := json.Unmarshal([]byte(output), &snapInfoList); err != nil { - return nil, errors.Wrap(err, "Failed to unmarshal snapshot manifest list") + return nil, errkit.Wrap(err, "Failed to unmarshal snapshot manifest list") } return snapInfoList, nil @@ -435,7 +436,7 @@ func parseKopiaRestoreProgressLine(line string) (stats *RestoreStats) { // size in bytes or an error if parsing is unsuccessful. func RepoSizeStatsFromBlobStatsRaw(blobStats string) (phySizeTotal int64, blobCount int, err error) { if blobStats == "" { - return phySizeTotal, blobCount, errors.New("received empty blob stats string") + return phySizeTotal, blobCount, errkit.New("received empty blob stats string") } sizePattern := regexp.MustCompile(repoTotalSizeFromBlobStatsRegEx) @@ -465,21 +466,21 @@ func RepoSizeStatsFromBlobStatsRaw(blobStats string) (phySizeTotal int64, blobCo } if countStr == "" { - return phySizeTotal, blobCount, errors.New("could not find count field in the blob stats") + return phySizeTotal, blobCount, errkit.New("could not find count field in the blob stats") } if sizeStr == "" { - return phySizeTotal, blobCount, errors.New("could not find size field in the blob stats") + return phySizeTotal, blobCount, errkit.New("could not find size field in the blob stats") } countVal, err := strconv.Atoi(countStr) if err != nil { - return phySizeTotal, blobCount, errors.Wrap(err, fmt.Sprintf("unable to convert parsed count value %s", countStr)) + return phySizeTotal, blobCount, errkit.Wrap(err, fmt.Sprintf("unable to convert parsed count value %s", countStr)) } sizeValBytes, err := strconv.Atoi(sizeStr) if err != nil { - return phySizeTotal, blobCount, errors.Wrap(err, fmt.Sprintf("unable to convert parsed size value %s", countStr)) + return phySizeTotal, blobCount, errkit.Wrap(err, fmt.Sprintf("unable to convert parsed size value %s", countStr)) } return int64(sizeValBytes), countVal, nil @@ -514,7 +515,7 @@ func ErrorsFromOutput(output string) []error { clean := ANSIEscapeCode.ReplaceAllString(l, "") // Strip all ANSI escape codes from line match := kopiaErrorPattern.FindAllStringSubmatch(clean, 1) if len(match) > 0 { - err = append(err, errors.New(match[0][1])) + err = append(err, errkit.New(match[0][1])) } } @@ -526,7 +527,7 @@ func ParsePolicyShow(output string) (policy.Policy, error) { policy := policy.Policy{} if err := json.Unmarshal([]byte(output), &policy); err != nil { - return policy, errors.Wrap(err, "Failed to unmarshal snapshot manifest list") + return policy, errkit.Wrap(err, "Failed to unmarshal snapshot manifest list") } return policy, nil diff --git a/pkg/kopia/command/repository.go b/pkg/kopia/command/repository.go index 20c44aeb37..22ec42d2d4 100644 --- a/pkg/kopia/command/repository.go +++ b/pkg/kopia/command/repository.go @@ -18,7 +18,7 @@ import ( "time" "github.com/go-openapi/strfmt" - "github.com/pkg/errors" + "github.com/kanisterio/errkit" "github.com/kanisterio/kanister/pkg/kopia/cli/args" "github.com/kanisterio/kanister/pkg/kopia/command/storage" @@ -68,7 +68,7 @@ func RepositoryConnectCommand(cmdArgs RepositoryCommandArgs) ([]string, error) { RepoPathPrefix: cmdArgs.RepoPathPrefix, }) if err != nil { - return nil, errors.Wrap(err, "Failed to generate storage args") + return nil, errkit.Wrap(err, "Failed to generate storage args") } if !time.Time(cmdArgs.PITFlag).IsZero() { @@ -106,7 +106,7 @@ func RepositoryCreateCommand(cmdArgs RepositoryCommandArgs) ([]string, error) { RepoPathPrefix: cmdArgs.RepoPathPrefix, }) if err != nil { - return nil, errors.Wrap(err, "Failed to generate storage args") + return nil, errkit.Wrap(err, "Failed to generate storage args") } return stringSliceCommand(command.Combine(bsArgs)), nil diff --git a/pkg/kopia/command/storage/secret_utils.go b/pkg/kopia/command/storage/secret_utils.go index 030b49e2b7..e430dab553 100644 --- a/pkg/kopia/command/storage/secret_utils.go +++ b/pkg/kopia/command/storage/secret_utils.go @@ -18,9 +18,10 @@ import ( "context" "time" - "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" + "github.com/kanisterio/errkit" + crv1alpha1 "github.com/kanisterio/kanister/pkg/apis/cr/v1alpha1" "github.com/kanisterio/kanister/pkg/aws" "github.com/kanisterio/kanister/pkg/blockstorage/azure" @@ -64,7 +65,7 @@ func locationType(m map[string][]byte) repositoryserver.LocType { // list of EnvVar based on secret type func GenerateEnvSpecFromCredentialSecret(s *corev1.Secret, assumeRoleDurationS3 time.Duration) ([]corev1.EnvVar, error) { if s == nil { - return nil, errors.New("Secret cannot be nil") + return nil, errkit.New("Secret cannot be nil") } secType := string(s.Type) switch secType { @@ -111,7 +112,7 @@ func getEnvSpecForAzureCredentialSecret(s *corev1.Secret) ([]corev1.EnvVar, erro if storageEnv != "" { env, err := azure.EnvironmentFromName(storageEnv) if err != nil { - return nil, errors.Wrapf(err, "Failed to get azure environment from name: %s", storageEnv) + return nil, errkit.Wrap(err, "Failed to get azure environment from name", "storageEnv", storageEnv) } blobDomain := "blob." + env.StorageEndpointSuffix // TODO : Check how we can set this env to use value from secret diff --git a/pkg/kopia/command/storage/storage_args.go b/pkg/kopia/command/storage/storage_args.go index c85720e393..4d0b9f3f67 100644 --- a/pkg/kopia/command/storage/storage_args.go +++ b/pkg/kopia/command/storage/storage_args.go @@ -15,7 +15,7 @@ package storage import ( - "fmt" + "github.com/kanisterio/errkit" "github.com/kanisterio/kanister/pkg/logsafe" "github.com/kanisterio/kanister/pkg/secrets/repositoryserver" @@ -47,6 +47,6 @@ func KopiaStorageArgs(params *StorageCommandParams) (logsafe.Cmd, error) { case repositoryserver.LocTypeAzure: return azureArgs(params.Location, params.RepoPathPrefix), nil default: - return nil, fmt.Errorf("unsupported type for the location: %s", LocType) + return nil, errkit.New("unsupported type for the location", "locationType", LocType) } } diff --git a/pkg/kopia/errors/utils.go b/pkg/kopia/errors/utils.go index 0cbfe47615..fbd5e0aac4 100644 --- a/pkg/kopia/errors/utils.go +++ b/pkg/kopia/errors/utils.go @@ -15,62 +15,16 @@ package errors import ( - "bytes" "regexp" "strings" - "github.com/pkg/errors" + "github.com/kanisterio/errkit" ) -type errorList []error - -var _ error = errorList{} - -func (e errorList) String() string { - sep := "" - var buf bytes.Buffer - buf.WriteRune('[') - for _, err := range e { - buf.WriteString(sep) - sep = "," - buf.WriteRune('"') - buf.WriteString(err.Error()) - buf.WriteRune('"') - } - buf.WriteRune(']') - return buf.String() -} - -func (e errorList) Error() string { - return e.String() -} - -// Append creates a new combined error from err1, err2. If either error is nil, -// then the other error is returned. -func Append(err1, err2 error) error { - if err1 == nil { - return err2 - } - if err2 == nil { - return err1 - } - el1, ok1 := err1.(errorList) - el2, ok2 := err2.(errorList) - switch { - case ok1 && ok2: - return append(el1, el2...) - case ok1: - return append(el1, err2) - case ok2: - return append(el2, err1) - } - return errorList{err1, err2} -} - // FirstMatching returns the first error that matches the predicate in a // causal dependency err->Cause()->Cause() .... func FirstMatching(err error, predicate func(error) bool) error { - for ; err != nil; err = errors.Unwrap(err) { + for ; err != nil; err = errkit.Unwrap(err) { if predicate(err) { return err } diff --git a/pkg/kopia/errors/utils_test.go b/pkg/kopia/errors/utils_test.go new file mode 100644 index 0000000000..164d3d79da --- /dev/null +++ b/pkg/kopia/errors/utils_test.go @@ -0,0 +1,49 @@ +// 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 errors + +import ( + "testing" + + "github.com/kanisterio/errkit" + "github.com/pkg/errors" + . "gopkg.in/check.v1" +) + +// Hook up gocheck into the "go test" runner. +func TestKopiaErrors(t *testing.T) { TestingT(t) } + +type KopiaErrorsTestSuite struct{} + +var _ = Suite(&KopiaErrorsTestSuite{}) + +// TestErrCheck verifies that error types are properly detected after wrapping them +func (s *KopiaErrorsTestSuite) TestErrCheck(c *C) { + origErr := errors.New("Some error") + + errWithMessage := errors.WithMessage(origErr, ErrInvalidPasswordStr) + errWrapped := errkit.Wrap(origErr, ErrInvalidPasswordStr) + + c.Assert(IsInvalidPasswordError(errWithMessage), Equals, true) + c.Assert(IsInvalidPasswordError(errWrapped), Equals, true) + c.Assert(IsRepoNotFoundError(errWrapped), Equals, false) + + permittedErrors := []ErrorType{ErrorInvalidPassword, ErrorRepoNotFound} + c.Assert(CheckKopiaErrors(errWithMessage, permittedErrors), Equals, true) + c.Assert(CheckKopiaErrors(errWrapped, permittedErrors), Equals, true) + + wrongErrors := []ErrorType{ErrorRepoNotFound} + c.Assert(CheckKopiaErrors(errWrapped, wrongErrors), Equals, false) +} diff --git a/pkg/kopia/maintenance/get_maintenance_owner.go b/pkg/kopia/maintenance/get_maintenance_owner.go index 7411d04e07..8299226c4b 100644 --- a/pkg/kopia/maintenance/get_maintenance_owner.go +++ b/pkg/kopia/maintenance/get_maintenance_owner.go @@ -18,11 +18,10 @@ import ( "bytes" "context" "encoding/json" - "fmt" + "github.com/kanisterio/errkit" kopiacli "github.com/kopia/kopia/cli" "github.com/kopia/kopia/repo/manifest" - "github.com/pkg/errors" "github.com/kanisterio/kanister/pkg/format" "github.com/kanisterio/kanister/pkg/kopia/command" @@ -76,7 +75,7 @@ func GetMaintenanceOwnerForConnectedRepository( func parseOwner(output []byte) (string, error) { maintInfo := kopiacli.MaintenanceInfo{} if err := json.Unmarshal(output, &maintInfo); err != nil { - return "", errors.New(fmt.Sprintf("failed to unmarshal maintenance info output: %v", err)) + return "", errkit.Wrap(err, "failed to unmarshal maintenance info output") } return maintInfo.Owner, nil } diff --git a/pkg/kopia/repository/client.go b/pkg/kopia/repository/client.go index 9bc478a367..49ed82e61c 100644 --- a/pkg/kopia/repository/client.go +++ b/pkg/kopia/repository/client.go @@ -22,9 +22,9 @@ import ( "time" "github.com/jpillora/backoff" + "github.com/kanisterio/errkit" "github.com/kopia/kopia/repo" "github.com/kopia/kopia/repo/content" - "github.com/pkg/errors" "github.com/kanisterio/kanister/pkg/kopia" "github.com/kanisterio/kanister/pkg/log" @@ -62,7 +62,7 @@ func ConnectToAPIServer( // Extra fingerprint from the TLS Certificate secret fingerprint, err := kopia.ExtractFingerprintFromCertificate(tlsCert) if err != nil { - return errors.Wrap(err, "Failed to extract fingerprint from Kopia API Server Certificate Secret") + return errkit.Wrap(err, "Failed to extract fingerprint from Kopia API Server Certificate Secret") } serverInfo := &repo.APIServerInfo{ @@ -95,7 +95,12 @@ func ConnectToAPIServer( } return true, nil }) - return errors.Wrap(err, "Failed connecting to the Kopia API Server") + + if err != nil { + return errkit.Wrap(err, "Failed connecting to the Kopia API Server") + } + + return nil } // Open connects to the kopia repository based on the config stored in the config file @@ -104,16 +109,16 @@ func ConnectToAPIServer( func Open(ctx context.Context, configFile, password, purpose string) (repo.RepositoryWriter, error) { repoConfig := repositoryConfigFileName(configFile) if _, err := os.Stat(repoConfig); os.IsNotExist(err) { - return nil, errors.New("Failed find kopia configuration file") + return nil, errkit.New("Failed find kopia configuration file") } r, err := repo.Open(ctx, repoConfig, password, &repo.Options{}) if os.IsNotExist(err) { - return nil, errors.New("Failed to find kopia repository, use `kopia repository create` or kopia repository connect` if already created") + return nil, errkit.New("Failed to find kopia repository, use `kopia repository create` or kopia repository connect` if already created") } if err != nil { - return nil, errors.Wrap(err, "Failed to open kopia repository") + return nil, errkit.Wrap(err, "Failed to open kopia repository") } _, rw, err := r.NewWriter(ctx, repo.WriteSessionOptions{ @@ -121,7 +126,11 @@ func Open(ctx context.Context, configFile, password, purpose string) (repo.Repos OnUpload: func(i int64) {}, }) - return rw, errors.Wrap(err, "Failed to open kopia repository writer") + if err != nil { + return nil, errkit.Wrap(err, "Failed to open kopia repository writer") + } + + return rw, nil } func repositoryConfigFileName(configFile string) string { diff --git a/pkg/kopia/repository/client_test.go b/pkg/kopia/repository/client_test.go index 9c41abb5fc..f6eef44de1 100644 --- a/pkg/kopia/repository/client_test.go +++ b/pkg/kopia/repository/client_test.go @@ -5,8 +5,9 @@ import ( "gopkg.in/check.v1" - "github.com/kanisterio/kanister/pkg/kopia/repository" "github.com/kopia/kopia/repo" + + "github.com/kanisterio/kanister/pkg/kopia/repository" ) func Test(t *testing.T) { check.TestingT(t) } diff --git a/pkg/kopia/repository/connect.go b/pkg/kopia/repository/connect.go index 1469cec8f5..d5e12d5749 100644 --- a/pkg/kopia/repository/connect.go +++ b/pkg/kopia/repository/connect.go @@ -4,7 +4,7 @@ import ( "context" "strings" - "github.com/pkg/errors" + "github.com/kanisterio/errkit" "k8s.io/client-go/kubernetes" "github.com/kanisterio/kanister/pkg/format" @@ -24,7 +24,7 @@ func ConnectToKopiaRepository( ) error { cmd, err := command.RepositoryConnectCommand(cmdArgs) if err != nil { - return errors.Wrap(err, "Failed to generate repository connect command") + return errkit.Wrap(err, "Failed to generate repository connect command") } stdout, stderr, err := kube.Exec(ctx, cli, namespace, pod, container, cmd, nil) @@ -36,15 +36,15 @@ func ConnectToKopiaRepository( switch { case strings.Contains(stderr, kerrors.ErrInvalidPasswordStr): - err = errors.WithMessage(err, kerrors.ErrInvalidPasswordStr) + err = errkit.Wrap(err, kerrors.ErrInvalidPasswordStr) case err != nil && strings.Contains(err.Error(), kerrors.ErrCodeOutOfMemoryStr): - err = errors.WithMessage(err, kerrors.ErrOutOfMemoryStr) + err = errkit.Wrap(err, kerrors.ErrOutOfMemoryStr) case strings.Contains(stderr, kerrors.ErrAccessDeniedStr): - err = errors.WithMessage(err, kerrors.ErrAccessDeniedStr) + err = errkit.Wrap(err, kerrors.ErrAccessDeniedStr) case kerrors.RepoNotInitialized(stderr): - err = errors.WithMessage(err, kerrors.ErrRepoNotFoundStr) + err = errkit.Wrap(err, kerrors.ErrRepoNotFoundStr) case kerrors.BucketDoesNotExist(stderr): - err = errors.WithMessage(err, kerrors.ErrBucketDoesNotExistStr) + err = errkit.Wrap(err, kerrors.ErrBucketDoesNotExistStr) } - return errors.Wrap(err, "Failed to connect to the backup repository") + return errkit.Wrap(err, "Failed to connect to the backup repository") } diff --git a/pkg/kopia/repository/connect_or_create.go b/pkg/kopia/repository/connect_or_create.go index f64bdbcad4..36ac4f3755 100644 --- a/pkg/kopia/repository/connect_or_create.go +++ b/pkg/kopia/repository/connect_or_create.go @@ -19,6 +19,8 @@ import ( "k8s.io/client-go/kubernetes" + "github.com/kanisterio/errkit" + "github.com/kanisterio/kanister/pkg/kopia/command" kerrors "github.com/kanisterio/kanister/pkg/kopia/errors" ) @@ -80,6 +82,6 @@ func ConnectToOrCreateKopiaRepository( return nil } - err = kerrors.Append(err, connectErr) + err = errkit.Append(err, connectErr) return err } diff --git a/pkg/kopia/repository/create.go b/pkg/kopia/repository/create.go index 5c858651ba..9aeb63422c 100644 --- a/pkg/kopia/repository/create.go +++ b/pkg/kopia/repository/create.go @@ -19,7 +19,7 @@ import ( "fmt" "strings" - "github.com/pkg/errors" + "github.com/kanisterio/errkit" "k8s.io/client-go/kubernetes" "github.com/kanisterio/kanister/pkg/format" @@ -43,7 +43,7 @@ func CreateKopiaRepository( ) error { cmd, err := command.RepositoryCreateCommand(cmdArgs) if err != nil { - return errors.Wrap(err, "Failed to generate repository create command") + return errkit.Wrap(err, "Failed to generate repository create command") } stdout, stderr, err := kube.Exec(ctx, cli, namespace, pod, container, cmd, nil) format.Log(pod, container, stdout) @@ -57,7 +57,7 @@ func CreateKopiaRepository( message = message + ": " + kerrors.ErrAccessDeniedStr } if err != nil { - return errors.Wrap(err, message) + return errkit.Wrap(err, message) } if err := setGlobalPolicy( @@ -68,7 +68,7 @@ func CreateKopiaRepository( container, cmdArgs.CommandArgs, ); err != nil { - return errors.Wrap(err, "Failed to set global policy") + return errkit.Wrap(err, "Failed to set global policy") } // Set custom maintenance owner in case of successful repository creation @@ -120,7 +120,7 @@ func setCustomMaintenanceOwner( ) error { nsUID, err := utils.GetNamespaceUID(context.Background(), cli, namespace) if err != nil { - return errors.Wrap(err, "Failed to get namespace UID") + return errkit.Wrap(err, "Failed to get namespace UID") } newOwner := fmt.Sprintf(maintenanceOwnerFormat, username, nsUID) cmd := command.MaintenanceSetOwner(command.MaintenanceSetOwnerCommandArgs{ diff --git a/pkg/kopia/snapshot/snapshot.go b/pkg/kopia/snapshot/snapshot.go index c7d6b9b4df..1ec5421b3c 100644 --- a/pkg/kopia/snapshot/snapshot.go +++ b/pkg/kopia/snapshot/snapshot.go @@ -21,13 +21,13 @@ import ( "strings" "time" + "github.com/kanisterio/errkit" "github.com/kopia/kopia/fs" "github.com/kopia/kopia/repo" "github.com/kopia/kopia/repo/manifest" "github.com/kopia/kopia/snapshot" "github.com/kopia/kopia/snapshot/policy" "github.com/kopia/kopia/snapshot/snapshotfs" - "github.com/pkg/errors" "github.com/kanisterio/kanister/pkg/kopia" "github.com/kanisterio/kanister/pkg/kopia/repository" @@ -48,37 +48,37 @@ func SnapshotSource( previous, err := findPreviousSnapshotManifest(ctx, rep, sourceInfo, nil) if err != nil { - return "", 0, errors.Wrap(err, "Failed to find previous kopia manifests") + return "", 0, errkit.Wrap(err, "Failed to find previous kopia manifests") } policyTree, err := policy.TreeForSource(ctx, rep, sourceInfo) if err != nil { - return "", 0, errors.Wrap(err, "Failed to get kopia policy tree") + return "", 0, errkit.Wrap(err, "Failed to get kopia policy tree") } manifest, err := u.Upload(ctx, rootDir, policyTree, sourceInfo, previous...) if err != nil { - return "", 0, errors.Wrap(err, "Failed to upload the kopia snapshot") + return "", 0, errkit.Wrap(err, "Failed to upload the kopia snapshot") } manifest.Description = description if _, err := snapshot.SaveSnapshot(ctx, rep, manifest); err != nil { - return "", 0, errors.Wrap(err, "Failed to save kopia manifest") + return "", 0, errkit.Wrap(err, "Failed to save kopia manifest") } // TODO: https://github.com/kanisterio/kanister/issues/2441 // _, err = policy.ApplyRetentionPolicy(ctx, rep, sourceInfo, true) // if err != nil { - // return "", 0, errors.Wrap(err, "Failed to apply kopia retention policy") + // return "", 0, errkit.Wrap(err, "Failed to apply kopia retention policy") // } if err = policy.SetManual(ctx, rep, sourceInfo); err != nil { - return "", 0, errors.Wrap(err, "Failed to set manual field in kopia scheduling policy for source") + return "", 0, errkit.Wrap(err, "Failed to set manual field in kopia scheduling policy for source") } if ferr := rep.Flush(ctx); ferr != nil { - return "", 0, errors.Wrap(ferr, "Failed to flush kopia repository") + return "", 0, errkit.Wrap(ferr, "Failed to flush kopia repository") } return reportStatus(ctx, snapshotStartTime, manifest) @@ -98,7 +98,7 @@ func reportStatus(ctx context.Context, snapshotStartTime time.Time, manifest *sn } } if len(errs) != 0 { - return "", 0, errors.New(strings.Join(errs, "\n")) + return "", 0, errkit.New(strings.Join(errs, "\n")) } return string(manifestID), snapSize, nil @@ -108,13 +108,13 @@ func reportStatus(ctx context.Context, snapshotStartTime time.Time, manifest *sn func Delete(ctx context.Context, backupID, path, password string) error { rep, err := repository.Open(ctx, kopia.DefaultClientConfigFilePath, password, pullRepoPurpose) if err != nil { - return errors.Wrap(err, "Failed to open kopia repository") + return errkit.Wrap(err, "Failed to open kopia repository") } // Load the kopia snapshot with the given backupID m, err := snapshot.LoadSnapshot(ctx, rep, manifest.ID(backupID)) if err != nil { - return errors.Wrapf(err, "Failed to load kopia snapshot with ID: %v", backupID) + return errkit.Wrap(err, "Failed to load kopia snapshot with ID", "backupId", backupID) } if err := rep.DeleteManifest(ctx, m.ID); err != nil { return err @@ -127,7 +127,7 @@ func Delete(ctx context.Context, backupID, path, password string) error { func findPreviousSnapshotManifest(ctx context.Context, rep repo.Repository, sourceInfo snapshot.SourceInfo, noLaterThan *fs.UTCTimestamp) ([]*snapshot.Manifest, error) { man, err := snapshot.ListSnapshots(ctx, rep, sourceInfo) if err != nil { - return nil, errors.Wrap(err, "Failed to list previous kopia snapshots") + return nil, errkit.Wrap(err, "Failed to list previous kopia snapshots") } // find latest complete snapshot @@ -158,7 +158,7 @@ func MarshalKopiaSnapshot(snapInfo *SnapshotInfo) (string, error) { } snap, err := json.Marshal(snapInfo) if err != nil { - return "", errors.Wrap(err, "failed to marshal kopia snapshot information") + return "", errkit.Wrap(err, "failed to marshal kopia snapshot information") } return string(snap), nil @@ -168,7 +168,7 @@ func MarshalKopiaSnapshot(snapInfo *SnapshotInfo) (string, error) { func UnmarshalKopiaSnapshot(snapInfoJSON string) (SnapshotInfo, error) { snap := SnapshotInfo{} if err := json.Unmarshal([]byte(snapInfoJSON), &snap); err != nil { - return snap, errors.Wrap(err, "failed to unmarshal kopia snapshot information") + return snap, errkit.Wrap(err, "failed to unmarshal kopia snapshot information") } return snap, snap.Validate() } diff --git a/pkg/kopia/snapshot/stream.go b/pkg/kopia/snapshot/stream.go index f22fb908f3..2c8c244bb0 100644 --- a/pkg/kopia/snapshot/stream.go +++ b/pkg/kopia/snapshot/stream.go @@ -21,13 +21,13 @@ import ( "path/filepath" "sync" + "github.com/kanisterio/errkit" "github.com/kopia/kopia/fs" "github.com/kopia/kopia/fs/localfs" "github.com/kopia/kopia/fs/virtualfs" "github.com/kopia/kopia/snapshot" "github.com/kopia/kopia/snapshot/restore" "github.com/kopia/kopia/snapshot/snapshotfs" - "github.com/pkg/errors" "github.com/kanisterio/kanister/pkg/kopia" "github.com/kanisterio/kanister/pkg/kopia/repository" @@ -58,10 +58,10 @@ type SnapshotInfo struct { // Validate validates SnapshotInfo field values func (si *SnapshotInfo) Validate() error { if si == nil { - return errors.New("kopia snapshotInfo cannot be nil") + return errkit.New("kopia snapshotInfo cannot be nil") } if si.ID == "" { - return errors.New("kopia snapshot ID cannot be empty") + return errkit.New("kopia snapshot ID cannot be empty") } return nil } @@ -72,7 +72,7 @@ func (si *SnapshotInfo) Validate() error { func Write(ctx context.Context, source io.ReadCloser, path, password string) (*SnapshotInfo, error) { rep, err := repository.Open(ctx, kopia.DefaultClientConfigFilePath, password, pushRepoPurpose) if err != nil { - return nil, errors.Wrap(err, "Failed to open kopia repository") + return nil, errkit.Wrap(err, "Failed to open kopia repository") } // If the input `path` provided does not have a parent directory OR @@ -118,12 +118,12 @@ func Write(ctx context.Context, source io.ReadCloser, path, password string) (*S func WriteFile(ctx context.Context, path, sourcePath, password string) (*SnapshotInfo, error) { rep, err := repository.Open(ctx, kopia.DefaultClientConfigFilePath, password, pushRepoPurpose) if err != nil { - return nil, errors.Wrap(err, "Failed to open kopia repository") + return nil, errkit.Wrap(err, "Failed to open kopia repository") } dir, err := filepath.Abs(sourcePath) if err != nil { - return nil, errors.Wrapf(err, "Invalid source path '%s'", sourcePath) + return nil, errkit.Wrap(err, "Invalid source path", "sourcePath", sourcePath) } // Populate the source info with parent path as the source @@ -134,7 +134,7 @@ func WriteFile(ctx context.Context, path, sourcePath, password string) (*Snapsho } rootDir, err := getLocalFSEntry(ctx, sourceInfo.Path) if err != nil { - return nil, errors.Wrap(err, "Unable to get local filesystem entry") + return nil, errkit.Wrap(err, "Unable to get local filesystem entry") } // Setup kopia uploader @@ -157,12 +157,12 @@ func WriteFile(ctx context.Context, path, sourcePath, password string) (*Snapsho func getLocalFSEntry(ctx context.Context, path0 string) (fs.Entry, error) { path, err := resolveSymlink(path0) if err != nil { - return nil, errors.Wrap(err, "resolveSymlink") + return nil, errkit.Wrap(err, "resolveSymlink") } e, err := localfs.NewEntry(path) if err != nil { - return nil, errors.Wrap(err, "can't get local fs entry") + return nil, errkit.Wrap(err, "can't get local fs entry") } return e, nil @@ -171,7 +171,7 @@ func getLocalFSEntry(ctx context.Context, path0 string) (fs.Entry, error) { func resolveSymlink(path string) (string, error) { st, err := os.Lstat(path) if err != nil { - return "", errors.Wrap(err, "stat") + return "", errkit.Wrap(err, "stat") } if (st.Mode() & os.ModeSymlink) == 0 { @@ -186,7 +186,7 @@ func resolveSymlink(path string) (string, error) { func Read(ctx context.Context, target io.Writer, backupID, path, password string) error { rep, err := repository.Open(ctx, kopia.DefaultClientConfigFilePath, password, pullRepoPurpose) if err != nil { - return errors.Wrap(err, "Failed to open kopia repository") + return errkit.Wrap(err, "Failed to open kopia repository") } // Get the kopia object ID belonging to the streaming file @@ -198,31 +198,35 @@ func Read(ctx context.Context, target io.Writer, backupID, path, password string // Open repository object and copy the data to the target r, err := rep.OpenObject(ctx, oid) if err != nil { - return errors.Wrapf(err, "Failed to open kopia object: %v", oid) + return errkit.Wrap(err, "Failed to open kopia object", "oid", oid) } defer r.Close() //nolint:errcheck _, err = copy(target, r) - return errors.Wrap(err, "Failed to copy snapshot data to the target") + if err != nil { + return errkit.Wrap(err, "Failed to copy snapshot data to the target") + } + + return nil } // ReadFile restores a kopia snapshot with the given ID to the given target func ReadFile(ctx context.Context, backupID, target, password string) error { rep, err := repository.Open(ctx, kopia.DefaultClientConfigFilePath, password, pullRepoPurpose) if err != nil { - return errors.Wrap(err, "Failed to open kopia repository") + return errkit.Wrap(err, "Failed to open kopia repository") } rootEntry, err := snapshotfs.FilesystemEntryFromIDWithPath(ctx, rep, backupID, false) if err != nil { - return errors.Wrap(err, "Unable to get filesystem entry") + return errkit.Wrap(err, "Unable to get filesystem entry") } p, err := filepath.Abs(target) if err != nil { - return errors.Wrap(err, "Unable to resolve path") + return errkit.Wrap(err, "Unable to resolve path") } // TODO: Do we want to keep this flags configurable? output := &restore.FilesystemOutput{ @@ -236,7 +240,12 @@ func ReadFile(ctx context.Context, backupID, target, password string) error { _, err = restore.Entry(ctx, rep, output, rootEntry, restore.Options{ Parallel: 8, }) - return errors.Wrap(err, "Failed to copy snapshot data to the target") + + if err != nil { + return errkit.Wrap(err, "Failed to copy snapshot data to the target") + } + + return nil } // bufferPool is a pool of shared buffers used during kopia read diff --git a/pkg/kopia/utils.go b/pkg/kopia/utils.go index 612b40910a..8b5a55004f 100644 --- a/pkg/kopia/utils.go +++ b/pkg/kopia/utils.go @@ -25,12 +25,12 @@ import ( "path/filepath" "strings" + "github.com/kanisterio/errkit" "github.com/kopia/kopia/repo" "github.com/kopia/kopia/repo/manifest" "github.com/kopia/kopia/repo/object" "github.com/kopia/kopia/snapshot" "github.com/kopia/kopia/snapshot/snapshotfs" - "github.com/pkg/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" @@ -70,22 +70,22 @@ const ( func ExtractFingerprintFromCertSecret(ctx context.Context, cli kubernetes.Interface, secretName, secretNamespace string) (string, error) { secret, err := cli.CoreV1().Secrets(secretNamespace).Get(ctx, secretName, metav1.GetOptions{}) if err != nil { - return "", errors.Wrapf(err, "Failed to get Certificate Secret. Secret: %s", secretName) + return "", errkit.Wrap(err, "Failed to get Certificate Secret.", "secretName", secretName) } certBytes, err := json.Marshal(secret.Data[TLSCertificateKey]) if err != nil { - return "", errors.Wrap(err, "Failed to marshal Certificate Secret Data") + return "", errkit.Wrap(err, "Failed to marshal Certificate Secret Data") } var certString string if err := json.Unmarshal([]byte(certBytes), &certString); err != nil { - return "", errors.Wrap(err, "Failed to unmarshal Certificate Secret Data") + return "", errkit.Wrap(err, "Failed to unmarshal Certificate Secret Data") } decodedCertData, err := base64.StdEncoding.DecodeString(certString) if err != nil { - return "", errors.Wrap(err, "Failed to decode Certificate Secret Data") + return "", errkit.Wrap(err, "Failed to decode Certificate Secret Data") } return extractFingerprintFromSliceOfBytes(decodedCertData) @@ -96,12 +96,12 @@ func ExtractFingerprintFromCertSecret(ctx context.Context, cli kubernetes.Interf func extractFingerprintFromSliceOfBytes(pemData []byte) (string, error) { block, rest := pem.Decode([]byte(pemData)) if block == nil || len(rest) > 0 { - return "", errors.New("Failed to PEM Decode Kopia API Server Certificate Secret Data") + return "", errkit.New("Failed to PEM Decode Kopia API Server Certificate Secret Data") } cert, err := x509.ParseCertificate(block.Bytes) if err != nil { - return "", errors.Wrap(err, "Failed to parse X509 Kopia API Server Certificate Secret Data") + return "", errkit.Wrap(err, "Failed to parse X509 Kopia API Server Certificate Secret Data") } fingerprint := sha256.Sum256(cert.Raw) @@ -114,17 +114,17 @@ func ExtractFingerprintFromCertificateJSON(cert string) (string, error) { var certMap map[string]string if err := json.Unmarshal([]byte(cert), &certMap); err != nil { - return "", errors.Wrap(err, "Failed to unmarshal Kopia API Server Certificate Secret Data") + return "", errkit.Wrap(err, "Failed to unmarshal Kopia API Server Certificate Secret Data") } decodedCertData, err := base64.StdEncoding.DecodeString(certMap[TLSCertificateKey]) if err != nil { - return "", errors.Wrap(err, "Failed to base64 decode Kopia API Server Certificate Secret Data") + return "", errkit.Wrap(err, "Failed to base64 decode Kopia API Server Certificate Secret Data") } fingerprint, err := extractFingerprintFromSliceOfBytes(decodedCertData) if err != nil { - return "", errors.Wrap(err, "Failed to extract fingerprint Kopia API Server Certificate Secret Data") + return "", errkit.Wrap(err, "Failed to extract fingerprint Kopia API Server Certificate Secret Data") } return fingerprint, nil @@ -135,7 +135,7 @@ func ExtractFingerprintFromCertificateJSON(cert string) (string, error) { func ExtractFingerprintFromCertificate(cert string) (string, error) { fingerprint, err := extractFingerprintFromSliceOfBytes([]byte(cert)) if err != nil { - return "", errors.Wrap(err, "Failed to extract fingerprint Kopia API Server Certificate Secret Data") + return "", errkit.Wrap(err, "Failed to extract fingerprint Kopia API Server Certificate Secret Data") } return fingerprint, nil @@ -150,22 +150,22 @@ func GetStreamingFileObjectIDFromSnapshot(ctx context.Context, rep repo.Reposito // Load the kopia snapshot with the given backupID m, err := snapshot.LoadSnapshot(ctx, rep, manifest.ID(backupID)) if err != nil { - return object.ID{}, errors.Wrapf(err, "Failed to load kopia snapshot with ID: %v", backupID) + return object.ID{}, errkit.Wrap(err, "Failed to load kopia snapshot with ID", "backupId", backupID) } // root entry of the kopia snapshot is a static directory with filepath.Dir(path) as its path if m.RootEntry == nil { - return object.ID{}, errors.New("No root entry found in kopia manifest") + return object.ID{}, errkit.New("No root entry found in kopia manifest") } rootEntry, err := snapshotfs.SnapshotRoot(rep, m) if err != nil { - return object.ID{}, errors.Wrapf(err, "Failed to get root entry from kopia snapshot with ID: %v", backupID) + return object.ID{}, errkit.Wrap(err, "Failed to get root entry from kopia snapshot with ID", "backupId", backupID) } // Get the nested entry belonging to the backed up streaming file and return its object ID e, err := snapshotfs.GetNestedEntry(ctx, rootEntry, []string{filepath.Base(path)}) if err != nil { - return object.ID{}, errors.Wrapf(err, "Failed to get nested entry from kopia snapshot: %v", filepath.Base(path)) + return object.ID{}, errkit.Wrap(err, "Failed to get nested entry from kopia snapshot", "pathBase", filepath.Base(path)) } return e.(object.HasObjectID).ObjectID(), nil diff --git a/pkg/kube/pod_controller_test.go b/pkg/kube/pod_controller_test.go index f8c92f836f..8eaea039a4 100644 --- a/pkg/kube/pod_controller_test.go +++ b/pkg/kube/pod_controller_test.go @@ -18,10 +18,10 @@ import ( "context" "errors" "fmt" - "github.com/kanisterio/errkit" "os" "time" + "github.com/kanisterio/errkit" . "gopkg.in/check.v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"