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/transform sidebranch #9665

Merged
merged 22 commits into from
Aug 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ecc83ef
Ui/transform enable (#9647)
chelshaw Jul 31, 2020
60e551f
Sidebranch: Transform Secret Engine Initial setup (#9625)
Monkeychip Jul 31, 2020
3f17db4
Merge branch 'master' into ui/transform-sidebranch
chelshaw Aug 5, 2020
ad57a3c
Ui/transform language fixes (#9666)
chelshaw Aug 10, 2020
5b3282e
Ui/create edit transformation fixes (#9668)
Monkeychip Aug 11, 2020
978cdfd
Merge branch 'master' into ui/transform-sidebranch
chelshaw Aug 17, 2020
716e9a4
Sidebranch: UI transform create and edit clean up (#9778)
Monkeychip Aug 19, 2020
12f6dee
Merge branch 'master' into ui/transform-sidebranch
chelshaw Aug 19, 2020
2cc7eb9
Merge branch 'master' into ui/transform-sidebranch
chelshaw Aug 20, 2020
9939a85
Ui/fix list roles transformation (#9788)
chelshaw Aug 20, 2020
f4a93bb
Ui/transform cleanup 2 (#9789)
Monkeychip Aug 20, 2020
9dcd886
Show KMIP un-selectable if enterprise but no ADP module (#9780)
chelshaw Aug 20, 2020
9b548a3
Merge branch 'master' into ui/transform-sidebranch
chelshaw Aug 20, 2020
c6e2560
New component transform-edit-base
chelshaw Aug 24, 2020
f595ed8
Duplicate RoleEdit as TransformEditBase and swap in all transform com…
chelshaw Aug 24, 2020
711d6ab
Roll back role-edit changes
chelshaw Aug 24, 2020
93a2752
Update to transform edit base
chelshaw Aug 24, 2020
19bc619
Remove extraeneous set backend type on transform components
chelshaw Aug 24, 2020
d79c481
formatting
chelshaw Aug 24, 2020
dc0c579
Revert search-select changes
chelshaw Aug 26, 2020
216d1a5
Update template/templates data on transformation (#9838)
chelshaw Aug 26, 2020
9353d56
Merge branch 'master' into ui/transform-sidebranch
chelshaw Aug 26, 2020
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
98 changes: 98 additions & 0 deletions ui/app/adapters/transform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { assign } from '@ember/polyfills';
import { allSettled } from 'rsvp';
import ApplicationAdapter from './application';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default ApplicationAdapter.extend({
namespace: 'v1',

createOrUpdate(store, type, snapshot) {
const serializer = store.serializerFor(type.modelName);
const data = serializer.serialize(snapshot);
const { id } = snapshot;
let url = this.urlForTransformations(snapshot.record.get('backend'), id);

return this.ajax(url, 'POST', { data });
},

createRecord() {
return this.createOrUpdate(...arguments);
},

updateRecord() {
return this.createOrUpdate(...arguments, 'update');
},

deleteRecord(store, type, snapshot) {
const { id } = snapshot;
return this.ajax(this.urlForTransformations(snapshot.record.get('backend'), id), 'DELETE');
},

pathForType() {
return 'transform';
},

urlForTransformations(backend, id) {
let url = `${this.buildURL()}/${encodePath(backend)}/transformation`;
if (id) {
url = url + '/' + encodePath(id);
}
return url;
},

optionsForQuery(id) {
let data = {};
if (!id) {
data['list'] = true;
}
return { data };
},

fetchByQuery(store, query) {
const { id, backend } = query;
const queryAjax = this.ajax(this.urlForTransformations(backend, id), 'GET', this.optionsForQuery(id));

return allSettled([queryAjax]).then(results => {
// query result 404d, so throw the adapterError
if (!results[0].value) {
throw results[0].reason;
}
let resp = {
id,
name: id,
backend,
data: {},
};

results.forEach(result => {
if (result.value) {
if (result.value.data.roles) {
// TODO: Check if this is needed and remove if not
resp.data = assign({}, resp.data, { zero_address_roles: result.value.data.roles });
} else {
let d = result.value.data;
if (d.templates) {
// In Transformations data goes up as "template", but comes down as "templates"
// To keep the keys consistent we're translating here
d = {
...d,
template: [d.templates],
};
delete d.templates;
}
resp.data = assign({}, resp.data, d);
}
}
});
return resp;
});
},

query(store, type, query) {
return this.fetchByQuery(store, query);
},

queryRecord(store, type, query) {
return this.fetchByQuery(store, query);
},
});
25 changes: 25 additions & 0 deletions ui/app/adapters/transform/role.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import ApplicationAdapater from '../application';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default ApplicationAdapater.extend({
namespace: 'v1',

pathForType() {
return 'role';
},

_url(backend, id) {
let type = this.pathForType();
let base = `/v1/${encodePath(backend)}/${type}`;
if (id) {
return `${base}/${encodePath(id)}`;
}
return base + '?list=true';
},

query(store, type, query) {
return this.ajax(this._url(query.backend), 'GET').then(result => {
return result;
});
},
});
25 changes: 25 additions & 0 deletions ui/app/adapters/transform/template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import ApplicationAdapater from '../application';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default ApplicationAdapater.extend({
namespace: 'v1',

pathForType() {
return 'template';
},

_url(backend, id) {
let type = this.pathForType();
let base = `${this.buildURL()}/${encodePath(backend)}/${type}`;
if (id) {
return `${base}/${encodePath(id)}`;
}
return base + '?list=true';
},

query(store, type, query) {
return this.ajax(this._url(query.backend), 'GET').then(result => {
return result;
});
},
});
9 changes: 4 additions & 5 deletions ui/app/components/mount-backend-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { computed } from '@ember/object';
import Component from '@ember/component';
import { task } from 'ember-concurrency';
import { methods } from 'vault/helpers/mountable-auth-methods';
import { engines, KMIP } from 'vault/helpers/mountable-secret-engines';
import { engines, KMIP, TRANSFORM } from 'vault/helpers/mountable-secret-engines';

const METHODS = methods();
const ENGINES = engines();
Expand Down Expand Up @@ -56,11 +56,10 @@ export default Component.extend({
}),

engines: computed('version.features[]', function() {
if (this.version.hasFeature('KMIP')) {
return ENGINES.concat([KMIP]);
} else {
return ENGINES;
if (this.get('version.isEnterprise')) {
return ENGINES.concat([KMIP, TRANSFORM]);
}
return ENGINES;
}),

willDestroy() {
Expand Down
3 changes: 3 additions & 0 deletions ui/app/components/transform-create-form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import TransformBase from './transform-edit-base';

export default TransformBase.extend({});
104 changes: 104 additions & 0 deletions ui/app/components/transform-edit-base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { inject as service } from '@ember/service';
import { or } from '@ember/object/computed';
import { isBlank } from '@ember/utils';
import { task, waitForEvent } from 'ember-concurrency';
import Component from '@ember/component';
import { set, get } from '@ember/object';
import FocusOnInsertMixin from 'vault/mixins/focus-on-insert';
import keys from 'vault/lib/keycodes';

const LIST_ROOT_ROUTE = 'vault.cluster.secrets.backend.list-root';
const SHOW_ROUTE = 'vault.cluster.secrets.backend.show';

export default Component.extend(FocusOnInsertMixin, {
router: service(),
wizard: service(),

mode: null,
// TODO: Investigate if we need all of these
emptyData: '{\n}',
onDataChange() {},
onRefresh() {},
model: null,
requestInFlight: or('model.isLoading', 'model.isReloading', 'model.isSaving'),

init() {
this._super(...arguments);
this.set('backendType', 'transform');
},

willDestroyElement() {
this._super(...arguments);
if (this.model && this.model.isError) {
this.model.rollbackAttributes();
}
},

waitForKeyUp: task(function*() {
while (true) {
let event = yield waitForEvent(document.body, 'keyup');
this.onEscape(event);
}
})
.on('didInsertElement')
.cancelOn('willDestroyElement'),

transitionToRoute() {
this.get('router').transitionTo(...arguments);
},

onEscape(e) {
if (e.keyCode !== keys.ESC || this.get('mode') !== 'show') {
return;
}
this.transitionToRoute(LIST_ROOT_ROUTE);
},

hasDataChanges() {
get(this, 'onDataChange')(get(this, 'model.hasDirtyAttributes'));
},

persist(method, successCallback) {
const model = get(this, 'model');
return model[method]().then(() => {
if (!get(model, 'isError')) {
if (this.get('wizard.featureState') === 'role') {
this.get('wizard').transitionFeatureMachine('role', 'CONTINUE', this.get('backendType'));
}
successCallback(model);
}
});
},

actions: {
createOrUpdate(type, event) {
event.preventDefault();
const modelId = this.get('model.id') || this.get('model.name'); // transform comes in as model.name
// prevent from submitting if there's no key
// maybe do something fancier later
if (type === 'create' && isBlank(modelId)) {
return;
}

this.persist('save', () => {
this.hasDataChanges();
this.transitionToRoute(SHOW_ROUTE, modelId);
});
},

setValue(key, event) {
set(get(this, 'model'), key, event.target.checked);
},

refresh() {
this.get('onRefresh')();
},

delete() {
this.persist('destroyRecord', () => {
this.hasDataChanges();
this.transitionToRoute(LIST_ROOT_ROUTE);
});
},
},
});
3 changes: 3 additions & 0 deletions ui/app/components/transform-edit-form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import TransformBase from './transform-edit-base';

export default TransformBase.extend({});
3 changes: 3 additions & 0 deletions ui/app/components/transform-show-transformation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import TransformBase from './transform-edit-base';

export default TransformBase.extend({});
3 changes: 3 additions & 0 deletions ui/app/components/transformation-edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import TransformBase from './transform-edit-base';

export default TransformBase.extend({});
9 changes: 9 additions & 0 deletions ui/app/helpers/mountable-secret-engines.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ export const KMIP = {
value: 'kmip',
type: 'kmip',
category: 'generic',
requiredFeature: 'KMIP',
};

export const TRANSFORM = {
displayName: 'Transform',
value: 'transform',
type: 'transform',
category: 'generic',
requiredFeature: 'Transform Secrets Engine',
};

const MOUNTABLE_SECRET_ENGINES = [
Expand Down
49 changes: 49 additions & 0 deletions ui/app/helpers/options-for-backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,55 @@ const SECRET_BACKENDS = {
editComponent: 'role-ssh-edit',
listItemPartial: 'partials/secret-list/ssh-role-item',
},
transform: {
displayName: 'Transformation',
navigateTree: false,
listItemPartial: 'partials/secret-list/transform-transformation-item',
tabs: [
{
name: 'transformations',
label: 'Transformations',
searchPlaceholder: 'Filter transformations',
item: 'transformation',
create: 'Create transformation',
editComponent: 'transformation-edit',
},
// TODO: Add tabs as needed
// {
// name: 'roles',
// modelPrefix: 'role/',
// label: 'Roles',
// searchPlaceholder: 'Filter roles',
// item: 'roles',
// create: 'Create role',
// tab: 'role',
// listItemPartial: 'partials/secret-list/item',
// editComponent: 'transform-role-edit',
// },
// {
// name: 'templates',
// modelPrefix: 'template/',
// label: 'Templates',
// searchPlaceholder: 'Filter templates',
// item: 'templates',
// create: 'Create template',
// tab: 'template',
// listItemPartial: 'partials/secret-list/item',
// editComponent: 'transform-template-edit',
// },
// {
// name: 'alphabets',
// modelPrefix: 'alphabet/',
// label: 'Alphabets',
// searchPlaceholder: 'Filter alphabets',
// item: 'alphabets',
// create: 'Create alphabet',
// tab: 'alphabet',
// listItemPartial: 'partials/secret-list/item',
// editComponent: 'alphabet-edit',
// },
],
},
transit: {
searchPlaceholder: 'Filter keys',
item: 'key',
Expand Down
12 changes: 11 additions & 1 deletion ui/app/helpers/supported-secret-backends.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import { helper as buildHelper } from '@ember/component/helper';

const SUPPORTED_SECRET_BACKENDS = ['aws', 'cubbyhole', 'generic', 'kv', 'pki', 'ssh', 'transit', 'kmip'];
const SUPPORTED_SECRET_BACKENDS = [
'aws',
'cubbyhole',
'generic',
'kv',
'pki',
'ssh',
'transit',
'kmip',
'transform',
];

export function supportedSecretBackends() {
return SUPPORTED_SECRET_BACKENDS;
Expand Down
Loading