cli: wrap errors

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/3146
GitOrigin-RevId: 5dd78bf9145d3bfc9ff4281239d849e796a36246
This commit is contained in:
Aravind K P 2021-12-15 23:24:47 +05:30 committed by hasura-bot
parent 37ecb0e3b2
commit 96cfacb58b
15 changed files with 195 additions and 90 deletions

View File

@ -53,7 +53,6 @@ import (
"github.com/hasura/graphql-engine/cli/v2/telemetry"
"github.com/hasura/graphql-engine/cli/v2/util"
"github.com/hasura/graphql-engine/cli/v2/version"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
"github.com/subosito/gotenv"
@ -204,7 +203,7 @@ func (c *ServerConfig) GetHasuraInternalServerConfig() error {
client := http.Client{Timeout: 30 * time.Second}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return errors.Wrap(err, "error fetching config from server")
return fmt.Errorf("error fetching config from server: %w", err)
}
if c.AdminSecret != "" {
@ -307,10 +306,10 @@ func (s *ServerConfig) SetTLSConfig() error {
certPath, _ := filepath.Abs(s.CAPath)
cert, err := ioutil.ReadFile(certPath)
if err != nil {
return errors.Errorf("error reading CA %s", s.CAPath)
return fmt.Errorf("error reading CA %s: %w", s.CAPath, err)
}
if ok := rootCAs.AppendCertsFromPEM(cert); !ok {
return errors.Errorf("Unable to append given CA cert.")
return fmt.Errorf("unable to append given CA cert")
}
s.TLSConfig = &tls.Config{
RootCAs: rootCAs,
@ -516,7 +515,7 @@ func (ec *ExecutionContext) Prepare() error {
// setup global config
err := ec.setupGlobalConfig()
if err != nil {
return errors.Wrap(err, "setting up global config failed")
return fmt.Errorf("setting up global config failed: %w", err)
}
if !ec.proPluginVersionValidated {
@ -554,7 +553,7 @@ func (ec *ExecutionContext) SetupPlugins() error {
base := filepath.Join(ec.GlobalConfigDir, "plugins")
base, err := filepath.Abs(base)
if err != nil {
return errors.Wrap(err, "cannot get absolute path")
return fmt.Errorf("cannot get absolute path: %w", err)
}
ec.PluginsConfig = plugins.New(base)
ec.PluginsConfig.Logger = ec.Logger
@ -594,7 +593,7 @@ func (ec *ExecutionContext) SetupCodegenAssetsRepo() error {
base := filepath.Join(ec.GlobalConfigDir, util.ActionsCodegenDirName)
base, err := filepath.Abs(base)
if err != nil {
return errors.Wrap(err, "cannot get absolute path")
return fmt.Errorf("cannot get absolute path: %w", err)
}
ec.CodegenAssetsRepo = util.NewGitUtil(util.ActionsCodegenRepoURI, base, "")
ec.CodegenAssetsRepo.Logger = ec.Logger
@ -621,7 +620,7 @@ func (ec *ExecutionContext) Validate() error {
// load .env file
err = ec.loadEnvfile()
if err != nil {
return errors.Wrap(err, "loading .env file failed")
return fmt.Errorf("loading .env file failed: %w", err)
}
// set names of config file
@ -630,7 +629,7 @@ func (ec *ExecutionContext) Validate() error {
// read config and parse the values into Config
err = ec.readConfig()
if err != nil {
return errors.Wrap(err, "cannot read config")
return fmt.Errorf("cannot read config: %w", err)
}
// set name of migration directory
@ -638,7 +637,7 @@ func (ec *ExecutionContext) Validate() error {
if _, err := os.Stat(ec.MigrationDir); os.IsNotExist(err) {
err = os.MkdirAll(ec.MigrationDir, os.ModePerm)
if err != nil {
return errors.Wrap(err, "cannot create migrations directory")
return fmt.Errorf("cannot create migrations directory: %w", err)
}
}
@ -646,7 +645,7 @@ func (ec *ExecutionContext) Validate() error {
if _, err := os.Stat(ec.SeedsDirectory); os.IsNotExist(err) {
err = os.MkdirAll(ec.SeedsDirectory, os.ModePerm)
if err != nil {
return errors.Wrap(err, "cannot create seeds directory")
return fmt.Errorf("cannot create seeds directory: %w", err)
}
}
@ -672,7 +671,7 @@ func (ec *ExecutionContext) Validate() error {
if _, err := os.Stat(ec.MetadataDir); os.IsNotExist(err) && !(len(ec.MetadataFile) > 0) {
err = os.MkdirAll(ec.MetadataDir, os.ModePerm)
if err != nil {
return errors.Wrap(err, "cannot create metadata directory")
return fmt.Errorf("cannot create metadata directory: %w", err)
}
}
}
@ -700,13 +699,13 @@ func (ec *ExecutionContext) Validate() error {
// get version from the server and match with the cli version
err = ec.checkServerVersion()
if err != nil {
return errors.Wrap(err, "version check")
return fmt.Errorf("version check: %w", err)
}
// get the server feature flags
err = ec.Version.GetServerFeatureFlags()
if err != nil {
return errors.Wrap(err, "error in getting server feature flags")
return fmt.Errorf("error in getting server feature flags %w", err)
}
var headers map[string]string
if ec.Config.AdminSecret != "" {
@ -762,9 +761,9 @@ func (ec *ExecutionContext) Validate() error {
}
var state *util.ServerState
if ec.HasMetadataV3 {
state = util.GetServerState(ec.Config.GetV1MetadataEndpoint(), ec.Config.ServerConfig.AdminSecret, ec.Config.ServerConfig.TLSConfig, ec.HasMetadataV3, ec.Logger)
state = util.GetServerState(httpClient, ec.Config.GetV1MetadataEndpoint(), ec.HasMetadataV3, ec.Logger)
} else {
state = util.GetServerState(ec.Config.GetV1QueryEndpoint(), ec.Config.ServerConfig.AdminSecret, ec.Config.ServerConfig.TLSConfig, ec.HasMetadataV3, ec.Logger)
state = util.GetServerState(httpClient, ec.Config.GetV1QueryEndpoint(), ec.HasMetadataV3, ec.Logger)
}
ec.ServerUUID = state.UUID
ec.Telemetry.ServerUUID = ec.ServerUUID
@ -776,7 +775,7 @@ func (ec *ExecutionContext) Validate() error {
func (ec *ExecutionContext) checkServerVersion() error {
v, err := version.FetchServerVersion(ec.Config.ServerConfig.GetVersionEndpoint(), ec.Config.ServerConfig.HTTPClient)
if err != nil {
return errors.Wrap(err, "failed to get version from server")
return fmt.Errorf("failed to get version from server: %w", err)
}
ec.Version.SetServerVersion(v)
ec.Telemetry.ServerVersion = ec.Version.GetServerVersion()
@ -837,7 +836,7 @@ func (ec *ExecutionContext) readConfig() error {
v.AddConfigPath(ec.ExecutionDirectory)
err := v.ReadInConfig()
if err != nil {
return errors.Wrap(err, "cannot read config from file/env")
return fmt.Errorf("cannot read config from file/env: %w", err)
}
adminSecret := v.GetString("admin_secret")
if adminSecret == "" {
@ -881,7 +880,7 @@ func (ec *ExecutionContext) readConfig() error {
}
err = ec.Config.ServerConfig.ParseEndpoint()
if err != nil {
return errors.Wrap(err, "unable to parse server endpoint")
return fmt.Errorf("unable to parse server endpoint: %w", err)
}
// this populates the ec.Config.ServerConfig.HasuraServerInternalConfig
@ -893,7 +892,7 @@ func (ec *ExecutionContext) readConfig() error {
err = ec.Config.ServerConfig.SetTLSConfig()
if err != nil {
return errors.Wrap(err, "setting up TLS config failed")
return fmt.Errorf("setting up TLS config failed: %w", err)
}
return ec.Config.ServerConfig.SetHTTPClient()
}

View File

@ -71,7 +71,7 @@ func (o *actionsCreateOptions) run() error {
o.EC.Spin("Deriving a Hasura operation...")
introSchema, err = o.EC.APIClient.V1Graphql.GetIntrospectionSchema()
if err != nil {
return errors.Wrap(err, "error in fetching introspection schema")
return fmt.Errorf("error in fetching introspection schema: %w", err)
}
o.EC.Spinner.Stop()
}

View File

@ -12,7 +12,6 @@ import (
goyaml "github.com/goccy/go-yaml"
"github.com/hasura/graphql-engine/cli/v2"
"github.com/hasura/graphql-engine/cli/v2/internal/projectmetadata"
"github.com/pkg/errors"
)
type MetadataModeHandler interface {
@ -39,11 +38,11 @@ func (m *metadataModeDirectoryHandler) Export(o *MetadataExportOptions) error {
files, err := metadataHandler.ExportMetadata()
o.EC.Spinner.Stop()
if err != nil {
return errors.Wrap(err, "failed to export metadata")
return fmt.Errorf("failed to export metadata: %w", err)
}
err = metadataHandler.WriteMetadata(files)
if err != nil {
return errors.Wrap(err, "cannot write metadata to project")
return fmt.Errorf("cannot write metadata to project: %w", err)
}
return nil
}

View File

@ -6,7 +6,6 @@ import (
"github.com/hasura/graphql-engine/cli/v2/internal/projectmetadata"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/hasura/graphql-engine/cli/v2"
@ -27,7 +26,7 @@ func newMetadataInconsistencyListCmd(ec *cli.ExecutionContext) *cobra.Command {
err := opts.run()
opts.EC.Spinner.Stop()
if err != nil {
return errors.Wrap(err, "failed to list inconsistent metadata")
return fmt.Errorf("failed to list inconsistent metadata: %w", err)
}
if opts.isConsistent {
opts.EC.Logger.Println("metadata is consistent")

View File

@ -6,7 +6,6 @@ import (
"github.com/hasura/graphql-engine/cli/v2"
"github.com/hasura/graphql-engine/cli/v2/internal/projectmetadata"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -44,7 +43,7 @@ func (o *MetadataReloadOptions) runWithInfo() error {
err := o.run()
o.EC.Spinner.Stop()
if err != nil {
return errors.Wrap(err, "failed to reload metadata")
return fmt.Errorf("failed to reload metadata: %w", err)
}
o.EC.Logger.Info("Metadata reloaded")
icListOpts := &metadataInconsistencyListOptions{
@ -52,7 +51,7 @@ func (o *MetadataReloadOptions) runWithInfo() error {
}
err = icListOpts.read(projectmetadata.NewHandlerFromEC(icListOpts.EC))
if err != nil {
return fmt.Errorf("failed to read metadata status: %v", err)
return fmt.Errorf("failed to read metadata status: %w", err)
}
if icListOpts.isConsistent {
icListOpts.EC.Logger.Infoln("Metadata is consistent")
@ -67,7 +66,7 @@ func (o *MetadataReloadOptions) run() error {
metadataHandler := projectmetadata.NewHandlerFromEC(o.EC)
_, err = metadataHandler.ReloadMetadata()
if err != nil {
return errors.Wrap(err, "Cannot reload metadata")
return fmt.Errorf("cannot reload metadata: %w", err)
}
return nil
}

View File

@ -198,7 +198,7 @@ func (o *MigrateApplyOptions) Apply() (chan MigrateApplyResult, error) {
// if so skip this
return "", fmt.Errorf("skipping applying migrations on database %s, encountered: \n%s", o.Source.Name, e.Error())
} else if err != nil {
return "", fmt.Errorf("skipping applying migrations on database %s, encountered: \n%v", o.Source.Name, err)
return "", fmt.Errorf("skipping applying migrations on database %s, encountered: \n%w", o.Source.Name, err)
}
return "", nil
}

View File

@ -19,7 +19,7 @@ import (
func YamlDiff(fromFile, toFile ytbx.InputFile, writer io.Writer, fileName string) (int, error) {
report, err := dyff.CompareInputFiles(fromFile, toFile, dyff.IgnoreOrderChanges(true))
if err != nil {
return -1, fmt.Errorf("error while getting diff: %v", err)
return -1, fmt.Errorf("error while getting diff: %w", err)
}
reportWriter := &dyff.HumanReport{
Report: report,
@ -32,7 +32,7 @@ func YamlDiff(fromFile, toFile ytbx.InputFile, writer io.Writer, fileName string
fmt.Fprintf(writer, "%s\n", fileName)
err = reportWriter.WriteReport(writer)
if err != nil {
return -1, fmt.Errorf("error while printing diff: %v", err)
return -1, fmt.Errorf("error while printing diff: %w", err)
}
}
return len(report.Diffs), nil

View File

@ -135,7 +135,7 @@ func DefaultGetFiles(yamlFile string) ([]string, error) {
files = append(files, nodeFiles...)
}
} else {
return nil, fmt.Errorf("finding child files in failed: %v", err)
return nil, fmt.Errorf("finding child files in failed: %w", err)
}
}

View File

@ -182,7 +182,7 @@ func SquashCmd(m *migrate.Migrate, from uint64, to int64, version int64, name, d
err = createOptions.Create()
if err != nil {
return versions, errors.Wrap(err, "cannot create migration")
return versions, fmt.Errorf("cannot create migration: %w", err)
}
return

View File

@ -142,7 +142,7 @@ func NewHasuraError(data []byte, isCmd bool) error {
var herror HasuraError
err := json.Unmarshal(data, &herror)
if err != nil {
return fmt.Errorf("failed parsing json: %v; response from API: %s", err, string(data))
return fmt.Errorf("failed parsing json: %w; response from API: %s", err, string(data))
}
return herror
default:

View File

@ -17,7 +17,6 @@ import (
migratedb "github.com/hasura/graphql-engine/cli/v2/migrate/database"
"github.com/hasura/graphql-engine/cli/v2"
"github.com/pkg/errors"
)
// MultiError holds multiple errors.
@ -166,7 +165,7 @@ func NewMigrate(ec *cli.ExecutionContext, isCmd bool, sourceName string, sourceK
t, err := New(opts)
if err != nil {
return nil, errors.Wrap(err, "cannot create migrate instance")
return nil, fmt.Errorf("cannot create migrate instance: %w", err)
}
if ec.Config.Version >= cli.V2 {
t.databaseDrv.EnableCheckMetadataConsistency(true)

View File

@ -10,7 +10,6 @@ import (
"testing"
"github.com/hasura/graphql-engine/cli/v2/internal/hasura"
"github.com/hasura/graphql-engine/cli/v2/pkg/migrate"
"github.com/stretchr/testify/require"
@ -247,7 +246,7 @@ func TestProjectMetadata_Reload(t *testing.T) {
name string
fields fields
want string
wantErr bool
wantErr require.ErrorAssertionFunc
}{
{
"can reload metadata",
@ -256,21 +255,61 @@ func TestProjectMetadata_Reload(t *testing.T) {
endpointString: hgeEndpoint,
},
`{"message": "success"}`,
false,
require.NoError,
},
// TODO: automate the following tests
// following tests are currently ran manually by making use of https://github.com/Shopify/toxiproxy
//{
// "can return expected error type when graphql engine connections fail",
// fields{
// projectDirectory: "testdata/projectv3",
// endpointString: "http://localhost:12345/something",
// },
// `{"message": "success"}`,
// func(t require.TestingT, err error, i ...interface{}) {
// var e *url.Error
// require.Truef(t, errors.As(err, &e), "expected err to be an instance of %v but got %v", reflect.TypeOf(&url.Error{}), reflect.TypeOf(err))
// },
//},
// config.json
// [
// {
// "name": "hasura",
// "listen": "[::]:18080",
// "upstream": "localhost:8080",
// "enabled": true
// }
// ]
//
// 1. Simulate reset peer
// $ toxiproxy-cli toxic add -t reset_peer hasura
// 2. Simulate timeout
// $ toxiproxy-cli toxic add -t timeout -a timeout=1 hasura
//{
// "return expect error type when graphql engine connections reset",
// fields{
// projectDirectory: "testdata/projectv3",
// endpointString: "http://localhost:18080",
// },
// `{"message": "success"}`,
// func(t require.TestingT, err error, i ...interface{}) {
// var e *url.Error
// require.Truef(t, errors.As(err, &e), "expected err to be an instance of %v but got %v", reflect.TypeOf(&url.Error{}), reflect.TypeOf(err))
// },
//},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p, err := NewProjectMetadata(tt.fields.projectDirectory, WithEndpoint(hgeEndpoint), WithAdminSecret(testutil.TestAdminSecret))
require.NoError(t, err)
p, err := NewProjectMetadata(tt.fields.projectDirectory, WithEndpoint(tt.fields.endpointString), WithAdminSecret(testutil.TestAdminSecret))
tt.wantErr(t, err)
if p != nil {
got, err := p.Reload()
if tt.wantErr {
require.Error(t, err)
}
require.NoError(t, err)
tt.wantErr(t, err)
gotb, err := ioutil.ReadAll(got)
require.NoError(t, err)
require.JSONEq(t, tt.want, string(gotb))
}
})
}
}

View File

@ -212,7 +212,17 @@ func TestProjectMigrate_Apply_Configv2(t *testing.T) {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, tt.want, got)
for idx, want := range tt.want {
if idx >= len(got) {
t.Errorf("expected to got to have equal number of elements: want %v got %v", len(tt.want), len(got))
}
if len(want.Message) > 0 {
assert.Equal(t, want.Message, got[idx].Message)
}
if want.Error != nil {
assert.Equal(t, want.Error.Error(), got[idx].Error.Error())
}
}
}
})
}

View File

@ -1,13 +1,15 @@
package util
import (
"crypto/tls"
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"path"
"github.com/parnurzeal/gorequest"
"github.com/hasura/graphql-engine/cli/v2/internal/httpc"
"github.com/sirupsen/logrus"
)
@ -23,40 +25,42 @@ type hdbVersion struct {
}
// GetServerState queries a server for the state.
func GetServerState(endpoint string, adminSecret string, config *tls.Config, hasMetadataV3 bool, log *logrus.Logger) *ServerState {
func GetServerState(client *httpc.Client, endpoint string, hasMetadataV3 bool, log *logrus.Logger) *ServerState {
state := &ServerState{
UUID: "00000000-0000-0000-0000-000000000000",
}
if hasMetadataV3 {
payload := `
payload := []byte(`
{
"type": "get_catalog_state",
"args": {}
}
`
req := gorequest.New()
if config != nil {
req.TLSClientConfig(config)
}
req.Post(endpoint).Send(payload)
req.Set("X-Hasura-Admin-Secret", adminSecret)
`)
var r struct {
ID string `json:"id"`
}
_, _, errs := req.EndStruct(&r)
if len(errs) != 0 {
log.Debugf("server state: errors: %v", errs)
var body interface{}
err := json.Unmarshal(payload, &body)
if err != nil {
log.Debugf("unmarshalling json request to construct server state failed: %v", err)
return state
}
req, err := client.NewRequest(http.MethodPost, endpoint, body)
if err != nil {
log.Debugf("constructing http request to construct server state failed: %v", err)
return state
}
_, err = client.Do(context.Background(), req, &r)
if err != nil {
log.Debugf("http request to construct server state failed: %v", err)
return state
}
state.UUID = r.ID
} else {
state := &ServerState{
UUID: "00000000-0000-0000-0000-000000000000",
}
payload := `{
payload := []byte(`{
"type": "select",
"args": {
"table": {
@ -68,30 +72,29 @@ func GetServerState(endpoint string, adminSecret string, config *tls.Config, has
"cli_state"
]
}
}`
req := gorequest.New()
if config != nil {
req.TLSClientConfig(config)
}`)
var body interface{}
err := json.Unmarshal(payload, &body)
if err != nil {
log.Debugf("unmarshalling json request to construct server state failed: %v", err)
return state
}
req, err := client.NewRequest(http.MethodPost, endpoint, body)
if err != nil {
log.Debugf("constructing http request to construct server state failed: %v", err)
return state
}
req.Post(endpoint).Send(payload)
req.Set("X-Hasura-Admin-Secret", adminSecret)
var r []hdbVersion
_, _, errs := req.EndStruct(&r)
if len(errs) != 0 {
log.Debugf("server state: errors: %v", errs)
_, err = client.Do(context.Background(), req, &r)
if err != nil {
log.Debugf("http request to construct server state failed: %v", err)
return state
}
if len(r) != 1 {
log.Debugf("invalid response: %v", r)
return state
}
if len(r) >= 1 {
state.UUID = r[0].UUID
state.CLIState = r[0].CLIState
}
}
return state
}
@ -104,7 +107,7 @@ func GetServerStatus(endpoint string) (err error) {
uri.Path = path.Join(uri.Path, "healthz")
resp, err := http.Get(uri.String())
if err != nil {
return fmt.Errorf("making http request failed: %s", err.Error())
return fmt.Errorf("making http request failed: %w", err)
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("request failed: url: %s status code: %v status: %s", uri.String(), resp.StatusCode, resp.Status)

58
cli/util/server_test.go Normal file
View File

@ -0,0 +1,58 @@
package util
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/hasura/graphql-engine/cli/v2/internal/httpc"
"github.com/hasura/graphql-engine/cli/v2/internal/testutil"
"github.com/sirupsen/logrus"
)
func TestGetServerState(t *testing.T) {
portV13, teardownV133 := testutil.StartHasura(t, "hasura/graphql-engine:v1.3.3")
hgeEndpointV133 := fmt.Sprintf("http://localhost:%s", portV13)
defer teardownV133()
port, teardown := testutil.StartHasura(t, testutil.HasuraDockerImage)
hgeEndpoint := fmt.Sprintf("http://localhost:%s", port)
defer teardown()
type args struct {
client *httpc.Client
endpoint string
hasMetadataV3 bool
log *logrus.Logger
}
tests := []struct {
name string
args args
}{
{
"can generate server state for v1.x",
args{
testutil.NewHttpcClient(t, portV13, nil),
fmt.Sprintf("%v/v1/query", hgeEndpointV133),
false,
logrus.New(),
},
},
{
"can generate server state for latest",
args{
testutil.NewHttpcClient(t, port, nil),
fmt.Sprintf("%v/v1/metadata", hgeEndpoint),
true,
logrus.New(),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := GetServerState(tt.args.client, tt.args.endpoint, tt.args.hasMetadataV3, tt.args.log)
assert.Truef(t, got.UUID != "00000000-0000-0000-0000-000000000000" && got.UUID != "", "expected server UUID to be set got: ", got.UUID)
})
}
}