]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; |
2 | ||
3 | import { I18n } from '@ngx-translate/i18n-polyfill'; | |
4 | import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; | |
5 | import { Observable } from 'rxjs'; | |
6 | ||
7 | import { OsdService } from '../../../../shared/api/osd.service'; | |
8 | import { ConfirmationModalComponent } from '../../../../shared/components/confirmation-modal/confirmation-modal.component'; | |
9 | import { CriticalConfirmationModalComponent } from '../../../../shared/components/critical-confirmation-modal/critical-confirmation-modal.component'; | |
10 | import { TableComponent } from '../../../../shared/datatable/table/table.component'; | |
11 | import { CellTemplate } from '../../../../shared/enum/cell-template.enum'; | |
12 | import { CdTableAction } from '../../../../shared/models/cd-table-action'; | |
13 | import { CdTableColumn } from '../../../../shared/models/cd-table-column'; | |
14 | import { CdTableSelection } from '../../../../shared/models/cd-table-selection'; | |
15 | import { Permissions } from '../../../../shared/models/permissions'; | |
16 | import { DimlessBinaryPipe } from '../../../../shared/pipes/dimless-binary.pipe'; | |
17 | import { AuthStorageService } from '../../../../shared/services/auth-storage.service'; | |
18 | import { OsdFlagsModalComponent } from '../osd-flags-modal/osd-flags-modal.component'; | |
19 | import { OsdRecvSpeedModalComponent } from '../osd-recv-speed-modal/osd-recv-speed-modal.component'; | |
20 | import { OsdReweightModalComponent } from '../osd-reweight-modal/osd-reweight-modal.component'; | |
21 | import { OsdScrubModalComponent } from '../osd-scrub-modal/osd-scrub-modal.component'; | |
22 | ||
23 | @Component({ | |
24 | selector: 'cd-osd-list', | |
25 | templateUrl: './osd-list.component.html', | |
26 | styleUrls: ['./osd-list.component.scss'] | |
27 | }) | |
28 | export class OsdListComponent implements OnInit { | |
29 | @ViewChild('statusColor') | |
30 | statusColor: TemplateRef<any>; | |
31 | @ViewChild('osdUsageTpl') | |
32 | osdUsageTpl: TemplateRef<any>; | |
33 | @ViewChild('markOsdConfirmationTpl') | |
34 | markOsdConfirmationTpl: TemplateRef<any>; | |
35 | @ViewChild('criticalConfirmationTpl') | |
36 | criticalConfirmationTpl: TemplateRef<any>; | |
37 | @ViewChild(TableComponent) | |
38 | tableComponent: TableComponent; | |
39 | @ViewChild('reweightBodyTpl') | |
40 | reweightBodyTpl: TemplateRef<any>; | |
41 | @ViewChild('safeToDestroyBodyTpl') | |
42 | safeToDestroyBodyTpl: TemplateRef<any>; | |
43 | ||
44 | permissions: Permissions; | |
45 | tableActions: CdTableAction[]; | |
46 | bsModalRef: BsModalRef; | |
47 | columns: CdTableColumn[]; | |
48 | ||
49 | osds = []; | |
50 | selection = new CdTableSelection(); | |
51 | ||
52 | protected static collectStates(osd) { | |
53 | return [osd['in'] ? 'in' : 'out', osd['up'] ? 'up' : 'down']; | |
54 | } | |
55 | ||
56 | constructor( | |
57 | private authStorageService: AuthStorageService, | |
58 | private osdService: OsdService, | |
59 | private dimlessBinaryPipe: DimlessBinaryPipe, | |
60 | private modalService: BsModalService, | |
61 | private i18n: I18n | |
62 | ) { | |
63 | this.permissions = this.authStorageService.getPermissions(); | |
64 | this.tableActions = [ | |
65 | { | |
66 | name: this.i18n('Scrub'), | |
67 | permission: 'update', | |
68 | icon: 'fa-stethoscope', | |
69 | click: () => this.scrubAction(false), | |
70 | disable: () => !this.hasOsdSelected | |
71 | }, | |
72 | { | |
73 | name: this.i18n('Deep Scrub'), | |
74 | permission: 'update', | |
75 | icon: 'fa-cog', | |
76 | click: () => this.scrubAction(true), | |
77 | disable: () => !this.hasOsdSelected | |
78 | }, | |
79 | { | |
80 | name: this.i18n('Reweight'), | |
81 | permission: 'update', | |
82 | click: () => this.reweight(), | |
83 | disable: () => !this.hasOsdSelected, | |
84 | icon: 'fa-balance-scale' | |
85 | }, | |
86 | { | |
87 | name: this.i18n('Mark Out'), | |
88 | permission: 'update', | |
89 | click: () => this.showConfirmationModal(this.i18n('out'), this.osdService.markOut), | |
90 | disable: () => this.isNotSelectedOrInState('out'), | |
91 | icon: 'fa-arrow-left' | |
92 | }, | |
93 | { | |
94 | name: this.i18n('Mark In'), | |
95 | permission: 'update', | |
96 | click: () => this.showConfirmationModal(this.i18n('in'), this.osdService.markIn), | |
97 | disable: () => this.isNotSelectedOrInState('in'), | |
98 | icon: 'fa-arrow-right' | |
99 | }, | |
100 | { | |
101 | name: this.i18n('Mark Down'), | |
102 | permission: 'update', | |
103 | click: () => this.showConfirmationModal(this.i18n('down'), this.osdService.markDown), | |
104 | disable: () => this.isNotSelectedOrInState('down'), | |
105 | icon: 'fa-arrow-down' | |
106 | }, | |
107 | { | |
108 | name: this.i18n('Mark Lost'), | |
109 | permission: 'delete', | |
110 | click: () => | |
111 | this.showCriticalConfirmationModal( | |
112 | this.i18n('Mark'), | |
113 | this.i18n('OSD lost'), | |
114 | this.i18n('marked lost'), | |
115 | this.osdService.markLost | |
116 | ), | |
117 | disable: () => this.isNotSelectedOrInState('up'), | |
118 | icon: 'fa-unlink' | |
119 | }, | |
120 | { | |
121 | name: this.i18n('Purge'), | |
122 | permission: 'delete', | |
123 | click: () => | |
124 | this.showCriticalConfirmationModal( | |
125 | this.i18n('Purge'), | |
126 | this.i18n('OSD'), | |
127 | this.i18n('purged'), | |
128 | this.osdService.purge | |
129 | ), | |
130 | disable: () => this.isNotSelectedOrInState('up'), | |
131 | icon: 'fa-eraser' | |
132 | }, | |
133 | { | |
134 | name: this.i18n('Destroy'), | |
135 | permission: 'delete', | |
136 | click: () => | |
137 | this.showCriticalConfirmationModal( | |
138 | this.i18n('destroy'), | |
139 | this.i18n('OSD'), | |
140 | this.i18n('destroyed'), | |
141 | this.osdService.destroy | |
142 | ), | |
143 | disable: () => this.isNotSelectedOrInState('up'), | |
144 | icon: 'fa-remove' | |
145 | } | |
146 | ]; | |
147 | } | |
148 | ||
149 | ngOnInit() { | |
150 | this.columns = [ | |
151 | { prop: 'host.name', name: this.i18n('Host') }, | |
152 | { prop: 'id', name: this.i18n('ID'), cellTransformation: CellTemplate.bold }, | |
153 | { prop: 'collectedStates', name: this.i18n('Status'), cellTemplate: this.statusColor }, | |
154 | { prop: 'stats.numpg', name: this.i18n('PGs') }, | |
155 | { prop: 'stats.stat_bytes', name: this.i18n('Size'), pipe: this.dimlessBinaryPipe }, | |
156 | { name: this.i18n('Usage'), cellTemplate: this.osdUsageTpl }, | |
157 | { | |
158 | prop: 'stats_history.out_bytes', | |
159 | name: this.i18n('Read bytes'), | |
160 | cellTransformation: CellTemplate.sparkline | |
161 | }, | |
162 | { | |
163 | prop: 'stats_history.in_bytes', | |
164 | name: this.i18n('Writes bytes'), | |
165 | cellTransformation: CellTemplate.sparkline | |
166 | }, | |
167 | { | |
168 | prop: 'stats.op_r', | |
169 | name: this.i18n('Read ops'), | |
170 | cellTransformation: CellTemplate.perSecond | |
171 | }, | |
172 | { | |
173 | prop: 'stats.op_w', | |
174 | name: this.i18n('Write ops'), | |
175 | cellTransformation: CellTemplate.perSecond | |
176 | } | |
177 | ]; | |
178 | } | |
179 | ||
180 | get hasOsdSelected() { | |
181 | if (this.selection.hasSelection) { | |
182 | const osdId = this.selection.first().id; | |
183 | const osd = this.osds.filter((o) => o.id === osdId).pop(); | |
184 | return !!osd; | |
185 | } | |
186 | return false; | |
187 | } | |
188 | ||
189 | updateSelection(selection: CdTableSelection) { | |
190 | this.selection = selection; | |
191 | } | |
192 | ||
193 | /** | |
194 | * Returns true if no row is selected or if the selected row is in the given | |
195 | * state. Useful for deactivating the corresponding menu entry. | |
196 | */ | |
197 | isNotSelectedOrInState(state: 'in' | 'up' | 'down' | 'out'): boolean { | |
198 | if (!this.hasOsdSelected) { | |
199 | return true; | |
200 | } | |
201 | ||
202 | const osdId = this.selection.first().id; | |
203 | const osd = this.osds.filter((o) => o.id === osdId).pop(); | |
204 | ||
205 | if (!osd) { | |
206 | // `osd` is undefined if the selected OSD has been removed. | |
207 | return true; | |
208 | } | |
209 | ||
210 | switch (state) { | |
211 | case 'in': | |
212 | return osd.in === 1; | |
213 | case 'out': | |
214 | return osd.in !== 1; | |
215 | case 'down': | |
216 | return osd.up !== 1; | |
217 | case 'up': | |
218 | return osd.up === 1; | |
219 | } | |
220 | } | |
221 | ||
222 | getOsdList() { | |
223 | this.osdService.getList().subscribe((data: any[]) => { | |
224 | this.osds = data; | |
225 | data.map((osd) => { | |
226 | osd.collectedStates = OsdListComponent.collectStates(osd); | |
227 | osd.stats_history.out_bytes = osd.stats_history.op_out_bytes.map((i) => i[1]); | |
228 | osd.stats_history.in_bytes = osd.stats_history.op_in_bytes.map((i) => i[1]); | |
229 | osd.cdIsBinary = true; | |
230 | return osd; | |
231 | }); | |
232 | }); | |
233 | } | |
234 | ||
235 | scrubAction(deep) { | |
236 | if (!this.hasOsdSelected) { | |
237 | return; | |
238 | } | |
239 | ||
240 | const initialState = { | |
241 | selected: this.tableComponent.selection.selected, | |
242 | deep: deep | |
243 | }; | |
244 | ||
245 | this.bsModalRef = this.modalService.show(OsdScrubModalComponent, { initialState }); | |
246 | } | |
247 | ||
248 | configureClusterAction() { | |
249 | this.bsModalRef = this.modalService.show(OsdFlagsModalComponent, {}); | |
250 | } | |
251 | ||
252 | showConfirmationModal(markAction: string, onSubmit: (id: number) => Observable<any>) { | |
253 | this.bsModalRef = this.modalService.show(ConfirmationModalComponent, { | |
254 | initialState: { | |
255 | titleText: this.i18n('Mark OSD {{markAction}}', { markAction: markAction }), | |
256 | buttonText: this.i18n('Mark {{markAction}}', { markAction: markAction }), | |
257 | bodyTpl: this.markOsdConfirmationTpl, | |
258 | bodyContext: { | |
259 | markActionDescription: markAction | |
260 | }, | |
261 | onSubmit: () => { | |
262 | onSubmit | |
263 | .call(this.osdService, this.selection.first().id) | |
264 | .subscribe(() => this.bsModalRef.hide()); | |
265 | } | |
266 | } | |
267 | }); | |
268 | } | |
269 | ||
270 | reweight() { | |
271 | const selectedOsd = this.osds.filter((o) => o.id === this.selection.first().id).pop(); | |
272 | this.modalService.show(OsdReweightModalComponent, { | |
273 | initialState: { | |
274 | currentWeight: selectedOsd.weight, | |
275 | osdId: selectedOsd.id | |
276 | } | |
277 | }); | |
278 | } | |
279 | ||
280 | showCriticalConfirmationModal( | |
281 | actionDescription: string, | |
282 | itemDescription: string, | |
283 | templateItemDescription: string, | |
284 | action: (id: number) => Observable<any> | |
285 | ): void { | |
286 | this.osdService.safeToDestroy(this.selection.first().id).subscribe((result) => { | |
287 | const modalRef = this.modalService.show(CriticalConfirmationModalComponent, { | |
288 | initialState: { | |
289 | actionDescription: actionDescription, | |
290 | itemDescription: itemDescription, | |
291 | bodyTemplate: this.criticalConfirmationTpl, | |
292 | bodyContext: { | |
293 | result: result, | |
294 | actionDescription: templateItemDescription | |
295 | }, | |
296 | submitAction: () => { | |
297 | action | |
298 | .call(this.osdService, this.selection.first().id) | |
299 | .subscribe(() => modalRef.hide()); | |
300 | } | |
301 | } | |
302 | }); | |
303 | }); | |
304 | } | |
305 | ||
306 | configureQosParamsAction() { | |
307 | this.bsModalRef = this.modalService.show(OsdRecvSpeedModalComponent, {}); | |
308 | } | |
309 | } |