1 <cd-modal [pageURL]="pageURL"
2 [modalRef]="activeModal">
3 <span class="modal-title"
4 i18n>{{ action | titlecase }} {{ resource | upperFirst }}</span>
5 <ng-container class="modal-content">
7 [formGroup]="serviceForm"
9 <div class="modal-body">
10 <cd-alert-panel *ngIf="serviceForm.controls.service_type.value === 'rgw' && showRealmCreationForm"
14 <a class="text-decoration-underline"
15 (click)="createMultisiteSetup()">
16 Click here</a> to create a new Realm/Zone Group/Zone
19 <div class="form-group row">
20 <label class="cd-col-form-label required"
23 <div class="cd-col-form-input">
24 <select id="service_type"
27 formControlName="service_type"
28 (change)="getServiceIds($event.target.value)">
30 [ngValue]="null">-- Select a service type --</option>
31 <option *ngFor="let serviceType of serviceTypes"
32 [value]="serviceType">
36 <span class="invalid-feedback"
37 *ngIf="serviceForm.showError('service_type', frm, 'required')"
38 i18n>This field is required.</span>
42 <!-- backend_service -->
43 <div *ngIf="serviceForm.controls.service_type.value === 'ingress'"
44 class="form-group row">
46 class="cd-col-form-label"
47 [ngClass]="{'required': ['ingress'].includes(serviceForm.controls.service_type.value)}"
48 for="backend_service">Backend Service</label>
49 <div class="cd-col-form-input">
50 <select id="backend_service"
51 name="backend_service"
53 formControlName="backend_service"
54 (change)="prePopulateId()">
55 <option *ngIf="services === null"
57 i18n>Loading...</option>
58 <option *ngIf="services !== null && services.length === 0"
60 i18n>-- No service available --</option>
61 <option *ngIf="services !== null && services.length > 0"
63 i18n>-- Select an existing service --</option>
64 <option *ngFor="let service of services"
65 [value]="service.service_name">{{ service.service_name }}</option>
67 <span class="invalid-feedback"
68 *ngIf="serviceForm.showError('backend_service', frm, 'required')"
69 i18n>This field is required.</span>
74 <div class="form-group row"
75 *ngIf="serviceForm.controls.service_type.value !== 'snmp-gateway'">
76 <label class="cd-col-form-label"
77 [ngClass]="{'required': ['mds', 'rgw', 'nfs', 'iscsi', 'ingress'].includes(serviceForm.controls.service_type.value)}"
80 <cd-helper i18n>Used in the service name which is <service_type.service_id></cd-helper>
82 <div class="cd-col-form-input">
83 <input id="service_id"
86 formControlName="service_id">
87 <span class="invalid-feedback"
88 *ngIf="serviceForm.showError('service_id', frm, 'required')"
89 i18n>This field is required.</span>
90 <span class="invalid-feedback"
91 *ngIf="serviceForm.showError('service_id', frm, 'uniqueName')"
92 i18n>This service id is already in use.</span>
93 <span class="invalid-feedback"
94 *ngIf="serviceForm.showError('service_id', frm, 'mdsPattern')"
95 i18n>MDS service id must start with a letter and contain alphanumeric characters or '.', '-', and '_'</span>
99 <div class="form-group row"
100 *ngIf="serviceForm.controls.service_type.value === 'rgw'">
101 <label class="cd-col-form-label"
104 <div class="cd-col-form-input">
105 <select class="form-select"
107 formControlName="realm_name"
109 [attr.disabled]="realmList.length === 0 || editing ? true : null">
110 <option *ngIf="realmList.length === 0"
112 selected>-- No realm available --</option>
113 <option *ngFor="let realm of realmList"
114 [value]="realm.name">
121 <div class="form-group row"
122 *ngIf="serviceForm.controls.service_type.value === 'rgw'">
123 <label class="cd-col-form-label"
125 i18n>Zone Group</label>
126 <div class="cd-col-form-input">
127 <select class="form-select"
129 formControlName="zonegroup_name"
130 name="zonegroup_name"
131 [attr.disabled]="zonegroupList.length === 0 || editing ? true : null">
132 <option *ngFor="let zonegroup of zonegroupList"
133 [value]="zonegroup.name">
140 <div class="form-group row"
141 *ngIf="serviceForm.controls.service_type.value === 'rgw'">
142 <label class="cd-col-form-label"
145 <div class="cd-col-form-input">
146 <select class="form-select"
148 formControlName="zone_name"
150 [attr.disabled]="zoneList.length === 0 || editing ? true : null">
151 <option *ngFor="let zone of zoneList"
160 <div class="form-group row">
161 <div class="cd-col-form-offset">
162 <div class="custom-control custom-checkbox">
163 <input class="custom-control-input"
166 formControlName="unmanaged">
167 <label class="custom-control-label"
169 i18n>Unmanaged</label>
170 <cd-helper i18n>If set to true, the orchestrator will not start nor stop any daemon associated with this service.
171 Placement and all other properties will be ignored.</cd-helper>
177 <div *ngIf="!serviceForm.controls.unmanaged.value"
178 class="form-group row">
179 <label class="cd-col-form-label"
181 i18n>Placement</label>
182 <div class="cd-col-form-input">
183 <select id="placement"
185 formControlName="placement">
187 value="hosts">Hosts</option>
189 value="label">Label</option>
195 <div *ngIf="!serviceForm.controls.unmanaged.value && serviceForm.controls.placement.value === 'label'"
196 class="form-group row">
198 class="cd-col-form-label"
199 for="label">Label</label>
200 <div class="cd-col-form-input">
204 formControlName="label"
205 [ngbTypeahead]="searchLabels"
206 (focus)="labelFocus.next($any($event).target.value)"
207 (click)="labelClick.next($any($event).target.value)">
208 <span class="invalid-feedback"
209 *ngIf="serviceForm.showError('label', frm, 'required')"
210 i18n>This field is required.</span>
215 <div *ngIf="!serviceForm.controls.unmanaged.value && serviceForm.controls.placement.value === 'hosts'"
216 class="form-group row">
217 <label class="cd-col-form-label"
220 <div class="cd-col-form-input">
221 <cd-select-badges id="hosts"
222 [data]="serviceForm.controls.hosts.value"
223 [options]="hosts.options"
224 [messages]="hosts.messages">
230 <div *ngIf="!serviceForm.controls.unmanaged.value"
231 class="form-group row">
232 <label class="cd-col-form-label"
234 <span i18n>Count</span>
235 <cd-helper i18n>Only that number of daemons will be created.</cd-helper>
237 <div class="cd-col-form-input">
241 formControlName="count"
243 <span class="invalid-feedback"
244 *ngIf="serviceForm.showError('count', frm, 'min')"
245 i18n>The value must be at least 1.</span>
246 <span class="invalid-feedback"
247 *ngIf="serviceForm.showError('count', frm, 'pattern')"
248 i18n>The entered value needs to be a number.</span>
253 <ng-container *ngIf="!serviceForm.controls.unmanaged.value && serviceForm.controls.service_type.value === 'rgw'">
254 <!-- rgw_frontend_port -->
255 <div class="form-group row">
257 class="cd-col-form-label"
258 for="rgw_frontend_port">Port</label>
259 <div class="cd-col-form-input">
260 <input id="rgw_frontend_port"
263 formControlName="rgw_frontend_port"
266 <span class="invalid-feedback"
267 *ngIf="serviceForm.showError('rgw_frontend_port', frm, 'pattern')"
268 i18n>The entered value needs to be a number.</span>
269 <span class="invalid-feedback"
270 *ngIf="serviceForm.showError('rgw_frontend_port', frm, 'min')"
271 i18n>The value must be at least 1.</span>
272 <span class="invalid-feedback"
273 *ngIf="serviceForm.showError('rgw_frontend_port', frm, 'max')"
274 i18n>The value cannot exceed 65535.</span>
281 <div class="form-group row"
282 *ngIf="serviceForm.controls.service_type.value === 'iscsi'">
284 class="cd-col-form-label required"
285 for="pool">Pool</label>
286 <div class="cd-col-form-input">
290 formControlName="pool">
291 <option *ngIf="pools === null"
293 i18n>Loading...</option>
294 <option *ngIf="pools && pools.length === 0"
296 i18n>-- No pools available --</option>
297 <option *ngIf="pools && pools.length > 0"
299 i18n>-- Select a pool --</option>
300 <option *ngFor="let pool of pools"
301 [value]="pool.pool_name">{{ pool.pool_name }}</option>
303 <span class="invalid-feedback"
304 *ngIf="serviceForm.showError('pool', frm, 'required')"
305 i18n>This field is required.</span>
309 <!-- fields in iSCSI which are hidden when unmanaged is true -->
310 <ng-container *ngIf="!serviceForm.controls.unmanaged.value && serviceForm.controls.service_type.value === 'iscsi'">
311 <!-- trusted_ip_list -->
312 <div class="form-group row">
313 <label class="cd-col-form-label"
314 for="trusted_ip_list">
315 <span i18n>Trusted IPs</span>
317 <span i18n>Comma separated list of IP addresses.</span>
319 <span i18n>Please add the <b>Ceph Manager</b> IP addresses here, otherwise the iSCSI gateways can't be reached.</span>
322 <div class="cd-col-form-input">
323 <input id="trusted_ip_list"
326 formControlName="trusted_ip_list">
331 <div class="form-group row">
333 class="cd-col-form-label"
334 for="api_port">Port</label>
335 <div class="cd-col-form-input">
339 formControlName="api_port"
342 <span class="invalid-feedback"
343 *ngIf="serviceForm.showError('api_port', frm, 'pattern')"
344 i18n>The entered value needs to be a number.</span>
345 <span class="invalid-feedback"
346 *ngIf="serviceForm.showError('api_port', frm, 'min')"
347 i18n>The value must be at least 1.</span>
348 <span class="invalid-feedback"
349 *ngIf="serviceForm.showError('api_port', frm, 'max')"
350 i18n>The value cannot exceed 65535.</span>
355 <div class="form-group row">
357 class="cd-col-form-label"
358 [ngClass]="{'required': ['iscsi'].includes(serviceForm.controls.service_type.value)}"
359 for="api_user">User</label>
360 <div class="cd-col-form-input">
364 formControlName="api_user">
365 <span class="invalid-feedback"
366 *ngIf="serviceForm.showError('api_user', frm, 'required')"
367 i18n>This field is required.</span>
371 <!-- api_password -->
372 <div class="form-group row">
374 class="cd-col-form-label"
375 [ngClass]="{'required': ['iscsi'].includes(serviceForm.controls.service_type.value)}"
376 for="api_password">Password</label>
377 <div class="cd-col-form-input">
378 <div class="input-group">
379 <input id="api_password"
382 autocomplete="new-password"
383 formControlName="api_password">
384 <button type="button"
385 class="btn btn-light"
386 cdPasswordButton="api_password">
388 <cd-copy-2-clipboard-button source="api_password">
389 </cd-copy-2-clipboard-button>
390 <span class="invalid-feedback"
391 *ngIf="serviceForm.showError('api_password', frm, 'required')"
392 i18n>This field is required.</span>
399 <ng-container *ngIf="serviceForm.controls.service_type.value === 'ingress'">
401 <div class="form-group row">
402 <label class="cd-col-form-label"
403 [ngClass]="{'required': ['ingress'].includes(serviceForm.controls.service_type.value)}"
405 <span i18n>Virtual IP</span>
407 <span i18n>The virtual IP address and subnet (in CIDR notation) where the ingress service will be available.</span>
410 <div class="cd-col-form-input">
411 <input id="virtual_ip"
414 formControlName="virtual_ip">
415 <span class="invalid-feedback"
416 *ngIf="serviceForm.showError('virtual_ip', frm, 'required')"
417 i18n>This field is required.</span>
421 <!-- frontend_port -->
422 <div class="form-group row">
423 <label class="cd-col-form-label"
424 [ngClass]="{'required': ['ingress'].includes(serviceForm.controls.service_type.value)}"
426 <span i18n>Frontend Port</span>
428 <span i18n>The port used to access the ingress service.</span>
431 <div class="cd-col-form-input">
432 <input id="frontend_port"
435 formControlName="frontend_port"
438 <span class="invalid-feedback"
439 *ngIf="serviceForm.showError('frontend_port', frm, 'pattern')"
440 i18n>The entered value needs to be a number.</span>
441 <span class="invalid-feedback"
442 *ngIf="serviceForm.showError('frontend_port', frm, 'min')"
443 i18n>The value must be at least 1.</span>
444 <span class="invalid-feedback"
445 *ngIf="serviceForm.showError('frontend_port', frm, 'max')"
446 i18n>The value cannot exceed 65535.</span>
447 <span class="invalid-feedback"
448 *ngIf="serviceForm.showError('frontend_port', frm, 'required')"
449 i18n>This field is required.</span>
453 <!-- monitor_port -->
454 <div class="form-group row">
455 <label class="cd-col-form-label"
456 [ngClass]="{'required': ['ingress'].includes(serviceForm.controls.service_type.value)}"
458 <span i18n>Monitor Port</span>
460 <span i18n>The port used by haproxy for load balancer status.</span>
463 <div class="cd-col-form-input">
464 <input id="monitor_port"
467 formControlName="monitor_port"
470 <span class="invalid-feedback"
471 *ngIf="serviceForm.showError('monitor_port', frm, 'pattern')"
472 i18n>The entered value needs to be a number.</span>
473 <span class="invalid-feedback"
474 *ngIf="serviceForm.showError('monitor_port', frm, 'min')"
475 i18n>The value must be at least 1.</span>
476 <span class="invalid-feedback"
477 *ngIf="serviceForm.showError('monitor_port', frm, 'max')"
478 i18n>The value cannot exceed 65535.</span>
479 <span class="invalid-feedback"
480 *ngIf="serviceForm.showError('monitor_port', frm, 'required')"
481 i18n>This field is required.</span>
484 <!-- virtual_interface_networks -->
485 <div class="form-group row"
486 *ngIf="!serviceForm.controls.unmanaged.value">
487 <label class="cd-col-form-label"
488 for="virtual_interface_networks">
489 <span i18n>CIDR Networks</span>
491 <span i18n>A list of networks to identify which network interface to use for the virtual IP address.</span>
494 <div class="cd-col-form-input">
495 <input id="virtual_interface_networks"
498 formControlName="virtual_interface_networks">
503 <!-- SNMP-Gateway -->
504 <ng-container *ngIf="serviceForm.controls.service_type.value === 'snmp-gateway'">
505 <!-- snmp-version -->
506 <div class="form-group row">
507 <label class="cd-col-form-label required"
510 <div class="cd-col-form-input">
511 <select id="snmp_version"
514 formControlName="snmp_version"
515 (change)="clearValidations()">
517 [ngValue]="null">-- Select SNMP version --</option>
518 <option *ngFor="let snmpVersion of ['V2c', 'V3']"
519 [value]="snmpVersion">{{ snmpVersion }}</option>
521 <span class="invalid-feedback"
522 *ngIf="serviceForm.showError('snmp_version', frm, 'required')"
523 i18n>This field is required.</span>
527 <div class="form-group row">
528 <label class="cd-col-form-label required"
529 for="snmp_destination">
530 <span i18n>Destination</span>
532 <span i18n>Must be of the format hostname:port.</span>
535 <div class="cd-col-form-input">
536 <input id="snmp_destination"
539 formControlName="snmp_destination">
540 <span class="invalid-feedback"
541 *ngIf="serviceForm.showError('snmp_destination', frm, 'required')"
542 i18n>This field is required.</span>
543 <span class="invalid-feedback"
544 *ngIf="serviceForm.showError('snmp_destination', frm, 'snmpDestinationPattern')"
545 i18n>The value does not match the pattern: <strong>hostname:port</strong></span>
548 <!-- Engine id for snmp V3 -->
549 <div class="form-group row"
550 *ngIf="serviceForm.controls.snmp_version.value === 'V3'">
551 <label class="cd-col-form-label required"
553 <span i18n>Engine Id</span>
555 <span i18n>Unique identifier for the device (in hex).</span>
558 <div class="cd-col-form-input">
559 <input id="engine_id"
562 formControlName="engine_id">
563 <span class="invalid-feedback"
564 *ngIf="serviceForm.showError('engine_id', frm, 'required')"
565 i18n>This field is required.</span>
566 <span class="invalid-feedback"
567 *ngIf="serviceForm.showError('engine_id', frm, 'snmpEngineIdPattern')"
568 i18n>The value does not match the pattern: <strong>Must be in hexadecimal and length must be multiple of 2 with min value = 10 amd max value = 64.</strong></span>
571 <!-- Auth protocol for snmp V3 -->
572 <div class="form-group row"
573 *ngIf="serviceForm.controls.snmp_version.value === 'V3'">
574 <label class="cd-col-form-label required"
576 i18n>Auth Protocol</label>
577 <div class="cd-col-form-input">
578 <select id="auth_protocol"
581 formControlName="auth_protocol">
583 [ngValue]="null">-- Select auth protocol --</option>
584 <option *ngFor="let authProtocol of ['SHA', 'MD5']"
585 [value]="authProtocol">
589 <span class="invalid-feedback"
590 *ngIf="serviceForm.showError('auth_protocol', frm, 'required')"
591 i18n>This field is required.</span>
594 <!-- Privacy protocol for snmp V3 -->
595 <div class="form-group row"
596 *ngIf="serviceForm.controls.snmp_version.value === 'V3'">
597 <label class="cd-col-form-label"
598 for="privacy_protocol"
599 i18n>Privacy Protocol</label>
600 <div class="cd-col-form-input">
601 <select id="privacy_protocol"
602 name="privacy_protocol"
604 formControlName="privacy_protocol">
606 [ngValue]="null">-- Select privacy protocol --</option>
607 <option *ngFor="let privacyProtocol of ['DES', 'AES']"
608 [value]="privacyProtocol">
609 {{ privacyProtocol }}
616 <legend i18n>Credentials</legend>
617 <!-- snmp v2c snmp_community -->
618 <div class="form-group row"
619 *ngIf="serviceForm.controls.snmp_version.value === 'V2c'">
620 <label class="cd-col-form-label required"
621 for="snmp_community">
622 <span i18n>SNMP Community</span>
624 <div class="cd-col-form-input">
625 <input id="snmp_community"
628 formControlName="snmp_community">
629 <span class="invalid-feedback"
630 *ngIf="serviceForm.showError('snmp_community', frm, 'required')"
631 i18n>This field is required.</span>
634 <!-- snmp v3 auth username -->
635 <div class="form-group row"
636 *ngIf="serviceForm.controls.snmp_version.value === 'V3'">
637 <label class="cd-col-form-label required"
638 for="snmp_v3_auth_username">
639 <span i18n>Username</span>
641 <div class="cd-col-form-input">
642 <input id="snmp_v3_auth_username"
645 formControlName="snmp_v3_auth_username">
646 <span class="invalid-feedback"
647 *ngIf="serviceForm.showError('snmp_v3_auth_username', frm, 'required')"
648 i18n>This field is required.</span>
651 <!-- snmp v3 auth password -->
652 <div class="form-group row"
653 *ngIf="serviceForm.controls.snmp_version.value === 'V3'">
654 <label class="cd-col-form-label required"
655 for="snmp_v3_auth_password">
656 <span i18n>Password</span>
658 <div class="cd-col-form-input">
659 <input id="snmp_v3_auth_password"
662 formControlName="snmp_v3_auth_password">
663 <span class="invalid-feedback"
664 *ngIf="serviceForm.showError('snmp_v3_auth_password', frm, 'required')"
665 i18n>This field is required.</span>
668 <!-- snmp v3 priv password -->
669 <div class="form-group row"
670 *ngIf="serviceForm.controls.snmp_version.value === 'V3' && serviceForm.controls.privacy_protocol.value !== null && serviceForm.controls.privacy_protocol.value !== undefined">
671 <label class="cd-col-form-label required"
672 for="snmp_v3_priv_password">
673 <span i18n>Encryption</span>
675 <div class="cd-col-form-input">
676 <input id="snmp_v3_priv_password"
679 formControlName="snmp_v3_priv_password">
680 <span class="invalid-feedback"
681 *ngIf="serviceForm.showError('snmp_v3_priv_password', frm, 'required')"
682 i18n>This field is required.</span>
687 <!-- RGW, Ingress & iSCSI -->
688 <ng-container *ngIf="!serviceForm.controls.unmanaged.value && ['rgw', 'iscsi', 'ingress'].includes(serviceForm.controls.service_type.value)">
690 <div class="form-group row">
691 <div class="cd-col-form-offset">
692 <div class="custom-control custom-checkbox">
693 <input class="custom-control-input"
696 formControlName="ssl">
697 <label class="custom-control-label"
705 <div *ngIf="serviceForm.controls.ssl.value"
706 class="form-group row">
707 <label class="cd-col-form-label"
709 <span i18n>Certificate</span>
710 <cd-helper i18n>The SSL certificate in PEM format.</cd-helper>
712 <div class="cd-col-form-input">
713 <textarea id="ssl_cert"
714 class="form-control resize-vertical text-monospace text-pre"
715 formControlName="ssl_cert"
719 (change)="fileUpload($event.target.files, 'ssl_cert')">
720 <span class="invalid-feedback"
721 *ngIf="serviceForm.showError('ssl_cert', frm, 'required')"
722 i18n>This field is required.</span>
723 <span class="invalid-feedback"
724 *ngIf="serviceForm.showError('ssl_cert', frm, 'pattern')"
725 i18n>Invalid SSL certificate.</span>
730 <div *ngIf="serviceForm.controls.ssl.value && !(['rgw', 'ingress'].includes(serviceForm.controls.service_type.value))"
731 class="form-group row">
732 <label class="cd-col-form-label"
734 <span i18n>Private key</span>
735 <cd-helper i18n>The SSL private key in PEM format.</cd-helper>
737 <div class="cd-col-form-input">
738 <textarea id="ssl_key"
739 class="form-control resize-vertical text-monospace text-pre"
740 formControlName="ssl_key"
744 (change)="fileUpload($event.target.files,'ssl_key')">
745 <span class="invalid-feedback"
746 *ngIf="serviceForm.showError('ssl_key', frm, 'required')"
747 i18n>This field is required.</span>
748 <span class="invalid-feedback"
749 *ngIf="serviceForm.showError('ssl_key', frm, 'pattern')"
750 i18n>Invalid SSL private key.</span>
755 <ng-container *ngIf="serviceForm.controls.service_type.value === 'grafana'">
756 <div class="form-group row">
757 <label class="cd-col-form-label"
759 <span i18n>Grafana Port</span>
761 <span i18n>The default port used by grafana.</span>
764 <div class="cd-col-form-input">
765 <input id="grafana_port"
768 formControlName="grafana_port"
771 <span class="invalid-feedback"
772 *ngIf="serviceForm.showError('grafana_port', frm, 'pattern')"
773 i18n>The entered value needs to be a number.</span>
774 <span class="invalid-feedback"
775 *ngIf="serviceForm.showError('grafana_port', frm, 'min')"
776 i18n>The value must be at least 1.</span>
777 <span class="invalid-feedback"
778 *ngIf="serviceForm.showError('grafana_port', frm, 'max')"
779 i18n>The value cannot exceed 65535.</span>
780 <span class="invalid-feedback"
781 *ngIf="serviceForm.showError('grafana_port', frm, 'required')"
782 i18n>This field is required.</span>
786 <div class="form-group row">
788 class="cd-col-form-label"
789 for="grafana_admin_password">
790 <span>Grafana Password</span>
791 <cd-helper>The password of the default Grafana Admin. Set once on first-run.</cd-helper>
793 <div class="cd-col-form-input">
794 <div class="input-group">
795 <input id="grafana_admin_password"
798 autocomplete="new-password"
799 [attr.disabled]="editing ? true:null"
800 formControlName="grafana_admin_password">
801 <span class="input-group-append">
802 <button type="button"
803 class="btn btn-light"
804 cdPasswordButton="grafana_admin_password">
806 <cd-copy-2-clipboard-button source="grafana_admin_password">
807 </cd-copy-2-clipboard-button>
815 <div class="modal-footer">
816 <div class="text-right">
817 <cd-form-button-panel (submitActionEvent)="onSubmit()"
819 [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"></cd-form-button-panel>