diff --git a/.golangci.yml b/.golangci.yml index 00da60a2..67853412 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -9,6 +9,8 @@ linters-settings: - $all - "!$test" deny: + - pkg: github.com/pkg/errors + desc: use "errors" instead - pkg: github.com/gogo/protobuf/proto desc: use "github.com/golang/protobuf/proto" instead diff --git a/api-tests/tests/monitoring-instances.spec.ts b/api-tests/tests/monitoring-instances.spec.ts index fe1707d7..cb8b505d 100644 --- a/api-tests/tests/monitoring-instances.spec.ts +++ b/api-tests/tests/monitoring-instances.spec.ts @@ -278,7 +278,7 @@ test('patch monitoring instance type fails on missing key', async ({ request }) const getJson = await updated.json() - expect(getJson.message).toMatch('pmm key is required') + expect(getJson.message).toMatch('Pmm key is required') }) test('create monitoring instance failures', async ({ request }) => { diff --git a/api/backup_storage.go b/api/backup_storage.go index 51ad06e8..a0a9a205 100644 --- a/api/backup_storage.go +++ b/api/backup_storage.go @@ -18,6 +18,8 @@ package api import ( "context" + "errors" + "fmt" "net/http" "github.com/AlekSi/pointer" @@ -25,7 +27,6 @@ import ( "github.com/jinzhu/gorm" "github.com/labstack/echo/v4" "github.com/lib/pq" - "github.com/pkg/errors" "github.com/percona/percona-everest-backend/model" "github.com/percona/percona-everest-backend/pkg/kubernetes" @@ -75,7 +76,7 @@ func (e *EverestServer) CreateBackupStorage(ctx echo.Context) error { //nolint:f }) } if existingStorage != nil { - err = errors.Errorf("Storage %s already exists", params.Name) + err = fmt.Errorf("storage %s already exists", params.Name) e.l.Error(err) return ctx.JSON(http.StatusConflict, Error{Message: pointer.ToString(err.Error())}) } @@ -152,7 +153,7 @@ func (e *EverestServer) DeleteBackupStorage(ctx echo.Context, backupStorageName ks, err := e.storage.ListKubernetesClusters(c) if err != nil { - e.l.Error(errors.Wrap(err, "Could not list Kubernetes clusters")) + e.l.Error(errors.Join(err, errors.New("could not list Kubernetes clusters"))) return ctx.JSON(http.StatusInternalServerError, Error{Message: pointer.ToString("Could not list Kubernetes clusters")}) } if len(ks) == 0 { @@ -161,7 +162,7 @@ func (e *EverestServer) DeleteBackupStorage(ctx echo.Context, backupStorageName // FIXME: Revisit it once multi k8s support will be enabled _, kubeClient, _, err := e.initKubeClient(ctx.Request().Context(), ks[0].ID) if err != nil { - e.l.Error(errors.Wrap(err, "could not init kube client for config")) + e.l.Error(errors.Join(err, errors.New("could not init kube client for config"))) return nil } @@ -169,7 +170,7 @@ func (e *EverestServer) DeleteBackupStorage(ctx echo.Context, backupStorageName return kubernetes.IsBackupStorageConfigInUse(ctx, name, kubeClient) }) if err != nil && !errors.Is(err, kubernetes.ErrConfigInUse) { - e.l.Error(errors.Wrap(err, "could not delete config")) + e.l.Error(errors.Join(err, errors.New("could not delete config"))) return nil } @@ -177,14 +178,14 @@ func (e *EverestServer) DeleteBackupStorage(ctx echo.Context, backupStorageName err := e.storage.DeleteBackupStorage(c, backupStorageName, tx) if err != nil { e.l.Error(err) - return errors.New("Could not delete backup storage") + return errors.New("could not delete backup storage") } if _, err := e.secretsStorage.DeleteSecret(c, bs.AccessKeyID); err != nil { - return errors.Wrap(err, "could not delete access key from secrets storage") + return errors.Join(err, errors.New("could not delete access key from secrets storage")) } if _, err := e.secretsStorage.DeleteSecret(c, bs.SecretKeyID); err != nil { - return errors.Wrap(err, "could not delete secret key from secrets storage") + return errors.Join(err, errors.New("could not delete secret key from secrets storage")) } return nil @@ -293,12 +294,12 @@ func (e *EverestServer) performBackupStorageUpdate( // FIXME: Revisit it once multi k8s support will be enabled _, kubeClient, _, err := e.initKubeClient(ctx.Request().Context(), ks[0].ID) if err != nil { - e.l.Error(errors.Wrap(err, "could not init kube client to update config")) + e.l.Error(errors.Join(err, errors.New("could not init kube client to update config"))) return ctx.JSON(http.StatusInternalServerError, Error{Message: pointer.ToString("Could not init kubernetes client to update config")}) } if err := kubeClient.UpdateConfig(ctx.Request().Context(), bs, e.secretsStorage.GetSecret); err != nil { - e.l.Error(errors.Wrap(err, "could not update config")) + e.l.Error(errors.Join(err, errors.New("could not update config"))) return ctx.JSON(http.StatusInternalServerError, Error{Message: pointer.ToString("Could not update config on the kubernetes cluster")}) } @@ -329,7 +330,7 @@ func (e *EverestServer) createSecrets( err := e.secretsStorage.CreateSecret(ctx, newID, *accessKey) if err != nil { e.l.Error(err) - return newAccessKeyID, newSecretKeyID, errors.New("Could not store access key in secrets storage") + return newAccessKeyID, newSecretKeyID, errors.New("could not store access key in secrets storage") } } @@ -341,7 +342,7 @@ func (e *EverestServer) createSecrets( err := e.secretsStorage.CreateSecret(ctx, newID, *secretKey) if err != nil { e.l.Error(err) - return newAccessKeyID, newSecretKeyID, errors.New("Could not store secret key in secrets storage") + return newAccessKeyID, newSecretKeyID, errors.New("could not store secret key in secrets storage") } } @@ -436,12 +437,12 @@ func (e *EverestServer) updateBackupStorage( var pgErr *pq.Error if errors.As(err, &pgErr) { if pgErr.Code.Name() == pgErrUniqueViolation { - return http.StatusBadRequest, errors.New("Backup storage with the same name already exists. " + pgErr.Detail) + return http.StatusBadRequest, errors.New("backup storage with the same name already exists. " + pgErr.Detail) } } e.l.Error(err) - return http.StatusInternalServerError, errors.New("Could not update backup storage") + return http.StatusInternalServerError, errors.New("could not update backup storage") } return 0, nil diff --git a/api/database_cluster.go b/api/database_cluster.go index 89eb04a9..7c7741cf 100644 --- a/api/database_cluster.go +++ b/api/database_cluster.go @@ -18,12 +18,13 @@ package api import ( "context" + "errors" + "fmt" "net/http" "github.com/AlekSi/pointer" "github.com/labstack/echo/v4" everestv1alpha1 "github.com/percona/everest-operator/api/v1alpha1" - "github.com/pkg/errors" "github.com/percona/percona-everest-backend/pkg/kubernetes" ) @@ -145,7 +146,7 @@ func (e *EverestServer) UpdateDatabaseCluster(ctx echo.Context, kubernetesID str oldDB, err := kubeClient.GetDatabaseCluster(ctx.Request().Context(), name) if err != nil { - return errors.Wrap(err, "Could not get old Database Cluster") + return errors.Join(err, errors.New("could not get old Database Cluster")) } if dbc.Spec.Engine.Version != nil { // XXX: Right now we do not support upgrading of versions @@ -239,13 +240,13 @@ func (e *EverestServer) createK8SBackupStorages(ctx context.Context, kubeClient for name := range names { bs, err := e.storage.GetBackupStorage(ctx, nil, name) if err != nil { - return errors.Wrap(err, "Could not get backup storage") + return errors.Join(err, errors.New("could not get backup storage")) } err = kubeClient.EnsureConfigExists(ctx, bs, e.secretsStorage.GetSecret) if err != nil { e.rollbackCreatedBackupStorages(ctx, kubeClient, processed) - return errors.Wrapf(err, "Could not create CRs for %s", name) + return errors.Join(err, fmt.Errorf("could not create CRs for %s", name)) } processed = append(processed, name) } @@ -256,7 +257,7 @@ func (e *EverestServer) rollbackCreatedBackupStorages(ctx context.Context, kubeC for _, name := range toDelete { bs, err := e.storage.GetBackupStorage(ctx, nil, name) if err != nil { - e.l.Error(errors.Wrap(err, "could not get backup storage")) + e.l.Error(errors.Join(err, errors.New("could not get backup storage"))) continue } @@ -264,7 +265,7 @@ func (e *EverestServer) rollbackCreatedBackupStorages(ctx context.Context, kubeC return kubernetes.IsBackupStorageConfigInUse(ctx, name, kubeClient) }) if err != nil && !errors.Is(err, kubernetes.ErrConfigInUse) { - e.l.Error(errors.Wrap(err, "could not delete backup storage config")) + e.l.Error(errors.Join(err, errors.New("could not delete backup storage config"))) continue } } @@ -276,7 +277,7 @@ func (e *EverestServer) deleteK8SMonitoringConfig( defer e.waitGroup.Done() i, err := e.storage.GetMonitoringInstance(name) if err != nil { - e.l.Error(errors.Wrap(err, "could get monitoring instance")) + e.l.Error(errors.Join(err, errors.New("could get monitoring instance"))) return } @@ -284,7 +285,7 @@ func (e *EverestServer) deleteK8SMonitoringConfig( return kubernetes.IsMonitoringConfigInUse(ctx, name, kubeClient) }) if err != nil && !errors.Is(err, kubernetes.ErrConfigInUse) { - e.l.Error(errors.Wrap(err, "could not delete monitoring config in Kubernetes")) + e.l.Error(errors.Join(err, errors.New("could not delete monitoring config in Kubernetes"))) return } } @@ -296,7 +297,7 @@ func (e *EverestServer) deleteK8SBackupStorages( for name := range names { bs, err := e.storage.GetBackupStorage(ctx, nil, name) if err != nil { - e.l.Error(errors.Wrap(err, "could not get backup storage")) + e.l.Error(errors.Join(err, errors.New("could not get backup storage"))) continue } @@ -304,7 +305,7 @@ func (e *EverestServer) deleteK8SBackupStorages( return kubernetes.IsBackupStorageConfigInUse(ctx, name, kubeClient) }) if err != nil && !errors.Is(err, kubernetes.ErrConfigInUse) { - e.l.Error(errors.Wrap(err, "could not delete backup storage config in Kubernetes")) + e.l.Error(errors.Join(err, errors.New("could not delete backup storage config in Kubernetes"))) continue } } @@ -315,14 +316,14 @@ func (e *EverestServer) deleteK8SBackupStorage( ) error { bs, err := e.storage.GetBackupStorage(ctx, nil, name) if err != nil { - return errors.Wrap(err, "could not find backup storage") + return errors.Join(err, errors.New("could not find backup storage")) } err = kubeClient.DeleteConfig(ctx, bs, func(ctx context.Context, name string) (bool, error) { return kubernetes.IsBackupStorageConfigInUse(ctx, name, kubeClient) }) if err != nil && !errors.Is(err, kubernetes.ErrConfigInUse) { - return errors.Wrap(err, "could not delete config in Kubernetes") + return errors.Join(err, errors.New("could not delete config in Kubernetes")) } return nil @@ -340,13 +341,13 @@ func (e *EverestServer) createBackupStoragesOnUpdate( for name := range toCreate { bs, err := e.storage.GetBackupStorage(ctx, nil, name) if err != nil { - return errors.Wrap(err, "Could not get backup storage") + return errors.Join(err, errors.New("could not get backup storage")) } err = kubeClient.EnsureConfigExists(ctx, bs, e.secretsStorage.GetSecret) if err != nil { e.rollbackCreatedBackupStorages(ctx, kubeClient, processed) - return errors.Wrapf(err, "Could not create CRs for %s", name) + return errors.Join(err, fmt.Errorf("could not create CRs for %s", name)) } processed = append(processed, name) } @@ -366,7 +367,7 @@ func (e *EverestServer) deleteBackupStoragesOnUpdate( for name := range toDelete { err := e.deleteK8SBackupStorage(ctx, kubeClient, name) if err != nil && !errors.Is(err, kubernetes.ErrConfigInUse) { - e.l.Error(errors.Wrapf(err, "Could not delete CRs for %s", name)) + e.l.Error(errors.Join(err, fmt.Errorf("could not delete CRs for %s", name))) } } } @@ -385,12 +386,12 @@ func (e *EverestServer) createMonitoringInstanceOnUpdate( if newName != "" && newName != oldName { i, err := e.storage.GetMonitoringInstance(newName) if err != nil { - return errors.Wrap(err, "Could not get monitoring instance") + return errors.Join(err, errors.New("could not get monitoring instance")) } err = kubeClient.EnsureConfigExists(ctx, i, e.secretsStorage.GetSecret) if err != nil { - return errors.Wrap(err, "Could not create monitoring config in Kubernetes") + return errors.Join(err, errors.New("could not create monitoring config in Kubernetes")) } } @@ -412,7 +413,7 @@ func (e *EverestServer) deleteMonitoringInstanceOnUpdate( if oldName != "" && newName != oldName { i, err := e.storage.GetMonitoringInstance(oldName) if err != nil { - e.l.Error(errors.Wrap(err, "Could not get monitoring instance")) + e.l.Error(errors.Join(err, errors.New("could not get monitoring instance"))) return } @@ -420,7 +421,7 @@ func (e *EverestServer) deleteMonitoringInstanceOnUpdate( return kubernetes.IsMonitoringConfigInUse(ctx, name, kubeClient) }) if err != nil && !errors.Is(err, kubernetes.ErrConfigInUse) { - e.l.Error(errors.Wrap(err, "Could not delete monitoring config from Kubernetes")) + e.l.Error(errors.Join(err, errors.New("could not delete monitoring config from Kubernetes"))) return } } diff --git a/api/everest.go b/api/everest.go index 872b5263..724c2dcc 100644 --- a/api/everest.go +++ b/api/everest.go @@ -21,6 +21,7 @@ package api import ( "context" "encoding/json" + "errors" "fmt" "io/fs" "net/http" @@ -29,7 +30,6 @@ import ( "github.com/deepmap/oapi-codegen/pkg/middleware" "github.com/labstack/echo/v4" echomiddleware "github.com/labstack/echo/v4/middleware" - "github.com/pkg/errors" "go.uber.org/zap" "github.com/percona/percona-everest-backend/cmd/config" @@ -89,7 +89,7 @@ func (e *EverestServer) initKubeClient(ctx context.Context, kubernetesID string) k, err := e.storage.GetKubernetesCluster(ctx, kubernetesID) if err != nil { e.l.Error(err) - return nil, nil, http.StatusBadRequest, errors.New("Could not find Kubernetes cluster") + return nil, nil, http.StatusBadRequest, errors.New("could not find Kubernetes cluster") } kubeClient, err := kubernetes.NewFromSecretsStorage( @@ -98,7 +98,7 @@ func (e *EverestServer) initKubeClient(ctx context.Context, kubernetesID string) ) if err != nil { e.l.Error(err) - return k, nil, http.StatusInternalServerError, errors.New("Could not create Kubernetes client from kubeconfig") + return k, nil, http.StatusInternalServerError, errors.New("could not create Kubernetes client from kubeconfig") } return k, kubeClient, 0, nil @@ -112,7 +112,7 @@ func (e *EverestServer) initHTTPServer() error { } fsys, err := fs.Sub(public.Static, "dist") if err != nil { - return errors.Wrap(err, "error reading filesystem") + return errors.Join(err, errors.New("error reading filesystem")) } staticFilesHandler := http.FileServer(http.FS(fsys)) indexFS := echo.MustSubFS(public.Index, "dist") @@ -133,7 +133,7 @@ func (e *EverestServer) initHTTPServer() error { basePath, err := swagger.Servers.BasePath() if err != nil { - return errors.Wrap(err, "could not get base path") + return errors.Join(err, errors.New("could not get base path")) } // Use our validation middleware to check all requests against the OpenAPI schema. @@ -155,7 +155,7 @@ func (e *EverestServer) Start() error { func (e *EverestServer) Shutdown(ctx context.Context) error { e.l.Info("Shutting down http server") if err := e.echo.Shutdown(ctx); err != nil { - e.l.Error(errors.Wrap(err, "could not shut down http server")) + e.l.Error(errors.Join(err, errors.New("could not shut down http server"))) } else { e.l.Info("http server shut down") } @@ -168,7 +168,7 @@ func (e *EverestServer) Shutdown(ctx context.Context) error { defer e.waitGroup.Done() e.l.Info("Shutting down database storage") if err := e.storage.Close(); err != nil { - e.l.Error(errors.Wrap(err, "could not shut down database storage")) + e.l.Error(errors.Join(err, errors.New("could not shut down database storage"))) } else { e.l.Info("Database storage shut down") } @@ -179,7 +179,7 @@ func (e *EverestServer) Shutdown(ctx context.Context) error { defer e.waitGroup.Done() e.l.Info("Shutting down secrets storage") if err := e.secretsStorage.Close(); err != nil { - e.l.Error(errors.Wrap(err, "could not shut down secret storage")) + e.l.Error(errors.Join(err, errors.New("could not shut down secret storage"))) } else { e.l.Info("Secret storage shut down") } @@ -208,7 +208,7 @@ func (e *EverestServer) getBodyFromContext(ctx echo.Context, into any) error { decoder := json.NewDecoder(reader) if err := decoder.Decode(into); err != nil { - return errors.Wrap(err, "could not decode body") + return errors.Join(err, errors.New("could not decode body")) } return nil } diff --git a/api/kubernetes.go b/api/kubernetes.go index f9abc75e..7b956095 100644 --- a/api/kubernetes.go +++ b/api/kubernetes.go @@ -19,13 +19,14 @@ package api import ( "context" "encoding/base64" + "errors" + "fmt" "net/http" "github.com/AlekSi/pointer" "github.com/jinzhu/gorm" "github.com/labstack/echo/v4" "github.com/lib/pq" - "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/client-go/tools/clientcmd" @@ -179,11 +180,11 @@ func (e *EverestServer) UnregisterKubernetesCluster(ctx echo.Context, kubernetes func (e *EverestServer) removeK8sCluster(ctx context.Context, kubernetesID string) error { if _, err := e.secretsStorage.DeleteSecret(ctx, kubernetesID); err != nil { - return errors.Wrap(err, "could not delete kubeconfig from secrets storage") + return errors.Join(err, errors.New("could not delete kubeconfig from secrets storage")) } if err := e.storage.DeleteKubernetesCluster(ctx, kubernetesID); err != nil { - return errors.Wrap(err, "could not delete Kubernetes cluster from db") + return errors.Join(err, errors.New("could not delete Kubernetes cluster from db")) } return nil @@ -268,7 +269,7 @@ func (e *EverestServer) disableK8sClusterMonitoring(ctx echo.Context, kubeClient for _, s := range kubeClient.SecretNamesFromVMAgent(vmAgent) { mcs, err := kubeClient.GetMonitoringConfigsBySecretName(ctx.Request().Context(), s) if err != nil { - err = errors.Wrapf(err, "could not list monitoring configs by secret name %s", s) + err = errors.Join(err, fmt.Errorf("could not list monitoring configs by secret name %s", s)) e.l.Error(err) return ctx.JSON(http.StatusInternalServerError, Error{Message: pointer.ToString(err.Error())}) } @@ -276,7 +277,7 @@ func (e *EverestServer) disableK8sClusterMonitoring(ctx echo.Context, kubeClient for _, mc := range mcs { err = kubeClient.DeleteMonitoringConfig(ctx.Request().Context(), mc.Name, mc.Spec.CredentialsSecretName) if err != nil && !errors.Is(err, kubernetes.ErrMonitoringConfigInUse) { - err = errors.Wrapf(err, "could not delete monitoring config %s from Kubernetes", mc.Name) + err = errors.Join(err, fmt.Errorf("could not delete monitoring config %s from Kubernetes", mc.Name)) e.l.Error(err) return ctx.JSON(http.StatusInternalServerError, Error{Message: pointer.ToString(err.Error())}) } @@ -327,19 +328,19 @@ func (e *EverestServer) calculateClusterResources( ) if err != nil { e.l.Error(err) - return nil, errors.New("Could not get cluster resources") + return nil, errors.New("could not get cluster resources") } consumedCPUMillis, consumedMemoryBytes, err := kubeClient.GetConsumedCPUAndMemory(ctx.Request().Context(), "") if err != nil { e.l.Error(err) - return nil, errors.New("Could not get consumed cpu and memory") + return nil, errors.New("could not get consumed cpu and memory") } consumedDiskBytes, err := kubeClient.GetConsumedDiskBytes(ctx.Request().Context(), clusterType, volumes) if err != nil { e.l.Error(err) - return nil, errors.New("Could not get consumed disk bytes") + return nil, errors.New("could not get consumed disk bytes") } availableCPUMillis := allCPUMillis - consumedCPUMillis @@ -378,19 +379,19 @@ func (e *EverestServer) getNamespace(ctx context.Context, params CreateKubernete kubeconfig, err := base64.StdEncoding.DecodeString(params.Kubeconfig) if err != nil { e.l.Error(err) - return nil, errors.New("Could not decode kubeconfig") + return nil, errors.New("could not decode kubeconfig") } kubeClient, err := kubernetes.New(kubeconfig, *params.Namespace, e.l) if err != nil { e.l.Error(err) - return nil, errors.New("Could not create kube client") + return nil, errors.New("could not create kube client") } ns, err := kubeClient.GetNamespace(ctx, *params.Namespace) if err != nil { e.l.Error(err) - return nil, errors.New("Could not get namespace from Kubernetes") + return nil, errors.New("could not get namespace from Kubernetes") } return ns, nil diff --git a/api/marshal.go b/api/marshal.go new file mode 100644 index 00000000..954747bc --- /dev/null +++ b/api/marshal.go @@ -0,0 +1,20 @@ +package api + +import ( + "encoding/json" + "unicode" +) + +// MarshalJSON capitalizes Error.Message and marshals it to byte array. +func (e Error) MarshalJSON() ([]byte, error) { + if e.Message != nil && *e.Message != "" { + r := []rune(*e.Message) + r[0] = unicode.ToUpper(r[0]) + *e.Message = string(r) + } + return json.Marshal(&struct { + Message *string `json:"message,omitempty"` + }{ + Message: e.Message, + }) +} diff --git a/api/monitoring_instance.go b/api/monitoring_instance.go index c07bacc8..5dbb4988 100644 --- a/api/monitoring_instance.go +++ b/api/monitoring_instance.go @@ -18,6 +18,7 @@ package api import ( "context" + "errors" "fmt" "net/http" @@ -25,7 +26,6 @@ import ( "github.com/google/uuid" "github.com/jinzhu/gorm" "github.com/labstack/echo/v4" - "github.com/pkg/errors" "github.com/percona/percona-everest-backend/model" "github.com/percona/percona-everest-backend/pkg/kubernetes" @@ -163,7 +163,7 @@ func (e *EverestServer) DeleteMonitoringInstance(ctx echo.Context, name string) ks, err := e.storage.ListKubernetesClusters(ctx.Request().Context()) if err != nil { - return errors.Wrap(err, "Could not list Kubernetes clusters") + return errors.Join(err, errors.New("could not list Kubernetes clusters")) } if len(ks) == 0 { return ctx.JSON(http.StatusInternalServerError, Error{Message: pointer.ToString("No registered kubernetes clusters available")}) @@ -171,7 +171,7 @@ func (e *EverestServer) DeleteMonitoringInstance(ctx echo.Context, name string) // FIXME: Revisit it once multi k8s support will be enabled _, kubeClient, _, err := e.initKubeClient(ctx.Request().Context(), ks[0].ID) if err != nil { - e.l.Error(errors.Wrap(err, "could not init kube client")) + e.l.Error(errors.Join(err, errors.New("could not init kube client"))) return ctx.JSON(http.StatusInternalServerError, Error{Message: pointer.ToString("Could not make connection to the kubernetes cluster")}) } @@ -179,19 +179,19 @@ func (e *EverestServer) DeleteMonitoringInstance(ctx echo.Context, name string) return kubernetes.IsMonitoringConfigInUse(ctx, name, kubeClient) }) if err != nil && !errors.Is(err, kubernetes.ErrConfigInUse) { - e.l.Error(errors.Wrap(err, "could not delete monitoring config from kubernetes cluster")) + e.l.Error(errors.Join(err, errors.New("could not delete monitoring config from kubernetes cluster"))) return ctx.JSON(http.StatusInternalServerError, Error{Message: pointer.ToString("Could not delete monitoring config from the Kubernetes cluster")}) } err = e.storage.Transaction(func(tx *gorm.DB) error { if err := e.storage.DeleteMonitoringInstance(i.Name, tx); err != nil { e.l.Error(err) - return errors.New("Could not delete monitoring instance") + return errors.New("could not delete monitoring instance") } _, err = e.secretsStorage.DeleteSecret(context.Background(), i.APIKeySecretID) if err != nil { - return errors.Wrapf(err, "could not delete monitoring instance API key secret %s", i.APIKeySecretID) + return errors.Join(err, fmt.Errorf("could not delete monitoring instance API key secret %s", i.APIKeySecretID)) } return nil @@ -224,14 +224,14 @@ func (e *EverestServer) createAndStorePMMApiKey(ctx context.Context, name, url, ) if err != nil { e.l.Error(err) - return "", errors.New("Could not create an API key in PMM") + return "", errors.New("could not create an API key in PMM") } } apiKeyID := uuid.NewString() if err := e.secretsStorage.CreateSecret(ctx, apiKeyID, apiKey); err != nil { e.l.Error(err) - return "", errors.New("Could not save API key to secrets storage") + return "", errors.New("could not save API key to secrets storage") } return apiKeyID, nil @@ -245,10 +245,10 @@ func (e *EverestServer) performMonitoringInstanceUpdate( //nolint:cyclop err := e.storage.Transaction(func(tx *gorm.DB) error { ks, err := e.storage.ListKubernetesClusters(ctx.Request().Context()) if err != nil { - return errors.Wrap(err, "Could not list Kubernetes clusters") + return errors.Join(err, errors.New("could not list Kubernetes clusters")) } if len(ks) == 0 { - return errors.New("No registered Kubernetes clusters available") + return errors.New("no registered Kubernetes clusters available") } err = e.storage.UpdateMonitoringInstance(name, model.UpdateMonitoringInstanceParams{ Type: (*model.MonitoringInstanceType)(¶ms.Type), @@ -257,17 +257,17 @@ func (e *EverestServer) performMonitoringInstanceUpdate( //nolint:cyclop }) if err != nil { if _, err := e.secretsStorage.DeleteSecret(ctx.Request().Context(), *apiKeyID); err != nil { - return errors.Wrapf(err, "Could not delete secret %s from secret storage", *apiKeyID) + return errors.Join(err, fmt.Errorf("could not delete secret %s from secret storage", *apiKeyID)) } e.l.Error(err) - return errors.New("Could not update monitoring instance") + return errors.New("could not update monitoring instance") } monitoringInstance, err = e.storage.GetMonitoringInstance(name) if err != nil { e.l.Error(err) - return errors.New("Could not find updated monitoring instance") + return errors.New("could not find updated monitoring instance") } // FIXME: Revisit it once multi k8s support will be enabled // FIXME: This is not recommended to do network calls in a database transaction @@ -275,16 +275,16 @@ func (e *EverestServer) performMonitoringInstanceUpdate( //nolint:cyclop // However, right now it guarantees data consistency _, kubeClient, _, err := e.initKubeClient(ctx.Request().Context(), ks[0].ID) if err != nil { - return errors.Wrap(err, "could not init kube client to update config") + return errors.Join(err, errors.New("could not init kube client to update config")) } if err := kubeClient.UpdateConfig(ctx.Request().Context(), monitoringInstance, e.secretsStorage.GetSecret); err != nil { - return errors.Wrap(err, "could not update config") + return errors.Join(err, errors.New("could not update config")) } if apiKeyID != nil { if _, err := e.secretsStorage.DeleteSecret(context.Background(), previousAPIKeyID); err != nil { - return errors.Wrapf(err, "could not delete monitoring instance api key secret %s", previousAPIKeyID) + return errors.Join(err, fmt.Errorf("could not delete monitoring instance api key secret %s", previousAPIKeyID)) } } diff --git a/api/proxy.go b/api/proxy.go index fed73417..c3084846 100644 --- a/api/proxy.go +++ b/api/proxy.go @@ -19,6 +19,7 @@ package api import ( "bytes" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -29,7 +30,6 @@ import ( "github.com/AlekSi/pointer" "github.com/labstack/echo/v4" - "github.com/pkg/errors" "go.uber.org/zap" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/rest" @@ -123,17 +123,17 @@ func everestResponseModifier(logger *zap.SugaredLogger) func(resp *http.Response if _, ok := rewriteCodes[resp.StatusCode]; ok { b, err := io.ReadAll(resp.Body) if err != nil { - logger.Error(errors.Wrap(err, "failed reading body")) + logger.Error(errors.Join(err, errors.New("failed reading body"))) return err } err = resp.Body.Close() if err != nil { - logger.Error(errors.Wrap(err, "failed closing body")) + logger.Error(errors.Join(err, errors.New("failed closing body"))) return err } b, err = tryOverrideResponseBody(b) if err != nil { - logger.Error(errors.Wrap(err, "failed overriding response body")) + logger.Error(errors.Join(err, errors.New("failed overriding response body"))) return err } diff --git a/api/validation.go b/api/validation.go index d381ec83..0aa077b8 100644 --- a/api/validation.go +++ b/api/validation.go @@ -49,20 +49,20 @@ var ( minCPUQuantity = resource.MustParse("600m") //nolint:gochecknoglobals minMemQuantity = resource.MustParse("512M") //nolint:gochecknoglobals - errDBCEmptyMetadata = errors.New("DatabaseCluster's Metadata should not be empty") - errDBCNameEmpty = errors.New("DatabaseCluster's metadata.name should not be empty") - errDBCNameWrongFormat = errors.New("DatabaseCluster's metadata.name should be a string") - errNotEnoughMemory = fmt.Errorf("Memory limits should be above %s", minMemQuantity.String()) //nolint:stylecheck - errInt64NotSupported = errors.New("Specifying resources using int64 data type is not supported. Please use string format for that") //nolint:stylecheck - errNotEnoughCPU = fmt.Errorf("CPU limits should be above %s", minCPUQuantity.String()) //nolint:stylecheck - errNotEnoughDiskSize = fmt.Errorf("Storage size should be above %s", minStorageQuantity.String()) //nolint:stylecheck - errUnsupportedPXCProxy = errors.New("You can use either HAProxy or Proxy SQL for PXC clusters") //nolint:stylecheck - errUnsupportedPGProxy = errors.New("You can use only PGBouncer as a proxy type for Postgres clusters") //nolint:stylecheck - errUnsupportedPSMDBProxy = errors.New("You can use only Mongos as a proxy type for MongoDB clusters") //nolint:stylecheck - errNoSchedules = errors.New("Please specify at least one backup schedule") //nolint:stylecheck + errDBCEmptyMetadata = errors.New("databaseCluster's Metadata should not be empty") + errDBCNameEmpty = errors.New("databaseCluster's metadata.name should not be empty") + errDBCNameWrongFormat = errors.New("databaseCluster's metadata.name should be a string") + errNotEnoughMemory = fmt.Errorf("memory limits should be above %s", minMemQuantity.String()) + errInt64NotSupported = errors.New("specifying resources using int64 data type is not supported. Please use string format for that") + errNotEnoughCPU = fmt.Errorf("CPU limits should be above %s", minCPUQuantity.String()) + errNotEnoughDiskSize = fmt.Errorf("storage size should be above %s", minStorageQuantity.String()) + errUnsupportedPXCProxy = errors.New("you can use either HAProxy or Proxy SQL for PXC clusters") + errUnsupportedPGProxy = errors.New("you can use only PGBouncer as a proxy type for Postgres clusters") + errUnsupportedPSMDBProxy = errors.New("you can use only Mongos as a proxy type for MongoDB clusters") + errNoSchedules = errors.New("please specify at least one backup schedule") errNoNameInSchedule = errors.New("'name' field for the backup schedules cannot be empty") errNoBackupStorageName = errors.New("'backupStorageName' field cannot be empty when schedule is enabled") - errNoResourceDefined = errors.New("Please specify resource limits for the cluster") //nolint:stylecheck + errNoResourceDefined = errors.New("please specify resource limits for the cluster") //nolint:gochecknoglobals operatorEngine = map[everestv1alpha1.EngineType]string{ everestv1alpha1.DatabaseEnginePXC: pxcDeploymentName, @@ -85,12 +85,12 @@ func ErrNameTooLong(fieldName string) error { // ErrCreateStorageNotSupported appears when trying to create a storage of a type that is not supported. func ErrCreateStorageNotSupported(storageType string) error { - return fmt.Errorf("Creating storage is not implemented for '%s'", storageType) //nolint:stylecheck + return fmt.Errorf("creating storage is not implemented for '%s'", storageType) } // ErrUpdateStorageNotSupported appears when trying to update a storage of a type that is not supported. func ErrUpdateStorageNotSupported(storageType string) error { - return fmt.Errorf("Updating storage is not implemented for '%s'", storageType) //nolint:stylecheck + return fmt.Errorf("updating storage is not implemented for '%s'", storageType) } // ErrInvalidURL when the given fieldName contains invalid URL. @@ -237,7 +237,7 @@ func validateCreateBackupStorageRequest(ctx echo.Context, l *zap.SugaredLogger) // check data access if err := validateStorageAccessByCreate(params); err != nil { l.Error(err) - return nil, errors.New("Could not connect to the backup storage, please check the new credentials are correct") //nolint:stylecheck + return nil, errors.New("could not connect to the backup storage, please check the new credentials are correct") } return ¶ms, nil @@ -360,7 +360,7 @@ func (e *EverestServer) validateDatabaseClusterCR(ctx echo.Context, kubernetesID } engineName, ok := operatorEngine[everestv1alpha1.EngineType(databaseCluster.Spec.Engine.Type)] if !ok { - return errors.New("Unsupported database engine") //nolint:stylecheck + return errors.New("unsupported database engine") } engine, err := kubeClient.GetDatabaseEngine(ctx.Request().Context(), engineName) if err != nil { @@ -384,7 +384,7 @@ func validateVersion(version *string, engine *everestv1alpha1.DatabaseEngine) er if version != nil { if len(engine.Spec.AllowedVersions) != 0 { if !containsVersion(*version, engine.Spec.AllowedVersions) { - return fmt.Errorf("Using %s version for %s is not allowed", *version, engine.Spec.Type) //nolint:stylecheck + return fmt.Errorf("using %s version for %s is not allowed", *version, engine.Spec.Type) } return nil } diff --git a/api/validation_test.go b/api/validation_test.go index fd9b255a..f36bbf70 100644 --- a/api/validation_test.go +++ b/api/validation_test.go @@ -16,11 +16,11 @@ package api import ( "encoding/json" + "errors" "testing" "github.com/AlekSi/pointer" everestv1alpha1 "github.com/percona/everest-operator/api/v1alpha1" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -367,7 +367,7 @@ func TestValidateVersion(t *testing.T) { AllowedVersions: []string{"8.0.31"}, }, }, - err: errors.New("Using 8.0.32 version for pxc is not allowed"), + err: errors.New("using 8.0.32 version for pxc is not allowed"), }, } for _, tc := range cases { diff --git a/cmd/main.go b/cmd/main.go index 89089748..39da2e47 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -17,13 +17,13 @@ package main import ( "context" + "errors" "net/http" "os" "os/signal" "time" "github.com/go-logr/zapr" - "github.com/pkg/errors" "go.uber.org/zap" ctrlruntimelog "sigs.k8s.io/controller-runtime/pkg/log" @@ -71,7 +71,7 @@ func main() { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := server.Shutdown(ctx); err != nil { - l.Error(errors.Wrap(err, "could not shut down Everest")) + l.Error(errors.Join(err, errors.New("could not shut down Everest"))) } else { l.Info("Everest shut down") } diff --git a/go.mod b/go.mod index a99fc99d..a62c6cba 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,6 @@ require ( github.com/labstack/echo/v4 v4.11.1 github.com/lib/pq v1.10.9 github.com/percona/everest-operator v0.0.16 - github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.8.4 go.uber.org/zap v1.25.0 k8s.io/api v0.28.1 @@ -76,6 +75,7 @@ require ( github.com/opencontainers/image-spec v1.1.0-rc2 // indirect github.com/pelletier/go-toml/v2 v2.0.9 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sergi/go-diff v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect diff --git a/model/backup_storage.go b/model/backup_storage.go index 8d8d2532..bf91bc3f 100644 --- a/model/backup_storage.go +++ b/model/backup_storage.go @@ -17,11 +17,11 @@ package model import ( "context" + "errors" "fmt" "time" everestv1alpha1 "github.com/percona/everest-operator/api/v1alpha1" - "github.com/pkg/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" ) @@ -50,11 +50,11 @@ func (b *BackupStorage) SecretName() string { func (b *BackupStorage) Secrets(ctx context.Context, getSecret func(ctx context.Context, id string) (string, error)) (map[string]string, error) { secretKey, err := getSecret(ctx, b.SecretKeyID) if err != nil { - return nil, errors.Wrap(err, "Failed to get secretKey") + return nil, errors.Join(err, errors.New("failed to get secretKey")) } accessKey, err := getSecret(ctx, b.AccessKeyID) if err != nil { - return nil, errors.Wrap(err, "Failed to get accessKey") + return nil, errors.Join(err, errors.New("failed to get accessKey")) } return map[string]string{ "AWS_SECRET_ACCESS_KEY": secretKey, diff --git a/model/backup_storage_helpers.go b/model/backup_storage_helpers.go index 01ff4344..39bffb9f 100644 --- a/model/backup_storage_helpers.go +++ b/model/backup_storage_helpers.go @@ -17,9 +17,9 @@ package model import ( "context" + "errors" "github.com/jinzhu/gorm" - "github.com/pkg/errors" ) // CreateBackupStorageParams parameters for BackupStorage record creation. @@ -124,7 +124,7 @@ func (db *Database) UpdateBackupStorage(_ context.Context, tx *gorm.DB, params U // Updates only non-empty fields defined in record if err = target.Model(old).Where("name = ?", params.Name).Updates(record).Error; err != nil { - return errors.Wrap(err, "could not update backup storage") + return errors.Join(err, errors.New("could not update backup storage")) } return nil diff --git a/model/database.go b/model/database.go index 2fedcefb..89d552c1 100644 --- a/model/database.go +++ b/model/database.go @@ -20,6 +20,7 @@ package model import ( "context" "database/sql" + "errors" "fmt" "github.com/golang-migrate/migrate/v4" @@ -27,7 +28,6 @@ import ( _ "github.com/golang-migrate/migrate/v4/source/file" // driver for loading migrations files "github.com/jinzhu/gorm" _ "github.com/lib/pq" // postgresql driver - "github.com/pkg/errors" "go.uber.org/zap" "github.com/percona/percona-everest-backend/cmd/config" @@ -45,7 +45,7 @@ func OpenDB(dsn string) (*gorm.DB, error) { db, err := gorm.Open("postgres", dsn) db.LogMode(config.Debug) if err != nil { - return nil, errors.Wrap(err, "failed to create a connection pool to PostgreSQL") + return nil, errors.Join(err, errors.New("failed to create a connection pool to PostgreSQL")) } return db, nil } @@ -56,7 +56,7 @@ func NewDatabase(name, dsn, migrationsDir string) (*Database, error) { db, err := OpenDB(dsn) if err != nil { - return nil, errors.Wrap(err, "failed to connect to database") + return nil, errors.Join(err, errors.New("failed to connect to database")) } return &Database{ @@ -91,21 +91,21 @@ func (db *Database) Transaction(fn func(tx *gorm.DB) error) error { func (db *Database) Migrate() (uint, error) { pgInstace, err := postgres.WithInstance(db.gormDB.DB(), &postgres.Config{}) if err != nil { - return 0, errors.Wrap(err, "failed to setup migrator driver") + return 0, errors.Join(err, errors.New("failed to setup migrator driver")) } m, err := migrate.NewWithDatabaseInstance("file://"+db.dir, "", pgInstace) if err != nil { - return 0, errors.Wrap(err, "failed to setup migrator") + return 0, errors.Join(err, errors.New("failed to setup migrator")) } if err = m.Up(); err != nil && !errors.Is(err, migrate.ErrNoChange) { - return 0, errors.Wrap(err, "failed to apply") + return 0, errors.Join(err, errors.New("failed to apply")) } v, dirty, err := m.Version() if err != nil { - return 0, errors.Wrap(err, "failed to check version") + return 0, errors.Join(err, errors.New("failed to check version")) } if dirty { return 0, errors.New("database is dirty; manual fix is required") diff --git a/model/monitoring_instance.go b/model/monitoring_instance.go index 1bfa4501..cb6902d8 100644 --- a/model/monitoring_instance.go +++ b/model/monitoring_instance.go @@ -22,7 +22,6 @@ import ( "time" everestv1alpha1 "github.com/percona/everest-operator/api/v1alpha1" - "github.com/pkg/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" ) @@ -84,7 +83,7 @@ func (m *MonitoringInstance) K8sResource( //nolint:ireturn Image: "percona/pmm-client:2", } default: - return nil, errors.Errorf("monitoring instance type %s not supported", m.Type) + return nil, fmt.Errorf("monitoring instance type %s not supported", m.Type) } return mc, nil diff --git a/model/monitoring_instance_helpers.go b/model/monitoring_instance_helpers.go index 137c504a..0d11ac51 100644 --- a/model/monitoring_instance_helpers.go +++ b/model/monitoring_instance_helpers.go @@ -17,8 +17,9 @@ package model import ( + "errors" + "github.com/jinzhu/gorm" - "github.com/pkg/errors" ) // UpdateMonitoringInstanceParams stores fields to be updated in monitoring instance. diff --git a/pkg/configs/configs.go b/pkg/configs/configs.go index 9805335e..4ec7b82d 100644 --- a/pkg/configs/configs.go +++ b/pkg/configs/configs.go @@ -18,9 +18,9 @@ package configs import ( "context" + "errors" "sync" - "github.com/pkg/errors" "go.uber.org/zap" "github.com/percona/percona-everest-backend/model" @@ -56,7 +56,7 @@ func DeleteConfigFromK8sClusters( _, kubeClient, _, err := initKubeClient(ctx, k.ID) if err != nil { - l.Error(errors.Wrap(err, "could not init kube client for config")) + l.Error(errors.Join(err, errors.New("could not init kube client for config"))) return } @@ -64,7 +64,7 @@ func DeleteConfigFromK8sClusters( return isInUse(ctx, name, kubeClient) }) if err != nil && !errors.Is(err, kubernetes.ErrConfigInUse) { - l.Error(errors.Wrap(err, "could not delete config")) + l.Error(errors.Join(err, errors.New("could not delete config"))) return } }() @@ -88,12 +88,12 @@ func UpdateConfigInAllK8sClusters( _, kubeClient, _, err := initKubeClient(ctx, k.ID) if err != nil { - l.Error(errors.Wrap(err, "could not init kube client to update config")) + l.Error(errors.Join(err, errors.New("could not init kube client to update config"))) return } if err := kubeClient.UpdateConfig(ctx, cfg, getSecret); err != nil { - l.Error(errors.Wrap(err, "could not update config")) + l.Error(errors.Join(err, errors.New("could not update config"))) return } }() diff --git a/pkg/convertors/convertors.go b/pkg/convertors/convertors.go index b6481ae4..f51e6822 100644 --- a/pkg/convertors/convertors.go +++ b/pkg/convertors/convertors.go @@ -17,12 +17,11 @@ package convertors import ( + "fmt" "math" "strconv" "strings" "unicode" - - "github.com/pkg/errors" ) const ( @@ -78,7 +77,7 @@ func StrToBytes(memory string) (uint64, error) { } coeficient, ok := suffixMapping[suffix] if !ok { - return 0, errors.Errorf("suffix '%s' is not supported", suffix) + return 0, fmt.Errorf("suffix '%s' is not supported", suffix) } if suffix != "" { @@ -86,7 +85,7 @@ func StrToBytes(memory string) (uint64, error) { } value, err := strconv.ParseFloat(memory, 64) if err != nil { - return 0, errors.Errorf("given value '%s' is not a number", memory) + return 0, fmt.Errorf("given value '%s' is not a number", memory) } return uint64(math.Ceil(value * coeficient)), nil } diff --git a/pkg/kubernetes/backup_storage.go b/pkg/kubernetes/backup_storage.go index 0e26145a..bb683b69 100644 --- a/pkg/kubernetes/backup_storage.go +++ b/pkg/kubernetes/backup_storage.go @@ -2,9 +2,9 @@ package kubernetes import ( "context" + "errors" everestv1alpha1 "github.com/percona/everest-operator/api/v1alpha1" - "github.com/pkg/errors" ) // IsBackupStorageConfigInUse returns true if the backup storage is in use @@ -12,7 +12,7 @@ import ( func IsBackupStorageConfigInUse(ctx context.Context, name string, kubeClient *Kubernetes) (bool, error) { //nolint:cyclop dbs, err := kubeClient.ListDatabaseClusters(ctx) if err != nil { - return false, errors.Wrap(err, "could not list database clusters in Kubernetes") + return false, errors.Join(err, errors.New("could not list database clusters in Kubernetes")) } for _, db := range dbs.Items { @@ -25,7 +25,7 @@ func IsBackupStorageConfigInUse(ctx context.Context, name string, kubeClient *Ku backups, err := kubeClient.ListDatabaseClusterBackups(ctx) if err != nil { - return false, errors.Wrap(err, "could not list database cluster backups in Kubernetes") + return false, errors.Join(err, errors.New("could not list database cluster backups in Kubernetes")) } for _, b := range backups.Items { if b.Spec.BackupStorageName == name { @@ -35,7 +35,7 @@ func IsBackupStorageConfigInUse(ctx context.Context, name string, kubeClient *Ku restores, err := kubeClient.ListDatabaseClusterRestores(ctx) if err != nil { - return false, errors.Wrap(err, "could not list database cluster restores in Kubernetes") + return false, errors.Join(err, errors.New("could not list database cluster restores in Kubernetes")) } for _, restore := range restores.Items { diff --git a/pkg/kubernetes/client/client.go b/pkg/kubernetes/client/client.go index 88dfeb24..0def3211 100644 --- a/pkg/kubernetes/client/client.go +++ b/pkg/kubernetes/client/client.go @@ -17,9 +17,9 @@ package client import ( + "errors" "time" - "github.com/pkg/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -213,7 +213,7 @@ func deleteObject(helper *resource.Helper, namespace, name string) error { func (c *Client) ListObjects(gvk schema.GroupVersionKind, into runtime.Object) error { helper, err := c.helperForGVK(gvk) if err != nil { - return errors.Wrap(err, "could not create helper") + return errors.Join(err, errors.New("could not create helper")) } l, err := helper.List(c.namespace, gvk.Version, &metav1.ListOptions{}) @@ -233,17 +233,17 @@ func (c *Client) ListObjects(gvk schema.GroupVersionKind, into runtime.Object) e func (c *Client) GetObject(gvk schema.GroupVersionKind, name string, into runtime.Object) error { helper, err := c.helperForGVK(gvk) if err != nil { - return errors.Wrap(err, "could not create helper") + return errors.Join(err, errors.New("could not create helper")) } l, err := helper.Get(c.namespace, name) if err != nil { - return errors.Wrap(err, "failed to get object using helper") + return errors.Join(err, errors.New("failed to get object using helper")) } u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(l) if err != nil { - return errors.Wrap(err, "failed to convert object to unstructured") + return errors.Join(err, errors.New("failed to convert object to unstructured")) } return runtime.DefaultUnstructuredConverter.FromUnstructured(u, into) diff --git a/pkg/kubernetes/client/customresources/resource.go b/pkg/kubernetes/client/customresources/resource.go index f83e6f21..2eb50043 100644 --- a/pkg/kubernetes/client/customresources/resource.go +++ b/pkg/kubernetes/client/customresources/resource.go @@ -17,9 +17,9 @@ package customresources import ( "context" + "errors" "strings" - "github.com/pkg/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -41,7 +41,7 @@ func (c *Client) objectKind(obj runtime.Object) (schema.GroupVersionKind, error) gvks, _, err := scheme.Scheme.ObjectKinds(obj) if err != nil { - return schema.GroupVersionKind{}, errors.Wrap(err, "could not retrieve object kinds") + return schema.GroupVersionKind{}, errors.Join(err, errors.New("could not retrieve object kinds")) } if len(gvks) != 1 { @@ -139,7 +139,7 @@ func (c *Client) DeleteResource( acc := meta.NewAccessor() name, err := acc.Name(obj) if err != nil { - return errors.Wrap(err, "could not get name from an object to delete") + return errors.Join(err, errors.New("could not get name from an object to delete")) } err = c.restClient. diff --git a/pkg/kubernetes/configs.go b/pkg/kubernetes/configs.go index 78e771f5..9039b64a 100644 --- a/pkg/kubernetes/configs.go +++ b/pkg/kubernetes/configs.go @@ -2,10 +2,10 @@ package kubernetes import ( "context" + "errors" "fmt" everestv1alpha1 "github.com/percona/everest-operator/api/v1alpha1" - "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" @@ -29,7 +29,7 @@ type ConfigK8sResourcer interface { } // ErrConfigInUse is returned when a config is in use. -var ErrConfigInUse error = errors.New("config is in use") +var ErrConfigInUse = errors.New("config is in use") // EnsureConfigExists makes sure a config resource for the provided object // exists in Kubernetes. If it does not, it is created. @@ -39,18 +39,18 @@ func (k *Kubernetes) EnsureConfigExists( ) error { config, err := cfg.K8sResource(k.namespace) if err != nil { - return errors.Wrap(err, "could not get Kubernetes resource object") + return errors.Join(err, errors.New("could not get Kubernetes resource object")) } acc := meta.NewAccessor() name, err := acc.Name(config) if err != nil { - return errors.Wrap(err, "could not get name from a config object") + return errors.Join(err, errors.New("could not get name from a config object")) } r, err := cfg.K8sResource(k.namespace) if err != nil { - return errors.Wrap(err, "could not get Kubernetes resource object") + return errors.Join(err, errors.New("could not get Kubernetes resource object")) } err = k.client.GetResource(ctx, name, r, &metav1.GetOptions{}) @@ -59,17 +59,17 @@ func (k *Kubernetes) EnsureConfigExists( } if !k8serrors.IsNotFound(err) { - return errors.Wrap(err, "could not get config from Kubernetes") + return errors.Join(err, errors.New("could not get config from Kubernetes")) } cfgSecrets, err := cfg.Secrets(ctx, getSecret) if err != nil { - return errors.Wrap(err, "could not get config secrets from secrets storage") + return errors.Join(err, errors.New("could not get config secrets from secrets storage")) } err = k.createConfigWithSecret(ctx, cfg.SecretName(), config, cfgSecrets) if err != nil { - return errors.Wrap(err, "could not create a config with secret") + return errors.Join(err, errors.New("could not create a config with secret")) } return nil @@ -82,18 +82,18 @@ func (k *Kubernetes) UpdateConfig( ) error { config, err := cfg.K8sResource(k.namespace) if err != nil { - return errors.Wrap(err, "could not get Kubernetes resource object") + return errors.Join(err, errors.New("could not get Kubernetes resource object")) } acc := meta.NewAccessor() name, err := acc.Name(config) if err != nil { - return errors.Wrap(err, "could not get name from a config object") + return errors.Join(err, errors.New("could not get name from a config object")) } r, err := cfg.K8sResource(k.namespace) if err != nil { - return errors.Wrap(err, "could not get Kubernetes resource object") + return errors.Join(err, errors.New("could not get Kubernetes resource object")) } err = k.client.GetResource(ctx, name, r, &metav1.GetOptions{}) @@ -102,17 +102,17 @@ func (k *Kubernetes) UpdateConfig( return nil } - return errors.Wrap(err, "could not get config resource from Kubernetes") + return errors.Join(err, errors.New("could not get config resource from Kubernetes")) } cfgSecrets, err := cfg.Secrets(ctx, getSecret) if err != nil { - return errors.Wrap(err, "could not get config secrets from secrets storage") + return errors.Join(err, errors.New("could not get config secrets from secrets storage")) } err = k.updateConfigWithSecret(ctx, cfg.SecretName(), config, cfgSecrets) if err != nil { - return errors.Wrap(err, "could not update config with secrets in Kubernetes") + return errors.Join(err, errors.New("could not update config with secrets in Kubernetes")) } return nil @@ -128,29 +128,29 @@ func (k *Kubernetes) DeleteConfig( config, err := cfg.K8sResource(k.namespace) if err != nil { - return errors.Wrap(err, "could not get Kubernetes resource object") + return errors.Join(err, errors.New("could not get Kubernetes resource object")) } acc := meta.NewAccessor() name, err := acc.Name(config) if err != nil { - return errors.Wrap(err, "could not get name from a config object") + return errors.Join(err, errors.New("could not get name from a config object")) } k.l.Debugf("Checking if config %s is in use", name) used, err := isInUse(ctx, name) if err != nil { - return errors.Wrap(err, "could not check if config is in use") + return errors.Join(err, errors.New("could not check if config is in use")) } if used { - return errors.Wrapf(ErrConfigInUse, "config %s in use", name) + return errors.Join(ErrConfigInUse, fmt.Errorf("config %s in use", name)) } k.l.Debugf("Deleting config %s", name) err = k.client.DeleteResource(ctx, config, &metav1.DeleteOptions{}) if err != nil && !k8serrors.IsNotFound(err) { - return errors.Wrap(err, "could not delete Kubernetes config object") + return errors.Join(err, errors.New("could not delete Kubernetes config object")) } go func() { @@ -159,7 +159,7 @@ func (k *Kubernetes) DeleteConfig( if secretName != "" { err := k.DeleteSecret(ctx, secretName, k.namespace) if err != nil && !k8serrors.IsNotFound(err) { - k.l.Error(errors.Wrapf(err, "could not delete secret %s for config %s", secretName, name)) + k.l.Error(errors.Join(err, fmt.Errorf("could not delete secret %s for config %s", secretName, name))) } } }() @@ -207,7 +207,7 @@ func (k *Kubernetes) updateConfigWithSecret( ) error { oldSecret, err := k.GetSecret(ctx, secretName, k.namespace) if err != nil { - return errors.Wrap(err, fmt.Sprintf("Failed to read secret %s", secretName)) + return errors.Join(err, fmt.Errorf("failed to read secret %s", secretName)) } secret := &corev1.Secret{ @@ -227,10 +227,10 @@ func (k *Kubernetes) updateConfigWithSecret( // rollback the changes _, err := k.UpdateSecret(ctx, oldSecret) if err != nil { - k.l.Error(errors.Wrapf(err, "could not revert back secret %s", oldSecret.Name)) + k.l.Error(errors.Join(err, fmt.Errorf("could not revert back secret %s", oldSecret.Name))) } - return errors.Wrap(err, "could not update config in Kubernetes") + return errors.Join(err, errors.New("could not update config in Kubernetes")) } return nil diff --git a/pkg/kubernetes/kubernetes.go b/pkg/kubernetes/kubernetes.go index 68e68405..d73f8030 100644 --- a/pkg/kubernetes/kubernetes.go +++ b/pkg/kubernetes/kubernetes.go @@ -19,9 +19,9 @@ package kubernetes import ( "context" "encoding/base64" + "errors" "strings" - "github.com/pkg/errors" "go.uber.org/zap" "github.com/percona/percona-everest-backend/pkg/kubernetes/client" @@ -78,11 +78,11 @@ func NewFromSecretsStorage( ) (*Kubernetes, error) { kubeconfigBase64, err := secretGetter.GetSecret(ctx, kubernetesID) if err != nil { - return nil, errors.Wrap(err, "could not get kubeconfig from secrets storage") + return nil, errors.Join(err, errors.New("could not get kubeconfig from secrets storage")) } kubeconfig, err := base64.StdEncoding.DecodeString(kubeconfigBase64) if err != nil { - return nil, errors.Wrap(err, "could not decode base64 kubeconfig") + return nil, errors.Join(err, errors.New("could not decode base64 kubeconfig")) } return New(kubeconfig, namespace, l) diff --git a/pkg/kubernetes/monitoring_config.go b/pkg/kubernetes/monitoring_config.go index 81a3e25c..4a313f72 100644 --- a/pkg/kubernetes/monitoring_config.go +++ b/pkg/kubernetes/monitoring_config.go @@ -17,14 +17,14 @@ package kubernetes import ( "context" + "errors" everestv1alpha1 "github.com/percona/everest-operator/api/v1alpha1" - "github.com/pkg/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) // ErrMonitoringConfigInUse is returned when a monitoring config is in use. -var ErrMonitoringConfigInUse error = errors.New("monitoring config is in use") +var ErrMonitoringConfigInUse = errors.New("monitoring config is in use") // DeleteMonitoringConfig deletes a MonitoringConfig. func (k *Kubernetes) DeleteMonitoringConfig(ctx context.Context, name, secretName string) error { @@ -32,14 +32,14 @@ func (k *Kubernetes) DeleteMonitoringConfig(ctx context.Context, name, secretNam used, err := IsMonitoringConfigInUse(ctx, name, k) if err != nil { - return errors.Wrap(err, "could not check if monitoring config is in use") + return errors.Join(err, errors.New("could not check if monitoring config is in use")) } if used { return ErrMonitoringConfigInUse } if err := k.client.DeleteMonitoringConfig(ctx, name); err != nil { - return errors.Wrap(err, "could not delete monitoring config") + return errors.Join(err, errors.New("could not delete monitoring config")) } if secretName == "" { @@ -84,7 +84,7 @@ func IsMonitoringConfigInUse(ctx context.Context, name string, kubeClient *Kuber dbs, err := kubeClient.ListDatabaseClusters(ctx) if err != nil { - return false, errors.Wrap(err, "could not list database clusters in Kubernetes") + return false, errors.Join(err, errors.New("could not list database clusters in Kubernetes")) } for _, db := range dbs.Items { @@ -99,7 +99,7 @@ func IsMonitoringConfigInUse(ctx context.Context, name string, kubeClient *Kuber func (k *Kubernetes) isMonitoringConfigUsedByVMAgent(ctx context.Context, name string) (bool, error) { vmAgents, err := k.ListVMAgents() if err != nil { - return false, errors.Wrap(err, "could not list VM agents in Kubernetes") + return false, errors.Join(err, errors.New("could not list VM agents in Kubernetes")) } secretNames := make([]string, 0, len(vmAgents.Items)) diff --git a/pkg/kubernetes/node.go b/pkg/kubernetes/node.go index 3c277899..1492fd7e 100644 --- a/pkg/kubernetes/node.go +++ b/pkg/kubernetes/node.go @@ -2,8 +2,8 @@ package kubernetes import ( "context" + "errors" - "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" ) @@ -11,7 +11,7 @@ import ( func (k *Kubernetes) GetWorkerNodes(ctx context.Context) ([]corev1.Node, error) { nodes, err := k.client.GetNodes(ctx) if err != nil { - return nil, errors.Wrap(err, "could not get nodes of Kubernetes cluster") + return nil, errors.Join(err, errors.New("could not get nodes of Kubernetes cluster")) } forbidenTaints := map[string]corev1.TaintEffect{ "node.cloudprovider.kubernetes.io/uninitialized": corev1.TaintEffectNoSchedule, diff --git a/pkg/kubernetes/resources.go b/pkg/kubernetes/resources.go index d31280b5..fdb16446 100644 --- a/pkg/kubernetes/resources.go +++ b/pkg/kubernetes/resources.go @@ -2,16 +2,19 @@ package kubernetes import ( "context" + "errors" + "fmt" "strings" - "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" "github.com/percona/percona-everest-backend/pkg/convertors" ) -// Max size of volume for AWS Elastic Block Storage service is 16TiB. -const maxVolumeSizeEBS uint64 = 16 * 1024 * 1024 * 1024 * 1024 +const ( + // Max size of volume for AWS Elastic Block Storage service is 16TiB. + maxVolumeSizeEBS uint64 = 16 * 1024 * 1024 * 1024 * 1024 +) // GetAllClusterResources goes through all cluster nodes and sums their allocatable resources. func (k *Kubernetes) GetAllClusterResources( @@ -32,7 +35,7 @@ func (k *Kubernetes) GetAllClusterResources( consumedBytes, err := sumVolumesSize(volumes) if err != nil { - return 0, 0, 0, errors.Wrap(err, "failed to sum persistent volumes storage sizes") + return 0, 0, 0, errors.Join(err, errors.New("failed to sum persistent volumes storage sizes")) } diskSizeBytes = (volumeCountEKS * maxVolumeSizeEBS) + consumedBytes } @@ -44,20 +47,20 @@ func (k *Kubernetes) getResourcesFromNodes(ctx context.Context, clusterType Clus nodes, err := k.GetWorkerNodes(ctx) if err != nil { - return 0, 0, 0, 0, errors.Wrap(err, "could not get a list of nodes") + return 0, 0, 0, 0, errors.Join(err, errors.New("could not get a list of nodes")) } var volumeCountEKS uint64 for _, node := range nodes { cpu, memory, err := getResources(node.Status.Allocatable) if err != nil { - return 0, 0, 0, 0, errors.Wrap(err, "could not get allocatable resources of the node") + return 0, 0, 0, 0, errors.Join(err, errors.New("could not get allocatable resources of the node")) } cpuMillis += cpu memoryBytes += memory switch clusterType { case ClusterTypeUnknown: - return 0, 0, 0, 0, errors.Errorf("unknown cluster type") + return 0, 0, 0, 0, errors.New("unknown cluster type") case ClusterTypeGeneric: // TODO support other cluster types continue @@ -96,7 +99,7 @@ func (k *Kubernetes) getEKSVolumeCount(node corev1.Node) (uint64, error) { volumeLimitPerNode := uint64(39) typeAndSize := strings.Split(strings.ToLower(nodeType), ".") if len(typeAndSize) < 2 { - return 0, errors.Errorf("failed to parse EKS node type '%s', it's not in expected format 'type.size'", nodeType) + return 0, fmt.Errorf("failed to parse EKS node type '%s', it's not in expected format 'type.size'", nodeType) } // ... however, if the node type is one of M5, C5, R5, T3, Z1D it's 25. limitedVolumesSet := map[string]struct{}{ @@ -113,11 +116,11 @@ func (k *Kubernetes) getEKSVolumeCount(node corev1.Node) (uint64, error) { func (k *Kubernetes) getMinikubeDiskSizeBytes(node corev1.Node) (uint64, error) { storage, ok := node.Status.Allocatable[corev1.ResourceEphemeralStorage] if !ok { - return 0, errors.Errorf("could not get storage size of the node") + return 0, errors.New("could not get storage size of the node") } bytes, err := convertors.StrToBytes(storage.String()) if err != nil { - return 0, errors.Wrapf(err, "could not convert storage size '%s' to bytes", storage.String()) + return 0, errors.Join(err, fmt.Errorf("could not convert storage size '%s' to bytes", storage.String())) } return bytes, err } @@ -129,14 +132,14 @@ func getResources(resources corev1.ResourceList) (cpuMillis uint64, memoryBytes if ok { cpuMillis, err = convertors.StrToMilliCPU(cpu.String()) if err != nil { - return 0, 0, errors.Wrapf(err, "failed to convert '%s' to millicpus", cpu.String()) + return 0, 0, errors.Join(err, fmt.Errorf("failed to convert '%s' to millicpus", cpu.String())) } } memory, ok := resources[corev1.ResourceMemory] if ok { memoryBytes, err = convertors.StrToBytes(memory.String()) if err != nil { - return 0, 0, errors.Wrapf(err, "failed to convert '%s' to bytes", memory.String()) + return 0, 0, errors.Join(err, fmt.Errorf("failed to convert '%s' to bytes", memory.String())) } } return cpuMillis, memoryBytes, nil @@ -162,7 +165,7 @@ func (k *Kubernetes) GetConsumedCPUAndMemory(ctx context.Context, namespace stri // Get CPU and Memory Requests of Pods' containers. pods, err := k.GetPods(ctx, namespace, nil) if err != nil { - return 0, 0, errors.Wrap(err, "failed to get consumed resources") + return 0, 0, errors.Join(err, errors.New("failed to get consumed resources")) } for _, ppod := range pods.Items { if ppod.Status.Phase != corev1.PodRunning { @@ -179,7 +182,7 @@ func (k *Kubernetes) GetConsumedCPUAndMemory(ctx context.Context, namespace stri for _, container := range append(ppod.Spec.Containers, nonTerminatedInitContainers...) { cpu, memory, err := getResources(container.Resources.Requests) if err != nil { - return 0, 0, errors.Wrap(err, "failed to sum all consumed resources") + return 0, 0, errors.Join(err, errors.New("failed to sum all consumed resources")) } cpuMillis += cpu memoryBytes += memory @@ -195,7 +198,7 @@ func (k *Kubernetes) GetConsumedDiskBytes( ) (uint64, error) { switch clusterType { case ClusterTypeUnknown: - return 0, errors.Errorf("unknown cluster type") + return 0, errors.New("unknown cluster type") case ClusterTypeGeneric: // TODO support other cluster types. return 0, nil @@ -205,7 +208,7 @@ func (k *Kubernetes) GetConsumedDiskBytes( case ClusterTypeEKS: consumedBytes, err := sumVolumesSize(volumes) if err != nil { - return 0, errors.Wrap(err, "failed to sum persistent volumes storage sizes") + return 0, errors.Join(err, errors.New("failed to sum persistent volumes storage sizes")) } return consumedBytes, nil } diff --git a/pkg/kubernetes/vmagent.go b/pkg/kubernetes/vmagent.go index bf1cc440..c1e9d9b7 100644 --- a/pkg/kubernetes/vmagent.go +++ b/pkg/kubernetes/vmagent.go @@ -18,9 +18,9 @@ package kubernetes import ( "context" "encoding/json" + "errors" "fmt" - "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -49,18 +49,18 @@ func (k *Kubernetes) DeployVMAgent(ctx context.Context, secretName, monitoringUR }) if err != nil && !k8serrors.IsAlreadyExists(err) { - return errors.Wrap(err, "could not create VMAgent username secret") + return errors.Join(err, errors.New("could not create VMAgent username secret")) } k.l.Debug("Applying VMAgent spec") vmagent, err := vmAgentSpec(k.namespace, secretName, monitoringURL) if err != nil { - return errors.Wrap(err, "cannot generate VMAgent spec") + return errors.Join(err, errors.New("cannot generate VMAgent spec")) } err = k.client.ApplyObject(vmagent) if err != nil && !k8serrors.IsAlreadyExists(err) { - return errors.Wrap(err, "cannot apply VMAgent spec") + return errors.Join(err, errors.New("cannot apply VMAgent spec")) } k.l.Debug("VMAgent spec has been applied") @@ -71,12 +71,12 @@ func (k *Kubernetes) DeployVMAgent(ctx context.Context, secretName, monitoringUR func (k *Kubernetes) DeleteVMAgent() error { vmagent, err := vmAgentSpec(k.namespace, "", "") if err != nil { - return errors.Wrap(err, "cannot generate VMAgent spec") + return errors.Join(err, errors.New("cannot generate VMAgent spec")) } err = k.client.DeleteObject(vmagent) if err != nil { - return errors.Wrap(err, "cannot delete VMAgent") + return errors.Join(err, errors.New("cannot delete VMAgent")) } return nil diff --git a/pkg/pmm/apikey.go b/pkg/pmm/apikey.go index a9bea304..f94ffd5a 100644 --- a/pkg/pmm/apikey.go +++ b/pkg/pmm/apikey.go @@ -19,11 +19,10 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "io" "net/http" - - "github.com/pkg/errors" ) // CreatePMMApiKey creates a new API key in PMM by using the provided username and password. @@ -63,9 +62,9 @@ func CreatePMMApiKey(ctx context.Context, hostname, apiKeyName, user, password s if resp.StatusCode >= http.StatusBadRequest { var pmmErr *pmmErrorMessage if err := json.Unmarshal(data, &pmmErr); err != nil { - return "", errors.Wrapf(err, "PMM returned an unknown error. HTTP status code %d", resp.StatusCode) + return "", errors.Join(err, fmt.Errorf("PMM returned an unknown error. HTTP status code %d", resp.StatusCode)) } - return "", errors.Errorf("PMM returned an error with message: %s", pmmErr.Message) + return "", fmt.Errorf("PMM returned an error with message: %s", pmmErr.Message) } var m map[string]interface{}