ui: Remove legacy ACLs (#11096)
This commit is contained in:
parent
5da06645b0
commit
51149cdae2
|
@ -1,74 +0,0 @@
|
||||||
import Adapter, { DATACENTER_QUERY_PARAM as API_DATACENTER_KEY } from './application';
|
|
||||||
import { SLUG_KEY } from 'consul-ui/models/acl';
|
|
||||||
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
|
|
||||||
|
|
||||||
// The old ACL system doesn't support the `ns=` query param
|
|
||||||
// TODO: Update to use this.formatDatacenter()
|
|
||||||
export default class AclAdapter extends Adapter {
|
|
||||||
requestForQuery(request, { dc, index }) {
|
|
||||||
// https://www.consul.io/api/acl.html#list-acls
|
|
||||||
return request`
|
|
||||||
GET /v1/acl/list?${{ dc }}
|
|
||||||
|
|
||||||
${{ index }}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
requestForQueryRecord(request, { dc, index, id }) {
|
|
||||||
if (typeof id === 'undefined') {
|
|
||||||
throw new Error('You must specify an id');
|
|
||||||
}
|
|
||||||
// https://www.consul.io/api/acl.html#read-acl-token
|
|
||||||
return request`
|
|
||||||
GET /v1/acl/info/${id}?${{ dc }}
|
|
||||||
|
|
||||||
${{ index }}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
requestForCreateRecord(request, serialized, data) {
|
|
||||||
// https://www.consul.io/api/acl.html#create-acl-token
|
|
||||||
return request`
|
|
||||||
PUT /v1/acl/create?${{ [API_DATACENTER_KEY]: data[DATACENTER_KEY] }}
|
|
||||||
|
|
||||||
${serialized}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
requestForUpdateRecord(request, serialized, data) {
|
|
||||||
// the id is in the data, don't add it into the URL
|
|
||||||
// https://www.consul.io/api/acl.html#update-acl-token
|
|
||||||
return request`
|
|
||||||
PUT /v1/acl/update?${{ [API_DATACENTER_KEY]: data[DATACENTER_KEY] }}
|
|
||||||
|
|
||||||
${serialized}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
requestForDeleteRecord(request, serialized, data) {
|
|
||||||
// https://www.consul.io/api/acl.html#delete-acl-token
|
|
||||||
return request`
|
|
||||||
PUT /v1/acl/destroy/${data[SLUG_KEY]}?${{ [API_DATACENTER_KEY]: data[DATACENTER_KEY] }}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
requestForCloneRecord(request, serialized, data) {
|
|
||||||
// https://www.consul.io/api/acl.html#clone-acl-token
|
|
||||||
return request`
|
|
||||||
PUT /v1/acl/clone/${data[SLUG_KEY]}?${{ [API_DATACENTER_KEY]: data[DATACENTER_KEY] }}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
clone(store, type, id, snapshot) {
|
|
||||||
return this.rpc(
|
|
||||||
function(adapter, request, serialized, unserialized) {
|
|
||||||
return adapter.requestForCloneRecord(request, serialized, unserialized);
|
|
||||||
},
|
|
||||||
function(serializer, respond, serialized, unserialized) {
|
|
||||||
return serializer.respondForCreateRecord(respond, serialized, unserialized);
|
|
||||||
},
|
|
||||||
snapshot,
|
|
||||||
type.modelName
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,130 +0,0 @@
|
||||||
<div
|
|
||||||
class="consul-acl-list"
|
|
||||||
...attributes
|
|
||||||
>
|
|
||||||
<TabularCollection
|
|
||||||
@items={{@items}}
|
|
||||||
as |item index|
|
|
||||||
>
|
|
||||||
<BlockSlot @name="header">
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Type</th>
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="row">
|
|
||||||
<td data-test-acl={{item.Name}}>
|
|
||||||
<a href={{href-to 'dc.acls.edit' item.ID}}>{{item.Name}}</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{#if (eq item.Type 'management')}}
|
|
||||||
<strong>{{item.Type}}</strong>
|
|
||||||
{{else}}
|
|
||||||
<span>{{item.Type}}</span>
|
|
||||||
{{/if}}
|
|
||||||
</td>
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="actions" as |index change checked|>
|
|
||||||
<PopoverMenu @expanded={{if (eq checked index) true false}} @onchange={{action change index}} @keyboardAccess={{false}} @submenus={{array "logout" "use" "delete"}}>
|
|
||||||
<BlockSlot @name="trigger">
|
|
||||||
More
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="menu" as |confirm send keypressClick|>
|
|
||||||
<li role="none">
|
|
||||||
<a data-test-edit role="menuitem" tabindex="-1" href={{href-to 'dc.acls.edit' item.ID}}>
|
|
||||||
{{#if (can "write acl" item=item)}}
|
|
||||||
Edit
|
|
||||||
{{else}}
|
|
||||||
View
|
|
||||||
{{/if}}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{{#if (eq item.ID token.SecretID) }}
|
|
||||||
<li role="none">
|
|
||||||
<label for={{concat confirm 'logout'}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-logout>Stop using</label>
|
|
||||||
<div role="menu">
|
|
||||||
<div class="confirmation-alert warning">
|
|
||||||
<div>
|
|
||||||
<header>
|
|
||||||
Confirm logout
|
|
||||||
</header>
|
|
||||||
<p>
|
|
||||||
Are you sure you want to stop using this ACL token? This will log you out.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<ul>
|
|
||||||
<li class="dangerous">
|
|
||||||
<button tabindex="-1" type="button" onclick={{action send 'logout' item}}>Logout</button>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for={{concat confirm 'logout'}}>Cancel</label>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
{{else}}
|
|
||||||
<li role="none">
|
|
||||||
<label for={{concat confirm 'use'}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-use>Use</label>
|
|
||||||
<div role="menu">
|
|
||||||
<div class="confirmation-alert warning">
|
|
||||||
<div>
|
|
||||||
<header>
|
|
||||||
Confirm use
|
|
||||||
</header>
|
|
||||||
<p>
|
|
||||||
Are you sure you want to use this ACL token?
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<ul>
|
|
||||||
<li class="dangerous">
|
|
||||||
<button
|
|
||||||
{{on 'click' (fn @onuse item)}}
|
|
||||||
data-test-confirm-use
|
|
||||||
tabindex="-1"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
Use
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for={{concat confirm 'use'}}>Cancel</label>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
{{/if}}
|
|
||||||
{{#if (can "duplicate acl" item=item)}}
|
|
||||||
<li role="none">
|
|
||||||
<button role="menuitem" tabindex="-1" type="button" data-test-clone {{action @onclone item}}>Duplicate</button>
|
|
||||||
</li>
|
|
||||||
{{/if}}
|
|
||||||
{{#if (can "delete acl" item=item)}}
|
|
||||||
<li role="none" class="dangerous">
|
|
||||||
<label for={{concat confirm 'delete'}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-delete>Delete</label>
|
|
||||||
<div role="menu">
|
|
||||||
<div class="confirmation-alert warning">
|
|
||||||
<div>
|
|
||||||
<header>
|
|
||||||
Confirm Delete
|
|
||||||
</header>
|
|
||||||
<p>
|
|
||||||
Are you sure you want to delete this token?
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<ul>
|
|
||||||
<li class="dangerous">
|
|
||||||
<button tabindex="-1" type="button" class="type-delete" onclick={{action @ondelete item}}>Delete</button>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label for={{concat confirm 'delete'}}>Cancel</label>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
{{/if}}
|
|
||||||
</BlockSlot>
|
|
||||||
</PopoverMenu>
|
|
||||||
</BlockSlot>
|
|
||||||
</TabularCollection>
|
|
||||||
</div>
|
|
|
@ -1,31 +0,0 @@
|
||||||
{{#if (eq @type 'create')}}
|
|
||||||
{{#if (eq @status 'success') }}
|
|
||||||
Your ACL token has been added.
|
|
||||||
{{else}}
|
|
||||||
There was an error adding your ACL token.
|
|
||||||
{{/if}}
|
|
||||||
{{else if (eq @type 'update') }}
|
|
||||||
{{#if (eq @status 'success') }}
|
|
||||||
Your ACL token has been saved.
|
|
||||||
{{else}}
|
|
||||||
There was an error saving your ACL token.
|
|
||||||
{{/if}}
|
|
||||||
{{ else if (eq @type 'delete')}}
|
|
||||||
{{#if (eq @status 'success') }}
|
|
||||||
Your ACL token was deleted.
|
|
||||||
{{else}}
|
|
||||||
There was an error deleting your ACL token.
|
|
||||||
{{/if}}
|
|
||||||
{{ else if (eq @type 'use')}}
|
|
||||||
{{#if (eq @status 'success') }}
|
|
||||||
Now using new ACL token.
|
|
||||||
{{else}}
|
|
||||||
There was an error using that ACL token.
|
|
||||||
{{/if}}
|
|
||||||
{{ else if (eq @type 'clone')}}
|
|
||||||
{{#if (eq @status 'success') }}
|
|
||||||
Your ACL token was cloned.
|
|
||||||
{{else}}
|
|
||||||
There was an error cloning your ACL token.
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
|
@ -1,127 +0,0 @@
|
||||||
<SearchBar
|
|
||||||
class="consul-acl-search-bar"
|
|
||||||
...attributes
|
|
||||||
@filter={{@filter}}
|
|
||||||
>
|
|
||||||
<:status as |search|>
|
|
||||||
|
|
||||||
{{#let
|
|
||||||
|
|
||||||
(t (concat "components.consul.acl.search-bar." search.status.key)
|
|
||||||
default=(array
|
|
||||||
(concat "common.search." search.status.key)
|
|
||||||
(concat "common.consul." search.status.key)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
(t (concat "components.consul.acl.search-bar." search.status.value)
|
|
||||||
default=(array
|
|
||||||
(concat "common.search." search.status.value)
|
|
||||||
(concat "common.consul." search.status.value)
|
|
||||||
(concat "common.brand." search.status.value)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
as |key value|}}
|
|
||||||
<search.RemoveFilter
|
|
||||||
aria-label={{t "common.ui.remove" item=(concat key " " value)}}
|
|
||||||
>
|
|
||||||
<dl>
|
|
||||||
<dt>{{key}}</dt>
|
|
||||||
<dd>{{value}}</dd>
|
|
||||||
</dl>
|
|
||||||
</search.RemoveFilter>
|
|
||||||
{{/let}}
|
|
||||||
|
|
||||||
</:status>
|
|
||||||
<:search as |search|>
|
|
||||||
<search.Search
|
|
||||||
@onsearch={{action @onsearch}}
|
|
||||||
@value={{@search}}
|
|
||||||
@placeholder={{t "common.search.search"}}
|
|
||||||
>
|
|
||||||
{{#if @filter.searchproperty}}
|
|
||||||
<search.Select
|
|
||||||
class="type-search-properties"
|
|
||||||
@position="right"
|
|
||||||
@onchange={{action @filter.searchproperty.change}}
|
|
||||||
@multiple={{true}}
|
|
||||||
@required={{true}}
|
|
||||||
as |components|>
|
|
||||||
<BlockSlot @name="selected">
|
|
||||||
<span>
|
|
||||||
{{t "common.search.searchproperty"}}
|
|
||||||
</span>
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="options">
|
|
||||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
|
||||||
{{#each @filter.searchproperty.default as |prop|}}
|
|
||||||
<Option @value={{prop}} @selected={{contains prop @filter.searchproperty.value}}>
|
|
||||||
{{t (concat "common.consul." (lowercase prop))}}
|
|
||||||
</Option>
|
|
||||||
{{/each}}
|
|
||||||
{{/let}}
|
|
||||||
</BlockSlot>
|
|
||||||
</search.Select>
|
|
||||||
{{/if}}
|
|
||||||
</search.Search>
|
|
||||||
</:search>
|
|
||||||
<:filter as |search|>
|
|
||||||
<search.Select
|
|
||||||
class="type-status"
|
|
||||||
@position="left"
|
|
||||||
@onchange={{action @filter.kind.change}}
|
|
||||||
@multiple={{true}}
|
|
||||||
as |components|>
|
|
||||||
<BlockSlot @name="selected">
|
|
||||||
<span>
|
|
||||||
{{t "components.consul.acl.search-bar.kind.name"}}
|
|
||||||
</span>
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="options">
|
|
||||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
|
||||||
{{#each (array "management" "client") as |state|}}
|
|
||||||
<Option class="value-{{state}}" @value={{state}} @selected={{contains state @filter.status.value}}>
|
|
||||||
{{t (concat "components.acl.search-bar.kind.options." state)
|
|
||||||
default=(array
|
|
||||||
(concat "common.search." state)
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</Option>
|
|
||||||
{{/each}}
|
|
||||||
{{/let}}
|
|
||||||
</BlockSlot>
|
|
||||||
</search.Select>
|
|
||||||
</:filter>
|
|
||||||
<:sort as |search|>
|
|
||||||
<search.Select
|
|
||||||
class="type-sort"
|
|
||||||
data-test-sort-control
|
|
||||||
@position="right"
|
|
||||||
@onchange={{action @sort.change}}
|
|
||||||
@multiple={{false}}
|
|
||||||
@required={{true}}
|
|
||||||
as |components|>
|
|
||||||
<BlockSlot @name="selected">
|
|
||||||
<span>
|
|
||||||
{{#let (from-entries (array
|
|
||||||
(array "Name:asc" (t "common.sort.alpha.asc"))
|
|
||||||
(array "Name:desc" (t "common.sort.alpha.desc"))
|
|
||||||
))
|
|
||||||
as |selectable|
|
|
||||||
}}
|
|
||||||
{{get selectable @sort.value}}
|
|
||||||
{{/let}}
|
|
||||||
</span>
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="options">
|
|
||||||
{{#let components.Optgroup components.Option as |Optgroup Option|}}
|
|
||||||
<Optgroup @label={{t "common.consul.name"}}>
|
|
||||||
<Option @value="Name:asc" @selected={{eq "Name:asc" @sort.value}}>{{t "common.sort.alpha.asc"}}</Option>
|
|
||||||
<Option @value="Name:desc" @selected={{eq "Name:desc" @sort.value}}>{{t "common.sort.alpha.desc"}}</Option>
|
|
||||||
</Optgroup>
|
|
||||||
{{/let}}
|
|
||||||
</BlockSlot>
|
|
||||||
</search.Select>
|
|
||||||
</:sort>
|
|
||||||
</SearchBar>
|
|
|
@ -1,2 +0,0 @@
|
||||||
import Controller from './edit';
|
|
||||||
export default class CreateController extends Controller {}
|
|
|
@ -1,30 +0,0 @@
|
||||||
import Controller from '@ember/controller';
|
|
||||||
import { inject as service } from '@ember/service';
|
|
||||||
|
|
||||||
export default Controller.extend({
|
|
||||||
builder: service('form'),
|
|
||||||
dom: service('dom'),
|
|
||||||
init: function() {
|
|
||||||
this._super(...arguments);
|
|
||||||
this.form = this.builder.form('acl');
|
|
||||||
},
|
|
||||||
setProperties: function(model) {
|
|
||||||
// essentially this replaces the data with changesets
|
|
||||||
this._super(
|
|
||||||
Object.keys(model).reduce((prev, key, i) => {
|
|
||||||
switch (key) {
|
|
||||||
case 'item':
|
|
||||||
prev[key] = this.form.setData(prev[key]).getData();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return prev;
|
|
||||||
}, model)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
change: function(e, value, item) {
|
|
||||||
const event = this.dom.normalizeEvent(e, value);
|
|
||||||
this.form.handleEvent(event);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,6 +0,0 @@
|
||||||
export default {
|
|
||||||
kind: {
|
|
||||||
management: (item, value) => item.Type === value,
|
|
||||||
client: (item, value) => item.Type === value,
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,6 +0,0 @@
|
||||||
import validations from 'consul-ui/validations/acl';
|
|
||||||
import builderFactory from 'consul-ui/utils/form/builder';
|
|
||||||
const builder = builderFactory();
|
|
||||||
export default function(container, name = '', v = validations, form = builder) {
|
|
||||||
return form(name, {}).setValidators(v);
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
import Mixin from '@ember/object/mixin';
|
|
||||||
import { get } from '@ember/object';
|
|
||||||
import { inject as service } from '@ember/service';
|
|
||||||
import WithBlockingActions from 'consul-ui/mixins/with-blocking-actions';
|
|
||||||
|
|
||||||
export default Mixin.create(WithBlockingActions, {
|
|
||||||
settings: service('settings'),
|
|
||||||
actions: {
|
|
||||||
use: function(item) {
|
|
||||||
return this.settings.persist({
|
|
||||||
token: {
|
|
||||||
Namespace: 'default',
|
|
||||||
AccessorID: null,
|
|
||||||
SecretID: get(item, 'ID'),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
logout: function(item) {
|
|
||||||
return this.settings.delete('token');
|
|
||||||
},
|
|
||||||
clone: function(item) {
|
|
||||||
return this.feedback.execute(() => {
|
|
||||||
return this.repo.clone(item).then(item => {
|
|
||||||
// cloning is similar to delete in that
|
|
||||||
// if you clone from the listing page, stay on the listing page
|
|
||||||
// whereas if you clone form another token, take me back to the listing page
|
|
||||||
// so I can see it
|
|
||||||
return this.afterDelete(...arguments);
|
|
||||||
});
|
|
||||||
}, 'clone');
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,19 +0,0 @@
|
||||||
import Model, { attr } from '@ember-data/model';
|
|
||||||
|
|
||||||
export const PRIMARY_KEY = 'uid';
|
|
||||||
export const SLUG_KEY = 'ID';
|
|
||||||
|
|
||||||
export default class Acl extends Model {
|
|
||||||
@attr('string') uid;
|
|
||||||
@attr('string') ID;
|
|
||||||
|
|
||||||
@attr('string') Datacenter;
|
|
||||||
// TODO: Why didn't I have to do this for KV's? This is to ensure that Name
|
|
||||||
// is '' and not null when creating maybe its due to the fact that `Key` is
|
|
||||||
// the primaryKey in Kv's
|
|
||||||
@attr('string', { defaultValue: () => '' }) Name;
|
|
||||||
@attr('string') Type;
|
|
||||||
@attr('string') Rules;
|
|
||||||
@attr('number') CreateIndex;
|
|
||||||
@attr('number') ModifyIndex;
|
|
||||||
}
|
|
|
@ -1,227 +1,236 @@
|
||||||
/* globals requirejs */
|
/* globals requirejs */
|
||||||
import EmberRouter from '@ember/routing/router';
|
import EmberRouter from '@ember/routing/router';
|
||||||
|
import config from './config/environment';
|
||||||
import { runInDebug } from '@ember/debug';
|
import { runInDebug } from '@ember/debug';
|
||||||
|
import merge from 'deepmerge';
|
||||||
import { env } from 'consul-ui/env';
|
import { env } from 'consul-ui/env';
|
||||||
import walk, { dump } from 'consul-ui/utils/routing/walk';
|
import walk, { dump } from 'consul-ui/utils/routing/walk';
|
||||||
|
|
||||||
export const routes = {
|
const doc = document;
|
||||||
// Our parent datacenter resource sets the namespace
|
const appName = config.modulePrefix;
|
||||||
// for the entire application
|
const appNameJS = appName
|
||||||
dc: {
|
.split('-')
|
||||||
_options: { path: '/:dc' },
|
.map((item, i) => (i ? `${item.substr(0, 1).toUpperCase()}${item.substr(1)}` : item))
|
||||||
// Services represent a consul service
|
.join('');
|
||||||
services: {
|
|
||||||
_options: { path: '/services' },
|
export const routes = merge.all(
|
||||||
// Show an individual service
|
[
|
||||||
show: {
|
{
|
||||||
_options: { path: '/:name' },
|
// Our parent datacenter resource sets the namespace
|
||||||
instances: {
|
// for the entire application
|
||||||
_options: { path: '/instances' },
|
dc: {
|
||||||
|
_options: { path: '/:dc' },
|
||||||
|
// Services represent a consul service
|
||||||
|
services: {
|
||||||
|
_options: { path: '/services' },
|
||||||
|
// Show an individual service
|
||||||
|
show: {
|
||||||
|
_options: { path: '/:name' },
|
||||||
|
instances: {
|
||||||
|
_options: { path: '/instances' },
|
||||||
|
},
|
||||||
|
intentions: {
|
||||||
|
_options: { path: '/intentions' },
|
||||||
|
edit: {
|
||||||
|
_options: { path: '/:intention_id' },
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
_options: { path: '/create' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
topology: {
|
||||||
|
_options: { path: '/topology' },
|
||||||
|
},
|
||||||
|
services: {
|
||||||
|
_options: { path: '/services' },
|
||||||
|
},
|
||||||
|
upstreams: {
|
||||||
|
_options: { path: '/upstreams' },
|
||||||
|
},
|
||||||
|
routing: {
|
||||||
|
_options: { path: '/routing' },
|
||||||
|
},
|
||||||
|
tags: {
|
||||||
|
_options: { path: '/tags' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
instance: {
|
||||||
|
_options: { path: '/:name/instances/:node/:id' },
|
||||||
|
healthchecks: {
|
||||||
|
_options: { path: '/health-checks' },
|
||||||
|
},
|
||||||
|
upstreams: {
|
||||||
|
_options: { path: '/upstreams' },
|
||||||
|
},
|
||||||
|
exposedpaths: {
|
||||||
|
_options: { path: '/exposed-paths' },
|
||||||
|
},
|
||||||
|
addresses: {
|
||||||
|
_options: { path: '/addresses' },
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
_options: { path: '/metadata' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
notfound: {
|
||||||
|
_options: { path: '/:name/:node/:id' },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
// Nodes represent a consul node
|
||||||
|
nodes: {
|
||||||
|
_options: { path: '/nodes' },
|
||||||
|
// Show an individual node
|
||||||
|
show: {
|
||||||
|
_options: { path: '/:name' },
|
||||||
|
healthchecks: {
|
||||||
|
_options: { path: '/health-checks' },
|
||||||
|
},
|
||||||
|
services: {
|
||||||
|
_options: { path: '/service-instances' },
|
||||||
|
},
|
||||||
|
rtt: {
|
||||||
|
_options: { path: '/round-trip-time' },
|
||||||
|
},
|
||||||
|
sessions: {
|
||||||
|
_options: { path: '/lock-sessions' },
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
_options: { path: '/metadata' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Intentions represent a consul intention
|
||||||
intentions: {
|
intentions: {
|
||||||
_options: { path: '/intentions' },
|
_options: { path: '/intentions' },
|
||||||
edit: {
|
edit: {
|
||||||
_options: { path: '/:intention_id' },
|
_options: {
|
||||||
|
path: '/:intention_id',
|
||||||
|
abilities: ['read intentions'],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
_options: { path: '/create' },
|
_options: {
|
||||||
|
path: '/create',
|
||||||
|
abilities: ['create intentions'],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
topology: {
|
// Key/Value
|
||||||
_options: { path: '/topology' },
|
kv: {
|
||||||
|
_options: { path: '/kv' },
|
||||||
|
folder: {
|
||||||
|
_options: { path: '/*key' },
|
||||||
|
},
|
||||||
|
edit: {
|
||||||
|
_options: { path: '/*key/edit' },
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
_options: {
|
||||||
|
path: '/*key/create',
|
||||||
|
abilities: ['create kvs'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'root-create': {
|
||||||
|
_options: {
|
||||||
|
path: '/create',
|
||||||
|
abilities: ['create kvs'],
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
services: {
|
// ACLs
|
||||||
_options: { path: '/services' },
|
acls: {
|
||||||
|
_options: {
|
||||||
|
path: '/acls',
|
||||||
|
abilities: ['access acls'],
|
||||||
|
},
|
||||||
|
policies: {
|
||||||
|
_options: {
|
||||||
|
path: '/policies',
|
||||||
|
abilities: ['read policies'],
|
||||||
|
},
|
||||||
|
edit: {
|
||||||
|
_options: { path: '/:id' },
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
_options: {
|
||||||
|
path: '/create',
|
||||||
|
abilities: ['create policies'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
roles: {
|
||||||
|
_options: {
|
||||||
|
path: '/roles',
|
||||||
|
abilities: ['read roles'],
|
||||||
|
},
|
||||||
|
edit: {
|
||||||
|
_options: { path: '/:id' },
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
_options: {
|
||||||
|
path: '/create',
|
||||||
|
abilities: ['create roles'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tokens: {
|
||||||
|
_options: {
|
||||||
|
path: '/tokens',
|
||||||
|
abilities: ['access acls'],
|
||||||
|
},
|
||||||
|
edit: {
|
||||||
|
_options: { path: '/:id' },
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
_options: {
|
||||||
|
path: '/create',
|
||||||
|
abilities: ['create tokens'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'auth-methods': {
|
||||||
|
_options: {
|
||||||
|
path: '/auth-methods',
|
||||||
|
abilities: ['read auth-methods'],
|
||||||
|
},
|
||||||
|
show: {
|
||||||
|
_options: { path: '/:id' },
|
||||||
|
'auth-method': {
|
||||||
|
_options: { path: '/auth-method' },
|
||||||
|
},
|
||||||
|
'binding-rules': {
|
||||||
|
_options: { path: '/binding-rules' },
|
||||||
|
},
|
||||||
|
'nspace-rules': {
|
||||||
|
_options: { path: '/nspace-rules' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
upstreams: {
|
'routing-config': {
|
||||||
_options: { path: '/upstreams' },
|
_options: { path: '/routing-config/:name' },
|
||||||
},
|
|
||||||
routing: {
|
|
||||||
_options: { path: '/routing' },
|
|
||||||
},
|
|
||||||
tags: {
|
|
||||||
_options: { path: '/tags' },
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
instance: {
|
// Shows a datacenter picker. If you only have one
|
||||||
_options: { path: '/:name/instances/:node/:id' },
|
// it just redirects you through.
|
||||||
healthchecks: {
|
index: {
|
||||||
_options: { path: '/health-checks' },
|
_options: { path: '/' },
|
||||||
},
|
},
|
||||||
upstreams: {
|
// The settings page is global.
|
||||||
_options: { path: '/upstreams' },
|
settings: {
|
||||||
},
|
_options: { path: '/setting' },
|
||||||
exposedpaths: {
|
|
||||||
_options: { path: '/exposed-paths' },
|
|
||||||
},
|
|
||||||
addresses: {
|
|
||||||
_options: { path: '/addresses' },
|
|
||||||
},
|
|
||||||
metadata: {
|
|
||||||
_options: { path: '/metadata' },
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
notfound: {
|
notfound: {
|
||||||
_options: { path: '/:name/:node/:id' },
|
_options: { path: '/*notfound' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Nodes represent a consul node
|
].concat(
|
||||||
nodes: {
|
...[...doc.querySelectorAll(`script[data-${appName}-routes]`)].map($item =>
|
||||||
_options: { path: '/nodes' },
|
JSON.parse($item.dataset[`${appNameJS}Routes`])
|
||||||
// Show an individual node
|
)
|
||||||
show: {
|
)
|
||||||
_options: { path: '/:name' },
|
);
|
||||||
healthchecks: {
|
|
||||||
_options: { path: '/health-checks' },
|
|
||||||
},
|
|
||||||
services: {
|
|
||||||
_options: { path: '/service-instances' },
|
|
||||||
},
|
|
||||||
rtt: {
|
|
||||||
_options: { path: '/round-trip-time' },
|
|
||||||
},
|
|
||||||
sessions: {
|
|
||||||
_options: { path: '/lock-sessions' },
|
|
||||||
},
|
|
||||||
metadata: {
|
|
||||||
_options: { path: '/metadata' },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// Intentions represent a consul intention
|
|
||||||
intentions: {
|
|
||||||
_options: { path: '/intentions' },
|
|
||||||
edit: {
|
|
||||||
_options: {
|
|
||||||
path: '/:intention_id',
|
|
||||||
abilities: ['read intentions'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
_options: {
|
|
||||||
path: '/create',
|
|
||||||
abilities: ['create intentions'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// Key/Value
|
|
||||||
kv: {
|
|
||||||
_options: { path: '/kv' },
|
|
||||||
folder: {
|
|
||||||
_options: { path: '/*key' },
|
|
||||||
},
|
|
||||||
edit: {
|
|
||||||
_options: { path: '/*key/edit' },
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
_options: {
|
|
||||||
path: '/*key/create',
|
|
||||||
abilities: ['create kvs'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'root-create': {
|
|
||||||
_options: {
|
|
||||||
path: '/create',
|
|
||||||
abilities: ['create kvs'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// ACLs
|
|
||||||
acls: {
|
|
||||||
_options: {
|
|
||||||
path: '/acls',
|
|
||||||
abilities: ['access acls'],
|
|
||||||
},
|
|
||||||
edit: {
|
|
||||||
_options: { path: '/:acl' },
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
_options: {
|
|
||||||
path: '/create',
|
|
||||||
abilities: ['create acls'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
policies: {
|
|
||||||
_options: {
|
|
||||||
path: '/policies',
|
|
||||||
abilities: ['read policies'],
|
|
||||||
},
|
|
||||||
edit: {
|
|
||||||
_options: { path: '/:id' },
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
_options: {
|
|
||||||
path: '/create',
|
|
||||||
abilities: ['create policies'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
roles: {
|
|
||||||
_options: {
|
|
||||||
path: '/roles',
|
|
||||||
abilities: ['read roles'],
|
|
||||||
},
|
|
||||||
edit: {
|
|
||||||
_options: { path: '/:id' },
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
_options: {
|
|
||||||
path: '/create',
|
|
||||||
abilities: ['create roles'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tokens: {
|
|
||||||
_options: {
|
|
||||||
path: '/tokens',
|
|
||||||
abilities: env('CONSUL_ACLS_ENABLED') ? ['read tokens'] : ['access acls'],
|
|
||||||
},
|
|
||||||
edit: {
|
|
||||||
_options: { path: '/:id' },
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
_options: {
|
|
||||||
path: '/create',
|
|
||||||
abilities: ['create tokens'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'auth-methods': {
|
|
||||||
_options: {
|
|
||||||
path: '/auth-methods',
|
|
||||||
abilities: ['read auth-methods'],
|
|
||||||
},
|
|
||||||
show: {
|
|
||||||
_options: { path: '/:id' },
|
|
||||||
'auth-method': {
|
|
||||||
_options: { path: '/auth-method' },
|
|
||||||
},
|
|
||||||
'binding-rules': {
|
|
||||||
_options: { path: '/binding-rules' },
|
|
||||||
},
|
|
||||||
'nspace-rules': {
|
|
||||||
_options: { path: '/nspace-rules' },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'routing-config': {
|
|
||||||
_options: { path: '/routing-config/:name' },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// Shows a datacenter picker. If you only have one
|
|
||||||
// it just redirects you through.
|
|
||||||
index: {
|
|
||||||
_options: { path: '/' },
|
|
||||||
},
|
|
||||||
// The settings page is global.
|
|
||||||
settings: {
|
|
||||||
_options: { path: '/setting' },
|
|
||||||
},
|
|
||||||
notfound: {
|
|
||||||
_options: { path: '/*notfound' },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
if (env('CONSUL_NSPACES_ENABLED')) {
|
if (env('CONSUL_NSPACES_ENABLED')) {
|
||||||
routes.dc.nspaces = {
|
routes.dc.nspaces = {
|
||||||
_options: {
|
_options: {
|
||||||
|
@ -242,7 +251,7 @@ if (env('CONSUL_NSPACES_ENABLED')) {
|
||||||
runInDebug(() => {
|
runInDebug(() => {
|
||||||
// check to see if we are running docfy and if so add its routes to our
|
// check to see if we are running docfy and if so add its routes to our
|
||||||
// route config
|
// route config
|
||||||
const docfyOutput = requirejs.entries['consul-ui/docfy-output'];
|
const docfyOutput = requirejs.entries[`${appName}/docfy-output`];
|
||||||
if (typeof docfyOutput !== 'undefined') {
|
if (typeof docfyOutput !== 'undefined') {
|
||||||
const output = {};
|
const output = {};
|
||||||
docfyOutput.callback(output);
|
docfyOutput.callback(output);
|
||||||
|
@ -269,13 +278,6 @@ runInDebug(() => {
|
||||||
})(routes, output.default.nested);
|
})(routes, output.default.nested);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
export default class Router extends EmberRouter {
|
|
||||||
location = env('locationType');
|
|
||||||
rootURL = env('rootURL');
|
|
||||||
}
|
|
||||||
|
|
||||||
Router.map(walk(routes));
|
|
||||||
|
|
||||||
// To print the Ember route DSL use `Routes()` in Web Inspectors console
|
// To print the Ember route DSL use `Routes()` in Web Inspectors console
|
||||||
// or `javascript:Routes()` in the location bar of your browser
|
// or `javascript:Routes()` in the location bar of your browser
|
||||||
runInDebug(() => {
|
runInDebug(() => {
|
||||||
|
@ -295,3 +297,9 @@ runInDebug(() => {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export default class Router extends EmberRouter {
|
||||||
|
location = env('locationType');
|
||||||
|
rootURL = env('rootURL');
|
||||||
|
}
|
||||||
|
Router.map(walk(routes));
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
import Route from 'consul-ui/routing/route';
|
|
||||||
import WithBlockingActions from 'consul-ui/mixins/with-blocking-actions';
|
|
||||||
export default class AclsRoute extends Route.extend(WithBlockingActions) {}
|
|
|
@ -1,39 +0,0 @@
|
||||||
import { inject as service } from '@ember/service';
|
|
||||||
import Route from 'consul-ui/routing/route';
|
|
||||||
import { hash } from 'rsvp';
|
|
||||||
import { get } from '@ember/object';
|
|
||||||
|
|
||||||
import WithAclActions from 'consul-ui/mixins/acl/with-actions';
|
|
||||||
|
|
||||||
export default class CreateRoute extends Route.extend(WithAclActions) {
|
|
||||||
templateName = 'dc/acls/edit';
|
|
||||||
|
|
||||||
@service('repository/acl')
|
|
||||||
repo;
|
|
||||||
|
|
||||||
beforeModel() {
|
|
||||||
this.repo.invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
model(params) {
|
|
||||||
this.item = this.repo.create({
|
|
||||||
Datacenter: this.modelFor('dc').dc.Name,
|
|
||||||
});
|
|
||||||
return hash({
|
|
||||||
create: true,
|
|
||||||
item: this.item,
|
|
||||||
types: ['management', 'client'],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setupController(controller, model) {
|
|
||||||
super.setupController(...arguments);
|
|
||||||
controller.setProperties(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
deactivate() {
|
|
||||||
if (get(this.item, 'isNew')) {
|
|
||||||
this.item.destroyRecord();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
import { inject as service } from '@ember/service';
|
|
||||||
import Route from 'consul-ui/routing/route';
|
|
||||||
import { hash } from 'rsvp';
|
|
||||||
|
|
||||||
import WithAclActions from 'consul-ui/mixins/acl/with-actions';
|
|
||||||
|
|
||||||
export default class EditRoute extends Route.extend(WithAclActions) {
|
|
||||||
@service('repository/acl')
|
|
||||||
repo;
|
|
||||||
|
|
||||||
@service('settings')
|
|
||||||
settings;
|
|
||||||
|
|
||||||
model(params) {
|
|
||||||
return hash({
|
|
||||||
item: this.repo.findBySlug({
|
|
||||||
dc: this.modelFor('dc').dc.Name,
|
|
||||||
id: params.id,
|
|
||||||
}),
|
|
||||||
types: ['management', 'client'],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setupController(controller, model) {
|
|
||||||
super.setupController(...arguments);
|
|
||||||
controller.setProperties(model);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
import { inject as service } from '@ember/service';
|
|
||||||
import Route from 'consul-ui/routing/route';
|
|
||||||
import { get } from '@ember/object';
|
|
||||||
|
|
||||||
import WithAclActions from 'consul-ui/mixins/acl/with-actions';
|
|
||||||
|
|
||||||
export default class IndexRoute extends Route.extend(WithAclActions) {
|
|
||||||
@service('repository/acl') repo;
|
|
||||||
@service('settings') settings;
|
|
||||||
|
|
||||||
queryParams = {
|
|
||||||
sortBy: 'sort',
|
|
||||||
kind: 'kind',
|
|
||||||
search: {
|
|
||||||
as: 'filter',
|
|
||||||
replace: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
async beforeModel(transition) {
|
|
||||||
const token = await this.settings.findBySlug('token');
|
|
||||||
// If you don't have a token set or you have a
|
|
||||||
// token set with AccessorID set to not null (new ACL mode)
|
|
||||||
// then rewrite to the new acls
|
|
||||||
if (!token || get(token, 'AccessorID') !== null) {
|
|
||||||
// If you return here, you get a TransitionAborted error in the tests only
|
|
||||||
// everything works fine either way checking things manually
|
|
||||||
this.replaceWith('dc.acls.tokens');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async model(params) {
|
|
||||||
const _items = this.repo.findAllByDatacenter({ dc: this.modelFor('dc').dc.Name });
|
|
||||||
const _token = this.settings.findBySlug('token');
|
|
||||||
return {
|
|
||||||
items: await _items,
|
|
||||||
token: await _token,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
setupController(controller, model) {
|
|
||||||
super.setupController(...arguments);
|
|
||||||
controller.setProperties(model);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,6 +15,22 @@ export default class BaseRoute extends Route {
|
||||||
@service('repository/permission') permissions;
|
@service('repository/permission') permissions;
|
||||||
@service('router') router;
|
@service('router') router;
|
||||||
|
|
||||||
|
redirect(model, transition) {
|
||||||
|
// remove any references to index as it is the same as the root routeName
|
||||||
|
const routeName = this.routeName
|
||||||
|
.split('.')
|
||||||
|
.filter(item => item !== 'index')
|
||||||
|
.join('.');
|
||||||
|
const to = get(routes, `${routeName}._options.redirect`);
|
||||||
|
if (typeof to !== 'undefined') {
|
||||||
|
// TODO: Does this need to return?
|
||||||
|
// Almost remember things getting strange if you returned from here
|
||||||
|
// which is why I didn't do it originally so be sure to look properly if
|
||||||
|
// you feel like adding a return
|
||||||
|
this.replaceWith(`${routeName}${to}`, model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inspects a custom `abilities` array on the router for this route. Every
|
* Inspects a custom `abilities` array on the router for this route. Every
|
||||||
* abililty needs to 'pass' for the route not to throw a 403 error. Anything
|
* abililty needs to 'pass' for the route not to throw a 403 error. Anything
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
import Serializer from './application';
|
|
||||||
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/acl';
|
|
||||||
|
|
||||||
export default class AclSerializer extends Serializer {
|
|
||||||
primaryKey = PRIMARY_KEY;
|
|
||||||
slugKey = SLUG_KEY;
|
|
||||||
|
|
||||||
respondForQueryRecord(respond, query) {
|
|
||||||
return super.respondForQueryRecord(
|
|
||||||
cb => respond((headers, body) => cb(headers, body[0])),
|
|
||||||
query
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
import Service from '@ember/service';
|
import Service from '@ember/service';
|
||||||
import { andOr } from 'consul-ui/utils/filter';
|
import { andOr } from 'consul-ui/utils/filter';
|
||||||
|
|
||||||
import acl from 'consul-ui/filter/predicates/acl';
|
|
||||||
import service from 'consul-ui/filter/predicates/service';
|
import service from 'consul-ui/filter/predicates/service';
|
||||||
import serviceInstance from 'consul-ui/filter/predicates/service-instance';
|
import serviceInstance from 'consul-ui/filter/predicates/service-instance';
|
||||||
import healthCheck from 'consul-ui/filter/predicates/health-check';
|
import healthCheck from 'consul-ui/filter/predicates/health-check';
|
||||||
|
@ -13,7 +12,6 @@ import policy from 'consul-ui/filter/predicates/policy';
|
||||||
import authMethod from 'consul-ui/filter/predicates/auth-method';
|
import authMethod from 'consul-ui/filter/predicates/auth-method';
|
||||||
|
|
||||||
const predicates = {
|
const predicates = {
|
||||||
acl: andOr(acl),
|
|
||||||
service: andOr(service),
|
service: andOr(service),
|
||||||
['service-instance']: andOr(serviceInstance),
|
['service-instance']: andOr(serviceInstance),
|
||||||
['health-check']: andOr(healthCheck),
|
['health-check']: andOr(healthCheck),
|
||||||
|
|
|
@ -2,7 +2,6 @@ import Service, { inject as service } from '@ember/service';
|
||||||
import builderFactory from 'consul-ui/utils/form/builder';
|
import builderFactory from 'consul-ui/utils/form/builder';
|
||||||
|
|
||||||
import kv from 'consul-ui/forms/kv';
|
import kv from 'consul-ui/forms/kv';
|
||||||
import acl from 'consul-ui/forms/acl';
|
|
||||||
import token from 'consul-ui/forms/token';
|
import token from 'consul-ui/forms/token';
|
||||||
import policy from 'consul-ui/forms/policy';
|
import policy from 'consul-ui/forms/policy';
|
||||||
import role from 'consul-ui/forms/role';
|
import role from 'consul-ui/forms/role';
|
||||||
|
@ -13,7 +12,6 @@ const builder = builderFactory();
|
||||||
|
|
||||||
const forms = {
|
const forms = {
|
||||||
kv: kv,
|
kv: kv,
|
||||||
acl: acl,
|
|
||||||
token: token,
|
token: token,
|
||||||
policy: policy,
|
policy: policy,
|
||||||
role: role,
|
role: role,
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
import RepositoryService from 'consul-ui/services/repository';
|
|
||||||
import { get } from '@ember/object';
|
|
||||||
import { PRIMARY_KEY } from 'consul-ui/models/acl';
|
|
||||||
const modelName = 'acl';
|
|
||||||
export default class AclService extends RepositoryService {
|
|
||||||
getModelName() {
|
|
||||||
return modelName;
|
|
||||||
}
|
|
||||||
|
|
||||||
getPrimaryKey() {
|
|
||||||
return PRIMARY_KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
clone(item) {
|
|
||||||
return this.store.clone(this.getModelName(), get(item, this.getPrimaryKey()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +1,7 @@
|
||||||
import RepositoryService from 'consul-ui/services/repository';
|
import RepositoryService from 'consul-ui/services/repository';
|
||||||
import statusFactory from 'consul-ui/utils/acls-status';
|
|
||||||
import isValidServerErrorFactory from 'consul-ui/utils/http/acl/is-valid-server-error';
|
|
||||||
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/auth-method';
|
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/auth-method';
|
||||||
import dataSource from 'consul-ui/decorators/data-source';
|
import dataSource from 'consul-ui/decorators/data-source';
|
||||||
|
|
||||||
const isValidServerError = isValidServerErrorFactory();
|
|
||||||
const status = statusFactory(isValidServerError, Promise);
|
|
||||||
const MODEL_NAME = 'auth-method';
|
const MODEL_NAME = 'auth-method';
|
||||||
|
|
||||||
export default class AuthMethodService extends RepositoryService {
|
export default class AuthMethodService extends RepositoryService {
|
||||||
|
@ -30,8 +26,4 @@ export default class AuthMethodService extends RepositoryService {
|
||||||
async findBySlug() {
|
async findBySlug() {
|
||||||
return super.findBySlug(...arguments);
|
return super.findBySlug(...arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
status(obj) {
|
|
||||||
return status(obj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
import RepositoryService from 'consul-ui/services/repository';
|
import RepositoryService from 'consul-ui/services/repository';
|
||||||
import statusFactory from 'consul-ui/utils/acls-status';
|
|
||||||
import isValidServerErrorFactory from 'consul-ui/utils/http/acl/is-valid-server-error';
|
|
||||||
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/binding-rule';
|
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/binding-rule';
|
||||||
import dataSource from 'consul-ui/decorators/data-source';
|
import dataSource from 'consul-ui/decorators/data-source';
|
||||||
|
|
||||||
const isValidServerError = isValidServerErrorFactory();
|
|
||||||
const status = statusFactory(isValidServerError, Promise);
|
|
||||||
const MODEL_NAME = 'binding-rule';
|
const MODEL_NAME = 'binding-rule';
|
||||||
|
|
||||||
export default class BindingRuleService extends RepositoryService {
|
export default class BindingRuleService extends RepositoryService {
|
||||||
|
@ -25,8 +21,4 @@ export default class BindingRuleService extends RepositoryService {
|
||||||
async findAllByAuthMethod() {
|
async findAllByAuthMethod() {
|
||||||
return super.findAll(...arguments);
|
return super.findAll(...arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
status(obj) {
|
|
||||||
return status(obj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
import RepositoryService from 'consul-ui/services/repository';
|
import RepositoryService from 'consul-ui/services/repository';
|
||||||
import { get } from '@ember/object';
|
import { get } from '@ember/object';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import statusFactory from 'consul-ui/utils/acls-status';
|
|
||||||
import isValidServerErrorFactory from 'consul-ui/utils/http/acl/is-valid-server-error';
|
|
||||||
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/policy';
|
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/policy';
|
||||||
import dataSource from 'consul-ui/decorators/data-source';
|
import dataSource from 'consul-ui/decorators/data-source';
|
||||||
|
|
||||||
const isValidServerError = isValidServerErrorFactory();
|
|
||||||
const status = statusFactory(isValidServerError, Promise);
|
|
||||||
const MODEL_NAME = 'policy';
|
const MODEL_NAME = 'policy';
|
||||||
|
|
||||||
export default class PolicyService extends RepositoryService {
|
export default class PolicyService extends RepositoryService {
|
||||||
|
@ -47,10 +43,6 @@ export default class PolicyService extends RepositoryService {
|
||||||
.getData();
|
.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
status(obj) {
|
|
||||||
return status(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
persist(item) {
|
persist(item) {
|
||||||
// only if a policy doesn't have a template, save it
|
// only if a policy doesn't have a template, save it
|
||||||
// right now only ServiceIdentities have templates and
|
// right now only ServiceIdentities have templates and
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
import RepositoryService from 'consul-ui/services/repository';
|
import RepositoryService from 'consul-ui/services/repository';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import statusFactory from 'consul-ui/utils/acls-status';
|
|
||||||
import isValidServerErrorFactory from 'consul-ui/utils/http/acl/is-valid-server-error';
|
|
||||||
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/role';
|
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/role';
|
||||||
import dataSource from 'consul-ui/decorators/data-source';
|
import dataSource from 'consul-ui/decorators/data-source';
|
||||||
|
|
||||||
const isValidServerError = isValidServerErrorFactory();
|
|
||||||
const status = statusFactory(isValidServerError, Promise);
|
|
||||||
const MODEL_NAME = 'role';
|
const MODEL_NAME = 'role';
|
||||||
|
|
||||||
export default class RoleService extends RepositoryService {
|
export default class RoleService extends RepositoryService {
|
||||||
|
@ -45,8 +41,4 @@ export default class RoleService extends RepositoryService {
|
||||||
.setData(item)
|
.setData(item)
|
||||||
.getData();
|
.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
status(obj) {
|
|
||||||
return status(obj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,8 @@ import RepositoryService from 'consul-ui/services/repository';
|
||||||
import { get } from '@ember/object';
|
import { get } from '@ember/object';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/token';
|
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/token';
|
||||||
import statusFactory from 'consul-ui/utils/acls-status';
|
|
||||||
import isValidServerErrorFactory from 'consul-ui/utils/http/acl/is-valid-server-error';
|
|
||||||
import dataSource from 'consul-ui/decorators/data-source';
|
import dataSource from 'consul-ui/decorators/data-source';
|
||||||
|
|
||||||
const isValidServerError = isValidServerErrorFactory();
|
|
||||||
const status = statusFactory(isValidServerError, Promise);
|
|
||||||
const MODEL_NAME = 'token';
|
const MODEL_NAME = 'token';
|
||||||
|
|
||||||
export default class TokenService extends RepositoryService {
|
export default class TokenService extends RepositoryService {
|
||||||
|
@ -24,10 +20,6 @@ export default class TokenService extends RepositoryService {
|
||||||
return SLUG_KEY;
|
return SLUG_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
status(obj) {
|
|
||||||
return status(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
@dataSource('/:partition/:ns/:dc/tokens')
|
@dataSource('/:partition/:ns/:dc/tokens')
|
||||||
async findAll() {
|
async findAll() {
|
||||||
return super.findAll(...arguments);
|
return super.findAll(...arguments);
|
||||||
|
@ -53,21 +45,14 @@ export default class TokenService extends RepositoryService {
|
||||||
|
|
||||||
@dataSource('/:partition/:ns/:dc/token/self/:secret')
|
@dataSource('/:partition/:ns/:dc/token/self/:secret')
|
||||||
self(params) {
|
self(params) {
|
||||||
// TODO: Does this need ns passing through?
|
// This request does not need ns or partition passing through as its
|
||||||
|
// inferred from the token itself.
|
||||||
return this.store
|
return this.store
|
||||||
.self(this.getModelName(), {
|
.self(this.getModelName(), {
|
||||||
secret: params.secret,
|
secret: params.secret,
|
||||||
dc: params.dc,
|
dc: params.dc,
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
// If we get this 500 RPC error, it means we are a legacy ACL cluster
|
|
||||||
// set AccessorID to null - which for the frontend means legacy mode
|
|
||||||
if (isValidServerError(e)) {
|
|
||||||
return {
|
|
||||||
AccessorID: null,
|
|
||||||
SecretID: params.secret,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return Promise.reject(e);
|
return Promise.reject(e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ import Service from '@ember/service';
|
||||||
import service from 'consul-ui/sort/comparators/service';
|
import service from 'consul-ui/sort/comparators/service';
|
||||||
import serviceInstance from 'consul-ui/sort/comparators/service-instance';
|
import serviceInstance from 'consul-ui/sort/comparators/service-instance';
|
||||||
import upstreamInstance from 'consul-ui/sort/comparators/upstream-instance';
|
import upstreamInstance from 'consul-ui/sort/comparators/upstream-instance';
|
||||||
import acl from 'consul-ui/sort/comparators/acl';
|
|
||||||
import kv from 'consul-ui/sort/comparators/kv';
|
import kv from 'consul-ui/sort/comparators/kv';
|
||||||
import healthCheck from 'consul-ui/sort/comparators/health-check';
|
import healthCheck from 'consul-ui/sort/comparators/health-check';
|
||||||
import intention from 'consul-ui/sort/comparators/intention';
|
import intention from 'consul-ui/sort/comparators/intention';
|
||||||
|
@ -34,7 +33,6 @@ const comparators = {
|
||||||
['upstream-instance']: upstreamInstance(options),
|
['upstream-instance']: upstreamInstance(options),
|
||||||
['health-check']: healthCheck(options),
|
['health-check']: healthCheck(options),
|
||||||
['auth-method']: authMethod(options),
|
['auth-method']: authMethod(options),
|
||||||
acl: acl(options),
|
|
||||||
kv: kv(options),
|
kv: kv(options),
|
||||||
intention: intention(options),
|
intention: intention(options),
|
||||||
token: token(options),
|
token: token(options),
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
export default ({ properties }) => (key = 'Name:asc') => {
|
|
||||||
return properties(['Name'])(key);
|
|
||||||
};
|
|
|
@ -1,51 +0,0 @@
|
||||||
<form>
|
|
||||||
<fieldset
|
|
||||||
disabled={{if (not (can "write acl" item=item)) "disabled"}}
|
|
||||||
>
|
|
||||||
<label class="type-text{{if item.error.Name ' has-error'}}">
|
|
||||||
<span>Name</span>
|
|
||||||
<Input @value={{item.Name}} @name="name" @autofocus="autofocus" />
|
|
||||||
</label>
|
|
||||||
<div role="radiogroup" class={{if item.error.Type ' has-error'}}>
|
|
||||||
{{#each types as |type|}}
|
|
||||||
<label>
|
|
||||||
<span>{{capitalize type}}</span>
|
|
||||||
<input type="radio" name="Type" value="{{type}}" checked={{if (eq item.Type type) 'checked'}} onchange={{ action 'change' }}/>
|
|
||||||
</label>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
<label class="type-text">
|
|
||||||
<span>Policy <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a></span>
|
|
||||||
<CodeEditor @class={{if item.error.Rules "error"}} @name="Rules" @value={{item.Rules}} @syntax="hcl" @onkeyup={{action "change" "Rules"}} />
|
|
||||||
</label>
|
|
||||||
{{#if create }}
|
|
||||||
<label class="type-text">
|
|
||||||
<span>ID</span>
|
|
||||||
<Input @value={{item.ID}} />
|
|
||||||
<em>We'll generate a UUID if this field is left empty.</em>
|
|
||||||
</label>
|
|
||||||
{{/if}}
|
|
||||||
</fieldset>
|
|
||||||
<div>
|
|
||||||
{{#if (and create (can "create acls")) }}
|
|
||||||
{{! we only need to check for an empty name here as ember munges autofocus, once we have autofocus back revisit this}}
|
|
||||||
<button type="submit" {{ action "create" item}} disabled={{if (or item.isPristine item.isInvalid (eq item.Name '')) 'disabled'}}>Save</button>
|
|
||||||
{{else}}
|
|
||||||
{{#if (can "write acl" item=item)}}
|
|
||||||
<button type="submit" {{ action "update" item}} disabled={{if item.isInvalid 'disabled'}}>Save</button>
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
<button type="reset" {{ action "cancel" item}}>Cancel</button>
|
|
||||||
{{# if (and (not create) (can "delete acl" item=item) ) }}
|
|
||||||
<ConfirmationDialog @message="Are you sure you want to delete this ACL token?">
|
|
||||||
<BlockSlot @name="action" as |confirm|>
|
|
||||||
<button type="button" data-test-delete class="type-delete" {{action confirm 'delete' item parent}}>Delete</button>
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="dialog" as |execute cancel message|>
|
|
||||||
<DeleteConfirmation @message={{message}} @execute={{execute}} @cancel={{cancel}} />
|
|
||||||
</BlockSlot>
|
|
||||||
</ConfirmationDialog>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
<Route
|
|
||||||
@name={{routeName}}
|
|
||||||
@title={{if create 'New ACL' 'Edit ACL'}}
|
|
||||||
as |route|>
|
|
||||||
<AppView>
|
|
||||||
<BlockSlot @name="notification" as |status type item error|>
|
|
||||||
<Consul::Acl::Notifications
|
|
||||||
@status={{status}}
|
|
||||||
@type={{type}}
|
|
||||||
@error={{error}}
|
|
||||||
/>
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="breadcrumbs">
|
|
||||||
<ol>
|
|
||||||
<li><a data-test-back href={{href-to 'dc.acls'}}>All Tokens</a></li>
|
|
||||||
</ol>
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="header">
|
|
||||||
<h1>
|
|
||||||
{{#if item.Name }}
|
|
||||||
{{item.Name}}
|
|
||||||
{{else}}
|
|
||||||
New token
|
|
||||||
{{/if}}
|
|
||||||
</h1>
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="actions">
|
|
||||||
{{#if (not create) }}
|
|
||||||
<CopyButton @value={{item.ID}} @name="token ID">
|
|
||||||
Copy token ID
|
|
||||||
</CopyButton>
|
|
||||||
{{#if (can "duplicate acl" item=item)}}
|
|
||||||
<button type="button" {{ action "clone" item }}>Clone token</button>
|
|
||||||
<ConfirmationDialog @message="Are you sure you want to use this ACL token?">
|
|
||||||
<BlockSlot @name="action" as |confirm|>
|
|
||||||
<button data-test-use type="button" {{ action confirm 'use' item }}>Use token</button>
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="dialog" as |execute cancel message|>
|
|
||||||
<p>
|
|
||||||
{{message}}
|
|
||||||
</p>
|
|
||||||
<button type="button" class="type-delete" {{action execute}}>Confirm Use</button>
|
|
||||||
<button type="button" class="type-cancel" {{action cancel}}>Cancel</button>
|
|
||||||
</BlockSlot>
|
|
||||||
</ConfirmationDialog>
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="content">
|
|
||||||
{{ partial 'dc/acls/form'}}
|
|
||||||
</BlockSlot>
|
|
||||||
</AppView>
|
|
||||||
</Route>
|
|
|
@ -1,101 +1,5 @@
|
||||||
<Route
|
<Route
|
||||||
@name={{routeName}}
|
@name={{routeName}}
|
||||||
@title="ACLs"
|
|
||||||
as |route|>
|
as |route|>
|
||||||
{{#let
|
{{did-insert (route-action 'replaceWith' 'dc.acls.tokens')}}
|
||||||
|
|
||||||
(hash
|
|
||||||
value=(or sortBy "Name:asc")
|
|
||||||
change=(action (mut sortBy) value="target.selected")
|
|
||||||
)
|
|
||||||
|
|
||||||
(hash
|
|
||||||
kind=(hash
|
|
||||||
value=(if kind (split kind ',') undefined)
|
|
||||||
change=(action (mut kind) value="target.selectedItems")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
items
|
|
||||||
|
|
||||||
as |sort filters items|}}
|
|
||||||
|
|
||||||
<AppView>
|
|
||||||
<BlockSlot @name="notification" as |status type item error|>
|
|
||||||
<Consul::Acl::Notifications
|
|
||||||
@status={{status}}
|
|
||||||
@type={{type}}
|
|
||||||
@error={{error}}
|
|
||||||
/>
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="header">
|
|
||||||
<h1>
|
|
||||||
ACL Tokens <em>{{format-number items.length}} total</em>
|
|
||||||
</h1>
|
|
||||||
<label for="toolbar-toggle"></label>
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="actions">
|
|
||||||
{{#if (can "create acls")}}
|
|
||||||
<a data-test-create href="{{href-to 'dc.acls.create'}}" class="type-create">Create</a>
|
|
||||||
{{/if}}
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="toolbar">
|
|
||||||
{{#if (gt items.length 0) }}
|
|
||||||
<Consul::Acl::SearchBar
|
|
||||||
@search={{search}}
|
|
||||||
@onsearch={{action (mut search) value="target.value"}}
|
|
||||||
|
|
||||||
@sort={{sort}}
|
|
||||||
|
|
||||||
@filter={{filters}}
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="content">
|
|
||||||
<DataCollection
|
|
||||||
@type="acl"
|
|
||||||
@sort={{sort.value}}
|
|
||||||
@filters={{filters}}
|
|
||||||
@search={{search}}
|
|
||||||
@items={{items}}
|
|
||||||
as |collection|>
|
|
||||||
<collection.Collection>
|
|
||||||
<Consul::Acl::List
|
|
||||||
@items={{collection.items}}
|
|
||||||
|
|
||||||
@ondelete={{route-action 'delete'}}
|
|
||||||
@onuse={{route-action 'use'}}
|
|
||||||
@onclone={{route-action 'clone'}}
|
|
||||||
>
|
|
||||||
</Consul::Acl::List>
|
|
||||||
</collection.Collection>
|
|
||||||
<collection.Empty>
|
|
||||||
<EmptyState
|
|
||||||
@login={{route.model.app.login.open}}
|
|
||||||
>
|
|
||||||
<BlockSlot @name="header">
|
|
||||||
<h2>
|
|
||||||
{{#if (gt items.length 0)}}
|
|
||||||
No ACLs found
|
|
||||||
{{else}}
|
|
||||||
Welcome to ACLs
|
|
||||||
{{/if}}
|
|
||||||
</h2>
|
|
||||||
</BlockSlot>
|
|
||||||
<BlockSlot @name="body">
|
|
||||||
<p>
|
|
||||||
{{#if (gt items.length 0)}}
|
|
||||||
No ACLs where found matching that search, or you may not have access to view the ACLs you are searching for.
|
|
||||||
{{else}}
|
|
||||||
There don't seem to be any ACLs yet, or you may not have access to view ACLs yet.
|
|
||||||
{{/if}}
|
|
||||||
</p>
|
|
||||||
</BlockSlot>
|
|
||||||
</EmptyState>
|
|
||||||
</collection.Empty>
|
|
||||||
</DataCollection>
|
|
||||||
</BlockSlot>
|
|
||||||
</AppView>
|
|
||||||
|
|
||||||
{{/let}}
|
|
||||||
</Route>
|
</Route>
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
// This is used by all acl routes to check whether
|
|
||||||
// acls are enabled on the server, and whether the user
|
|
||||||
// has a valid token
|
|
||||||
// Right now this is very acl specific, but is likely to be
|
|
||||||
// made a bit more less specific
|
|
||||||
|
|
||||||
export default function(isValidServerError, P = Promise) {
|
|
||||||
return function(obj) {
|
|
||||||
const propName = Object.keys(obj)[0];
|
|
||||||
const p = obj[propName];
|
|
||||||
let authorize;
|
|
||||||
let enable;
|
|
||||||
return {
|
|
||||||
isAuthorized: new P(function(resolve) {
|
|
||||||
authorize = function(bool) {
|
|
||||||
resolve(bool);
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
isEnabled: new P(function(resolve) {
|
|
||||||
enable = function(bool) {
|
|
||||||
resolve(bool);
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
[propName]: p
|
|
||||||
.catch(function(e) {
|
|
||||||
if (e.errors && e.errors[0]) {
|
|
||||||
switch (e.errors[0].status) {
|
|
||||||
case '500':
|
|
||||||
if (isValidServerError(e)) {
|
|
||||||
enable(true);
|
|
||||||
authorize(false);
|
|
||||||
} else {
|
|
||||||
enable(false);
|
|
||||||
authorize(false);
|
|
||||||
return P.reject(e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '403':
|
|
||||||
enable(true);
|
|
||||||
authorize(false);
|
|
||||||
break;
|
|
||||||
case '401':
|
|
||||||
enable(false);
|
|
||||||
authorize(false);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
enable(false);
|
|
||||||
authorize(false);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
enable(false);
|
|
||||||
authorize(false);
|
|
||||||
throw e;
|
|
||||||
})
|
|
||||||
.then(function(res) {
|
|
||||||
enable(true);
|
|
||||||
authorize(true);
|
|
||||||
return res;
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
// very specific error check just for one specific ACL case
|
|
||||||
// likely to be reused at a later date, so lets use the specific
|
|
||||||
// case we need right now as default
|
|
||||||
const UNKNOWN_METHOD_ERROR = "rpc error making call: rpc: can't find method ACL";
|
|
||||||
export default function(response = UNKNOWN_METHOD_ERROR) {
|
|
||||||
return function(e) {
|
|
||||||
if (e && e.errors && e.errors[0] && e.errors[0].detail) {
|
|
||||||
return e.errors[0].detail.indexOf(response) !== -1;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
import { validatePresence, validateLength } from 'ember-changeset-validations/validators';
|
|
||||||
export default {
|
|
||||||
Name: [validatePresence(true), validateLength({ min: 1 })],
|
|
||||||
Type: validatePresence(true),
|
|
||||||
};
|
|
|
@ -163,6 +163,9 @@ module.exports = function(defaults, $ = process.env) {
|
||||||
app.import('vendor/metrics-providers/prometheus.js', {
|
app.import('vendor/metrics-providers/prometheus.js', {
|
||||||
outputFile: 'assets/metrics-providers/prometheus.js',
|
outputFile: 'assets/metrics-providers/prometheus.js',
|
||||||
});
|
});
|
||||||
|
app.import('vendor/acls/routes.js', {
|
||||||
|
outputFile: 'assets/acls/routes.js',
|
||||||
|
});
|
||||||
app.import('vendor/init.js', {
|
app.import('vendor/init.js', {
|
||||||
outputFile: 'assets/init.js',
|
outputFile: 'assets/init.js',
|
||||||
});
|
});
|
||||||
|
|
|
@ -41,6 +41,26 @@ ${environment === 'production' ? `{{jsonEncode .}}` : JSON.stringify(config.oper
|
||||||
"codemirror/mode/yaml/yaml.js": "${rootURL}assets/codemirror/mode/yaml/yaml.js"
|
"codemirror/mode/yaml/yaml.js": "${rootURL}assets/codemirror/mode/yaml/yaml.js"
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
${
|
||||||
|
environment === 'production'
|
||||||
|
? `
|
||||||
|
{{if .ACLsEnabled}}
|
||||||
|
<script data-${appName}-routing src="${rootURL}assets/acls/routes.js"></script>
|
||||||
|
{{end}}
|
||||||
|
`
|
||||||
|
: `
|
||||||
|
<script>
|
||||||
|
if(document.cookie['CONSUL_ACLS_ENABLED']) {
|
||||||
|
const appName = '${appName}';
|
||||||
|
const appNameJS = appName.split('-').map((item, i) => i ? \`\${item.substr(0, 1).toUpperCase()}\${item.substr(1)}\` : item).join('');
|
||||||
|
const $script = document.createElement('script');
|
||||||
|
$script.setAttribute('src', '${rootURL}assets/acls/routes.js');
|
||||||
|
$script.dataset[\`\${appNameJS}Routes\`] = null;
|
||||||
|
document.body.appendChild($script);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
`
|
||||||
|
}
|
||||||
<script src="${rootURL}assets/init.js"></script>
|
<script src="${rootURL}assets/init.js"></script>
|
||||||
<script src="${rootURL}assets/vendor.js"></script>
|
<script src="${rootURL}assets/vendor.js"></script>
|
||||||
${environment === 'test' ? `<script src="${rootURL}assets/test-support.js"></script>` : ``}
|
${environment === 'test' ? `<script src="${rootURL}assets/test-support.js"></script>` : ``}
|
||||||
|
|
|
@ -85,6 +85,7 @@
|
||||||
"d3-selection": "^2.0.0",
|
"d3-selection": "^2.0.0",
|
||||||
"d3-shape": "^2.0.0",
|
"d3-shape": "^2.0.0",
|
||||||
"dayjs": "^1.9.3",
|
"dayjs": "^1.9.3",
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
"ember-assign-helper": "^0.3.0",
|
"ember-assign-helper": "^0.3.0",
|
||||||
"ember-auto-import": "^1.5.3",
|
"ember-auto-import": "^1.5.3",
|
||||||
"ember-can": "^3.0.0",
|
"ember-can": "^3.0.0",
|
||||||
|
|
|
@ -29,7 +29,7 @@ module.exports = function(app, options) {
|
||||||
// sets the base CSP policy for the UI
|
// sets the base CSP policy for the UI
|
||||||
app.use(function(request, response, next) {
|
app.use(function(request, response, next) {
|
||||||
response.set({
|
response.set({
|
||||||
'Content-Security-Policy': `default-src 'self' ws: localhost:${options.liveReloadPort} http: localhost:${options.liveReloadPort}; img-src 'self' data: ; style-src 'self' 'unsafe-inline'`,
|
'Content-Security-Policy': `default-src 'self' 'unsafe-inline' ws: localhost:${options.liveReloadPort} http: localhost:${options.liveReloadPort}; img-src 'self' data: ; style-src 'self' 'unsafe-inline'`,
|
||||||
});
|
});
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,106 +0,0 @@
|
||||||
import { module, test } from 'qunit';
|
|
||||||
import { setupTest } from 'ember-qunit';
|
|
||||||
module('Integration | Adapter | acl', function(hooks) {
|
|
||||||
setupTest(hooks);
|
|
||||||
const dc = 'dc-1';
|
|
||||||
const id = 'token-name';
|
|
||||||
test('requestForQuery returns the correct url', function(assert) {
|
|
||||||
const adapter = this.owner.lookup('adapter:acl');
|
|
||||||
const client = this.owner.lookup('service:client/http');
|
|
||||||
const request = client.url.bind(client);
|
|
||||||
const expected = `GET /v1/acl/list?dc=${dc}`;
|
|
||||||
const actual = adapter.requestForQuery(request, {
|
|
||||||
dc: dc,
|
|
||||||
});
|
|
||||||
assert.equal(actual, expected);
|
|
||||||
});
|
|
||||||
test('requestForQueryRecord returns the correct url', function(assert) {
|
|
||||||
const adapter = this.owner.lookup('adapter:acl');
|
|
||||||
const client = this.owner.lookup('service:client/http');
|
|
||||||
const request = client.url.bind(client);
|
|
||||||
const expected = `GET /v1/acl/info/${id}?dc=${dc}`;
|
|
||||||
const actual = adapter.requestForQueryRecord(request, {
|
|
||||||
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:acl');
|
|
||||||
const client = this.owner.lookup('service:client/http');
|
|
||||||
const request = client.url.bind(client);
|
|
||||||
assert.throws(function() {
|
|
||||||
adapter.requestForQueryRecord(request, {
|
|
||||||
dc: dc,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
test('requestForCreateRecord returns the correct url', function(assert) {
|
|
||||||
const adapter = this.owner.lookup('adapter:acl');
|
|
||||||
const client = this.owner.lookup('service:client/http');
|
|
||||||
const request = client.url.bind(client);
|
|
||||||
const expected = `PUT /v1/acl/create?dc=${dc}`;
|
|
||||||
const actual = adapter
|
|
||||||
.requestForCreateRecord(
|
|
||||||
request,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
Datacenter: dc,
|
|
||||||
ID: id,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.split('\n')[0];
|
|
||||||
assert.equal(actual, expected);
|
|
||||||
});
|
|
||||||
test('requestForUpdateRecord returns the correct url', function(assert) {
|
|
||||||
const adapter = this.owner.lookup('adapter:acl');
|
|
||||||
const client = this.owner.lookup('service:client/http');
|
|
||||||
const request = client.url.bind(client);
|
|
||||||
const expected = `PUT /v1/acl/update?dc=${dc}`;
|
|
||||||
const actual = adapter
|
|
||||||
.requestForUpdateRecord(
|
|
||||||
request,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
Datacenter: dc,
|
|
||||||
ID: id,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.split('\n')[0];
|
|
||||||
assert.equal(actual, expected);
|
|
||||||
});
|
|
||||||
test('requestForDeleteRecord returns the correct url', function(assert) {
|
|
||||||
const adapter = this.owner.lookup('adapter:acl');
|
|
||||||
const client = this.owner.lookup('service:client/http');
|
|
||||||
const request = client.url.bind(client);
|
|
||||||
const expected = `PUT /v1/acl/destroy/${id}?dc=${dc}`;
|
|
||||||
const actual = adapter
|
|
||||||
.requestForDeleteRecord(
|
|
||||||
request,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
Datacenter: dc,
|
|
||||||
ID: id,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.split('/n')[0];
|
|
||||||
assert.equal(actual, expected);
|
|
||||||
});
|
|
||||||
test('requestForCloneRecord returns the correct url', function(assert) {
|
|
||||||
const adapter = this.owner.lookup('adapter:acl');
|
|
||||||
const client = this.owner.lookup('service:client/http');
|
|
||||||
const request = client.url.bind(client);
|
|
||||||
const expected = `PUT /v1/acl/clone/${id}?dc=${dc}`;
|
|
||||||
const actual = adapter
|
|
||||||
.requestForCloneRecord(
|
|
||||||
request,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
Datacenter: dc,
|
|
||||||
ID: id,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.split('\n')[0];
|
|
||||||
assert.equal(actual, expected);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,12 +0,0 @@
|
||||||
import { module, test } from 'qunit';
|
|
||||||
import { setupTest } from 'ember-qunit';
|
|
||||||
|
|
||||||
module('Unit | Adapter | acl', function(hooks) {
|
|
||||||
setupTest(hooks);
|
|
||||||
|
|
||||||
// Replace this with your real tests.
|
|
||||||
test('it exists', function(assert) {
|
|
||||||
let adapter = this.owner.lookup('adapter:acl');
|
|
||||||
assert.ok(adapter);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,12 +0,0 @@
|
||||||
import { module, test } from 'qunit';
|
|
||||||
import { setupTest } from 'ember-qunit';
|
|
||||||
|
|
||||||
module('Unit | Controller | dc/acls/create', function(hooks) {
|
|
||||||
setupTest(hooks);
|
|
||||||
|
|
||||||
// Replace this with your real tests.
|
|
||||||
test('it exists', function(assert) {
|
|
||||||
let controller = this.owner.lookup('controller:dc/acls/create');
|
|
||||||
assert.ok(controller);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,12 +0,0 @@
|
||||||
import { module, test } from 'qunit';
|
|
||||||
import { setupTest } from 'ember-qunit';
|
|
||||||
|
|
||||||
module('Unit | Controller | dc/acls/edit', function(hooks) {
|
|
||||||
setupTest(hooks);
|
|
||||||
|
|
||||||
// Replace this with your real tests.
|
|
||||||
test('it exists', function(assert) {
|
|
||||||
let controller = this.owner.lookup('controller:dc/acls/edit');
|
|
||||||
assert.ok(controller);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,75 +0,0 @@
|
||||||
import { module } from 'qunit';
|
|
||||||
import { setupTest } from 'ember-qunit';
|
|
||||||
import test from 'ember-sinon-qunit/test-support/test';
|
|
||||||
import Service from '@ember/service';
|
|
||||||
import Route from 'consul-ui/routes/dc/acls/index';
|
|
||||||
|
|
||||||
import Mixin from 'consul-ui/mixins/acl/with-actions';
|
|
||||||
|
|
||||||
module('Unit | Mixin | acl/with actions', function(hooks) {
|
|
||||||
setupTest(hooks);
|
|
||||||
|
|
||||||
hooks.beforeEach(function() {
|
|
||||||
this.subject = function() {
|
|
||||||
const MixedIn = Route.extend(Mixin);
|
|
||||||
this.owner.register('test-container:acl/with-actions-object', MixedIn);
|
|
||||||
return this.owner.lookup('test-container:acl/with-actions-object');
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Replace this with your real tests.
|
|
||||||
test('it works', function(assert) {
|
|
||||||
const subject = this.subject();
|
|
||||||
assert.ok(subject);
|
|
||||||
});
|
|
||||||
test('use persists the token', function(assert) {
|
|
||||||
assert.expect(2);
|
|
||||||
const item = { ID: 'id' };
|
|
||||||
const expected = { Namespace: 'default', AccessorID: null, SecretID: item.ID };
|
|
||||||
this.owner.register(
|
|
||||||
'service:settings',
|
|
||||||
Service.extend({
|
|
||||||
persist: function(actual) {
|
|
||||||
assert.deepEqual(actual.token, expected);
|
|
||||||
return Promise.resolve(actual);
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
const subject = this.subject();
|
|
||||||
return subject.actions.use
|
|
||||||
.bind(subject)(item)
|
|
||||||
.then(function(actual) {
|
|
||||||
assert.deepEqual(actual.token, expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
test('clone clones the token and calls afterDelete correctly', function(assert) {
|
|
||||||
assert.expect(4);
|
|
||||||
this.owner.register(
|
|
||||||
'service:feedback',
|
|
||||||
Service.extend({
|
|
||||||
execute: function(cb, name) {
|
|
||||||
assert.equal(name, 'clone');
|
|
||||||
return cb();
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
const expected = { ID: 'id' };
|
|
||||||
this.owner.register(
|
|
||||||
'service:repository/acl',
|
|
||||||
Service.extend({
|
|
||||||
clone: function(actual) {
|
|
||||||
assert.deepEqual(actual, expected);
|
|
||||||
return Promise.resolve(actual);
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
const subject = this.subject();
|
|
||||||
const afterDelete = this.stub(subject, 'afterDelete').returnsArg(0);
|
|
||||||
return subject.actions.clone
|
|
||||||
.bind(subject)(expected)
|
|
||||||
.then(function(actual) {
|
|
||||||
assert.ok(afterDelete.calledOnce);
|
|
||||||
assert.equal(actual, expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,14 +0,0 @@
|
||||||
import { module, test } from 'qunit';
|
|
||||||
import { setupTest } from 'ember-qunit';
|
|
||||||
import { run } from '@ember/runloop';
|
|
||||||
|
|
||||||
module('Unit | Model | acl', function(hooks) {
|
|
||||||
setupTest(hooks);
|
|
||||||
|
|
||||||
// Replace this with your real tests.
|
|
||||||
test('it exists', function(assert) {
|
|
||||||
let store = this.owner.lookup('service:store');
|
|
||||||
let model = run(() => store.createRecord('acl', {}));
|
|
||||||
assert.ok(model);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,11 +0,0 @@
|
||||||
import { module, test } from 'qunit';
|
|
||||||
import { setupTest } from 'ember-qunit';
|
|
||||||
|
|
||||||
module('Unit | Route | dc/acls', function(hooks) {
|
|
||||||
setupTest(hooks);
|
|
||||||
|
|
||||||
test('it exists', function(assert) {
|
|
||||||
let route = this.owner.lookup('route:dc/acls');
|
|
||||||
assert.ok(route);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,11 +0,0 @@
|
||||||
import { module, test } from 'qunit';
|
|
||||||
import { setupTest } from 'ember-qunit';
|
|
||||||
|
|
||||||
module('Unit | Route | dc/acls/create', function(hooks) {
|
|
||||||
setupTest(hooks);
|
|
||||||
|
|
||||||
test('it exists', function(assert) {
|
|
||||||
let route = this.owner.lookup('route:dc/acls/create');
|
|
||||||
assert.ok(route);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,11 +0,0 @@
|
||||||
import { module, test } from 'qunit';
|
|
||||||
import { setupTest } from 'ember-qunit';
|
|
||||||
|
|
||||||
module('Unit | Route | dc/acls/edit', function(hooks) {
|
|
||||||
setupTest(hooks);
|
|
||||||
|
|
||||||
test('it exists', function(assert) {
|
|
||||||
let route = this.owner.lookup('route:dc/acls/edit');
|
|
||||||
assert.ok(route);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,11 +0,0 @@
|
||||||
import { module, test } from 'qunit';
|
|
||||||
import { setupTest } from 'ember-qunit';
|
|
||||||
|
|
||||||
module('Unit | Route | dc/acls/index', function(hooks) {
|
|
||||||
setupTest(hooks);
|
|
||||||
|
|
||||||
test('it exists', function(assert) {
|
|
||||||
let route = this.owner.lookup('route:dc/acls/index');
|
|
||||||
assert.ok(route);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,43 +0,0 @@
|
||||||
import { module, test } from 'qunit';
|
|
||||||
|
|
||||||
import ExactSearch from 'consul-ui/utils/search/exact';
|
|
||||||
import predicates from 'consul-ui/search/predicates/acl';
|
|
||||||
|
|
||||||
module('Unit | Search | Predicate | acl', function() {
|
|
||||||
test('items are found by properties', function(assert) {
|
|
||||||
const actual = new ExactSearch(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
ID: 'HIT-id',
|
|
||||||
Name: 'name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: 'id',
|
|
||||||
Name: 'name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: 'id',
|
|
||||||
Name: 'name-HIT',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
{
|
|
||||||
finders: predicates,
|
|
||||||
}
|
|
||||||
).search('hit');
|
|
||||||
assert.equal(actual.length, 2);
|
|
||||||
});
|
|
||||||
test('items are not found', function(assert) {
|
|
||||||
const actual = new ExactSearch(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
ID: 'id',
|
|
||||||
Name: 'name',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
{
|
|
||||||
finders: predicates,
|
|
||||||
}
|
|
||||||
).search('hit');
|
|
||||||
assert.equal(actual.length, 0);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,24 +0,0 @@
|
||||||
import { module, test } from 'qunit';
|
|
||||||
import { setupTest } from 'ember-qunit';
|
|
||||||
import { run } from '@ember/runloop';
|
|
||||||
|
|
||||||
module('Unit | Serializer | acl', 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('acl');
|
|
||||||
|
|
||||||
assert.ok(serializer);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('it serializes records', function(assert) {
|
|
||||||
let store = this.owner.lookup('service:store');
|
|
||||||
let record = run(() => store.createRecord('acl', {}));
|
|
||||||
|
|
||||||
let serializedRecord = record.serialize();
|
|
||||||
|
|
||||||
assert.ok(serializedRecord);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,12 +0,0 @@
|
||||||
import { module, test } from 'qunit';
|
|
||||||
import { setupTest } from 'ember-qunit';
|
|
||||||
|
|
||||||
module('Unit | Service | acl', function(hooks) {
|
|
||||||
setupTest(hooks);
|
|
||||||
|
|
||||||
// Replace this with your real tests.
|
|
||||||
test('it exists', function(assert) {
|
|
||||||
let service = this.owner.lookup('service:repository/acl');
|
|
||||||
assert.ok(service);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,89 +0,0 @@
|
||||||
import { module } from 'qunit';
|
|
||||||
import test from 'ember-sinon-qunit/test-support/test';
|
|
||||||
import aclsStatus from 'consul-ui/utils/acls-status';
|
|
||||||
|
|
||||||
module('Unit | Utility | acls status', function() {
|
|
||||||
test('it rejects and nothing is enabled or authorized', function(assert) {
|
|
||||||
const isValidServerError = this.stub().returns(false);
|
|
||||||
const status = aclsStatus(isValidServerError);
|
|
||||||
[
|
|
||||||
this.stub().rejects(),
|
|
||||||
this.stub().rejects({ errors: [] }),
|
|
||||||
this.stub().rejects({ errors: [{ status: '404' }] }),
|
|
||||||
].forEach(function(reject) {
|
|
||||||
const actual = status({
|
|
||||||
response: reject(),
|
|
||||||
});
|
|
||||||
assert.rejects(actual.response);
|
|
||||||
['isAuthorized', 'isEnabled'].forEach(function(prop) {
|
|
||||||
actual[prop].then(function(actual) {
|
|
||||||
assert.notOk(actual);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
test('with a 401 it resolves with an empty array and nothing is enabled or authorized', function(assert) {
|
|
||||||
assert.expect(3);
|
|
||||||
const isValidServerError = this.stub().returns(false);
|
|
||||||
const status = aclsStatus(isValidServerError);
|
|
||||||
const actual = status({
|
|
||||||
response: this.stub().rejects({ errors: [{ status: '401' }] })(),
|
|
||||||
});
|
|
||||||
actual.response.then(function(actual) {
|
|
||||||
assert.deepEqual(actual, []);
|
|
||||||
});
|
|
||||||
['isAuthorized', 'isEnabled'].forEach(function(prop) {
|
|
||||||
actual[prop].then(function(actual) {
|
|
||||||
assert.notOk(actual);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
test("with a 403 it resolves with an empty array and it's enabled but not authorized", function(assert) {
|
|
||||||
assert.expect(3);
|
|
||||||
const isValidServerError = this.stub().returns(false);
|
|
||||||
const status = aclsStatus(isValidServerError);
|
|
||||||
const actual = status({
|
|
||||||
response: this.stub().rejects({ errors: [{ status: '403' }] })(),
|
|
||||||
});
|
|
||||||
actual.response.then(function(actual) {
|
|
||||||
assert.deepEqual(actual, []);
|
|
||||||
});
|
|
||||||
actual.isEnabled.then(function(actual) {
|
|
||||||
assert.ok(actual);
|
|
||||||
});
|
|
||||||
actual.isAuthorized.then(function(actual) {
|
|
||||||
assert.notOk(actual);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
test("with a 500 (but not a 'valid' error) it rejects and nothing is enabled or authorized", function(assert) {
|
|
||||||
assert.expect(3);
|
|
||||||
const isValidServerError = this.stub().returns(false);
|
|
||||||
const status = aclsStatus(isValidServerError);
|
|
||||||
const actual = status({
|
|
||||||
response: this.stub().rejects({ errors: [{ status: '500' }] })(),
|
|
||||||
});
|
|
||||||
assert.rejects(actual.response);
|
|
||||||
['isAuthorized', 'isEnabled'].forEach(function(prop) {
|
|
||||||
actual[prop].then(function(actual) {
|
|
||||||
assert.notOk(actual);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
test("with a 500 and a 'valid' error, it resolves with an empty array and it's enabled but not authorized", function(assert) {
|
|
||||||
assert.expect(3);
|
|
||||||
const isValidServerError = this.stub().returns(true);
|
|
||||||
const status = aclsStatus(isValidServerError);
|
|
||||||
const actual = status({
|
|
||||||
response: this.stub().rejects({ errors: [{ status: '500' }] })(),
|
|
||||||
});
|
|
||||||
actual.response.then(function(actual) {
|
|
||||||
assert.deepEqual(actual, []);
|
|
||||||
});
|
|
||||||
actual.isEnabled.then(function(actual) {
|
|
||||||
assert.ok(actual);
|
|
||||||
});
|
|
||||||
actual.isAuthorized.then(function(actual) {
|
|
||||||
assert.notOk(actual);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,49 +0,0 @@
|
||||||
import createIsValidServerError from 'consul-ui/utils/http/acl/is-valid-server-error';
|
|
||||||
import { module, test } from 'qunit';
|
|
||||||
|
|
||||||
module('Unit | Utility | http/acl/is valid server error', function() {
|
|
||||||
const createEmberDataError = function(response) {
|
|
||||||
return {
|
|
||||||
errors: [
|
|
||||||
{
|
|
||||||
detail: response,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
};
|
|
||||||
test('it returns a function', function(assert) {
|
|
||||||
const isValidServerError = createIsValidServerError();
|
|
||||||
assert.ok(typeof isValidServerError === 'function');
|
|
||||||
});
|
|
||||||
test("it returns false if there is no 'correctly' formatted error", function(assert) {
|
|
||||||
const isValidServerError = createIsValidServerError();
|
|
||||||
assert.notOk(isValidServerError());
|
|
||||||
assert.notOk(isValidServerError({}));
|
|
||||||
assert.notOk(isValidServerError({ errors: {} }));
|
|
||||||
assert.notOk(isValidServerError({ errors: [{}] }));
|
|
||||||
assert.notOk(isValidServerError({ errors: [{ notDetail: '' }] }));
|
|
||||||
});
|
|
||||||
// don't go too crazy with these, just enough for sanity check, we are essentially testing indexOf
|
|
||||||
test("it returns false if the response doesn't contain the exact error response", function(assert) {
|
|
||||||
const isValidServerError = createIsValidServerError();
|
|
||||||
[
|
|
||||||
"pc error making call: rpc: can't find method ACL",
|
|
||||||
"rpc error making call: rpc: can't find method",
|
|
||||||
"rpc rror making call: rpc: can't find method ACL",
|
|
||||||
].forEach(function(response) {
|
|
||||||
const e = createEmberDataError(response);
|
|
||||||
assert.notOk(isValidServerError(e));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
test('it returns true if the response contains the exact error response', function(assert) {
|
|
||||||
const isValidServerError = createIsValidServerError();
|
|
||||||
[
|
|
||||||
"rpc error making call: rpc: can't find method ACL",
|
|
||||||
" rpc error making call: rpc: can't find method ACL",
|
|
||||||
"rpc error making call: rpc: rpc error making call: rpc: rpc error making call: rpc: can't find method ACL",
|
|
||||||
].forEach(function(response) {
|
|
||||||
const e = createEmberDataError(response);
|
|
||||||
assert.ok(isValidServerError(e));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
(function(appNameJS = 'consulUi', doc = document) {
|
||||||
|
const scripts = doc.getElementsByTagName('script');
|
||||||
|
const script = scripts[scripts.length - 1];
|
||||||
|
script.dataset[`${appNameJS}Routes`] = JSON.stringify({
|
||||||
|
dc: {
|
||||||
|
acls: {
|
||||||
|
tokens: {
|
||||||
|
_options: {
|
||||||
|
abilities: ['read tokens'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})();
|
|
@ -5102,6 +5102,11 @@ deep-is@^0.1.3, deep-is@~0.1.3:
|
||||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
||||||
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
|
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
|
||||||
|
|
||||||
|
deepmerge@^4.2.2:
|
||||||
|
version "4.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
|
||||||
|
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
|
||||||
|
|
||||||
defaults@^1.0.3:
|
defaults@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
|
resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
|
||||||
|
|
Loading…
Reference in New Issue