ui: Asyncify Service Model Hooks (#9312)

* ui: Add Kind grouping computed properties

* Use new computed properties and move model hooks to async methods
This commit is contained in:
John Cowen 2020-12-02 15:42:18 +00:00 committed by hashicorp-ci
parent 4fbbfdcfa2
commit 9d9e77f417
5 changed files with 108 additions and 100 deletions

View File

@ -38,6 +38,27 @@ export default class ServiceInstance extends Model {
return [...new Set(sources)]; return [...new Set(sources)];
} }
@computed('Service.Kind')
get IsProxy() {
return ['connect-proxy', 'mesh-gateway', 'ingress-gateway', 'terminating-gateway'].includes(
this.Service.Kind
);
}
// IsOrigin means that the service can have associated up or down streams,
// this service being the origin point of those streams
@computed('Service.Kind')
get IsOrigin() {
return !['connect-proxy', 'mesh-gateway'].includes(this.Service.Kind);
}
// IsMeshOrigin means that the service can have associated up or downstreams
// that are in the Consul mesh itself
@computed('IsOrigin')
get IsMeshOrigin() {
return this.IsOrigin && !['terminating-gateway'].includes(this.Service.Kind);
}
@computed('ChecksPassing', 'ChecksWarning', 'ChecksCritical') @computed('ChecksPassing', 'ChecksWarning', 'ChecksCritical')
get Status() { get Status() {
switch (true) { switch (true) {

View File

@ -1,6 +1,5 @@
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import Route from 'consul-ui/routing/route'; import Route from 'consul-ui/routing/route';
import { hash } from 'rsvp';
export default class IndexRoute extends Route { export default class IndexRoute extends Route {
@service('data-source/service') data; @service('data-source/service') data;
@ -20,14 +19,15 @@ export default class IndexRoute extends Route {
}, },
}; };
model(params) { async model(params, transition) {
const nspace = this.modelFor('nspace').nspace.substr(1); const nspace = this.modelFor('nspace').nspace.substr(1);
const dc = this.modelFor('dc').dc.Name; const dc = this.modelFor('dc').dc.Name;
return hash({ const items = await this.data.source(uri => uri`/${nspace}/${dc}/services`);
nspace: nspace, return {
dc: dc, dc,
items: this.data.source(uri => uri`/${nspace}/${dc}/services`), nspace,
}); items,
};
} }
setupController(controller, model) { setupController(controller, model) {

View File

@ -1,54 +1,46 @@
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import Route from 'consul-ui/routing/route'; import Route from 'consul-ui/routing/route';
import { hash } from 'rsvp';
import { get } from '@ember/object'; import { get } from '@ember/object';
export default class InstanceRoute extends Route { export default class InstanceRoute extends Route {
@service('data-source/service') @service('data-source/service') data;
data;
model(params) { async model(params, transition) {
const dc = this.modelFor('dc').dc.Name; const dc = this.modelFor('dc').dc.Name;
const nspace = this.modelFor('nspace').nspace.substr(1) || 'default'; const nspace = this.modelFor('nspace').nspace.substr(1) || 'default';
return hash({
dc: dc, const item = await this.data.source(
nspace: nspace,
item: this.data.source(
uri => uri`/${nspace}/${dc}/service-instance/${params.id}/${params.node}/${params.name}` uri => uri`/${nspace}/${dc}/service-instance/${params.id}/${params.node}/${params.name}`
), );
}).then(model => {
// this will not be run in a blocking loop, but this is ok as let proxyMeta, proxy;
// its highly unlikely that a service will suddenly change to being a if (get(item, 'IsOrigin')) {
// connect-proxy or vice versa so leave as is for now proxyMeta = await this.data.source(
return hash({ uri => uri`/${nspace}/${dc}/proxy-instance/${params.id}/${params.node}/${params.name}`
...model, );
proxyMeta: if (typeof get(proxyMeta, 'ServiceID') !== 'undefined') {
// proxies and mesh-gateways can't have proxies themselves so don't even look const proxyParams = {
['connect-proxy', 'mesh-gateway'].includes(get(model.item, 'Kind')) id: get(proxyMeta, 'ServiceID'),
? null node: get(proxyMeta, 'Node'),
: this.data.source( name: get(proxyMeta, 'ServiceName'),
uri =>
uri`/${nspace}/${dc}/proxy-instance/${params.id}/${params.node}/${params.name}`
),
}).then(model => {
if (typeof get(model, 'proxyMeta.ServiceID') === 'undefined') {
return model;
}
const proxy = {
id: get(model, 'proxyMeta.ServiceID'),
node: get(model, 'proxyMeta.Node'),
name: get(model, 'proxyMeta.ServiceName'),
}; };
return hash({
...model,
// Proxies have identical dc/nspace as their parent instance // Proxies have identical dc/nspace as their parent instance
// No need to use Proxy's dc/nspace response // so no need to use Proxy's dc/nspace response
proxy: this.data.source( // the proxy itself is just a normal service model
uri => uri`/${nspace}/${dc}/service-instance/${proxy.id}/${proxy.node}/${proxy.name}` proxy = await this.data.source(
), uri =>
}); uri`/${nspace}/${dc}/service-instance/${proxyParams.id}/${proxyParams.node}/${proxyParams.name}`
}); );
}); }
}
return {
dc,
nspace,
item,
proxyMeta,
proxy,
};
} }
setupController(controller, model) { setupController(controller, model) {

View File

@ -1,6 +1,5 @@
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import Route from 'consul-ui/routing/route'; import Route from 'consul-ui/routing/route';
import { hash } from 'rsvp';
import { get } from '@ember/object'; import { get } from '@ember/object';
import { action, setProperties } from '@ember/object'; import { action, setProperties } from '@ember/object';
@ -24,54 +23,48 @@ export default class ShowRoute extends Route {
this.refresh(); this.refresh();
} }
model(params, transition) { async model(params, transition) {
const dc = this.modelFor('dc').dc.Name; const dc = this.modelFor('dc').dc.Name;
const nspace = this.modelFor('nspace').nspace.substr(1); const nspace = this.modelFor('nspace').nspace.substr(1);
return hash({ const slug = params.name;
slug: params.name,
dc: dc, let chain = null;
nspace: nspace, let topology = null;
items: this.data.source( let proxies = [];
const urls = this.config.get().dashboard_url_templates;
const items = await this.data.source(
uri => uri`/${nspace}/${dc}/service-instances/for-service/${params.name}` uri => uri`/${nspace}/${dc}/service-instances/for-service/${params.name}`
), );
urls: this.config.get().dashboard_url_templates,
chain: null, const item = get(items, 'firstObject');
proxies: [], if (get(item, 'IsOrigin')) {
topology: null, chain = await this.data.source(uri => uri`/${nspace}/${dc}/discovery-chain/${params.name}`);
}) proxies = await this.data.source(
.then(model => {
return ['connect-proxy', 'mesh-gateway', 'ingress-gateway', 'terminating-gateway'].includes(
get(model, 'items.firstObject.Service.Kind')
)
? model
: hash({
...model,
chain: this.data.source(uri => uri`/${nspace}/${dc}/discovery-chain/${params.name}`),
// Whilst `proxies` isn't used anywhere in the show templates
// it provides a relationship of ProxyInstance on the ServiceInstance
// which can respond at a completely different blocking rate to
// the ServiceInstance itself
proxies: this.data.source(
uri => uri`/${nspace}/${dc}/proxies/for-service/${params.name}` uri => uri`/${nspace}/${dc}/proxies/for-service/${params.name}`
), );
});
}) if (get(item, 'IsMeshOrigin')) {
.then(model => { let kind = get(item, 'Service.Kind');
let kind = get(model, 'items.firstObject.Service.Kind');
if (typeof kind === 'undefined') { if (typeof kind === 'undefined') {
kind = ''; kind = '';
} }
return ['mesh-gateway', 'terminating-gateway'].includes( topology = await this.data.source(
get(model, 'items.firstObject.Service.Kind')
)
? model
: hash({
...model,
topology: this.data.source(
uri => uri`/${nspace}/${dc}/topology/${params.name}/${kind}` uri => uri`/${nspace}/${dc}/topology/${params.name}/${kind}`
), );
}); }
}); }
return {
dc,
nspace,
slug,
items,
urls,
chain,
proxies,
topology,
};
} }
setupController(controller, model) { setupController(controller, model) {

View File

@ -1,6 +1,5 @@
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import Route from 'consul-ui/routing/route'; import Route from 'consul-ui/routing/route';
import { hash } from 'rsvp';
export default class ServicesRoute extends Route { export default class ServicesRoute extends Route {
@service('data-source/service') data; @service('data-source/service') data;
@ -18,7 +17,7 @@ export default class ServicesRoute extends Route {
}, },
}; };
model() { async model(params, transition) {
const dc = this.modelFor('dc').dc.Name; const dc = this.modelFor('dc').dc.Name;
const nspace = this.modelFor('nspace').nspace.substr(1); const nspace = this.modelFor('nspace').nspace.substr(1);
const parent = this.routeName const parent = this.routeName
@ -26,11 +25,14 @@ export default class ServicesRoute extends Route {
.slice(0, -1) .slice(0, -1)
.join('.'); .join('.');
const name = this.modelFor(parent).slug; const name = this.modelFor(parent).slug;
return hash({ const gatewayServices = await this.data.source(
dc: dc, uri => uri`/${nspace}/${dc}/gateways/for-service/${name}`
nspace: nspace, );
gatewayServices: this.data.source(uri => uri`/${nspace}/${dc}/gateways/for-service/${name}`), return {
}); dc,
nspace,
gatewayServices,
};
} }
setupController(controller, model) { setupController(controller, model) {