From 61e3c00b2115ddfdfb2514024c9f930cfc3b96c3 Mon Sep 17 00:00:00 2001 From: Nedim Akar <148047517+nedimakar@users.noreply.github.com> Date: Thu, 2 Nov 2023 15:45:25 +0100 Subject: [PATCH] feat: add errorz package to combine errors as enum in there (#47) * feat: add errorz package to combine errors as enum in there * feat: missed duplicated error * fix: not worked error checks * fix: not worked error checks * rename error package * applied JRA's suggestions * applied JRA's suggestions * fix error in test suite --------- Co-authored-by: Nedim Akar Co-authored-by: Nedim Akar Co-authored-by: Jan-Robin Aumann --- src/jetstream/cnsi.go | 21 ++++++++++----- .../custom_errors/constants/constants.go | 7 +++++ src/jetstream/custom_errors/custom_errors.go | 26 +++++++++++++++++++ src/jetstream/datastore/datastore.go | 7 +++-- src/jetstream/middleware.go | 16 +++++++----- src/jetstream/plugins/kubernetes/main.go | 4 +-- .../pgsql_goose_db_version.go | 18 +++++++------ .../pgsql_goose_db_version_test.go | 12 +++------ src/jetstream/setup_console.go | 5 ++-- 9 files changed, 80 insertions(+), 36 deletions(-) create mode 100644 src/jetstream/custom_errors/constants/constants.go create mode 100644 src/jetstream/custom_errors/custom_errors.go diff --git a/src/jetstream/cnsi.go b/src/jetstream/cnsi.go index d5ac2c8e09..1fe0e72e95 100644 --- a/src/jetstream/cnsi.go +++ b/src/jetstream/cnsi.go @@ -3,6 +3,7 @@ package main import ( "crypto/x509" "encoding/json" + "errors" "fmt" "net/http" "net/url" @@ -23,15 +24,21 @@ import ( const dbReferenceError = "unable to establish a database reference: '%v'" func isSSLRelatedError(err error) (bool, string) { - if urlErr, ok := err.(*url.Error); ok { - if x509Err, ok := urlErr.Err.(x509.UnknownAuthorityError); ok { - return true, x509Err.Error() + var urlError *url.Error + if errors.As(err, &urlError) { + var ( + certInvalidError *x509.CertificateInvalidError + unknownAuthorityError *x509.UnknownAuthorityError + hostnameError *x509.HostnameError + ) + if errors.As(urlError.Err, unknownAuthorityError) { + return true, unknownAuthorityError.Error() } - if x509Err, ok := urlErr.Err.(x509.HostnameError); ok { - return true, x509Err.Error() + if errors.As(urlError.Err, hostnameError) { + return true, hostnameError.Error() } - if x509Err, ok := urlErr.Err.(x509.CertificateInvalidError); ok { - return true, x509Err.Error() + if errors.As(urlError.Err, certInvalidError) { + return true, certInvalidError.Error() } } return false, "" diff --git a/src/jetstream/custom_errors/constants/constants.go b/src/jetstream/custom_errors/constants/constants.go new file mode 100644 index 0000000000..f7dcacc278 --- /dev/null +++ b/src/jetstream/custom_errors/constants/constants.go @@ -0,0 +1,7 @@ +package constants + +const ( + ERR_GOOSE_DB_NO_DATABASE_VERSIONS_FOUND = "pgsql_goosedb: no database versions found" + ERR_GOOSE_DB_NO_SUCH_TABLE = "pgsql_goosedb: no such table" + ERR_GOOSE_DB_FAILED_GETTING_CURRENT_DATABASE_VERSION = "pgsql_goosedb: error trying to get current database version: %w" +) diff --git a/src/jetstream/custom_errors/custom_errors.go b/src/jetstream/custom_errors/custom_errors.go new file mode 100644 index 0000000000..961b646bae --- /dev/null +++ b/src/jetstream/custom_errors/custom_errors.go @@ -0,0 +1,26 @@ +package custom_errors + +import ( + "fmt" + + "github.com/cloudfoundry-incubator/stratos/src/jetstream/custom_errors/constants" +) + +type GooseDBNoDatabaseVersionsFoundError struct{} + +func (e GooseDBNoDatabaseVersionsFoundError) Error() string { + return constants.ERR_GOOSE_DB_NO_DATABASE_VERSIONS_FOUND +} + +type GooseDBNoSuchTableError struct{} + +func (e GooseDBNoSuchTableError) Error() string { + return constants.ERR_GOOSE_DB_NO_SUCH_TABLE +} + +func ErrGettingCurrentVersion(err error) error { + return fmt.Errorf(constants.ERR_GOOSE_DB_FAILED_GETTING_CURRENT_DATABASE_VERSION, err) +} + +var ErrNoDatabaseVersionsFound = GooseDBNoDatabaseVersionsFoundError{} +var ErrNoSuchTable = GooseDBNoSuchTableError{} diff --git a/src/jetstream/datastore/datastore.go b/src/jetstream/datastore/datastore.go index 37f0aaa620..17030c102c 100644 --- a/src/jetstream/datastore/datastore.go +++ b/src/jetstream/datastore/datastore.go @@ -2,6 +2,7 @@ package datastore import ( "database/sql" + "errors" "fmt" "os" "path" @@ -9,6 +10,8 @@ import ( "strings" "time" + "github.com/cloudfoundry-incubator/stratos/src/jetstream/custom_errors" + goosedbversion "github.com/cloudfoundry-incubator/stratos/src/jetstream/repository/goose-db-version" "github.com/govau/cf-common/env" log "github.com/sirupsen/logrus" @@ -301,9 +304,9 @@ func WaitForMigrations(db *sql.DB) error { databaseVersionRec, err := dbVersionRepo.GetCurrentVersion() if err != nil { var errorMsg = err.Error() - if strings.Contains(err.Error(), "no such table") { + if errors.Is(err, custom_errors.ErrNoSuchTable) { errorMsg = "Waiting for versions table to be created" - } else if strings.Contains(err.Error(), "No database versions found") { + } else if errors.Is(err, custom_errors.ErrNoDatabaseVersionsFound) { errorMsg = "Versions table is empty - waiting for migrations" } log.Infof("Database schema check: %s", errorMsg) diff --git a/src/jetstream/middleware.go b/src/jetstream/middleware.go index 41d2dd6ad0..2b4cfdd48d 100644 --- a/src/jetstream/middleware.go +++ b/src/jetstream/middleware.go @@ -5,6 +5,7 @@ import ( "database/sql" "errors" "fmt" + "net" "net/http" "os" "strings" @@ -39,12 +40,15 @@ const APIKeyAuthScheme = "Bearer" func handleSessionError(config api.PortalConfig, c echo.Context, err error, doNotLog bool, msg string) error { log.Debug("handleSessionError") - if strings.Contains(err.Error(), "dial tcp") { - return api.NewHTTPShadowError( - http.StatusServiceUnavailable, - "Service is currently unavailable", - "Service is currently unavailable: %v", err, - ) + var netOpErr *net.OpError + if errors.As(err, &netOpErr) { + if netOpErr.Op == "dial" && netOpErr.Net == "tcp" { + return api.NewHTTPShadowError( + http.StatusServiceUnavailable, + "Service is currently unavailable", + "Service is currently unavailable: %v", err, + ) + } } if doNotLog { diff --git a/src/jetstream/plugins/kubernetes/main.go b/src/jetstream/plugins/kubernetes/main.go index 4026dd49dd..36ad4d201e 100644 --- a/src/jetstream/plugins/kubernetes/main.go +++ b/src/jetstream/plugins/kubernetes/main.go @@ -1,13 +1,13 @@ package kubernetes import ( + "crypto/x509" "encoding/json" "fmt" "io/ioutil" "net/http" "net/url" "strconv" - "strings" "errors" @@ -288,7 +288,7 @@ func (c *KubernetesSpecification) RequiresCert(ec echo.Context) error { Message string } if err != nil { - if strings.Contains(err.Error(), "x509: certificate") { + if errors.Is(err, new(x509.CertificateInvalidError)) { response.Status = http.StatusOK response.Required = true } else { diff --git a/src/jetstream/repository/goose-db-version/pgsql_goose_db_version.go b/src/jetstream/repository/goose-db-version/pgsql_goose_db_version.go index ef279f03d8..7a340a5b17 100644 --- a/src/jetstream/repository/goose-db-version/pgsql_goose_db_version.go +++ b/src/jetstream/repository/goose-db-version/pgsql_goose_db_version.go @@ -4,10 +4,12 @@ import ( "database/sql" "errors" "fmt" + "strings" log "github.com/sirupsen/logrus" "github.com/cloudfoundry-incubator/stratos/src/jetstream/api" + "github.com/cloudfoundry-incubator/stratos/src/jetstream/custom_errors" ) const ( @@ -35,15 +37,15 @@ func (p *PostgresGooseDBVersionRepository) GetCurrentVersion() (api.GooseDBVersi err := p.db.QueryRow(getCurrentVersion).Scan(&dbVersion.VersionID) - switch { - case err == sql.ErrNoRows: - return api.GooseDBVersionRecord{}, errors.New("No database versions found") - case err != nil: - return api.GooseDBVersionRecord{}, fmt.Errorf("Error trying to get current database version: %v", err) - default: - // do nothing + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return api.GooseDBVersionRecord{}, custom_errors.ErrNoDatabaseVersionsFound + } else if strings.Contains(err.Error(), "no such table") { + return api.GooseDBVersionRecord{}, custom_errors.ErrNoSuchTable + } else { + return api.GooseDBVersionRecord{}, custom_errors.ErrGettingCurrentVersion(err) + } } - return *dbVersion, nil } diff --git a/src/jetstream/repository/goose-db-version/pgsql_goose_db_version_test.go b/src/jetstream/repository/goose-db-version/pgsql_goose_db_version_test.go index c45f1799d1..de588f3830 100644 --- a/src/jetstream/repository/goose-db-version/pgsql_goose_db_version_test.go +++ b/src/jetstream/repository/goose-db-version/pgsql_goose_db_version_test.go @@ -2,7 +2,6 @@ package goosedbversion import ( "errors" - "fmt" "testing" "gopkg.in/DATA-DOG/go-sqlmock.v1" @@ -10,6 +9,7 @@ import ( . "github.com/smartystreets/goconvey/convey" "github.com/cloudfoundry-incubator/stratos/src/jetstream/api" + "github.com/cloudfoundry-incubator/stratos/src/jetstream/custom_errors" ) func TestPgSQLGooseDB(t *testing.T) { @@ -63,9 +63,6 @@ func TestPgSQLGooseDB(t *testing.T) { }) Convey("if one doesn't exist", func() { - - expectedErrorMessage := "No database versions found" - // Database setup rs := sqlmock.NewRows(rowFieldsForVersionID) mock.ExpectQuery(selectFromDBVersionWhere). @@ -74,7 +71,7 @@ func TestPgSQLGooseDB(t *testing.T) { Convey("there should be an error", func() { repository, _ := NewPostgresGooseDBVersionRepository(db) _, err := repository.GetCurrentVersion() - So(err, ShouldResemble, errors.New(expectedErrorMessage)) + So(err, ShouldResemble, custom_errors.ErrNoDatabaseVersionsFound) dberr := mock.ExpectationsWereMet() So(dberr, ShouldBeNil) @@ -82,9 +79,6 @@ func TestPgSQLGooseDB(t *testing.T) { }) Convey("if there is a problem talking to the database", func() { - - expectedErrorMessage := fmt.Sprintf("Error trying to get current database version: %s", "error") - // Database setup mock.ExpectQuery(selectFromDBVersionWhere). WillReturnError(errors.New("error")) @@ -92,7 +86,7 @@ func TestPgSQLGooseDB(t *testing.T) { Convey("there should be an error", func() { repository, _ := NewPostgresGooseDBVersionRepository(db) _, err := repository.GetCurrentVersion() - So(err, ShouldResemble, errors.New(expectedErrorMessage)) + So(err, ShouldResemble, custom_errors.ErrGettingCurrentVersion(errors.New("error"))) dberr := mock.ExpectationsWereMet() So(dberr, ShouldBeNil) diff --git a/src/jetstream/setup_console.go b/src/jetstream/setup_console.go index 5416b0b805..fca48fad3f 100644 --- a/src/jetstream/setup_console.go +++ b/src/jetstream/setup_console.go @@ -1,13 +1,13 @@ package main import ( + "crypto/x509" "errors" "fmt" "net/http" "net/url" "regexp" "strconv" - "strings" "github.com/govau/cf-common/env" "github.com/labstack/echo/v4" @@ -93,7 +93,8 @@ func (p *portalProxy) setupGetAvailableScopes(c echo.Context) error { errInfo, ok := err.(api.ErrHTTPRequest) if ok { if errInfo.Status == 0 { - if strings.Contains(errInfo.Error(), "x509: certificate") { + var certError *x509.CertificateInvalidError + if errors.As(err, certError) { return api.NewHTTPShadowError( http.StatusBadRequest, "Could not connect to the UAA - Certificate error - check Skip SSL validation setting",