]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
7d2734b61f63aacbf1ab825491bfc9999bc0f22a
[ceph-ci.git] /
1 import { Component } from '@angular/core';
2 import { AbstractControl, ValidationErrors, Validators } from '@angular/forms';
3 import { Router } from '@angular/router';
4 import { RgwUserAccountsService } from '~/app/shared/api/rgw-user-accounts.service';
5 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
6 import { CdForm } from '~/app/shared/forms/cd-form';
7 import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
8 import { Account } from '../models/rgw-user-accounts';
9 import { NotificationService } from '~/app/shared/services/notification.service';
10 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
11 import { CdValidators, isEmptyInputValue } from '~/app/shared/forms/cd-validators';
12 import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
13 import { FormatterService } from '~/app/shared/services/formatter.service';
14 import { Observable, concat as observableConcat } from 'rxjs';
15
16 @Component({
17   selector: 'cd-rgw-user-accounts-form',
18   templateUrl: './rgw-user-accounts-form.component.html',
19   styleUrls: ['./rgw-user-accounts-form.component.scss']
20 })
21 export class RgwUserAccountsFormComponent extends CdForm {
22   accountForm: CdFormGroup;
23   action: string;
24   resource: string;
25   editing: boolean = false;
26   submitObservables: Observable<Object>[] = [];
27
28   constructor(
29     private router: Router,
30     private actionLabels: ActionLabelsI18n,
31     private rgwUserAccountsService: RgwUserAccountsService,
32     private notificationService: NotificationService,
33     private formBuilder: CdFormBuilder
34   ) {
35     super();
36     this.editing = this.router.url.includes('rgw/accounts/edit');
37     this.action = this.editing ? this.actionLabels.EDIT : this.actionLabels.CREATE;
38     this.resource = $localize`Account`;
39     this.createForm();
40     this.loadingReady();
41   }
42
43   private createForm() {
44     this.accountForm = this.formBuilder.group({
45       account_id: [''],
46       tenant: [''],
47       account_name: ['', Validators.required],
48       email: ['', CdValidators.email],
49       max_users_mode: [1],
50       max_users: [
51         1000,
52         [CdValidators.requiredIf({ max_users_mode: '1' }), CdValidators.number(false)]
53       ],
54       max_roles_mode: [1],
55       max_roles: [
56         1000,
57         [CdValidators.requiredIf({ max_roles_mode: '1' }), CdValidators.number(false)]
58       ],
59       max_group_mode: [1],
60       max_group: [
61         1000,
62         [CdValidators.requiredIf({ max_group_mode: '1' }), CdValidators.number(false)]
63       ],
64       max_access_keys_mode: [1],
65       max_access_keys: [
66         4,
67         [CdValidators.requiredIf({ max_access_keys_mode: '1' }), CdValidators.number(false)]
68       ],
69       max_buckets_mode: [1],
70       max_buckets: [
71         1000,
72         [CdValidators.requiredIf({ max_buckets_mode: '1' }), CdValidators.number(false)]
73       ],
74       account_quota_enabled: [false],
75       account_quota_max_size_unlimited: [true],
76       account_quota_max_size: [
77         null,
78         [
79           CdValidators.composeIf(
80             {
81               account_quota_enabled: true,
82               account_quota_max_size_unlimited: false
83             },
84             [Validators.required, this.quotaMaxSizeValidator]
85           )
86         ]
87       ],
88       account_quota_max_objects_unlimited: [true],
89       account_quota_max_objects: [
90         null,
91         [
92           CdValidators.requiredIf({
93             account_quota_enabled: true,
94             account_quota_max_objects_unlimited: false
95           }),
96           Validators.pattern(/^[0-9]+$/)
97         ]
98       ],
99       bucket_quota_enabled: [false],
100       bucket_quota_max_size_unlimited: [true],
101       bucket_quota_max_size: [
102         null,
103         [
104           CdValidators.composeIf(
105             {
106               bucket_quota_enabled: true,
107               bucket_quota_max_size_unlimited: false
108             },
109             [Validators.required, this.quotaMaxSizeValidator]
110           )
111         ]
112       ],
113       bucket_quota_max_objects_unlimited: [true],
114       bucket_quota_max_objects: [
115         null,
116         [
117           CdValidators.requiredIf({
118             bucket_quota_enabled: true,
119             bucket_quota_max_objects_unlimited: false
120           }),
121           Validators.pattern(/^[0-9]+$/)
122         ]
123       ]
124     });
125   }
126
127   /**
128    * Validate the quota maximum size, e.g. 1096, 1K, 30M or 1.9MiB.
129    */
130   quotaMaxSizeValidator(control: AbstractControl): ValidationErrors | null {
131     if (isEmptyInputValue(control.value)) {
132       return null;
133     }
134     const m = RegExp('^(\\d+(\\.\\d+)?)\\s*(B|K(B|iB)?|M(B|iB)?|G(B|iB)?|T(B|iB)?)?$', 'i').exec(
135       control.value
136     );
137     if (m === null) {
138       return { quotaMaxSize: true };
139     }
140     const bytes = new FormatterService().toBytes(control.value);
141     return bytes < 1024 ? { quotaMaxSize: true } : null;
142   }
143
144   submit() {
145     let notificationTitle: string = '';
146     if (this.accountForm.invalid) {
147       return;
148     }
149
150     if (this.accountForm.pending) {
151       this.accountForm.setErrors({ cdSubmitButton: true });
152       return;
153     }
154
155     if (!this.editing) {
156       const formvalue = this.accountForm.value;
157       const createPayload = {
158         account_id: formvalue.account_id,
159         account_name: formvalue.account_name,
160         email: formvalue.email,
161         tenant: formvalue.tenant,
162         max_users: this.getValueFromFormControl('max_users'),
163         max_buckets: this.getValueFromFormControl('max_buckets'),
164         max_roles: this.getValueFromFormControl('max_roles'),
165         max_group: this.getValueFromFormControl('max_group'),
166         max_access_keys: this.getValueFromFormControl('max_access_keys')
167       };
168       notificationTitle = $localize`Account created successfully`;
169       this.rgwUserAccountsService.create(createPayload).subscribe({
170         next: (account: Account) => {
171           this.accountForm.get('account_id').setValue(account.id);
172           this.setQuotaConfig();
173           this.notificationService.show(NotificationType.success, notificationTitle);
174         },
175         error: () => {
176           // Reset the 'Submit' button.
177           this.accountForm.setErrors({ cdSubmitButton: true });
178         }
179       });
180     }
181   }
182
183   setQuotaConfig() {
184     const accountId: string = this.accountForm.get('account_id').value;
185     // Check if account quota has been modified.
186     if (this._isQuotaConfDirty('account')) {
187       const accountQuotaArgs = this._getQuotaArgs('account');
188       this.submitObservables.push(
189         this.rgwUserAccountsService.setQuota(accountId, accountQuotaArgs)
190       );
191     }
192     // Check if bucket quota has been modified.
193     if (this._isQuotaConfDirty('bucket')) {
194       const bucketQuotaArgs = this._getQuotaArgs('bucket');
195       this.submitObservables.push(this.rgwUserAccountsService.setQuota(accountId, bucketQuotaArgs));
196     }
197     // Finally execute all observables one by one in serial.
198     observableConcat(...this.submitObservables).subscribe({
199       error: () => {
200         // Reset the 'Submit' button.
201         this.accountForm.setErrors({ cdSubmitButton: true });
202       },
203       complete: () => {
204         this.goToListView();
205       }
206     });
207     if (this.submitObservables.length == 0) {
208       this.goToListView();
209     }
210   }
211
212   /**
213    * Helper function to get the arguments for the API request when any
214    * quota configuration has been modified.
215    */
216   private _getQuotaArgs(quotaType: string) {
217     const result = {
218       quota_type: quotaType,
219       enabled: this.accountForm.getValue(`${quotaType}_quota_enabled`),
220       max_size: '-1',
221       max_objects: '-1'
222     };
223     if (!this.accountForm.getValue(`${quotaType}_quota_max_size_unlimited`)) {
224       // Convert the given value to bytes.
225       const bytes = new FormatterService().toBytes(
226         this.accountForm.getValue(`${quotaType}_quota_max_size`)
227       );
228       // Finally convert the value to KiB.
229       result['max_size'] = (bytes / 1024).toFixed(0) as any;
230     }
231     if (!this.accountForm.getValue(`${quotaType}_quota_max_objects_unlimited`)) {
232       result['max_objects'] = `${this.accountForm.getValue(`${quotaType}_quota_max_objects`)}`;
233     }
234     return result;
235   }
236
237   /**
238    * Check if any quota has been modified.
239    * @return {Boolean} Returns TRUE if the quota has been modified.
240    */
241   private _isQuotaConfDirty(quotaType: string): boolean {
242     if (this.accountForm.get(`${quotaType}_quota_enabled`).value) {
243       return [
244         `${quotaType}_quota_enabled`,
245         `${quotaType}_quota_max_size_unlimited`,
246         `${quotaType}_quota_max_size`,
247         `${quotaType}_quota_max_objects_unlimited`,
248         `${quotaType}_quota_max_objects`
249       ].some((path) => {
250         return this.accountForm.get(path).dirty;
251       });
252     }
253     return false;
254   }
255
256   onModeChange(mode: string, formControlName: string) {
257     if (mode === '1') {
258       // If 'Custom' mode is selected, then ensure that the form field
259       // 'Max. buckets' contains a valid value. Set it to default if
260       // necessary.
261       if (!this.accountForm.get(formControlName).valid) {
262         this.accountForm.patchValue({
263           [formControlName]: 1000
264         });
265       }
266     }
267   }
268
269   goToListView(): void {
270     this.router.navigate(['rgw/accounts']);
271   }
272
273   getValueFromFormControl(formControlName: string) {
274     const formvalue = this.accountForm.value;
275     return formvalue[`${formControlName}_mode`] == 1
276       ? formvalue[formControlName]
277       : formvalue[`${formControlName}_mode`];
278   }
279 }