diff --git a/ui-v2/app/adapters/gateway.js b/ui-v2/app/adapters/gateway.js
deleted file mode 100644
index 96d1e4cf1e..0000000000
--- a/ui-v2/app/adapters/gateway.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import Adapter from './application';
-
-export default Adapter.extend({
- requestForQueryRecord: function(request, { dc, ns, index, id }) {
- if (typeof id === 'undefined') {
- throw new Error('You must specify an id');
- }
- return request`
- GET /v1/internal/ui/gateway-services-nodes/${id}?${{ dc }}
-
- ${{
- ...this.formatNspace(ns),
- index,
- }}
- `;
- },
-});
diff --git a/ui-v2/app/adapters/service.js b/ui-v2/app/adapters/service.js
index 27276fecb1..dd079aaaa5 100644
--- a/ui-v2/app/adapters/service.js
+++ b/ui-v2/app/adapters/service.js
@@ -1,15 +1,26 @@
import Adapter from './application';
// TODO: Update to use this.formatDatacenter()
export default Adapter.extend({
- requestForQuery: function(request, { dc, ns, index }) {
- return request`
- GET /v1/internal/ui/services?${{ dc }}
+ requestForQuery: function(request, { dc, ns, index, gateway }) {
+ if (typeof gateway !== 'undefined') {
+ return request`
+ GET /v1/internal/ui/gateway-services-nodes/${gateway}?${{ dc }}
- ${{
- ...this.formatNspace(ns),
- index,
- }}
+ ${{
+ ...this.formatNspace(ns),
+ index,
+ }}
+ `;
+ } else {
+ return request`
+ GET /v1/internal/ui/services?${{ dc }}
+
+ ${{
+ ...this.formatNspace(ns),
+ index,
+ }}
`;
+ }
},
requestForQueryRecord: function(request, { dc, ns, index, id }) {
if (typeof id === 'undefined') {
diff --git a/ui-v2/app/models/gateway.js b/ui-v2/app/models/gateway.js
deleted file mode 100644
index 85b081a0ff..0000000000
--- a/ui-v2/app/models/gateway.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import Model from 'ember-data/model';
-import attr from 'ember-data/attr';
-
-export const PRIMARY_KEY = 'uid';
-export const SLUG_KEY = 'Name';
-export default Model.extend({
- [PRIMARY_KEY]: attr('string'),
- [SLUG_KEY]: attr('string'),
- Datacenter: attr('string'),
- Namespace: attr('string'),
- Services: attr(),
-});
diff --git a/ui-v2/app/models/service.js b/ui-v2/app/models/service.js
index 611031f04d..18a739fa1d 100644
--- a/ui-v2/app/models/service.js
+++ b/ui-v2/app/models/service.js
@@ -17,6 +17,7 @@ export default Model.extend({
ProxyFor: attr(),
Kind: attr('string'),
ExternalSources: attr(),
+ GatewayConfig: attr(),
Meta: attr(),
Address: attr('string'),
TaggedAddresses: attr(),
diff --git a/ui-v2/app/routes/dc/services/show.js b/ui-v2/app/routes/dc/services/show.js
index e5b699de58..2af752b489 100644
--- a/ui-v2/app/routes/dc/services/show.js
+++ b/ui-v2/app/routes/dc/services/show.js
@@ -8,7 +8,6 @@ export default Route.extend({
intentionRepo: service('repository/intention'),
chainRepo: service('repository/discovery-chain'),
proxyRepo: service('repository/proxy'),
- gatewayRepo: service('repository/gateway'),
settings: service('settings'),
model: function(params, transition = {}) {
const dc = this.modelFor('dc').dc.Name;
@@ -55,7 +54,7 @@ export default Route.extend({
.then(model => {
return ['ingress-gateway', 'terminating-gateway'].includes(get(model, 'item.Service.Kind'))
? hash({
- gateway: this.gatewayRepo.findBySlug(params.name, dc, nspace),
+ gatewayServices: this.repo.findGatewayBySlug(params.name, dc, nspace),
...model,
})
: model;
diff --git a/ui-v2/app/serializers/gateway.js b/ui-v2/app/serializers/gateway.js
deleted file mode 100644
index 069c7a695f..0000000000
--- a/ui-v2/app/serializers/gateway.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import Serializer from './application';
-import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/gateway';
-
-export default Serializer.extend({
- primaryKey: PRIMARY_KEY,
- slugKey: SLUG_KEY,
- respondForQueryRecord: function(respond, query) {
- return this._super(function(cb) {
- return respond(function(headers, body) {
- return cb(headers, {
- Name: query.id,
- Services: body,
- });
- });
- }, query);
- },
-});
diff --git a/ui-v2/app/services/client/http.js b/ui-v2/app/services/client/http.js
index b5f75acd62..71e081267f 100644
--- a/ui-v2/app/services/client/http.js
+++ b/ui-v2/app/services/client/http.js
@@ -96,6 +96,11 @@ export default Service.extend({
body: function(strs, ...values) {
let body = {};
const doubleBreak = strs.reduce(function(prev, item, i) {
+ // Ensure each line has no whitespace either end, including empty lines
+ item = item
+ .split('\n')
+ .map(item => item.trim())
+ .join('\n');
if (item.indexOf('\n\n') !== -1) {
return i;
}
diff --git a/ui-v2/app/services/data-source/protocols/http.js b/ui-v2/app/services/data-source/protocols/http.js
index a0bbabca6b..4cda93be88 100644
--- a/ui-v2/app/services/data-source/protocols/http.js
+++ b/ui-v2/app/services/data-source/protocols/http.js
@@ -20,7 +20,7 @@ export default Service.extend({
// always be complete, they should never have things like '///model'
let find;
const repo = this[model];
- if (typeof repo.reconcile === 'function') {
+ if (repo.shouldReconcile(src)) {
configuration.createEvent = function(result = {}, configuration) {
const event = {
type: 'message',
diff --git a/ui-v2/app/services/repository.js b/ui-v2/app/services/repository.js
index 8116914baf..c5088d66f6 100644
--- a/ui-v2/app/services/repository.js
+++ b/ui-v2/app/services/repository.js
@@ -15,6 +15,9 @@ export default Service.extend({
},
//
store: service('store'),
+ shouldReconcile: function(method) {
+ return true;
+ },
reconcile: function(meta = {}) {
// unload anything older than our current sync date/time
if (typeof meta.date !== 'undefined') {
diff --git a/ui-v2/app/services/repository/gateway.js b/ui-v2/app/services/repository/gateway.js
deleted file mode 100644
index 647cf86629..0000000000
--- a/ui-v2/app/services/repository/gateway.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import RepositoryService from 'consul-ui/services/repository';
-
-const modelName = 'gateway';
-export default RepositoryService.extend({
- getModelName: function() {
- return modelName;
- },
-});
diff --git a/ui-v2/app/services/repository/service.js b/ui-v2/app/services/repository/service.js
index ca9a5bc657..ae34a6dd2e 100644
--- a/ui-v2/app/services/repository/service.js
+++ b/ui-v2/app/services/repository/service.js
@@ -5,6 +5,13 @@ export default RepositoryService.extend({
getModelName: function() {
return modelName;
},
+ shouldReconcile: function(method) {
+ switch (method) {
+ case 'findGatewayBySlug':
+ return false;
+ }
+ return this._super(...arguments);
+ },
findBySlug: function(slug, dc) {
return this._super(...arguments).then(function(item) {
// TODO: Move this to the Serializer
@@ -69,4 +76,15 @@ export default RepositoryService.extend({
throw e;
});
},
+ findGatewayBySlug: function(slug, dc, nspace, configuration) {
+ const query = {
+ dc: dc,
+ ns: nspace,
+ gateway: slug,
+ };
+ if (typeof configuration.cursor !== 'undefined') {
+ query.index = configuration.cursor;
+ }
+ return this.store.query(this.getModelName(), query);
+ },
});
diff --git a/ui-v2/app/services/repository/type/event-source.js b/ui-v2/app/services/repository/type/event-source.js
index 65bd874f84..9ddc23e610 100644
--- a/ui-v2/app/services/repository/type/event-source.js
+++ b/ui-v2/app/services/repository/type/event-source.js
@@ -10,15 +10,13 @@ const createProxy = function(repo, find, settings, cache, serialize = JSON.strin
const client = this.client;
// custom createEvent, here used to reconcile the ember-data store for each tick
let createEvent;
- if (typeof repo.reconcile === 'function') {
+ if (repo.shouldReconcile(find)) {
createEvent = function(result = {}, configuration) {
const event = {
type: 'message',
data: result,
};
- if (repo.reconcile === 'function') {
- repo.reconcile(get(event, 'data.meta'));
- }
+ repo.reconcile(get(event, 'data.meta'));
return event;
};
}
diff --git a/ui-v2/app/templates/dc/services/show/services.hbs b/ui-v2/app/templates/dc/services/show/services.hbs
index e93ef13e9f..b29e1dc91a 100644
--- a/ui-v2/app/templates/dc/services/show/services.hbs
+++ b/ui-v2/app/templates/dc/services/show/services.hbs
@@ -1,12 +1,12 @@
- {{#if (gt gateway.Services.length 0)}}
+ {{#if (gt gatewayServices.length 0)}}
The following services may receive traffic from external services through this gateway. Learn more about configuring gateways in our
step-by-step guide.
-
+
{{else}}
diff --git a/ui-v2/app/templates/dc/services/show/upstreams.hbs b/ui-v2/app/templates/dc/services/show/upstreams.hbs
index 372b868685..f329541e8a 100644
--- a/ui-v2/app/templates/dc/services/show/upstreams.hbs
+++ b/ui-v2/app/templates/dc/services/show/upstreams.hbs
@@ -1,12 +1,12 @@
- {{#if (gt gateway.Services.length 0)}}
+ {{#if (gt gatewayServices.length 0)}}
Upstreams are services that may receive traffic from this gateway. Learn more about configuring gateways in our documentation.
{{#let item.Service.Namespace as |nspace|}}
-
+
{{#if (service/exists item)}}
{{item.Name}}
diff --git a/ui-v2/tests/integration/adapters/gateway-test.js b/ui-v2/tests/integration/adapters/gateway-test.js
deleted file mode 100644
index f2138a61b8..0000000000
--- a/ui-v2/tests/integration/adapters/gateway-test.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import { module, test } from 'qunit';
-import { setupTest } from 'ember-qunit';
-
-module('Integration | Adapter | gateway', function(hooks) {
- setupTest(hooks);
- const dc = 'dc-1';
- const id = 'slug';
- test('requestForQueryRecord returns the correct url/method', function(assert) {
- const adapter = this.owner.lookup('adapter:gateway');
- const client = this.owner.lookup('service:client/http');
- const expected = `GET /v1/internal/ui/gateway-services-nodes/${id}?dc=${dc}`;
- const actual = adapter.requestForQueryRecord(client.url, {
- dc: dc,
- id: id,
- });
- assert.equal(actual, expected);
- });
- test("requestForQueryRecord throws if you don't specify an id", function(assert) {
- const adapter = this.owner.lookup('adapter:gateway');
- const client = this.owner.lookup('service:client/http');
- assert.throws(function() {
- adapter.requestForQueryRecord(client.url, {
- dc: dc,
- });
- });
- });
-});
diff --git a/ui-v2/tests/integration/adapters/service-test.js b/ui-v2/tests/integration/adapters/service-test.js
index face132991..7588fdfc57 100644
--- a/ui-v2/tests/integration/adapters/service-test.js
+++ b/ui-v2/tests/integration/adapters/service-test.js
@@ -23,6 +23,21 @@ module('Integration | Adapter | service', function(hooks) {
actual = actual.join('\n').trim();
assert.equal(actual, `${shouldHaveNspace(nspace) ? `ns=${nspace}` : ``}`);
});
+ test(`requestForQuery returns the correct url/method when called with gateway when nspace is ${nspace}`, function(assert) {
+ const adapter = this.owner.lookup('adapter:service');
+ const client = this.owner.lookup('service:client/http');
+ const gateway = 'gateway';
+ const expected = `GET /v1/internal/ui/gateway-services-nodes/${gateway}?dc=${dc}`;
+ let actual = adapter.requestForQuery(client.url, {
+ dc: dc,
+ ns: nspace,
+ gateway: gateway,
+ });
+ actual = actual.split('\n');
+ assert.equal(actual.shift().trim(), expected);
+ actual = actual.join('\n').trim();
+ assert.equal(actual, `${shouldHaveNspace(nspace) ? `ns=${nspace}` : ``}`);
+ });
test(`requestForQueryRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:service');
const client = this.owner.lookup('service:client/http');
diff --git a/ui-v2/tests/integration/serializers/gateway-test.js b/ui-v2/tests/integration/serializers/gateway-test.js
deleted file mode 100644
index 837c09aa77..0000000000
--- a/ui-v2/tests/integration/serializers/gateway-test.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import { module, test } from 'qunit';
-import { setupTest } from 'ember-qunit';
-
-import { get } from 'consul-ui/tests/helpers/api';
-import {
- HEADERS_SYMBOL as META,
- HEADERS_DATACENTER as DC,
- HEADERS_NAMESPACE as NSPACE,
-} from 'consul-ui/utils/http/consul';
-
-module('Integration | Serializer | gateway', function(hooks) {
- setupTest(hooks);
- test('respondForQueryRecord returns the correct data for item endpoint', function(assert) {
- const serializer = this.owner.lookup('serializer:gateway');
- const dc = 'dc-1';
- const id = 'slug';
- const nspace = 'default';
- const request = {
- url: `/v1/internal/ui/gateway-services-nodes/${id}?dc=${dc}`,
- };
- return get(request.url).then(function(payload) {
- const expected = {
- Datacenter: dc,
- [META]: {
- [DC.toLowerCase()]: dc,
- [NSPACE.toLowerCase()]: nspace,
- },
- uid: `["${nspace}","${dc}","${id}"]`,
- Name: id,
- Namespace: nspace,
- Services: payload,
- };
- const actual = serializer.respondForQueryRecord(
- function(cb) {
- const headers = {};
- const body = payload;
- return cb(headers, body);
- },
- {
- dc: dc,
- id: id,
- }
- );
- assert.deepEqual(actual, expected);
- });
- });
-});
diff --git a/ui-v2/tests/integration/serializers/service-test.js b/ui-v2/tests/integration/serializers/service-test.js
index f970562dc1..1d50230d7d 100644
--- a/ui-v2/tests/integration/serializers/service-test.js
+++ b/ui-v2/tests/integration/serializers/service-test.js
@@ -40,6 +40,37 @@ module('Integration | Serializer | service', function(hooks) {
assert.deepEqual(actual, expected);
});
});
+ test(`respondForQuery returns the correct data for list endpoint when gateway is set when nspace is ${nspace}`, function(assert) {
+ const serializer = this.owner.lookup('serializer:service');
+ const gateway = 'gateway';
+ const request = {
+ url: `/v1/internal/ui/gateway-services-nodes/${gateway}?dc=${dc}${
+ typeof nspace !== 'undefined' ? `&ns=${nspace}` : ``
+ }`,
+ };
+ return get(request.url).then(function(payload) {
+ const expected = payload.map(item =>
+ Object.assign({}, item, {
+ Namespace: item.Namespace || undefinedNspace,
+ Datacenter: dc,
+ uid: `["${item.Namespace || undefinedNspace}","${dc}","${item.Name}"]`,
+ })
+ );
+ const actual = serializer.respondForQuery(
+ function(cb) {
+ const headers = {};
+ const body = payload;
+ return cb(headers, body);
+ },
+ {
+ dc: dc,
+ ns: nspace,
+ gateway: gateway,
+ }
+ );
+ assert.deepEqual(actual, expected);
+ });
+ });
test(`respondForQueryRecord returns the correct data for item endpoint when nspace is ${nspace}`, function(assert) {
const serializer = this.owner.lookup('serializer:service');
const id = 'service-name';
diff --git a/ui-v2/tests/integration/services/repository/gateway-test.js b/ui-v2/tests/integration/services/repository/gateway-test.js
deleted file mode 100644
index c43b2f7e46..0000000000
--- a/ui-v2/tests/integration/services/repository/gateway-test.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-import repo from 'consul-ui/tests/helpers/repo';
-
-moduleFor('service:repository/gateway', 'Integration | Repository | gateway', {
- // Specify the other units that are required for this test.
- integration: true,
-});
-const dc = 'dc-1';
-const id = 'slug';
-const nspace = 'default';
-test('findBySlug returns the correct data for item endpoint', function(assert) {
- return repo(
- 'Gateway',
- 'findBySlug',
- this.subject(),
- function retrieveStub(stub) {
- return stub(`/v1/internal/ui/gateway-services-nodes/${id}`);
- },
- function performTest(service) {
- return service.findBySlug(id, dc);
- },
- function performAssertion(actual, expected) {
- assert.deepEqual(
- actual,
- expected(function(payload) {
- return Object.assign(
- {},
- {
- Datacenter: dc,
- Name: id,
- Namespace: nspace,
- uid: `["${nspace}","${dc}","${id}"]`,
- },
- {
- Services: payload,
- }
- );
- })
- );
- }
- );
-});
diff --git a/ui-v2/tests/integration/services/repository/service-test.js b/ui-v2/tests/integration/services/repository/service-test.js
index be2745912e..ace26d0bd6 100644
--- a/ui-v2/tests/integration/services/repository/service-test.js
+++ b/ui-v2/tests/integration/services/repository/service-test.js
@@ -130,4 +130,46 @@ const undefinedNspace = 'default';
}
);
});
+ test(`findGatewayBySlug returns the correct data for list endpoint when nspace is ${nspace}`, function(assert) {
+ get(this.subject(), 'store').serializerFor(NAME).timestamp = function() {
+ return now;
+ };
+ const gateway = 'gateway';
+ const conf = {
+ cursor: 1,
+ };
+ return repo(
+ 'Service',
+ 'findGatewayBySlug',
+ this.subject(),
+ function retrieveStub(stub) {
+ return stub(
+ `/v1/internal/ui/gateway-services-nodes/${gateway}?dc=${dc}${
+ typeof nspace !== 'undefined' ? `&ns=${nspace}` : ``
+ }`,
+ {
+ CONSUL_SERVICE_COUNT: '100',
+ }
+ );
+ },
+ function performTest(service) {
+ return service.findGatewayBySlug(gateway, dc, nspace || undefinedNspace, conf);
+ },
+ function performAssertion(actual, expected) {
+ assert.deepEqual(
+ actual,
+ expected(function(payload) {
+ return payload.map(item =>
+ Object.assign({}, item, {
+ SyncTime: now,
+ Datacenter: dc,
+ Namespace: item.Namespace || undefinedNspace,
+ uid: `["${item.Namespace || undefinedNspace}","${dc}","${item.Name}"]`,
+ })
+ );
+ })
+ );
+ }
+ );
+ });
});
diff --git a/ui-v2/tests/unit/adapters/gateway-test.js b/ui-v2/tests/unit/adapters/gateway-test.js
deleted file mode 100644
index e131d648bc..0000000000
--- a/ui-v2/tests/unit/adapters/gateway-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { module, test } from 'qunit';
-import { setupTest } from 'ember-qunit';
-
-module('Unit | Adapter | gateway', function(hooks) {
- setupTest(hooks);
-
- // Replace this with your real tests.
- test('it exists', function(assert) {
- let adapter = this.owner.lookup('adapter:gateway');
- assert.ok(adapter);
- });
-});
diff --git a/ui-v2/tests/unit/models/gateway-test.js b/ui-v2/tests/unit/models/gateway-test.js
deleted file mode 100644
index d86be7ec1f..0000000000
--- a/ui-v2/tests/unit/models/gateway-test.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import { module, test } from 'qunit';
-import { setupTest } from 'ember-qunit';
-
-module('Unit | Model | gateway', function(hooks) {
- setupTest(hooks);
-
- // Replace this with your real tests.
- test('it exists', function(assert) {
- let store = this.owner.lookup('service:store');
- let model = store.createRecord('gateway', {});
- assert.ok(model);
- });
-});
diff --git a/ui-v2/tests/unit/serializers/gateway-test.js b/ui-v2/tests/unit/serializers/gateway-test.js
deleted file mode 100644
index fc0a1c80e8..0000000000
--- a/ui-v2/tests/unit/serializers/gateway-test.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import { module, test } from 'qunit';
-import { setupTest } from 'ember-qunit';
-
-module('Unit | Serializer | gateway', function(hooks) {
- setupTest(hooks);
-
- // Replace this with your real tests.
- test('it exists', function(assert) {
- let store = this.owner.lookup('service:store');
- let serializer = store.serializerFor('gateway');
-
- assert.ok(serializer);
- });
-
- test('it serializes records', function(assert) {
- let store = this.owner.lookup('service:store');
- let record = store.createRecord('gateway', {});
-
- let serializedRecord = record.serialize();
-
- assert.ok(serializedRecord);
- });
-});
diff --git a/ui-v2/tests/unit/services/repository/gateway-test.js b/ui-v2/tests/unit/services/repository/gateway-test.js
deleted file mode 100644
index ca2989eb3e..0000000000
--- a/ui-v2/tests/unit/services/repository/gateway-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { module, test } from 'qunit';
-import { setupTest } from 'ember-qunit';
-
-module('Unit | Repository | gateway', function(hooks) {
- setupTest(hooks);
-
- // Replace this with your real tests.
- test('it exists', function(assert) {
- const repo = this.owner.lookup('service:repository/gateway');
- assert.ok(repo);
- });
-});
diff --git a/ui-v2/yarn.lock b/ui-v2/yarn.lock
index 35170d6efc..a79b75e863 100644
--- a/ui-v2/yarn.lock
+++ b/ui-v2/yarn.lock
@@ -1211,9 +1211,9 @@
js-yaml "^3.13.1"
"@hashicorp/consul-api-double@^2.6.2":
- version "2.15.1"
- resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-2.15.1.tgz#1b41c92ee7930e0bcead8283eea019b5f1238819"
- integrity sha512-0q0h2krXFR5uj/A+x5WtsKVF1ltPPDrrxmX9g+SjUmeWHIcffH7qz/PCo4fdqWOPjcTXkPfBxSZwGd2uDishaQ==
+ version "2.15.2"
+ resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-2.15.2.tgz#e2c34a348b9959fcc95ffad797c1fed9644a41bd"
+ integrity sha512-VNdwsL3ut4SubCtwWfqX4prD9R/RczKtWUID6s6K9h1TCdzTgpZQhbb+gdzaYGqzCE3Mrw416JzclxVTIFIUFw==
"@hashicorp/ember-cli-api-double@^3.0.2":
version "3.0.2"