1 <cd-loading-panel *
ngIf=
"!(info && ecProfiles)"
2 i18n
>Loading...
</cd-loading-panel>
4 <div class=
"cd-col-form">
6 *
ngIf=
"info && ecProfiles"
11 <div i18n=
"form title|Example: Create Pool@@formTitle"
12 class=
"card-header">{{ action | titlecase }} {{ resource | upperFirst }}
</div>
14 <div class=
"card-body">
16 <div class=
"form-group row">
17 <label class=
"cd-col-form-label required"
20 <div class=
"cd-col-form-input">
27 formControlName=
"name"
29 <span class=
"invalid-feedback"
30 *
ngIf=
"form.showError('name', formDir, 'required')"
31 i18n
>This field is required!
</span>
32 <span class=
"invalid-feedback"
33 *
ngIf=
"form.showError('name', formDir, 'uniqueName')"
34 i18n
>The chosen Ceph pool name is already in use.
</span>
35 <span *
ngIf=
"form.showError('name', formDir, 'rbdPool')"
36 class=
"invalid-feedback"
37 i18n
>It's not possible to create an RBD pool with '/' in the name.
38 Please change the name or remove 'rbd' from the applications list.
</span>
39 <span *
ngIf=
"form.showError('name', formDir, 'pattern')"
40 class=
"invalid-feedback"
41 i18n
>Pool name can only contain letters, numbers, '.', '-', '_' or '/'.
</span>
45 <!-- Pool type selection -->
46 <div class=
"form-group row">
47 <label class=
"cd-col-form-label required"
49 i18n
>Pool type
</label>
50 <div class=
"cd-col-form-input">
51 <select class=
"form-control custom-select"
53 formControlName=
"poolType"
56 i18n
>-- Select a pool type --
</option>
57 <option *
ngFor=
"let poolType of data.poolTypes"
62 <span class=
"invalid-feedback"
63 *
ngIf=
"form.showError('poolType', formDir, 'required')"
64 i18n
>This field is required!
</span>
68 <div *
ngIf=
"isReplicated || isErasure">
69 <!-- PG Autoscale Mode -->
70 <div class=
"form-group row">
72 class=
"cd-col-form-label"
73 for=
"pgAutoscaleMode">PG Autoscale
</label>
74 <div class=
"cd-col-form-input">
75 <select class=
"form-control custom-select"
77 name=
"pgAutoscaleMode"
78 formControlName=
"pgAutoscaleMode">
79 <option *
ngFor=
"let mode of pgAutoscaleModes"
88 <div class=
"form-group row"
89 *
ngIf=
"form.getValue('pgAutoscaleMode') !== 'on'">
90 <label class=
"cd-col-form-label required"
92 i18n
>Placement groups
</label>
93 <div class=
"cd-col-form-input">
94 <input class=
"form-control"
97 formControlName=
"pgNum"
100 (focus)=
"externalPgChange = false"
103 <span class=
"invalid-feedback"
104 *
ngIf=
"form.showError('pgNum', formDir, 'required')"
105 i18n
>This field is required!
</span>
106 <span class=
"invalid-feedback"
107 *
ngIf=
"form.showError('pgNum', formDir, 'min')"
108 i18n
>At least one placement group is needed!
</span>
109 <span class=
"invalid-feedback"
110 *
ngIf=
"form.showError('pgNum', formDir, '34')"
111 i18n
>Your cluster can't handle this many PGs. Please recalculate the PG amount needed.
</span>
112 <span class=
"form-text text-muted">
113 <cd-doc section=
"pgs"
114 docText=
"Calculation help"
115 i18n-docText
></cd-doc>
117 <span class=
"form-text text-muted"
118 *
ngIf=
"externalPgChange"
119 i18n
>The current PGs settings were calculated for you, you
120 should make sure the values suit your needs before submit.
</span>
124 <!-- Replica Size -->
125 <div class=
"form-group row"
126 *
ngIf=
"isReplicated">
127 <label class=
"cd-col-form-label required"
129 i18n
>Replicated size
</label>
130 <div class=
"cd-col-form-input">
131 <input class=
"form-control"
137 formControlName=
"size">
138 <span class=
"invalid-feedback"
139 *
ngIf=
"form.showError('size', formDir)">
140 <ul class=
"list-inline">
141 <li i18n
>Minimum: {{ getMinSize() }}
</li>
142 <li i18n
>Maximum: {{ getMaxSize() }}
</li>
145 <span class=
"invalid-feedback"
146 *
ngIf=
"form.showError('size', formDir)"
147 i18n
>The size specified is out of range. A value from
148 {{ getMinSize() }} to {{ getMaxSize() }} is usable.
</span>
153 <div class=
"form-group row"
154 *
ngIf=
"info.is_all_bluestore && isErasure">
156 class=
"cd-col-form-label">Flags
</label>
157 <div class=
"cd-col-form-input">
158 <div class=
"custom-control custom-checkbox">
159 <input type=
"checkbox"
160 class=
"custom-control-input"
162 formControlName=
"ecOverwrites">
163 <label class=
"custom-control-label"
165 i18n
>EC Overwrites
</label>
171 <!-- Applications -->
172 <div class=
"form-group row">
174 class=
"cd-col-form-label"
175 for=
"applications">Applications
</label>
176 <div class=
"cd-col-form-input">
177 <cd-select-badges id=
"applications"
178 [customBadges]=
"true"
179 [customBadgeValidators]=
"data.applications.validators"
180 [messages]=
"data.applications.messages"
181 [data]=
"data.applications.selected"
182 [options]=
"data.applications.available"
184 (selection)=
"appSelection()">
190 <div *
ngIf=
"isErasure || isReplicated">
192 <legend i18n
>CRUSH
</legend>
194 <!-- Erasure Profile select -->
195 <div class=
"form-group row"
198 class=
"cd-col-form-label"
199 for=
"erasureProfile">Erasure code profile
</label>
200 <div class=
"cd-col-form-input">
201 <div class=
"input-group">
202 <select class=
"form-control custom-select"
204 name=
"erasureProfile"
205 formControlName=
"erasureProfile">
206 <option *
ngIf=
"!ecProfiles"
208 i18n
>Loading...
</option>
209 <option *
ngIf=
"ecProfiles && ecProfiles.length === 0"
211 i18n
>-- No erasure code profile available --
</option>
212 <option *
ngIf=
"ecProfiles && ecProfiles.length > 0"
214 i18n
>-- Select an erasure code profile --
</option>
215 <option *
ngFor=
"let ecp of ecProfiles"
220 <span class=
"input-group-append">
221 <button class=
"btn btn-light"
222 [ngClass]=
"{'active': data.erasureInfo}"
225 (click)=
"data.erasureInfo = !data.erasureInfo">
226 <i [ngClass]=
"[icons.questionCircle]"
227 aria-hidden=
"true"></i>
229 <button class=
"btn btn-light"
232 (click)=
"addErasureCodeProfile()">
233 <i [ngClass]=
"[icons.add]"
234 aria-hidden=
"true"></i>
236 <button class=
"btn btn-light"
239 tooltip=
"This profile can't be deleted as it is in use."
242 #
ecpDeletionBtn=
"bs-tooltip"
243 (click)=
"deleteErasureCodeProfile()">
244 <i [ngClass]=
"[icons.trash]"
245 aria-hidden=
"true"></i>
249 <span class=
"form-text text-muted"
251 *
ngIf=
"data.erasureInfo && form.getValue('erasureProfile')">
252 <tabset #ecpInfoTabs
>
256 <cd-table-key-value [renderObjects]=
"true"
257 [hideKeys]=
"['name']"
258 [data]=
"form.getValue('erasureProfile')"
259 [autoReload]=
"false">
260 </cd-table-key-value>
263 heading=
"Used by pools"
264 class=
"used-by-pools">
265 <ng-template #ecpIsNotUsed
>
266 <span i18n
>Profile is not in use.
</span>
268 <ul *
ngIf=
"ecpUsage; else ecpIsNotUsed">
269 <li *
ngFor=
"let pool of ecpUsage">
279 <!-- Crush ruleset selection -->
280 <div class=
"form-group row"
281 *
ngIf=
"isErasure && !editing">
282 <label class=
"cd-col-form-label"
284 i18n
>Crush ruleset
</label>
285 <div class=
"cd-col-form-input">
286 <span class=
"form-text text-muted"
287 i18n
>A new crush ruleset will be implicitly created.
</span>
290 <div class=
"form-group row"
291 *
ngIf=
"isReplicated || editing">
292 <label class=
"cd-col-form-label"
294 i18n
>Crush ruleset
</label>
295 <div class=
"cd-col-form-input">
296 <ng-template #noRules
>
297 <span class=
"form-text text-muted">
298 <span i18n
>There are no rules.
</span>
301 <div *
ngIf=
"current.rules.length > 0; else noRules">
302 <div class=
"input-group">
303 <select class=
"form-control custom-select"
305 formControlName=
"crushRule"
307 <option [ngValue]=
"null"
308 i18n
>-- Select a crush rule --
</option>
309 <option *
ngFor=
"let rule of current.rules"
314 <span class=
"input-group-append">
315 <button class=
"btn btn-light"
316 [ngClass]=
"{'active': data.crushInfo}"
317 id=
"crush-info-button"
319 (click)=
"data.crushInfo = !data.crushInfo">
320 <i [ngClass]=
"[icons.questionCircle]"
321 aria-hidden=
"true"></i>
323 <button class=
"btn btn-light"
325 *
ngIf=
"isReplicated && !editing"
326 (click)=
"addCrushRule()">
327 <i [ngClass]=
"[icons.add]"
328 aria-hidden=
"true"></i>
330 <button class=
"btn btn-light"
331 *
ngIf=
"isReplicated && !editing"
333 tooltip=
"This rule can't be deleted as it is in use."
336 #
crushDeletionBtn=
"bs-tooltip"
337 (click)=
"deleteCrushRule()">
338 <i [ngClass]=
"[icons.trash]"
339 aria-hidden=
"true"></i>
343 <span class=
"form-text text-muted"
344 id=
"crush-info-block"
345 *
ngIf=
"data.crushInfo && form.getValue('crushRule')">
346 <tabset #crushInfoTabs
>
349 class=
"crush-rule-info">
350 <cd-table-key-value [renderObjects]=
"false"
351 [hideKeys]=
"['steps', 'ruleset', 'type', 'rule_name']"
352 [data]=
"form.getValue('crushRule')"
353 [autoReload]=
"false">
354 </cd-table-key-value>
357 heading=
"Crush steps"
358 class=
"crush-rule-steps">
360 <li *
ngFor=
"let step of form.get('crushRule').value.steps">
361 {{ describeCrushStep(step) }}
366 heading=
"Used by pools"
367 class=
"used-by-pools">
368 <ng-template #ruleIsNotUsed
>
369 <span i18n
>Rule is not in use.
</span>
371 <ul *
ngIf=
"crushUsage; else ruleIsNotUsed">
372 <li *
ngFor=
"let pool of crushUsage">
379 <span class=
"invalid-feedback"
380 *
ngIf=
"form.showError('crushRule', formDir, 'required')"
381 i18n
>This field is required!
</span>
382 <span class=
"invalid-feedback"
383 *
ngIf=
"form.showError('crushRule', formDir, 'tooFewOsds')"
384 i18n
>The rule can't be used in the current cluster as it has
385 too few OSDs to meet the minimum required OSD by this rule.
</span>
393 <div *
ngIf=
"info.is_all_bluestore"
394 formGroupName=
"compression">
395 <legend i18n
>Compression
</legend>
397 <!-- Compression Mode -->
398 <div class=
"form-group row">
400 class=
"cd-col-form-label"
401 for=
"mode">Mode
</label>
402 <div class=
"cd-col-form-input">
403 <select class=
"form-control custom-select"
406 formControlName=
"mode">
407 <option *
ngFor=
"let mode of info.compression_modes"
414 <div *
ngIf=
"hasCompressionEnabled()">
415 <!-- Compression algorithm selection -->
416 <div class=
"form-group row">
418 class=
"cd-col-form-label"
419 for=
"algorithm">Algorithm
</label>
420 <div class=
"cd-col-form-input">
421 <select class=
"form-control custom-select"
424 formControlName=
"algorithm">
425 <option *
ngIf=
"!info.compression_algorithms"
427 i18n
>Loading...
</option>
428 <option *
ngIf=
"info.compression_algorithms && info.compression_algorithms.length === 0"
430 ngValue=
"">-- No erasure compression algorithm available --
</option>
431 <option *
ngFor=
"let algorithm of info.compression_algorithms"
439 <!-- Compression min blob size -->
440 <div class=
"form-group row">
442 class=
"cd-col-form-label"
443 for=
"minBlobSize">Minimum blob size
</label>
444 <div class=
"cd-col-form-input">
445 <input id=
"minBlobSize"
447 formControlName=
"minBlobSize"
452 placeholder=
"e.g., 128KiB"
455 <span class=
"invalid-feedback"
456 *
ngIf=
"form.showError('minBlobSize', formDir, 'min')"
457 i18n
>Value should be greater than
0</span>
458 <span class=
"invalid-feedback"
459 *
ngIf=
"form.showError('minBlobSize', formDir, 'maximum')"
460 i18n
>Value should be less than the maximum blob size
</span>
464 <!-- Compression max blob size -->
465 <div class=
"form-group row">
467 class=
"cd-col-form-label"
468 for=
"maxBlobSize">Maximum blob size
</label>
469 <div class=
"cd-col-form-input">
470 <input id=
"maxBlobSize"
473 formControlName=
"maxBlobSize"
476 placeholder=
"e.g., 512KiB"
479 <span class=
"invalid-feedback"
480 *
ngIf=
"form.showError('maxBlobSize', formDir, 'min')"
481 i18n
>Value should be greater than
0</span>
482 <span class=
"invalid-feedback"
483 *
ngIf=
"form.showError('maxBlobSize', formDir, 'minimum')"
484 i18n
>Value should be greater than the minimum blob size
</span>
488 <!-- Compression ratio -->
489 <div class=
"form-group row">
491 class=
"cd-col-form-label"
492 for=
"ratio">Ratio
</label>
493 <div class=
"cd-col-form-input">
496 formControlName=
"ratio"
503 placeholder=
"Compression ratio">
504 <span class=
"invalid-feedback"
505 *
ngIf=
"form.showError('ratio', formDir, 'min') || form.showError('ratio', formDir, 'max')"
506 i18n
>Value should be between
0.0 and
1.0</span>
515 <legend i18n
>Quotas
</legend>
518 <div class=
"form-group row">
519 <label class=
"cd-col-form-label"
521 <ng-container i18n
>Max bytes
</ng-container>
523 <span i18n
>Leave it blank or specify
0 to disable this quota.
</span>
525 <span i18n
>A valid quota should be greater than
0.
</span>
528 <div class=
"cd-col-form-input">
529 <input class=
"form-control"
533 formControlName=
"max_bytes"
535 placeholder=
"e.g., 10GiB"
542 <div class=
"form-group row">
543 <label class=
"cd-col-form-label"
545 <ng-container i18n
>Max objects
</ng-container>
547 <span i18n
>Leave it blank or specify
0 to disable this quota.
</span>
549 <span i18n
>A valid quota should be greater than
0.
</span>
552 <div class=
"cd-col-form-input">
553 <input class=
"form-control"
558 formControlName=
"max_objects">
559 <span class=
"invalid-feedback"
560 *
ngIf=
"form.showError('max_objects', formDir, 'min')"
561 i18n
>The value should be greater or equal to
0</span>
566 <!-- Pool configuration -->
567 <div [hidden]=
"isErasure || data.applications.selected.indexOf('rbd') === -1">
568 <cd-rbd-configuration-form [form]=
"form"
569 [initializeData]=
"initializeConfigData"
570 (changes)=
"currentConfigurationValues = $event()">
571 </cd-rbd-configuration-form>
574 <div class=
"card-footer">
575 <div class=
"button-group text-right">
576 <cd-submit-button [form]=
"formDir"
577 i18n=
"form action button|Example: Create Pool@@formActionButton"
578 (submitAction)=
"submit()">{{ action | titlecase }} {{ resource | upperFirst }}
580 <cd-back-button></cd-back-button>