mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
parent
b02cd336d0
commit
21b61af109
@ -11,6 +11,7 @@ The order and collapsed state of columns is now persisted across page navigation
|
|||||||
|
|
||||||
### Bug fixes and improvements
|
### Bug fixes and improvements
|
||||||
|
|
||||||
|
- cli: allow customization of server api paths (close #4016)
|
||||||
- cli: clean up migration files created during a failed migrate api (close #4312) (#4319)
|
- cli: clean up migration files created during a failed migrate api (close #4312) (#4319)
|
||||||
- cli: add support for multiple versions of plugin (close #4105)
|
- cli: add support for multiple versions of plugin (close #4105)
|
||||||
- cli: template assets path in console HTML for unversioned builds
|
- cli: template assets path in console HTML for unversioned builds
|
||||||
|
55
cli/cli.go
55
cli/cli.go
@ -12,7 +12,9 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -61,6 +63,36 @@ const (
|
|||||||
V2
|
V2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ServerAPIPaths has the custom paths defined for server api
|
||||||
|
type ServerAPIPaths struct {
|
||||||
|
Query string `yaml:"query,omitempty"`
|
||||||
|
GraphQL string `yaml:"graphql,omitempty"`
|
||||||
|
Config string `yaml:"config,omitempty"`
|
||||||
|
PGDump string `yaml:"pg_dump,omitempty"`
|
||||||
|
Version string `yaml:"version,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetQueryParams - encodes the values in url
|
||||||
|
func (s ServerAPIPaths) GetQueryParams() url.Values {
|
||||||
|
vals := url.Values{}
|
||||||
|
t := reflect.TypeOf(s)
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
field := t.Field(i)
|
||||||
|
tag := field.Tag.Get("yaml")
|
||||||
|
splitTag := strings.Split(tag, ",")
|
||||||
|
if len(splitTag) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name := splitTag[0]
|
||||||
|
if name == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v := reflect.ValueOf(s).Field(i)
|
||||||
|
vals.Add(name, v.String())
|
||||||
|
}
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
// ErrInvalidConfigVersion - if the config version is not valid
|
// ErrInvalidConfigVersion - if the config version is not valid
|
||||||
var ErrInvalidConfigVersion error = fmt.Errorf("invalid config version")
|
var ErrInvalidConfigVersion error = fmt.Errorf("invalid config version")
|
||||||
|
|
||||||
@ -105,10 +137,19 @@ type ServerConfig struct {
|
|||||||
AccessKey string `yaml:"access_key,omitempty"`
|
AccessKey string `yaml:"access_key,omitempty"`
|
||||||
// AdminSecret (optional) Admin secret required to query the endpoint
|
// AdminSecret (optional) Admin secret required to query the endpoint
|
||||||
AdminSecret string `yaml:"admin_secret,omitempty"`
|
AdminSecret string `yaml:"admin_secret,omitempty"`
|
||||||
|
// APIPaths (optional) API paths for server
|
||||||
|
APIPaths *ServerAPIPaths `yaml:"api_paths,omitempty"`
|
||||||
|
|
||||||
ParsedEndpoint *url.URL `yaml:"-"`
|
ParsedEndpoint *url.URL `yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetVersionEndpoint provides the url to contact the version API
|
||||||
|
func (s *ServerConfig) GetVersionEndpoint() string {
|
||||||
|
nurl := *s.ParsedEndpoint
|
||||||
|
nurl.Path = path.Join(nurl.Path, s.APIPaths.Version)
|
||||||
|
return nurl.String()
|
||||||
|
}
|
||||||
|
|
||||||
// ParseEndpoint ensures the endpoint is valid.
|
// ParseEndpoint ensures the endpoint is valid.
|
||||||
func (s *ServerConfig) ParseEndpoint() error {
|
func (s *ServerConfig) ParseEndpoint() error {
|
||||||
nurl, err := url.Parse(s.Endpoint)
|
nurl, err := url.Parse(s.Endpoint)
|
||||||
@ -398,7 +439,7 @@ func (ec *ExecutionContext) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ec *ExecutionContext) checkServerVersion() error {
|
func (ec *ExecutionContext) checkServerVersion() error {
|
||||||
v, err := version.FetchServerVersion(ec.Config.ServerConfig.Endpoint)
|
v, err := version.FetchServerVersion(ec.Config.ServerConfig.GetVersionEndpoint())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to get version from server")
|
return errors.Wrap(err, "failed to get version from server")
|
||||||
}
|
}
|
||||||
@ -441,6 +482,11 @@ func (ec *ExecutionContext) readConfig() error {
|
|||||||
v.SetDefault("endpoint", "http://localhost:8080")
|
v.SetDefault("endpoint", "http://localhost:8080")
|
||||||
v.SetDefault("admin_secret", "")
|
v.SetDefault("admin_secret", "")
|
||||||
v.SetDefault("access_key", "")
|
v.SetDefault("access_key", "")
|
||||||
|
v.SetDefault("api_paths.query", "v1/query")
|
||||||
|
v.SetDefault("api_paths.graphql", "v1/graphql")
|
||||||
|
v.SetDefault("api_paths.config", "v1alpha1/config")
|
||||||
|
v.SetDefault("api_paths.pg_dump", "v1alpha1/pg_dump")
|
||||||
|
v.SetDefault("api_paths.version", "v1/version")
|
||||||
v.SetDefault("metadata_directory", "")
|
v.SetDefault("metadata_directory", "")
|
||||||
v.SetDefault("migrations_directory", "migrations")
|
v.SetDefault("migrations_directory", "migrations")
|
||||||
v.SetDefault("actions.kind", "synchronous")
|
v.SetDefault("actions.kind", "synchronous")
|
||||||
@ -462,6 +508,13 @@ func (ec *ExecutionContext) readConfig() error {
|
|||||||
ServerConfig: ServerConfig{
|
ServerConfig: ServerConfig{
|
||||||
Endpoint: v.GetString("endpoint"),
|
Endpoint: v.GetString("endpoint"),
|
||||||
AdminSecret: adminSecret,
|
AdminSecret: adminSecret,
|
||||||
|
APIPaths: &ServerAPIPaths{
|
||||||
|
Query: v.GetString("api_paths.query"),
|
||||||
|
GraphQL: v.GetString("api_paths.graphql"),
|
||||||
|
Config: v.GetString("api_paths.config"),
|
||||||
|
PGDump: v.GetString("api_paths.pg_dump"),
|
||||||
|
Version: v.GetString("api_paths.version"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
MetadataDirectory: v.GetString("metadata_directory"),
|
MetadataDirectory: v.GetString("metadata_directory"),
|
||||||
MigrationsDirectory: v.GetString("migrations_directory"),
|
MigrationsDirectory: v.GetString("migrations_directory"),
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
|
|
||||||
"github.com/hasura/graphql-engine/cli"
|
"github.com/hasura/graphql-engine/cli"
|
||||||
|
"github.com/hasura/graphql-engine/cli/metadata/actions/types"
|
||||||
"github.com/hasura/graphql-engine/cli/migrate/database/hasuradb"
|
"github.com/hasura/graphql-engine/cli/migrate/database/hasuradb"
|
||||||
"github.com/hasura/graphql-engine/cli/migrate/source"
|
"github.com/hasura/graphql-engine/cli/migrate/source"
|
||||||
"github.com/hasura/graphql-engine/cli/migrate/source/file"
|
"github.com/hasura/graphql-engine/cli/migrate/source/file"
|
||||||
@ -319,7 +320,23 @@ func newScriptsUpdateConfigV2Cmd(ec *cli.ExecutionContext) *cobra.Command {
|
|||||||
return errors.Wrap(err, "cannot write metadata")
|
return errors.Wrap(err, "cannot write metadata")
|
||||||
}
|
}
|
||||||
ec.Spin("Writing new config file...")
|
ec.Spin("Writing new config file...")
|
||||||
err = ec.WriteConfig(nil)
|
// Read the config from config.yaml
|
||||||
|
cfgByt, err := ioutil.ReadFile(ec.ConfigFile)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "cannot read config file")
|
||||||
|
}
|
||||||
|
var cfg cli.Config
|
||||||
|
err = yaml.Unmarshal(cfgByt, &cfg)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "cannot parse config file")
|
||||||
|
}
|
||||||
|
cfg.Version = cli.V2
|
||||||
|
cfg.MetadataDirectory = ec.Viper.GetString("metadata_directory")
|
||||||
|
cfg.ActionConfig = &types.ActionExecutionConfig{
|
||||||
|
Kind: ec.Viper.GetString("actions.kind"),
|
||||||
|
HandlerWebhookBaseURL: ec.Viper.GetString("actions.handler_webhook_baseurl"),
|
||||||
|
}
|
||||||
|
err = ec.WriteConfig(&cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "cannot write config file")
|
return errors.Wrap(err, "cannot write config file")
|
||||||
}
|
}
|
||||||
|
@ -40,9 +40,9 @@ var (
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
MigrationsTable string
|
MigrationsTable string
|
||||||
SettingsTable string
|
SettingsTable string
|
||||||
v1URL *nurl.URL
|
queryURL *nurl.URL
|
||||||
graphqlURL *nurl.URL
|
graphqlURL *nurl.URL
|
||||||
schemDumpURL *nurl.URL
|
pgDumpURL *nurl.URL
|
||||||
Headers map[string]string
|
Headers map[string]string
|
||||||
isCMD bool
|
isCMD bool
|
||||||
Plugins types.MetadataPlugins
|
Plugins types.MetadataPlugins
|
||||||
@ -115,20 +115,20 @@ func (h *HasuraDB) Open(url string, isCMD bool, logger *log.Logger) (database.Dr
|
|||||||
config := &Config{
|
config := &Config{
|
||||||
MigrationsTable: DefaultMigrationsTable,
|
MigrationsTable: DefaultMigrationsTable,
|
||||||
SettingsTable: DefaultSettingsTable,
|
SettingsTable: DefaultSettingsTable,
|
||||||
v1URL: &nurl.URL{
|
queryURL: &nurl.URL{
|
||||||
Scheme: scheme,
|
Scheme: scheme,
|
||||||
Host: hurl.Host,
|
Host: hurl.Host,
|
||||||
Path: path.Join(hurl.Path, "v1/query"),
|
Path: path.Join(hurl.Path, params.Get("query")),
|
||||||
},
|
},
|
||||||
graphqlURL: &nurl.URL{
|
graphqlURL: &nurl.URL{
|
||||||
Scheme: scheme,
|
Scheme: scheme,
|
||||||
Host: hurl.Host,
|
Host: hurl.Host,
|
||||||
Path: path.Join(hurl.Path, "v1/graphql"),
|
Path: path.Join(hurl.Path, params.Get("graphql")),
|
||||||
},
|
},
|
||||||
schemDumpURL: &nurl.URL{
|
pgDumpURL: &nurl.URL{
|
||||||
Scheme: scheme,
|
Scheme: scheme,
|
||||||
Host: hurl.Host,
|
Host: hurl.Host,
|
||||||
Path: path.Join(hurl.Path, "v1alpha1/pg_dump"),
|
Path: path.Join(hurl.Path, params.Get("pg_dump")),
|
||||||
},
|
},
|
||||||
isCMD: isCMD,
|
isCMD: isCMD,
|
||||||
Headers: headers,
|
Headers: headers,
|
||||||
@ -417,7 +417,7 @@ func (h *HasuraDB) ensureVersionTable() error {
|
|||||||
|
|
||||||
func (h *HasuraDB) sendv1Query(m interface{}) (resp *http.Response, body []byte, err error) {
|
func (h *HasuraDB) sendv1Query(m interface{}) (resp *http.Response, body []byte, err error) {
|
||||||
request := gorequest.New()
|
request := gorequest.New()
|
||||||
request = request.Post(h.config.v1URL.String()).Send(m)
|
request = request.Post(h.config.queryURL.String()).Send(m)
|
||||||
for headerName, headerValue := range h.config.Headers {
|
for headerName, headerValue := range h.config.Headers {
|
||||||
request.Set(headerName, headerValue)
|
request.Set(headerName, headerValue)
|
||||||
}
|
}
|
||||||
@ -455,7 +455,7 @@ func (h *HasuraDB) sendv1GraphQL(query interface{}) (resp *http.Response, body [
|
|||||||
func (h *HasuraDB) sendSchemaDumpQuery(m interface{}) (resp *http.Response, body []byte, err error) {
|
func (h *HasuraDB) sendSchemaDumpQuery(m interface{}) (resp *http.Response, body []byte, err error) {
|
||||||
request := gorequest.New()
|
request := gorequest.New()
|
||||||
|
|
||||||
request = request.Post(h.config.schemDumpURL.String()).Send(m)
|
request = request.Post(h.config.pgDumpURL.String()).Send(m)
|
||||||
|
|
||||||
for headerName, headerValue := range h.config.Headers {
|
for headerName, headerValue := range h.config.Headers {
|
||||||
request.Set(headerName, headerValue)
|
request.Set(headerName, headerValue)
|
||||||
|
@ -121,7 +121,7 @@ func FilterCustomQuery(u *nurl.URL) *nurl.URL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewMigrate(ec *cli.ExecutionContext, isCmd bool) (*Migrate, error) {
|
func NewMigrate(ec *cli.ExecutionContext, isCmd bool) (*Migrate, error) {
|
||||||
dbURL := GetDataPath(ec.Config.ServerConfig.ParsedEndpoint, GetAdminSecretHeaderName(ec.Version), ec.Config.ServerConfig.AdminSecret)
|
dbURL := GetDataPath(ec)
|
||||||
fileURL := GetFilePath(ec.MigrationDir)
|
fileURL := GetFilePath(ec.MigrationDir)
|
||||||
t, err := New(fileURL.String(), dbURL.String(), isCmd, int(ec.Config.Version), ec.Logger)
|
t, err := New(fileURL.String(), dbURL.String(), isCmd, int(ec.Config.Version), ec.Logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -132,13 +132,15 @@ func NewMigrate(ec *cli.ExecutionContext, isCmd bool) (*Migrate, error) {
|
|||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDataPath(url *nurl.URL, adminSecretHeader, adminSecretValue string) *nurl.URL {
|
func GetDataPath(ec *cli.ExecutionContext) *nurl.URL {
|
||||||
|
url := ec.Config.ServerConfig.ParsedEndpoint
|
||||||
host := &nurl.URL{
|
host := &nurl.URL{
|
||||||
Scheme: "hasuradb",
|
Scheme: "hasuradb",
|
||||||
Host: url.Host,
|
Host: url.Host,
|
||||||
Path: url.Path,
|
Path: url.Path,
|
||||||
|
RawQuery: ec.Config.ServerConfig.APIPaths.GetQueryParams().Encode(),
|
||||||
}
|
}
|
||||||
q := url.Query()
|
q := host.Query()
|
||||||
// Set sslmode in query
|
// Set sslmode in query
|
||||||
switch scheme := url.Scheme; scheme {
|
switch scheme := url.Scheme; scheme {
|
||||||
case "https":
|
case "https":
|
||||||
@ -146,8 +148,8 @@ func GetDataPath(url *nurl.URL, adminSecretHeader, adminSecretValue string) *nur
|
|||||||
default:
|
default:
|
||||||
q.Set("sslmode", "disable")
|
q.Set("sslmode", "disable")
|
||||||
}
|
}
|
||||||
if adminSecretValue != "" {
|
if GetAdminSecretHeaderName(ec.Version) != "" {
|
||||||
q.Add("headers", fmt.Sprintf("%s:%s", adminSecretHeader, adminSecretValue))
|
q.Add("headers", fmt.Sprintf("%s:%s", GetAdminSecretHeaderName(ec.Version), ec.Config.ServerConfig.AdminSecret))
|
||||||
}
|
}
|
||||||
host.RawQuery = q.Encode()
|
host.RawQuery = q.Encode()
|
||||||
return host
|
return host
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
package version
|
package version
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
|
|
||||||
yaml "github.com/ghodss/yaml"
|
yaml "github.com/ghodss/yaml"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -16,12 +14,7 @@ type serverVersionResponse struct {
|
|||||||
|
|
||||||
// FetchServerVersion reads the version from server.
|
// FetchServerVersion reads the version from server.
|
||||||
func FetchServerVersion(endpoint string) (version string, err error) {
|
func FetchServerVersion(endpoint string) (version string, err error) {
|
||||||
ep, err := url.Parse(endpoint)
|
response, err := http.Get(endpoint)
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrap(err, "cannot parse endpoint as a valid url")
|
|
||||||
}
|
|
||||||
versionEndpoint := fmt.Sprintf("%s/v1/version", ep.String())
|
|
||||||
response, err := http.Get(versionEndpoint)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.Wrap(err, "failed making version api call")
|
return "", errors.Wrap(err, "failed making version api call")
|
||||||
}
|
}
|
||||||
@ -30,7 +23,7 @@ func FetchServerVersion(endpoint string) (version string, err error) {
|
|||||||
case http.StatusNotFound:
|
case http.StatusNotFound:
|
||||||
return "", nil
|
return "", nil
|
||||||
default:
|
default:
|
||||||
return "", errors.Errorf("GET %s failed - [%d]", versionEndpoint, response.StatusCode)
|
return "", errors.Errorf("GET %s failed - [%d]", endpoint, response.StatusCode)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
|
Loading…
Reference in New Issue
Block a user