diff --git a/modules/web/src/app/node-data/basic/provider/openstack/component.ts b/modules/web/src/app/node-data/basic/provider/openstack/component.ts index 99b32cef46..7008402497 100644 --- a/modules/web/src/app/node-data/basic/provider/openstack/component.ts +++ b/modules/web/src/app/node-data/basic/provider/openstack/component.ts @@ -33,7 +33,7 @@ import {ClusterSpecService} from '@core/services/cluster-spec'; import {DatacenterService} from '@core/services/datacenter'; import {NodeDataService} from '@core/services/node-data/service'; import {FilteredComboboxComponent} from '@shared/components/combobox/component'; -import {DatacenterOperatingSystemOptions} from '@shared/entity/datacenter'; +import {Datacenter, DatacenterOperatingSystemOptions} from '@shared/entity/datacenter'; import {NodeCloudSpec, NodeSpec, OpenstackNodeSpec} from '@shared/entity/node'; import {OpenstackAvailabilityZone, OpenstackFlavor, OpenstackServerGroup} from '@shared/entity/provider/openstack'; import {OperatingSystem} from '@shared/model/NodeProviderConstants'; @@ -53,6 +53,7 @@ enum Controls { InstanceReadyCheckPeriod = 'instanceReadyCheckPeriod', InstanceReadyCheckTimeout = 'instanceReadyCheckTimeout', ServerGroup = 'serverGroup', + EnableConfigDrive = 'enableConfigDrive', } enum FlavorState { @@ -118,6 +119,7 @@ export class OpenstackBasicNodeDataComponent extends BaseFormValidator implement selectedServerGroupID = ''; serverGroupLabel = ServerGroupState.Empty; isEnterpriseEdition = DynamicModule.isEnterpriseEdition; + isInWizardMode: boolean; private _quotaCalculationService: QuotaCalculationService; @@ -169,8 +171,11 @@ export class OpenstackBasicNodeDataComponent extends BaseFormValidator implement [Controls.InstanceReadyCheckPeriod]: this._builder.control(this._instanceReadyCheckPeriodDefault), [Controls.InstanceReadyCheckTimeout]: this._builder.control(this._instanceReadyCheckTimeoutDefault), [Controls.ServerGroup]: this._builder.control(''), + [Controls.EnableConfigDrive]: this._builder.control(false), }); + this.isInWizardMode = this._nodeDataService.isInWizardMode(); + this._init(); this._nodeDataService.nodeData = this._getNodeData(); @@ -180,7 +185,8 @@ export class OpenstackBasicNodeDataComponent extends BaseFormValidator implement this.form.get(Controls.Image).valueChanges, this.form.get(Controls.UseFloatingIP).valueChanges, this.form.get(Controls.InstanceReadyCheckPeriod).valueChanges, - this.form.get(Controls.InstanceReadyCheckTimeout).valueChanges + this.form.get(Controls.InstanceReadyCheckTimeout).valueChanges, + this.form.get(Controls.EnableConfigDrive).valueChanges ) .pipe(takeUntil(this._unsubscribe)) .subscribe(_ => { @@ -195,6 +201,7 @@ export class OpenstackBasicNodeDataComponent extends BaseFormValidator implement .subscribe(dc => { this._setDefaultImage(OperatingSystem.Ubuntu); this._enforceFloatingIP(dc.spec.openstack.enforceFloatingIP); + this._enforceConfigDrive(dc); }); this._nodeDataService.operatingSystemChanges @@ -244,6 +251,10 @@ export class OpenstackBasicNodeDataComponent extends BaseFormValidator implement return this.form.get(Controls.UseFloatingIP).disabled; } + isConfigDriveEnforced(): boolean { + return this.form.get(Controls.EnableConfigDrive).disabled; + } + isDiskSizeRequired(): boolean { return this.form.get(Controls.CustomDiskSize).hasValidator(Validators.required); } @@ -290,6 +301,9 @@ export class OpenstackBasicNodeDataComponent extends BaseFormValidator implement this.form.get(Controls.UseCustomDisk).setValue(!!diskSize); this.form.get(Controls.InstanceReadyCheckPeriod).setValue(instanceReadyCheckPeriod); this.form.get(Controls.InstanceReadyCheckTimeout).setValue(instanceReadyCheckTimeout); + this.form + .get(Controls.EnableConfigDrive) + .setValue(this._nodeDataService.nodeData.spec.cloud.openstack?.configDrive ?? false); this._defaultOS = this._nodeDataService.operatingSystem; this._defaultImage = this._nodeDataService.nodeData.spec.cloud.openstack.image; @@ -416,15 +430,19 @@ export class OpenstackBasicNodeDataComponent extends BaseFormValidator implement return; } - if ( - !this._nodeDataService.isInWizardMode() && - !this._clusterSpecService.cluster.spec.cloud.openstack.floatingIPPool - ) { + if (!this.isInWizardMode && !this._clusterSpecService.cluster.spec.cloud.openstack.floatingIPPool) { this.form.get(Controls.UseFloatingIP).setValue(false); this.form.get(Controls.UseFloatingIP).disable(); } } + private _enforceConfigDrive(dc: Datacenter): void { + if (dc.spec.openstack.enableConfigDrive) { + this.form.get(Controls.EnableConfigDrive).setValue(true); + this.form.get(Controls.EnableConfigDrive).disable(); + } + } + private _getNodeData(): NodeData { return { spec: { @@ -436,6 +454,7 @@ export class OpenstackBasicNodeDataComponent extends BaseFormValidator implement instanceReadyCheckPeriod: `${this.form.get(Controls.InstanceReadyCheckPeriod).value}s`, instanceReadyCheckTimeout: `${this.form.get(Controls.InstanceReadyCheckTimeout).value}s`, serverGroup: this.selectedServerGroupID, + configDrive: this.form.get(Controls.EnableConfigDrive)?.value ?? false, } as OpenstackNodeSpec, } as NodeCloudSpec, } as NodeSpec, @@ -459,7 +478,7 @@ export class OpenstackBasicNodeDataComponent extends BaseFormValidator implement }; if ( - !this._nodeDataService.isInWizardMode() && + !this.isInWizardMode && !this._initialQuotaCalculationPayload && !!this._nodeDataService.nodeData.creationTimestamp ) { diff --git a/modules/web/src/app/node-data/basic/provider/openstack/style.scss b/modules/web/src/app/node-data/basic/provider/openstack/style.scss index 19b8d3b4e5..741d2775ea 100644 --- a/modules/web/src/app/node-data/basic/provider/openstack/style.scss +++ b/modules/web/src/app/node-data/basic/provider/openstack/style.scss @@ -22,7 +22,3 @@ align-self: center; margin-left: 5px; } - -.use-floating-ip-checkbox { - padding-bottom: 20px; -} diff --git a/modules/web/src/app/node-data/basic/provider/openstack/template.html b/modules/web/src/app/node-data/basic/provider/openstack/template.html index 184d799f0a..02ec9e5397 100644 --- a/modules/web/src/app/node-data/basic/provider/openstack/template.html +++ b/modules/web/src/app/node-data/basic/provider/openstack/template.html @@ -96,15 +96,23 @@ - - Allocate Floating IP +
+ + Allocate Floating IP + - +
+
+ + Enable Config Drive + + +
(); readonly controls = Controls; + readonly Provider = Provider; readonly domainRegex = '^(?!-)[A-Za-z0-9-]+([\\-.][a-z0-9]+)*\\.[A-Za-z]{2,6}$'; readonly countryCodes: string[] = countryCodeLookup.countries.map(country => country.iso2); readonly providers = INTERNAL_NODE_PROVIDERS; @@ -131,10 +133,32 @@ export class DatacenterDataDialogComponent implements OnInit, OnDestroy { this._initRequiredEmailsInput(); this._initProviderConfigEditor(); + if (this.form.get(Controls.Provider).value === Provider.OpenStack) { + this.form.addControl( + Controls.EnableConfigDrive, + new FormControl(this.data.isEditing ? this.data.datacenter.spec.openstack.enableConfigDrive : false) + ); + } + if (this.form.get(Controls.EnforceAuditWebhookBackend).value) { this._initAuditWebhookBackendControls(this.data.datacenter.spec.enforcedAuditWebhookSettings); } + this.form + .get(Controls.Provider) + .valueChanges.pipe(takeUntil(this._unsubscribe)) + .subscribe((provider: Provider) => { + if (provider === Provider.OpenStack) { + this.form.addControl( + Controls.EnableConfigDrive, + new FormControl(this.data.isEditing ? this.data.datacenter.spec.openstack.enableConfigDrive : false) + ); + } else { + this.form.removeControl(Controls.EnableConfigDrive); + } + this.form.updateValueAndValidity(); + }); + this.form .get(Controls.EnforceAuditLogging) .valueChanges.pipe(takeUntil(this._unsubscribe)) @@ -209,6 +233,9 @@ export class DatacenterDataDialogComponent implements OnInit, OnDestroy { }; datacenter.spec[datacenter.spec.provider] = this._getProviderConfig(); + if (datacenter.spec.provider === Provider.OpenStack) { + datacenter.spec[datacenter.spec.provider].enableConfigDrive = this.form.get(Controls.EnableConfigDrive)?.value; + } // Nullify old provider value (it is needed to make edit work as it uses JSON Merge Patch). if (this.data.isEditing && datacenter.spec.provider !== this.data.datacenter.spec.provider) { diff --git a/modules/web/src/app/settings/admin/dynamic-datacenters/datacenter-data-dialog/template.html b/modules/web/src/app/settings/admin/dynamic-datacenters/datacenter-data-dialog/template.html index 44cc65d3a8..3efc3cf38e 100644 --- a/modules/web/src/app/settings/admin/dynamic-datacenters/datacenter-data-dialog/template.html +++ b/modules/web/src/app/settings/admin/dynamic-datacenters/datacenter-data-dialog/template.html @@ -187,9 +187,21 @@ + Provider Configuration + + + +
+ Enable Config Drive + + +
+
+
- -
Provider Configuration
If not specified default configuration will be used. diff --git a/modules/web/src/app/shared/components/cluster-summary/template.html b/modules/web/src/app/shared/components/cluster-summary/template.html index ac0855a7d2..b23f244da6 100644 --- a/modules/web/src/app/shared/components/cluster-summary/template.html +++ b/modules/web/src/app/shared/components/cluster-summary/template.html @@ -1186,6 +1186,9 @@

IPv6

+ + diff --git a/modules/web/src/app/shared/entity/datacenter.ts b/modules/web/src/app/shared/entity/datacenter.ts index 266caa84d4..3fb71b6c9b 100644 --- a/modules/web/src/app/shared/entity/datacenter.ts +++ b/modules/web/src/app/shared/entity/datacenter.ts @@ -134,6 +134,7 @@ export class OpenStackDatacenterSpec { region: string; images: DatacenterOperatingSystemOptions; enforceFloatingIP: boolean; + enableConfigDrive?: boolean; } export class EquinixDatacenterSpec { diff --git a/modules/web/src/app/shared/entity/node.ts b/modules/web/src/app/shared/entity/node.ts index e9b7211780..82098c0f22 100644 --- a/modules/web/src/app/shared/entity/node.ts +++ b/modules/web/src/app/shared/entity/node.ts @@ -265,6 +265,7 @@ export class OpenstackNodeSpec { availabilityZone?: string; instanceReadyCheckPeriod: string; instanceReadyCheckTimeout: string; + configDrive?: boolean; } export class EquinixNodeSpec {