Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui: Namespace Support #6639

Merged
merged 61 commits into from
Dec 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
404fbc4
Add `ns=` query parameter to all adapters that require it also..
Oct 17, 2019
73f4d29
Add adapter tests for new `ns=` query parameter
Oct 17, 2019
61a4d3e
Add Namespace to models and their serializers where required (inc uid)
Oct 17, 2019
c56b9ac
Add serializer tests for new Namespace property and uid
Oct 17, 2019
db852e8
Add nspace model layer (adapter, serializer, model, repo)
Oct 17, 2019
4f00dc3
Add nspace model layer tests
Oct 17, 2019
24e9ffe
Add seom missed model layer tests
Oct 17, 2019
0dbcc4e
Add notion of nspaces to repos and routes that need them
Oct 17, 2019
8800e09
Amend repo integration tests to add nspaces
Oct 17, 2019
8167ada
Add all the things to deal with inserting a new route in the middle
Oct 17, 2019
3bd18d6
Make intentions aware of namespacing
Oct 17, 2019
3e21667
Make upstreams aware of namespacing
Oct 17, 2019
6fde689
CSS amends related to making upstreams and intentions namespace aware
Oct 17, 2019
2c9445e
Add nspace menu into the main nav header, refactor the old dc menu also
Oct 17, 2019
eb08c1f
CSS additions related to refactoring out dc menu and reusing for nspaces
Oct 17, 2019
822f426
CSS for showing namespaces in the Composite Rows (upstreams, intentions)
Oct 17, 2019
b694b77
Test for specific nspace/or helper
Oct 17, 2019
1a6b923
Add all the sub things required for nspace crud
Oct 17, 2019
8e065c8
Nspace CRUD
Oct 17, 2019
373dd78
CSS required for nspace CRUD
Oct 17, 2019
4530d41
Config to let us turn nspaces on and off (WIP)
Oct 17, 2019
a15bda9
Fix an ember-data missing AdapterError by using the new org structure
Oct 17, 2019
1a889cc
Enable blocking queries for nspaces
Oct 17, 2019
6459a8c
Tweak DOM text assertion
Oct 17, 2019
0f362f7
Add a URL assertion step to be able to loosen up asserting lots of URLs
Oct 17, 2019
3aca683
Loosen up the page-navigtion scenario and include nspaces
Oct 17, 2019
4f124fe
Adds notion of nspaces to all of the acceptence tests (no nspace tests)
Oct 17, 2019
f279418
Adds the dependencies and mock updates for tests to work
Oct 17, 2019
29dcf06
Give nspaces a SyncTime so we can reconcile nspaces with the backend
Oct 28, 2019
8844a25
If we can't find a namespace then right now you are in default (pre ACL)
Oct 28, 2019
a89825f
If you only have access to one namespace, then that is the one you're in
Oct 28, 2019
d6a899f
Set up ACL enabled detection from index.html instead of error code
Oct 28, 2019
3c4ffc4
Visual work mainly around the namespace menu
Oct 28, 2019
73c9a83
Prevent duplicating nspaces with ember data
Oct 28, 2019
d876982
Make sure policy and role selectors use nspacing
Nov 8, 2019
f694ff3
Redirect the user to the origin nspace of the authorized ACL
Nov 8, 2019
edd83b6
Ensure the current nspace is shown on the settings page
Nov 14, 2019
9961ada
Lint
Nov 18, 2019
f929130
Ensure we always have a nspace even if the saved on doesn't exist
Nov 18, 2019
8181a90
Add missed `this.` for repo
Nov 18, 2019
23611c8
ui: Fixes DC switching when blocking queries are enabled (#6808)
johncowen Nov 19, 2019
a670804
Ensure both dc and nspace menus are refreshed on page change
Nov 19, 2019
9ad76f7
Set things up ready for a temporary feature flag for managing nspaces
Nov 19, 2019
f8adc3f
Restrict nspace refreshing to the create action to avoid jittery menu
Nov 19, 2019
600e379
Fix up some existing tests
Nov 19, 2019
6dab00d
Add nspace form validation plus some extra copy
Nov 22, 2019
1c1107c
Tweak validation for unneccessary `-`
Nov 25, 2019
a6d0d23
Upgrade consul-api-double to include a namespace for certain items
Nov 26, 2019
b0eeb59
Be extra careful to check the nspace when reconciling
Nov 26, 2019
7933df7
Remove most of the drop-nav styles now we have %menu-panel
Nov 26, 2019
1a9a1fc
ui: Adds `href-mut` helper for modifying current URLs (#6799)
johncowen Nov 26, 2019
c2df164
Finish up the href-mut stuff with nspace support
Nov 26, 2019
5362932
Add menu headers
Nov 26, 2019
7fe5811
Improve tabability of {{toggle-button}}
Nov 28, 2019
10215ab
ui: Tweak the icons in the menu bar (inverted tick and mobile dots)
Nov 29, 2019
885e98e
Amend confusing comment
Dec 11, 2019
f649d06
Add TODO comment for a reminder to change the rem's
Dec 12, 2019
619c0a7
Tweak some CSS selectors as a result of a rebase, tweak menu padding
Dec 12, 2019
fce23da
Fix up erroneous rebase
Dec 12, 2019
871db69
ui: Namespace authorization integration (#6933)
johncowen Dec 17, 2019
fd421ff
ui: Keyboard-ize main navigation menu (#6941)
johncowen Dec 17, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ui-v2/app/adapters/acl.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import Adapter, { DATACENTER_QUERY_PARAM as API_DATACENTER_KEY } from './applica
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 Adapter.extend({
requestForQuery: function(request, { dc, index }) {
// https://www.consul.io/api/acl.html#list-acls
Expand Down
12 changes: 12 additions & 0 deletions ui-v2/app/adapters/application.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import Adapter from './http';
import { inject as service } from '@ember/service';
import config from 'consul-ui/config/environment';

export const DATACENTER_QUERY_PARAM = 'dc';
export const NSPACE_QUERY_PARAM = 'ns';
export default Adapter.extend({
repo: service('settings'),
client: service('client/http'),
formatNspace: function(nspace) {
if (config.CONSUL_NSPACES_ENABLED) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the enterprise binary write this value?

Copy link
Contributor Author

@johncowen johncowen Dec 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will do at somepoint yeah, I think for now we can just use our CONSUL_BINARY_TYPE setting that we already have - I think this specific NSPACE one is going to be added later. Potentially a PR coming after this one to temporarily use the CONSUL_BINARY_TYPE setting (which the binary writes already)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been PRed now, see #6921 (backend support) and #6933 (using these values properly)

return nspace !== '' ? { [NSPACE_QUERY_PARAM]: nspace } : undefined;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this need to be url encoded? wasn't sure if request does that for you or not

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah request encodes every variable you pass inside the template literals, both keys and values.

Copy link
Contributor Author

@johncowen johncowen Dec 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't strictly correct 😁 . Basically its not request that does it its ember-data/jQuery.

When writing the template literal any variables used in the URL itself is encoded. Then any body used in anything other that a GET request is sent as JSON encoded.

A GET request with a body is a little special and follows the old ember-data adapter functionality, in that any body with a GET request gets moved to the GET params (as you can't send a body with a GET request). Under the hood ember-data relied on jQuery to do this and when we did our data layer refactor we tried to replicate this functionality completely, you can see it here with a comment on urlencoding https://github.com/hashicorp/consul/pull/5637/files#diff-d12a13b0f2b1e3556993c370c1ee3ddfR182.

I've just double checked this and it does get url encoded, but we are also protected somewhat by the fact that namespaces can only have DNS compatible names, and therefore probably don't need url encoding anyhow

}
},
formatDatacenter: function(dc) {
return {
[DATACENTER_QUERY_PARAM]: dc,
};
},
// TODO: kinda protected for the moment
// decide where this should go either read/write from http
// should somehow use this or vice versa
Expand Down
1 change: 1 addition & 0 deletions ui-v2/app/adapters/coordinate.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Adapter from './application';
// TODO: Update to use this.formatDatacenter()
export default Adapter.extend({
requestForQuery: function(request, { dc, index }) {
return request`
Expand Down
3 changes: 1 addition & 2 deletions ui-v2/app/adapters/http.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Adapter from 'ember-data/adapter';
import AdapterError from '@ember-data/adapter/error';
import {
AbortError,
TimeoutError,
Expand All @@ -8,9 +9,7 @@ import {
NotFoundError,
ConflictError,
InvalidError,
AdapterError,
} from 'ember-data/adapters/errors';

// TODO: This is a little skeleton cb function
// is to be replaced soon with something slightly more involved
const responder = function(response) {
Expand Down
24 changes: 22 additions & 2 deletions ui-v2/app/adapters/intention.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
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

// TODO: Update to use this.formatDatacenter()
export default Adapter.extend({
requestForQuery: function(request, { dc, index, id }) {
return request`
Expand All @@ -24,14 +28,30 @@ export default Adapter.extend({
return request`
POST /v1/connect/intentions?${{ [API_DATACENTER_KEY]: data[DATACENTER_KEY] }}

${serialized}
${{
SourceNS: serialized.SourceNS,
DestinationNS: serialized.DestinationNS,
SourceName: serialized.SourceName,
DestinationName: serialized.DestinationName,
SourceType: serialized.SourceType,
Action: serialized.Action,
Description: serialized.Description,
}}
`;
},
requestForUpdateRecord: function(request, serialized, data) {
return request`
PUT /v1/connect/intentions/${data[SLUG_KEY]}?${{ [API_DATACENTER_KEY]: data[DATACENTER_KEY] }}

${serialized}
${{
SourceNS: serialized.SourceNS,
DestinationNS: serialized.DestinationNS,
SourceName: serialized.SourceName,
DestinationName: serialized.DestinationName,
SourceType: serialized.SourceType,
Action: serialized.Action,
Description: serialized.Description,
}}
`;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means we can easily prevent certain props/values from being sent in a request, and means we can get rid of our custom writable function. We only did it for intentions for now as we were there, but we'll probably remove elsewhere in another PR and eventually delete our custom writable. You'll see us removing this for the intentions model/serializer further down.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you use serializer at all with the new adapter? Just curious as in out-of-the-box ember data, that's where this would be done.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use our old style ApplicationSerializer, but we don't normalize anything there, the serializer deals with all the HTTP header bits still but not a lot else. Long term we hope to move everything to this style of normalization as its a easier to see whats happening, and looks exactly like the Consul API documentation, um more notes here:

#6285

We still plan on a similar refactoring of our Serializers (similar to what we did for our Adapters) for response serializing, just its not high on the priority list right now, it might happen pre-1.8 or something.

},
requestForDeleteRecord: function(request, serialized, data) {
Expand Down
40 changes: 29 additions & 11 deletions ui-v2/app/adapters/kv.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,62 @@
import Adapter, { DATACENTER_QUERY_PARAM as API_DATACENTER_KEY } from './application';
import Adapter from './application';

import isFolder from 'consul-ui/utils/isFolder';
import keyToArray from 'consul-ui/utils/keyToArray';

import { SLUG_KEY } from 'consul-ui/models/kv';
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
import { NSPACE_KEY } from 'consul-ui/models/nspace';

// TODO: Update to use this.formatDatacenter()
const API_KEYS_KEY = 'keys';
export default Adapter.extend({
requestForQuery: function(request, { dc, index, id, separator }) {
requestForQuery: function(request, { dc, ns, index, id, separator }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
return request`
GET /v1/kv/${keyToArray(id)}?${{ [API_KEYS_KEY]: null, dc, separator }}

${{ index }}
${{
...this.formatNspace(ns),
index,
}}
`;
},
requestForQueryRecord: function(request, { dc, index, id }) {
requestForQueryRecord: function(request, { dc, ns, index, id }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
return request`
GET /v1/kv/${keyToArray(id)}?${{ dc }}

${{ index }}
${{
...this.formatNspace(ns),
index,
}}
`;
},
// TODO: Should we replace text/plain here with x-www-form-encoded?
// See https://github.com/hashicorp/consul/issues/3804
requestForCreateRecord: function(request, serialized, data) {
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatNspace(data[NSPACE_KEY]),
};
return request`
PUT /v1/kv/${keyToArray(data[SLUG_KEY])}?${{ [API_DATACENTER_KEY]: data[DATACENTER_KEY] }}
PUT /v1/kv/${keyToArray(data[SLUG_KEY])}?${params}
Content-Type: text/plain; charset=utf-8

${serialized}
`;
},
requestForUpdateRecord: function(request, serialized, data) {
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatNspace(data[NSPACE_KEY]),
};
return request`
PUT /v1/kv/${keyToArray(data[SLUG_KEY])}?${{ [API_DATACENTER_KEY]: data[DATACENTER_KEY] }}
PUT /v1/kv/${keyToArray(data[SLUG_KEY])}?${params}
Content-Type: text/plain; charset=utf-8

${serialized}
Expand All @@ -51,11 +67,13 @@ export default Adapter.extend({
if (isFolder(data[SLUG_KEY])) {
recurse = null;
}
return request`
DELETE /v1/kv/${keyToArray(data[SLUG_KEY])}?${{
[API_DATACENTER_KEY]: data[DATACENTER_KEY],
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatNspace(data[NSPACE_KEY]),
recurse,
}}
};
return request`
DELETE /v1/kv/${keyToArray(data[SLUG_KEY])}?${params}
`;
},
});
1 change: 1 addition & 0 deletions ui-v2/app/adapters/node.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Adapter from './application';
// TODO: Update to use this.formatDatacenter()
export default Adapter.extend({
requestForQuery: function(request, { dc, index, id }) {
return request`
Expand Down
82 changes: 82 additions & 0 deletions ui-v2/app/adapters/nspace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import Adapter from './application';
import { SLUG_KEY } from 'consul-ui/models/nspace';

// namespaces aren't categorized by datacenter, therefore no dc
export default Adapter.extend({
requestForQuery: function(request, { index }) {
return request`
GET /v1/namespaces

${{ index }}
`;
},
requestForQueryRecord: function(request, { index, id }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an name');
}
return request`
GET /v1/namespace/${id}

${{ index }}
`;
},
requestForCreateRecord: function(request, serialized, data) {
return request`
PUT /v1/namespace/${data[SLUG_KEY]}

${{
Name: serialized.Name,
Description: serialized.Description,
ACLs: {
PolicyDefaults: serialized.ACLs.PolicyDefaults.map(item => ({ ID: item.ID })),
RoleDefaults: serialized.ACLs.RoleDefaults.map(item => ({ ID: item.ID })),
},
}}
`;
},
requestForUpdateRecord: function(request, serialized, data) {
return request`
PUT /v1/namespace/${data[SLUG_KEY]}

${{
Description: serialized.Description,
ACLs: {
PolicyDefaults: serialized.ACLs.PolicyDefaults.map(item => ({ ID: item.ID })),
RoleDefaults: serialized.ACLs.RoleDefaults.map(item => ({ ID: item.ID })),
},
}}
`;
},
requestForDeleteRecord: function(request, serialized, data) {
return request`
DELETE /v1/namespace/${data[SLUG_KEY]}
`;
},
requestForAuthorize: function(request, { dc, ns, index }) {
return request`
POST /v1/internal/acl/authorize?${{ dc, ns, index }}

${[
{
Resource: 'operator',
Access: 'write',
},
]}
`;
},
authorize: function(store, type, id, snapshot) {
return this.request(
function(adapter, request, serialized, unserialized) {
return adapter.requestForAuthorize(request, serialized, unserialized);
},
function(serializer, respond, serialized, unserialized) {
// Completely skip the serializer here
return respond(function(headers, body) {
return body;
});
},
snapshot,
type.modelName
);
},
});
36 changes: 28 additions & 8 deletions ui-v2/app/adapters/policy.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
import Adapter, { DATACENTER_QUERY_PARAM as API_DATACENTER_KEY } from './application';
import Adapter from './application';

import { SLUG_KEY } from 'consul-ui/models/policy';
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
import { NSPACE_KEY } from 'consul-ui/models/nspace';

// TODO: Update to use this.formatDatacenter()
export default Adapter.extend({
requestForQuery: function(request, { dc, index, id }) {
requestForQuery: function(request, { dc, ns, index, id }) {
return request`
GET /v1/acl/policies?${{ dc }}

${{ index }}
${{
...this.formatNspace(ns),
index,
}}
`;
},
requestForQueryRecord: function(request, { dc, index, id }) {
requestForQueryRecord: function(request, { dc, ns, index, id }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
return request`
GET /v1/acl/policy/${id}?${{ dc }}

${{ index }}
${{
...this.formatNspace(ns),
index,
}}
`;
},
requestForCreateRecord: function(request, serialized, data) {
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatNspace(data[NSPACE_KEY]),
};
return request`
PUT /v1/acl/policy?${{ [API_DATACENTER_KEY]: data[DATACENTER_KEY] }}
PUT /v1/acl/policy?${params}

${{
Name: serialized.Name,
Expand All @@ -34,8 +46,12 @@ export default Adapter.extend({
`;
},
requestForUpdateRecord: function(request, serialized, data) {
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatNspace(data[NSPACE_KEY]),
};
return request`
PUT /v1/acl/policy/${data[SLUG_KEY]}?${{ [API_DATACENTER_KEY]: data[DATACENTER_KEY] }}
PUT /v1/acl/policy/${data[SLUG_KEY]}?${params}

${{
Name: serialized.Name,
Expand All @@ -46,8 +62,12 @@ export default Adapter.extend({
`;
},
requestForDeleteRecord: function(request, serialized, data) {
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatNspace(data[NSPACE_KEY]),
};
return request`
DELETE /v1/acl/policy/${data[SLUG_KEY]}?${{ [API_DATACENTER_KEY]: data[DATACENTER_KEY] }}
DELETE /v1/acl/policy/${data[SLUG_KEY]}?${params}
`;
},
});
8 changes: 6 additions & 2 deletions ui-v2/app/adapters/proxy.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import Adapter from './application';
// TODO: Update to use this.formatDatacenter()
export default Adapter.extend({
requestForQuery: function(request, { dc, index, id }) {
requestForQuery: function(request, { dc, ns, index, id }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
return request`
GET /v1/catalog/connect/${id}?${{ dc }}

${{ index }}
${{
...this.formatNspace(ns),
index,
}}
`;
},
});
Loading