Skip to content

Commit

Permalink
Merge pull request #8006 from hashicorp/f-ui/csi-node-only-support
Browse files Browse the repository at this point in the history
UI: CSI node only support
  • Loading branch information
DingoEatingFuzz authored and cgbaker committed May 30, 2020
1 parent 1ee0963 commit cf4a988
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 81 deletions.
9 changes: 9 additions & 0 deletions ui/app/styles/core/columns.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,13 @@
&.is-bottom-aligned {
align-items: flex-end;
}

&.is-max-half {
max-width: 50%;
}

&.is-centered {
margin-left: auto;
margin-right: auto;
}
}
8 changes: 6 additions & 2 deletions ui/app/templates/csi/plugins/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,12 @@
{{#link-to "csi.plugins.plugin" row.model.plainId class="is-primary"}}{{row.model.plainId}}{{/link-to}}
</td>
<td data-test-plugin-controller-health>
{{if (gt row.model.controllersHealthy 0) "Healthy" "Unhealthy"}}
({{row.model.controllersHealthy}}/{{row.model.controllersExpected}})
{{#if row.model.controllerRequired}}
{{if (gt row.model.controllersHealthy 0) "Healthy" "Unhealthy"}}
({{row.model.controllersHealthy}}/{{row.model.controllersExpected}})
{{else}}
<em class="is-faded">Node Only</em>
{{/if}}
</td>
<td data-test-plugin-node-health>
{{if (gt row.model.nodesHealthy 0) "Healthy" "Unhealthy"}}
Expand Down
132 changes: 69 additions & 63 deletions ui/app/templates/csi/plugins/plugin.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
<div class="boxed-section is-small">
<div class="boxed-section-body inline-definitions">
<span class="label">Plugin Details</span>
<span class="pair" data-test-plugin-controller-health>
<span class="term">Controller Health</span>
{{format-percentage model.controllersHealthy total=model.controllersExpected}}
({{model.controllersHealthy}}/{{model.controllersExpected}})
</span>
{{#if model.controllerRequired}}
<span class="pair" data-test-plugin-controller-health>
<span class="term">Controller Health</span>
{{format-percentage model.controllersHealthy total=model.controllersExpected}}
({{model.controllersHealthy}}/{{model.controllersExpected}})
</span>
{{/if}}
<span class="pair" data-test-plugin-node-health>
<span class="term">Node Health</span>
{{format-percentage model.nodesHealthy total=model.nodesExpected}}
Expand All @@ -23,38 +25,40 @@
</div>

<div class="columns">
<div class="column">
<div class="boxed-section">
<div class="boxed-section-head is-hollow">Controller Health</div>
<div class="boxed-section-body">
<div class="columns is-bottom-aligned">
<div class="column is-half">
{{gauge-chart
label="Availability"
value=model.controllersHealthy
total=model.controllersExpected}}
</div>
<div class="column">
<div class="metric">
<h3 class="label">Available</h3>
<p class="value">{{model.controllersHealthy}}</p>
{{#if model.controllerRequired}}
<div class="column" data-test-plugin-controller-availability>
<div class="boxed-section">
<div class="boxed-section-head is-hollow">Controller Health</div>
<div class="boxed-section-body">
<div class="columns is-centered is-max-half is-bottom-aligned">
<div class="column is-half">
{{gauge-chart
label="Availability"
value=model.controllersHealthy
total=model.controllersExpected}}
</div>
</div>
<div class="column">
<div class="metric">
<h3 class="label">Expected</h3>
<p class="value">{{model.controllersExpected}}</p>
<div class="column">
<div class="metric">
<h3 class="label">Available</h3>
<p class="value">{{model.controllersHealthy}}</p>
</div>
</div>
<div class="column">
<div class="metric">
<h3 class="label">Expected</h3>
<p class="value">{{model.controllersExpected}}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{{/if}}
<div class="column">
<div class="boxed-section">
<div class="boxed-section" data-test-plugin-node-availability>
<div class="boxed-section-head is-hollow">Node Health</div>
<div class="boxed-section-body">
<div class="columns is-bottom-aligned">
<div class="columns is-centered is-max-half is-bottom-aligned">
<div class="column is-half">
{{gauge-chart
label="Availability"
Expand All @@ -79,42 +83,44 @@
</div>
</div>

<div class="boxed-section">
<div class="boxed-section-head">
Controller Allocations
</div>
<div class="boxed-section-body {{if model.controllers "is-full-bleed"}}">
{{#if model.controllers}}
{{#list-table
source=sortedControllers
class="with-foot" as |t|}}
{{#t.head}}
<th class="is-narrow"></th>
<td>ID</td>
<th>Created</th>
<th>Modified</th>
<th>Health</th>
<th>Client</th>
<th>Job</th>
<th>Version</th>
<th>Volumes</th>
<th>CPU</th>
<th>Memory</th>
{{/t.head}}
{{#t.body key="model.allocID" as |row|}}
{{plugin-allocation-row
data-test-controller-allocation=row.model.allocID
pluginAllocation=row.model}}
{{/t.body}}
{{/list-table}}
{{else}}
<div class="empty-message" data-test-empty-controller-allocations>
<h3 class="empty-message-headline" data-test-empty-controller-allocations-headline>No Controller Plugin Allocations</h3>
<p class="empty-message-body" data-test-empty-controller-allocations-message>No allocations are providing controller plugin service.</p>
</div>
{{/if}}
{{#if model.controllerRequired}}
<div class="boxed-section" data-test-controller-allocations>
<div class="boxed-section-head">
Controller Allocations
</div>
<div class="boxed-section-body {{if model.controllers "is-full-bleed"}}">
{{#if model.controllers}}
{{#list-table
source=sortedControllers
class="with-foot" as |t|}}
{{#t.head}}
<th class="is-narrow"></th>
<td>ID</td>
<th>Created</th>
<th>Modified</th>
<th>Health</th>
<th>Client</th>
<th>Job</th>
<th>Version</th>
<th>Volumes</th>
<th>CPU</th>
<th>Memory</th>
{{/t.head}}
{{#t.body key="model.allocID" as |row|}}
{{plugin-allocation-row
data-test-controller-allocation=row.model.allocID
pluginAllocation=row.model}}
{{/t.body}}
{{/list-table}}
{{else}}
<div class="empty-message" data-test-empty-controller-allocations>
<h3 class="empty-message-headline" data-test-empty-controller-allocations-headline>No Controller Plugin Allocations</h3>
<p class="empty-message-body" data-test-empty-controller-allocations-message>No allocations are providing controller plugin service.</p>
</div>
{{/if}}
</div>
</div>
</div>
{{/if}}

<div class="boxed-section">
<div class="boxed-section-head">
Expand Down
40 changes: 28 additions & 12 deletions ui/mirage/factories/csi-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,19 @@ export default Factory.extend({

provider: faker.helpers.randomize(STORAGE_PROVIDERS),
version: '1.0.1',

controllerRequired: faker.random.boolean,
controllersHealthy: () => faker.random.number(3),

controllersHealthy() {
if (!this.controllerRequired) return 0;
return faker.random.number(3);
},
controllersExpected() {
return this.controllersHealthy + faker.random.number({ min: 1, max: 2 });
// This property must be read before the conditional
// or Mirage will incorrectly sort dependent properties.
const healthy = this.controllersHealthy;
if (!this.controllerRequired) return 0;
return healthy + faker.random.number({ min: 1, max: 2 });
},

nodesHealthy: () => faker.random.number(3),
Expand All @@ -25,7 +34,10 @@ export default Factory.extend({
// Internal property to determine whether or not this plugin
// Should create one or two Jobs to represent Node and
// Controller plugins.
isMonolith: faker.random.boolean,
isMonolith() {
if (!this.controllerRequired) return false;
return faker.random.boolean;
},

// When false, the plugin will not make its own volumes
createVolumes: true,
Expand All @@ -49,11 +61,13 @@ export default Factory.extend({
shallow: plugin.shallow,
});
} else {
const controllerJob = server.create('job', {
type: 'service',
createAllocations: false,
shallow: plugin.shallow,
});
const controllerJob =
plugin.controllerRequired &&
server.create('job', {
type: 'service',
createAllocations: false,
shallow: plugin.shallow,
});
const nodeJob = server.create('job', {
type: 'service',
createAllocations: false,
Expand All @@ -63,10 +77,12 @@ export default Factory.extend({
job: nodeJob,
shallow: plugin.shallow,
});
storageControllers = server.createList('storage-controller', plugin.controllersExpected, {
job: controllerJob,
shallow: plugin.shallow,
});
storageControllers =
plugin.controllerRequired &&
server.createList('storage-controller', plugin.controllersExpected, {
job: controllerJob,
shallow: plugin.shallow,
});
}

plugin.update({
Expand Down
15 changes: 14 additions & 1 deletion ui/tests/acceptance/plugin-detail-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ module('Acceptance | plugin detail', function(hooks) {

hooks.beforeEach(function() {
server.create('node');
plugin = server.create('csi-plugin');
plugin = server.create('csi-plugin', { controllerRequired: true });
});

test('/csi/plugins/:id should have a breadcrumb trail linking back to Plugins and Storage', async function(assert) {
Expand Down Expand Up @@ -147,6 +147,7 @@ module('Acceptance | plugin detail', function(hooks) {

test('when there are no plugin allocations, the tables present empty states', async function(assert) {
const emptyPlugin = server.create('csi-plugin', {
controllerRequired: true,
controllersHealthy: 0,
controllersExpected: 0,
nodesHealthy: 0,
Expand All @@ -161,4 +162,16 @@ module('Acceptance | plugin detail', function(hooks) {
assert.ok(PluginDetail.nodeTableIsEmpty);
assert.equal(PluginDetail.nodeEmptyState.headline, 'No Node Plugin Allocations');
});

test('when the plugin is node-only, the controller information is omitted', async function(assert) {
const nodeOnlyPlugin = server.create('csi-plugin', { controllerRequired: false });

await PluginDetail.visit({ id: nodeOnlyPlugin.id });

assert.notOk(PluginDetail.controllerAvailabilityIsPresent);
assert.ok(PluginDetail.nodeAvailabilityIsPresent);

assert.notOk(PluginDetail.controllerHealthIsPresent);
assert.notOk(PluginDetail.controllerTableIsPresent);
});
});
19 changes: 18 additions & 1 deletion ui/tests/acceptance/plugins-list-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ module('Acceptance | plugins list', function(hooks) {
});

test('each plugin row should contain information about the plugin', async function(assert) {
const plugin = server.create('csi-plugin', { shallow: true });
const plugin = server.create('csi-plugin', { shallow: true, controllerRequired: true });

await PluginsList.visit();

Expand All @@ -55,6 +55,23 @@ module('Acceptance | plugins list', function(hooks) {
assert.equal(pluginRow.provider, plugin.provider);
});

test('node only plugins explain that there is no controller health for this plugin type', async function(assert) {
const plugin = server.create('csi-plugin', { shallow: true, controllerRequired: false });

await PluginsList.visit();

const pluginRow = PluginsList.plugins.objectAt(0);
const nodeHealthStr = plugin.nodesHealthy > 0 ? 'Healthy' : 'Unhealthy';

assert.equal(pluginRow.id, plugin.id);
assert.equal(pluginRow.controllerHealth, 'Node Only');
assert.equal(
pluginRow.nodeHealth,
`${nodeHealthStr} (${plugin.nodesHealthy}/${plugin.nodesExpected})`
);
assert.equal(pluginRow.provider, plugin.provider);
});

test('each plugin row should link to the corresponding plugin', async function(assert) {
const plugin = server.create('csi-plugin', { shallow: true });

Expand Down
5 changes: 3 additions & 2 deletions ui/tests/integration/plugin-allocation-row-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ module('Integration | Component | plugin allocation row', function(hooks) {
});

test('Plugin allocation row immediately fetches the plugin allocation', async function(assert) {
const plugin = this.server.create('csi-plugin', { id: 'plugin' });
const plugin = this.server.create('csi-plugin', { id: 'plugin', controllerRequired: true });
const storageController = plugin.controllers.models[0];

const pluginRecord = await this.store.find('plugin', 'csi/plugin');
Expand All @@ -42,7 +42,7 @@ module('Integration | Component | plugin allocation row', function(hooks) {
});

test('After the plugin allocation row fetches the plugin allocation, allocation stats are fetched', async function(assert) {
const plugin = this.server.create('csi-plugin', { id: 'plugin' });
const plugin = this.server.create('csi-plugin', { id: 'plugin', controllerRequired: true });
const storageController = plugin.controllers.models[0];

const pluginRecord = await this.store.find('plugin', 'csi/plugin');
Expand All @@ -66,6 +66,7 @@ module('Integration | Component | plugin allocation row', function(hooks) {
const plugin = this.server.create('csi-plugin', {
id: 'plugin',
isMonolith: false,
controllerRequired: true,
controllersExpected: 2,
});
const storageController = plugin.controllers.models[0];
Expand Down
6 changes: 6 additions & 0 deletions ui/tests/pages/storage/plugins/detail.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ export default create({

title: text('[data-test-title]'),

controllerHealthIsPresent: isPresent('[data-test-plugin-controller-health]'),
controllerHealth: text('[data-test-plugin-controller-health]'),
nodeHealth: text('[data-test-plugin-node-health]'),
provider: text('[data-test-plugin-provider]'),

controllerAvailabilityIsPresent: isPresent('[data-test-plugin-controller-availability]'),
nodeAvailabilityIsPresent: isPresent('[data-test-plugin-node-availability]'),

breadcrumbs: collection('[data-test-breadcrumb]', {
id: attribute('data-test-breadcrumb'),
text: text(),
Expand All @@ -32,6 +36,8 @@ export default create({
...allocations('[data-test-controller-allocation]', 'controllerAllocations'),
...allocations('[data-test-node-allocation]', 'nodeAllocations'),

controllerTableIsPresent: isPresent('[data-test-controller-allocations]'),

controllerTableIsEmpty: isPresent('[data-test-empty-controller-allocations]'),
controllerEmptyState: {
headline: text('[data-test-empty-controller-allocations-headline]'),
Expand Down

0 comments on commit cf4a988

Please sign in to comment.