]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-form/osd-form.component.ts
check in ceph 17.2.3 sources
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / cluster / osd / osd-form / osd-form.component.ts
CommitLineData
a4b75251 1import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
20effc67 2import { FormControl } from '@angular/forms';
9f95a23c
TL
3import { Router } from '@angular/router';
4
f67539c2
TL
5import _ from 'lodash';
6
7import { InventoryDevice } from '~/app/ceph/cluster/inventory/inventory-devices/inventory-device.model';
8import { HostService } from '~/app/shared/api/host.service';
9import { OrchestratorService } from '~/app/shared/api/orchestrator.service';
10import { FormButtonPanelComponent } from '~/app/shared/components/form-button-panel/form-button-panel.component';
11import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
12import { Icons } from '~/app/shared/enum/icons.enum';
13import { CdForm } from '~/app/shared/forms/cd-form';
14import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
15import { CdTableColumn } from '~/app/shared/models/cd-table-column';
16import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
17import { ModalService } from '~/app/shared/services/modal.service';
a4b75251 18import { WizardStepsService } from '~/app/shared/services/wizard-steps.service';
9f95a23c
TL
19import { OsdCreationPreviewModalComponent } from '../osd-creation-preview-modal/osd-creation-preview-modal.component';
20import { DevicesSelectionChangeEvent } from '../osd-devices-selection-groups/devices-selection-change-event.interface';
21import { DevicesSelectionClearEvent } from '../osd-devices-selection-groups/devices-selection-clear-event.interface';
22import { OsdDevicesSelectionGroupsComponent } from '../osd-devices-selection-groups/osd-devices-selection-groups.component';
23import { DriveGroup } from './drive-group.model';
24import { OsdFeature } from './osd-feature.interface';
25
26@Component({
27 selector: 'cd-osd-form',
28 templateUrl: './osd-form.component.html',
29 styleUrls: ['./osd-form.component.scss']
30})
f67539c2
TL
31export class OsdFormComponent extends CdForm implements OnInit {
32 @ViewChild('dataDeviceSelectionGroups')
9f95a23c
TL
33 dataDeviceSelectionGroups: OsdDevicesSelectionGroupsComponent;
34
f67539c2 35 @ViewChild('walDeviceSelectionGroups')
9f95a23c
TL
36 walDeviceSelectionGroups: OsdDevicesSelectionGroupsComponent;
37
f67539c2 38 @ViewChild('dbDeviceSelectionGroups')
9f95a23c
TL
39 dbDeviceSelectionGroups: OsdDevicesSelectionGroupsComponent;
40
f67539c2
TL
41 @ViewChild('previewButtonPanel')
42 previewButtonPanel: FormButtonPanelComponent;
9f95a23c 43
a4b75251
TL
44 @Input()
45 hideTitle = false;
46
47 @Input()
48 hideSubmitBtn = false;
49
50 @Output() emitDriveGroup: EventEmitter<DriveGroup> = new EventEmitter();
51
9f95a23c
TL
52 icons = Icons;
53
54 form: CdFormGroup;
55 columns: Array<CdTableColumn> = [];
56
9f95a23c
TL
57 allDevices: InventoryDevice[] = [];
58
59 availDevices: InventoryDevice[] = [];
60 dataDeviceFilters: any[] = [];
61 dbDeviceFilters: any[] = [];
62 walDeviceFilters: any[] = [];
63 hostname = '';
64 driveGroup = new DriveGroup();
65
66 action: string;
67 resource: string;
68
69 features: { [key: string]: OsdFeature };
70 featureList: OsdFeature[] = [];
71
f67539c2 72 hasOrchestrator = true;
9f95a23c
TL
73
74 constructor(
75 public actionLabels: ActionLabelsI18n,
76 private authStorageService: AuthStorageService,
9f95a23c 77 private orchService: OrchestratorService,
f67539c2 78 private hostService: HostService,
9f95a23c 79 private router: Router,
a4b75251
TL
80 private modalService: ModalService,
81 public wizardStepService: WizardStepsService
9f95a23c 82 ) {
f67539c2
TL
83 super();
84 this.resource = $localize`OSDs`;
9f95a23c
TL
85 this.action = this.actionLabels.CREATE;
86 this.features = {
87 encrypted: {
88 key: 'encrypted',
f67539c2 89 desc: $localize`Encryption`
9f95a23c
TL
90 }
91 };
92 this.featureList = _.map(this.features, (o, key) => Object.assign(o, { key: key }));
93 this.createForm();
94 }
95
96 ngOnInit() {
97 this.orchService.status().subscribe((status) => {
98 this.hasOrchestrator = status.available;
f67539c2 99 if (status.available) {
9f95a23c 100 this.getDataDevices();
f67539c2
TL
101 } else {
102 this.loadingNone();
9f95a23c
TL
103 }
104 });
105
106 this.form.get('walSlots').valueChanges.subscribe((value) => this.setSlots('wal', value));
107 this.form.get('dbSlots').valueChanges.subscribe((value) => this.setSlots('db', value));
108 _.each(this.features, (feature) => {
109 this.form
110 .get('features')
111 .get(feature.key)
112 .valueChanges.subscribe((value) => this.featureFormUpdate(feature.key, value));
113 });
114 }
115
116 createForm() {
117 this.form = new CdFormGroup({
20effc67
TL
118 walSlots: new FormControl(0),
119 dbSlots: new FormControl(0),
9f95a23c
TL
120 features: new CdFormGroup(
121 this.featureList.reduce((acc: object, e) => {
122 // disable initially because no data devices are selected
123 acc[e.key] = new FormControl({ value: false, disabled: true });
124 return acc;
125 }, {})
126 )
127 });
128 }
129
130 getDataDevices() {
f67539c2 131 this.hostService.inventoryDeviceList().subscribe(
9f95a23c
TL
132 (devices: InventoryDevice[]) => {
133 this.allDevices = _.filter(devices, 'available');
134 this.availDevices = [...this.allDevices];
f67539c2 135 this.loadingReady();
9f95a23c
TL
136 },
137 () => {
138 this.allDevices = [];
139 this.availDevices = [];
f67539c2 140 this.loadingError();
9f95a23c
TL
141 }
142 );
143 }
144
145 setSlots(type: string, slots: number) {
146 if (typeof slots !== 'number') {
147 return;
148 }
149 if (slots >= 0) {
150 this.driveGroup.setSlots(type, slots);
151 }
152 }
153
154 featureFormUpdate(key: string, checked: boolean) {
155 this.driveGroup.setFeature(key, checked);
156 }
157
158 enableFeatures() {
159 this.featureList.forEach((feature) => {
160 this.form.get(feature.key).enable({ emitEvent: false });
161 });
162 }
163
164 disableFeatures() {
165 this.featureList.forEach((feature) => {
166 const control = this.form.get(feature.key);
167 control.disable({ emitEvent: false });
168 control.setValue(false, { emitEvent: false });
169 });
170 }
171
172 onDevicesSelected(event: DevicesSelectionChangeEvent) {
173 this.availDevices = event.dataOut;
174
175 if (event.type === 'data') {
176 // If user selects data devices for a single host, make only remaining devices on
177 // that host as available.
178 const hostnameFilter = _.find(event.filters, { prop: 'hostname' });
179 if (hostnameFilter) {
180 this.hostname = hostnameFilter.value.raw;
181 this.availDevices = event.dataOut.filter((device: InventoryDevice) => {
182 return device.hostname === this.hostname;
183 });
184 this.driveGroup.setHostPattern(this.hostname);
185 } else {
186 this.driveGroup.setHostPattern('*');
187 }
188 this.enableFeatures();
189 }
190 this.driveGroup.setDeviceSelection(event.type, event.filters);
a4b75251
TL
191
192 this.emitDriveGroup.emit(this.driveGroup);
9f95a23c
TL
193 }
194
195 onDevicesCleared(event: DevicesSelectionClearEvent) {
196 if (event.type === 'data') {
197 this.availDevices = [...this.allDevices];
198 this.walDeviceSelectionGroups.devices = [];
199 this.dbDeviceSelectionGroups.devices = [];
200 this.disableFeatures();
201 this.driveGroup.reset();
202 this.form.get('walSlots').setValue(0, { emitEvent: false });
203 this.form.get('dbSlots').setValue(0, { emitEvent: false });
204 } else {
205 this.availDevices = [...this.availDevices, ...event.clearedDevices];
206 this.driveGroup.clearDeviceSelection(event.type);
207 const slotControlName = `${event.type}Slots`;
208 this.form.get(slotControlName).setValue(0, { emitEvent: false });
209 }
210 }
211
212 submit() {
213 // use user name and timestamp for drive group name
214 const user = this.authStorageService.getUsername();
215 this.driveGroup.setName(`dashboard-${user}-${_.now()}`);
f67539c2
TL
216 const modalRef = this.modalService.show(OsdCreationPreviewModalComponent, {
217 driveGroups: [this.driveGroup.spec]
9f95a23c 218 });
f67539c2 219 modalRef.componentInstance.submitAction.subscribe(() => {
9f95a23c
TL
220 this.router.navigate(['/osd']);
221 });
f67539c2 222 this.previewButtonPanel.submitButton.loading = false;
9f95a23c
TL
223 }
224}