Skip to content

Commit

Permalink
cli: support ee-lite in CLI console
Browse files Browse the repository at this point in the history
Closes https://hasurahq.atlassian.net/browse/PLAT-351

PR-URL: hasura/graphql-engine-mono#7256
Co-authored-by: Sooraj <8408875+soorajshankar@users.noreply.github.com>
Co-authored-by: Manas Agarwal <5352361+manasag@users.noreply.github.com>
GitOrigin-RevId: 5096e76f11ab2860fae9fa7cd71c9afaead20cc0
  • Loading branch information
3 people authored and hasura-bot committed Jan 30, 2023
1 parent f7d4051 commit a0c5e16
Show file tree
Hide file tree
Showing 11 changed files with 217 additions and 20 deletions.
3 changes: 2 additions & 1 deletion cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (

"github.com/hasura/graphql-engine/cli/v2/internal/hasura/pgdump"
"github.com/hasura/graphql-engine/cli/v2/internal/hasura/v1graphql"
"github.com/hasura/graphql-engine/cli/v2/internal/hasura/v1version"
"github.com/hasura/graphql-engine/cli/v2/migrate/database/hasuradb"

"github.com/hasura/graphql-engine/cli/v2/internal/hasura/v1metadata"
Expand Down Expand Up @@ -228,7 +229,6 @@ func (c *ServerConfig) GetHasuraInternalServerConfig(client *httpc.Client) error
if err != nil {
return errors.E(op, fmt.Errorf("error fetching config from server: %w", err))
}

r, err := client.Do(ctx, req, &c.HasuraServerInternalConfig)
if err != nil {
return errors.E(op, errors.KindNetwork, err)
Expand Down Expand Up @@ -771,6 +771,7 @@ You could fix this problem by taking one of the following actions:
V2Query: v2query.New(httpClient, ec.Config.GetV2QueryEndpoint()),
PGDump: pgdump.New(httpClient, ec.Config.GetPGDumpEndpoint()),
V1Graphql: v1graphql.New(httpClient, ec.Config.GetV1GraphqlEndpoint()),
V1Version: v1version.New(httpClient, ec.Config.GetVersionEndpoint()),
}
var state *util.ServerState
if ec.HasMetadataV3 {
Expand Down
51 changes: 39 additions & 12 deletions cli/commands/console.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,7 @@ func (o *ConsoleOptions) Run() error {
return errors.E(op, err)
}

// Setup console server
const basePath = "templates/gohtml/"
const templateFilename = "console.gohtml"
templateProvider := console.NewDefaultTemplateProvider(basePath, templateFilename, console.ConsoleFS)
consoleTemplateVersion := templateProvider.GetTemplateVersion(o.EC.Version)
consoleAssetsVersion := templateProvider.GetAssetsVersion(o.EC.Version)
o.EC.Logger.Debugf("rendering console template [%s] with assets [%s]", consoleTemplateVersion, consoleAssetsVersion)

var templateProvider console.TemplateProvider
adminSecretHeader := cli.GetAdminSecretHeaderName(o.EC.Version)
if o.EC.Config.ServerConfig.HasuraServerInternalConfig.ConsoleAssetsDir != "" {
o.UseServerAssets = true
Expand All @@ -159,7 +152,8 @@ func (o *ConsoleOptions) Run() error {
// change to dataApiUrl value user entered in flag --console-hge-endpoint
dataApiUrl = o.DataApiUrl
}
consoleRouter, err := console.BuildConsoleRouter(templateProvider, consoleTemplateVersion, o.StaticDir, gin.H{

templateVars := gin.H{
"apiHost": o.APIHost.String(),
"apiPort": o.APIPort,
"cliVersion": o.EC.Version.GetCLIVersion(),
Expand All @@ -168,15 +162,48 @@ func (o *ConsoleOptions) Run() error {
"dataApiVersion": "",
"hasAccessKey": adminSecretHeader == cli.XHasuraAccessKey,
"adminSecret": o.EC.Config.ServerConfig.AdminSecret,
"assetsPath": templateProvider.GetAssetsCDN(),
"assetsVersion": consoleAssetsVersion,
"enableTelemetry": o.EC.GlobalConfig.EnableTelemetry,
"cliUUID": o.EC.GlobalConfig.UUID,
"migrateSkipExecution": true,
"cdnAssets": !o.UseServerAssets,
"consolePath": "/console",
"urlPrefix": "/console",
})
}
const basePath = "templates/gohtml/"
const templateFilename = "console.gohtml"

versionInfo, err := o.EC.APIClient.V1Version.GetVersion()
if err != nil {
return errors.E(op, err)
}
templateProvider = console.NewDefaultTemplateProvider(basePath, templateFilename, console.ConsoleFS)
// we use the default template provider by default but
// if we are able to find out the server type from the version API
// introduced in: https://github.com/hasura/graphql-engine-mono/pull/7141
// we will use that information to choose the correct server type and set the
// template provider accordingly.
if versionInfo.ServerType != nil {
switch *versionInfo.ServerType {
case "ee":
templateVars["consoleType"] = "pro-lite"
templateProvider = console.NewEETemplateProvider(basePath, templateFilename, console.ConsoleFS)
case "ee-classic":
templateVars["consoleType"] = "pro"
templateProvider = console.NewEETemplateProvider(basePath, templateFilename, console.ConsoleFS)
case "cloud":
templateVars["consoleType"] = "cloud"
templateProvider = console.NewCloudTemplateProvider(basePath, templateFilename, console.ConsoleFS)
}
}
consoleTemplateVersion := templateProvider.GetTemplateVersion(o.EC.Version)
consoleAssetsVersion := templateProvider.GetAssetsVersion(o.EC.Version)
templateVars["assetsVersion"] = consoleAssetsVersion
templateVars["assetsPath"] = templateProvider.GetAssetsCDN()

// Setup console server
o.EC.Logger.Debugf("rendering console template [%s] with assets [%s]", consoleTemplateVersion, consoleAssetsVersion)

consoleRouter, err := console.BuildConsoleRouter(templateProvider, consoleTemplateVersion, o.StaticDir, templateVars)
if err != nil {
return errors.E(op, fmt.Errorf("error serving console: %w", err))
}
Expand Down
10 changes: 10 additions & 0 deletions cli/internal/hasura/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Client struct {
V2Query V2Query
PGDump PGDump
V1Graphql V1Graphql
V1Version V1Version
}

type V1Query interface {
Expand Down Expand Up @@ -53,6 +54,15 @@ type V2Query interface {
Bulk([]RequestBody) (io.Reader, error)
}

type V1VersionResponse struct {
Version string `json:"version,omitempty"`
ServerType *string `json:"server_type,omitempty"`
}

type V1Version interface {
GetVersion() (*V1VersionResponse, error)
}

type IntrospectionSchema interface{}
type V1Graphql interface {
GetIntrospectionSchema() (IntrospectionSchema, error)
Expand Down
58 changes: 58 additions & 0 deletions cli/internal/hasura/v1version/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package v1version

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"

"github.com/hasura/graphql-engine/cli/v2/internal/errors"
"github.com/hasura/graphql-engine/cli/v2/internal/hasura"
"github.com/hasura/graphql-engine/cli/v2/internal/httpc"
)

type Client struct {
*httpc.Client
path string
}

func New(client *httpc.Client, path string) *Client {
return &Client{client, path}
}

func (c *Client) GetVersion() (*hasura.V1VersionResponse, error) {
var op errors.Op = "v1version.Client.GetVersion"
b := new(bytes.Buffer)
resp, err := c.send(nil, b)
if err != nil {
return nil, errors.E(op, err)
}

if resp.StatusCode != http.StatusOK {
if b.Len() > 0 {
return nil, errors.E(op, errors.KindHasuraAPI, b.String())
} else {
return nil, errors.E(op, errors.KindHasuraAPI, fmt.Errorf("API request to %v failed, code: %v", c.path, resp.StatusCode))
}
}
o := new(hasura.V1VersionResponse)
if err := json.NewDecoder(b).Decode(o); err != nil {
return nil, errors.E(op, fmt.Errorf("decoding API response failed for: %v", c.path))
}
return o, nil
}

func (c *Client) send(body interface{}, responseBodyWriter io.Writer) (*httpc.Response, error) {
var op errors.Op = "v1version.Client.send"
req, err := c.NewRequest(http.MethodGet, c.path, body)
if err != nil {
return nil, errors.E(op, err)
}
resp, err := c.LockAndDo(context.Background(), req, responseBodyWriter)
if err != nil {
return nil, errors.E(op, err)
}
return resp, nil
}
36 changes: 36 additions & 0 deletions cli/pkg/console/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,39 @@ func (p *DefaultTemplateProvider) GetAssetsVersion(v *version.Version) string {
func (p *DefaultTemplateProvider) GetAssetsCDN() string {
return "https://graphql-engine-cdn.hasura.io/console/assets"
}

type EELiteTemplateProvider struct {
*DefaultTemplateProvider
}

func NewEETemplateProvider(basePath string, templateFileName string, consoleFs embed.FS) *EELiteTemplateProvider {
return &EELiteTemplateProvider{
NewDefaultTemplateProvider(basePath, templateFileName, consoleFs),
}
}

func (p *EELiteTemplateProvider) GetAssetsVersion(v *version.Version) string {
return fmt.Sprintf("channel/versioned/%s", v.Server)
}

func (p *EELiteTemplateProvider) GetAssetsCDN() string {
return "https://graphql-engine-cdn.hasura.io/pro-console/assets"
}

type CloudTemplateProvider struct {
*DefaultTemplateProvider
}

func (p *CloudTemplateProvider) GetAssetsVersion(v *version.Version) string {
return fmt.Sprintf("channel/versioned/%s", v.Server)
}

func (p *CloudTemplateProvider) GetAssetsCDN() string {
return "https://graphql-engine-cdn.hasura.io/cloud-console/assets"
}

func NewCloudTemplateProvider(basePath string, templateFileName string, consoleFs embed.FS) *CloudTemplateProvider {
return &CloudTemplateProvider{
NewDefaultTemplateProvider(basePath, templateFileName, consoleFs),
}
}
1 change: 1 addition & 0 deletions cli/pkg/console/templates/gohtml/latest/console.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
cdnAssets: {{.cdnAssets}},
assetsVersion: {{.assetsVersion}},
consolePath:{{.consolePath}},
consoleType: {{.consoleType}}
};
window.__env.versionedAssetsPath = window.__env.assetsPath;
</script>
Expand Down
3 changes: 2 additions & 1 deletion frontend/libs/console/legacy-ce/src/lib/helpers/localDev.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ const cliEnvVars = `
tenantID: '${process.env.HASURA_CLOUD_TENANT_ID || ''}',
projectID: '${process.env.HASURA_CLOUD_PROJECT_ID || ''}',
cloudRootDomain: '${process.env.HASURA_CLOUD_ROOT_DOMAIN}',
consoleSentryDsn: '${process.env.HASURA_CONSOLE_SENTRY_DSN}'
consoleSentryDsn: '${process.env.HASURA_CONSOLE_SENTRY_DSN}',
consoleType: '${process.env.HASURA_CONSOLE_TYPE}'
`;

const envVars = process.env.CONSOLE_MODE === 'cli' ? cliEnvVars : serverEnvVars;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,46 @@ describe('isProConsole', () => {
expect(isProConsole(env)).toBe(false);
});
});

describe('when consoleMode is cli and consoleType is cloud', () => {
it('returns true', () => {
const env: ProConsoleEnv = {
consoleMode: 'cli',
consoleType: 'cloud',
};
expect(isProConsole(env)).toBe(true);
});
});

describe('when consoleMode is cli and consoleType is pro', () => {
it('returns true', () => {
const env: ProConsoleEnv = {
consoleMode: 'cli',
consoleType: 'pro',
};
expect(isProConsole(env)).toBe(true);
});
});

describe('when consoleMode is cli and consoleType is pro-lite', () => {
it('returns true', () => {
const env: ProConsoleEnv = {
consoleMode: 'cli',
consoleType: 'pro-lite',
};
expect(isProConsole(env)).toBe(true);
});
});

describe('when consoleMode is cli and consoleType is oss', () => {
it('returns false', () => {
const env: ProConsoleEnv = {
consoleMode: 'cli',
consoleType: 'oss',
};
expect(isProConsole(env)).toBe(false);
});
});
});

describe('isMonitoringTabSupportedEnvironment', () => {
Expand Down
12 changes: 10 additions & 2 deletions frontend/libs/console/legacy-ce/src/lib/utils/proConsole.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,16 @@ export const isProConsole = (env: ProConsoleEnv) => {
return true;
}

if (env.consoleMode === 'cli' && env.pro === true) {
return true;
if (env.consoleMode === 'cli') {
if (
env.consoleType === 'cloud' ||
env.consoleType === 'pro' ||
env.consoleType === 'pro-lite'
)
return true;

// to support old CLI logic, when consoleType is not provided by the CLI
if (env.pro === true) return true;
}

return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const cliEnvVars = `
pro: ${process.env.IS_PRO},
cloudRootDomain: '${process.env.HASURA_CLOUD_ROOT_DOMAIN}',
consoleSentryDsn: '${process.env.HASURA_CONSOLE_SENTRY_DSN}',
consoleType: '${process.env.HASURA_CONSOLE_TYPE}',
tenantID: '${process.env.HASURA_CLOUD_TENANT_ID || ''}',
`;

Expand Down
22 changes: 18 additions & 4 deletions frontend/libs/console/legacy-ee/src/lib/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -264,13 +264,27 @@ const routes = store => {
return composeOnEnterHooks(onEnterHooks)(...args);
};

/**
* ## checkIfAdmin
* This function checks if the user is an admin or not and redirects to the access denied page if not.
* This is used to hide the security tab from non-admin users.
*/
const checkIfAdmin = (nextState, replaceState) => {
const mainData = store.getState().main;
// when console type is pro-lite only admin secret login is allowed, making this check unnecessary
if (globals.consoleType !== 'pro-lite') {
if (!mainData.project.privileges.includes('admin')) {
replaceState('api/security/access_denied');
}
// ie. admin privileges are already checked in the login process
if (globals.consoleType === 'pro-lite') return; // show security tab

// cloud cli doesn't have any privileges when `hasura console` command is executed, it will only have previleges when `hasura pro console` is executed.
// this will make sure that security tab is visible even when the users are running `hasura console` command with valid admin secret
if (globals.consoleType === 'cloud' && globals.consoleMode === 'cli') {
// this will be true when `hasura console` is executed with a valid admin secret -> through which security tab APIs are accessible
if (globals.adminSecret && globals.adminSecret !== '') return; // show security tab
}

// check privileges for all other cases
if (!mainData.project.privileges.includes('admin')) {
replaceState('api/security/access_denied'); // show access denied page
}
};

Expand Down

0 comments on commit a0c5e16

Please sign in to comment.