1 import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
8 } from '@angular/forms';
9 import { ActionLabelsI18n, URLVerbs } from '~/app/shared/constants/app.constants';
10 import { CdForm } from '~/app/shared/forms/cd-form';
11 import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
12 import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
13 import _ from 'lodash';
14 import { ActivatedRoute, Router } from '@angular/router';
15 import { RgwStorageClassService } from '~/app/shared/api/rgw-storage-class.service';
16 import { RgwZonegroupService } from '~/app/shared/api/rgw-zonegroup.service';
19 ALLOW_READ_THROUGH_TEXT,
21 MULTIPART_MIN_PART_TEXT,
22 MULTIPART_SYNC_THRESHOLD_TEXT,
25 RETAIN_HEAD_OBJECT_TEXT,
28 TARGET_ACCESS_KEY_TEXT,
32 TARGET_SECRET_KEY_TEXT,
37 CLOUDS3_STORAGE_CLASS_TEXT,
38 LOCAL_STORAGE_CLASS_TEXT,
39 GLACIER_STORAGE_CLASS_TEXT,
40 GLACIER_RESTORE_DAY_TEXT,
41 GLACIER_RESTORE_TIER_TYPE_TEXT,
43 READTHROUGH_RESTORE_DAYS_TEXT,
44 RESTORE_STORAGE_CLASS_TEXT,
48 STORAGE_CLASS_CONSTANTS,
49 STANDARD_TIER_TYPE_TEXT,
50 EXPEDITED_TIER_TYPE_TEXT,
52 CLOUD_TIER_REQUIRED_FIELDS,
53 GLACIER_REQUIRED_FIELDS,
54 GLACIER_TARGET_STORAGE_CLASS,
68 } from '../models/rgw-storage-class.model';
69 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
70 import { NotificationService } from '~/app/shared/services/notification.service';
71 import { CdValidators } from '~/app/shared/forms/cd-validators';
72 import { FormatterService } from '~/app/shared/services/formatter.service';
73 import validator from 'validator';
74 import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe';
75 import { PoolService } from '~/app/shared/api/pool.service';
76 import { Pool } from '../../pool/pool';
77 import { catchError, map, switchMap } from 'rxjs/operators';
78 import { RGW } from '../utils/constants';
79 import { forkJoin, of } from 'rxjs';
80 import { RgwZoneService } from '~/app/shared/api/rgw-zone.service';
81 import { BucketTieringUtils } from '../utils/rgw-bucket-tiering';
84 selector: 'cd-rgw-storage-class-form',
85 templateUrl: './rgw-storage-class-form.component.html',
86 styleUrls: ['./rgw-storage-class-form.component.scss']
88 export class RgwStorageClassFormComponent extends CdForm implements OnInit {
89 storageClassForm: CdFormGroup;
93 showAdvanced: boolean = false;
94 defaultZoneGroup: string;
95 zonegroupNames: ZoneGroup[];
96 placementTargets: string[] = [];
97 selectedZoneGroup: string;
99 defaultZonegroup: ZoneGroup;
100 zoneGroupDetails: ZoneGroupDetails;
101 storageClassInfo: StorageClass;
102 tierTargetInfo: TierTarget;
103 glacierStorageClassDetails: S3Glacier;
104 allowReadThrough: boolean = false;
105 TIER_TYPE = TIER_TYPE;
106 TIER_TYPE_DISPLAY = TIER_TYPE_DISPLAY;
107 storageClassOptions: TypeOption[];
108 helpTextLabels: TextLabels;
109 typeOptions: TypeOption[];
110 aclTypeLabel = AclTypeLabel;
111 aclHelperText = AclHelperText;
113 removedAclSourceIds: string[] = [];
114 urlValidator = (control: AbstractControl): ValidationErrors | null => {
115 const value = control.value;
116 return !value || validator.isURL(value) ? null : { invalidUrl: true };
123 public actionLabels: ActionLabelsI18n,
124 private formBuilder: CdFormBuilder,
125 private notificationService: NotificationService,
126 private rgwStorageService: RgwStorageClassService,
127 private rgwZoneGroupService: RgwZonegroupService,
128 private router: Router,
129 private route: ActivatedRoute,
130 public formatter: FormatterService,
131 private cdRef: ChangeDetectorRef,
132 private poolService: PoolService,
133 private dimlessBinary: DimlessBinaryPipe,
134 private rgwZoneService: RgwZoneService
137 this.resource = $localize`Tiering Storage Class`;
138 this.editing = this.router.url.startsWith(`/rgw/tiering/${URLVerbs.EDIT}`);
139 this.action = this.editing ? this.actionLabels.EDIT : this.actionLabels.CREATE;
143 this.helpTextLabels = {
144 targetPathText: TARGET_PATH_TEXT,
145 targetEndpointText: TARGET_ENDPOINT_TEXT,
146 targetRegionText: TARGET_REGION_TEXT,
147 targetAccessKeyText: TARGET_ACCESS_KEY_TEXT,
148 targetSecretKeyText: TARGET_SECRET_KEY_TEXT,
149 retainHeadObjectText: RETAIN_HEAD_OBJECT_TEXT,
150 allowReadThroughText: ALLOW_READ_THROUGH_TEXT,
151 storageClassText: LOCAL_STORAGE_CLASS_TEXT,
152 multipartMinPartText: MULTIPART_MIN_PART_TEXT,
153 multipartSyncThresholdText: MULTIPART_SYNC_THRESHOLD_TEXT,
154 tiertypeText: STANDARD_TIER_TYPE_TEXT,
155 glacierRestoreDayText: GLACIER_RESTORE_DAY_TEXT,
156 glacierRestoreTiertypeText: GLACIER_RESTORE_TIER_TYPE_TEXT,
157 restoreDaysText: RESTORE_DAYS_TEXT,
158 readthroughrestoreDaysText: READTHROUGH_RESTORE_DAYS_TEXT,
159 restoreStorageClassText: RESTORE_STORAGE_CLASS_TEXT
161 this.storageClassOptions = [
162 { value: TIER_TYPE.LOCAL, label: TIER_TYPE_DISPLAY.LOCAL },
163 { value: TIER_TYPE.CLOUD_TIER, label: TIER_TYPE_DISPLAY.CLOUD_TIER },
164 { value: TIER_TYPE.GLACIER, label: TIER_TYPE_DISPLAY.GLACIER }
166 this.typeOptions = [...AclTypeOptions];
168 this.storageClassTypeText();
169 this.updateTierTypeHelpText();
170 this.loadZoneGroup();
172 this.route.params.subscribe((params: StorageClass) => {
173 this.storageClassInfo = params;
175 this.rgwStorageService
176 .getPlacement_target(this.storageClassInfo.placement_target)
178 switchMap((placementTargetInfo: PlacementTarget) => {
179 // Set the tierTargetInfo based on the placementTargetInfo and storageClassInfo
180 this.tierTargetInfo = this.getTierTargetByStorageClass(
182 this.storageClassInfo.storage_class
184 const tierType = this.tierTargetInfo?.val?.tier_type ?? TIER_TYPE.LOCAL;
186 // If tierType is LOCAL, make the second API calls
187 if (tierType === TIER_TYPE.LOCAL) {
189 this.poolService.getList(),
190 this.rgwZoneService.getAllZonesInfo()
191 ]).pipe(map(([pools, zones]) => ({ placementTargetInfo, pools, zones })));
194 // If tierType is not LOCAL, just return placementTargetInfo with null pools and zones
195 return of({ placementTargetInfo, pools: null, zones: null });
197 map(({ placementTargetInfo, pools, zones }) => {
198 return { placementTargetInfo, pools, zones };
202 placementTargetInfo: null,
210 placementTargetInfo: PlacementTarget;
211 pools: Pool[] | null;
212 zones: AllZonesResponse | null;
214 let response = this.tierTargetInfo?.val?.s3;
215 this.aclList = response?.acl_mappings || [];
216 this.storageClassForm.patchValue({
217 zonegroup: this.storageClassInfo?.zonegroup_name,
218 region: response?.region,
219 placement_target: this.storageClassInfo?.placement_target,
220 storageClassType: this.tierTargetInfo?.val?.tier_type ?? TIER_TYPE.LOCAL,
221 target_endpoint: response?.endpoint,
222 storage_class: this.storageClassInfo?.storage_class,
223 access_key: response?.access_key,
224 secret_key: response?.secret,
225 target_path: response?.target_path,
226 retain_head_object: this.tierTargetInfo?.val?.retain_head_object || false,
227 multipart_sync_threshold:
228 this.dimlessBinary.transform(response?.multipart_sync_threshold) || '',
229 multipart_min_part_size:
230 this.dimlessBinary.transform(response?.multipart_min_part_size) || '',
231 allow_read_through: this.tierTargetInfo?.val?.allow_read_through || false,
232 restore_storage_class: this.tierTargetInfo?.val?.restore_storage_class,
233 read_through_restore_days: this.tierTargetInfo?.val?.read_through_restore_days,
234 acl_mappings: response?.acl_mappings || []
237 this.storageClassForm.get('storageClassType')?.value === TIER_TYPE.CLOUD_TIER ||
238 this.storageClassForm.get('storageClassType')?.value === TIER_TYPE.GLACIER
241 if (this.aclList.length > 0) {
242 this.aclList.forEach((acl) => {
244 this.formBuilder.group({
245 source_id: [acl.val?.source_id || ''],
246 dest_id: [acl.val?.dest_id || ''],
247 type: [acl.val?.type || AclTypeConst.ID, Validators.required]
255 if (this.tierTargetInfo?.val?.tier_type == TIER_TYPE.GLACIER) {
256 let glacierResponse = this.tierTargetInfo?.val['s3-glacier'];
257 this.storageClassForm.patchValue({
258 glacier_restore_tier_type: glacierResponse.glacier_restore_tier_type,
259 glacier_restore_days: glacierResponse.glacier_restore_days
262 const zoneInfo = BucketTieringUtils.getZoneInfoHelper(data.zones?.zones, {
263 placement_target: this.storageClassInfo?.placement_target,
264 storage_class: this.storageClassInfo?.storage_class
267 this.rgwPools = data.pools.filter((pool: Pool) =>
268 pool.application_metadata?.includes(RGW)
270 this.storageClassForm.get('pool').setValue(zoneInfo.data_pool);
271 this.storageClassForm.get('zone').setValue(zoneInfo.zone_name);
276 this.storageClassForm.get('zonegroup').disable();
277 this.storageClassForm.get('placement_target').disable();
278 this.storageClassForm.get('storage_class').disable();
279 this.storageClassForm.get('zone').disable();
280 this.storageClassForm.get('storageClassType').disable();
283 this.poolService.getList().subscribe((resp: Pool[]) => {
284 // Filter only pools with "rgw" in application_metadata
285 this.rgwPools = resp.filter((pool: Pool) => pool.application_metadata?.includes(RGW));
289 this.storageClassForm.get('storageClassType').valueChanges.subscribe((value) => {
290 this.updateValidatorsBasedOnStorageClass(value);
292 this.storageClassForm.get('allow_read_through').valueChanges.subscribe((value) => {
293 this.onAllowReadThroughChange(value);
297 public createAcls(): CdFormGroup {
298 const group = this.formBuilder.group({
299 type: new FormControl(AclTypeConst.ID, Validators.required),
300 source_id: new FormControl('', [
301 CdValidators.composeIf(
303 type: AclTypeConst.EMAIL
307 CdValidators.composeIf(
309 type: AclTypeConst.URI
314 dest_id: new FormControl('', [
315 CdValidators.composeIf(
317 type: AclTypeConst.EMAIL
321 CdValidators.composeIf(
323 type: AclTypeConst.URI
332 get acls(): FormArray {
333 return this.storageClassForm.get('acls') as FormArray;
336 private updateValidatorsBasedOnStorageClass(value: string) {
337 GLACIER_REQUIRED_FIELDS.forEach((field) => {
338 const control = this.storageClassForm.get(field);
341 (value === TIER_TYPE.CLOUD_TIER && CLOUD_TIER_REQUIRED_FIELDS.includes(field)) ||
342 (value === TIER_TYPE.GLACIER && GLACIER_REQUIRED_FIELDS.includes(field))
344 control.setValidators([Validators.required]);
346 control.clearValidators();
348 control.updateValueAndValidity();
352 const defaultValues: {
353 allow_read_through: boolean;
354 read_through_restore_days: number;
355 restore_storage_class: string;
356 multipart_min_part_size: number;
357 multipart_sync_threshold: number;
359 allow_read_through: false,
360 read_through_restore_days: STORAGE_CLASS_CONSTANTS.DEFAULT_READTHROUGH_RESTORE_DAYS,
361 restore_storage_class: STORAGE_CLASS_CONSTANTS.DEFAULT_STORAGE_CLASS,
362 multipart_min_part_size: STORAGE_CLASS_CONSTANTS.DEFAULT_MULTIPART_MIN_PART_SIZE,
363 multipart_sync_threshold: STORAGE_CLASS_CONSTANTS.DEFAULT_MULTIPART_SYNC_THRESHOLD
365 (Object.keys(defaultValues) as Array<keyof typeof defaultValues>).forEach((key) => {
366 this.storageClassForm.get(key)?.setValue(defaultValues[key]);
372 this.acls.push(this.createAcls());
375 removeAcl(index: number) {
376 if (this.acls.length > 1) {
377 this.acls.removeAt(index);
379 const removedAcl = this.acls.at(0).value;
381 if (removedAcl?.source_id) {
382 this.removedAclSourceIds.push(removedAcl.source_id);
384 const newGroup = this.createAcls();
385 this.acls.setControl(0, newGroup);
388 this.cdRef.detectChanges();
391 getAclLabel(field: AclFieldType, type?: string): string {
393 return field === AclFieldType.Source ? AclLabel.source : AclLabel.destination;
396 this.aclTypeLabel[type]?.[field] ||
397 (field === AclFieldType.Source ? AclLabel.source : AclLabel.destination)
401 getAclHelperText(type: string, field: AclFieldType): string {
402 return this.aclHelperText[type]?.[field] || '';
405 storageClassTypeText() {
406 this.storageClassForm?.get('storageClassType')?.valueChanges.subscribe((value) => {
407 if (value === TIER_TYPE.LOCAL) {
408 this.helpTextLabels.storageClassText = LOCAL_STORAGE_CLASS_TEXT;
409 } else if (value === TIER_TYPE.CLOUD_TIER) {
410 this.helpTextLabels.storageClassText = CLOUDS3_STORAGE_CLASS_TEXT;
411 } else if (value === TIER_TYPE.GLACIER) {
412 this.helpTextLabels.storageClassText = GLACIER_STORAGE_CLASS_TEXT;
417 updateTierTypeHelpText() {
418 this.storageClassForm?.get('glacier_restore_tier_type')?.valueChanges.subscribe((value) => {
419 if (value === STORAGE_CLASS_CONSTANTS.DEFAULT_STORAGE_CLASS) {
420 this.helpTextLabels.tiertypeText = STANDARD_TIER_TYPE_TEXT;
422 this.helpTextLabels.tiertypeText = EXPEDITED_TIER_TYPE_TEXT;
430 const lockDaysValidator = CdValidators.custom('lockDays', () => {
431 if (!self.storageClassForm || !self.storageClassForm.getRawValue()) {
435 const lockDays = Number(self.storageClassForm.getValue('read_through_restore_days'));
436 return !Number.isInteger(lockDays) || lockDays === 0;
438 this.storageClassForm = this.formBuilder.group({
439 storage_class: new FormControl('', {
440 validators: [Validators.required]
442 zonegroup: new FormControl(this.selectedZoneGroup, {
443 validators: [Validators.required]
445 region: new FormControl('', [
446 CdValidators.composeIf({ storageClassType: TIER_TYPE.CLOUD_TIER }, [Validators.required])
448 placement_target: new FormControl('', {
449 validators: [Validators.required]
451 target_endpoint: new FormControl('', [Validators.required, this.urlValidator]),
452 access_key: new FormControl(null, [
453 CdValidators.composeIf({ storageClassType: TIER_TYPE.CLOUD_TIER }, [Validators.required])
455 secret_key: new FormControl(null, [
456 CdValidators.composeIf({ storageClassType: TIER_TYPE.CLOUD_TIER }, [Validators.required])
458 target_path: new FormControl('', [
459 CdValidators.composeIf({ storageClassType: TIER_TYPE.CLOUD_TIER }, [Validators.required])
461 retain_head_object: new FormControl(true),
462 glacier_restore_tier_type: new FormControl(STORAGE_CLASS_CONSTANTS.DEFAULT_STORAGE_CLASS, [
463 CdValidators.composeIf({ storageClassType: TIER_TYPE.GLACIER }, [Validators.required])
465 glacier_restore_days: new FormControl(STORAGE_CLASS_CONSTANTS.DEFAULT_GLACIER_RESTORE_DAYS, [
466 CdValidators.composeIf({ storageClassType: TIER_TYPE.GLACIER || TIER_TYPE.CLOUD_TIER }, [
467 CdValidators.number(false),
471 restore_storage_class: new FormControl(STORAGE_CLASS_CONSTANTS.DEFAULT_STORAGE_CLASS),
472 read_through_restore_days: new FormControl(
474 value: STORAGE_CLASS_CONSTANTS.DEFAULT_READTHROUGH_RESTORE_DAYS,
477 CdValidators.composeIf(
478 (form: AbstractControl) => {
479 const type = form.get('storageClassType')?.value;
480 return type === TIER_TYPE.GLACIER || type === TIER_TYPE.CLOUD_TIER;
482 [CdValidators.number(false), lockDaysValidator]
485 multipart_sync_threshold: new FormControl(
486 STORAGE_CLASS_CONSTANTS.DEFAULT_MULTIPART_SYNC_THRESHOLD
488 multipart_min_part_size: new FormControl(
489 STORAGE_CLASS_CONSTANTS.DEFAULT_MULTIPART_MIN_PART_SIZE
491 allow_read_through: new FormControl(false),
492 storageClassType: new FormControl(TIER_TYPE.LOCAL, Validators.required),
493 pool: new FormControl('', [
494 CdValidators.composeIf({ storageClassType: TIER_TYPE.LOCAL }, [Validators.required])
496 zone: new FormControl(null, [
497 CdValidators.composeIf({ storageClassType: TIER_TYPE.LOCAL }, [Validators.required])
499 acls: new FormArray([])
501 this.storageClassForm.get('storageClassType')?.valueChanges.subscribe((type: string) => {
502 if (type === TIER_TYPE.CLOUD_TIER) {
503 const aclsArray = this.storageClassForm.get('acls') as FormArray;
505 aclsArray.push(this.createAcls());
510 loadZoneGroup(): Promise<void> {
511 return new Promise((resolve, reject) => {
512 this.rgwZoneGroupService.getAllZonegroupsInfo().subscribe(
513 (data: ZoneGroupDetails) => {
514 this.zoneGroupDetails = data;
515 this.zonegroupNames = [];
517 if (data.zonegroups && data.zonegroups.length > 0) {
518 this.zonegroupNames = data.zonegroups.map((zoneGroup: ZoneGroup) => ({
520 name: zoneGroup.name,
521 zones: zoneGroup.zones
524 this.defaultZonegroup = this.zonegroupNames.find(
525 (zonegroup) => zonegroup.id === data?.default_zonegroup
527 this.storageClassForm.get('zonegroup').setValue(this.defaultZonegroup?.name);
528 this.onZonegroupChange();
539 onZonegroupChange(): void {
540 const zoneGroupControl = this.storageClassForm.get('zonegroup').value;
541 const selectedZoneGroup = this.zoneGroupDetails?.zonegroups?.find(
542 (zonegroup) => zonegroup?.name === zoneGroupControl
544 const defaultPlacementTarget = selectedZoneGroup?.placement_targets?.find(
545 (target: Target) => target.name === DEFAULT_PLACEMENT
548 if (selectedZoneGroup?.placement_targets) {
549 this.placementTargets = selectedZoneGroup.placement_targets.map(
550 (target: Target) => target.name
553 if (defaultPlacementTarget && !this.editing) {
554 this.storageClassForm.get('placement_target').setValue(defaultPlacementTarget.name);
556 this.storageClassForm
557 .get('placement_target')
558 .setValue(this.storageClassInfo?.placement_target || null);
560 this.zones = selectedZoneGroup?.zones;
564 const component = this;
565 const requestModel = this.buildRequest();
566 const rawFormValue = _.cloneDeep(this.storageClassForm.getRawValue());
567 const zoneRequest: ZoneRequest = {
568 zone_name: this.storageClassForm.get('zone').value,
569 placement_target: this.storageClassForm.get('placement_target').value,
570 storage_class: this.storageClassForm.get('storage_class').value,
571 data_pool: this.storageClassForm.get('pool')?.value || ''
574 const storageclassName = this.storageClassForm.get('storage_class').value;
576 const editStorageClass$ = this.rgwStorageService.editStorageClass(requestModel);
579 rawFormValue.storageClassType === TIER_TYPE.LOCAL
580 ? editStorageClass$.pipe(
581 switchMap(() => this.rgwStorageService.editStorageClassZone(zoneRequest))
587 this.notificationService.show(
588 NotificationType.success,
589 $localize`Edited Storage Class '${storageclassName}'`
594 component.storageClassForm.setErrors({ cdSubmitButton: true });
598 const createStorageClass$ = this.rgwStorageService.createStorageClass(requestModel);
601 rawFormValue.storageClassType === TIER_TYPE.LOCAL
602 ? createStorageClass$.pipe(
603 switchMap(() => this.rgwStorageService.createStorageClassZone(zoneRequest))
605 : createStorageClass$;
607 createZone$.subscribe(
609 this.notificationService.show(
610 NotificationType.success,
611 $localize`Created Storage Class '${storageclassName}'`
616 component.storageClassForm.setErrors({ cdSubmitButton: true });
622 this.router.navigate([`rgw/tiering`]);
625 getTierTargetByStorageClass(placementTargetInfo: PlacementTarget, storageClass: string) {
626 const tierTarget = placementTargetInfo?.tier_targets?.find(
627 (target: TierTarget) => target.val.storage_class === storageClass
632 onAllowReadThroughChange(checked: boolean): void {
633 this.allowReadThrough = checked;
634 const readThroughDaysControl = this.storageClassForm.get('read_through_restore_days');
635 if (this.allowReadThrough) {
636 this.storageClassForm.get('retain_head_object')?.setValue(true);
637 this.storageClassForm.get('retain_head_object')?.disable();
638 readThroughDaysControl?.enable();
640 this.storageClassForm.get('retain_head_object')?.enable();
641 readThroughDaysControl?.disable();
645 isTierMatch(...types: string[]): boolean {
646 const tierType = this.storageClassForm.getValue('storageClassType');
647 return types.includes(tierType);
651 if (this.storageClassForm.errors) return null;
652 const rawFormValue = _.cloneDeep(this.storageClassForm.value);
653 const zoneGroup = this.storageClassForm.get('zonegroup').value;
654 const storageClass = this.storageClassForm.get('storage_class').value;
655 const placementId = this.storageClassForm.get('placement_target').value;
656 const storageClassType = this.storageClassForm.get('storageClassType').value;
657 const retain_head_object = this.storageClassForm.get('retain_head_object').value;
658 const multipart_min_part_size = this.formatter.toBytes(
659 this.storageClassForm.get('multipart_min_part_size').value
661 const multipart_sync_threshold = this.formatter.toBytes(
662 this.storageClassForm.get('multipart_sync_threshold').value
665 const removeAclList: ACLVal[] = rawFormValue.acls || [];
666 const tier_config_rm: TierConfigRm = {};
667 this.removedAclSourceIds.forEach((sourceId: string, index: number) => {
668 tier_config_rm[`acls[${index}].source_id`] = sourceId;
670 if (this.aclList?.length > rawFormValue.acls?.length) {
671 this.aclList?.forEach((acl: ACL, index: number) => {
672 const sourceId = acl?.val?.source_id;
673 const ifExist = removeAclList.find((acl: ACLVal) => acl?.source_id === sourceId);
676 tier_config_rm[`acls[${index}].source_id`] = sourceId;
681 return this.buildPlacementTargets(
688 multipart_sync_threshold,
689 multipart_min_part_size,
694 private buildPlacementTargets(
695 storageClassType: string,
698 storageClass: string,
699 retain_head_object: boolean,
701 multipart_sync_threshold: number,
702 multipart_min_part_size: number,
703 tier_config_rm: TierConfigRm
706 placement_id: placementId,
707 storage_class: storageClass,
708 tier_config_rm: tier_config_rm
711 if (storageClassType === TIER_TYPE.LOCAL) {
713 zone_group: zoneGroup,
714 placement_targets: [baseTarget]
718 const aclConfig: { [key: string]: string } = {};
720 rawFormValue.acls.forEach((acl: ACLVal, index: number) => {
721 const sourceId = acl?.source_id?.trim();
722 if (!sourceId) return;
724 const destId = acl?.dest_id?.trim() || '';
725 const type = acl?.type?.trim() || AclTypeConst.ID;
727 aclConfig[`acls[${index}].source_id`] = sourceId;
728 aclConfig[`acls[${index}].dest_id`] = destId;
729 aclConfig[`acls[${index}].type`] = type as AclType;
732 endpoint: rawFormValue.target_endpoint,
733 access_key: rawFormValue.access_key,
734 secret: rawFormValue.secret_key,
735 target_path: rawFormValue.target_path,
737 allow_read_through: rawFormValue.allow_read_through,
738 region: rawFormValue.region,
739 multipart_sync_threshold,
740 multipart_min_part_size,
741 restore_storage_class: rawFormValue.restore_storage_class,
742 ...(rawFormValue.allow_read_through
743 ? { read_through_restore_days: rawFormValue.read_through_restore_days }
748 if (storageClassType === TIER_TYPE.CLOUD_TIER) {
750 zone_group: zoneGroup,
754 tier_type: TIER_TYPE.CLOUD_TIER,
755 tier_config_rm: tier_config_rm,
764 if (storageClassType === TIER_TYPE.GLACIER) {
766 zone_group: zoneGroup,
770 tier_type: TIER_TYPE.GLACIER,
771 tier_config_rm: tier_config_rm,
774 glacier_restore_days: rawFormValue.glacier_restore_days,
775 glacier_restore_tier_type: rawFormValue.glacier_restore_tier_type,
776 target_storage_class: GLACIER_TARGET_STORAGE_CLASS
783 this.removedAclSourceIds = [];
785 zone_group: zoneGroup,
786 placement_targets: [baseTarget]