diff --git a/ui/packages/consul-ui/app/services/client/http.js b/ui/packages/consul-ui/app/services/client/http.js index 9b77365019..708b64d2a5 100644 --- a/ui/packages/consul-ui/app/services/client/http.js +++ b/ui/packages/consul-ui/app/services/client/http.js @@ -203,12 +203,13 @@ export default class HttpService extends Service { // also see adapters/kv content-types in requestForCreate/UpdateRecord // also see https://github.com/hashicorp/consul/issues/3804 params.headers[CONTENT_TYPE] = 'application/json; charset=utf-8'; + params.url = `${this.env.var('CONSUL_API_PREFIX')}${params.url}`; return params; } fetchWithToken(path, params) { return this.settings.findBySlug('token').then(token => { - return fetch(`${path}`, { + return fetch(`${this.env.var('CONSUL_API_PREFIX')}${path}`, { ...params, credentials: 'include', headers: { diff --git a/ui/packages/consul-ui/app/utils/get-environment.js b/ui/packages/consul-ui/app/utils/get-environment.js index fd3757fbff..9fabe8b7ac 100644 --- a/ui/packages/consul-ui/app/utils/get-environment.js +++ b/ui/packages/consul-ui/app/utils/get-environment.js @@ -132,6 +132,12 @@ export default function(config = {}, win = window, doc = document) { return operatorConfig.LocalDatacenter; case 'CONSUL_DATACENTER_PRIMARY': return operatorConfig.PrimaryDatacenter; + case 'CONSUL_API_PREFIX': + // we want API prefix to look like an env var for if we ever change + // operator config to be an API request, we need this variable before we + // make and API request so this specific variable should never be be + // retrived via an API request + return operatorConfig.APIPrefix; case 'CONSUL_UI_CONFIG': dashboards = { service: undefined, @@ -246,6 +252,7 @@ export default function(config = {}, win = window, doc = document) { case 'CONSUL_UI_CONFIG': case 'CONSUL_DATACENTER_LOCAL': case 'CONSUL_DATACENTER_PRIMARY': + case 'CONSUL_API_PREFIX': case 'CONSUL_ACLS_ENABLED': case 'CONSUL_NSPACES_ENABLED': case 'CONSUL_PEERINGS_ENABLED': diff --git a/ui/packages/consul-ui/config/environment.js b/ui/packages/consul-ui/config/environment.js index a85b0093d8..4bd0967996 100644 --- a/ui/packages/consul-ui/config/environment.js +++ b/ui/packages/consul-ui/config/environment.js @@ -86,6 +86,7 @@ module.exports = function(environment, $ = process.env) { PartitionsEnabled: false, LocalDatacenter: env('CONSUL_DATACENTER_LOCAL', 'dc1'), PrimaryDatacenter: env('CONSUL_DATACENTER_PRIMARY', 'dc1'), + APIPrefix: env('CONSUL_API_PREFIX', '') }, // Static variables used in multiple places throughout the UI @@ -111,6 +112,7 @@ module.exports = function(environment, $ = process.env) { PartitionsEnabled: env('CONSUL_PARTITIONS_ENABLED', false), LocalDatacenter: env('CONSUL_DATACENTER_LOCAL', 'dc1'), PrimaryDatacenter: env('CONSUL_DATACENTER_PRIMARY', 'dc1'), + APIPrefix: env('CONSUL_API_PREFIX', '') }, '@hashicorp/ember-cli-api-double': { @@ -118,6 +120,7 @@ module.exports = function(environment, $ = process.env) { enabled: true, endpoints: { '/v1': '/mock-api/v1', + '/prefixed-api': '/mock-api/prefixed-api', }, }, APP: Object.assign({}, ENV.APP, { @@ -162,6 +165,7 @@ module.exports = function(environment, $ = process.env) { PartitionsEnabled: env('CONSUL_PARTITIONS_ENABLED', true), LocalDatacenter: env('CONSUL_DATACENTER_LOCAL', 'dc1'), PrimaryDatacenter: env('CONSUL_DATACENTER_PRIMARY', 'dc1'), + APIPrefix: env('CONSUL_API_PREFIX', '') }, '@hashicorp/ember-cli-api-double': { @@ -176,7 +180,9 @@ module.exports = function(environment, $ = process.env) { ENV = Object.assign({}, ENV, { // in production operatorConfig is populated at consul runtime from // operator configuration - operatorConfig: {}, + operatorConfig: { + APIPrefix: '' + }, }); break; } diff --git a/ui/packages/consul-ui/mock-api/prefixed-api/v1/catalog/.config b/ui/packages/consul-ui/mock-api/prefixed-api/v1/catalog/.config new file mode 100644 index 0000000000..93326539bf --- /dev/null +++ b/ui/packages/consul-ui/mock-api/prefixed-api/v1/catalog/.config @@ -0,0 +1,7 @@ +--- +"*": + GET: + "*": + headers: + response: + X-Consul-Default-Acl-Policy: ${env('CONSUL_ACL_POLICY', fake.helpers.randomize(['allow', 'deny']))} diff --git a/ui/packages/consul-ui/mock-api/prefixed-api/v1/catalog/datacenters b/ui/packages/consul-ui/mock-api/prefixed-api/v1/catalog/datacenters new file mode 100644 index 0000000000..5cfa3ee6b2 --- /dev/null +++ b/ui/packages/consul-ui/mock-api/prefixed-api/v1/catalog/datacenters @@ -0,0 +1,13 @@ +[ + ${ + range(env('CONSUL_DATACENTER_COUNT', 10)).map((item, i) => { + if(i === 0) { + return `"${env('CONSUL_DATACENTER_LOCAL', 'dc1')}"`; + } + return ` + "${fake.address.countryCode().toLowerCase()}_${ i % 2 ? "west" : "east"}-${i}" +`; + } + ) + } +] diff --git a/ui/packages/consul-ui/mock-api/prefixed-api/v1/internal/acl/authorize b/ui/packages/consul-ui/mock-api/prefixed-api/v1/internal/acl/authorize new file mode 100644 index 0000000000..11d84ed6e4 --- /dev/null +++ b/ui/packages/consul-ui/mock-api/prefixed-api/v1/internal/acl/authorize @@ -0,0 +1,14 @@ +[ +${ + http.body.map(item => { + return JSON.stringify( + Object.assign( + item, + { + Allow: !!JSON.parse(env(`CONSUL_RESOURCE_${item.Resource.toUpperCase()}_${item.Access.toUpperCase()}`, 'true')) + } + ) + ); + }) +} +] diff --git a/ui/packages/consul-ui/mock-api/prefixed-api/v1/internal/ui/services b/ui/packages/consul-ui/mock-api/prefixed-api/v1/internal/ui/services new file mode 100644 index 0000000000..ccf51a864a --- /dev/null +++ b/ui/packages/consul-ui/mock-api/prefixed-api/v1/internal/ui/services @@ -0,0 +1,22 @@ +[ + { + "Name": "consul", + "Datacenter": "dc1", + "Tags": null, + "Nodes": [ + "node" + ], + "ExternalSources": null, + "InstanceCount": 1, + "ChecksPassing": 1, + "ChecksWarning": 0, + "ChecksCritical": 0, + "GatewayConfig": {}, + "TransparentProxy": false, + "ConnectNative": false, + "Partition": "default", + "Namespace": "default", + "ConnectedWithProxy": false, + "ConnectedWithGateway": false + } +] diff --git a/ui/packages/consul-ui/node-tests/config/environment.js b/ui/packages/consul-ui/node-tests/config/environment.js index fc64faf944..286fb741db 100644 --- a/ui/packages/consul-ui/node-tests/config/environment.js +++ b/ui/packages/consul-ui/node-tests/config/environment.js @@ -11,7 +11,9 @@ test( { environment: 'production', CONSUL_BINARY_TYPE: 'oss', - operatorConfig: {} + operatorConfig: { + APIPrefix: '', + } }, { environment: 'test', @@ -24,6 +26,7 @@ test( PeeringEnabled: true, LocalDatacenter: 'dc1', PrimaryDatacenter: 'dc1', + APIPrefix: '', } }, { @@ -40,6 +43,7 @@ test( PeeringEnabled: true, LocalDatacenter: 'dc1', PrimaryDatacenter: 'dc1', + APIPrefix: '', } }, { @@ -56,6 +60,7 @@ test( PeeringEnabled: true, LocalDatacenter: 'dc1', PrimaryDatacenter: 'dc1', + APIPrefix: '', } }, { @@ -69,6 +74,7 @@ test( PeeringEnabled: true, LocalDatacenter: 'dc1', PrimaryDatacenter: 'dc1', + APIPrefix: '', } } ].forEach( diff --git a/ui/packages/consul-ui/tests/acceptance/api-prefix.feature b/ui/packages/consul-ui/tests/acceptance/api-prefix.feature new file mode 100644 index 0000000000..bc4a9d87e3 --- /dev/null +++ b/ui/packages/consul-ui/tests/acceptance/api-prefix.feature @@ -0,0 +1,7 @@ +@setupApplicationTest +Feature: api-prefix + Scenario: + Given 1 datacenter model with the value "dc1" + And an API prefix of "/prefixed-api" + When I visit the index page + Then a GET request was made to "/prefixed-api/v1/catalog/datacenters" diff --git a/ui/packages/consul-ui/tests/acceptance/steps/api-prefix-steps.js b/ui/packages/consul-ui/tests/acceptance/steps/api-prefix-steps.js new file mode 100644 index 0000000000..f40e979108 --- /dev/null +++ b/ui/packages/consul-ui/tests/acceptance/steps/api-prefix-steps.js @@ -0,0 +1,11 @@ +import steps from './steps'; + +// step definitions that are shared between features should be moved to the +// tests/acceptance/steps/steps.js file + +export default function(assert) { + return steps(assert) + .then('I should find a file', function() { + assert.ok(true, this.step); + }); +} diff --git a/ui/packages/consul-ui/tests/steps.js b/ui/packages/consul-ui/tests/steps.js index 43b1c0c553..973098dae8 100644 --- a/ui/packages/consul-ui/tests/steps.js +++ b/ui/packages/consul-ui/tests/steps.js @@ -87,6 +87,7 @@ export default function({ api.server.respondWith(url.split('?')[0], data); }; const setCookie = function(key, value) { + document.cookie = `${key}=${value}`; api.server.setCookie(key, value); }; diff --git a/ui/packages/consul-ui/tests/steps/doubles/http.js b/ui/packages/consul-ui/tests/steps/doubles/http.js index b92ec8ae7d..3624cc1aa2 100644 --- a/ui/packages/consul-ui/tests/steps/doubles/http.js +++ b/ui/packages/consul-ui/tests/steps/doubles/http.js @@ -17,5 +17,8 @@ export default function(scenario, respondWith, set, oidc) { }) .given('a network latency of $number', function(number) { set('CONSUL_LATENCY', number); + }) + .given('an API prefix of "$prefix"', function(prefix) { + set('CONSUL_API_PREFIX', prefix); }); }