]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/blob
ba3d476a432bdd2b614c18fef641e09c4b2c1911
[ceph-ci.git] /
1 import { HttpParams } from '@angular/common/http';
2 import { Component, Input, OnInit, ViewChild } from '@angular/core';
3 import { AbstractControl, UntypedFormControl, Validators } from '@angular/forms';
4 import { ActivatedRoute, Router } from '@angular/router';
5
6 import { NgbActiveModal, NgbTypeahead } from '@ng-bootstrap/ng-bootstrap';
7 import { ListItem } from 'carbon-components-angular';
8 import _ from 'lodash';
9 import { forkJoin, merge, Observable, Subject, Subscription } from 'rxjs';
10 import { debounceTime, distinctUntilChanged, filter, map } from 'rxjs/operators';
11 import { Pool } from '~/app/ceph/pool/pool';
12 import { CreateRgwServiceEntitiesComponent } from '~/app/ceph/rgw/create-rgw-service-entities/create-rgw-service-entities.component';
13 import { RgwRealm, RgwZonegroup, RgwZone, RgwEntities } from '~/app/ceph/rgw/models/rgw-multisite';
14
15 import { CephServiceService } from '~/app/shared/api/ceph-service.service';
16 import { HostService } from '~/app/shared/api/host.service';
17 import { PoolService } from '~/app/shared/api/pool.service';
18 import { RbdService } from '~/app/shared/api/rbd.service';
19 import { RgwMultisiteService } from '~/app/shared/api/rgw-multisite.service';
20 import { RgwRealmService } from '~/app/shared/api/rgw-realm.service';
21 import { RgwZoneService } from '~/app/shared/api/rgw-zone.service';
22 import { RgwZonegroupService } from '~/app/shared/api/rgw-zonegroup.service';
23 import { SelectMessages } from '~/app/shared/components/select/select-messages.model';
24 import { SelectOption } from '~/app/shared/components/select/select-option.model';
25 import {
26   ActionLabelsI18n,
27   TimerServiceInterval,
28   URLVerbs,
29   SSL_PROTOCOLS,
30   SSL_CIPHERS
31 } from '~/app/shared/constants/app.constants';
32 import { CdForm } from '~/app/shared/forms/cd-form';
33 import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
34 import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
35 import { CdValidators } from '~/app/shared/forms/cd-validators';
36 import { FinishedTask } from '~/app/shared/models/finished-task';
37 import { Host } from '~/app/shared/models/host.interface';
38 import { CephServiceSpec, QatOptions, QatSepcs } from '~/app/shared/models/service.interface';
39 import { ModalCdsService } from '~/app/shared/services/modal-cds.service';
40 import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
41 import { TimerService } from '~/app/shared/services/timer.service';
42
43 @Component({
44   selector: 'cd-service-form',
45   templateUrl: './service-form.component.html',
46   styleUrls: ['./service-form.component.scss'],
47   standalone: false
48 })
49 export class ServiceFormComponent extends CdForm implements OnInit {
50   public sub = new Subscription();
51
52   readonly MDS_SVC_ID_PATTERN = /^[a-zA-Z_.-][a-zA-Z0-9_.-]*$/;
53   readonly SNMP_DESTINATION_PATTERN = /^[^\:]+:[0-9]/;
54   readonly SNMP_ENGINE_ID_PATTERN = /^[0-9A-Fa-f]{10,64}/g;
55   readonly INGRESS_SUPPORTED_SERVICE_TYPES = ['rgw', 'nfs'];
56   readonly SMB_CONFIG_URI_PATTERN = /^(http:|https:|rados:|rados:mon-config-key:)/;
57   readonly OAUTH2_ISSUER_URL_PATTERN = /^(https?:\/\/)?([a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+)(:[0-9]{1,5})?(\/.*)?$/;
58   readonly SSL_CIPHERS_PATTERN = /^[a-zA-Z0-9\-:]+$/;
59   readonly DEFAULT_SSL_PROTOCOL_ITEM = [{ content: 'TLSv1.3', selected: true }];
60   @ViewChild(NgbTypeahead, { static: false })
61   typeahead: NgbTypeahead;
62
63   @Input() hiddenServices: string[] = [];
64
65   @Input() editing = false;
66
67   @Input() serviceName: string;
68
69   @Input() serviceType: string;
70
71   serviceForm: CdFormGroup;
72   action: string;
73   resource: string;
74   serviceTypes: string[] = [];
75   serviceIds: string[] = [];
76   hosts: any;
77   labels: string[];
78   labelClick = new Subject<string>();
79   labelFocus = new Subject<string>();
80   pools: Array<Pool>;
81   rbdPools: Array<Pool>;
82   services: Array<CephServiceSpec> = [];
83   pageURL: string;
84   serviceList: CephServiceSpec[];
85   multisiteInfo: object[] = [];
86   defaultRealmId = '';
87   defaultZonegroupId = '';
88   defaultZoneId = '';
89   realmList: RgwRealm[] = [];
90   zonegroupList: RgwZonegroup[] = [];
91   zoneList: RgwZone[] = [];
92   defaultZonegroup: RgwZonegroup;
93   showRealmCreationForm = false;
94   defaultsInfo: { defaultRealmName: string; defaultZonegroupName: string; defaultZoneName: string };
95   realmNames: string[];
96   zonegroupNames: string[];
97   zoneNames: string[];
98   smbFeaturesList = ['domain'];
99   currentURL: string;
100   port: number = 443;
101   sslProtocolsItems: Array<ListItem> = Object.values(SSL_PROTOCOLS).map((protocol) => ({
102     content: protocol,
103     selected: true
104   }));
105   sslCiphersItems: Array<ListItem> = Object.values(SSL_CIPHERS).map((cipher) => ({
106     content: cipher,
107     selected: false
108   }));
109   showMgmtGatewayMessage: boolean = false;
110   qatCompressionOptions = [
111     { value: QatOptions.hw, label: 'Hardware' },
112     { value: QatOptions.sw, label: 'Software' },
113     { value: QatOptions.none, label: 'None' }
114   ];
115
116   constructor(
117     public actionLabels: ActionLabelsI18n,
118     private cephServiceService: CephServiceService,
119     private formBuilder: CdFormBuilder,
120     private hostService: HostService,
121     private poolService: PoolService,
122     private rbdService: RbdService,
123     private router: Router,
124     private taskWrapperService: TaskWrapperService,
125     public timerService: TimerService,
126     public timerServiceVariable: TimerServiceInterval,
127     public rgwRealmService: RgwRealmService,
128     public rgwZonegroupService: RgwZonegroupService,
129     public rgwZoneService: RgwZoneService,
130     public rgwMultisiteService: RgwMultisiteService,
131     private route: ActivatedRoute,
132     public activeModal: NgbActiveModal,
133     public modalService: ModalCdsService
134   ) {
135     super();
136     this.resource = $localize`service`;
137     this.hosts = {
138       options: [],
139       messages: new SelectMessages({
140         empty: $localize`There are no hosts.`,
141         filter: $localize`Filter hosts`
142       })
143     };
144     this.createForm();
145   }
146
147   createForm() {
148     this.serviceForm = this.formBuilder.group({
149       // Global
150       service_type: [null, [Validators.required]],
151       service_id: [
152         null,
153         [
154           CdValidators.composeIf(
155             {
156               service_type: 'mds'
157             },
158             [
159               Validators.required,
160               CdValidators.custom('mdsPattern', (value: string) => {
161                 if (_.isEmpty(value)) {
162                   return false;
163                 }
164                 return !this.MDS_SVC_ID_PATTERN.test(value);
165               })
166             ]
167           ),
168           CdValidators.requiredIf({
169             service_type: 'nfs'
170           }),
171           CdValidators.requiredIf({
172             service_type: 'iscsi'
173           }),
174           CdValidators.requiredIf({
175             service_type: 'nvmeof'
176           }),
177           CdValidators.requiredIf({
178             service_type: 'ingress'
179           }),
180           CdValidators.requiredIf({
181             service_type: 'smb'
182           }),
183           CdValidators.composeIf(
184             {
185               service_type: 'rgw'
186             },
187             [Validators.required]
188           ),
189           CdValidators.custom('uniqueName', (service_id: string) => {
190             return this.serviceIds && this.serviceIds.includes(service_id);
191           })
192         ]
193       ],
194       placement: ['hosts'],
195       label: [
196         null,
197         [
198           CdValidators.requiredIf({
199             placement: 'label',
200             unmanaged: false
201           })
202         ]
203       ],
204       hosts: [[]],
205       count: [null, [CdValidators.number(false)]],
206       unmanaged: [false],
207       // iSCSI
208       // NVMe/TCP
209       pool: [
210         null,
211         [
212           CdValidators.requiredIf({
213             service_type: 'iscsi'
214           }),
215           CdValidators.requiredIf({
216             service_type: 'nvmeof'
217           })
218         ]
219       ],
220       group: [
221         'default',
222         CdValidators.requiredIf({
223           service_type: 'nvmeof'
224         })
225       ],
226       enable_mtls: [false],
227       root_ca_cert: [
228         null,
229         [
230           CdValidators.composeIf(
231             {
232               service_type: 'nvmeof',
233               enable_mtls: true
234             },
235             [Validators.required]
236           )
237         ]
238       ],
239       client_cert: [
240         null,
241         [
242           CdValidators.composeIf(
243             {
244               service_type: 'nvmeof',
245               enable_mtls: true
246             },
247             [Validators.required]
248           )
249         ]
250       ],
251       client_key: [
252         null,
253         [
254           CdValidators.composeIf(
255             {
256               service_type: 'nvmeof',
257               enable_mtls: true
258             },
259             [Validators.required]
260           )
261         ]
262       ],
263       server_cert: [
264         null,
265         [
266           CdValidators.composeIf(
267             {
268               service_type: 'nvmeof',
269               enable_mtls: true
270             },
271             [Validators.required]
272           )
273         ]
274       ],
275       server_key: [
276         null,
277         [
278           CdValidators.composeIf(
279             {
280               service_type: 'nvmeof',
281               enable_mtls: true
282             },
283             [Validators.required]
284           )
285         ]
286       ],
287       // RGW
288       rgw_frontend_port: [null, [CdValidators.number(false)]],
289       realm_name: [null],
290       zonegroup_name: [null],
291       zone_name: [null],
292       qat: new CdFormGroup({
293         compression: new UntypedFormControl(QatOptions.none)
294       }),
295       // iSCSI
296       trusted_ip_list: [null],
297       api_port: [null, [CdValidators.number(false)]],
298       api_user: [
299         null,
300         [
301           CdValidators.requiredIf({
302             service_type: 'iscsi',
303             unmanaged: false
304           })
305         ]
306       ],
307       api_password: [
308         null,
309         [
310           CdValidators.requiredIf({
311             service_type: 'iscsi',
312             unmanaged: false
313           })
314         ]
315       ],
316       // smb
317       cluster_id: [
318         null,
319         [
320           CdValidators.requiredIf({
321             service_type: 'smb'
322           })
323         ]
324       ],
325       features: new CdFormGroup(
326         this.smbFeaturesList.reduce((acc: object, e) => {
327           acc[e] = new UntypedFormControl(false);
328           return acc;
329         }, {})
330       ),
331       config_uri: [
332         null,
333         [
334           CdValidators.composeIf(
335             {
336               service_type: 'smb'
337             },
338             [
339               Validators.required,
340               CdValidators.custom('configUriPattern', (value: string) => {
341                 if (_.isEmpty(value)) {
342                   return false;
343                 }
344                 return !this.SMB_CONFIG_URI_PATTERN.test(value);
345               })
346             ]
347           )
348         ]
349       ],
350       custom_dns: [null],
351       join_sources: [null],
352       user_sources: [null],
353       include_ceph_users: [null],
354       // Ingress
355       backend_service: [
356         null,
357         [
358           CdValidators.requiredIf({
359             service_type: 'ingress'
360           })
361         ]
362       ],
363       virtual_ip: [
364         null,
365         [
366           CdValidators.requiredIf({
367             service_type: 'ingress'
368           })
369         ]
370       ],
371       frontend_port: [
372         null,
373         [
374           CdValidators.number(false),
375           CdValidators.requiredIf({
376             service_type: 'ingress'
377           })
378         ]
379       ],
380       monitor_port: [
381         null,
382         [
383           CdValidators.number(false),
384           CdValidators.requiredIf({
385             service_type: 'ingress'
386           })
387         ]
388       ],
389       virtual_interface_networks: [null],
390       ssl_protocols: [this.DEFAULT_SSL_PROTOCOL_ITEM],
391       ssl_ciphers: [
392         null,
393         [
394           CdValidators.custom('invalidPattern', (ciphers: string) => {
395             if (_.isEmpty(ciphers)) {
396               return false;
397             }
398             return !this.SSL_CIPHERS_PATTERN.test(ciphers);
399           })
400         ]
401       ],
402       // RGW, Ingress & iSCSI
403       ssl: [false],
404       ssl_cert: [
405         '',
406         [
407           CdValidators.composeIf(
408             {
409               service_type: 'rgw',
410               unmanaged: false,
411               ssl: true
412             },
413             [Validators.required, CdValidators.pemCert()]
414           ),
415           CdValidators.composeIf(
416             {
417               service_type: 'iscsi',
418               unmanaged: false,
419               ssl: true
420             },
421             [Validators.required, CdValidators.sslCert()]
422           ),
423           CdValidators.composeIf(
424             {
425               service_type: 'ingress',
426               unmanaged: false,
427               ssl: true
428             },
429             [Validators.required, CdValidators.pemCert()]
430           ),
431           CdValidators.composeIf(
432             {
433               service_type: 'oauth2-proxy',
434               unmanaged: false,
435               ssl: true
436             },
437             [Validators.required, CdValidators.sslCert()]
438           ),
439           CdValidators.composeIf(
440             {
441               service_type: 'mgmt-gateway',
442               unmanaged: false,
443               ssl: false
444             },
445             [CdValidators.sslCert()]
446           )
447         ]
448       ],
449       ssl_key: [
450         '',
451         [
452           CdValidators.composeIf(
453             {
454               service_type: 'iscsi',
455               unmanaged: false,
456               ssl: true
457             },
458             [Validators.required, CdValidators.sslPrivKey()]
459           ),
460           CdValidators.composeIf(
461             {
462               service_type: 'oauth2-proxy',
463               unmanaged: false,
464               ssl: true
465             },
466             [Validators.required, CdValidators.sslPrivKey()]
467           ),
468           CdValidators.composeIf(
469             {
470               service_type: 'mgmt-gateway',
471               unmanaged: false,
472               ssl: false
473             },
474             [CdValidators.sslPrivKey()]
475           )
476         ]
477       ],
478       // mgmt-gateway
479       enable_auth: [null],
480       port: [443, [CdValidators.number(false)]],
481       // snmp-gateway
482       snmp_version: [
483         null,
484         [
485           CdValidators.requiredIf({
486             service_type: 'snmp-gateway'
487           })
488         ]
489       ],
490       snmp_destination: [
491         null,
492         {
493           validators: [
494             CdValidators.requiredIf({
495               service_type: 'snmp-gateway'
496             }),
497             CdValidators.custom('snmpDestinationPattern', (value: string) => {
498               if (_.isEmpty(value)) {
499                 return false;
500               }
501               return !this.SNMP_DESTINATION_PATTERN.test(value);
502             })
503           ]
504         }
505       ],
506       engine_id: [
507         null,
508         [
509           CdValidators.requiredIf({
510             service_type: 'snmp-gateway'
511           }),
512           CdValidators.custom('snmpEngineIdPattern', (value: string) => {
513             if (_.isEmpty(value)) {
514               return false;
515             }
516             return !this.SNMP_ENGINE_ID_PATTERN.test(value);
517           })
518         ]
519       ],
520       auth_protocol: [
521         'SHA',
522         [
523           CdValidators.requiredIf({
524             service_type: 'snmp-gateway'
525           })
526         ]
527       ],
528       privacy_protocol: [null],
529       snmp_community: [
530         null,
531         [
532           CdValidators.requiredIf({
533             snmp_version: 'V2c'
534           })
535         ]
536       ],
537       snmp_v3_auth_username: [
538         null,
539         [
540           CdValidators.requiredIf({
541             service_type: 'snmp-gateway'
542           })
543         ]
544       ],
545       snmp_v3_auth_password: [
546         null,
547         [
548           CdValidators.requiredIf({
549             service_type: 'snmp-gateway'
550           })
551         ]
552       ],
553       snmp_v3_priv_password: [
554         null,
555         [
556           CdValidators.requiredIf({
557             privacy_protocol: { op: '!empty' }
558           })
559         ]
560       ],
561       grafana_port: [null, [CdValidators.number(false)]],
562       grafana_admin_password: [null],
563       // oauth2-proxy
564       provider_display_name: [
565         'My OIDC provider',
566         [
567           CdValidators.requiredIf({
568             service_type: 'oauth2-proxy'
569           })
570         ]
571       ],
572       client_id: [
573         null,
574         [
575           CdValidators.requiredIf({
576             service_type: 'oauth2-proxy'
577           })
578         ]
579       ],
580       client_secret: [
581         null,
582         [
583           CdValidators.requiredIf({
584             service_type: 'oauth2-proxy'
585           })
586         ]
587       ],
588       oidc_issuer_url: [
589         null,
590         [
591           CdValidators.requiredIf({
592             service_type: 'oauth2-proxy'
593           }),
594           CdValidators.custom('validUrl', (url: string) => {
595             if (_.isEmpty(url)) {
596               return false;
597             }
598             return !this.OAUTH2_ISSUER_URL_PATTERN.test(url);
599           })
600         ]
601       ],
602       https_address: [null, [CdValidators.oauthAddressTest()]],
603       redirect_url: [null],
604       allowlist_domains: [null]
605     });
606   }
607
608   resolveRoute() {
609     if (this.router.url.includes('services/(modal:create')) {
610       this.pageURL = 'services';
611       this.route.params.subscribe((params: { type: string }) => {
612         if (params?.type) {
613           this.serviceType = params.type;
614           this.serviceForm.get('service_type').setValue(this.serviceType);
615         }
616       });
617     } else if (this.router.url.includes('services/(modal:edit')) {
618       this.editing = true;
619       this.pageURL = 'services';
620       this.route.params.subscribe((params: { type: string; name: string }) => {
621         this.serviceName = params.name;
622         this.serviceType = params.type;
623       });
624     }
625   }
626
627   ngOnInit(): void {
628     this.action = this.actionLabels.CREATE;
629     this.resolveRoute();
630
631     this.cephServiceService
632       .list(new HttpParams({ fromObject: { limit: -1, offset: 0 } }))
633       .observable.subscribe((services: CephServiceSpec[]) => {
634         this.serviceList = services;
635         this.services = services.filter((service: any) =>
636           this.INGRESS_SUPPORTED_SERVICE_TYPES.includes(service.service_type)
637         );
638       });
639
640     this.cephServiceService.getKnownTypes().subscribe((resp: Array<string>) => {
641       // Remove service types:
642       // osd       - This is deployed a different way.
643       // container - This should only be used in the CLI.
644       // promtail  - This is deprecated and replaced by alloy.
645       this.hiddenServices.push('osd', 'container', 'promtail');
646
647       this.serviceTypes = _.difference(resp, this.hiddenServices).sort();
648     });
649     this.hostService.getAllHosts().subscribe((resp: Host[]) => {
650       const options: SelectOption[] = [];
651       _.forEach(resp, (host: Host) => {
652         if (_.get(host, 'sources.orchestrator', false)) {
653           const option = new SelectOption(false, _.get(host, 'hostname'), '');
654           options.push(option);
655         }
656       });
657       this.hosts.options = [...options];
658     });
659     this.hostService.getLabels().subscribe((resp: string[]) => {
660       this.labels = resp;
661     });
662     this.poolService.getList().subscribe((resp: Pool[]) => {
663       this.pools = resp;
664       this.rbdPools = this.pools.filter(this.rbdService.isRBDPool);
665       if (!this.editing && this.serviceType) {
666         this.onServiceTypeChange(this.serviceType);
667       }
668     });
669
670     if (this.editing) {
671       this.action = this.actionLabels.EDIT;
672       this.disableForEditing(this.serviceType);
673       this.cephServiceService
674         .list(new HttpParams({ fromObject: { limit: -1, offset: 0 } }), this.serviceName)
675         .observable.subscribe((response: CephServiceSpec[]) => {
676           const formKeys = ['service_type', 'service_id', 'unmanaged'];
677           formKeys.forEach((keys) => {
678             this.serviceForm.get(keys).setValue(response[0][keys]);
679           });
680           if (!response[0]['unmanaged']) {
681             const placementKey = Object.keys(response[0]['placement'])[0];
682             let placementValue: string;
683             ['hosts', 'label'].indexOf(placementKey) >= 0
684               ? (placementValue = placementKey)
685               : (placementValue = 'hosts');
686             this.serviceForm.get('placement').setValue(placementValue);
687             this.serviceForm.get('count').setValue(response[0]['placement']['count']);
688             if (response[0]?.placement[placementValue]) {
689               this.serviceForm.get(placementValue).setValue(response[0]?.placement[placementValue]);
690             }
691           }
692           switch (this.serviceType) {
693             case 'iscsi':
694               const specKeys = ['pool', 'api_password', 'api_user', 'trusted_ip_list', 'api_port'];
695               specKeys.forEach((key) => {
696                 this.serviceForm.get(key).setValue(response[0].spec[key]);
697               });
698               this.serviceForm.get('ssl').setValue(response[0].spec?.api_secure);
699               if (response[0].spec?.api_secure) {
700                 this.serviceForm.get('ssl_cert').setValue(response[0].spec?.ssl_cert);
701                 this.serviceForm.get('ssl_key').setValue(response[0].spec?.ssl_key);
702               }
703               break;
704             case 'nvmeof':
705               this.serviceForm.get('pool').setValue(response[0].spec.pool);
706               this.serviceForm.get('group').setValue(response[0].spec.group);
707               this.serviceForm.get('enable_mtls').setValue(response[0].spec?.enable_auth);
708               this.serviceForm.get('root_ca_cert').setValue(response[0].spec?.root_ca_cert);
709               this.serviceForm.get('client_cert').setValue(response[0].spec?.client_cert);
710               this.serviceForm.get('client_key').setValue(response[0].spec?.client_key);
711               this.serviceForm.get('server_cert').setValue(response[0].spec?.server_cert);
712               this.serviceForm.get('server_key').setValue(response[0].spec?.server_key);
713               break;
714             case 'rgw':
715               this.serviceForm
716                 .get('rgw_frontend_port')
717                 .setValue(response[0].spec?.rgw_frontend_port);
718               this.setRgwFields(
719                 response[0].spec?.rgw_realm,
720                 response[0].spec?.rgw_zonegroup,
721                 response[0].spec?.rgw_zone,
722                 response[0].spec?.qat
723               );
724               this.serviceForm.get('ssl').setValue(response[0].spec?.ssl);
725               if (response[0].spec?.ssl) {
726                 this.serviceForm
727                   .get('ssl_cert')
728                   .setValue(response[0].spec?.rgw_frontend_ssl_certificate);
729               }
730               break;
731             case 'ingress':
732               const ingressSpecKeys = [
733                 'backend_service',
734                 'virtual_ip',
735                 'frontend_port',
736                 'monitor_port',
737                 'virtual_interface_networks',
738                 'ssl'
739               ];
740               ingressSpecKeys.forEach((key) => {
741                 this.serviceForm.get(key).setValue(response[0].spec[key]);
742               });
743               if (response[0].spec?.ssl) {
744                 this.serviceForm.get('ssl_cert').setValue(response[0].spec?.ssl_cert);
745                 this.serviceForm.get('ssl_key').setValue(response[0].spec?.ssl_key);
746               }
747               break;
748             case 'mgmt-gateway':
749               let hrefSplitted = window.location.href.split(':');
750               this.currentURL = hrefSplitted[0] + hrefSplitted[1];
751               this.port = response[0].spec?.port;
752
753               if (response[0].spec?.ssl_protocols) {
754                 let selectedValues: Array<ListItem> = [];
755                 for (const value of response[0].spec.ssl_protocols) {
756                   selectedValues.push({ content: value, selected: true });
757                 }
758                 this.serviceForm.get('ssl_protocols').setValue(selectedValues);
759               }
760               if (response[0].spec?.ssl_ciphers) {
761                 this.serviceForm
762                   .get('ssl_ciphers')
763                   .setValue(response[0].spec?.ssl_ciphers.join(':'));
764               }
765               if (response[0].spec?.ssl_cert) {
766                 this.serviceForm.get('ssl_cert').setValue(response[0].spec.ssl_cert);
767               }
768               if (response[0].spec?.ssl_key) {
769                 this.serviceForm.get('ssl_key').setValue(response[0].spec.ssl_key);
770               }
771               if (response[0].spec?.enable_auth) {
772                 this.serviceForm.get('enable_auth').setValue(response[0].spec.enable_auth);
773               }
774               if (response[0].spec?.port) {
775                 this.serviceForm.get('port').setValue(response[0].spec.port);
776               }
777               break;
778             case 'smb':
779               const smbSpecKeys = [
780                 'cluster_id',
781                 'config_uri',
782                 'features',
783                 'join_sources',
784                 'user_sources',
785                 'custom_dns',
786                 'include_ceph_users'
787               ];
788               smbSpecKeys.forEach((key) => {
789                 if (key === 'features') {
790                   if (response[0].spec?.features) {
791                     response[0].spec.features.forEach((feature) => {
792                       this.serviceForm.get(`features.${feature}`).setValue(true);
793                     });
794                   }
795                 } else {
796                   this.serviceForm.get(key).setValue(response[0].spec[key]);
797                 }
798               });
799               break;
800             case 'snmp-gateway':
801               const snmpCommonSpecKeys = ['snmp_version', 'snmp_destination'];
802               snmpCommonSpecKeys.forEach((key) => {
803                 this.serviceForm.get(key).setValue(response[0].spec[key]);
804               });
805               if (this.serviceForm.getValue('snmp_version') === 'V3') {
806                 const snmpV3SpecKeys = [
807                   'engine_id',
808                   'auth_protocol',
809                   'privacy_protocol',
810                   'snmp_v3_auth_username',
811                   'snmp_v3_auth_password',
812                   'snmp_v3_priv_password'
813                 ];
814                 snmpV3SpecKeys.forEach((key) => {
815                   if (key !== null) {
816                     if (
817                       key === 'snmp_v3_auth_username' ||
818                       key === 'snmp_v3_auth_password' ||
819                       key === 'snmp_v3_priv_password'
820                     ) {
821                       this.serviceForm.get(key).setValue(response[0].spec['credentials'][key]);
822                     } else {
823                       this.serviceForm.get(key).setValue(response[0].spec[key]);
824                     }
825                   }
826                 });
827               } else {
828                 this.serviceForm
829                   .get('snmp_community')
830                   .setValue(response[0].spec['credentials']['snmp_community']);
831               }
832               break;
833             case 'grafana':
834               this.serviceForm.get('grafana_port').setValue(response[0].spec.port);
835               this.serviceForm
836                 .get('grafana_admin_password')
837                 .setValue(response[0].spec.initial_admin_password);
838               break;
839             case 'oauth2-proxy':
840               const oauth2SpecKeys = [
841                 'https_address',
842                 'provider_display_name',
843                 'client_id',
844                 'client_secret',
845                 'oidc_issuer_url',
846                 'redirect_url',
847                 'allowlist_domains'
848               ];
849               oauth2SpecKeys.forEach((key) => {
850                 this.serviceForm.get(key).setValue(response[0].spec[key]);
851               });
852               if (response[0].spec?.ssl) {
853                 this.serviceForm.get('ssl_cert').setValue(response[0].spec?.ssl_cert);
854                 this.serviceForm.get('ssl_key').setValue(response[0].spec?.ssl_key);
855               }
856           }
857         });
858     }
859     this.detectChanges();
860   }
861
862   detectChanges(): void {
863     const service_type = this.serviceForm.get('service_type');
864     if (service_type) {
865       service_type.valueChanges.subscribe((value) => {
866         if (value === 'mgmt-gateway') {
867           const port = this.serviceForm.get('port');
868           if (port) {
869             port.valueChanges.subscribe((_) => {
870               this.showMgmtGatewayMessage = true;
871             });
872           }
873           const ssl_protocols = this.serviceForm.get('ssl_protocols');
874           if (ssl_protocols) {
875             ssl_protocols.valueChanges.subscribe((_) => {
876               this.showMgmtGatewayMessage = true;
877             });
878           }
879           const ssl_ciphers = this.serviceForm.get('ssl_ciphers');
880           if (ssl_ciphers) {
881             ssl_ciphers.valueChanges.subscribe((_) => {
882               this.showMgmtGatewayMessage = true;
883             });
884           }
885         }
886       });
887     }
888   }
889
890   getDefaultsEntitiesForRgw(
891     defaultRealmId: string,
892     defaultZonegroupId: string,
893     defaultZoneId: string
894   ): { defaultRealmName: string; defaultZonegroupName: string; defaultZoneName: string } {
895     const defaultRealm = this.realmList.find((x: { id: string }) => x.id === defaultRealmId);
896     const defaultZonegroup = this.zonegroupList.find(
897       (x: { id: string }) => x.id === defaultZonegroupId
898     );
899     const defaultZone = this.zoneList.find((x: { id: string }) => x.id === defaultZoneId);
900     const defaultRealmName = defaultRealm !== undefined ? defaultRealm.name : null;
901     const defaultZonegroupName = defaultZonegroup !== undefined ? defaultZonegroup.name : 'default';
902     const defaultZoneName = defaultZone !== undefined ? defaultZone.name : 'default';
903     if (defaultZonegroupName === 'default' && !this.zonegroupNames.includes(defaultZonegroupName)) {
904       const defaultZonegroup = new RgwZonegroup();
905       defaultZonegroup.name = 'default';
906       this.zonegroupList.push(defaultZonegroup);
907     }
908     if (defaultZoneName === 'default' && !this.zoneNames.includes(defaultZoneName)) {
909       const defaultZone = new RgwZone();
910       defaultZone.name = 'default';
911       this.zoneList.push(defaultZone);
912     }
913     return {
914       defaultRealmName: defaultRealmName,
915       defaultZonegroupName: defaultZonegroupName,
916       defaultZoneName: defaultZoneName
917     };
918   }
919
920   getDefaultPlacementCount(serviceType: string) {
921     /**
922      * `defaults` from src/pybind/mgr/cephadm/module.py
923      */
924     switch (serviceType) {
925       case 'mon':
926         this.serviceForm.get('count').setValue(5);
927         break;
928       case 'mgr':
929       case 'mds':
930       case 'rgw':
931       case 'ingress':
932       case 'rbd-mirror':
933         this.serviceForm.get('count').setValue(2);
934         break;
935       case 'iscsi':
936       case 'cephfs-mirror':
937       case 'nfs':
938       case 'grafana':
939       case 'alertmanager':
940       case 'prometheus':
941       case 'loki':
942       case 'container':
943       case 'snmp-gateway':
944       case 'elastic-serach':
945       case 'jaeger-collector':
946       case 'jaeger-query':
947       case 'smb':
948       case 'oauth2-proxy':
949       case 'mgmt-gateway':
950         this.serviceForm.get('count').setValue(1);
951         break;
952       default:
953         this.serviceForm.get('count').setValue(null);
954     }
955   }
956
957   setRgwFields(realm_name?: string, zonegroup_name?: string, zone_name?: string, qat?: QatSepcs) {
958     const observables = [
959       this.rgwRealmService.getAllRealmsInfo(),
960       this.rgwZonegroupService.getAllZonegroupsInfo(),
961       this.rgwZoneService.getAllZonesInfo()
962     ];
963     this.sub = forkJoin(observables).subscribe(
964       (multisiteInfo: [object, object, object]) => {
965         this.multisiteInfo = multisiteInfo;
966         this.realmList =
967           this.multisiteInfo[0] !== undefined && this.multisiteInfo[0].hasOwnProperty('realms')
968             ? this.multisiteInfo[0]['realms']
969             : [];
970         this.zonegroupList =
971           this.multisiteInfo[1] !== undefined && this.multisiteInfo[1].hasOwnProperty('zonegroups')
972             ? this.multisiteInfo[1]['zonegroups']
973             : [];
974         this.zoneList =
975           this.multisiteInfo[2] !== undefined && this.multisiteInfo[2].hasOwnProperty('zones')
976             ? this.multisiteInfo[2]['zones']
977             : [];
978         this.realmNames = this.realmList.map((realm) => {
979           return realm['name'];
980         });
981         this.zonegroupNames = this.zonegroupList.map((zonegroup) => {
982           return zonegroup['name'];
983         });
984         this.zoneNames = this.zoneList.map((zone) => {
985           return zone['name'];
986         });
987         this.defaultRealmId = multisiteInfo[0]['default_realm'];
988         this.defaultZonegroupId = multisiteInfo[1]['default_zonegroup'];
989         this.defaultZoneId = multisiteInfo[2]['default_zone'];
990         this.defaultsInfo = this.getDefaultsEntitiesForRgw(
991           this.defaultRealmId,
992           this.defaultZonegroupId,
993           this.defaultZoneId
994         );
995         if (!this.editing) {
996           this.serviceForm.get('realm_name').setValue(this.defaultsInfo['defaultRealmName']);
997           this.serviceForm
998             .get('zonegroup_name')
999             .setValue(this.defaultsInfo['defaultZonegroupName']);
1000           this.serviceForm.get('zone_name').setValue(this.defaultsInfo['defaultZoneName']);
1001         } else {
1002           if (realm_name && !this.realmNames.includes(realm_name)) {
1003             const realm = new RgwRealm();
1004             realm.name = realm_name;
1005             this.realmList.push(realm);
1006           }
1007           if (zonegroup_name && !this.zonegroupNames.includes(zonegroup_name)) {
1008             const zonegroup = new RgwZonegroup();
1009             zonegroup.name = zonegroup_name;
1010             this.zonegroupList.push(zonegroup);
1011           }
1012           if (zone_name && !this.zoneNames.includes(zone_name)) {
1013             const zone = new RgwZone();
1014             zone.name = zone_name;
1015             this.zoneList.push(zone);
1016           }
1017           if (zonegroup_name === undefined && zone_name === undefined) {
1018             zonegroup_name = 'default';
1019             zone_name = 'default';
1020           }
1021           this.serviceForm.get('realm_name').setValue(realm_name);
1022           this.serviceForm.get('zonegroup_name').setValue(zonegroup_name);
1023           this.serviceForm.get('zone_name').setValue(zone_name);
1024         }
1025         if (qat) {
1026           this.serviceForm.get(`qat.compression`)?.setValue(qat['compression']);
1027         }
1028         if (this.realmList.length === 0) {
1029           this.showRealmCreationForm = true;
1030         } else {
1031           this.showRealmCreationForm = false;
1032         }
1033       },
1034       (_error) => {
1035         const defaultZone = new RgwZone();
1036         defaultZone.name = 'default';
1037         const defaultZonegroup = new RgwZonegroup();
1038         defaultZonegroup.name = 'default';
1039         this.zoneList.push(defaultZone);
1040         this.zonegroupList.push(defaultZonegroup);
1041       }
1042     );
1043   }
1044
1045   setNvmeServiceId() {
1046     const pool = this.serviceForm.get('pool').value;
1047     const group = this.serviceForm.get('group').value;
1048     if (pool && group) {
1049       this.serviceForm.get('service_id').setValue(`${pool}.${group}`);
1050     } else if (pool) {
1051       this.serviceForm.get('service_id').setValue(pool);
1052     } else if (group) {
1053       this.serviceForm.get('service_id').setValue(group);
1054     } else {
1055       this.serviceForm.get('service_id').setValue(null);
1056     }
1057   }
1058
1059   setNvmeDefaultPool() {
1060     const defaultPool =
1061       this.rbdPools?.find((p: Pool) => p.pool_name === 'rbd')?.pool_name ||
1062       this.rbdPools?.[0].pool_name;
1063     this.serviceForm.get('pool').setValue(defaultPool);
1064   }
1065
1066   requiresServiceId(serviceType: string) {
1067     return ['mds', 'rgw', 'nfs', 'iscsi', 'nvmeof', 'smb', 'ingress'].includes(serviceType);
1068   }
1069
1070   setServiceId(serviceId: string): void {
1071     const requiresServiceId: boolean = this.requiresServiceId(serviceId);
1072     if (requiresServiceId && serviceId === 'nvmeof') {
1073       this.setNvmeDefaultPool();
1074       this.setNvmeServiceId();
1075     } else if (requiresServiceId) {
1076       this.serviceForm.get('service_id').setValue(null);
1077     } else {
1078       this.serviceForm.get('service_id').setValue(serviceId);
1079     }
1080   }
1081
1082   onServiceTypeChange(selectedServiceType: string) {
1083     this.setServiceId(selectedServiceType);
1084
1085     this.serviceIds = this.serviceList
1086       ?.filter((service) => service['service_type'] === selectedServiceType)
1087       .map((service) => service['service_id']);
1088
1089     this.getDefaultPlacementCount(selectedServiceType);
1090
1091     if (selectedServiceType === 'rgw') {
1092       this.setRgwFields();
1093     }
1094     if (selectedServiceType === 'mgmt-gateway') {
1095       let hrefSplitted = window.location.href.split(':');
1096       this.currentURL = hrefSplitted[0] + hrefSplitted[1];
1097       // mgmt-gateway lacks HA for now
1098       this.serviceForm.get('count').disable();
1099     } else {
1100       this.serviceForm.get('count').enable();
1101     }
1102   }
1103
1104   onPlacementChange(selected: string) {
1105     if (selected === 'label') {
1106       this.serviceForm.get('count').setValue(null);
1107     }
1108   }
1109
1110   disableForEditing(serviceType: string) {
1111     const disableForEditKeys = ['service_type', 'service_id'];
1112     disableForEditKeys.forEach((key) => {
1113       this.serviceForm.get(key).disable();
1114     });
1115     switch (serviceType) {
1116       case 'ingress':
1117         this.serviceForm.get('backend_service').disable();
1118         break;
1119       case 'nvmeof':
1120         this.serviceForm.get('pool').disable();
1121         this.serviceForm.get('group').disable();
1122         break;
1123     }
1124   }
1125
1126   searchLabels = (text$: Observable<string>) => {
1127     return merge(
1128       text$.pipe(debounceTime(200), distinctUntilChanged()),
1129       this.labelFocus,
1130       this.labelClick.pipe(filter(() => !this.typeahead.isPopupOpen()))
1131     ).pipe(
1132       map((value) =>
1133         this.labels
1134           .filter((label: string) => label.toLowerCase().indexOf(value.toLowerCase()) > -1)
1135           .slice(0, 10)
1136       )
1137     );
1138   };
1139
1140   fileUpload(files: FileList, controlName: string) {
1141     const file: File = files[0];
1142     const reader = new FileReader();
1143     reader.addEventListener('load', (event: ProgressEvent<FileReader>) => {
1144       const control: AbstractControl = this.serviceForm.get(controlName);
1145       control.setValue(event.target.result);
1146       control.markAsDirty();
1147       control.markAsTouched();
1148       control.updateValueAndValidity();
1149     });
1150     reader.readAsText(file, 'utf8');
1151   }
1152
1153   prePopulateId() {
1154     const control: AbstractControl = this.serviceForm.get('service_id');
1155     const backendService = this.serviceForm.getValue('backend_service');
1156     // Set Id as read-only
1157     control.reset({ value: backendService, disabled: true });
1158   }
1159
1160   onSubmit() {
1161     const self = this;
1162     const values: object = this.serviceForm.getRawValue();
1163     const serviceType: string = values['service_type'];
1164     let taskUrl = `service/${URLVerbs.CREATE}`;
1165     if (this.editing) {
1166       taskUrl = `service/${URLVerbs.EDIT}`;
1167     }
1168     const serviceSpec: object = {
1169       service_type: serviceType,
1170       placement: {},
1171       unmanaged: values['unmanaged']
1172     };
1173     if (serviceType === 'rgw') {
1174       serviceSpec['rgw_realm'] = values['realm_name'] ? values['realm_name'] : null;
1175       serviceSpec['rgw_zonegroup'] =
1176         values['zonegroup_name'] !== 'default' ? values['zonegroup_name'] : null;
1177       serviceSpec['rgw_zone'] = values['zone_name'] !== 'default' ? values['zone_name'] : null;
1178       if (values['qat']['compression'] && values['qat']['compression'] != QatOptions.none) {
1179         serviceSpec['qat'] = values['qat'];
1180       } else if (values['qat']['compression'] == QatOptions.none) {
1181         delete serviceSpec['qat'];
1182       }
1183     }
1184
1185     const serviceId: string = values['service_id'];
1186     let serviceName: string = serviceType;
1187     if (_.isString(serviceId) && !_.isEmpty(serviceId)) {
1188       serviceName = `${serviceType}.${serviceId}`;
1189       serviceSpec['service_id'] = serviceId;
1190     }
1191
1192     // These services has some fields to be
1193     // filled out even if unmanaged is true
1194     switch (serviceType) {
1195       case 'ingress':
1196         serviceSpec['backend_service'] = values['backend_service'];
1197         serviceSpec['service_id'] = values['backend_service'];
1198         if (_.isNumber(values['frontend_port']) && values['frontend_port'] > 0) {
1199           serviceSpec['frontend_port'] = values['frontend_port'];
1200         }
1201         if (_.isString(values['virtual_ip']) && !_.isEmpty(values['virtual_ip'])) {
1202           serviceSpec['virtual_ip'] = values['virtual_ip'].trim();
1203         }
1204         if (_.isNumber(values['monitor_port']) && values['monitor_port'] > 0) {
1205           serviceSpec['monitor_port'] = values['monitor_port'];
1206         }
1207         break;
1208
1209       case 'nvmeof':
1210         serviceSpec['pool'] = values['pool'];
1211         serviceSpec['group'] = values['group'];
1212         serviceSpec['enable_auth'] = values['enable_mtls'];
1213         if (values['enable_mtls']) {
1214           serviceSpec['root_ca_cert'] = values['root_ca_cert'];
1215           serviceSpec['client_cert'] = values['client_cert'];
1216           serviceSpec['client_key'] = values['client_key'];
1217           serviceSpec['server_cert'] = values['server_cert'];
1218           serviceSpec['server_key'] = values['server_key'];
1219         }
1220         break;
1221       case 'iscsi':
1222         serviceSpec['pool'] = values['pool'];
1223         break;
1224
1225       case 'smb':
1226         serviceSpec['cluster_id'] = values['cluster_id']?.trim();
1227         serviceSpec['config_uri'] = values['config_uri']?.trim();
1228         for (const feature in values['features']) {
1229           if (values['features'][feature]) {
1230             (serviceSpec['features'] = serviceSpec['features'] || []).push(feature);
1231           }
1232         }
1233         serviceSpec['custom_dns'] = values['custom_dns'];
1234         serviceSpec['join_sources'] = values['join_sources']?.trim();
1235         serviceSpec['user_sources'] = values['user_sources']?.trim();
1236         serviceSpec['include_ceph_users'] = values['include_ceph_users']?.trim();
1237         break;
1238
1239       case 'snmp-gateway':
1240         serviceSpec['credentials'] = {};
1241         serviceSpec['snmp_version'] = values['snmp_version'];
1242         serviceSpec['snmp_destination'] = values['snmp_destination'];
1243         if (values['snmp_version'] === 'V3') {
1244           serviceSpec['engine_id'] = values['engine_id'];
1245           serviceSpec['auth_protocol'] = values['auth_protocol'];
1246           serviceSpec['credentials']['snmp_v3_auth_username'] = values['snmp_v3_auth_username'];
1247           serviceSpec['credentials']['snmp_v3_auth_password'] = values['snmp_v3_auth_password'];
1248           if (values['privacy_protocol'] !== null) {
1249             serviceSpec['privacy_protocol'] = values['privacy_protocol'];
1250             serviceSpec['credentials']['snmp_v3_priv_password'] = values['snmp_v3_priv_password'];
1251           }
1252         } else {
1253           serviceSpec['credentials']['snmp_community'] = values['snmp_community'];
1254         }
1255         break;
1256     }
1257
1258     if (!values['unmanaged']) {
1259       switch (values['placement']) {
1260         case 'hosts':
1261           if (values['hosts'].length > 0) {
1262             serviceSpec['placement']['hosts'] = values['hosts'];
1263           }
1264           break;
1265         case 'label':
1266           serviceSpec['placement']['label'] = values['label'];
1267           break;
1268       }
1269       if (_.isNumber(values['count']) && values['count'] > 0) {
1270         serviceSpec['placement']['count'] = values['count'];
1271       }
1272       switch (serviceType) {
1273         case 'rgw':
1274           if (_.isNumber(values['rgw_frontend_port']) && values['rgw_frontend_port'] > 0) {
1275             serviceSpec['rgw_frontend_port'] = values['rgw_frontend_port'];
1276           }
1277           serviceSpec['ssl'] = values['ssl'];
1278           if (values['ssl']) {
1279             serviceSpec['rgw_frontend_ssl_certificate'] = values['ssl_cert']?.trim();
1280           }
1281           break;
1282         case 'iscsi':
1283           if (_.isString(values['trusted_ip_list']) && !_.isEmpty(values['trusted_ip_list'])) {
1284             serviceSpec['trusted_ip_list'] = values['trusted_ip_list'].trim();
1285           }
1286           if (_.isNumber(values['api_port']) && values['api_port'] > 0) {
1287             serviceSpec['api_port'] = values['api_port'];
1288           }
1289           serviceSpec['api_user'] = values['api_user'];
1290           serviceSpec['api_password'] = values['api_password'];
1291           serviceSpec['api_secure'] = values['ssl'];
1292           if (values['ssl']) {
1293             serviceSpec['ssl_cert'] = values['ssl_cert']?.trim();
1294             serviceSpec['ssl_key'] = values['ssl_key']?.trim();
1295           }
1296           break;
1297         case 'ingress':
1298           serviceSpec['ssl'] = values['ssl'];
1299           if (values['ssl']) {
1300             serviceSpec['ssl_cert'] = values['ssl_cert']?.trim();
1301             serviceSpec['ssl_key'] = values['ssl_key']?.trim();
1302           }
1303           serviceSpec['virtual_interface_networks'] = values['virtual_interface_networks'];
1304           break;
1305         case 'mgmt-gateway':
1306           serviceSpec['ssl_cert'] = values['ssl_cert']?.trim();
1307           serviceSpec['ssl_key'] = values['ssl_key']?.trim();
1308           serviceSpec['enable_auth'] = values['enable_auth'];
1309           serviceSpec['port'] = values['port'];
1310           if ([443, 80].includes(values['port'])) {
1311             // omit port default values due to issues with redirect_url on the backend
1312             delete serviceSpec['port'];
1313           }
1314           serviceSpec['ssl_protocols'] = [];
1315           if (values['ssl_protocols'] != this.DEFAULT_SSL_PROTOCOL_ITEM) {
1316             for (const key of Object.keys(values['ssl_protocols'])) {
1317               serviceSpec['ssl_protocols'].push(values['ssl_protocols'][key]['content']);
1318             }
1319           }
1320           serviceSpec['ssl_ciphers'] = values['ssl_ciphers']?.trim().split(':');
1321           break;
1322         case 'grafana':
1323           serviceSpec['port'] = values['grafana_port'];
1324           serviceSpec['initial_admin_password'] = values['grafana_admin_password'];
1325           break;
1326         case 'oauth2-proxy':
1327           serviceSpec['provider_display_name'] = values['provider_display_name']?.trim();
1328           serviceSpec['client_id'] = values['client_id']?.trim();
1329           serviceSpec['client_secret'] = values['client_secret']?.trim();
1330           serviceSpec['oidc_issuer_url'] = values['oidc_issuer_url']?.trim();
1331           serviceSpec['https_address'] = values['https_address']?.trim();
1332           serviceSpec['redirect_url'] = values['redirect_url']?.trim();
1333           serviceSpec['allowlist_domains'] = values['allowlist_domains']
1334             ?.split(',')
1335             .map((domain: string) => {
1336               return domain.trim();
1337             });
1338           if (values['ssl']) {
1339             serviceSpec['ssl_cert'] = values['ssl_cert']?.trim();
1340             serviceSpec['ssl_key'] = values['ssl_key']?.trim();
1341           }
1342           break;
1343       }
1344     }
1345     this.taskWrapperService
1346       .wrapTaskAroundCall({
1347         task: new FinishedTask(taskUrl, {
1348           service_name: serviceName
1349         }),
1350         call: this.editing
1351           ? this.cephServiceService.update(serviceSpec)
1352           : this.cephServiceService.create(serviceSpec)
1353       })
1354       .subscribe({
1355         error() {
1356           self.serviceForm.setErrors({ cdSubmitButton: true });
1357         },
1358         complete: () => {
1359           this.pageURL === 'services'
1360             ? this.router.navigate([this.pageURL, { outlets: { modal: null } }])
1361             : this.activeModal.close();
1362         }
1363       });
1364   }
1365
1366   clearValidations() {
1367     const snmpVersion = this.serviceForm.getValue('snmp_version');
1368     const privacyProtocol = this.serviceForm.getValue('privacy_protocol');
1369     if (snmpVersion === 'V3') {
1370       this.serviceForm.get('snmp_community').clearValidators();
1371     } else {
1372       this.serviceForm.get('engine_id').clearValidators();
1373       this.serviceForm.get('auth_protocol').clearValidators();
1374       this.serviceForm.get('privacy_protocol').clearValidators();
1375       this.serviceForm.get('snmp_v3_auth_username').clearValidators();
1376       this.serviceForm.get('snmp_v3_auth_password').clearValidators();
1377     }
1378     if (privacyProtocol === null) {
1379       this.serviceForm.get('snmp_v3_priv_password').clearValidators();
1380     }
1381   }
1382
1383   createMultisiteSetup() {
1384     const modalRef = this.modalService.show(CreateRgwServiceEntitiesComponent);
1385     const modalComponent = modalRef as CreateRgwServiceEntitiesComponent;
1386     modalComponent.submitAction.subscribe((item: RgwEntities) => {
1387       this.setRgwFields(item.realm_name, item.zonegroup_name, item.zone_name);
1388     });
1389   }
1390 }