ui: Ensure service instance data does not get re-written on blocking refresh (#11903)
* Add some less fake API data * Rename the models class so as to not be confused with JS Proxies * Rearrange routlets slightly and add some initial outletFor tests * Move away from a MeshChecks computed property and just use a helper * Just use ServiceChecks for healthiness filtering for the moment * Make TProxy cookie configurable * Amend exposed paths and upstreams so they know about meta AND proxy * Slight bit of TaggedAddresses refactor while I was checking for `meta` etc * Document CONSUL_TPROXY_ENABLE
This commit is contained in:
parent
3ab747109b
commit
514e24ba9f
|
@ -0,0 +1,4 @@
|
||||||
|
```release-note:bug
|
||||||
|
ui: Fixes a bug where proxy service health checks would sometimes not appear
|
||||||
|
until refresh
|
||||||
|
```
|
|
@ -28,6 +28,10 @@ export default class Outlet extends Component {
|
||||||
return this.args.model || {};
|
return this.args.model || {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get name() {
|
||||||
|
return this.args.name;
|
||||||
|
}
|
||||||
|
|
||||||
setAppRoute(name) {
|
setAppRoute(name) {
|
||||||
if (name !== 'loading' || name === 'oidc-provider-debug') {
|
if (name !== 'loading' || name === 'oidc-provider-debug') {
|
||||||
const doc = this.element.ownerDocument.documentElement;
|
const doc = this.element.ownerDocument.documentElement;
|
||||||
|
@ -55,7 +59,9 @@ export default class Outlet extends Component {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'model':
|
case 'model':
|
||||||
this.route._model = this.args.model;
|
if(typeof this.route !== 'undefined') {
|
||||||
|
this.route._model = value;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{{did-insert this.connect}}
|
{{did-insert this.connect}}
|
||||||
{{will-destroy this.disconnect}}
|
{{will-destroy this.disconnect}}
|
||||||
{{yield (hash
|
{{yield (hash
|
||||||
model=(or this.model this._model)
|
model=this.model
|
||||||
params=this.params
|
params=this.params
|
||||||
currentName=this.router.currentRoute.name
|
currentName=this.router.currentRoute.name
|
||||||
|
|
||||||
|
|
|
@ -14,17 +14,14 @@ export default class RouteComponent extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
get model() {
|
get model() {
|
||||||
if(this.args.name) {
|
if(this._model) {
|
||||||
const temp = this.args.name.split('.');
|
return this._model;
|
||||||
temp.pop();
|
|
||||||
const name = temp.join('.');
|
|
||||||
let model = this.routlet.modelFor(name);
|
|
||||||
if(Object.keys(model).length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
return model;
|
if (this.args.name) {
|
||||||
|
const outlet = this.routlet.outletFor(this.args.name);
|
||||||
|
return this.routlet.modelFor(outlet.name);
|
||||||
}
|
}
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
|
|
@ -5,7 +5,7 @@ export default {
|
||||||
passing: (item, value) => item.Status === value,
|
passing: (item, value) => item.Status === value,
|
||||||
warning: (item, value) => item.Status === value,
|
warning: (item, value) => item.Status === value,
|
||||||
critical: (item, value) => item.Status === value,
|
critical: (item, value) => item.Status === value,
|
||||||
empty: (item, value) => item.MeshChecks.length === 0,
|
empty: (item, value) => item.ServiceChecks.length === 0,
|
||||||
},
|
},
|
||||||
source: (item, values) => {
|
source: (item, values) => {
|
||||||
return setHelpers.intersectionSize(values, new Set(item.ExternalSources || [])) !== 0;
|
return setHelpers.intersectionSize(values, new Set(item.ExternalSources || [])) !== 0;
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { helper } from '@ember/component/helper';
|
||||||
|
import mergeChecks from 'consul-ui/utils/merge-checks';
|
||||||
|
|
||||||
|
export default helper(function([checks, exposed], hash) {
|
||||||
|
return mergeChecks(
|
||||||
|
checks,
|
||||||
|
exposed
|
||||||
|
);
|
||||||
|
});
|
|
@ -5,7 +5,7 @@ export const PRIMARY_KEY = 'uid';
|
||||||
export const SLUG_KEY = 'Node,ServiceID';
|
export const SLUG_KEY = 'Node,ServiceID';
|
||||||
|
|
||||||
// TODO: This should be changed to ProxyInstance
|
// TODO: This should be changed to ProxyInstance
|
||||||
export default class Proxy extends ServiceInstanceModel {
|
export default class ProxyServiceInstance extends ServiceInstanceModel {
|
||||||
@attr('string') uid;
|
@attr('string') uid;
|
||||||
@attr('string') ID;
|
@attr('string') ID;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import Model, { attr, belongsTo } from '@ember-data/model';
|
import Model, { attr } from '@ember-data/model';
|
||||||
import { fragmentArray } from 'ember-data-model-fragments/attributes';
|
import { fragmentArray } from 'ember-data-model-fragments/attributes';
|
||||||
import { computed, get } from '@ember/object';
|
import { computed } from '@ember/object';
|
||||||
import { or, filter, alias } from '@ember/object/computed';
|
import { or, filter, alias } from '@ember/object/computed';
|
||||||
import { tracked } from '@glimmer/tracking';
|
import { tracked } from '@glimmer/tracking';
|
||||||
import mergeChecks from 'consul-ui/utils/merge-checks';
|
|
||||||
|
|
||||||
export const PRIMARY_KEY = 'uid';
|
export const PRIMARY_KEY = 'uid';
|
||||||
export const SLUG_KEY = 'Node.Node,Service.ID';
|
export const SLUG_KEY = 'Node.Node,Service.ID';
|
||||||
|
@ -28,8 +27,6 @@ export default class ServiceInstance extends Model {
|
||||||
@attr('string') uid;
|
@attr('string') uid;
|
||||||
|
|
||||||
@attr('string') Datacenter;
|
@attr('string') Datacenter;
|
||||||
// ProxyInstance is the ember-data model relationship
|
|
||||||
@belongsTo('Proxy') ProxyInstance;
|
|
||||||
// Proxy is the actual JSON api response
|
// Proxy is the actual JSON api response
|
||||||
@attr() Proxy;
|
@attr() Proxy;
|
||||||
@attr() Node;
|
@attr() Node;
|
||||||
|
@ -55,18 +52,6 @@ export default class ServiceInstance extends Model {
|
||||||
@filter('Checks.@each.Kind', (item, i, arr) => item.Kind === 'service') ServiceChecks;
|
@filter('Checks.@each.Kind', (item, i, arr) => item.Kind === 'service') ServiceChecks;
|
||||||
@filter('Checks.@each.Kind', (item, i, arr) => item.Kind === 'node') NodeChecks;
|
@filter('Checks.@each.Kind', (item, i, arr) => item.Kind === 'node') NodeChecks;
|
||||||
|
|
||||||
// MeshChecks are a concatenation of Checks for the Instance and Checks for
|
|
||||||
// the ProxyInstance.
|
|
||||||
@computed('Checks.[]', 'ProxyInstance.{Checks.[],ServiceProxy.Expose.Checks}')
|
|
||||||
get MeshChecks() {
|
|
||||||
// merge the instance and proxy checks together, avoiding duplicate node
|
|
||||||
// checks and additionally setting any checks to exposed if required
|
|
||||||
return mergeChecks(
|
|
||||||
[get(this, 'Checks'), get(this, 'ProxyInstance.Checks')],
|
|
||||||
get(this, 'ProxyInstance.ServiceProxy.Expose.Checks')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@computed('Service.Meta')
|
@computed('Service.Meta')
|
||||||
get ExternalSources() {
|
get ExternalSources() {
|
||||||
const sources = Object.entries(this.Service.Meta || {})
|
const sources = Object.entries(this.Service.Meta || {})
|
||||||
|
|
|
@ -36,8 +36,9 @@ export default class ProxyService extends RepositoryService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@dataSource('/:partition/:ns/:dc/proxy-instance/:serviceId/:node/:id')
|
@dataSource('/:partition/:ns/:dc/proxy-instance/:serviceId/:node/:id')
|
||||||
findInstanceBySlug(params, configuration) {
|
async findInstanceBySlug(params, configuration) {
|
||||||
return this.findAllBySlug(params, configuration).then(function(items) {
|
const items = await this.findAllBySlug(params, configuration);
|
||||||
|
|
||||||
let res = {};
|
let res = {};
|
||||||
if (get(items, 'length') > 0) {
|
if (get(items, 'length') > 0) {
|
||||||
let instance = items
|
let instance = items
|
||||||
|
@ -54,6 +55,5 @@ export default class ProxyService extends RepositoryService {
|
||||||
}
|
}
|
||||||
set(res, 'meta', get(items, 'meta'));
|
set(res, 'meta', get(items, 'meta'));
|
||||||
return res;
|
return res;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
import RepositoryService from 'consul-ui/services/repository';
|
import RepositoryService from 'consul-ui/services/repository';
|
||||||
import { inject as service } from '@ember/service';
|
|
||||||
import { set } from '@ember/object';
|
import { set } from '@ember/object';
|
||||||
import { ACCESS_READ } from 'consul-ui/abilities/base';
|
import { ACCESS_READ } from 'consul-ui/abilities/base';
|
||||||
import dataSource from 'consul-ui/decorators/data-source';
|
import dataSource from 'consul-ui/decorators/data-source';
|
||||||
|
|
||||||
const modelName = 'service-instance';
|
const modelName = 'service-instance';
|
||||||
export default class ServiceInstanceService extends RepositoryService {
|
export default class ServiceInstanceService extends RepositoryService {
|
||||||
@service('repository/proxy') proxyRepo;
|
|
||||||
getModelName() {
|
getModelName() {
|
||||||
return modelName;
|
return modelName;
|
||||||
}
|
}
|
||||||
|
@ -34,44 +32,6 @@ export default class ServiceInstanceService extends RepositoryService {
|
||||||
|
|
||||||
@dataSource('/:partition/:ns/:dc/service-instance/:serviceId/:node/:id')
|
@dataSource('/:partition/:ns/:dc/service-instance/:serviceId/:node/:id')
|
||||||
async findBySlug(params, configuration = {}) {
|
async findBySlug(params, configuration = {}) {
|
||||||
if (typeof configuration.cursor !== 'undefined') {
|
return super.findBySlug(...arguments);
|
||||||
params.index = configuration.cursor;
|
|
||||||
params.uri = configuration.uri;
|
|
||||||
}
|
|
||||||
return this.authorizeBySlug(
|
|
||||||
async () => this.store.queryRecord(this.getModelName(), params),
|
|
||||||
ACCESS_READ,
|
|
||||||
params
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@dataSource('/:partition/:ns/:dc/proxy-service-instance/:serviceId/:node/:id')
|
|
||||||
async findProxyBySlug(params, configuration = {}) {
|
|
||||||
const instance = await this.findBySlug(...arguments);
|
|
||||||
let proxy = this.store.peekRecord('proxy', instance.uid);
|
|
||||||
// Currently, we call the proxy endpoint before this endpoint
|
|
||||||
// therefore proxy is never undefined. If we ever call this endpoint
|
|
||||||
// first we'll need to do something like the following
|
|
||||||
// if(typeof proxy === 'undefined') {
|
|
||||||
// await proxyRepo.create({})
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Copy over all the things to the ProxyServiceInstance
|
|
||||||
['Service', 'Node', 'meta'].forEach(prop => {
|
|
||||||
set(proxy, prop, instance[prop]);
|
|
||||||
});
|
|
||||||
['Checks'].forEach(prop => {
|
|
||||||
// completely wipe out any previous values so we don't accumulate things
|
|
||||||
// eternally
|
|
||||||
proxy.set(prop, []);
|
|
||||||
instance[prop].forEach(item => {
|
|
||||||
if (typeof item !== 'undefined') {
|
|
||||||
proxy[prop].addFragment(item.copy());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// delete the ServiceInstance record as we now have a ProxyServiceInstance
|
|
||||||
instance.unloadRecord();
|
|
||||||
return proxy;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,21 +75,11 @@ export default class RoutletService extends Service {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
addOutlet(name, outlet) {
|
outletFor(routeName) {
|
||||||
outlets.set(name, outlet);
|
const keys = [...outlets.keys()];
|
||||||
}
|
const pos = keys.indexOf(routeName);
|
||||||
|
const key = pos + 1;
|
||||||
removeOutlet(name) {
|
return outlets.get(keys[key]);
|
||||||
outlets.delete(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// modelFor gets the model for Outlet specified by `name`, not the Route
|
|
||||||
modelFor(name) {
|
|
||||||
const outlet = outlets.get(name);
|
|
||||||
if (typeof outlet !== 'undefined') {
|
|
||||||
return outlet.model || {};
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -149,20 +139,43 @@ export default class RoutletService extends Service {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
addRoute(name, route) {
|
|
||||||
const keys = [...outlets.keys()];
|
// modelFor gets the model for Outlet specified by `name`, not the Route
|
||||||
const pos = keys.indexOf(name);
|
modelFor(name) {
|
||||||
const key = pos + 1;
|
const outlet = outlets.get(name);
|
||||||
const outlet = outlets.get(keys[key]);
|
if (typeof outlet !== 'undefined') {
|
||||||
|
return outlet.model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addRoute(name, route) {
|
||||||
|
const outlet = this.outletFor(name);
|
||||||
if (typeof outlet !== 'undefined') {
|
if (typeof outlet !== 'undefined') {
|
||||||
route._model = outlet.model;
|
|
||||||
outlet.route = route;
|
outlet.route = route;
|
||||||
// TODO: Try to avoid the double computation bug
|
// TODO: Try to avoid the double computation bug
|
||||||
schedule('afterRender', () => {
|
schedule('afterRender', () => {
|
||||||
outlet.routeName = route.args.name;
|
outlet.routeName = name;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeRoute(name, route) {}
|
removeRoute(name, route) {
|
||||||
|
const outlet = this.outletFor(name);
|
||||||
|
route._model = undefined;
|
||||||
|
if (typeof outlet !== 'undefined') {
|
||||||
|
schedule('afterRender', () => {
|
||||||
|
outlet.route = undefined;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addOutlet(name, outlet) {
|
||||||
|
outlets.set(name, outlet);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeOutlet(name) {
|
||||||
|
schedule('afterRender', () => {
|
||||||
|
outlets.delete(name);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,6 +94,7 @@ as |item|}}
|
||||||
name=route.params.name
|
name=route.params.name
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
@onchange={{action (mut meta) value="data"}}
|
||||||
as |meta|>
|
as |meta|>
|
||||||
{{! We only really need meta to get the correct ServiceID }}
|
{{! We only really need meta to get the correct ServiceID }}
|
||||||
{{! but we may as well use the NodeName and ServiceName }}
|
{{! but we may as well use the NodeName and ServiceName }}
|
||||||
|
@ -101,8 +102,13 @@ as |item|}}
|
||||||
{{! so if we can ever get ServiceID from elsewhere we could save }}
|
{{! so if we can ever get ServiceID from elsewhere we could save }}
|
||||||
{{! a HTTP request/long poll here }}
|
{{! a HTTP request/long poll here }}
|
||||||
{{#if meta.data.ServiceID}}
|
{{#if meta.data.ServiceID}}
|
||||||
|
{{! if we have a proxy then get the additional instance information }}
|
||||||
|
{{! for the proxy itself so if the service is called `backend` }}
|
||||||
|
{{! its likely to have a proxy service called `backend-sidecar-proxy` }}
|
||||||
|
{{! and this second request get the info for that instance and saves }}
|
||||||
|
{{! it into the `proxy` variable }}
|
||||||
<DataSource
|
<DataSource
|
||||||
@src={{uri '/${partition}/${nspace}/${dc}/proxy-service-instance/${id}/${node}/${name}'
|
@src={{uri '/${partition}/${nspace}/${dc}/service-instance/${id}/${node}/${name}'
|
||||||
(hash
|
(hash
|
||||||
partition=route.params.partition
|
partition=route.params.partition
|
||||||
nspace=route.params.nspace
|
nspace=route.params.nspace
|
||||||
|
@ -112,7 +118,8 @@ as |item|}}
|
||||||
name=meta.data.ServiceName
|
name=meta.data.ServiceName
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
@onchange={{action (mut proxy) value="data"}}/>
|
@onchange={{action (mut proxy) value="data"}}
|
||||||
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</DataSource>
|
</DataSource>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
@ -129,7 +136,9 @@ as |item|}}
|
||||||
</h1>
|
</h1>
|
||||||
<Consul::ExternalSource @item={{item}} @withInfo={{true}} />
|
<Consul::ExternalSource @item={{item}} @withInfo={{true}} />
|
||||||
<Consul::Kind @item={{item}} @withInfo={{true}} />
|
<Consul::Kind @item={{item}} @withInfo={{true}} />
|
||||||
{{#if (eq proxy.ServiceProxy.Mode 'transparent')}}
|
{{! TODO: Looks like we can get this straight from item.Proxy.Mode }}
|
||||||
|
{{! the less we need `proxy` and `meta` the better }}
|
||||||
|
{{#if (eq meta.ServiceProxy.Mode 'transparent')}}
|
||||||
<Consul::TransparentProxy />
|
<Consul::TransparentProxy />
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</BlockSlot>
|
</BlockSlot>
|
||||||
|
@ -153,23 +162,18 @@ as |item|}}
|
||||||
compact
|
compact
|
||||||
(array
|
(array
|
||||||
(hash label="Health Checks" href=(href-to "dc.services.instance.healthchecks") selected=(is-href "dc.services.instance.healthchecks"))
|
(hash label="Health Checks" href=(href-to "dc.services.instance.healthchecks") selected=(is-href "dc.services.instance.healthchecks"))
|
||||||
(if
|
(if (eq item.Service.Kind 'mesh-gateway') (hash label="Addresses" href=(href-to "dc.services.instance.addresses") selected=(is-href "dc.services.instance.addresses")))
|
||||||
(eq item.Service.Kind 'mesh-gateway')
|
(if proxy (hash label="Upstreams" href=(href-to "dc.services.instance.upstreams") selected=(is-href "dc.services.instance.upstreams")))
|
||||||
(hash label="Addresses" href=(href-to "dc.services.instance.addresses") selected=(is-href "dc.services.instance.addresses")) ""
|
(if proxy (hash label="Exposed Paths" href=(href-to "dc.services.instance.exposedpaths") selected=(is-href "dc.services.instance.exposedpaths")))
|
||||||
)
|
|
||||||
(if proxy
|
|
||||||
(hash label="Upstreams" href=(href-to "dc.services.instance.upstreams") selected=(is-href "dc.services.instance.upstreams"))
|
|
||||||
)
|
|
||||||
(if proxy
|
|
||||||
(hash label="Exposed Paths" href=(href-to "dc.services.instance.exposedpaths") selected=(is-href "dc.services.instance.exposedpaths"))
|
|
||||||
)
|
|
||||||
(hash label="Tags & Meta" href=(href-to "dc.services.instance.metadata") selected=(is-href "dc.services.instance.metadata"))
|
(hash label="Tags & Meta" href=(href-to "dc.services.instance.metadata") selected=(is-href "dc.services.instance.metadata"))
|
||||||
)
|
)
|
||||||
}}/>
|
}}
|
||||||
|
/>
|
||||||
<Outlet
|
<Outlet
|
||||||
@name={{routeName}}
|
@name={{routeName}}
|
||||||
@model={{assign (hash
|
@model={{assign (hash
|
||||||
proxy=proxy
|
proxy=proxy
|
||||||
|
meta=meta
|
||||||
item=item
|
item=item
|
||||||
) route.model}}
|
) route.model}}
|
||||||
as |o|>
|
as |o|>
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
@name={{routeName}}
|
@name={{routeName}}
|
||||||
as |route|>
|
as |route|>
|
||||||
{{#let
|
{{#let
|
||||||
route.model.item
|
(entries route.model.item.Service.TaggedAddresses)
|
||||||
as |item|}}
|
as |items|}}
|
||||||
<div class="tab-section">
|
<div class="tab-section">
|
||||||
{{#if item.Service.TaggedAddresses }}
|
{{#if (gt items.length 0)}}
|
||||||
<TabularCollection
|
<TabularCollection
|
||||||
data-test-addresses
|
data-test-addresses
|
||||||
class="consul-tagged-addresses"
|
class="consul-tagged-addresses"
|
||||||
@items={{entries item.Service.TaggedAddresses}} as |taggedAddress index|
|
@items={{items}} as |taggedAddress index|
|
||||||
>
|
>
|
||||||
<BlockSlot @name="header">
|
<BlockSlot @name="header">
|
||||||
<th>Tag</th>
|
<th>Tag</th>
|
||||||
|
|
|
@ -3,13 +3,17 @@
|
||||||
as |route|>
|
as |route|>
|
||||||
{{#let
|
{{#let
|
||||||
route.model.proxy
|
route.model.proxy
|
||||||
as |proxy|}}
|
route.model.meta
|
||||||
|
as |item proxy|}}
|
||||||
<div class="tab-section">
|
<div class="tab-section">
|
||||||
{{#if (gt proxy.Service.Proxy.Expose.Paths.length 0)}}
|
{{#if (gt proxy.ServiceProxy.Expose.Paths.length 0)}}
|
||||||
<p>
|
<p>
|
||||||
The following list shows individual HTTP paths exposed through Envoy for external services like Prometheus. Read more about this in our documentation.
|
The following list shows individual HTTP paths exposed through Envoy for external services like Prometheus. Read more about this in our <Action @href={{concat (env 'CONSUL_DOCS_URL') '/connect/registration/service-registration#expose-paths-configuration-reference'}} @external={{true}}>documentation</Action>.
|
||||||
</p>
|
</p>
|
||||||
<Consul::ExposedPath::List @items={{proxy.Service.Proxy.Expose.Paths}} @address={{proxy.Address}} />
|
<Consul::ExposedPath::List
|
||||||
|
@items={{proxy.ServiceProxy.Expose.Paths}}
|
||||||
|
@address={{or item.Service.Address item.Node.Address}}
|
||||||
|
/>
|
||||||
{{else}}
|
{{else}}
|
||||||
<EmptyState>
|
<EmptyState>
|
||||||
<BlockSlot @name="body">
|
<BlockSlot @name="body">
|
||||||
|
|
|
@ -27,7 +27,7 @@ as |route|>
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
route.model.item.MeshChecks
|
(merge-checks (array route.model.item.Checks route.model.proxy.Checks) route.model.proxy.ServiceProxy.Expose.Checks)
|
||||||
|
|
||||||
as |sort filters items|}}
|
as |sort filters items|}}
|
||||||
<div class="tab-section">
|
<div class="tab-section">
|
||||||
|
|
|
@ -25,9 +25,10 @@ as |route|>
|
||||||
route.params.dc
|
route.params.dc
|
||||||
|
|
||||||
route.model.proxy
|
route.model.proxy
|
||||||
|
route.model.meta
|
||||||
route.model.proxy.Service.Proxy.Upstreams
|
route.model.proxy.Service.Proxy.Upstreams
|
||||||
|
|
||||||
as |sort filters partition nspace dc proxy items|}}
|
as |sort filters partition nspace dc proxy meta items|}}
|
||||||
{{#if (gt items.length 0)}}
|
{{#if (gt items.length 0)}}
|
||||||
<input type="checkbox" id="toolbar-toggle" />
|
<input type="checkbox" id="toolbar-toggle" />
|
||||||
<Consul::UpstreamInstance::SearchBar
|
<Consul::UpstreamInstance::SearchBar
|
||||||
|
@ -40,12 +41,16 @@ as |route|>
|
||||||
@filter={{filters}}
|
@filter={{filters}}
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if (eq proxy.ServiceProxy.Mode 'transparent')}}
|
{{! TODO: Looks like we can get this straight from item.Proxy.Mode }}
|
||||||
|
{{! the less we need `proxy` and `meta` the better }}
|
||||||
|
{{#if (eq meta.ServiceProxy.Mode 'transparent')}}
|
||||||
<Notice
|
<Notice
|
||||||
@type="warning"
|
@type="warning"
|
||||||
as |notice|>
|
as |notice|>
|
||||||
<notice.Header>
|
<notice.Header>
|
||||||
<h3>{{t "routes.dc.services.instance.upstreams.tproxy-mode.header"}}</h3>
|
<h3>
|
||||||
|
{{t "routes.dc.services.instance.upstreams.tproxy-mode.header"}}
|
||||||
|
</h3>
|
||||||
</notice.Header>
|
</notice.Header>
|
||||||
<notice.Body>
|
<notice.Body>
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -9,6 +9,7 @@ Below is a list of the most commonly used functions as bookmarklets followed by
|
||||||
| [Print Routing DSL](javascript:Routes()) | Print out Ember's Route DSL for the application |
|
| [Print Routing DSL](javascript:Routes()) | Print out Ember's Route DSL for the application |
|
||||||
| [Save Current Scenario](javascript:Scenario()) | Opens a tab with links to allow you to create a bookmarklet or share a URL of your current scenario (your Consul UI relarted development/debug cookies) |
|
| [Save Current Scenario](javascript:Scenario()) | Opens a tab with links to allow you to create a bookmarklet or share a URL of your current scenario (your Consul UI relarted development/debug cookies) |
|
||||||
| [Enable ACLs](javascript:Scenario('CONSUL_ACLS_ENABLE=1')) | Enable ACLs |
|
| [Enable ACLs](javascript:Scenario('CONSUL_ACLS_ENABLE=1')) | Enable ACLs |
|
||||||
|
| [Enable TProxy](javascript:Scenario('CONSUL_TPROXY_ENABLE=1')) | Enable TProxy |
|
||||||
| [Enable Nspaces](javascript:Scenario('CONSUL_NSPACES_ENABLE=1')) | Enable Namespace Support |
|
| [Enable Nspaces](javascript:Scenario('CONSUL_NSPACES_ENABLE=1')) | Enable Namespace Support |
|
||||||
| [Enable Partitions](javascript:Scenario('CONSUL_PARTITIONS_ENABLE=1')) | Enable Admin Partition Support |
|
| [Enable Partitions](javascript:Scenario('CONSUL_PARTITIONS_ENABLE=1')) | Enable Admin Partition Support |
|
||||||
| [Enable SSO](javascript:Scenario('CONSUL_SSO_ENABLE=1')) | Enable SSO Support |
|
| [Enable SSO](javascript:Scenario('CONSUL_SSO_ENABLE=1')) | Enable SSO Support |
|
||||||
|
@ -37,6 +38,7 @@ token/secret.
|
||||||
| -------- | ------------- | ----------- |
|
| -------- | ------------- | ----------- |
|
||||||
| `CONSUL_ACLS_ENABLE` | false | Enable/disable ACLs support. |
|
| `CONSUL_ACLS_ENABLE` | false | Enable/disable ACLs support. |
|
||||||
| `CONSUL_ACLS_LEGACY` | false | Enable/disable legacy ACLs support. |
|
| `CONSUL_ACLS_LEGACY` | false | Enable/disable legacy ACLs support. |
|
||||||
|
| `CONSUL_TPROXY_ENABLE` | false | Enable/disable TProxy support globally (if not a service may have this applied randomly). |
|
||||||
| `CONSUL_NSPACES_ENABLE` | false | Enable/disable Namespace support. |
|
| `CONSUL_NSPACES_ENABLE` | false | Enable/disable Namespace support. |
|
||||||
| `CONSUL_SSO_ENABLE` | false | Enable/disable SSO support. |
|
| `CONSUL_SSO_ENABLE` | false | Enable/disable SSO support. |
|
||||||
| `CONSUL_OIDC_PROVIDER_URL` | undefined | Provide a OIDC provider URL for SSO. |
|
| `CONSUL_OIDC_PROVIDER_URL` | undefined | Provide a OIDC provider URL for SSO. |
|
||||||
|
|
|
@ -52,7 +52,7 @@ ${range(env('CONSUL_EXPOSED_COUNT', 3)).map((i) => `
|
||||||
`)}
|
`)}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"Mode": "${fake.helpers.randomize(['', 'direct', 'transparent'])}",
|
"Mode": "${env('CONSUL_TPROXY_ENABLE') ? `transparent` : fake.helpers.randomize(['', 'direct', 'transparent'])}",
|
||||||
"TransparentProxy": {},
|
"TransparentProxy": {},
|
||||||
"DestinationServiceName": "${location.pathname.slice(4)}"
|
"DestinationServiceName": "${location.pathname.slice(4)}"
|
||||||
${ location.pathname.slice(4) === "service-0" ? `
|
${ location.pathname.slice(4) === "service-0" ? `
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"ID": "237b9eeb-bba1-e6e3-3c99-c527d6d76cc0",
|
||||||
|
"Node": "node",
|
||||||
|
"Address": "172.17.0.2",
|
||||||
|
"Datacenter": "dc1",
|
||||||
|
"TaggedAddresses": {
|
||||||
|
"lan": "172.17.0.2",
|
||||||
|
"lan_ipv4": "172.17.0.2",
|
||||||
|
"wan": "172.17.0.2",
|
||||||
|
"wan_ipv4": "172.17.0.2"
|
||||||
|
},
|
||||||
|
"NodeMeta": {
|
||||||
|
"consul-network-segment": ""
|
||||||
|
},
|
||||||
|
"ServiceKind": "connect-proxy",
|
||||||
|
"ServiceID": "backend-sidecar-proxy",
|
||||||
|
"ServiceName": "backend-sidecar-proxy",
|
||||||
|
"ServiceTags": [],
|
||||||
|
"ServiceAddress": "",
|
||||||
|
"ServiceWeights": {
|
||||||
|
"Passing": 1,
|
||||||
|
"Warning": 1
|
||||||
|
},
|
||||||
|
"ServiceMeta": {},
|
||||||
|
"ServicePort": 21000,
|
||||||
|
"ServiceSocketPath": "",
|
||||||
|
"ServiceEnableTagOverride": false,
|
||||||
|
"ServiceProxy": {
|
||||||
|
"DestinationServiceName": "backend",
|
||||||
|
"DestinationServiceID": "backend",
|
||||||
|
"LocalServiceAddress": "127.0.0.1",
|
||||||
|
"LocalServicePort": 7000,
|
||||||
|
"Mode": "",
|
||||||
|
"MeshGateway": {},
|
||||||
|
"Expose": {}
|
||||||
|
},
|
||||||
|
"ServiceConnect": {},
|
||||||
|
"CreateIndex": 19,
|
||||||
|
"ModifyIndex": 19
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "237b9eeb-bba1-e6e3-3c99-c527d6d76cc0",
|
||||||
|
"Node": "node",
|
||||||
|
"Address": "172.17.0.2",
|
||||||
|
"Datacenter": "dc1",
|
||||||
|
"TaggedAddresses": {
|
||||||
|
"lan": "172.17.0.2",
|
||||||
|
"lan_ipv4": "172.17.0.2",
|
||||||
|
"wan": "172.17.0.2",
|
||||||
|
"wan_ipv4": "172.17.0.2"
|
||||||
|
},
|
||||||
|
"NodeMeta": {
|
||||||
|
"consul-network-segment": ""
|
||||||
|
},
|
||||||
|
"ServiceKind": "connect-proxy",
|
||||||
|
"ServiceID": "backend-v2-sidecar-proxy",
|
||||||
|
"ServiceName": "backend-sidecar-proxy",
|
||||||
|
"ServiceTags": [],
|
||||||
|
"ServiceAddress": "",
|
||||||
|
"ServiceWeights": {
|
||||||
|
"Passing": 1,
|
||||||
|
"Warning": 1
|
||||||
|
},
|
||||||
|
"ServiceMeta": {},
|
||||||
|
"ServicePort": 21001,
|
||||||
|
"ServiceSocketPath": "",
|
||||||
|
"ServiceEnableTagOverride": false,
|
||||||
|
"ServiceProxy": {
|
||||||
|
"DestinationServiceName": "backend",
|
||||||
|
"DestinationServiceID": "backend-v2",
|
||||||
|
"LocalServiceAddress": "127.0.0.1",
|
||||||
|
"LocalServicePort": 7001,
|
||||||
|
"Mode": "",
|
||||||
|
"MeshGateway": {},
|
||||||
|
"Expose": {}
|
||||||
|
},
|
||||||
|
"ServiceConnect": {},
|
||||||
|
"CreateIndex": 21,
|
||||||
|
"ModifyIndex": 21
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,122 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Node": {
|
||||||
|
"ID": "237b9eeb-bba1-e6e3-3c99-c527d6d76cc0",
|
||||||
|
"Node": "node",
|
||||||
|
"Address": "172.17.0.2",
|
||||||
|
"Datacenter": "dc1",
|
||||||
|
"TaggedAddresses": {
|
||||||
|
"lan": "172.17.0.2",
|
||||||
|
"lan_ipv4": "172.17.0.2",
|
||||||
|
"wan": "172.17.0.2",
|
||||||
|
"wan_ipv4": "172.17.0.2"
|
||||||
|
},
|
||||||
|
"Meta": {
|
||||||
|
"consul-network-segment": ""
|
||||||
|
},
|
||||||
|
"CreateIndex": 14,
|
||||||
|
"ModifyIndex": 17
|
||||||
|
},
|
||||||
|
"Service": {
|
||||||
|
"ID": "backend",
|
||||||
|
"Service": "backend",
|
||||||
|
"Tags": [],
|
||||||
|
"Address": "",
|
||||||
|
"Meta": null,
|
||||||
|
"Port": 7000,
|
||||||
|
"Weights": {
|
||||||
|
"Passing": 1,
|
||||||
|
"Warning": 1
|
||||||
|
},
|
||||||
|
"EnableTagOverride": false,
|
||||||
|
"Proxy": {
|
||||||
|
"Mode": "",
|
||||||
|
"MeshGateway": {},
|
||||||
|
"Expose": {}
|
||||||
|
},
|
||||||
|
"Connect": {},
|
||||||
|
"CreateIndex": 18,
|
||||||
|
"ModifyIndex": 18
|
||||||
|
},
|
||||||
|
"Checks": [
|
||||||
|
{
|
||||||
|
"Node": "node",
|
||||||
|
"CheckID": "serfHealth",
|
||||||
|
"Name": "Serf Health Status",
|
||||||
|
"Status": "passing",
|
||||||
|
"Notes": "",
|
||||||
|
"Output": "Agent alive and reachable",
|
||||||
|
"ServiceID": "",
|
||||||
|
"ServiceName": "",
|
||||||
|
"ServiceTags": [],
|
||||||
|
"Type": "",
|
||||||
|
"Interval": "",
|
||||||
|
"Timeout": "",
|
||||||
|
"ExposedPort": 0,
|
||||||
|
"Definition": {},
|
||||||
|
"CreateIndex": 14,
|
||||||
|
"ModifyIndex": 14
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Node": {
|
||||||
|
"ID": "237b9eeb-bba1-e6e3-3c99-c527d6d76cc0",
|
||||||
|
"Node": "node",
|
||||||
|
"Address": "172.17.0.2",
|
||||||
|
"Datacenter": "dc1",
|
||||||
|
"TaggedAddresses": {
|
||||||
|
"lan": "172.17.0.2",
|
||||||
|
"lan_ipv4": "172.17.0.2",
|
||||||
|
"wan": "172.17.0.2",
|
||||||
|
"wan_ipv4": "172.17.0.2"
|
||||||
|
},
|
||||||
|
"Meta": {
|
||||||
|
"consul-network-segment": ""
|
||||||
|
},
|
||||||
|
"CreateIndex": 14,
|
||||||
|
"ModifyIndex": 17
|
||||||
|
},
|
||||||
|
"Service": {
|
||||||
|
"ID": "backend-v2",
|
||||||
|
"Service": "backend",
|
||||||
|
"Tags": [],
|
||||||
|
"Address": "",
|
||||||
|
"Meta": null,
|
||||||
|
"Port": 7001,
|
||||||
|
"Weights": {
|
||||||
|
"Passing": 1,
|
||||||
|
"Warning": 1
|
||||||
|
},
|
||||||
|
"EnableTagOverride": false,
|
||||||
|
"Proxy": {
|
||||||
|
"Mode": "",
|
||||||
|
"MeshGateway": {},
|
||||||
|
"Expose": {}
|
||||||
|
},
|
||||||
|
"Connect": {},
|
||||||
|
"CreateIndex": 20,
|
||||||
|
"ModifyIndex": 20
|
||||||
|
},
|
||||||
|
"Checks": [
|
||||||
|
{
|
||||||
|
"Node": "node",
|
||||||
|
"CheckID": "serfHealth",
|
||||||
|
"Name": "Serf Health Status",
|
||||||
|
"Status": "passing",
|
||||||
|
"Notes": "",
|
||||||
|
"Output": "Agent alive and reachable",
|
||||||
|
"ServiceID": "",
|
||||||
|
"ServiceName": "",
|
||||||
|
"ServiceTags": [],
|
||||||
|
"Type": "",
|
||||||
|
"Interval": "",
|
||||||
|
"Timeout": "",
|
||||||
|
"ExposedPort": 0,
|
||||||
|
"Definition": {},
|
||||||
|
"CreateIndex": 14,
|
||||||
|
"ModifyIndex": 14
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,204 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Node": {
|
||||||
|
"ID": "237b9eeb-bba1-e6e3-3c99-c527d6d76cc0",
|
||||||
|
"Node": "node",
|
||||||
|
"Address": "172.17.0.2",
|
||||||
|
"Datacenter": "dc1",
|
||||||
|
"TaggedAddresses": {
|
||||||
|
"lan": "172.17.0.2",
|
||||||
|
"lan_ipv4": "172.17.0.2",
|
||||||
|
"wan": "172.17.0.2",
|
||||||
|
"wan_ipv4": "172.17.0.2"
|
||||||
|
},
|
||||||
|
"Meta": {
|
||||||
|
"consul-network-segment": ""
|
||||||
|
},
|
||||||
|
"CreateIndex": 14,
|
||||||
|
"ModifyIndex": 17
|
||||||
|
},
|
||||||
|
"Service": {
|
||||||
|
"Kind": "connect-proxy",
|
||||||
|
"ID": "backend-sidecar-proxy",
|
||||||
|
"Service": "backend-sidecar-proxy",
|
||||||
|
"Tags": [],
|
||||||
|
"Address": "",
|
||||||
|
"Meta": null,
|
||||||
|
"Port": 21000,
|
||||||
|
"Weights": {
|
||||||
|
"Passing": 1,
|
||||||
|
"Warning": 1
|
||||||
|
},
|
||||||
|
"EnableTagOverride": false,
|
||||||
|
"Proxy": {
|
||||||
|
"DestinationServiceName": "backend",
|
||||||
|
"DestinationServiceID": "backend",
|
||||||
|
"LocalServiceAddress": "127.0.0.1",
|
||||||
|
"LocalServicePort": 7000,
|
||||||
|
"Mode": "",
|
||||||
|
"MeshGateway": {},
|
||||||
|
"Expose": {}
|
||||||
|
},
|
||||||
|
"Connect": {},
|
||||||
|
"CreateIndex": 19,
|
||||||
|
"ModifyIndex": 19
|
||||||
|
},
|
||||||
|
"Checks": [
|
||||||
|
{
|
||||||
|
"Node": "node",
|
||||||
|
"CheckID": "serfHealth",
|
||||||
|
"Name": "Serf Health Status",
|
||||||
|
"Status": "passing",
|
||||||
|
"Notes": "",
|
||||||
|
"Output": "Agent alive and reachable",
|
||||||
|
"ServiceID": "",
|
||||||
|
"ServiceName": "",
|
||||||
|
"ServiceTags": [],
|
||||||
|
"Type": "",
|
||||||
|
"Interval": "",
|
||||||
|
"Timeout": "",
|
||||||
|
"ExposedPort": 0,
|
||||||
|
"Definition": {},
|
||||||
|
"CreateIndex": 14,
|
||||||
|
"ModifyIndex": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Node": "node",
|
||||||
|
"CheckID": "service:backend-sidecar-proxy:1",
|
||||||
|
"Name": "Connect Sidecar Listening",
|
||||||
|
"Status": "critical",
|
||||||
|
"Notes": "",
|
||||||
|
"Output": "dial tcp 127.0.0.1:21000: connect: connection refused",
|
||||||
|
"ServiceID": "backend-sidecar-proxy",
|
||||||
|
"ServiceName": "backend-sidecar-proxy",
|
||||||
|
"ServiceTags": [],
|
||||||
|
"Type": "tcp",
|
||||||
|
"Interval": "",
|
||||||
|
"Timeout": "",
|
||||||
|
"ExposedPort": 0,
|
||||||
|
"Definition": {},
|
||||||
|
"CreateIndex": 19,
|
||||||
|
"ModifyIndex": 42
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Node": "node",
|
||||||
|
"CheckID": "service:backend-sidecar-proxy:2",
|
||||||
|
"Name": "Connect Sidecar Aliasing backend",
|
||||||
|
"Status": "critical",
|
||||||
|
"Notes": "",
|
||||||
|
"Output": "No checks found.",
|
||||||
|
"ServiceID": "backend-sidecar-proxy",
|
||||||
|
"ServiceName": "backend-sidecar-proxy",
|
||||||
|
"ServiceTags": [],
|
||||||
|
"Type": "alias",
|
||||||
|
"Interval": "",
|
||||||
|
"Timeout": "",
|
||||||
|
"ExposedPort": 0,
|
||||||
|
"Definition": {},
|
||||||
|
"CreateIndex": 19,
|
||||||
|
"ModifyIndex": 19
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Node": {
|
||||||
|
"ID": "237b9eeb-bba1-e6e3-3c99-c527d6d76cc0",
|
||||||
|
"Node": "node",
|
||||||
|
"Address": "172.17.0.2",
|
||||||
|
"Datacenter": "dc1",
|
||||||
|
"TaggedAddresses": {
|
||||||
|
"lan": "172.17.0.2",
|
||||||
|
"lan_ipv4": "172.17.0.2",
|
||||||
|
"wan": "172.17.0.2",
|
||||||
|
"wan_ipv4": "172.17.0.2"
|
||||||
|
},
|
||||||
|
"Meta": {
|
||||||
|
"consul-network-segment": ""
|
||||||
|
},
|
||||||
|
"CreateIndex": 14,
|
||||||
|
"ModifyIndex": 17
|
||||||
|
},
|
||||||
|
"Service": {
|
||||||
|
"Kind": "connect-proxy",
|
||||||
|
"ID": "backend-v2-sidecar-proxy",
|
||||||
|
"Service": "backend-sidecar-proxy",
|
||||||
|
"Tags": [],
|
||||||
|
"Address": "",
|
||||||
|
"Meta": null,
|
||||||
|
"Port": 21001,
|
||||||
|
"Weights": {
|
||||||
|
"Passing": 1,
|
||||||
|
"Warning": 1
|
||||||
|
},
|
||||||
|
"EnableTagOverride": false,
|
||||||
|
"Proxy": {
|
||||||
|
"DestinationServiceName": "backend",
|
||||||
|
"DestinationServiceID": "backend-v2",
|
||||||
|
"LocalServiceAddress": "127.0.0.1",
|
||||||
|
"LocalServicePort": 7001,
|
||||||
|
"Mode": "",
|
||||||
|
"MeshGateway": {},
|
||||||
|
"Expose": {}
|
||||||
|
},
|
||||||
|
"Connect": {},
|
||||||
|
"CreateIndex": 21,
|
||||||
|
"ModifyIndex": 21
|
||||||
|
},
|
||||||
|
"Checks": [
|
||||||
|
{
|
||||||
|
"Node": "node",
|
||||||
|
"CheckID": "serfHealth",
|
||||||
|
"Name": "Serf Health Status",
|
||||||
|
"Status": "passing",
|
||||||
|
"Notes": "",
|
||||||
|
"Output": "Agent alive and reachable",
|
||||||
|
"ServiceID": "",
|
||||||
|
"ServiceName": "",
|
||||||
|
"ServiceTags": [],
|
||||||
|
"Type": "",
|
||||||
|
"Interval": "",
|
||||||
|
"Timeout": "",
|
||||||
|
"ExposedPort": 0,
|
||||||
|
"Definition": {},
|
||||||
|
"CreateIndex": 14,
|
||||||
|
"ModifyIndex": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Node": "node",
|
||||||
|
"CheckID": "service:backend-v2-sidecar-proxy:1",
|
||||||
|
"Name": "Connect Sidecar Listening",
|
||||||
|
"Status": "critical",
|
||||||
|
"Notes": "",
|
||||||
|
"Output": "dial tcp 127.0.0.1:21001: connect: connection refused",
|
||||||
|
"ServiceID": "backend-v2-sidecar-proxy",
|
||||||
|
"ServiceName": "backend-sidecar-proxy",
|
||||||
|
"ServiceTags": [],
|
||||||
|
"Type": "tcp",
|
||||||
|
"Interval": "",
|
||||||
|
"Timeout": "",
|
||||||
|
"ExposedPort": 0,
|
||||||
|
"Definition": {},
|
||||||
|
"CreateIndex": 21,
|
||||||
|
"ModifyIndex": 44
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Node": "node",
|
||||||
|
"CheckID": "service:backend-v2-sidecar-proxy:2",
|
||||||
|
"Name": "Connect Sidecar Aliasing backend-v2",
|
||||||
|
"Status": "passing",
|
||||||
|
"Notes": "",
|
||||||
|
"Output": "No checks found.",
|
||||||
|
"ServiceID": "backend-v2-sidecar-proxy",
|
||||||
|
"ServiceName": "backend-sidecar-proxy",
|
||||||
|
"ServiceTags": [],
|
||||||
|
"Type": "alias",
|
||||||
|
"Interval": "",
|
||||||
|
"Timeout": "",
|
||||||
|
"ExposedPort": 0,
|
||||||
|
"Definition": {},
|
||||||
|
"CreateIndex": 21,
|
||||||
|
"ModifyIndex": 21
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { moduleFor, test } from 'ember-qunit';
|
||||||
|
moduleFor('service:routlet', 'Integration | Routlet', {
|
||||||
|
// Specify the other units that are required for this test.
|
||||||
|
integration: true,
|
||||||
|
});
|
||||||
|
test('outletFor works', function(assert) {
|
||||||
|
const routlet = this.subject();
|
||||||
|
routlet.addOutlet('application', {
|
||||||
|
name: 'application'
|
||||||
|
});
|
||||||
|
routlet.addRoute('dc', {});
|
||||||
|
routlet.addOutlet('dc', {
|
||||||
|
name: 'dc'
|
||||||
|
});
|
||||||
|
routlet.addRoute('dc.services', {});
|
||||||
|
routlet.addOutlet('dc.services', {
|
||||||
|
name: 'dc.services'
|
||||||
|
});
|
||||||
|
routlet.addRoute('dc.services.instances', {});
|
||||||
|
|
||||||
|
let actual = routlet.outletFor('dc.services');
|
||||||
|
let expected = 'dc';
|
||||||
|
assert.equal(actual.name, expected);
|
||||||
|
|
||||||
|
actual = routlet.outletFor('dc');
|
||||||
|
expected = 'application';
|
||||||
|
assert.equal(actual.name, expected);
|
||||||
|
|
||||||
|
actual = routlet.outletFor('application');
|
||||||
|
expected = undefined;
|
||||||
|
assert.equal(actual, expected);
|
||||||
|
});
|
Loading…
Reference in New Issue