ui: [BUGFIX] Request intention listing with ns parameter (#9432)
This PR adds the ns=* query parameter when namespaces are enabled to keep backwards compatibility with how the UI used to work (Intentions page always lists all intention across all namespace you have access to) I found a tiny dev bug for printing out the current URL during acceptance testing and fixed that up while I was there.
This commit is contained in:
parent
1dcf7fe0f8
commit
7a21bd7720
|
@ -0,0 +1,4 @@
|
||||||
|
```release-note:bug
|
||||||
|
ui: request intention listing with ns=* parameter to retrieve all intentions
|
||||||
|
across namespaces
|
||||||
|
```
|
|
@ -2,12 +2,16 @@ import Adapter, { DATACENTER_QUERY_PARAM as API_DATACENTER_KEY } from './applica
|
||||||
import { get } from '@ember/object';
|
import { get } from '@ember/object';
|
||||||
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
|
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
|
||||||
|
|
||||||
// Intentions use SourceNS and DestinationNS properties for namespacing so we
|
// Intentions have different namespacing to the rest of the UI in that the don't
|
||||||
// don't need to add the `?ns=` anywhere here
|
// have a Namespace property, the DestinationNS is essentially its namespace.
|
||||||
|
// Listing of intentions still requires the `ns` query string parameter which
|
||||||
|
// will give us all the intentions that have the `ns` as either the SourceNS or
|
||||||
|
// the DestinationNS.
|
||||||
|
// We currently list intentions by the * wildcard namespace for back compat reasons
|
||||||
|
|
||||||
// TODO: Update to use this.formatDatacenter()
|
// TODO: Update to use this.formatDatacenter()
|
||||||
export default class IntentionAdapter extends Adapter {
|
export default class IntentionAdapter extends Adapter {
|
||||||
requestForQuery(request, { dc, filter, index, uri }) {
|
requestForQuery(request, { dc, ns, filter, index, uri }) {
|
||||||
return request`
|
return request`
|
||||||
GET /v1/connect/intentions?${{ dc }}
|
GET /v1/connect/intentions?${{ dc }}
|
||||||
X-Request-ID: ${uri}${
|
X-Request-ID: ${uri}${
|
||||||
|
@ -18,6 +22,7 @@ export default class IntentionAdapter extends Adapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
${{
|
${{
|
||||||
|
...this.formatNspace('*'),
|
||||||
index,
|
index,
|
||||||
filter,
|
filter,
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -72,7 +72,7 @@ as |api|>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
<DataSource
|
<DataSource
|
||||||
@src={{concat '/' @nspace '/' @dc '/services'}}
|
@src={{concat '/*/' @dc '/services'}}
|
||||||
@onchange={{action this.createServices item}}
|
@onchange={{action this.createServices item}}
|
||||||
/>
|
/>
|
||||||
{{#if (env 'CONSUL_NSPACES_ENABLED')}}
|
{{#if (env 'CONSUL_NSPACES_ENABLED')}}
|
||||||
|
|
|
@ -1,24 +1,30 @@
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import Route from 'consul-ui/routing/route';
|
import Route from 'consul-ui/routing/route';
|
||||||
import { hash } from 'rsvp';
|
|
||||||
|
|
||||||
export default class EditRoute extends Route {
|
export default class EditRoute extends Route {
|
||||||
@service('repository/intention')
|
@service('repository/intention') repo;
|
||||||
repo;
|
@service('env') env;
|
||||||
|
|
||||||
model({ intention_id }, transition) {
|
async model({ intention_id }, transition) {
|
||||||
const dc = this.modelFor('dc').dc.Name;
|
const dc = this.modelFor('dc').dc.Name;
|
||||||
const nspace = '*';
|
const nspace = this.modelFor('nspace').nspace.substr(1);
|
||||||
return hash({
|
|
||||||
dc: dc,
|
let item;
|
||||||
nspace: nspace,
|
if (typeof intention_id !== 'undefined') {
|
||||||
item:
|
item = await this.repo.findBySlug(intention_id, dc, nspace);
|
||||||
typeof intention_id !== 'undefined'
|
} else {
|
||||||
? this.repo.findBySlug(intention_id, dc, nspace)
|
const defaultNspace = this.env.var('CONSUL_NSPACES_ENABLED') ? '*' : 'default';
|
||||||
: this.repo.create({
|
item = await this.repo.create({
|
||||||
Datacenter: dc,
|
SourceNS: nspace || defaultNspace,
|
||||||
}),
|
DestinationNS: nspace || defaultNspace,
|
||||||
});
|
Datacenter: dc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
dc,
|
||||||
|
nspace,
|
||||||
|
item,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
setupController(controller, model) {
|
setupController(controller, model) {
|
||||||
|
|
|
@ -17,7 +17,7 @@ export default class IndexRoute extends Route {
|
||||||
model(params) {
|
model(params) {
|
||||||
return {
|
return {
|
||||||
dc: this.modelFor('dc').dc.Name,
|
dc: this.modelFor('dc').dc.Name,
|
||||||
nspace: this.modelFor('nspace').nspace.substr(1) || 'default',
|
nspace: this.modelFor('nspace').nspace.substr(1),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ export default class RepositoryService extends Service {
|
||||||
if (dc === meta.dc) {
|
if (dc === meta.dc) {
|
||||||
if (checkNspace) {
|
if (checkNspace) {
|
||||||
const nspace = get(item, 'Namespace');
|
const nspace = get(item, 'Namespace');
|
||||||
if (nspace !== meta.namespace) {
|
if (typeof nspace !== 'undefined' && nspace !== meta.nspace) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,51 @@ Feature: dc / intentions / create: Intention Create
|
||||||
In order to define intentions
|
In order to define intentions
|
||||||
As a user
|
As a user
|
||||||
I want to visit the intention create page, fill in the form and hit the create button and see a success notification
|
I want to visit the intention create page, fill in the form and hit the create button and see a success notification
|
||||||
Scenario:
|
@onlyNamespaceable
|
||||||
|
Scenario: with namespaces enabled
|
||||||
|
Given 1 datacenter model with the value "datacenter"
|
||||||
|
And 3 service models from yaml
|
||||||
|
---
|
||||||
|
- Name: web
|
||||||
|
Kind: ~
|
||||||
|
- Name: db
|
||||||
|
Kind: ~
|
||||||
|
- Name: cache
|
||||||
|
Kind: ~
|
||||||
|
---
|
||||||
|
When I visit the intention page for yaml
|
||||||
|
---
|
||||||
|
dc: datacenter
|
||||||
|
---
|
||||||
|
Then the url should be /datacenter/intentions/create
|
||||||
|
And the title should be "New Intention - Consul"
|
||||||
|
# Set source
|
||||||
|
And I click "[data-test-source-element] .ember-power-select-trigger"
|
||||||
|
And I type "web" into ".ember-power-select-search-input"
|
||||||
|
And I click ".ember-power-select-option:first-child"
|
||||||
|
Then I see the text "web" in "[data-test-source-element] .ember-power-select-selected-item"
|
||||||
|
# Set destination
|
||||||
|
And I click "[data-test-destination-element] .ember-power-select-trigger"
|
||||||
|
And I type "db" into ".ember-power-select-search-input"
|
||||||
|
And I click ".ember-power-select-option:first-child"
|
||||||
|
Then I see the text "db" in "[data-test-destination-element] .ember-power-select-selected-item"
|
||||||
|
# Specifically set deny
|
||||||
|
And I click "[value=deny]"
|
||||||
|
And I submit
|
||||||
|
# TODO: When namespace is empty we expect *
|
||||||
|
# Then a PUT request was made to "/v1/connect/intentions/exact?source=@namespace%2Fweb&destination=@namespace%2Fdb&dc=datacenter" from yaml
|
||||||
|
# ---
|
||||||
|
# body:
|
||||||
|
# SourceName: web
|
||||||
|
# DestinationName: db
|
||||||
|
# Action: deny
|
||||||
|
# ---
|
||||||
|
Then the url should be /datacenter/intentions
|
||||||
|
And the title should be "Intentions - Consul"
|
||||||
|
And "[data-notification]" has the "notification-update" class
|
||||||
|
And "[data-notification]" has the "success" class
|
||||||
|
@notNamespaceable
|
||||||
|
Scenario: with namespaces disabled
|
||||||
Given 1 datacenter model with the value "datacenter"
|
Given 1 datacenter model with the value "datacenter"
|
||||||
And 3 service models from yaml
|
And 3 service models from yaml
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,17 +1,35 @@
|
||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
import { setupTest } from 'ember-qunit';
|
import { setupTest } from 'ember-qunit';
|
||||||
|
import getNspaceRunner from 'consul-ui/tests/helpers/get-nspace-runner';
|
||||||
|
|
||||||
|
const nspaceRunner = getNspaceRunner('intention');
|
||||||
|
|
||||||
module('Integration | Adapter | intention', function(hooks) {
|
module('Integration | Adapter | intention', function(hooks) {
|
||||||
setupTest(hooks);
|
setupTest(hooks);
|
||||||
const dc = 'dc-1';
|
const dc = 'dc-1';
|
||||||
const id = 'SourceNS:SourceName:DestinationNS:DestinationName';
|
const id = 'SourceNS:SourceName:DestinationNS:DestinationName';
|
||||||
test('requestForQuery returns the correct url', function(assert) {
|
test('requestForQuery returns the correct url', function(assert) {
|
||||||
const adapter = this.owner.lookup('adapter:intention');
|
return nspaceRunner(
|
||||||
const client = this.owner.lookup('service:client/http');
|
(adapter, serializer, client) => {
|
||||||
const expected = `GET /v1/connect/intentions?dc=${dc}`;
|
return adapter.requestForQuery(client.body, {
|
||||||
const actual = adapter.requestForQuery(client.requestParams.bind(client), {
|
dc: dc,
|
||||||
dc: dc,
|
ns: 'team-1',
|
||||||
});
|
filter: '*',
|
||||||
assert.equal(`${actual.method} ${actual.url}`, expected);
|
index: 1,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filter: '*',
|
||||||
|
index: 1,
|
||||||
|
ns: '*',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filter: '*',
|
||||||
|
index: 1,
|
||||||
|
},
|
||||||
|
this,
|
||||||
|
assert
|
||||||
|
);
|
||||||
});
|
});
|
||||||
test('requestForQueryRecord returns the correct url', function(assert) {
|
test('requestForQueryRecord returns the correct url', function(assert) {
|
||||||
const adapter = this.owner.lookup('adapter:intention');
|
const adapter = this.owner.lookup('adapter:intention');
|
||||||
|
|
|
@ -102,7 +102,7 @@ export default function({
|
||||||
visit(library, pages, utils.setCurrentPage, reset);
|
visit(library, pages, utils.setCurrentPage, reset);
|
||||||
click(library, utils.find, helpers.click);
|
click(library, utils.find, helpers.click);
|
||||||
form(library, utils.find, helpers.fillIn, helpers.triggerKeyEvent, utils.getCurrentPage);
|
form(library, utils.find, helpers.fillIn, helpers.triggerKeyEvent, utils.getCurrentPage);
|
||||||
debug(library, assert, utils.currentURL);
|
debug(library, assert, helpers.currentURL);
|
||||||
assertHttp(library, assert, lastNthRequest);
|
assertHttp(library, assert, lastNthRequest);
|
||||||
assertModel(library, assert, utils.find, utils.getCurrentPage, pauseUntil, pluralize);
|
assertModel(library, assert, utils.find, utils.getCurrentPage, pauseUntil, pluralize);
|
||||||
assertPage(library, assert, utils.find, utils.getCurrentPage, $);
|
assertPage(library, assert, utils.find, utils.getCurrentPage, $);
|
||||||
|
|
Loading…
Reference in New Issue