ui: Correct readonly L7 Intentions API calls (#8725)
* Disable ability to select destination if not creating * Add a LegacyID for intentions that don't have them * Use `/exact/` endpoint for reading single intentions * Fix up test for new API interaction * Upgrade consul-api-double * Comment out tests using destination for the moment Also, removed any intention related things from the old page-navigation tests
This commit is contained in:
parent
0594667c3a
commit
4a76042989
|
@ -1,6 +1,5 @@
|
|||
import Adapter, { DATACENTER_QUERY_PARAM as API_DATACENTER_KEY } from './application';
|
||||
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
|
||||
import { SLUG_KEY } from 'consul-ui/models/intention';
|
||||
// Intentions use SourceNS and DestinationNS properties for namespacing
|
||||
// so we don't need to add the `?ns=` anywhere here
|
||||
|
||||
|
@ -26,8 +25,13 @@ export default Adapter.extend({
|
|||
if (typeof id === 'undefined') {
|
||||
throw new Error('You must specify an id');
|
||||
}
|
||||
const [SourceNS, SourceName, DestinationNS, DestinationName] = id
|
||||
.split(':')
|
||||
.map(decodeURIComponent);
|
||||
return request`
|
||||
GET /v1/connect/intentions/${id}?${{ dc }}
|
||||
GET /v1/connect/intentions/exact?source=${SourceNS +
|
||||
'/' +
|
||||
SourceName}&destination=${DestinationNS + '/' + DestinationName}&${{ dc }}
|
||||
Cache-Control: no-store
|
||||
|
||||
${{ index }}
|
||||
|
@ -51,7 +55,7 @@ export default Adapter.extend({
|
|||
},
|
||||
requestForUpdateRecord: function(request, serialized, data) {
|
||||
return request`
|
||||
PUT /v1/connect/intentions/${data[SLUG_KEY]}?${{ [API_DATACENTER_KEY]: data[DATACENTER_KEY] }}
|
||||
PUT /v1/connect/intentions/${data.LegacyID}?${{ [API_DATACENTER_KEY]: data[DATACENTER_KEY] }}
|
||||
|
||||
${{
|
||||
SourceNS: serialized.SourceNS,
|
||||
|
@ -60,13 +64,14 @@ export default Adapter.extend({
|
|||
DestinationName: serialized.DestinationName,
|
||||
SourceType: serialized.SourceType,
|
||||
Action: serialized.Action,
|
||||
Meta: serialized.Meta,
|
||||
Description: serialized.Description,
|
||||
}}
|
||||
`;
|
||||
},
|
||||
requestForDeleteRecord: function(request, serialized, data) {
|
||||
return request`
|
||||
DELETE /v1/connect/intentions/${data[SLUG_KEY]}?${{
|
||||
DELETE /v1/connect/intentions/${data.LegacyID}?${{
|
||||
[API_DATACENTER_KEY]: data[DATACENTER_KEY],
|
||||
}}
|
||||
`;
|
||||
|
|
|
@ -43,7 +43,9 @@
|
|||
{{nspace.Name}}
|
||||
{{/if}}
|
||||
</PowerSelectWithCreate>
|
||||
<em>Search for an existing namespace, or enter any Namespace name.</em>
|
||||
{{#if create}}
|
||||
<em>Search for an existing namespace, or enter any Namespace name.</em>
|
||||
{{/if}}
|
||||
</label>
|
||||
{{/if}}
|
||||
</fieldset>
|
||||
|
@ -52,6 +54,7 @@
|
|||
<label data-test-destination-element class="type-select{{if item.error.DestinationName ' has-error'}}">
|
||||
<span>Destination Service</span>
|
||||
<PowerSelectWithCreate
|
||||
@disabled={{not create}}
|
||||
@options={{services}}
|
||||
@searchField="Name"
|
||||
@selected={{DestinationName}}
|
||||
|
@ -66,12 +69,15 @@
|
|||
{{service.Name}}
|
||||
{{/if}}
|
||||
</PowerSelectWithCreate>
|
||||
<em>Search for an existing service, or enter any Service name.</em>
|
||||
{{#if create}}
|
||||
<em>Search for an existing service, or enter any Service name.</em>
|
||||
{{/if}}
|
||||
</label>
|
||||
{{#if (env 'CONSUL_NSPACES_ENABLED')}}
|
||||
<label data-test-destination-nspace class="type-select{{if item.error.DestinationNS ' has-error'}}">
|
||||
<span>Destination Namespace</span>
|
||||
<PowerSelectWithCreate
|
||||
@disabled={{not create}}
|
||||
@options={{nspaces}}
|
||||
@searchField="Name"
|
||||
@selected={{DestinationNS}}
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
@DestinationNS={{DestinationNS}}
|
||||
@item={{item}}
|
||||
@disabled={{api.disabled}}
|
||||
@create={{api.isCreate}}
|
||||
@onchange={{api.change}}
|
||||
/>
|
||||
<div>
|
||||
|
|
|
@ -20,6 +20,7 @@ export default Model.extend({
|
|||
Action: attr('string'),
|
||||
Meta: attr(),
|
||||
Legacy: attr('boolean', { defaultValue: true }),
|
||||
LegacyID: attr('string'),
|
||||
|
||||
IsManagedByCRD: computed('Meta', function() {
|
||||
const meta = Object.entries(this.Meta || {}).find(
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Serializer from './application';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { get } from '@ember/object';
|
||||
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/intention';
|
||||
|
||||
export default Serializer.extend({
|
||||
|
@ -11,13 +12,14 @@ export default Serializer.extend({
|
|||
this.uri = this.encoder.uriTag();
|
||||
},
|
||||
ensureID: function(item) {
|
||||
if (typeof item.ID !== 'string') {
|
||||
item.ID = this
|
||||
.uri`${item.SourceNS}:${item.SourceName}:${item.DestinationNS}:${item.DestinationName}`;
|
||||
if (!get(item, 'ID.length')) {
|
||||
item.Legacy = false;
|
||||
} else {
|
||||
item.Legacy = true;
|
||||
item.LegacyID = item.ID;
|
||||
}
|
||||
item.ID = this
|
||||
.uri`${item.SourceNS}:${item.SourceName}:${item.DestinationNS}:${item.DestinationName}`;
|
||||
return item;
|
||||
},
|
||||
respondForQuery: function(respond, query) {
|
||||
|
@ -42,4 +44,16 @@ export default Serializer.extend({
|
|||
query
|
||||
);
|
||||
},
|
||||
respondForUpdateRecord: function(respond, serialized, data) {
|
||||
return this._super(
|
||||
cb =>
|
||||
respond((headers, body) => {
|
||||
body.LegacyID = body.ID;
|
||||
body.ID = serialized.ID;
|
||||
return cb(headers, body);
|
||||
}),
|
||||
serialized,
|
||||
data
|
||||
);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -35,7 +35,7 @@ Feature: dc / intentions / filtered-select: Intention Service Select Dropdowns
|
|||
---------------
|
||||
| Name |
|
||||
| source |
|
||||
| destination |
|
||||
#| destination |
|
||||
---------------
|
||||
Scenario: Opening the [Name] dropdown with 2 services with the same name from different nspaces
|
||||
Given 1 datacenter model with the value "datacenter"
|
||||
|
@ -65,5 +65,5 @@ Feature: dc / intentions / filtered-select: Intention Service Select Dropdowns
|
|||
---------------
|
||||
| Name |
|
||||
| source |
|
||||
| destination |
|
||||
#| destination |
|
||||
---------------
|
||||
|
|
|
@ -19,5 +19,5 @@ Feature: dc / intentions / form-select: Intention Service Select Dropdowns
|
|||
---------------
|
||||
| Name |
|
||||
| source |
|
||||
| destination |
|
||||
# | destination |
|
||||
---------------
|
||||
|
|
|
@ -26,7 +26,6 @@ Feature: page-navigation
|
|||
| nodes | /dc-1/nodes | /v1/internal/ui/nodes?dc=dc-1 |
|
||||
| kvs | /dc-1/kv | /v1/kv/?keys&dc=dc-1&separator=%2F&ns=@namespace |
|
||||
| acls | /dc-1/acls/tokens | /v1/acl/tokens?dc=dc-1&ns=@namespace |
|
||||
| intentions | /dc-1/intentions | /v1/connect/intentions?dc=dc-1 |
|
||||
# | settings | /settings | /v1/catalog/datacenters |
|
||||
-------------------------------------------------------------------------------------
|
||||
Scenario: Clicking a [Item] in the [Model] listing and back again
|
||||
|
@ -87,20 +86,6 @@ Feature: page-navigation
|
|||
- /v1/namespaces
|
||||
- /v1/acl/policies?dc=dc-1&ns=@namespace
|
||||
---
|
||||
Scenario: The intention detail page calls the correct API endpoints
|
||||
When I visit the intention page for yaml
|
||||
---
|
||||
dc: dc-1
|
||||
intention: intention
|
||||
---
|
||||
Then the url should be /dc-1/intentions/intention
|
||||
Then the last GET requests included from yaml
|
||||
---
|
||||
- /v1/catalog/datacenters
|
||||
- /v1/namespaces
|
||||
- /v1/connect/intentions/intention?dc=dc-1
|
||||
- /v1/internal/ui/services?dc=dc-1&ns=*
|
||||
---
|
||||
|
||||
Scenario: Clicking a [Item] in the [Model] listing and cancelling
|
||||
When I visit the [Model] page for yaml
|
||||
|
@ -116,7 +101,6 @@ Feature: page-navigation
|
|||
| Item | Model | URL | Back |
|
||||
| kv | kvs | /dc-1/kv/0-key-value/edit | /dc-1/kv |
|
||||
# | acl | acls | /dc-1/acls/anonymous | /dc-1/acls |
|
||||
# | intention | intentions | /dc-1/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca | /dc-1/intentions |
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
@ignore
|
||||
Scenario: Clicking items in the listings, without depending on the salt ^
|
||||
|
|
|
@ -3,7 +3,8 @@ import { setupTest } from 'ember-qunit';
|
|||
module('Integration | Adapter | intention', function(hooks) {
|
||||
setupTest(hooks);
|
||||
const dc = 'dc-1';
|
||||
const id = 'intention-name';
|
||||
const legacyId = 'intention-name';
|
||||
const id = 'SourceNS:SourceName:DestinationNS:DestinationName';
|
||||
test('requestForQuery returns the correct url', function(assert) {
|
||||
const adapter = this.owner.lookup('adapter:intention');
|
||||
const client = this.owner.lookup('service:client/http');
|
||||
|
@ -16,7 +17,7 @@ module('Integration | Adapter | intention', function(hooks) {
|
|||
test('requestForQueryRecord returns the correct url', function(assert) {
|
||||
const adapter = this.owner.lookup('adapter:intention');
|
||||
const client = this.owner.lookup('service:client/http');
|
||||
const expected = `GET /v1/connect/intentions/${id}?dc=${dc}`;
|
||||
const expected = `GET /v1/connect/intentions/exact?source=SourceNS%2FSourceName&destination=DestinationNS%2FDestinationName&dc=${dc}`;
|
||||
const actual = adapter
|
||||
.requestForQueryRecord(client.url, {
|
||||
dc: dc,
|
||||
|
@ -53,7 +54,7 @@ module('Integration | Adapter | intention', function(hooks) {
|
|||
test('requestForUpdateRecord returns the correct url', function(assert) {
|
||||
const adapter = this.owner.lookup('adapter:intention');
|
||||
const client = this.owner.lookup('service:client/http');
|
||||
const expected = `PUT /v1/connect/intentions/${id}?dc=${dc}`;
|
||||
const expected = `PUT /v1/connect/intentions/${legacyId}?dc=${dc}`;
|
||||
const actual = adapter
|
||||
.requestForUpdateRecord(
|
||||
client.url,
|
||||
|
@ -61,6 +62,7 @@ module('Integration | Adapter | intention', function(hooks) {
|
|||
{
|
||||
Datacenter: dc,
|
||||
ID: id,
|
||||
LegacyID: legacyId,
|
||||
}
|
||||
)
|
||||
.split('\n')[0];
|
||||
|
@ -69,7 +71,7 @@ module('Integration | Adapter | intention', function(hooks) {
|
|||
test('requestForDeleteRecord returns the correct url', function(assert) {
|
||||
const adapter = this.owner.lookup('adapter:intention');
|
||||
const client = this.owner.lookup('service:client/http');
|
||||
const expected = `DELETE /v1/connect/intentions/${id}?dc=${dc}`;
|
||||
const expected = `DELETE /v1/connect/intentions/${legacyId}?dc=${dc}`;
|
||||
const actual = adapter
|
||||
.requestForDeleteRecord(
|
||||
client.url,
|
||||
|
@ -77,6 +79,7 @@ module('Integration | Adapter | intention', function(hooks) {
|
|||
{
|
||||
Datacenter: dc,
|
||||
ID: id,
|
||||
LegacyID: legacyId,
|
||||
}
|
||||
)
|
||||
.split('\n')[0];
|
||||
|
|
|
@ -23,7 +23,7 @@ module('Integration | Serializer | intention', function(hooks) {
|
|||
// TODO: default isn't required here, once we've
|
||||
// refactored out our Serializer this can go
|
||||
Namespace: nspace,
|
||||
uid: `["${nspace}","${dc}","${item.ID}"]`,
|
||||
uid: `["${nspace}","${dc}","${item.SourceNS}:${item.SourceName}:${item.DestinationNS}:${item.DestinationName}"]`,
|
||||
})
|
||||
);
|
||||
const actual = serializer.respondForQuery(
|
||||
|
@ -46,7 +46,17 @@ module('Integration | Serializer | intention', function(hooks) {
|
|||
const request = {
|
||||
url: `/v1/connect/intentions/${id}?dc=${dc}`,
|
||||
};
|
||||
const item = {
|
||||
SourceNS: 'SourceNS',
|
||||
SourceName: 'SourceName',
|
||||
DestinationNS: 'DestinationNS',
|
||||
DestinationName: 'DestinationName',
|
||||
};
|
||||
return get(request.url).then(function(payload) {
|
||||
payload = {
|
||||
...payload,
|
||||
...item,
|
||||
};
|
||||
const expected = Object.assign({}, payload, {
|
||||
Datacenter: dc,
|
||||
[META]: {
|
||||
|
@ -56,7 +66,7 @@ module('Integration | Serializer | intention', function(hooks) {
|
|||
// TODO: default isn't required here, once we've
|
||||
// refactored out our Serializer this can go
|
||||
Namespace: nspace,
|
||||
uid: `["${nspace}","${dc}","${id}"]`,
|
||||
uid: `["${nspace}","${dc}","${item.SourceNS}:${item.SourceName}:${item.DestinationNS}:${item.DestinationName}"]`,
|
||||
});
|
||||
const actual = serializer.respondForQueryRecord(
|
||||
function(cb) {
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
import { moduleFor, test } from 'ember-qunit';
|
||||
import repo from 'consul-ui/tests/helpers/repo';
|
||||
import { get } from '@ember/object';
|
||||
const NAME = 'intention';
|
||||
moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, {
|
||||
integration: true,
|
||||
});
|
||||
|
||||
const now = new Date().getTime();
|
||||
const dc = 'dc-1';
|
||||
const id = 'token-name';
|
||||
const nspace = 'default';
|
||||
test('findAllByDatacenter returns the correct data for list endpoint', function(assert) {
|
||||
get(this.subject(), 'store').serializerFor(NAME).timestamp = function() {
|
||||
return now;
|
||||
};
|
||||
return repo(
|
||||
'Intention',
|
||||
'findAllByDatacenter',
|
||||
this.subject(),
|
||||
function retrieveStub(stub) {
|
||||
return stub(`/v1/connect/intentions?dc=${dc}`, {
|
||||
CONSUL_INTENTION_COUNT: '1',
|
||||
});
|
||||
},
|
||||
function performTest(service) {
|
||||
return service.findAllByDatacenter(dc);
|
||||
},
|
||||
function performAssertion(actual, expected) {
|
||||
assert.deepEqual(
|
||||
actual[0],
|
||||
expected(function(payload) {
|
||||
const item = payload[0];
|
||||
return {
|
||||
...item,
|
||||
CreatedAt: new Date(item.CreatedAt),
|
||||
UpdatedAt: new Date(item.UpdatedAt),
|
||||
Legacy: true,
|
||||
SyncTime: now,
|
||||
Datacenter: dc,
|
||||
// TODO: nspace isn't required here, once we've
|
||||
// refactored out our Serializer this can go
|
||||
uid: `["${nspace}","${dc}","${item.ID}"]`,
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
test('findBySlug returns the correct data for item endpoint', function(assert) {
|
||||
return repo(
|
||||
'Intention',
|
||||
'findBySlug',
|
||||
this.subject(),
|
||||
function(stub) {
|
||||
return stub(`/v1/connect/intentions/${id}?dc=${dc}`);
|
||||
},
|
||||
function(service) {
|
||||
return service.findBySlug(id, dc);
|
||||
},
|
||||
function(actual, expected) {
|
||||
assert.deepEqual(
|
||||
actual,
|
||||
expected(function(payload) {
|
||||
const item = payload;
|
||||
return Object.assign({}, item, {
|
||||
Legacy: true,
|
||||
CreatedAt: new Date(item.CreatedAt),
|
||||
UpdatedAt: new Date(item.UpdatedAt),
|
||||
Datacenter: dc,
|
||||
// TODO: nspace isn't required here, once we've
|
||||
// refactored out our Serializer this can go
|
||||
uid: `["${nspace}","${dc}","${item.ID}"]`,
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
|
@ -1520,9 +1520,9 @@
|
|||
js-yaml "^3.13.1"
|
||||
|
||||
"@hashicorp/consul-api-double@^5.0.0":
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-5.0.0.tgz#099e56ded356421cdfa5e63b4a07c9a2232ffb88"
|
||||
integrity sha512-2+Rg4mfxTTUrJiYeRWV5mEWVZTYUK1udFNMb79ygNdC/HScDvU8sTVwPrf6GuRve6oLakk1lB/D4d6AsMmtS4w==
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-5.0.1.tgz#07880706ab26cc242332cef86b2c03b3b4ec4e56"
|
||||
integrity sha512-uptXq/XTGL5uzGqvwRqC0tzHKCJMVAaRMucPxjbMb4r9wOmOdT4Z2BUJD8GDcCSFIWE8hbWeqAlCXRrokZ3wbw==
|
||||
|
||||
"@hashicorp/ember-cli-api-double@^3.1.0":
|
||||
version "3.1.1"
|
||||
|
|
Loading…
Reference in New Issue