target workers UI Enterprise and HCP workflow (#1601)

adds ingress filter to target worker filter
This commit is contained in:
Dharini Jeeva authored and GitHub committed 2023-01-25 15:12:14 -08:00
1 parent de986c3df4
commit d7f54af7e4
9 files changed
+241 -83

No files matched your search

+15 -11
View File
@@ -374,27 +374,31 @@ target:
diagram: diagram:
client: Client client: Client
any-worker: Any worker any-worker: Any worker
front-line-worker: Front line worker frontline-worker: Frontline worker
hcp-worker: HCP worker hcp-worker: HCP worker
egress-worker: Egress worker egress-worker: Egress worker
ingress-worker: Ingress worker ingress-worker: Ingress worker
host: Host host: Host
network: Private network network: Private network
filter-explainer: filter-explainer:
any-worker: In this configuration, the client will attemt to connect through any client-accessible worker. any-worker: In this configuration, the client will attempt to connect through any client-accessible worker.
egress-worker: In this configuration, the client will attemt to connect through any filtered egress worker. egress-worker: In this configuration, the client will attempt to connect through any filtered egress worker.
ingress-worker: In this configuration, the client will attempt to conect through any filtered ingress worker. ingress-worker: In this configuration, the client will attempt to connect through any filtered ingress worker.
hcp-worker: In this configuration, the client will attempt to connect through any HCP-managed worker. hcp-worker: In this configuration, the client will attempt to connect through any HCP-managed worker.
ent-dual-egress-on: In this configuration, the client will attempt to connect through any client-accessible "frontline" worker and reach the host through any filtered egress worker. dual-egress-on: In this configuration, the client will attempt to connect through any client-accessible "frontline" worker and reach the host through any filtered egress worker.
hcp-dual-egress-on: In this configuration, the client will attempt to connect through any HC-managed worker and reach the host through any filtered egress worker. dual-egress-on-ingress-on: In this configuration, the client will attempt to connect through any filtered ingress worker and reach the host through any filtered egress worker.
dual-egress-on-ingress-on: In this configuration, the client will attempt to connect through any filtered ingress worker and reach the house through any filtered egress worker. hcp-dual-egress-on: In this configuration, the client will attempt to connect through any HCP-managed worker and reach the host through any filtered egress worker.
filter:
title: Filter
description: Boolean expression.
egress_worker_filter: egress_worker_filter:
title: Egress worker filter title: Egress worker filter
description: Specify workers that have access to the target (such as within a private network). description: Specify workers that have access to the target (such as within a private network).
filter: ingress_worker_filter:
title: Filter title: Ingress worker filter
description: Boolean expression. description: Specify workers Boundary should use to start the route to this target.
update_filter: Update Filter actions:
update-filter: Update Filter
credential-store: credential-store:
title: Credential Store title: Credential Store
title_plural: Credential Stores title_plural: Credential Stores
@@ -176,6 +176,7 @@
</Hds::Form::TextInput::Field> </Hds::Form::TextInput::Field>
{{#if (feature-flag 'target-worker-filters-v2')}} {{#if (feature-flag 'target-worker-filters-v2')}}
<Hds::Form::Fieldset <Hds::Form::Fieldset
class='target-workers' class='target-workers'
@layout='horizontal' @layout='horizontal'
@@ -218,9 +219,7 @@
<F.Control> <F.Control>
<Hds::Button <Hds::Button
class='update-filter-button' class='update-filter-button'
@text={{t @text={{t 'resources.target.workers.actions.update-filter'}}
'resources.target.workers.egress_worker_filter.filter.update_filter'
}}
@color='secondary' @color='secondary'
disabled={{form.disabled}} disabled={{form.disabled}}
{{on 'click' this.migrateWorkerFilters}} {{on 'click' this.migrateWorkerFilters}}
@@ -228,24 +227,51 @@
</F.Control> </F.Control>
{{/if}} {{/if}}
{{/if}} {{/if}}
<F.Control>
{{#if this.showTargetFilters}}
{{#if this.workerDiagramHCPDualFilter}}
<WorkerDiagram::DualFilter::Hcp
@egressFilter={{this.egressWorkerFilterEnabled}}
@ingressFilter={{this.ingressWorkerFilterEnabled}}
/>
{{else if this.workerDiagramDualFilter}}
<WorkerDiagram::DualFilter
@egressFilter={{this.egressWorkerFilterEnabled}}
@ingressFilter={{this.ingressWorkerFilterEnabled}}
/>
{{else}}
<WorkerDiagram::SingleFilter
@egressFilter={{this.egressWorkerFilterEnabled}}
/>
{{/if}}
{{#if this.showEgressFilter}} {{#if (feature-flag 'target-worker-filters-v2-ingress')}}
<F.Control> <Form::Target::WorkerFilter
<WorkerDiagram::SingleFilter @name='ingress_worker_filter'
@egressFilter={{this.egressWorkerFilterEnabled}} @disabled={{form.disabled}}
/> @value={{@model.ingress_worker_filter}}
@toggleAction={{this.toggleIngressFilter}}
@toggleEnabled={{this.ingressWorkerFilterEnabled}}
@onChange={{set-from-event @model 'ingress_worker_filter'}}
@isInvalid={{@model.errors.ingress_worker_filter}}
as |F|
>
{{#if @model.errors.ingress_worker_filter}}
<F.Error as |E|>
{{#each @model.errors.ingress_worker_filter as |error|}}
<E.Message>{{error.message}}</E.Message>
{{/each}}
</F.Error>
{{/if}}
</Form::Target::WorkerFilter>
{{/if}}
</F.Control>
<F.Control>
<Form::Target::WorkerFilter <Form::Target::WorkerFilter
@name='egress_worker_filter' @name='egress_worker_filter'
@type='text'
@disabled={{form.disabled}} @disabled={{form.disabled}}
@value={{@model.egress_worker_filter}} @value={{@model.egress_worker_filter}}
@toggleAction={{this.toggleEgressWorkerFilter}} @toggleAction={{this.toggleEgressFilter}}
@checked={{this.egressWorkerFilterEnabled}}
@toggleEnabled={{this.egressWorkerFilterEnabled}} @toggleEnabled={{this.egressWorkerFilterEnabled}}
@errors={{@model.errors.egress_worker_filter}}
@onChange={{set-from-event @model 'egress_worker_filter'}} @onChange={{set-from-event @model 'egress_worker_filter'}}
@isInvalid={{@model.errors.egress_worker_filter}} @isInvalid={{@model.errors.egress_worker_filter}}
as |F| as |F|
@@ -259,40 +285,8 @@
{{/if}} {{/if}}
</Form::Target::WorkerFilter> </Form::Target::WorkerFilter>
</F.Control> {{/if}}
{{/if}} </F.Control>
{{#if @model.isNew}}
<F.Control>
<WorkerDiagram::SingleFilter
@egressFilter={{this.egressWorkerFilterEnabled}}
/>
</F.Control>
<F.Control>
<Form::Target::WorkerFilter
@name='egress_worker_filter'
@type='text'
@disabled={{form.disabled}}
@value={{@model.egress_worker_filter}}
@toggleAction={{this.toggleEgressWorkerFilter}}
@checked={{this.egressWorkerFilterEnabled}}
@toggleEnabled={{this.egressWorkerFilterEnabled}}
@errors={{@model.errors.egress_worker_filter}}
@onChange={{set-from-event @model 'egress_worker_filter'}}
@isInvalid={{@model.errors.egress_worker_filter}}
as |F|
>
{{#if @model.errors.egress_worker_filter}}
<F.Error as |E|>
{{#each @model.errors.egress_worker_filter as |error|}}
<E.Message>{{error.message}}</E.Message>
{{/each}}
</F.Error>
{{/if}}
</Form::Target::WorkerFilter>
</F.Control>
{{/if}}
</Hds::Form::Fieldset> </Hds::Form::Fieldset>
{{else}} {{else}}
@@ -326,4 +320,5 @@
@cancelText={{t 'actions.cancel'}} @cancelText={{t 'actions.cancel'}}
/> />
{{/if}} {{/if}}
</Rose::Form> </Rose::Form>
@@ -2,6 +2,7 @@ import Component from '@glimmer/component';
import { TYPES_TARGET } from 'api/models/target'; import { TYPES_TARGET } from 'api/models/target';
import { action } from '@ember/object'; import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking'; import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
// NOTE: this is all a temporary solution till we have a resource type helper. // NOTE: this is all a temporary solution till we have a resource type helper.
const types = [...TYPES_TARGET].reverse(); const types = [...TYPES_TARGET].reverse();
@@ -9,13 +10,13 @@ const icons = {
ssh: 'terminal-screen', ssh: 'terminal-screen',
tcp: 'network', tcp: 'network',
}; };
export default class FormTargetComponent extends Component { export default class FormTargetComponent extends Component {
// =properties // =properties
@tracked egressWorkerFilterEnabled = @tracked egressWorkerFilterEnabled = this.args.model.egress_worker_filter;
this.args.model.egress_worker_filter?.length; @tracked ingressWorkerFilterEnabled = this.args.model.ingress_worker_filter;
// =properties // =services
@service features;
/** /**
* maps resource type with icon * maps resource type with icon
* @type {object} * @type {object}
@@ -49,28 +50,56 @@ export default class FormTargetComponent extends Component {
* @type {boolean} * @type {boolean}
*/ */
get showUpdateWorkerFilterButton() { get showUpdateWorkerFilterButton() {
return this.args.model.worker_filter?.length; return this.args.model.worker_filter;
} }
get showEgressFilter() { /**
return !this.args.model.worker_filter?.length && !this.args.model.isNew; * determines when the filters should be shown
* @type {boolean}
*/
get showTargetFilters() {
return !this.args.model.worker_filter;
}
//note: these getters will go away when we refactor worker diagram
/**
* determines when the enterprise dual filter diagrams should be shown
* @type {boolean}
*/
get workerDiagramDualFilter() {
return this.features.isEnabled('target-worker-filters-v2-ingress');
}
/**
* determines when the hcp dual filter diagrams should be shown
* @type {boolean}
*/
get workerDiagramHCPDualFilter() {
return this.features.isEnabled('target-worker-filters-v2-hcp');
} }
//actions //actions
@action @action
toggleEgressWorkerFilter() { toggleEgressFilter() {
this.egressWorkerFilterEnabled = !this.egressWorkerFilterEnabled; this.egressWorkerFilterEnabled = !this.egressWorkerFilterEnabled;
if (!this.egressWorkerFilterEnabled) { if (!this.egressWorkerFilterEnabled) {
this.args.model.egress_worker_filter = ''; this.args.model.egress_worker_filter = '';
} }
} }
// =actions @action
toggleIngressFilter() {
this.ingressWorkerFilterEnabled = !this.ingressWorkerFilterEnabled;
if (!this.ingressWorkerFilterEnabled) {
this.args.model.ingress_worker_filter = '';
}
}
@action @action
migrateWorkerFilters() { migrateWorkerFilters() {
this.egressWorkerFilterEnabled = true; this.egressWorkerFilterEnabled = true;
this.ingressWorkerFilterEnabled = true;
// When update is clicked, copy worker filter value into egress filter and clear the worker_filter // When update is clicked, copy worker filter value into egress filter and clear the worker_filter
this.args.model.egress_worker_filter = this.args.model.worker_filter; this.args.model.egress_worker_filter = this.args.model.worker_filter;
this.args.model.ingress_worker_filter = this.args.model.worker_filter;
this.args.model.worker_filter = ''; this.args.model.worker_filter = '';
} }
@@ -82,7 +111,9 @@ export default class FormTargetComponent extends Component {
cancel() { cancel() {
this.args.cancel(); this.args.cancel();
// Reset the tracked variable for toggles after rollback // Reset the tracked variable for toggles after rollback
this.egressWorkerFilterEnabled =
this.args.model.egress_worker_filter?.length; this.egressWorkerFilterEnabled = this.args.model.egress_worker_filter;
this.ingressWorkerFilterEnabled = this.args.model.ingress_worker_filter;
} }
} }
@@ -1,8 +1,8 @@
<div class='target-worker-filter'> <div class='target-worker-filter' data-test-filter={{@name}}>
<Hds::Form::Toggle::Field <Hds::Form::Toggle::Field
name='target-worker-filter-toggle' name='target-worker-filter-toggle'
checked={{@checked}} checked={{@toggleEnabled}}
disabled={{@disabled}} disabled={{@disabled}}
@isRequired={{false}} @isRequired={{false}}
@isOptional={{true}} @isOptional={{true}}
@@ -27,12 +27,9 @@
{{on 'input' @onChange}} {{on 'input' @onChange}}
as |F| as |F|
> >
<F.Label>{{t <F.Label>{{t 'resources.target.workers.filter.title'}}</F.Label>
(concat 'resources.target.workers.' @name '.filter.title') <F.HelperText>
}}</F.Label> {{t 'resources.target.workers.filter.description'}}
<F.HelperText>{{t
(concat 'resources.target.workers.' @name '.filter.description')
}}
<Hds::Link::Inline @href={{doc-url 'target.worker-filters'}}> <Hds::Link::Inline @href={{doc-url 'target.worker-filters'}}>
{{t 'actions.learn-more'}} {{t 'actions.learn-more'}}
</Hds::Link::Inline> </Hds::Link::Inline>
@@ -21,7 +21,9 @@
</OrderedSeriesDiagram> </OrderedSeriesDiagram>
<div class='target-worker-filter-explainer'> <div class='target-worker-filter-explainer'>
<Hds::Form::HelperText> <Hds::Form::HelperText>
{{t 'resources.target.workers.filter-explainer.hcp-dual-egress-on'}} {{t
'resources.target.workers.filter-explainer.dual-egress-on-ingress-on'
}}
</Hds::Form::HelperText> </Hds::Form::HelperText>
</div> </div>
{{else if @ingressFilter}} {{else if @ingressFilter}}
@@ -56,7 +58,7 @@
{{#if (feature-flag 'target-worker-filters-v2-hcp')}} {{#if (feature-flag 'target-worker-filters-v2-hcp')}}
{{t 'resources.target.workers.diagram.hcp-worker'}} {{t 'resources.target.workers.diagram.hcp-worker'}}
{{else}} {{else}}
{{t 'resources.target.workers.diagram.front-line-worker'}} {{t 'resources.target.workers.diagram.frontline-worker'}}
{{/if}} {{/if}}
</D.Item> </D.Item>
<D.Group <D.Group
@@ -73,7 +75,7 @@
</OrderedSeriesDiagram> </OrderedSeriesDiagram>
<div class='target-worker-filter-explainer'> <div class='target-worker-filter-explainer'>
<Hds::Form::HelperText> <Hds::Form::HelperText>
{{t 'resources.target.workers.filter-explainer.egress-on'}} {{t 'resources.target.workers.filter-explainer.hcp-dual-egress-on'}}
</Hds::Form::HelperText> </Hds::Form::HelperText>
</div> </div>
{{else}} {{else}}
@@ -49,7 +49,7 @@
{{t 'resources.target.workers.diagram.client'}} {{t 'resources.target.workers.diagram.client'}}
</D.Item> </D.Item>
<D.Item @icon='settings'> <D.Item @icon='settings'>
{{t 'resources.target.workers.diagram.front-line-worker'}} {{t 'resources.target.workers.diagram.frontline-worker'}}
</D.Item> </D.Item>
<D.Group <D.Group
@title={{t 'resources.target.workers.diagram.network'}} @title={{t 'resources.target.workers.diagram.network'}}
@@ -65,7 +65,7 @@
</OrderedSeriesDiagram> </OrderedSeriesDiagram>
<div class='target-worker-filter-explainer'> <div class='target-worker-filter-explainer'>
<Hds::Form::HelperText> <Hds::Form::HelperText>
{{t 'resources.target.workers.filter-explainer.egress-worker'}} {{t 'resources.target.workers.filter-explainer.dual-egress-on'}}
</Hds::Form::HelperText> </Hds::Form::HelperText>
</div> </div>
{{else}} {{else}}
@@ -136,6 +136,7 @@ module('Acceptance | targets | create', function (hooks) {
'random filter' 'random filter'
); );
}); });
test('can create type `tcp` when `target-worker-filters-v2` is disabled', async function (assert) { test('can create type `tcp` when `target-worker-filters-v2` is disabled', async function (assert) {
featuresService.disable('target-worker-filters-v2'); featuresService.disable('target-worker-filters-v2');
assert.expect(4); assert.expect(4);
@@ -161,6 +162,7 @@ module('Acceptance | targets | create', function (hooks) {
'random filter' 'random filter'
); );
}); });
test('can create type `tcp` when `target-worker-filters-v2` is enabled', async function (assert) { test('can create type `tcp` when `target-worker-filters-v2` is enabled', async function (assert) {
featuresService.enable('target-worker-filters-v2'); featuresService.enable('target-worker-filters-v2');
assert.expect(4); assert.expect(4);
@@ -188,6 +190,42 @@ module('Acceptance | targets | create', function (hooks) {
'random filter' 'random filter'
); );
}); });
test('can create type `tcp` when `target-worker-filters-v2` and `target-worker-filters-v2-ingress` is enabled', async function (assert) {
featuresService.enable('target-worker-filters-v2');
featuresService.enable('target-worker-filters-v2-ingress');
assert.expect(4);
const targetCount = getTargetCount();
const tcpTargetCount = getTCPTargetCount();
await visit(urls.targets);
await click(`[href="${urls.newTarget}"]`);
await click('[value="tcp"]');
await fillIn('[name="name"]', 'random string');
await click(
'[data-test-filter="egress_worker_filter"] .hds-form-toggle__control'
);
await fillIn('[name="egress_worker_filter"]', 'random filter');
await click(
'[data-test-filter="ingress_worker_filter"] .hds-form-toggle__control'
);
await fillIn('[name="ingress_worker_filter"]', 'random filter');
await click('[type="submit"]');
assert.strictEqual(getTargetCount(), targetCount + 1);
assert.strictEqual(getTCPTargetCount(), tcpTargetCount + 1);
assert.strictEqual(
this.server.schema.targets.all().models[getTargetCount() - 1].name,
'random string'
);
assert.strictEqual(
this.server.schema.targets.all().models[getTargetCount() - 1]
.egressWorkerFilter,
'random filter'
);
});
test('default port is not marked required for SSH targets', async function (assert) { test('default port is not marked required for SSH targets', async function (assert) {
assert.expect(1); assert.expect(1);
await visit(urls.newTarget); await visit(urls.newTarget);
@@ -0,0 +1,57 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, getContext } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
import { setupIntl } from 'ember-intl/test-support';
module('Integration | Component | form/target/details', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);
let featuresService;
hooks.beforeEach(function () {
const { owner } = getContext();
featuresService = owner.lookup('service:features');
this.model = { type: 'ssh' };
this.submit = () => {};
this.cancel = () => {};
this.changeType = () => {};
});
test('shows the correct worker diagram when `target-worker-filters-v2` is enabled', async function (assert) {
featuresService.enable('target-worker-filters-v2');
featuresService.disable('target-worker-filters-v2-ingress');
featuresService.disable('target-worker-filters-v2-hcp');
assert.expect(1);
await render(
hbs`<Form::Target::Details @model={{this.model}} @defaultPort='22' @submit={{this.submit}} @cancel={{this.cancel}} @changeType={{this.changeType}} />`
);
assert.dom('[data-test-single-filter-egress-off]').isVisible();
});
test('shows the correct worker diagram when `target-worker-filters-v2` and `target-worker-filters-v2-ingress` is enabled', async function (assert) {
featuresService.enable('target-worker-filters-v2');
featuresService.enable('target-worker-filters-v2-ingress');
featuresService.disable('target-worker-filters-v2-hcp');
assert.expect(1);
await render(
hbs`<Form::Target::Details @model={{this.model}} @defaultPort='22' @submit={{this.submit}} @cancel={{this.cancel}} @changeType={{this.changeType}} />`
);
assert.dom('[data-test-dual-filters]').isVisible();
});
test('shows the correct worker diagram when `target-worker-filters-v2` and `target-worker-filters-v2-ingress` and `target-worker-filters-v2-hcp` is enabled', async function (assert) {
featuresService.enable('target-worker-filters-v2');
featuresService.enable('target-worker-filters-v2-ingress');
featuresService.enable('target-worker-filters-v2-hcp');
assert.expect(1);
await render(
hbs`<Form::Target::Details @model={{this.model}} @defaultPort='22' @submit={{this.submit}} @cancel={{this.cancel}} @changeType={{this.changeType}} />`
);
assert.dom('[data-test-dual-filters-hcp]').isVisible();
});
});
@@ -0,0 +1,34 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
import { setupIntl } from 'ember-intl/test-support';
module('Integration | Component | form/target/worker-filter', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);
test('it only renders a toggle field when "toggleEnabled" is false', async function (assert) {
assert.expect(2);
this.onChange = () => {};
this.toggleAction = () => {};
await render(
hbs`<Form::Target::WorkerFilter @name='egress_worker_filter' @toggleEnabled={{false}} @toggleAction={{this.toggleAction}} @onChange={{this.onChange}}/>`
);
assert.dom('.hds-form-toggle').isVisible();
assert.dom('.hds-form-text-input').doesNotExist();
});
test('it renders a toggle field and text input field when "toggleEnabled" is true', async function (assert) {
assert.expect(2);
this.onChange = () => {};
this.toggleAction = () => {};
await render(
hbs`<Form::Target::WorkerFilter @name='egress_worker_filter' @toggleEnabled={{true}} @toggleAction={{this.toggleAction}} @onChange={{this.onChange}}/>`
);
assert.dom('.hds-form-toggle').isVisible();
assert.dom('.hds-form-text-input').isVisible();
});
});