ui: Support for Node Identities (#8137)

* Add all the new data required for NodeIdentities

* Add potential NodeIdentity to the token list component

* Amend the policy-form/selector to allow node identity creation

* Fix up CSS for radio buttons and select label

* Add node-identity policy template component

* Fix up and add acceptance tests for NodeIndentities

* Make sure policy previews take node identities into account

* Only show certain policy markup if those we have those policies

* Potentially temporarily hide dt's that don't have icons yet
This commit is contained in:
John Cowen 2020-06-23 09:59:43 +01:00 committed by GitHub
parent 146afbe9a2
commit c5d0216939
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 237 additions and 75 deletions

View File

@ -50,6 +50,7 @@ export default Adapter.extend({
Description: serialized.Description, Description: serialized.Description,
Policies: serialized.Policies, Policies: serialized.Policies,
ServiceIdentities: serialized.ServiceIdentities, ServiceIdentities: serialized.ServiceIdentities,
NodeIdentities: serialized.NodeIdentities,
...Namespace(serialized.Namespace), ...Namespace(serialized.Namespace),
}} }}
`; `;
@ -66,6 +67,7 @@ export default Adapter.extend({
Description: serialized.Description, Description: serialized.Description,
Policies: serialized.Policies, Policies: serialized.Policies,
ServiceIdentities: serialized.ServiceIdentities, ServiceIdentities: serialized.ServiceIdentities,
NodeIdentities: serialized.NodeIdentities,
...Namespace(serialized.Namespace), ...Namespace(serialized.Namespace),
}} }}
`; `;

View File

@ -53,6 +53,7 @@ export default Adapter.extend({
Policies: serialized.Policies, Policies: serialized.Policies,
Roles: serialized.Roles, Roles: serialized.Roles,
ServiceIdentities: serialized.ServiceIdentities, ServiceIdentities: serialized.ServiceIdentities,
NodeIdentities: serialized.NodeIdentities,
Local: serialized.Local, Local: serialized.Local,
...Namespace(serialized.Namespace), ...Namespace(serialized.Namespace),
}} }}
@ -84,6 +85,7 @@ export default Adapter.extend({
Policies: serialized.Policies, Policies: serialized.Policies,
Roles: serialized.Roles, Roles: serialized.Roles,
ServiceIdentities: serialized.ServiceIdentities, ServiceIdentities: serialized.ServiceIdentities,
NodeIdentities: serialized.NodeIdentities,
Local: serialized.Local, Local: serialized.Local,
...Namespace(serialized.Namespace), ...Namespace(serialized.Namespace),
}} }}

View File

@ -3,7 +3,7 @@
<div role="group"> <div role="group">
<fieldset> <fieldset>
<h2>Source</h2> <h2>Source</h2>
<label data-test-source-element class="type-text{{if _item.error.SourceName ' has-error'}}"> <label data-test-source-element class="type-select{{if _item.error.SourceName ' has-error'}}">
<span>Source Service</span> <span>Source Service</span>
<PowerSelectWithCreate <PowerSelectWithCreate
@options={{_services}} @options={{_services}}
@ -23,7 +23,7 @@
<em>Search for an existing service, or enter any Service name.</em> <em>Search for an existing service, or enter any Service name.</em>
</label> </label>
{{#if (env 'CONSUL_NSPACES_ENABLED')}} {{#if (env 'CONSUL_NSPACES_ENABLED')}}
<label data-test-source-nspace class="type-text{{if _item.error.SourceNS ' has-error'}}"> <label data-test-source-nspace class="type-select{{if _item.error.SourceNS ' has-error'}}">
<span>Source Namespace</span> <span>Source Namespace</span>
<PowerSelectWithCreate <PowerSelectWithCreate
@options={{_nspaces}} @options={{_nspaces}}
@ -46,7 +46,7 @@
</fieldset> </fieldset>
<fieldset> <fieldset>
<h2>Destination</h2> <h2>Destination</h2>
<label data-test-destination-element class="type-text{{if _item.error.DestinationName ' has-error'}}"> <label data-test-destination-element class="type-select{{if _item.error.DestinationName ' has-error'}}">
<span>Destination Service</span> <span>Destination Service</span>
<PowerSelectWithCreate <PowerSelectWithCreate
@options={{_services}} @options={{_services}}
@ -66,7 +66,7 @@
<em>Search for an existing service, or enter any Service name.</em> <em>Search for an existing service, or enter any Service name.</em>
</label> </label>
{{#if (env 'CONSUL_NSPACES_ENABLED')}} {{#if (env 'CONSUL_NSPACES_ENABLED')}}
<label data-test-destination-nspace class="type-text{{if _item.error.DestinationNS ' has-error'}}"> <label data-test-destination-nspace class="type-select{{if _item.error.DestinationNS ' has-error'}}">
<span>Destination Namespace</span> <span>Destination Namespace</span>
<PowerSelectWithCreate <PowerSelectWithCreate
@options={{_nspaces}} @options={{_nspaces}}

View File

@ -10,7 +10,7 @@
</dd> </dd>
</dl> </dl>
{{/if}} {{/if}}
<a href={{href-to 'dc.acls.tokens.edit' item.AccessorID}}>{{substr item.AccessorID -8}}</a> <a href={{href-to 'dc.acls.tokens.edit' item.AccessorID}}>{{substr item.AccessorID -8}}</a>
</BlockSlot> </BlockSlot>
<BlockSlot @name="details"> <BlockSlot @name="details">
<dl> <dl>
@ -23,7 +23,9 @@
{{#let (get policies 'management') as |management|}} {{#let (get policies 'management') as |management|}}
{{#if (gt management.length 0)}} {{#if (gt management.length 0)}}
<dl> <dl>
<dt>Management</dt> <dt>
Management
</dt>
<dd> <dd>
{{#each (get policies 'management') as |item|}} {{#each (get policies 'management') as |item|}}
<span data-test-policy class={{policy/typeof item}}>{{item.Name}}</span> <span data-test-policy class={{policy/typeof item}}>{{item.Name}}</span>
@ -32,26 +34,34 @@
</dl> </dl>
{{/if}} {{/if}}
{{/let}} {{/let}}
{{#let (get policies 'identities') as |identities|}}
{{#if (gt identities.length 0)}}
<dl> <dl>
<dt>Identities</dt> <dt>Identities</dt>
<dd> <dd>
{{#each (append (get policies 'identities')) as |item|}} {{#each identities as |item|}}
<span data-test-policy class={{policy/typeof item}}>Service Identity: {{item.Name}}</span> <span data-test-policy class={{policy/typeof item}}>{{if (eq item.template 'service-identity') 'Service' 'Node'}} Identity: {{item.Name}}</span>
{{/each}} {{/each}}
</dd> </dd>
</dl> </dl>
{{/if}}
{{/let}}
{{#let (append (get policies 'policies') item.Roles) as |policies|}}
{{#if (gt policies.length 0)}}
<dl> <dl>
<dt>Rules</dt> <dt>Rules</dt>
<dd> <dd>
{{#if (token/is-legacy item) }} {{#if (token/is-legacy item) }}
Legacy tokens have embedded rules. Legacy tokens have embedded rules.
{{ else }} {{ else }}
{{#each (append (get policies 'policies') item.Roles) as |item|}} {{#each policies as |item|}}
<span data-test-policy class={{policy/typeof item}}>{{item.Name}}</span> <span data-test-policy class={{policy/typeof item}}>{{item.Name}}</span>
{{/each}} {{/each}}
{{/if}} {{/if}}
</dd> </dd>
</dl> </dl>
{{/if}}
{{/let}}
{{/let}} {{/let}}
<dl> <dl>
<dt>Description</dt> <dt>Description</dt>

View File

@ -0,0 +1,6 @@
node "{{name}}" {
policy = "write"
}
service_prefix "" {
policy = "read"
}

View File

@ -0,0 +1,5 @@
import Component from '@ember/component';
export default Component.extend({
tagName: '',
});

View File

@ -3,11 +3,11 @@
{{#yield-slot name='template'}} {{#yield-slot name='template'}}
{{else}} {{else}}
<header> <header>
Policy{{if allowServiceIdentity ' or service identity?' ''}} Policy{{if allowIdentity ' or identity?' ''}}
</header> </header>
{{#if allowServiceIdentity}} {{#if allowIdentity}}
<p> <p>
A Service Identity is default policy with a configurable service name. This saves you some time and effort you're using Consul for Connect features. Identities are default policies with configurable names. They save you some time and effort you're using Consul for Connect features.
</p> </p>
{{! this should use radio-group }} {{! this should use radio-group }}
<div role="radiogroup" class={{if item.error.Type ' has-error'}}> <div role="radiogroup" class={{if item.error.Type ' has-error'}}>
@ -34,17 +34,38 @@
</label> </label>
<label class="type-text" data-test-rules> <label class="type-text" data-test-rules>
<span>Rules <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a></span> <span>Rules <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a></span>
{{#if (eq item.template '') }} {{#if (eq item.template 'service-identity')}}
<CodeEditor @readonly={{true}} @name={{concat name "[Rules]"}} @syntax="hcl" @oninput={{action "change" (concat name "[Rules]")}}>
{{~component 'service-identity' name=item.Name~}}
</CodeEditor>
{{else if (eq item.template 'node-identity')}}
<CodeEditor @readonly={{true}} @name={{concat name "[Rules]"}} @syntax="hcl" @oninput={{action "change" (concat name "[Rules]")}}>
{{~component 'node-identity' name=item.Name~}}
</CodeEditor>
{{else}}
<CodeEditor @syntax="hcl" @class={{if item.error.Rules "error"}} @name={{concat name "[Rules]"}} @value={{item.Rules}} @onkeyup={{action "change" (concat name "[Rules]")}} /> <CodeEditor @syntax="hcl" @class={{if item.error.Rules "error"}} @name={{concat name "[Rules]"}} @value={{item.Rules}} @onkeyup={{action "change" (concat name "[Rules]")}} />
{{#if item.error.Rules}} {{#if item.error.Rules}}
<strong>{{item.error.Rules.validation}}</strong> <strong>{{item.error.Rules.validation}}</strong>
{{/if}} {{/if}}
{{else}}
<CodeEditor @readonly={{true}} @name={{concat name "[Rules]"}} @syntax="hcl" @oninput={{action "change" (concat name "[Rules]")}}>
{{~component 'service-identity' name=item.Name~}}
</CodeEditor>
{{/if}} {{/if}}
</label> </label>
{{#if (eq item.template 'node-identity')}}
<DataSource @src="/*/*/datacenters"
@onchange={{action (mut datacenters) value="data"}}
/>
<label class="type-select" data-test-datacenter>
<span>Datacenter</span>
<PowerSelect
@options={{map-by 'Name' datacenters}}
@searchField="Name"
@selected={{or item.Datacenter dc}}
@searchPlaceholder="Type a datacenter name"
@onChange={{action "change" "Datacenter"}} as |Name|>
{{Name}}
</PowerSelect>
</label>
{{else}}
<div class="type-toggle"> <div class="type-toggle">
<span>Valid datacenters</span> <span>Valid datacenters</span>
<label> <label>
@ -52,10 +73,11 @@
<span>All</span> <span>All</span>
</label> </label>
</div> </div>
{{#if isScoped }} {{#if isScoped }}
<DataSource @src="/*/*/datacenters" <DataSource @src="/*/*/datacenters"
@onchange={{action (mut datacenters) value="data"}} @onchange={{action (mut datacenters) value="data"}}
/> />
<div class="checkbox-group" role="group"> <div class="checkbox-group" role="group">
{{#each datacenters as |dc| }} {{#each datacenters as |dc| }}
<label class="type-checkbox"> <label class="type-checkbox">
@ -72,6 +94,9 @@
{{/if}} {{/if}}
{{/each}} {{/each}}
</div> </div>
{{/if}}
{{/if}} {{/if}}
{{#if (eq item.template '') }} {{#if (eq item.template '') }}
<label class="type-text"> <label class="type-text">

View File

@ -4,7 +4,7 @@ import { get, set } from '@ember/object';
export default FormComponent.extend({ export default FormComponent.extend({
type: 'policy', type: 'policy',
name: 'policy', name: 'policy',
allowServiceIdentity: true, allowIdentity: true,
classNames: ['policy-form'], classNames: ['policy-form'],
isScoped: false, isScoped: false,
@ -20,6 +20,10 @@ export default FormComponent.extend({
name: 'Service Identity', name: 'Service Identity',
template: 'service-identity', template: 'service-identity',
}, },
{
name: 'Node Identity',
template: 'node-identity',
},
]; ];
}, },
actions: { actions: {

View File

@ -8,7 +8,7 @@ export default (submitable, cancelable, radiogroup, text) => (
prefix: 'policy', prefix: 'policy',
...submitable(), ...submitable(),
...cancelable(), ...cancelable(),
...radiogroup('template', ['', 'service-identity'], 'policy'), ...radiogroup('template', ['', 'service-identity', 'node-identity'], 'policy'),
rules: { rules: {
error: text('[data-test-rules] strong'), error: text('[data-test-rules] strong'),
}, },

View File

@ -50,35 +50,48 @@
<BlockSlot @name="row"> <BlockSlot @name="row">
<td class={{policy/typeof item}}> <td class={{policy/typeof item}}>
{{#if item.ID }} {{#if item.ID }}
<a href={{href-to 'dc.acls.policies.edit' item.ID}}>{{item.Name}}</a> <a href={{href-to 'dc.acls.policies.edit' item.ID}}>{{item.Name}}</a>
{{else}} {{else}}
<a name={{item.Name}}>{{item.Name}}</a> <a name={{item.Name}}>{{item.Name}}</a>
{{/if}} {{/if}}
</td> </td>
</BlockSlot> </BlockSlot>
<BlockSlot @name="details"> <BlockSlot @name="details">
{{#if (eq item.template '')}} {{#if (eq item.template '')}}
<DataSource <DataSource
@src={{concat '/' item.Namespace '/' dc '/policy/' item.ID}} @src={{concat '/' item.Namespace '/' dc '/policy/' item.ID}}
@onchange={{action (mut loadedItem) value="data"}} @onchange={{action (mut loadedItem) value="data"}}
@loading="lazy" @loading="lazy"
/> />
{{/if}} {{/if}}
{{#if (eq item.template 'node-identity')}}
<dl>
<dt>Datacenter:</dt>
<dd>
{{item.Datacenter}}
</dd>
</dl>
{{else}}
<dl> <dl>
<dt>Datacenters:</dt> <dt>Datacenters:</dt>
<dd> <dd>
{{join ', ' (policy/datacenters (or loadedItem item))}} {{join ', ' (policy/datacenters (or loadedItem item))}}
</dd> </dd>
</dl> </dl>
{{/if}}
<label class="type-text"> <label class="type-text">
<span>Rules <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a></span> <span>Rules <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a></span>
{{#if (eq item.template '')}} {{#if (eq item.template 'service-identity')}}
<CodeEditor @syntax="hcl" @readonly={{true}} @value={{or loadedItem.Rules item.Rules}} /> <CodeEditor @syntax="hcl" @readonly={{true}}>
{{else}} {{~component 'service-identity' name=item.Name~}}
<CodeEditor @syntax="hcl" @readonly={{true}}> </CodeEditor>
{{~component 'service-identity' name=item.Name~}} {{else if (eq item.template 'node-identity')}}
</CodeEditor> <CodeEditor @syntax="hcl" @readonly={{true}}>
{{/if}} {{~component 'node-identity' name=item.Name~}}
</CodeEditor>
{{else}}
<CodeEditor @syntax="hcl" @readonly={{true}} @value={{or loadedItem.Rules item.Rules}} />
{{/if}}
</label> </label>
<div> <div>
<ConfirmationDialog @message="Are you sure you want to remove this policy from this token?"> <ConfirmationDialog @message="Are you sure you want to remove this policy from this token?">

View File

@ -10,7 +10,7 @@ export default ChildSelectorComponent.extend({
repo: service('repository/policy/component'), repo: service('repository/policy/component'),
name: 'policy', name: 'policy',
type: 'policy', type: 'policy',
allowServiceIdentity: true, allowIdentity: true,
classNames: ['policy-selector'], classNames: ['policy-selector'],
init: function() { init: function() {
this._super(...arguments); this._super(...arguments);

View File

@ -3,14 +3,14 @@ import { get } from '@ember/object';
import minimizeModel from 'consul-ui/utils/minimizeModel'; import minimizeModel from 'consul-ui/utils/minimizeModel';
const normalizeServiceIdentities = function(items) { const normalizeIdentities = function(items, template, name, dc) {
return (items || []).map(function(item) { return (items || []).map(function(item) {
const policy = { const policy = {
template: 'service-identity', template: template,
Name: item.ServiceName, Name: item[name],
}; };
if (typeof item.Datacenters !== 'undefined') { if (typeof item[dc] !== 'undefined') {
policy.Datacenters = item.Datacenters; policy[dc] = item[dc];
} }
return policy; return policy;
}); });
@ -25,17 +25,17 @@ const normalizePolicies = function(items) {
}; };
}); });
}; };
const serializeServiceIdentities = function(items) { const serializeIdentities = function(items, template, name, dc) {
return items return items
.filter(function(item) { .filter(function(item) {
return get(item, 'template') === 'service-identity'; return get(item, 'template') === template;
}) })
.map(function(item) { .map(function(item) {
const identity = { const identity = {
ServiceName: get(item, 'Name'), [name]: get(item, 'Name'),
}; };
if (get(item, 'Datacenters')) { if (typeof get(item, dc) !== 'undefined') {
identity.Datacenters = get(item, 'Datacenters'); identity[dc] = get(item, dc);
} }
return identity; return identity;
}); });
@ -51,9 +51,18 @@ export default Mixin.create({
respondForQueryRecord: function(respond, query) { respondForQueryRecord: function(respond, query) {
return this._super(function(cb) { return this._super(function(cb) {
return respond((headers, body) => { return respond((headers, body) => {
body.Policies = normalizePolicies(body.Policies).concat( body.Policies = normalizePolicies(body.Policies)
normalizeServiceIdentities(body.ServiceIdentities) .concat(
); normalizeIdentities(
body.ServiceIdentities,
'service-identity',
'ServiceName',
'Datacenters'
)
)
.concat(
normalizeIdentities(body.NodeIdentities, 'node-identity', 'NodeName', 'Datacenter')
);
return cb(headers, body); return cb(headers, body);
}); });
}, query); }, query);
@ -64,9 +73,18 @@ export default Mixin.create({
return cb( return cb(
headers, headers,
body.map(function(item) { body.map(function(item) {
item.Policies = normalizePolicies(item.Policies).concat( item.Policies = normalizePolicies(item.Policies)
normalizeServiceIdentities(item.ServiceIdentities) .concat(
); normalizeIdentities(
item.ServiceIdentities,
'service-identity',
'ServiceName',
'Datacenters'
)
)
.concat(
normalizeIdentities(item.NodeIdentities, 'node-identity', 'NodeName', 'Datacenter')
);
return item; return item;
}) })
); );
@ -75,7 +93,18 @@ export default Mixin.create({
}, },
serialize: function(snapshot, options) { serialize: function(snapshot, options) {
const data = this._super(...arguments); const data = this._super(...arguments);
data.ServiceIdentities = serializeServiceIdentities(data.Policies); data.ServiceIdentities = serializeIdentities(
data.Policies,
'service-identity',
'ServiceName',
'Datacenters'
);
data.NodeIdentities = serializeIdentities(
data.Policies,
'node-identity',
'NodeName',
'Datacenter'
);
data.Policies = minimizeModel(serializePolicies(data.Policies)); data.Policies = minimizeModel(serializePolicies(data.Policies));
return data; return data;
}, },

View File

@ -22,6 +22,11 @@ export default Model.extend({
return []; return [];
}, },
}), }),
NodeIdentities: attr({
defaultValue: function() {
return [];
},
}),
// frontend only for ordering where CreateIndex can't be used // frontend only for ordering where CreateIndex can't be used
CreateTime: attr('date'), CreateTime: attr('date'),
// //

View File

@ -39,6 +39,11 @@ export default Model.extend({
return []; return [];
}, },
}), }),
NodeIdentities: attr({
defaultValue: function() {
return [];
},
}),
CreateTime: attr('date'), CreateTime: attr('date'),
Hash: attr('string'), Hash: attr('string'),
CreateIndex: attr('number'), CreateIndex: attr('number'),

View File

@ -15,7 +15,6 @@
} }
%radio-group label > span { %radio-group label > span {
margin-left: 1em; margin-left: 1em;
margin-top: 0.2em;
} }
%radio-group label, %radio-group label,
%radio-group label > span { %radio-group label > span {

View File

@ -13,6 +13,11 @@
.consul-token-list > ul > li:not(:first-child) { .consul-token-list > ul > li:not(:first-child) {
@extend %with-composite-row-intent; @extend %with-composite-row-intent;
} }
/*TODO: This hides the icons-less dt's in the below lists as */
/* they don't have tooltips */
.consul-token-list > ul > li:not(:first-child) dt {
display: none;
}
/* TODO: the service list has a 1px offset */ /* TODO: the service list has a 1px offset */
.consul-service-list li > div:first-child > dl:first-child dd { .consul-service-list li > div:first-child > dl:first-child dd {
margin-top: 1px; margin-top: 1px;

View File

@ -20,6 +20,7 @@ label span {
@extend %form-row; @extend %form-row;
} }
%radio-group label, %radio-group label,
%main-content .type-select,
%main-content .type-password, %main-content .type-password,
%main-content .type-text { %main-content .type-text {
@extend %form-element; @extend %form-element;

View File

@ -30,7 +30,7 @@
<p> <p>
By adding policies to this namespaces, you will apply them to all tokens created within this namespace. By adding policies to this namespaces, you will apply them to all tokens created within this namespace.
</p> </p>
<PolicySelector @dc={{dc}} @nspace="default" @allowServiceIdentity={{false}} @items={{item.ACLs.PolicyDefaults}} /> <PolicySelector @dc={{dc}} @nspace="default" @allowIdentity={{false}} @items={{item.ACLs.PolicyDefaults}} />
</fieldset> </fieldset>
{{/if}} {{/if}}
<div> <div>

View File

@ -6,6 +6,7 @@ Feature: dc / acls / policies / as many / add existing: Add existing policy
--- ---
Policies: ~ Policies: ~
ServiceIdentities: ~ ServiceIdentities: ~
NodeIdentities: ~
--- ---
And 2 policy models from yaml And 2 policy models from yaml
--- ---

View File

@ -6,6 +6,7 @@ Feature: dc / acls / policies / as many / add new: Add new policy
--- ---
Policies: ~ Policies: ~
ServiceIdentities: ~ ServiceIdentities: ~
NodeIdentities: ~
--- ---
When I visit the [Model] page for yaml When I visit the [Model] page for yaml
--- ---
@ -52,7 +53,6 @@ Feature: dc / acls / policies / as many / add new: Add new policy
Then I fill in the policies.form with yaml Then I fill in the policies.form with yaml
--- ---
Name: New-Service-Identity Name: New-Service-Identity
Description: New Service Identity Description
--- ---
And I click serviceIdentity on the policies.form And I click serviceIdentity on the policies.form
And I click submit on the policies.form And I click submit on the policies.form
@ -73,6 +73,31 @@ Feature: dc / acls / policies / as many / add new: Add new policy
| token | | token |
| role | | role |
------------- -------------
Scenario: Adding a new node identity as a child of [Model]
Then I fill in the policies.form with yaml
---
Name: New-Node-Identity
---
And I click nodeIdentity on the policies.form
And I click submit on the policies.form
And I submit
Then a PUT request was made to "/v1/acl/[Model]/key?dc=datacenter" from yaml
---
body:
Namespace: @namespace
NodeIdentities:
- NodeName: New-Node-Identity
Datacenter: datacenter
---
Then the url should be /datacenter/acls/[Model]s
And "[data-notification]" has the "notification-update" class
And "[data-notification]" has the "success" class
Where:
-------------
| Model |
| token |
| role |
-------------
Scenario: Adding a new policy as a child of [Model] and getting an error Scenario: Adding a new policy as a child of [Model] and getting an error
Given the url "/v1/acl/policy" responds with from yaml Given the url "/v1/acl/policy" responds with from yaml
--- ---
@ -113,3 +138,15 @@ Feature: dc / acls / policies / as many / add new: Add new policy
| token | | token |
| role | | role |
------------- -------------
Scenario: Try to edit the Node Identity using the code editor
And I click nodeIdentity on the policies.form
Then I can't fill in the policies.form with yaml
---
Rules: key {}
---
Where:
-------------
| Model |
| token |
| role |
-------------

View File

@ -6,8 +6,8 @@ Feature: dc / acls / policies / as many / list: List
--- ---
ServiceIdentities: ServiceIdentities:
- ServiceName: Service-Identity - ServiceName: Service-Identity
- ServiceName: Service-Identity 2 NodeIdentities:
- ServiceName: Service-Identity 3 - NodeName: Node-Identity
Policies: Policies:
- Name: Policy - Name: Policy
ID: 0000 ID: 0000
@ -22,8 +22,8 @@ Feature: dc / acls / policies / as many / list: List
[Model]: key [Model]: key
--- ---
Then the url should be /datacenter/acls/[Model]s/key Then the url should be /datacenter/acls/[Model]s/key
# ServiceIdentities turn into policies # Identities turn into policies
Then I see 6 policy models on the policies component Then I see 5 policy models on the policies component
Where: Where:
------------- -------------
| Model | | Model |

View File

@ -5,6 +5,7 @@ Feature: dc / acls / policies / as many / remove: Remove
And 1 [Model] model from yaml And 1 [Model] model from yaml
--- ---
ServiceIdentities: ~ ServiceIdentities: ~
NodeIdentities: ~
Policies: Policies:
- Name: Policy - Name: Policy
ID: 00000000-0000-0000-0000-000000000001 ID: 00000000-0000-0000-0000-000000000001

View File

@ -6,6 +6,7 @@ Feature: dc / acls / tokens / clone: Cloning an ACL token
--- ---
AccessorID: token AccessorID: token
SecretID: ee52203d-989f-4f7a-ab5a-2bef004164ca SecretID: ee52203d-989f-4f7a-ab5a-2bef004164ca
Legacy: ~
--- ---
Scenario: Cloning an ACL token from the listing page Scenario: Cloning an ACL token from the listing page
When I visit the tokens page for yaml When I visit the tokens page for yaml

View File

@ -4,16 +4,27 @@ export const createPolicies = function(item) {
template: '', template: '',
...item, ...item,
}; };
}).concat( })
item.ServiceIdentities.map(function(item) { .concat(
const policy = { item.ServiceIdentities.map(function(item) {
template: 'service-identity', const policy = {
Name: item.ServiceName, template: 'service-identity',
}; Name: item.ServiceName,
if (typeof item.Datacenters !== 'undefined') { };
policy.Datacenters = item.Datacenters; if (typeof item.Datacenters !== 'undefined') {
} policy.Datacenters = item.Datacenters;
return policy; }
}) return policy;
); })
)
.concat(
item.NodeIdentities.map(function(item) {
const policy = {
template: 'node-identity',
Name: item.NodeName,
Datacenter: item.Datacenter,
};
return policy;
})
);
}; };

View File

@ -1211,9 +1211,9 @@
js-yaml "^3.13.1" js-yaml "^3.13.1"
"@hashicorp/consul-api-double@^3.0.0": "@hashicorp/consul-api-double@^3.0.0":
version "3.0.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-3.0.0.tgz#a1ad94f33e006d01cebf2b22d1f87efef1756ece" resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-3.1.0.tgz#6f0cfc32d99b6f0c876d473ff8fdc489b7403904"
integrity sha512-wB1YgDBN3eOvNWRzSOc2k0eVE7C8YHFC5rJEdNWWTzjOokj6zDr40g2yLiaDMXl21XQs5LE8kNstEe8pf2+JUQ== integrity sha512-TsRvkBJTzMaXlSyaFT4HU+Phhk+7K2kWPmnuM41cqkHsCLfoTllQ37avQyLYGM/57yfd0ajbI4M6IKoYJnQUWg==
"@hashicorp/ember-cli-api-double@^3.1.0": "@hashicorp/ember-cli-api-double@^3.1.0":
version "3.1.0" version "3.1.0"