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