From 9c2dd6f820bb78571584336f577b37888f6fd326 Mon Sep 17 00:00:00 2001 From: Aravind Shankar Date: Mon, 9 Jul 2018 14:48:54 +0530 Subject: [PATCH 1/9] [cli] handle server enpoints that contains a url path --- cli/cli.go | 18 +++++++++-- cli/commands/console.go | 33 ++++++------------- cli/commands/console_test.go | 6 +++- cli/commands/metadata_apply.go | 13 ++------ cli/commands/metadata_apply_test.go | 8 +++-- cli/commands/metadata_export.go | 13 ++------ cli/commands/metadata_export_test.go | 8 +++-- cli/commands/metadata_reset.go | 12 ++----- cli/commands/metadata_reset_test.go | 8 +++-- cli/commands/migrate_apply.go | 12 ++----- cli/commands/migrate_apply_test.go | 20 ++++++++---- cli/commands/migrate_status.go | 11 ++----- cli/commands/migrate_status_test.go | 13 +++++--- cli/commands/migrate_test.go | 13 ++++++-- cli/migrate/api/metadata.go | 8 ++--- cli/migrate/api/migrate.go | 26 ++++----------- cli/migrate/api/settings.go | 4 ++- cli/migrate/cmd/commands.go | 7 ++++ cli/util/migrate.go | 48 ++++++++++++++++++++++++---- 19 files changed, 149 insertions(+), 132 deletions(-) diff --git a/cli/cli.go b/cli/cli.go index 8eaf1425efd3b..1b852e3146a89 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -9,6 +9,7 @@ package cli import ( "bytes" + "net/url" "os" "path/filepath" "regexp" @@ -50,6 +51,18 @@ type HasuraGraphQLConfig struct { Endpoint string `json:"endpoint"` // AccessKey (optional) required to query the endpoint AccessKey string `json:"access_key,omitempty"` + + ParsedEndpoint *url.URL +} + +// ParseEndpoint ensures the endpoint is valid. +func (hgc *HasuraGraphQLConfig) ParseEndpoint() error { + nurl, err := url.Parse(hgc.Endpoint) + if err != nil { + return err + } + hgc.ParsedEndpoint = nurl + return nil } // ExecutionContext contains various contextual information required by the cli @@ -204,15 +217,14 @@ func (ec *ExecutionContext) readConfig() error { v.AddConfigPath(ec.ExecutionDirectory) err := v.ReadInConfig() if err != nil { - ec.Logger.WithError(err).Error("cannot read config file") return errors.Wrap(err, "cannor read config file") } - ec.Config = &HasuraGraphQLConfig{ Endpoint: v.GetString("endpoint"), AccessKey: v.GetString("access_key"), } - return nil + err = ec.Config.ParseEndpoint() + return err } // setupSpinner creates a default spinner if the context does not already have diff --git a/cli/commands/console.go b/cli/commands/console.go index c72d9c9f476bc..729b3a0c73043 100644 --- a/cli/commands/console.go +++ b/cli/commands/console.go @@ -4,8 +4,6 @@ import ( "fmt" "net/http" "net/url" - "path/filepath" - "runtime" "sync" "github.com/fatih/color" @@ -86,12 +84,7 @@ func (o *consoleOptions) run() error { r, } - u, err := url.Parse(o.EC.Config.Endpoint) - if err != nil { - return errors.Wrap(err, "cannot parse endpoint as url") - } - - router.setRoutes(u.Host, o.EC.Config.AccessKey, o.EC.MigrationDir) + router.setRoutes(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey, o.EC.MigrationDir) if o.EC.Version == nil { return errors.New("cannot validate version, object is nil") @@ -105,7 +98,7 @@ func (o *consoleOptions) run() error { "apiHost": "http://" + o.Address, "apiPort": o.APIPort, "cliVersion": o.EC.Version.GetCLIVersion(), - "dataApiUrl": o.EC.Config.Endpoint, + "dataApiUrl": o.EC.Config.ParsedEndpoint.String(), "dataApiVersion": "", "accessKey": o.EC.Config.AccessKey, "assetsVersion": consoleAssetsVersion, @@ -158,14 +151,14 @@ type consoleRouter struct { *gin.Engine } -func (router *consoleRouter) setRoutes(host, accessKey, migrationDir string) { +func (router *consoleRouter) setRoutes(nurl *url.URL, accessKey, migrationDir string) { apis := router.Group("/apis") { // Migrate api endpoints and middleware migrateAPIs := apis.Group("/migrate") { migrateAPIs.Use(setFilePath(migrationDir)) - migrateAPIs.Use(setDataPath(host, accessKey)) + migrateAPIs.Use(setDataPath(nurl, accessKey)) settingsAPIs := migrateAPIs.Group("/settings") { settingsAPIs.Any("", api.SettingsAPI) @@ -176,19 +169,16 @@ func (router *consoleRouter) setRoutes(host, accessKey, migrationDir string) { metadataAPIs := apis.Group("/metadata") { metadataAPIs.Use(setFilePath(migrationDir)) - metadataAPIs.Use(setDataPath(host, accessKey)) + metadataAPIs.Use(setDataPath(nurl, accessKey)) metadataAPIs.Any("", api.MetadataAPI) } } } -func setDataPath(hostName, accessKey string) gin.HandlerFunc { +func setDataPath(nurl *url.URL, accessKey string) gin.HandlerFunc { return func(c *gin.Context) { - host := url.URL{ - Scheme: "hasuradb", - User: url.UserPassword("admin", accessKey), - Host: hostName, - } + host := util.GetDataPath(nurl, accessKey) + c.Set("dbpath", host) c.Next() } @@ -196,11 +186,8 @@ func setDataPath(hostName, accessKey string) gin.HandlerFunc { func setFilePath(dir string) gin.HandlerFunc { return func(c *gin.Context) { - if runtime.GOOS == "windows" { - c.Set("filedir", "file:///"+filepath.Clean(dir)) - } else { - c.Set("filedir", "file://"+filepath.Clean(dir)) - } + host := util.GetFilePath(dir) + c.Set("filedir", host) c.Next() } } diff --git a/cli/commands/console_test.go b/cli/commands/console_test.go index 1ba2ba0e1c7a9..34d089922e4a3 100644 --- a/cli/commands/console_test.go +++ b/cli/commands/console_test.go @@ -29,6 +29,10 @@ func TestConsoleCmd(t *testing.T) { DontOpenBrowser: true, } opts.EC.Spinner.Writer = &fake.FakeWriter{} + err := opts.EC.Config.ParseEndpoint() + if err != nil { + t.Fatal(err) + } go func() { t.Log("waiting for console to start") @@ -38,7 +42,7 @@ func TestConsoleCmd(t *testing.T) { opts.WG.Done() opts.WG.Done() }() - err := opts.run() + err = opts.run() if err != nil { t.Fatalf("failed running console: %v", err) } diff --git a/cli/commands/metadata_apply.go b/cli/commands/metadata_apply.go index 3e3aa50524a61..7356c94c317e1 100644 --- a/cli/commands/metadata_apply.go +++ b/cli/commands/metadata_apply.go @@ -1,11 +1,8 @@ package commands import ( - "net/url" - "github.com/hasura/graphql-engine/cli" "github.com/hasura/graphql-engine/cli/util" - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -36,12 +33,6 @@ type metadataApplyOptions struct { } func (o *metadataApplyOptions) run() error { - dbURL, err := url.Parse(o.EC.Config.Endpoint) - if err != nil { - return errors.Wrap(err, "error parsing Endpoint") - } - - dbURL.Scheme = "hasuradb" - dbURL.User = url.UserPassword("admin", o.EC.Config.AccessKey) - return util.ExecuteMetadata(o.actionType, "file://"+o.EC.MigrationDir, dbURL.String(), o.EC.ExecutionDirectory) + dbURL := util.GetDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) + return util.ExecuteMetadata(o.actionType, "file://"+o.EC.MigrationDir, dbURL, o.EC.ExecutionDirectory) } diff --git a/cli/commands/metadata_apply_test.go b/cli/commands/metadata_apply_test.go index 0e430f6a935c8..5624985dc2cb6 100644 --- a/cli/commands/metadata_apply_test.go +++ b/cli/commands/metadata_apply_test.go @@ -1,6 +1,7 @@ package commands import ( + "net/url" "testing" "time" @@ -9,7 +10,7 @@ import ( "github.com/sirupsen/logrus/hooks/test" ) -func testMetadataApply(t *testing.T, executionDir string, endpoint string) { +func testMetadataApply(t *testing.T, executionDir string, endpoint *url.URL) { logger, _ := test.NewNullLogger() opts := &metadataApplyOptions{ EC: &cli.ExecutionContext{ @@ -17,8 +18,9 @@ func testMetadataApply(t *testing.T, executionDir string, endpoint string) { Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond), ExecutionDirectory: executionDir, Config: &cli.HasuraGraphQLConfig{ - Endpoint: endpoint, - AccessKey: "", + Endpoint: endpoint.String(), + AccessKey: "", + ParsedEndpoint: endpoint, }, }, actionType: "apply", diff --git a/cli/commands/metadata_export.go b/cli/commands/metadata_export.go index 73a3f32249871..d69f31cb8aa25 100644 --- a/cli/commands/metadata_export.go +++ b/cli/commands/metadata_export.go @@ -1,11 +1,8 @@ package commands import ( - "net/url" - "github.com/hasura/graphql-engine/cli" "github.com/hasura/graphql-engine/cli/util" - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -36,12 +33,6 @@ type metadataExportOptions struct { } func (o *metadataExportOptions) run() error { - dbURL, err := url.Parse(o.EC.Config.Endpoint) - if err != nil { - return errors.Wrap(err, "error parsing Endpoint") - } - - dbURL.Scheme = "hasuradb" - dbURL.User = url.UserPassword("admin", o.EC.Config.AccessKey) - return util.ExecuteMetadata(o.actionType, "file://"+o.EC.MigrationDir, dbURL.String(), o.EC.ExecutionDirectory) + dbURL := util.GetDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) + return util.ExecuteMetadata(o.actionType, "file://"+o.EC.MigrationDir, dbURL, o.EC.ExecutionDirectory) } diff --git a/cli/commands/metadata_export_test.go b/cli/commands/metadata_export_test.go index b89007c345ca2..a58034ff6cdd5 100644 --- a/cli/commands/metadata_export_test.go +++ b/cli/commands/metadata_export_test.go @@ -1,6 +1,7 @@ package commands import ( + "net/url" "testing" "time" @@ -9,7 +10,7 @@ import ( "github.com/sirupsen/logrus/hooks/test" ) -func testMetadataExport(t *testing.T, executionDir string, endpoint string) { +func testMetadataExport(t *testing.T, executionDir string, endpoint *url.URL) { logger, _ := test.NewNullLogger() opts := &metadataExportOptions{ EC: &cli.ExecutionContext{ @@ -17,8 +18,9 @@ func testMetadataExport(t *testing.T, executionDir string, endpoint string) { Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond), ExecutionDirectory: executionDir, Config: &cli.HasuraGraphQLConfig{ - Endpoint: endpoint, - AccessKey: "", + Endpoint: endpoint.String(), + AccessKey: "", + ParsedEndpoint: endpoint, }, }, actionType: "export", diff --git a/cli/commands/metadata_reset.go b/cli/commands/metadata_reset.go index a8442c809ae6f..916e1f5f65aaa 100644 --- a/cli/commands/metadata_reset.go +++ b/cli/commands/metadata_reset.go @@ -1,8 +1,6 @@ package commands import ( - "net/url" - "github.com/hasura/graphql-engine/cli" "github.com/hasura/graphql-engine/cli/util" "github.com/pkg/errors" @@ -36,14 +34,8 @@ type metadataResetOptions struct { } func (o *metadataResetOptions) run() error { - dbURL, err := url.Parse(o.EC.Config.Endpoint) - if err != nil { - return errors.Wrap(err, "error parsing Endpoint") - } - - dbURL.Scheme = "hasuradb" - dbURL.User = url.UserPassword("admin", o.EC.Config.AccessKey) - err = util.ExecuteMetadata(o.actionType, "file://"+o.EC.MigrationDir, dbURL.String(), o.EC.ExecutionDirectory) + dbURL := util.GetDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) + err := util.ExecuteMetadata(o.actionType, "file://"+o.EC.MigrationDir, dbURL, o.EC.ExecutionDirectory) if err != nil { return errors.Wrap(err, "Cannot reset metadata") } diff --git a/cli/commands/metadata_reset_test.go b/cli/commands/metadata_reset_test.go index 984ce7346faa8..beac528285a6d 100644 --- a/cli/commands/metadata_reset_test.go +++ b/cli/commands/metadata_reset_test.go @@ -1,6 +1,7 @@ package commands import ( + "net/url" "testing" "time" @@ -9,7 +10,7 @@ import ( "github.com/sirupsen/logrus/hooks/test" ) -func testMetadataReset(t *testing.T, executionDir string, endpoint string) { +func testMetadataReset(t *testing.T, executionDir string, endpoint *url.URL) { logger, _ := test.NewNullLogger() opts := &metadataResetOptions{ EC: &cli.ExecutionContext{ @@ -17,8 +18,9 @@ func testMetadataReset(t *testing.T, executionDir string, endpoint string) { Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond), ExecutionDirectory: executionDir, Config: &cli.HasuraGraphQLConfig{ - Endpoint: endpoint, - AccessKey: "", + Endpoint: endpoint.String(), + AccessKey: "", + ParsedEndpoint: endpoint, }, }, actionType: "reset", diff --git a/cli/commands/migrate_apply.go b/cli/commands/migrate_apply.go index ddd733289ca9a..325aac94e2647 100644 --- a/cli/commands/migrate_apply.go +++ b/cli/commands/migrate_apply.go @@ -1,7 +1,6 @@ package commands import ( - "net/url" "strconv" "github.com/hasura/graphql-engine/cli" @@ -47,15 +46,10 @@ func (o *migrateApplyOptions) run() error { return errors.Wrap(err, "error validating flags") } - dbURL, err := url.Parse(o.EC.Config.Endpoint) - if err != nil { - return errors.Wrap(err, "error parsing endpoint") - } - - dbURL.Scheme = "hasuradb" - dbURL.User = url.UserPassword("admin", o.EC.Config.AccessKey) + dbURL := util.GetDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) + sourceURL := util.GetFilePath(o.EC.MigrationDir) - err = util.ExecuteMigration(migrationType, "file://"+o.EC.MigrationDir, dbURL.String(), step) + err = util.ExecuteMigration(migrationType, sourceURL, dbURL, step) if err != nil { if err == migrate.ErrNoChange { o.EC.Logger.Info("nothing to apply") diff --git a/cli/commands/migrate_apply_test.go b/cli/commands/migrate_apply_test.go index 2bfbd04c68910..218cbf92d6776 100644 --- a/cli/commands/migrate_apply_test.go +++ b/cli/commands/migrate_apply_test.go @@ -2,6 +2,7 @@ package commands import ( "math/rand" + "net/url" "os" "path/filepath" "strconv" @@ -14,7 +15,7 @@ import ( "github.com/stretchr/testify/assert" ) -func testMigrateApply(t *testing.T, endpoint string, migrationsDir string, up string, down string, version string, versionType string) { +func testMigrateApply(t *testing.T, endpoint *url.URL, migrationsDir string, up string, down string, version string, versionType string) { logger, hook := test.NewNullLogger() opts := &migrateApplyOptions{ EC: &cli.ExecutionContext{ @@ -22,8 +23,9 @@ func testMigrateApply(t *testing.T, endpoint string, migrationsDir string, up st Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond), MigrationDir: migrationsDir, Config: &cli.HasuraGraphQLConfig{ - Endpoint: endpoint, - AccessKey: "", + Endpoint: endpoint.String(), + AccessKey: "", + ParsedEndpoint: endpoint, }, }, upMigration: up, @@ -48,8 +50,9 @@ func TestMigrateApplyWithInvalidEndpoint(t *testing.T) { Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond), MigrationDir: filepath.Join(os.TempDir(), "hasura-cli-test-"+strconv.Itoa(rand.Intn(1000))), Config: &cli.HasuraGraphQLConfig{ - Endpoint: ":", - AccessKey: "", + Endpoint: ":", + AccessKey: "", + ParsedEndpoint: &url.URL{}, }, }, } @@ -76,7 +79,12 @@ func TestMigrateApplyWithMultipleFlags(t *testing.T) { downMigration: "2", } - err := opts.run() + err := opts.EC.Config.ParseEndpoint() + if err == nil { + t.Fatalf("expected err not to be nil") + } + + err = opts.run() if err == nil { t.Fatalf("expected err not to be nil") } diff --git a/cli/commands/migrate_status.go b/cli/commands/migrate_status.go index 17f8a97ec113c..6a9e54ce8a2ba 100644 --- a/cli/commands/migrate_status.go +++ b/cli/commands/migrate_status.go @@ -3,7 +3,6 @@ package commands import ( "bytes" "fmt" - "net/url" "text/tabwriter" "github.com/hasura/graphql-engine/cli" @@ -39,14 +38,8 @@ type migrateStatusOptions struct { } func (o *migrateStatusOptions) run() (*migrate.Status, error) { - dbURL, err := url.Parse(o.EC.Config.Endpoint) - if err != nil { - return nil, errors.Wrap(err, "error parsing Endpoint") - } - - dbURL.Scheme = "hasuradb" - dbURL.User = url.UserPassword("admin", o.EC.Config.AccessKey) - status, err := util.ExecuteStatus("file://"+o.EC.MigrationDir, dbURL.String()) + dbURL := util.GetDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) + status, err := util.ExecuteStatus("file://"+o.EC.MigrationDir, dbURL) if err != nil { return nil, errors.Wrap(err, "cannot fetch migrate status") } diff --git a/cli/commands/migrate_status_test.go b/cli/commands/migrate_status_test.go index c27bb955184b5..4dbbb0d055fb0 100644 --- a/cli/commands/migrate_status_test.go +++ b/cli/commands/migrate_status_test.go @@ -2,6 +2,7 @@ package commands import ( "math/rand" + "net/url" "os" "path/filepath" "strconv" @@ -15,7 +16,7 @@ import ( "github.com/stretchr/testify/assert" ) -func testMigrateStatus(t *testing.T, endpoint string, migrationsDir string, expectedStatus *migrate.Status) { +func testMigrateStatus(t *testing.T, endpoint *url.URL, migrationsDir string, expectedStatus *migrate.Status) { logger, _ := test.NewNullLogger() opts := &migrateStatusOptions{ EC: &cli.ExecutionContext{ @@ -23,8 +24,9 @@ func testMigrateStatus(t *testing.T, endpoint string, migrationsDir string, expe Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond), MigrationDir: migrationsDir, Config: &cli.HasuraGraphQLConfig{ - Endpoint: endpoint, - AccessKey: "", + Endpoint: endpoint.String(), + AccessKey: "", + ParsedEndpoint: endpoint, }, }, } @@ -44,8 +46,9 @@ func TestMigrateStatusWithInvalidEndpoint(t *testing.T) { Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond), MigrationDir: filepath.Join(os.TempDir(), "hasura-cli-test-"+strconv.Itoa(rand.Intn(1000))), Config: &cli.HasuraGraphQLConfig{ - Endpoint: ":", - AccessKey: "", + Endpoint: ":", + AccessKey: "", + ParsedEndpoint: &url.URL{}, }, }, } diff --git a/cli/commands/migrate_test.go b/cli/commands/migrate_test.go index 9fb1c15c24a48..68293c098d24f 100644 --- a/cli/commands/migrate_test.go +++ b/cli/commands/migrate_test.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "io/ioutil" + "net/url" "os" "path" "path/filepath" @@ -81,7 +82,10 @@ func testMigrateWithDocker(t *testing.T, migrationsDir, executionDir string) { defer pi.Remove() defer ri.Remove() - endpointURL := fmt.Sprintf("http://%s:%d", ri.Host(), ri.Port()) + endpointURL, err := url.Parse(fmt.Sprintf("http://%s:%d", ri.Host(), ri.Port())) + if err != nil { + t.Fatal(err) + } // Create migration Dir migrationsDir, err := ioutil.TempDir("", "") if err != nil { @@ -101,7 +105,10 @@ func testMigrateWithDocker(t *testing.T, migrationsDir, executionDir string) { } func TestMigrateCmd(t *testing.T) { - endpointURL := os.Getenv("HASURA_GRAPHQL_TEST_ENDPOINT") + endpointURL, err := url.Parse(os.Getenv("HASURA_GRAPHQL_TEST_ENDPOINT")) + if err != nil { + t.Fatal(err) + } // Create migration Dir migrationsDir, err := ioutil.TempDir("", "") if err != nil { @@ -119,7 +126,7 @@ func TestMigrateCmd(t *testing.T) { testMigrate(t, endpointURL, migrationsDir, executionDir) } -func testMigrate(t *testing.T, endpoint, migrationsDir, executionDir string) { +func testMigrate(t *testing.T, endpoint *url.URL, migrationsDir, executionDir string) { // Create 1_create_table_test.up.sql which creates table test mustWriteFile(t, migrationsDir, "1_create_table_test.up.sql", `CREATE TABLE "test"("id" serial NOT NULL, PRIMARY KEY ("id") )`) // Create 1_create_table_test.down.sql which creates table test diff --git a/cli/migrate/api/metadata.go b/cli/migrate/api/metadata.go index a3db1d4ed8d90..3e2c3ea2aba5c 100644 --- a/cli/migrate/api/metadata.go +++ b/cli/migrate/api/metadata.go @@ -20,11 +20,7 @@ func MetadataAPI(c *gin.Context) { return } - sourceURL, err := url.Parse(sourcePtr.(string)) - if err != nil { - c.JSON(http.StatusInternalServerError, &Response{Code: "internal_error", Message: err.Error()}) - return - } + sourceURL := sourcePtr.(url.URL) // Get hasuradb url databasePtr, ok := c.Get("dbpath") @@ -36,7 +32,7 @@ func MetadataAPI(c *gin.Context) { databaseURL := databasePtr.(url.URL) // Create new migrate - t, err := migrate.New(sourcePtr.(string), databaseURL.String(), false) + t, err := migrate.New(sourceURL.String(), databaseURL.String(), false) if err != nil { if strings.HasPrefix(err.Error(), DataAPIError) { c.JSON(http.StatusInternalServerError, &Response{Code: "data_api_error", Message: err.Error()}) diff --git a/cli/migrate/api/migrate.go b/cli/migrate/api/migrate.go index 3e0195c981fb9..7ceb530224e77 100644 --- a/cli/migrate/api/migrate.go +++ b/cli/migrate/api/migrate.go @@ -3,7 +3,6 @@ package api import ( "net/http" "net/url" - "runtime" "strings" "time" @@ -43,16 +42,11 @@ func MigrateAPI(c *gin.Context) { } // Convert to url.URL - databaseURL := databasePtr.(url.URL) - - sourceURL, err := url.Parse(sourcePtr.(string)) - if err != nil { - c.JSON(http.StatusInternalServerError, &Response{Code: "internal_error", Message: err.Error()}) - return - } + databaseURL := databasePtr.(*url.URL) + sourceURL := sourcePtr.(url.URL) // Create new migrate - t, err := migrate.New(sourcePtr.(string), databaseURL.String(), false) + t, err := migrate.New(sourceURL.String(), databaseURL.String(), false) if err != nil { if strings.HasPrefix(err.Error(), DataAPIError) { c.JSON(http.StatusInternalServerError, &Response{Code: "data_api_error", Message: err.Error()}) @@ -74,16 +68,10 @@ func MigrateAPI(c *gin.Context) { } startTime := time.Now() - // Conver to Millisecond + // Convert to Millisecond timestamp := startTime.UnixNano() / int64(time.Millisecond) - var dirPtr string - if runtime.GOOS == "windows" { - dirPtr = strings.Trim(sourceURL.Path, "/") - } else { - dirPtr = "/" + strings.Trim(sourceURL.Path, "/") + "/" - } - err = cmd.CreateCmd(dirPtr, timestamp, request.Name, request.Up) + err = cmd.CreateCmd(sourceURL.Path, timestamp, request.Name, request.Up) if err != nil { c.JSON(http.StatusInternalServerError, &Response{Code: "create_file_error", Message: err.Error()}) return @@ -92,7 +80,7 @@ func MigrateAPI(c *gin.Context) { // Rescan file system err = t.ReScan() if err != nil { - deleteErr := cmd.DeleteCmd(dirPtr, timestamp) + deleteErr := cmd.DeleteCmd(sourceURL.Path, timestamp) if deleteErr != nil { c.JSON(http.StatusInternalServerError, &Response{Code: "delete_file_error", Message: deleteErr.Error()}) return @@ -102,7 +90,7 @@ func MigrateAPI(c *gin.Context) { } if err = t.Migrate(uint64(timestamp), "up"); err != nil { - deleteErr := cmd.DeleteCmd(dirPtr, timestamp) + deleteErr := cmd.DeleteCmd(sourceURL.Path, timestamp) if deleteErr != nil { c.JSON(http.StatusInternalServerError, &Response{Code: "delete_file_error", Message: deleteErr.Error()}) return diff --git a/cli/migrate/api/settings.go b/cli/migrate/api/settings.go index c38bf7c9a2253..cbba7dd0ab9de 100644 --- a/cli/migrate/api/settings.go +++ b/cli/migrate/api/settings.go @@ -21,6 +21,8 @@ func SettingsAPI(c *gin.Context) { return } + sourceURL := sourcePtr.(url.URL) + // Get hasuradb url databasePtr, ok := c.Get("dbpath") if !ok { @@ -31,7 +33,7 @@ func SettingsAPI(c *gin.Context) { databaseURL := databasePtr.(url.URL) // Create new migrate - t, err := migrate.New(sourcePtr.(string), databaseURL.String(), false) + t, err := migrate.New(sourceURL.String(), databaseURL.String(), false) if err != nil { if strings.HasPrefix(err.Error(), DataAPIError) { c.JSON(500, &Response{Code: "data_api_error", Message: err.Error()}) diff --git a/cli/migrate/cmd/commands.go b/cli/migrate/cmd/commands.go index 3a0ba47abd270..90fcc669d4906 100644 --- a/cli/migrate/cmd/commands.go +++ b/cli/migrate/cmd/commands.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "os" "path/filepath" + "runtime" "strings" "github.com/ghodss/yaml" @@ -22,6 +23,9 @@ var ext = []string{sqlFile, yamlFile} func DeleteCmd(dir string, timestamp int64) error { count := 0 + if runtime.GOOS == "windows" { + dir = strings.TrimPrefix(dir, "/") + } fileName := fmt.Sprintf("%v_", timestamp) // scan directory files, err := ioutil.ReadDir(dir) @@ -48,6 +52,9 @@ func DeleteCmd(dir string, timestamp int64) error { } func CreateCmd(dir string, timestamp int64, name string, options ...interface{}) error { + if runtime.GOOS == "windows" { + dir = strings.TrimPrefix(dir, "/") + } fileName := fmt.Sprintf("%v_%v.", timestamp, name) base := filepath.Join(dir, fileName) err := os.MkdirAll(dir, os.ModePerm) diff --git a/cli/util/migrate.go b/cli/util/migrate.go index 87ce66b99d99e..2aba4a614b3b3 100644 --- a/cli/util/migrate.go +++ b/cli/util/migrate.go @@ -4,12 +4,16 @@ import ( "encoding/json" "fmt" "io/ioutil" + "net/url" "path/filepath" + "runtime" "strconv" "github.com/ghodss/yaml" "github.com/hasura/graphql-engine/cli/migrate" mig "github.com/hasura/graphql-engine/cli/migrate/cmd" + _ "github.com/hasura/graphql-engine/cli/migrate/database/hasuradb" + _ "github.com/hasura/graphql-engine/cli/migrate/source/file" "github.com/pkg/errors" ) @@ -25,10 +29,10 @@ func GetValidStepFromString(stepString string) (step int64, err error) { return step, nil } -func ExecuteMigration(cmd, dir, db string, stepOrVersion int64) error { +func ExecuteMigration(cmd string, dir, db *url.URL, stepOrVersion int64) error { var err error - t, err := migrate.New(dir, db, true) + t, err := migrate.New(dir.String(), db.String(), true) if err != nil { return errors.Wrap(err, "cannot create migrate instance") } @@ -54,10 +58,10 @@ func ExecuteMigration(cmd, dir, db string, stepOrVersion int64) error { return err } -func ExecuteMetadata(cmd, dir, db, metadata string) error { +func ExecuteMetadata(cmd, dir string, db *url.URL, metadata string) error { var err error - t, err := migrate.New(dir, db, true) + t, err := migrate.New(dir, db.String(), true) if err != nil { return errors.Wrap(err, "cannot create migrate instance") } @@ -108,10 +112,10 @@ func ExecuteMetadata(cmd, dir, db, metadata string) error { return nil } -func ExecuteStatus(dir, db string) (*migrate.Status, error) { +func ExecuteStatus(dir string, db *url.URL) (*migrate.Status, error) { var err error - t, err := migrate.New(dir, db, true) + t, err := migrate.New(dir, db.String(), true) if err != nil { return nil, errors.Wrap(err, "cannot create migrate instance") } @@ -122,3 +126,35 @@ func ExecuteStatus(dir, db string) (*migrate.Status, error) { } return status, nil } + +func GetDataPath(nurl *url.URL, accessKey string) *url.URL { + host := &url.URL{ + Scheme: "hasuradb", + User: url.UserPassword("admin", accessKey), + Host: nurl.Host, + Path: nurl.Path, + } + q := nurl.Query() + // Set sslmode in query + switch scheme := nurl.Scheme; scheme { + case "https": + q.Set("sslmode", "enable") + default: + q.Set("sslmode", "disable") + } + host.RawQuery = q.Encode() + return host +} + +func GetFilePath(dir string) *url.URL { + host := &url.URL{ + Scheme: "file", + Path: dir, + } + + // Add Prefix / to path if runtime.GOOS equals to windows + if runtime.GOOS == "windows" { + host.Path = "/" + host.Path + } + return host +} From 4a54cfa2b54db33434b2861df7fc9f83cfc243ec Mon Sep 17 00:00:00 2001 From: Aravind Shankar Date: Mon, 9 Jul 2018 15:14:55 +0530 Subject: [PATCH 2/9] [cli] unexport testHasuraDB --- cli/migrate/database/hasuradb/hasuradb_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/migrate/database/hasuradb/hasuradb_test.go b/cli/migrate/database/hasuradb/hasuradb_test.go index 627246b42837f..b4d79deae19b2 100644 --- a/cli/migrate/database/hasuradb/hasuradb_test.go +++ b/cli/migrate/database/hasuradb/hasuradb_test.go @@ -48,7 +48,7 @@ func isReadyRaven(i mt.Instance) bool { return false } -func Test(t *testing.T) { +func testHasuraDB(t *testing.T) { mt.ParallelTest(t, postgresVersions, isReadyPostgres, func(t *testing.T, pi mt.Instance) { for i, v := range ravenVersions { From 8b63f98c9e86478bada14326c490cef21c7747f2 Mon Sep 17 00:00:00 2001 From: Aravind Shankar Date: Mon, 9 Jul 2018 16:09:05 +0530 Subject: [PATCH 3/9] [cli] added util/migrate tests --- cli/util/migrate_test.go | 57 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 cli/util/migrate_test.go diff --git a/cli/util/migrate_test.go b/cli/util/migrate_test.go new file mode 100644 index 0000000000000..4593eb238e5f9 --- /dev/null +++ b/cli/util/migrate_test.go @@ -0,0 +1,57 @@ +package util + +import ( + "io/ioutil" + "net/url" + "os" + "testing" +) + +func TestGetValidStepFromString(t *testing.T) { + tt := []struct { + step string + output int64 + }{ + {step: "1", output: 1}, + {step: "-1", output: -1}, + } + + for i, v := range tt { + step, err := GetValidStepFromString(v.step) + if err != nil { + t.Fatal(err) + } + + if step != v.output { + t.Fatalf("expected step to be %d in index %d but got %d", v.output, i, step) + } + } +} + +func TestGetDataPath(t *testing.T) { + nurl := &url.URL{ + Scheme: "http", + Host: "localhost:8080", + } + expectedURL := "hasuradb://admin:@localhost:8080?sslmode=disable" + dURL := GetDataPath(nurl, "") + + if dURL.String() != expectedURL { + t.Fatalf("expected url to be %s, but got %s", expectedURL, dURL.String()) + } +} + +func TestGetFilePath(t *testing.T) { + // Create migration Dir + migrationsDir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(migrationsDir) + expectedURL := "file://" + migrationsDir + + fURL := GetFilePath(migrationsDir) + if fURL.String() != expectedURL { + t.Fatalf("expected url to be %s, but got %s", expectedURL, fURL.String()) + } +} From 44fe7e311366aa3a82d1684d1c652dad32440c47 Mon Sep 17 00:00:00 2001 From: Aravind Shankar Date: Mon, 9 Jul 2018 16:09:50 +0530 Subject: [PATCH 4/9] [cli] hasuradb driver handle url parsing in open --- cli/migrate/database/hasuradb/hasuradb.go | 26 ++++++++++++++--------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/cli/migrate/database/hasuradb/hasuradb.go b/cli/migrate/database/hasuradb/hasuradb.go index adc4b6ff488b6..ad0dc301fc52b 100644 --- a/cli/migrate/database/hasuradb/hasuradb.go +++ b/cli/migrate/database/hasuradb/hasuradb.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "net/http" nurl "net/url" + "path" "regexp" "strconv" "strings" @@ -90,6 +91,20 @@ func (h *HasuraDB) Open(url string, isCMD bool) (database.Driver, error) { log.Debug(err) return nil, err } + // Use sslMode to set Scheme + values := hurl.Query() + sslMode := values.Get("sslmode") + if sslMode == "enable" { + hurl.Scheme = "https" + } else { + hurl.Scheme = "http" + } + values.Del("sslmode") + hurl.RawQuery = values.Encode() + // Remove UserInfo + hurl.User = nil + // Add v1/query to path + hurl.Path = path.Join(hurl.Path, "v1/query") var user, pass string switch hurl.User { @@ -443,16 +458,7 @@ func (h *HasuraDB) ensureVersionTable() error { func (h *HasuraDB) sendQuery(m interface{}) (resp *http.Response, body []byte, err error) { request := gorequest.New() - newURL := h.config.URL - - newURL.Scheme = "http" - newURL.User = nil - - if !strings.Contains(newURL.Path, "v1/query") { - newURL.Path = SingleJoiningSlash(newURL.Path, "v1/query") - } - - request = request.Post(newURL.String()).Send(m) + request = request.Post(h.config.URL.String()).Send(m) if h.config.UserID != "" { request = request.Set(ACCESS_KEY_HEADER, h.config.UserID) From ae245b01f607f018a85488a097d4d4c916821dba Mon Sep 17 00:00:00 2001 From: Aravind Shankar Date: Mon, 9 Jul 2018 16:11:45 +0530 Subject: [PATCH 5/9] [cli] addPrefix if / not present --- cli/util/migrate.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/util/migrate.go b/cli/util/migrate.go index 2aba4a614b3b3..1188168b5b279 100644 --- a/cli/util/migrate.go +++ b/cli/util/migrate.go @@ -8,6 +8,7 @@ import ( "path/filepath" "runtime" "strconv" + "strings" "github.com/ghodss/yaml" "github.com/hasura/graphql-engine/cli/migrate" @@ -153,7 +154,7 @@ func GetFilePath(dir string) *url.URL { } // Add Prefix / to path if runtime.GOOS equals to windows - if runtime.GOOS == "windows" { + if runtime.GOOS == "windows" && !strings.HasPrefix(host.Path, "/") { host.Path = "/" + host.Path } return host From 2bb4eed2ea951712ba34547a55fa28d01c3d2bf9 Mon Sep 17 00:00:00 2001 From: Aravind Shankar Date: Mon, 9 Jul 2018 16:16:04 +0530 Subject: [PATCH 6/9] [cli] fix migrate api url conversion --- cli/migrate/api/metadata.go | 4 ++-- cli/migrate/api/migrate.go | 2 +- cli/migrate/api/settings.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cli/migrate/api/metadata.go b/cli/migrate/api/metadata.go index 3e2c3ea2aba5c..4d4c680888d4e 100644 --- a/cli/migrate/api/metadata.go +++ b/cli/migrate/api/metadata.go @@ -20,7 +20,7 @@ func MetadataAPI(c *gin.Context) { return } - sourceURL := sourcePtr.(url.URL) + sourceURL := sourcePtr.(*url.URL) // Get hasuradb url databasePtr, ok := c.Get("dbpath") @@ -29,7 +29,7 @@ func MetadataAPI(c *gin.Context) { } // Convert to url.URL - databaseURL := databasePtr.(url.URL) + databaseURL := databasePtr.(*url.URL) // Create new migrate t, err := migrate.New(sourceURL.String(), databaseURL.String(), false) diff --git a/cli/migrate/api/migrate.go b/cli/migrate/api/migrate.go index 7ceb530224e77..c8f05c6f72b8d 100644 --- a/cli/migrate/api/migrate.go +++ b/cli/migrate/api/migrate.go @@ -43,7 +43,7 @@ func MigrateAPI(c *gin.Context) { // Convert to url.URL databaseURL := databasePtr.(*url.URL) - sourceURL := sourcePtr.(url.URL) + sourceURL := sourcePtr.(*url.URL) // Create new migrate t, err := migrate.New(sourceURL.String(), databaseURL.String(), false) diff --git a/cli/migrate/api/settings.go b/cli/migrate/api/settings.go index cbba7dd0ab9de..1c05d65e001e9 100644 --- a/cli/migrate/api/settings.go +++ b/cli/migrate/api/settings.go @@ -21,7 +21,7 @@ func SettingsAPI(c *gin.Context) { return } - sourceURL := sourcePtr.(url.URL) + sourceURL := sourcePtr.(*url.URL) // Get hasuradb url databasePtr, ok := c.Get("dbpath") @@ -30,7 +30,7 @@ func SettingsAPI(c *gin.Context) { } // Convert to url.URL - databaseURL := databasePtr.(url.URL) + databaseURL := databasePtr.(*url.URL) // Create new migrate t, err := migrate.New(sourceURL.String(), databaseURL.String(), false) From 22ce9469d451352a4425d474214c7feab6fefefa Mon Sep 17 00:00:00 2001 From: Aravind Shankar Date: Mon, 9 Jul 2018 16:21:44 +0530 Subject: [PATCH 7/9] [cli] executeMetadata should handle url.URL for migrationDir --- cli/commands/metadata_apply.go | 3 ++- cli/commands/metadata_export.go | 3 ++- cli/commands/metadata_reset.go | 3 ++- cli/util/migrate.go | 4 ++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/cli/commands/metadata_apply.go b/cli/commands/metadata_apply.go index 7356c94c317e1..e4b16b947a005 100644 --- a/cli/commands/metadata_apply.go +++ b/cli/commands/metadata_apply.go @@ -34,5 +34,6 @@ type metadataApplyOptions struct { func (o *metadataApplyOptions) run() error { dbURL := util.GetDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) - return util.ExecuteMetadata(o.actionType, "file://"+o.EC.MigrationDir, dbURL, o.EC.ExecutionDirectory) + fileURL := util.GetFilePath(o.EC.MigrationDir) + return util.ExecuteMetadata(o.actionType, fileURL, dbURL, o.EC.ExecutionDirectory) } diff --git a/cli/commands/metadata_export.go b/cli/commands/metadata_export.go index d69f31cb8aa25..c91196866b6a6 100644 --- a/cli/commands/metadata_export.go +++ b/cli/commands/metadata_export.go @@ -34,5 +34,6 @@ type metadataExportOptions struct { func (o *metadataExportOptions) run() error { dbURL := util.GetDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) - return util.ExecuteMetadata(o.actionType, "file://"+o.EC.MigrationDir, dbURL, o.EC.ExecutionDirectory) + fileURL := util.GetFilePath(o.EC.MigrationDir) + return util.ExecuteMetadata(o.actionType, fileURL, dbURL, o.EC.ExecutionDirectory) } diff --git a/cli/commands/metadata_reset.go b/cli/commands/metadata_reset.go index 916e1f5f65aaa..43a1706f87dd0 100644 --- a/cli/commands/metadata_reset.go +++ b/cli/commands/metadata_reset.go @@ -35,7 +35,8 @@ type metadataResetOptions struct { func (o *metadataResetOptions) run() error { dbURL := util.GetDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) - err := util.ExecuteMetadata(o.actionType, "file://"+o.EC.MigrationDir, dbURL, o.EC.ExecutionDirectory) + fileURL := util.GetFilePath(o.EC.MigrationDir) + err := util.ExecuteMetadata(o.actionType, fileURL, dbURL, o.EC.ExecutionDirectory) if err != nil { return errors.Wrap(err, "Cannot reset metadata") } diff --git a/cli/util/migrate.go b/cli/util/migrate.go index 1188168b5b279..94882d55565fb 100644 --- a/cli/util/migrate.go +++ b/cli/util/migrate.go @@ -59,10 +59,10 @@ func ExecuteMigration(cmd string, dir, db *url.URL, stepOrVersion int64) error { return err } -func ExecuteMetadata(cmd, dir string, db *url.URL, metadata string) error { +func ExecuteMetadata(cmd string, dir, db *url.URL, metadata string) error { var err error - t, err := migrate.New(dir, db.String(), true) + t, err := migrate.New(dir.String(), db.String(), true) if err != nil { return errors.Wrap(err, "cannot create migrate instance") } From eba6d5cedf5cdd33ea02c05b90e0012483a87c92 Mon Sep 17 00:00:00 2001 From: Aravind Shankar Date: Mon, 9 Jul 2018 16:49:55 +0530 Subject: [PATCH 8/9] [cli] move util/migrate.go to command/migrate.go --- cli/commands/console.go | 4 +- cli/commands/metadata_apply.go | 7 +- cli/commands/metadata_export.go | 7 +- cli/commands/metadata_reset.go | 7 +- cli/commands/migrate.go | 142 ++++++++++++++++++++++++++++ cli/commands/migrate_apply.go | 7 +- cli/commands/migrate_status.go | 5 +- cli/util/migrate.go | 161 -------------------------------- cli/util/migrate_test.go | 57 ----------- 9 files changed, 159 insertions(+), 238 deletions(-) delete mode 100644 cli/util/migrate.go delete mode 100644 cli/util/migrate_test.go diff --git a/cli/commands/console.go b/cli/commands/console.go index 729b3a0c73043..f70d3df84165a 100644 --- a/cli/commands/console.go +++ b/cli/commands/console.go @@ -177,7 +177,7 @@ func (router *consoleRouter) setRoutes(nurl *url.URL, accessKey, migrationDir st func setDataPath(nurl *url.URL, accessKey string) gin.HandlerFunc { return func(c *gin.Context) { - host := util.GetDataPath(nurl, accessKey) + host := getDataPath(nurl, accessKey) c.Set("dbpath", host) c.Next() @@ -186,7 +186,7 @@ func setDataPath(nurl *url.URL, accessKey string) gin.HandlerFunc { func setFilePath(dir string) gin.HandlerFunc { return func(c *gin.Context) { - host := util.GetFilePath(dir) + host := getFilePath(dir) c.Set("filedir", host) c.Next() } diff --git a/cli/commands/metadata_apply.go b/cli/commands/metadata_apply.go index e4b16b947a005..1d967860c6fd5 100644 --- a/cli/commands/metadata_apply.go +++ b/cli/commands/metadata_apply.go @@ -2,7 +2,6 @@ package commands import ( "github.com/hasura/graphql-engine/cli" - "github.com/hasura/graphql-engine/cli/util" "github.com/spf13/cobra" ) @@ -33,7 +32,7 @@ type metadataApplyOptions struct { } func (o *metadataApplyOptions) run() error { - dbURL := util.GetDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) - fileURL := util.GetFilePath(o.EC.MigrationDir) - return util.ExecuteMetadata(o.actionType, fileURL, dbURL, o.EC.ExecutionDirectory) + dbURL := getDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) + fileURL := getFilePath(o.EC.MigrationDir) + return executeMetadata(o.actionType, fileURL, dbURL, o.EC.ExecutionDirectory) } diff --git a/cli/commands/metadata_export.go b/cli/commands/metadata_export.go index c91196866b6a6..b75d607a6c81f 100644 --- a/cli/commands/metadata_export.go +++ b/cli/commands/metadata_export.go @@ -2,7 +2,6 @@ package commands import ( "github.com/hasura/graphql-engine/cli" - "github.com/hasura/graphql-engine/cli/util" "github.com/spf13/cobra" ) @@ -33,7 +32,7 @@ type metadataExportOptions struct { } func (o *metadataExportOptions) run() error { - dbURL := util.GetDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) - fileURL := util.GetFilePath(o.EC.MigrationDir) - return util.ExecuteMetadata(o.actionType, fileURL, dbURL, o.EC.ExecutionDirectory) + dbURL := getDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) + fileURL := getFilePath(o.EC.MigrationDir) + return executeMetadata(o.actionType, fileURL, dbURL, o.EC.ExecutionDirectory) } diff --git a/cli/commands/metadata_reset.go b/cli/commands/metadata_reset.go index 43a1706f87dd0..621e8c84e85e2 100644 --- a/cli/commands/metadata_reset.go +++ b/cli/commands/metadata_reset.go @@ -2,7 +2,6 @@ package commands import ( "github.com/hasura/graphql-engine/cli" - "github.com/hasura/graphql-engine/cli/util" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -34,9 +33,9 @@ type metadataResetOptions struct { } func (o *metadataResetOptions) run() error { - dbURL := util.GetDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) - fileURL := util.GetFilePath(o.EC.MigrationDir) - err := util.ExecuteMetadata(o.actionType, fileURL, dbURL, o.EC.ExecutionDirectory) + dbURL := getDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) + fileURL := getFilePath(o.EC.MigrationDir) + err := executeMetadata(o.actionType, fileURL, dbURL, o.EC.ExecutionDirectory) if err != nil { return errors.Wrap(err, "Cannot reset metadata") } diff --git a/cli/commands/migrate.go b/cli/commands/migrate.go index 5369debe51f2c..8226ed450a324 100644 --- a/cli/commands/migrate.go +++ b/cli/commands/migrate.go @@ -1,9 +1,21 @@ package commands import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/url" + "path/filepath" + "runtime" + "strings" + + "github.com/ghodss/yaml" "github.com/hasura/graphql-engine/cli" + "github.com/hasura/graphql-engine/cli/migrate" + mig "github.com/hasura/graphql-engine/cli/migrate/cmd" _ "github.com/hasura/graphql-engine/cli/migrate/database/hasuradb" _ "github.com/hasura/graphql-engine/cli/migrate/source/file" + "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -33,3 +45,133 @@ func NewMigrateCmd(ec *cli.ExecutionContext) *cobra.Command { v.BindPFlag("access_key", f.Lookup("access-key")) return migrateCmd } + +func executeMigration(cmd string, dir, db *url.URL, stepOrVersion int64) error { + var err error + + t, err := migrate.New(dir.String(), db.String(), true) + if err != nil { + return errors.Wrap(err, "cannot create migrate instance") + } + + switch cmd { + case "up": + err = mig.UpCmd(t, stepOrVersion) + case "down": + err = mig.DownCmd(t, stepOrVersion) + case "version": + var direction string + if stepOrVersion >= 0 { + direction = "up" + } else { + direction = "down" + stepOrVersion = -(stepOrVersion) + } + err = mig.GotoCmd(t, uint64(stepOrVersion), direction) + default: + err = fmt.Errorf("Invalid command") + } + + return err +} + +func executeMetadata(cmd string, dir, db *url.URL, metadata string) error { + var err error + + t, err := migrate.New(dir.String(), db.String(), true) + if err != nil { + return errors.Wrap(err, "cannot create migrate instance") + } + + switch cmd { + case "export": + metaData, err := t.ExportMetadata() + if err != nil { + return errors.Wrap(err, "Cannot export metadata") + } + + t, err := json.Marshal(metaData) + if err != nil { + return errors.Wrap(err, "Cannot Marshal metadata") + } + + data, err := yaml.JSONToYAML(t) + if err != nil { + return err + } + + err = ioutil.WriteFile(filepath.Join(metadata, "metadata.yaml"), data, 0644) + if err != nil { + return errors.Wrap(err, "cannot save metadata") + } + case "reset": + err := t.ResetMetadata() + if err != nil { + return errors.Wrap(err, "Cannot reset Metadata") + } + case "apply": + data, err := ioutil.ReadFile(filepath.Join(metadata, "metadata.yaml")) + if err != nil { + return errors.Wrap(err, "cannot read metadata file") + } + + var q interface{} + err = yaml.Unmarshal(data, &q) + if err != nil { + return errors.Wrap(err, "cannot parse metadata file") + } + + err = t.ApplyMetadata(q) + if err != nil { + return errors.Wrap(err, "cannot apply metadata on the database") + } + } + return nil +} + +func executeStatus(dir, db *url.URL) (*migrate.Status, error) { + var err error + + t, err := migrate.New(dir.String(), db.String(), true) + if err != nil { + return nil, errors.Wrap(err, "cannot create migrate instance") + } + + status, err := t.GetStatus() + if err != nil { + return nil, err + } + return status, nil +} + +func getDataPath(nurl *url.URL, accessKey string) *url.URL { + host := &url.URL{ + Scheme: "hasuradb", + User: url.UserPassword("admin", accessKey), + Host: nurl.Host, + Path: nurl.Path, + } + q := nurl.Query() + // Set sslmode in query + switch scheme := nurl.Scheme; scheme { + case "https": + q.Set("sslmode", "enable") + default: + q.Set("sslmode", "disable") + } + host.RawQuery = q.Encode() + return host +} + +func getFilePath(dir string) *url.URL { + host := &url.URL{ + Scheme: "file", + Path: dir, + } + + // Add Prefix / to path if runtime.GOOS equals to windows + if runtime.GOOS == "windows" && !strings.HasPrefix(host.Path, "/") { + host.Path = "/" + host.Path + } + return host +} diff --git a/cli/commands/migrate_apply.go b/cli/commands/migrate_apply.go index 325aac94e2647..983ada573e73c 100644 --- a/cli/commands/migrate_apply.go +++ b/cli/commands/migrate_apply.go @@ -5,7 +5,6 @@ import ( "github.com/hasura/graphql-engine/cli" migrate "github.com/hasura/graphql-engine/cli/migrate" - "github.com/hasura/graphql-engine/cli/util" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -46,10 +45,10 @@ func (o *migrateApplyOptions) run() error { return errors.Wrap(err, "error validating flags") } - dbURL := util.GetDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) - sourceURL := util.GetFilePath(o.EC.MigrationDir) + dbURL := getDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) + sourceURL := getFilePath(o.EC.MigrationDir) - err = util.ExecuteMigration(migrationType, sourceURL, dbURL, step) + err = executeMigration(migrationType, sourceURL, dbURL, step) if err != nil { if err == migrate.ErrNoChange { o.EC.Logger.Info("nothing to apply") diff --git a/cli/commands/migrate_status.go b/cli/commands/migrate_status.go index 6a9e54ce8a2ba..5ab948bb7b56f 100644 --- a/cli/commands/migrate_status.go +++ b/cli/commands/migrate_status.go @@ -38,8 +38,9 @@ type migrateStatusOptions struct { } func (o *migrateStatusOptions) run() (*migrate.Status, error) { - dbURL := util.GetDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) - status, err := util.ExecuteStatus("file://"+o.EC.MigrationDir, dbURL) + dbURL := getDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) + fileURL := getFilePath(o.EC.MigrationDir) + status, err := executeStatus(fileURL, dbURL) if err != nil { return nil, errors.Wrap(err, "cannot fetch migrate status") } diff --git a/cli/util/migrate.go b/cli/util/migrate.go deleted file mode 100644 index 94882d55565fb..0000000000000 --- a/cli/util/migrate.go +++ /dev/null @@ -1,161 +0,0 @@ -package util - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "net/url" - "path/filepath" - "runtime" - "strconv" - "strings" - - "github.com/ghodss/yaml" - "github.com/hasura/graphql-engine/cli/migrate" - mig "github.com/hasura/graphql-engine/cli/migrate/cmd" - _ "github.com/hasura/graphql-engine/cli/migrate/database/hasuradb" - _ "github.com/hasura/graphql-engine/cli/migrate/source/file" - "github.com/pkg/errors" -) - -const ( - INVALID_STEP = "Cannot parse the number of steps. Should be a positive integer" -) - -func GetValidStepFromString(stepString string) (step int64, err error) { - step, err = strconv.ParseInt(stepString, 10, 64) - if err != nil { - return 0, errors.Wrap(err, "not a valid input") - } - return step, nil -} - -func ExecuteMigration(cmd string, dir, db *url.URL, stepOrVersion int64) error { - var err error - - t, err := migrate.New(dir.String(), db.String(), true) - if err != nil { - return errors.Wrap(err, "cannot create migrate instance") - } - - switch cmd { - case "up": - err = mig.UpCmd(t, stepOrVersion) - case "down": - err = mig.DownCmd(t, stepOrVersion) - case "version": - var direction string - if stepOrVersion >= 0 { - direction = "up" - } else { - direction = "down" - stepOrVersion = -(stepOrVersion) - } - err = mig.GotoCmd(t, uint64(stepOrVersion), direction) - default: - err = fmt.Errorf("Invalid command") - } - - return err -} - -func ExecuteMetadata(cmd string, dir, db *url.URL, metadata string) error { - var err error - - t, err := migrate.New(dir.String(), db.String(), true) - if err != nil { - return errors.Wrap(err, "cannot create migrate instance") - } - - switch cmd { - case "export": - metaData, err := t.ExportMetadata() - if err != nil { - return errors.Wrap(err, "Cannot export metadata") - } - - t, err := json.Marshal(metaData) - if err != nil { - return errors.Wrap(err, "Cannot Marshal metadata") - } - - data, err := yaml.JSONToYAML(t) - if err != nil { - return err - } - - err = ioutil.WriteFile(filepath.Join(metadata, "metadata.yaml"), data, 0644) - if err != nil { - return errors.Wrap(err, "cannot save metadata") - } - case "reset": - err := t.ResetMetadata() - if err != nil { - return errors.Wrap(err, "Cannot reset Metadata") - } - case "apply": - data, err := ioutil.ReadFile(filepath.Join(metadata, "metadata.yaml")) - if err != nil { - return errors.Wrap(err, "cannot read metadata file") - } - - var q interface{} - err = yaml.Unmarshal(data, &q) - if err != nil { - return errors.Wrap(err, "cannot parse metadata file") - } - - err = t.ApplyMetadata(q) - if err != nil { - return errors.Wrap(err, "cannot apply metadata on the database") - } - } - return nil -} - -func ExecuteStatus(dir string, db *url.URL) (*migrate.Status, error) { - var err error - - t, err := migrate.New(dir, db.String(), true) - if err != nil { - return nil, errors.Wrap(err, "cannot create migrate instance") - } - - status, err := t.GetStatus() - if err != nil { - return nil, err - } - return status, nil -} - -func GetDataPath(nurl *url.URL, accessKey string) *url.URL { - host := &url.URL{ - Scheme: "hasuradb", - User: url.UserPassword("admin", accessKey), - Host: nurl.Host, - Path: nurl.Path, - } - q := nurl.Query() - // Set sslmode in query - switch scheme := nurl.Scheme; scheme { - case "https": - q.Set("sslmode", "enable") - default: - q.Set("sslmode", "disable") - } - host.RawQuery = q.Encode() - return host -} - -func GetFilePath(dir string) *url.URL { - host := &url.URL{ - Scheme: "file", - Path: dir, - } - - // Add Prefix / to path if runtime.GOOS equals to windows - if runtime.GOOS == "windows" && !strings.HasPrefix(host.Path, "/") { - host.Path = "/" + host.Path - } - return host -} diff --git a/cli/util/migrate_test.go b/cli/util/migrate_test.go deleted file mode 100644 index 4593eb238e5f9..0000000000000 --- a/cli/util/migrate_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package util - -import ( - "io/ioutil" - "net/url" - "os" - "testing" -) - -func TestGetValidStepFromString(t *testing.T) { - tt := []struct { - step string - output int64 - }{ - {step: "1", output: 1}, - {step: "-1", output: -1}, - } - - for i, v := range tt { - step, err := GetValidStepFromString(v.step) - if err != nil { - t.Fatal(err) - } - - if step != v.output { - t.Fatalf("expected step to be %d in index %d but got %d", v.output, i, step) - } - } -} - -func TestGetDataPath(t *testing.T) { - nurl := &url.URL{ - Scheme: "http", - Host: "localhost:8080", - } - expectedURL := "hasuradb://admin:@localhost:8080?sslmode=disable" - dURL := GetDataPath(nurl, "") - - if dURL.String() != expectedURL { - t.Fatalf("expected url to be %s, but got %s", expectedURL, dURL.String()) - } -} - -func TestGetFilePath(t *testing.T) { - // Create migration Dir - migrationsDir, err := ioutil.TempDir("", "") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(migrationsDir) - expectedURL := "file://" + migrationsDir - - fURL := GetFilePath(migrationsDir) - if fURL.String() != expectedURL { - t.Fatalf("expected url to be %s, but got %s", expectedURL, fURL.String()) - } -} From 44d232c44ecd9f01831ddf6d1385c12cf7cb371b Mon Sep 17 00:00:00 2001 From: Aravind Shankar Date: Mon, 9 Jul 2018 19:15:41 +0530 Subject: [PATCH 9/9] [cli] fix #10, use logger from execution context in migrate --- cli/commands/console.go | 19 +++-- cli/commands/metadata.go | 54 ++++++++++++ cli/commands/metadata_apply.go | 8 +- cli/commands/metadata_export.go | 8 +- cli/commands/metadata_reset.go | 8 +- cli/commands/migrate.go | 83 +++---------------- cli/commands/migrate_apply.go | 8 +- cli/commands/migrate_status.go | 8 +- cli/migrate/api/metadata.go | 10 ++- cli/migrate/api/migrate.go | 10 ++- cli/migrate/api/settings.go | 10 ++- cli/migrate/database/driver.go | 10 ++- cli/migrate/database/hasuradb/hasuradb.go | 29 ++++--- .../database/hasuradb/hasuradb_test.go | 3 +- cli/migrate/database/hasuradb/metadata.go | 28 +++---- cli/migrate/database/hasuradb/settings.go | 18 ++-- cli/migrate/migrate.go | 21 +++-- cli/migrate/source/driver.go | 12 ++- cli/migrate/source/file/file.go | 8 +- cli/migrate/source/file/file_test.go | 36 +++++--- cli/migrate/source/stub/stub.go | 8 +- cli/migrate/source/stub/stub_test.go | 7 +- 22 files changed, 244 insertions(+), 162 deletions(-) diff --git a/cli/commands/console.go b/cli/commands/console.go index f70d3df84165a..7f03ad422057d 100644 --- a/cli/commands/console.go +++ b/cli/commands/console.go @@ -13,6 +13,7 @@ import ( "github.com/hasura/graphql-engine/cli/migrate/api" "github.com/hasura/graphql-engine/cli/util" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/skratchdot/open-golang/open" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -84,7 +85,7 @@ func (o *consoleOptions) run() error { r, } - router.setRoutes(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey, o.EC.MigrationDir) + router.setRoutes(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey, o.EC.MigrationDir, o.EC.Logger) if o.EC.Version == nil { return errors.New("cannot validate version, object is nil") @@ -151,14 +152,15 @@ type consoleRouter struct { *gin.Engine } -func (router *consoleRouter) setRoutes(nurl *url.URL, accessKey, migrationDir string) { +func (router *consoleRouter) setRoutes(nurl *url.URL, accessKey, migrationDir string, logger *logrus.Logger) { apis := router.Group("/apis") { + apis.Use(setLogger(logger)) + apis.Use(setFilePath(migrationDir)) + apis.Use(setDataPath(nurl, accessKey)) // Migrate api endpoints and middleware migrateAPIs := apis.Group("/migrate") { - migrateAPIs.Use(setFilePath(migrationDir)) - migrateAPIs.Use(setDataPath(nurl, accessKey)) settingsAPIs := migrateAPIs.Group("/settings") { settingsAPIs.Any("", api.SettingsAPI) @@ -168,8 +170,6 @@ func (router *consoleRouter) setRoutes(nurl *url.URL, accessKey, migrationDir st // Migrate api endpoints and middleware metadataAPIs := apis.Group("/metadata") { - metadataAPIs.Use(setFilePath(migrationDir)) - metadataAPIs.Use(setDataPath(nurl, accessKey)) metadataAPIs.Any("", api.MetadataAPI) } } @@ -192,6 +192,13 @@ func setFilePath(dir string) gin.HandlerFunc { } } +func setLogger(logger *logrus.Logger) gin.HandlerFunc { + return func(c *gin.Context) { + c.Set("logger", logger) + c.Next() + } +} + func allowCors() gin.HandlerFunc { config := cors.DefaultConfig() config.AddAllowHeaders("X-Hasura-User-Id") diff --git a/cli/commands/metadata.go b/cli/commands/metadata.go index 4513c00013c13..7255fd09a7601 100644 --- a/cli/commands/metadata.go +++ b/cli/commands/metadata.go @@ -1,7 +1,14 @@ package commands import ( + "encoding/json" + "io/ioutil" + "path/filepath" + + "github.com/ghodss/yaml" "github.com/hasura/graphql-engine/cli" + "github.com/hasura/graphql-engine/cli/migrate" + "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -31,3 +38,50 @@ func NewMetadataCmd(ec *cli.ExecutionContext) *cobra.Command { v.BindPFlag("access_key", f.Lookup("access-key")) return metadataCmd } + +func executeMetadata(cmd string, t *migrate.Migrate, metadata string) error { + switch cmd { + case "export": + metaData, err := t.ExportMetadata() + if err != nil { + return errors.Wrap(err, "Cannot export metadata") + } + + t, err := json.Marshal(metaData) + if err != nil { + return errors.Wrap(err, "Cannot Marshal metadata") + } + + data, err := yaml.JSONToYAML(t) + if err != nil { + return err + } + + err = ioutil.WriteFile(filepath.Join(metadata, "metadata.yaml"), data, 0644) + if err != nil { + return errors.Wrap(err, "cannot save metadata") + } + case "reset": + err := t.ResetMetadata() + if err != nil { + return errors.Wrap(err, "Cannot reset Metadata") + } + case "apply": + data, err := ioutil.ReadFile(filepath.Join(metadata, "metadata.yaml")) + if err != nil { + return errors.Wrap(err, "cannot read metadata file") + } + + var q interface{} + err = yaml.Unmarshal(data, &q) + if err != nil { + return errors.Wrap(err, "cannot parse metadata file") + } + + err = t.ApplyMetadata(q) + if err != nil { + return errors.Wrap(err, "cannot apply metadata on the database") + } + } + return nil +} diff --git a/cli/commands/metadata_apply.go b/cli/commands/metadata_apply.go index 1d967860c6fd5..26486990829ee 100644 --- a/cli/commands/metadata_apply.go +++ b/cli/commands/metadata_apply.go @@ -32,7 +32,9 @@ type metadataApplyOptions struct { } func (o *metadataApplyOptions) run() error { - dbURL := getDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) - fileURL := getFilePath(o.EC.MigrationDir) - return executeMetadata(o.actionType, fileURL, dbURL, o.EC.ExecutionDirectory) + migrateDrv, err := newMigrate(o.EC.MigrationDir, o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey, o.EC.Logger) + if err != nil { + return err + } + return executeMetadata(o.actionType, migrateDrv, o.EC.ExecutionDirectory) } diff --git a/cli/commands/metadata_export.go b/cli/commands/metadata_export.go index b75d607a6c81f..0c42f1790767b 100644 --- a/cli/commands/metadata_export.go +++ b/cli/commands/metadata_export.go @@ -32,7 +32,9 @@ type metadataExportOptions struct { } func (o *metadataExportOptions) run() error { - dbURL := getDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) - fileURL := getFilePath(o.EC.MigrationDir) - return executeMetadata(o.actionType, fileURL, dbURL, o.EC.ExecutionDirectory) + migrateDrv, err := newMigrate(o.EC.MigrationDir, o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey, o.EC.Logger) + if err != nil { + return err + } + return executeMetadata(o.actionType, migrateDrv, o.EC.ExecutionDirectory) } diff --git a/cli/commands/metadata_reset.go b/cli/commands/metadata_reset.go index 621e8c84e85e2..6b3139c3f94cd 100644 --- a/cli/commands/metadata_reset.go +++ b/cli/commands/metadata_reset.go @@ -33,9 +33,11 @@ type metadataResetOptions struct { } func (o *metadataResetOptions) run() error { - dbURL := getDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) - fileURL := getFilePath(o.EC.MigrationDir) - err := executeMetadata(o.actionType, fileURL, dbURL, o.EC.ExecutionDirectory) + migrateDrv, err := newMigrate(o.EC.MigrationDir, o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey, o.EC.Logger) + if err != nil { + return err + } + err = executeMetadata(o.actionType, migrateDrv, o.EC.ExecutionDirectory) if err != nil { return errors.Wrap(err, "Cannot reset metadata") } diff --git a/cli/commands/migrate.go b/cli/commands/migrate.go index 8226ed450a324..c839893e754b0 100644 --- a/cli/commands/migrate.go +++ b/cli/commands/migrate.go @@ -1,21 +1,18 @@ package commands import ( - "encoding/json" "fmt" - "io/ioutil" "net/url" - "path/filepath" "runtime" "strings" - "github.com/ghodss/yaml" "github.com/hasura/graphql-engine/cli" "github.com/hasura/graphql-engine/cli/migrate" mig "github.com/hasura/graphql-engine/cli/migrate/cmd" _ "github.com/hasura/graphql-engine/cli/migrate/database/hasuradb" _ "github.com/hasura/graphql-engine/cli/migrate/source/file" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -46,13 +43,18 @@ func NewMigrateCmd(ec *cli.ExecutionContext) *cobra.Command { return migrateCmd } -func executeMigration(cmd string, dir, db *url.URL, stepOrVersion int64) error { - var err error - - t, err := migrate.New(dir.String(), db.String(), true) +func newMigrate(dir string, db *url.URL, accessKey string, logger *logrus.Logger) (*migrate.Migrate, error) { + dbURL := getDataPath(db, accessKey) + fileURL := getFilePath(dir) + t, err := migrate.New(fileURL.String(), dbURL.String(), true, logger) if err != nil { - return errors.Wrap(err, "cannot create migrate instance") + return nil, errors.Wrap(err, "cannot create migrate instance") } + return t, nil +} + +func executeMigration(cmd string, t *migrate.Migrate, stepOrVersion int64) error { + var err error switch cmd { case "up": @@ -75,68 +77,7 @@ func executeMigration(cmd string, dir, db *url.URL, stepOrVersion int64) error { return err } -func executeMetadata(cmd string, dir, db *url.URL, metadata string) error { - var err error - - t, err := migrate.New(dir.String(), db.String(), true) - if err != nil { - return errors.Wrap(err, "cannot create migrate instance") - } - - switch cmd { - case "export": - metaData, err := t.ExportMetadata() - if err != nil { - return errors.Wrap(err, "Cannot export metadata") - } - - t, err := json.Marshal(metaData) - if err != nil { - return errors.Wrap(err, "Cannot Marshal metadata") - } - - data, err := yaml.JSONToYAML(t) - if err != nil { - return err - } - - err = ioutil.WriteFile(filepath.Join(metadata, "metadata.yaml"), data, 0644) - if err != nil { - return errors.Wrap(err, "cannot save metadata") - } - case "reset": - err := t.ResetMetadata() - if err != nil { - return errors.Wrap(err, "Cannot reset Metadata") - } - case "apply": - data, err := ioutil.ReadFile(filepath.Join(metadata, "metadata.yaml")) - if err != nil { - return errors.Wrap(err, "cannot read metadata file") - } - - var q interface{} - err = yaml.Unmarshal(data, &q) - if err != nil { - return errors.Wrap(err, "cannot parse metadata file") - } - - err = t.ApplyMetadata(q) - if err != nil { - return errors.Wrap(err, "cannot apply metadata on the database") - } - } - return nil -} - -func executeStatus(dir, db *url.URL) (*migrate.Status, error) { - var err error - - t, err := migrate.New(dir.String(), db.String(), true) - if err != nil { - return nil, errors.Wrap(err, "cannot create migrate instance") - } - +func executeStatus(t *migrate.Migrate) (*migrate.Status, error) { status, err := t.GetStatus() if err != nil { return nil, err diff --git a/cli/commands/migrate_apply.go b/cli/commands/migrate_apply.go index 983ada573e73c..4375c4d8cca63 100644 --- a/cli/commands/migrate_apply.go +++ b/cli/commands/migrate_apply.go @@ -45,10 +45,12 @@ func (o *migrateApplyOptions) run() error { return errors.Wrap(err, "error validating flags") } - dbURL := getDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) - sourceURL := getFilePath(o.EC.MigrationDir) + migrateDrv, err := newMigrate(o.EC.MigrationDir, o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey, o.EC.Logger) + if err != nil { + return err + } - err = executeMigration(migrationType, sourceURL, dbURL, step) + err = executeMigration(migrationType, migrateDrv, step) if err != nil { if err == migrate.ErrNoChange { o.EC.Logger.Info("nothing to apply") diff --git a/cli/commands/migrate_status.go b/cli/commands/migrate_status.go index 5ab948bb7b56f..a18d2f8d0bcba 100644 --- a/cli/commands/migrate_status.go +++ b/cli/commands/migrate_status.go @@ -38,9 +38,11 @@ type migrateStatusOptions struct { } func (o *migrateStatusOptions) run() (*migrate.Status, error) { - dbURL := getDataPath(o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey) - fileURL := getFilePath(o.EC.MigrationDir) - status, err := executeStatus(fileURL, dbURL) + migrateDrv, err := newMigrate(o.EC.MigrationDir, o.EC.Config.ParsedEndpoint, o.EC.Config.AccessKey, o.EC.Logger) + if err != nil { + return nil, errors.Wrap(err, "cannot create migrate instance") + } + status, err := executeStatus(migrateDrv) if err != nil { return nil, errors.Wrap(err, "cannot fetch migrate status") } diff --git a/cli/migrate/api/metadata.go b/cli/migrate/api/metadata.go index 4d4c680888d4e..0d9b87d603156 100644 --- a/cli/migrate/api/metadata.go +++ b/cli/migrate/api/metadata.go @@ -11,6 +11,7 @@ import ( "github.com/ghodss/yaml" "github.com/gin-gonic/gin" "github.com/hasura/graphql-engine/cli/migrate" + "github.com/sirupsen/logrus" ) func MetadataAPI(c *gin.Context) { @@ -31,8 +32,15 @@ func MetadataAPI(c *gin.Context) { // Convert to url.URL databaseURL := databasePtr.(*url.URL) + // Get Logger + loggerPtr, ok := c.Get("logger") + if !ok { + return + } + logger := loggerPtr.(*logrus.Logger) + // Create new migrate - t, err := migrate.New(sourceURL.String(), databaseURL.String(), false) + t, err := migrate.New(sourceURL.String(), databaseURL.String(), false, logger) if err != nil { if strings.HasPrefix(err.Error(), DataAPIError) { c.JSON(http.StatusInternalServerError, &Response{Code: "data_api_error", Message: err.Error()}) diff --git a/cli/migrate/api/migrate.go b/cli/migrate/api/migrate.go index c8f05c6f72b8d..2e06c1328c8fe 100644 --- a/cli/migrate/api/migrate.go +++ b/cli/migrate/api/migrate.go @@ -9,6 +9,7 @@ import ( "github.com/gin-gonic/gin" "github.com/hasura/graphql-engine/cli/migrate" "github.com/hasura/graphql-engine/cli/migrate/cmd" + "github.com/sirupsen/logrus" ) const ( @@ -41,12 +42,19 @@ func MigrateAPI(c *gin.Context) { return } + // Get Logger + loggerPtr, ok := c.Get("logger") + if !ok { + return + } + // Convert to url.URL databaseURL := databasePtr.(*url.URL) sourceURL := sourcePtr.(*url.URL) + logger := loggerPtr.(*logrus.Logger) // Create new migrate - t, err := migrate.New(sourceURL.String(), databaseURL.String(), false) + t, err := migrate.New(sourceURL.String(), databaseURL.String(), false, logger) if err != nil { if strings.HasPrefix(err.Error(), DataAPIError) { c.JSON(http.StatusInternalServerError, &Response{Code: "data_api_error", Message: err.Error()}) diff --git a/cli/migrate/api/settings.go b/cli/migrate/api/settings.go index 1c05d65e001e9..cd0a0a038e740 100644 --- a/cli/migrate/api/settings.go +++ b/cli/migrate/api/settings.go @@ -7,6 +7,7 @@ import ( "github.com/gin-gonic/gin" "github.com/hasura/graphql-engine/cli/migrate" + "github.com/sirupsen/logrus" ) type SettingReqeust struct { @@ -32,8 +33,15 @@ func SettingsAPI(c *gin.Context) { // Convert to url.URL databaseURL := databasePtr.(*url.URL) + // Get Logger + loggerPtr, ok := c.Get("logger") + if !ok { + return + } + logger := loggerPtr.(*logrus.Logger) + // Create new migrate - t, err := migrate.New(sourceURL.String(), databaseURL.String(), false) + t, err := migrate.New(sourceURL.String(), databaseURL.String(), false, logger) if err != nil { if strings.HasPrefix(err.Error(), DataAPIError) { c.JSON(500, &Response{Code: "data_api_error", Message: err.Error()}) diff --git a/cli/migrate/database/driver.go b/cli/migrate/database/driver.go index 341a8e1f970bc..8c43412f3fdd1 100644 --- a/cli/migrate/database/driver.go +++ b/cli/migrate/database/driver.go @@ -43,7 +43,7 @@ type Driver interface { // Open returns a new driver instance configured with parameters // coming from the URL string. Migrate will call this function // only once per instance. - Open(url string, isCMD bool) (Driver, error) + Open(url string, isCMD bool, logger *log.Logger) (Driver, error) // Close closes the underlying database instance managed by the driver. // Migrate will call this function only once per instance. @@ -108,7 +108,7 @@ type Driver interface { } // Open returns a new driver instance. -func Open(url string, isCMD bool) (Driver, error) { +func Open(url string, isCMD bool, logger *log.Logger) (Driver, error) { u, err := nurl.Parse(url) if err != nil { log.Debug(err) @@ -126,7 +126,11 @@ func Open(url string, isCMD bool) (Driver, error) { return nil, fmt.Errorf("database driver: unknown driver hasuradb (forgotten import?)") } - return d.Open(url, isCMD) + if logger == nil { + logger = log.New() + } + + return d.Open(url, isCMD, logger) } func Register(name string, driver Driver) { diff --git a/cli/migrate/database/hasuradb/hasuradb.go b/cli/migrate/database/hasuradb/hasuradb.go index ad0dc301fc52b..aad49d6c56c6b 100644 --- a/cli/migrate/database/hasuradb/hasuradb.go +++ b/cli/migrate/database/hasuradb/hasuradb.go @@ -53,11 +53,12 @@ type HasuraDB struct { migrations *database.Migrations migrationQuery HasuraInterfaceBulk isLocked bool + logger *log.Logger } -func WithInstance(config *Config) (database.Driver, error) { +func WithInstance(config *Config, logger *log.Logger) (database.Driver, error) { if config == nil { - log.Debug(ErrNilConfig) + logger.Debug(ErrNilConfig) return nil, ErrNilConfig } @@ -65,15 +66,16 @@ func WithInstance(config *Config) (database.Driver, error) { config: config, migrations: database.NewMigrations(), settings: database.Settings, + logger: logger, } if err := hx.ensureVersionTable(); err != nil { - log.Debug(err) + logger.Debug(err) return nil, err } if err := hx.ensureSettingsTable(); err != nil { - log.Debug(err) + logger.Debug(err) return nil, err } @@ -85,10 +87,13 @@ func WithInstance(config *Config) (database.Driver, error) { return hx, nil } -func (h *HasuraDB) Open(url string, isCMD bool) (database.Driver, error) { +func (h *HasuraDB) Open(url string, isCMD bool, logger *log.Logger) (database.Driver, error) { + if logger == nil { + logger = log.New() + } hurl, err := nurl.Parse(url) if err != nil { - log.Debug(err) + logger.Debug(err) return nil, err } // Use sslMode to set Scheme @@ -132,10 +137,10 @@ func (h *HasuraDB) Open(url string, isCMD bool) (database.Driver, error) { Role: user, UserID: pass, isCMD: isCMD, - }) + }, logger) if err != nil { - log.Debug(err) + logger.Debug(err) return nil, err } @@ -389,17 +394,17 @@ func (h *HasuraDB) ensureVersionTable() error { resp, body, err := h.sendQuery(query) if err != nil { - log.Debug(err) + h.logger.Debug(err) return err } - log.Debug("response: ", string(body)) + h.logger.Debug("response: ", string(body)) var horror HasuraError if resp.StatusCode != http.StatusOK { err = json.Unmarshal(body, &horror) if err != nil { - log.Debug(err) + h.logger.Debug(err) return err } return horror.Error(h.config.isCMD) @@ -409,7 +414,7 @@ func (h *HasuraDB) ensureVersionTable() error { err = json.Unmarshal(body, &hres) if err != nil { - log.Debug(err) + h.logger.Debug(err) return err } diff --git a/cli/migrate/database/hasuradb/hasuradb_test.go b/cli/migrate/database/hasuradb/hasuradb_test.go index b4d79deae19b2..3e2c3782bc942 100644 --- a/cli/migrate/database/hasuradb/hasuradb_test.go +++ b/cli/migrate/database/hasuradb/hasuradb_test.go @@ -5,7 +5,6 @@ import ( sqldriver "database/sql/driver" "fmt" "io" - "testing" mt "github.com/hasura/graphql-engine/cli/migrate/testing" _ "github.com/lib/pq" @@ -48,6 +47,7 @@ func isReadyRaven(i mt.Instance) bool { return false } +/* func testHasuraDB(t *testing.T) { mt.ParallelTest(t, postgresVersions, isReadyPostgres, func(t *testing.T, pi mt.Instance) { @@ -69,3 +69,4 @@ func testHasuraDB(t *testing.T) { }) }) } +*/ diff --git a/cli/migrate/database/hasuradb/metadata.go b/cli/migrate/database/hasuradb/metadata.go index 2d2a6b2e04eb0..715074ffc44d8 100644 --- a/cli/migrate/database/hasuradb/metadata.go +++ b/cli/migrate/database/hasuradb/metadata.go @@ -3,8 +3,6 @@ package hasuradb import ( "encoding/json" "net/http" - - log "github.com/sirupsen/logrus" ) func (h *HasuraDB) ExportMetadata() (interface{}, error) { @@ -15,16 +13,16 @@ func (h *HasuraDB) ExportMetadata() (interface{}, error) { resp, body, err := h.sendQuery(query) if err != nil { - log.Debug(err) + h.logger.Debug(err) return nil, err } - log.Debug("response: ", string(body)) + h.logger.Debug("response: ", string(body)) var horror HasuraError if resp.StatusCode != http.StatusOK { err = json.Unmarshal(body, &horror) if err != nil { - log.Debug(err) + h.logger.Debug(err) return nil, err } return nil, horror.Error(h.config.isCMD) @@ -33,7 +31,7 @@ func (h *HasuraDB) ExportMetadata() (interface{}, error) { var hres interface{} err = json.Unmarshal(body, &hres) if err != nil { - log.Debug(err) + h.logger.Debug(err) return nil, err } @@ -48,16 +46,16 @@ func (h *HasuraDB) ResetMetadata() error { resp, body, err := h.sendQuery(query) if err != nil { - log.Debug(err) + h.logger.Debug(err) return err } - log.Debug("response: ", string(body)) + h.logger.Debug("response: ", string(body)) var horror HasuraError if resp.StatusCode != http.StatusOK { err = json.Unmarshal(body, &horror) if err != nil { - log.Debug(err) + h.logger.Debug(err) return err } return horror.Error(h.config.isCMD) @@ -82,16 +80,16 @@ func (h *HasuraDB) ApplyMetadata(data interface{}) error { resp, body, err := h.sendQuery(query) if err != nil { - log.Debug(err) + h.logger.Debug(err) return err } - log.Debug("response: ", string(body)) + h.logger.Debug("response: ", string(body)) var horror HasuraError if resp.StatusCode != http.StatusOK { err = json.Unmarshal(body, &horror) if err != nil { - log.Debug(err) + h.logger.Debug(err) return err } return horror.Error(h.config.isCMD) @@ -107,16 +105,16 @@ func (h *HasuraDB) Query(data []interface{}) error { resp, body, err := h.sendQuery(query) if err != nil { - log.Debug(err) + h.logger.Debug(err) return err } - log.Debug("response: ", string(body)) + h.logger.Debug("response: ", string(body)) var horror HasuraError if resp.StatusCode != http.StatusOK { err = json.Unmarshal(body, &horror) if err != nil { - log.Debug(err) + h.logger.Debug(err) return err } return horror.Error(h.config.isCMD) diff --git a/cli/migrate/database/hasuradb/settings.go b/cli/migrate/database/hasuradb/settings.go index 79aa50f71d81c..92d89bc96b9b6 100644 --- a/cli/migrate/database/hasuradb/settings.go +++ b/cli/migrate/database/hasuradb/settings.go @@ -4,8 +4,6 @@ import ( "encoding/json" "fmt" "net/http" - - log "github.com/sirupsen/logrus" ) const ( @@ -23,16 +21,16 @@ func (h *HasuraDB) ensureSettingsTable() error { resp, body, err := h.sendQuery(query) if err != nil { - log.Debug(err) + h.logger.Debug(err) return err } - log.Debug("response: ", string(body)) + h.logger.Debug("response: ", string(body)) var horror HasuraError if resp.StatusCode != http.StatusOK { err = json.Unmarshal(body, &horror) if err != nil { - log.Debug(err) + h.logger.Debug(err) return err } return horror.Error(h.config.isCMD) @@ -42,7 +40,7 @@ func (h *HasuraDB) ensureSettingsTable() error { err = json.Unmarshal(body, &hres) if err != nil { - log.Debug(err) + h.logger.Debug(err) return err } @@ -66,7 +64,7 @@ func (h *HasuraDB) ensureSettingsTable() error { if err != nil { return err } - log.Debug("response: ", string(body)) + h.logger.Debug("response: ", string(body)) if resp.StatusCode != http.StatusOK { err = json.Unmarshal(body, &horror) @@ -116,7 +114,7 @@ func (h *HasuraDB) setDefaultSettings() error { if resp.StatusCode != http.StatusOK { err = json.Unmarshal(body, &horror) if err != nil { - log.Debug(err) + h.logger.Debug(err) return err } return horror.Error(h.config.isCMD) @@ -138,7 +136,7 @@ func (h *HasuraDB) GetSetting(name string) (value string, err error) { if err != nil { return value, err } - log.Debug("response: ", string(body)) + h.logger.Debug("response: ", string(body)) var horror HasuraError @@ -187,7 +185,7 @@ func (h *HasuraDB) UpdateSetting(name string, value string) error { if err != nil { return err } - log.Debug("response: ", string(body)) + h.logger.Debug("response: ", string(body)) var horror HasuraError diff --git a/cli/migrate/migrate.go b/cli/migrate/migrate.go index 7581ce22e36d2..2df60674656be 100644 --- a/cli/migrate/migrate.go +++ b/cli/migrate/migrate.go @@ -67,6 +67,9 @@ type Migrate struct { databaseURL string databaseDrv database.Driver + // Logger is the global logger object to print logs. + Logger *log.Logger + // GracefulStop accepts `true` and will stop executing migrations // as soon as possible at a safe break point, so that the database // is not corrupted. @@ -92,7 +95,7 @@ type Migrate struct { // New returns a new Migrate instance from a source URL and a database URL. // The URL scheme is defined by each driver. -func New(sourceUrl string, databaseUrl string, cmd bool) (*Migrate, error) { +func New(sourceUrl string, databaseUrl string, cmd bool, logger *log.Logger) (*Migrate, error) { m := newCommon(cmd) sourceName, err := schemeFromUrl(sourceUrl) @@ -111,14 +114,18 @@ func New(sourceUrl string, databaseUrl string, cmd bool) (*Migrate, error) { m.databaseName = databaseName m.databaseURL = databaseUrl - sourceDrv, err := source.Open(sourceUrl) + if logger == nil { + logger = log.New() + } + + sourceDrv, err := source.Open(sourceUrl, logger) if err != nil { log.Debug(err) return nil, err } m.sourceDrv = sourceDrv - databaseDrv, err := database.Open(databaseUrl, cmd) + databaseDrv, err := database.Open(databaseUrl, cmd, logger) if err != nil { log.Debug(err) return nil, err @@ -141,16 +148,16 @@ func newCommon(cmd bool) *Migrate { } func (m *Migrate) ReScan() error { - sourceDrv, err := source.Open(m.sourceURL) + sourceDrv, err := source.Open(m.sourceURL, m.Logger) if err != nil { - log.Debug(err) + m.Logger.Debug(err) return err } m.sourceDrv = sourceDrv - databaseDrv, err := database.Open(m.databaseURL, m.isCMD) + databaseDrv, err := database.Open(m.databaseURL, m.isCMD, m.Logger) if err != nil { - log.Debug(err) + m.Logger.Debug(err) return err } m.databaseDrv = databaseDrv diff --git a/cli/migrate/source/driver.go b/cli/migrate/source/driver.go index 7f3cbe52111d1..3fd90c9b79f79 100644 --- a/cli/migrate/source/driver.go +++ b/cli/migrate/source/driver.go @@ -5,6 +5,8 @@ import ( "io" nurl "net/url" "sync" + + log "github.com/sirupsen/logrus" ) var driversMu sync.RWMutex @@ -32,7 +34,7 @@ type Driver interface { // Open returns a a new driver instance configured with parameters // coming from the URL string. Migrate will call this function // only once per instance. - Open(url string) (Driver, error) + Open(url string, logger *log.Logger) (Driver, error) // Close closes the underlying source instance managed by the driver. // Migrate will call this function only once per instance. @@ -91,7 +93,7 @@ type Driver interface { } // Open returns a new driver instance. -func Open(url string) (Driver, error) { +func Open(url string, logger *log.Logger) (Driver, error) { u, err := nurl.Parse(url) if err != nil { return nil, err @@ -108,7 +110,11 @@ func Open(url string) (Driver, error) { return nil, fmt.Errorf("source driver: unknown driver %v (forgotten import?)", u.Scheme) } - return d.Open(url) + if logger == nil { + logger = log.New() + } + + return d.Open(url, logger) } // Register globally registers a driver. diff --git a/cli/migrate/source/file/file.go b/cli/migrate/source/file/file.go index 89f96602b7666..954bc17831fb7 100644 --- a/cli/migrate/source/file/file.go +++ b/cli/migrate/source/file/file.go @@ -12,19 +12,24 @@ import ( "strings" "github.com/hasura/graphql-engine/cli/migrate/source" + log "github.com/sirupsen/logrus" ) type File struct { url string path string migrations *source.Migrations + logger *log.Logger } func init() { source.Register("file", &File{}) } -func (f *File) Open(url string) (source.Driver, error) { +func (f *File) Open(url string, logger *log.Logger) (source.Driver, error) { + if logger == nil { + logger = log.New() + } u, err := nurl.Parse(url) if err != nil { return nil, err @@ -62,6 +67,7 @@ func (f *File) Open(url string) (source.Driver, error) { nf := &File{ url: url, + logger: logger, path: p, migrations: source.NewMigrations(), } diff --git a/cli/migrate/source/file/file_test.go b/cli/migrate/source/file/file_test.go index 92d61d855b222..cc3f8bb24c745 100644 --- a/cli/migrate/source/file/file_test.go +++ b/cli/migrate/source/file/file_test.go @@ -9,6 +9,7 @@ import ( "testing" st "github.com/hasura/graphql-engine/cli/migrate/source/testing" + "github.com/sirupsen/logrus/hooks/test" ) func Test(t *testing.T) { @@ -35,8 +36,9 @@ func Test(t *testing.T) { mustWriteFile(t, tmpDir, "8_foobar.up.sql", "7 up") mustWriteFile(t, tmpDir, "8_foobar.down.sql", "7 down") + logger, _ := test.NewNullLogger() f := &File{} - d, err := f.Open("file://" + tmpDir) + d, err := f.Open("file://"+tmpDir, logger) if err != nil { t.Fatal(err) } @@ -58,8 +60,9 @@ func TestOpen(t *testing.T) { t.Fatal("expected tmpDir to be absolute path") } + logger, _ := test.NewNullLogger() f := &File{} - _, err = f.Open("file://" + tmpDir) // absolute path + _, err = f.Open("file://"+tmpDir, logger) // absolute path if err != nil { t.Fatal(err) } @@ -88,10 +91,11 @@ func TestOpenWithRelativePath(t *testing.T) { mustWriteFile(t, filepath.Join(tmpDir, "foo"), "1_foobar.up.sql", "") + logger, _ := test.NewNullLogger() f := &File{} // dir: foo - d, err := f.Open("file://foo") + d, err := f.Open("file://foo", logger) if err != nil { t.Fatal(err) } @@ -101,7 +105,7 @@ func TestOpenWithRelativePath(t *testing.T) { } // dir: ./foo - d, err = f.Open("file://./foo") + d, err = f.Open("file://./foo", logger) if err != nil { t.Fatal(err) } @@ -117,8 +121,9 @@ func TestOpenDefaultsToCurrentDirectory(t *testing.T) { t.Fatal(err) } + logger, _ := test.NewNullLogger() f := &File{} - d, err := f.Open("file://") + d, err := f.Open("file://", logger) if err != nil { t.Fatal(err) } @@ -138,24 +143,27 @@ func TestOpenWithDuplicateVersion(t *testing.T) { mustWriteFile(t, tmpDir, "1_foo.up.sql", "") // 1 up mustWriteFile(t, tmpDir, "1_bar.up.sql", "") // 1 up + logger, _ := test.NewNullLogger() f := &File{} - _, err = f.Open("file://" + tmpDir) + _, err = f.Open("file://"+tmpDir, logger) if err == nil { t.Fatal("expected err") } } func TestOpenWithInvalidFileURL(t *testing.T) { + logger, _ := test.NewNullLogger() f := &File{} - _, err := f.Open(":") + _, err := f.Open(":", logger) if err == nil { t.Fatal("exepected err to be not nil") } } func TestWithEmptyMigration(t *testing.T) { + logger, _ := test.NewNullLogger() s := &File{} - d, err := s.Open("") + d, err := s.Open("", logger) if err != nil { t.Fatal(err) } @@ -171,8 +179,9 @@ func TestWithEmptyMigration(t *testing.T) { } func TestWithInvalidDirectory(t *testing.T) { + logger, _ := test.NewNullLogger() s := &File{} - _, err := s.Open("file://invalidir") + _, err := s.Open("file://invalidir", logger) if err == nil { t.Fatal("exepected err to be not nil") } @@ -185,8 +194,9 @@ func TestClose(t *testing.T) { } defer os.RemoveAll(tmpDir) + logger, _ := test.NewNullLogger() f := &File{} - d, err := f.Open("file://" + tmpDir) + d, err := f.Open("file://"+tmpDir, logger) if err != nil { t.Fatal(err) } @@ -211,21 +221,23 @@ func mustCreateBenchmarkDir(t *testing.B) (dir string) { } func BenchmarkOpen(b *testing.B) { + logger, _ := test.NewNullLogger() dir := mustCreateBenchmarkDir(b) defer os.RemoveAll(dir) b.ResetTimer() for n := 0; n < b.N; n++ { f := &File{} - f.Open("file://" + dir) + f.Open("file://"+dir, logger) } b.StopTimer() } func BenchmarkNext(b *testing.B) { + logger, _ := test.NewNullLogger() dir := mustCreateBenchmarkDir(b) defer os.RemoveAll(dir) f := &File{} - d, _ := f.Open("file://" + dir) + d, _ := f.Open("file://"+dir, logger) b.ResetTimer() v, err := d.First() for n := 0; n < b.N; n++ { diff --git a/cli/migrate/source/stub/stub.go b/cli/migrate/source/stub/stub.go index dfc71f250a457..76b43f147b5f0 100644 --- a/cli/migrate/source/stub/stub.go +++ b/cli/migrate/source/stub/stub.go @@ -8,6 +8,7 @@ import ( "os" "github.com/hasura/graphql-engine/cli/migrate/source" + log "github.com/sirupsen/logrus" ) func init() { @@ -21,13 +22,18 @@ type Stub struct { Instance interface{} Migrations *source.Migrations Config *Config + logger *log.Logger } -func (s *Stub) Open(url string) (source.Driver, error) { +func (s *Stub) Open(url string, logger *log.Logger) (source.Driver, error) { + if logger == nil { + logger = log.New() + } return &Stub{ Url: url, Migrations: source.NewMigrations(), Config: &Config{}, + logger: logger, }, nil } diff --git a/cli/migrate/source/stub/stub_test.go b/cli/migrate/source/stub/stub_test.go index 2430583fe792e..d7b54d0611987 100644 --- a/cli/migrate/source/stub/stub_test.go +++ b/cli/migrate/source/stub/stub_test.go @@ -5,11 +5,13 @@ import ( "github.com/hasura/graphql-engine/cli/migrate/source" st "github.com/hasura/graphql-engine/cli/migrate/source/testing" + "github.com/sirupsen/logrus/hooks/test" ) func Test(t *testing.T) { + logger, _ := test.NewNullLogger() s := &Stub{} - d, err := s.Open("") + d, err := s.Open("", logger) if err != nil { t.Fatal(err) } @@ -32,8 +34,9 @@ func Test(t *testing.T) { } func TestWithEmptyMigration(t *testing.T) { + logger, _ := test.NewNullLogger() s := &Stub{} - d, err := s.Open("") + d, err := s.Open("", logger) if err != nil { t.Fatal(err) }