Merge pull request #929 from hashicorp/chore-unknown-type

Add support for "unknown" dynamic host catalogs
This commit is contained in:
Randall Morey authored and GitHub committed 2022-01-28 11:46:34 -05:00
commit cd71c53ff2
9 files changed
+144 -47

No files matched your search

@@ -0,0 +1,16 @@
import ModelAbility from './model';
/**
* Provides abilities for host catalogs.
*/
export default class HostCatalogAbility extends ModelAbility {
// =permissions
/**
* Only "known" host catalog types may be read.
* @type {boolean}
*/
get canRead() {
return !this.model.isUnknown && this.hasAuthorizedAction('read');
}
}
+24 -8
View File
@@ -1,8 +1,12 @@
import GeneratedHostCatalogModel from '../generated/models/host-catalog';
export const types = ['aws', 'azure'];
export default class HostCatalogModel extends GeneratedHostCatalogModel {
// =attributes
/**
* Returns if the host-catalog is static type or not.
* True if the host catalog is static.
* @type {boolean}
*/
get isStatic() {
@@ -10,7 +14,7 @@ export default class HostCatalogModel extends GeneratedHostCatalogModel {
}
/**
* Returns if the host-catalog is a plugin or not.
* True if the host catalog is a plugin.
* @type {boolean}
*/
get isPlugin() {
@@ -18,7 +22,15 @@ export default class HostCatalogModel extends GeneratedHostCatalogModel {
}
/**
* Returns if host-catalog plugin is AWS or not
* True if the host catalog is an unknown type.
* @type {boolean}
*/
get isUnknown() {
return this.isPlugin && !types.includes(this.plugin.name);
}
/**
* True if host catalog plugin type is AWS.
* @type {boolean}
*/
get isAWS() {
@@ -26,23 +38,27 @@ export default class HostCatalogModel extends GeneratedHostCatalogModel {
}
/**
* Return if host-catalog plugin is Azure or not.
* True if host catalog plugin type is Azure.
* @type {boolean}
*/
get isAzure() {
return this.compositeType === 'azure';
}
/** If host-catalog is a plugins returns its name,
* otherwise returns the host-catalog type
/**
* If host catalog is a plugin return `plugin.name`,
* otherwise return the host catalog type.
* @type {string}
*/
get compositeType() {
return this.isPlugin ? this.plugin.name : this.type;
if (this.isUnknown) return 'unknown';
if (this.isPlugin) return this.plugin.name;
return 'static';
}
/**
* Sets type, if type is different than static, sets plugin name to type
* Sets `type`. If type is different than `static`, sets `type` to `plugin`
* and `plugin.name` to the specified type.
*/
set compositeType(type) {
if (type === 'static') {
+1
View File
@@ -0,0 +1 @@
export { default } from 'api/abilities/host-catalog';
+24 -1
View File
@@ -1,7 +1,14 @@
import factory from '../generated/factories/host-catalog';
import { trait } from 'ember-cli-mirage';
import permissions from '../helpers/permissions';
import { datatype, address } from 'faker';
import { datatype, address, random } from 'faker';
const types = ['static', 'plugin'];
// Represents known plugin types, except "foobar" which models the possibility
// of receiving an _unknown_ type, which the UI must handle gracefully.
const pluginTypes = ['aws', 'azure', 'foobar'];
let pluginTypeCounter = 1;
export default factory.extend({
authorized_actions: () =>
@@ -17,6 +24,22 @@ export default factory.extend({
'host-sets': ['create', 'list'],
};
},
id: (i) => `host-catalog-id-${i}`,
// Cycle through available types
type: (i) => types[i % types.length],
plugin: function (i) {
if (this.type === 'plugin') {
return {
id: `plugin-id-${i}`,
name: pluginTypes[pluginTypeCounter++ % pluginTypes.length],
description: random.words(),
};
}
},
attributes() {
switch (this.plugin?.name) {
case 'aws':
@@ -5,19 +5,10 @@ import { random, date, datatype } from 'faker';
* GeneratedHostCatalogModelFactory
*/
export default Factory.extend({
type: () => random.arrayElement(['static', 'plugin']),
type: 'static',
name: () => random.words(),
description: () => random.words(),
created_time: () => date.recent(),
updated_time: () => date.recent(),
disabled: () => datatype.boolean(),
plugin: function (i) {
if (this.type == 'plugin') {
return {
id: `pl_${datatype.hexaDecimal(5)}`,
name: i % 2 ? 'aws' : 'azure',
description: random.words(),
};
}
},
});
+1 -1
View File
@@ -46,7 +46,7 @@ export default function (server) {
// Other resources
server.schema.scopes.where({ type: 'project' }).models.forEach((scope) => {
server.createList('host-catalog', 4, { scope }, 'withChildren');
server.createList('host-catalog', 8, { scope }, 'withChildren');
server.createList('credential-store', 3, { scope }, 'withAssociations');
server.createList('target', 2, { scope }, 'withAssociations');
// Sessions have target data. Create it after targets.
@@ -10,29 +10,52 @@ module('Unit | Model | host catalog', function (hooks) {
assert.ok(model);
});
test('it has isStatic function and returns the expected values', async function (assert) {
test('it has isStatic property and returns the expected values', async function (assert) {
assert.expect(3);
const store = this.owner.lookup('service:store');
const modelA = store.createRecord('host-catalog', { type: 'static' });
const modelB = store.createRecord('host-catalog', { type: 'plugin' });
assert.equal(typeof modelA.isStatic, 'boolean');
assert.true(modelA.isStatic);
const modelA = store.createRecord('host-catalog', { compositeType: 'aws' });
const modelB = store.createRecord('host-catalog', {
compositeType: 'foobar',
});
const modelC = store.createRecord('host-catalog', {
compositeType: 'static',
});
assert.false(modelA.isStatic);
assert.false(modelB.isStatic);
assert.true(modelC.isStatic);
});
test('it has isPlugin function and returns the expected values', async function (assert) {
assert.expect(3);
test('it has isPlugin property and returns the expected values', async function (assert) {
assert.expect(2);
const store = this.owner.lookup('service:store');
const modelPlugin = store.createRecord('host-catalog', { type: 'plugin' });
const modelStatic = store.createRecord('host-catalog', { type: 'static' });
assert.equal(typeof modelPlugin.isPlugin, 'boolean');
const modelPlugin = store.createRecord('host-catalog', {
compositeType: 'aws',
});
const modelStatic = store.createRecord('host-catalog', {
compositeType: 'static',
});
assert.true(modelPlugin.isPlugin);
assert.false(modelStatic.isPlugin);
});
test('it has isAWS function and returns the expected values', async function (assert) {
test('it has isUnknown property and returns the expected values', async function (assert) {
assert.expect(3);
const store = this.owner.lookup('service:store');
const modelA = store.createRecord('host-catalog', {
compositeType: 'static',
});
const modelB = store.createRecord('host-catalog', { compositeType: 'aws' });
const modelC = store.createRecord('host-catalog', {
compositeType: 'no-such-type',
});
assert.false(modelA.isUnknown);
assert.false(modelB.isUnknown);
assert.true(modelC.isUnknown);
});
test('it has isAWS property and returns the expected values', async function (assert) {
assert.expect(2);
const store = this.owner.lookup('service:store');
const modelAws = store.createRecord('host-catalog', {
type: 'plugin',
plugin: { name: 'aws' },
@@ -40,13 +63,12 @@ module('Unit | Model | host catalog', function (hooks) {
const modelRandom = store.createRecord('host-catalog', {
plugin: { name: 'random' },
});
assert.equal(typeof modelAws.isAWS, 'boolean');
assert.true(modelAws.isAWS);
assert.false(modelRandom.isAWS);
});
test('it has isAzure function and return the expected values', async function (assert) {
assert.expect(3);
test('it has isAzure property and return the expected values', async function (assert) {
assert.expect(2);
const store = this.owner.lookup('service:store');
const modelAzure = store.createRecord('host-catalog', {
type: 'plugin',
@@ -55,7 +77,6 @@ module('Unit | Model | host catalog', function (hooks) {
const modelRandom = store.createRecord('host-catalog', {
plugin: { name: 'random' },
});
assert.equal(typeof modelAzure.isAzure, 'boolean');
assert.true(modelAzure.isAzure);
assert.false(modelRandom.isAzure);
});
@@ -63,16 +84,20 @@ module('Unit | Model | host catalog', function (hooks) {
test('get compositeType returns expected values', async function (assert) {
assert.expect(3);
const store = this.owner.lookup('service:store');
const modelPlugin = store.createRecord('host-catalog', {
type: 'plugin',
plugin: { name: 'Test name' },
});
const modelStatic = store.createRecord('host-catalog', {
const modelA = store.createRecord('host-catalog', {
type: 'static',
});
assert.equal(typeof modelPlugin.compositeType, 'string');
assert.equal(modelPlugin.compositeType, 'Test name');
assert.equal(modelStatic.compositeType, 'static');
const modelB = store.createRecord('host-catalog', {
type: 'plugin',
plugin: { name: 'aws' },
});
const modelC = store.createRecord('host-catalog', {
type: 'plugin',
plugin: { name: 'no-such-type' },
});
assert.equal(modelA.compositeType, 'static');
assert.equal(modelB.compositeType, 'aws');
assert.equal(modelC.compositeType, 'unknown');
});
test('set compositeType sets expected values', async function (assert) {
@@ -84,7 +109,6 @@ module('Unit | Model | host catalog', function (hooks) {
const modelStatic = store.createRecord('host-catalog', {
compositeType: 'static',
});
assert.equal(modelPlugin.type, 'plugin');
assert.equal(modelPlugin.plugin.name, 'aws');
assert.equal(modelStatic.type, 'static');
@@ -85,6 +85,9 @@ host-catalog:
delete: Delete Host Catalog
types:
static: Static
unknown: Unknown
aws: AWS
azure: Azure
host-set:
title: Host Set
title_plural: Host Sets
@@ -111,6 +114,9 @@ host-set:
description: No hosts available for selection.
types:
static: Static
unknown: Unknown
aws: AWS
azure: Azure
host:
title: Host
title_plural: Hosts
@@ -130,6 +136,9 @@ host:
delete: Delete Host
types:
static: Static
unknown: Unknown
aws: AWS
azure: Azure
session:
title: Session
title_plural: Sessions
@@ -43,7 +43,7 @@
{{#each @model as |hostCatalog|}}
<body.row as |row|>
<row.headerCell>
{{#if (can 'read model' hostCatalog)}}
{{#if (can 'read host-catalog' hostCatalog)}}
<LinkTo
@route='scopes.scope.host-catalogs.host-catalog'
@model={{hostCatalog.id}}
@@ -59,7 +59,19 @@
{{#if hostCatalog.isStatic}}
<Rose::Badge>
{{t
(concat 'resources.host-catalog.types.' hostCatalog.type)
(concat
'resources.host-catalog.types.'
hostCatalog.compositeType
)
}}
</Rose::Badge>
{{else if hostCatalog.isUnknown}}
<Rose::Badge>
{{t
(concat
'resources.host-catalog.types.'
hostCatalog.compositeType
)
}}
</Rose::Badge>
{{else}}
@@ -70,7 +82,12 @@
'-color-16'
}}
>
{{hostCatalog.compositeType}}
{{t
(concat
'resources.host-catalog.types.'
hostCatalog.compositeType
)
}}
</Rose::Badge>
{{/if}}
</row.cell>