From 9a302f6f4ae544ad1ed839dccc23b9e3e512b077 Mon Sep 17 00:00:00 2001 From: John Cowen Date: Mon, 19 Oct 2020 17:29:43 +0100 Subject: [PATCH] ui: Clean up and document environment.js file (#8966) * Move various environment getting utils out of the main file and test/doc * Clean up and document the entire environment file * Tweak the environment tests to reflect what they should be * Explicitly enable namespaces instead of defaulting * Allow env fallback functions to be called lazily Otherwise the executables used for finding out things would be required during build, this way if env vars are set the executable aren't needed * Infer booleans from the fallback and cast them as such --- .circleci/config.yml | 1 + ui-v2/config/environment.js | 162 +++++++++++++------------ ui-v2/config/utils.js | 32 +++++ ui-v2/node-tests/config/environment.js | 22 ++-- ui-v2/node-tests/config/utils.js | 28 +++++ 5 files changed, 159 insertions(+), 86 deletions(-) create mode 100644 ui-v2/config/utils.js create mode 100644 ui-v2/node-tests/config/utils.js diff --git a/.circleci/config.yml b/.circleci/config.yml index a3755648af..fac4584bd9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -704,6 +704,7 @@ jobs: environment: EMBER_TEST_REPORT: test-results/report-ent.xml #outputs test report for CircleCI test summary EMBER_TEST_PARALLEL: true #enables test parallelization with ember-exam + CONSUL_NSPACES_ENABLED: 1 parallelism: 4 steps: - checkout diff --git a/ui-v2/config/environment.js b/ui-v2/config/environment.js index a6dca6b2ba..485fe35d13 100644 --- a/ui-v2/config/environment.js +++ b/ui-v2/config/environment.js @@ -1,16 +1,49 @@ 'use strict'; -const fs = require('fs'); const path = require('path'); -module.exports = function (environment, $ = process.env) { +const utils = require('./utils'); + +const repositoryRoot = path.resolve(__dirname, '../../'); + +const repositoryYear = utils.repositoryYear; +const repositorySHA = utils.repositorySHA; +const binaryVersion = utils.binaryVersion(repositoryRoot); + +module.exports = function(environment, $ = process.env) { + // basic 'get env var with fallback' accessor + const env = function(flag, fallback) { + // a fallback value MUST be set + if (typeof fallback === 'undefined') { + throw new Error(`Please provide a fallback value for $${flag}`); + } + // return the env var if set + if (typeof $[flag] !== 'undefined') { + if (typeof fallback === 'boolean') { + // if we are expecting a boolean JSON parse strings to numbers/booleans + return !!JSON.parse($[flag]); + } + return $[flag]; + } + // If the fallback is a function call it and return the result. + // Lazily calling the function means binaries used for fallback don't need + // to be available if we are sure the environment variables will be set + if (typeof fallback === 'function') { + return fallback(); + } + // just return the fallback value + return fallback; + }; + let ENV = { modulePrefix: 'consul-ui', environment, rootURL: '/ui/', locationType: 'auto', - // We use a complete dynamically (from Consul) configured - // torii provider. We provide this object here to - // prevent ember from giving a log message when starting ember up + + // We use a complete dynamically (from Consul) configured torii provider. + // We provide this object here to prevent ember from giving a log message + // when starting ember up torii: {}, + EmberENV: { FEATURES: { // Here you can enable experimental features on an ember canary build @@ -29,52 +62,42 @@ module.exports = function (environment, $ = process.env) { injectionFactories: ['view', 'controller', 'component'], }, }; + + // The following 'environment variables' are set at build-time and compiled + // into a meta tag in generated index.html file. + // They can be accessed in the UI by using either: + // + // 1. The 'env' service from within javascript: `@service('env') env;` (../app/services/env.js) + // 2. The 'env' helper from within hbs: `{{env 'VARIABLE_NAME'}}` (../app/helpers/env.js) + // + // These variables can be overwritten depending on certain environments. + // For example for a production release the binary will overwrite some + // variables at runtime, during development some variables can be + // overwritten by adding cookie values using the browsers' Web Inspector + // TODO: These should probably go onto APP ENV = Object.assign({}, ENV, { - CONSUL_UI_DISABLE_REALTIME: typeof process.env.CONSUL_UI_DISABLE_REALTIME !== 'undefined', - CONSUL_UI_DISABLE_ANCHOR_SELECTION: - typeof process.env.CONSUL_UI_DISABLE_ANCHOR_SELECTION !== 'undefined', - CONSUL_COPYRIGHT_YEAR: (function (val) { - if (val) { - return val; - } - return require('child_process') - .execSync('git show -s --format=%ci HEAD') - .toString() - .trim() - .split('-') - .shift(); - })(process.env.CONSUL_COPYRIGHT_YEAR), - CONSUL_GIT_SHA: (function (val) { - if (val) { - return val; - } + // The following variables are compile-time variables that are set during + // the consul build process and baked into the generated assetsfs file that + // is later added to the consul binary itself. Some values, if not set, + // will automatically pull information from the git repository which means + // these values are guaranteed to be set/correct during development. + CONSUL_COPYRIGHT_YEAR: env('CONSUL_COPYRIGHT_YEAR', repositoryYear), + CONSUL_GIT_SHA: env('CONSUL_GIT_SHA', repositorySHA), + CONSUL_VERSION: env('CONSUL_VERSION', binaryVersion), + CONSUL_BINARY_TYPE: env('CONSUL_BINARY_TYPE', 'oss'), - return require('child_process') - .execSync('git rev-parse --short HEAD') - .toString() - .trim(); - })(process.env.CONSUL_GIT_SHA), - CONSUL_VERSION: (function (val) { - if (val) { - return val; - } - // see /scripts/dist.sh:8 - const version_go = `${path.dirname(path.dirname(__dirname))}/version/version.go`; - const contents = fs.readFileSync(version_go).toString(); - return contents - .split('\n') - .find(function (item, i, arr) { - return item.indexOf('Version =') !== -1; - }) - .trim() - .split('"')[1]; - })(process.env.CONSUL_VERSION), - CONSUL_BINARY_TYPE: process.env.CONSUL_BINARY_TYPE ? process.env.CONSUL_BINARY_TYPE : 'oss', + // These can be overwritten by the UI user at runtime by setting localStorage values + CONSUL_UI_DISABLE_REALTIME: env('CONSUL_UI_DISABLE_REALTIME', false), + CONSUL_UI_DISABLE_ANCHOR_SELECTION: env('CONSUL_UI_DISABLE_ANCHOR_SELECTION', false), + + // The following variables are runtime variables that are overwritten when + // the go binary services the index.html page CONSUL_ACLS_ENABLED: false, CONSUL_NSPACES_ENABLED: false, CONSUL_SSO_ENABLED: false, + // Static variables used in multiple places throughout the UI CONSUL_HOME_URL: 'https://www.consul.io', CONSUL_REPO_ISSUES_URL: 'https://github.com/hashicorp/consul/issues/new/choose', CONSUL_DOCS_URL: 'https://www.consul.io/docs', @@ -82,22 +105,16 @@ module.exports = function (environment, $ = process.env) { CONSUL_DOCS_API_URL: 'https://www.consul.io/api', CONSUL_COPYRIGHT_URL: 'https://www.hashicorp.com', }); - const isTestLike = ['staging', 'test'].indexOf(environment) > -1; - const isDevLike = ['development', 'staging', 'test'].indexOf(environment) > -1; - const isProdLike = ['production', 'staging'].indexOf(environment) > -1; switch (true) { case environment === 'test': ENV = Object.assign({}, ENV, { locationType: 'none', - CONSUL_NSPACES_TEST: true, - CONSUL_NSPACES_ENABLED: - typeof $['CONSUL_NSPACES_ENABLED'] !== 'undefined' - ? !!JSON.parse(String($['CONSUL_NSPACES_ENABLED']).toLowerCase()) - : true, - CONSUL_SSO_ENABLED: - typeof $['CONSUL_SSO_ENABLED'] !== 'undefined' - ? !!JSON.parse(String($['CONSUL_SSO_ENABLED']).toLowerCase()) - : false, + + // During testing ACLs default to being turned on + CONSUL_ACLS_ENABLED: env('CONSUL_ACLS_ENABLED', true), + CONSUL_NSPACES_ENABLED: env('CONSUL_NSPACES_ENABLED', false), + CONSUL_SSO_ENABLED: env('CONSUL_SSO_ENABLED', false), + '@hashicorp/ember-cli-api-double': { 'auto-import': false, enabled: true, @@ -109,6 +126,11 @@ module.exports = function (environment, $ = process.env) { LOG_ACTIVE_GENERATION: false, LOG_VIEW_LOOKUPS: false, + // LOG_RESOLVER: true, + // LOG_ACTIVE_GENERATION: true, + // LOG_TRANSITIONS: true, + // LOG_TRANSITIONS_INTERNAL: true, + rootElement: '#ember-testing', autoboot: false, }), @@ -116,8 +138,14 @@ module.exports = function (environment, $ = process.env) { break; case environment === 'staging': ENV = Object.assign({}, ENV, { - CONSUL_NSPACES_ENABLED: true, - CONSUL_SSO_ENABLED: true, + // On staging sites everything defaults to being turned on by + // different staging sites can be built with certain features disabled + // by setting an environment variable to 0 during building (e.g. + // CONSUL_NSPACES_ENABLED=0 make build) + CONSUL_ACLS_ENABLED: env('CONSUL_ACLS_ENABLED', true), + CONSUL_NSPACES_ENABLED: env('CONSUL_NSPACES_ENABLED', true), + CONSUL_SSO_ENABLED: env('CONSUL_SSO_ENABLED', true), + '@hashicorp/ember-cli-api-double': { enabled: true, endpoints: { @@ -134,7 +162,7 @@ module.exports = function (environment, $ = process.env) { // tag which obscured the Go template tag syntax. // // __RUNTIME_BOOL_Xxxx__ will be replaced with either "true" or "false" - // depending on whether the named variable is true or valse in the data + // depending on whether the named variable is true or false in the data // returned from `uiTemplateDataFromConfig`. CONSUL_ACLS_ENABLED: '__RUNTIME_BOOL_ACLsEnabled__', CONSUL_SSO_ENABLED: '__RUNTIME_BOOL_SSOEnabled__', @@ -142,21 +170,5 @@ module.exports = function (environment, $ = process.env) { }); break; } - switch (true) { - case isTestLike: - ENV = Object.assign({}, ENV, { - CONSUL_ACLS_ENABLED: true, - // 'APP': Object.assign({}, ENV.APP, { - // 'LOG_RESOLVER': true, - // 'LOG_ACTIVE_GENERATION': true, - // 'LOG_TRANSITIONS': true, - // 'LOG_TRANSITIONS_INTERNAL': true, - // 'LOG_VIEW_LOOKUPS': true, - // }) - }); - break; - case isProdLike: - break; - } return ENV; }; diff --git a/ui-v2/config/utils.js b/ui-v2/config/utils.js new file mode 100644 index 0000000000..cc16e26ac5 --- /dev/null +++ b/ui-v2/config/utils.js @@ -0,0 +1,32 @@ +const read = require('fs').readFileSync; +const exec = require('child_process').execSync; + +// See tests ../node-tests/config/utils.js +const repositoryYear = function(date = exec('git show -s --format=%ci HEAD')) { + return date + .toString() + .trim() + .split('-') + .shift(); +}; +const repositorySHA = function(sha = exec('git rev-parse --short HEAD')) { + return sha.toString().trim(); +}; +const binaryVersion = function(repositoryRoot) { + return function(versionFileContents = read(`${repositoryRoot}/version/version.go`)) { + // see /scripts/dist.sh:8 + return versionFileContents + .toString() + .split('\n') + .find(function(item, i, arr) { + return item.indexOf('Version =') !== -1; + }) + .trim() + .split('"')[1]; + }; +}; +module.exports = { + repositoryYear: repositoryYear, + repositorySHA: repositorySHA, + binaryVersion: binaryVersion, +}; diff --git a/ui-v2/node-tests/config/environment.js b/ui-v2/node-tests/config/environment.js index 1c55034e4e..6b5b5fca22 100644 --- a/ui-v2/node-tests/config/environment.js +++ b/ui-v2/node-tests/config/environment.js @@ -14,16 +14,6 @@ test( CONSUL_NSPACES_ENABLED: '__RUNTIME_BOOL_NamespacesEnabled__', }, { - environment: 'test', - CONSUL_BINARY_TYPE: 'oss', - CONSUL_ACLS_ENABLED: true, - CONSUL_NSPACES_ENABLED: true, - CONSUL_SSO_ENABLED: false, - }, - { - $: { - CONSUL_NSPACES_ENABLED: 0 - }, environment: 'test', CONSUL_BINARY_TYPE: 'oss', CONSUL_ACLS_ENABLED: true, @@ -32,7 +22,7 @@ test( }, { $: { - CONSUL_SSO_ENABLED: 0 + CONSUL_NSPACES_ENABLED: 1 }, environment: 'test', CONSUL_BINARY_TYPE: 'oss', @@ -40,6 +30,16 @@ test( CONSUL_NSPACES_ENABLED: true, CONSUL_SSO_ENABLED: false, }, + { + $: { + CONSUL_SSO_ENABLED: 1 + }, + environment: 'test', + CONSUL_BINARY_TYPE: 'oss', + CONSUL_ACLS_ENABLED: true, + CONSUL_NSPACES_ENABLED: false, + CONSUL_SSO_ENABLED: true, + }, { environment: 'staging', CONSUL_BINARY_TYPE: 'oss', diff --git a/ui-v2/node-tests/config/utils.js b/ui-v2/node-tests/config/utils.js new file mode 100644 index 0000000000..d9bf3a8a79 --- /dev/null +++ b/ui-v2/node-tests/config/utils.js @@ -0,0 +1,28 @@ +const test = require('tape'); + +const utils = require('../../config/utils.js'); + +test( + 'utils.respositoryYear parses the year out correctly', + function(t) { + const expected = '2020'; + const actual = utils.repositoryYear('2020-10-14 16:34:57 -0700') + t.equal(actual, expected, 'It parses the year correctly'); + t.end(); + } +); +test( + 'utils.binaryVersion parses the version out correctly', + function(t) { + const expected = '1.9.0'; + const actual = utils.binaryVersion()(` + + Version = "1.9.0" + + VersionPrerelease = "dev" + +`) + t.equal(actual, expected, 'It parses the version correctly'); + t.end(); + } +);