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">
12 <div class="form-group row">
13 <label class="cd-col-form-label required"
16 <div class="cd-col-form-input">
17 <select id="service_type"
20 formControlName="service_type"
21 (change)="getServiceIds($event.target.value)">
23 [ngValue]="null">-- Select a service type --</option>
24 <option *ngFor="let serviceType of serviceTypes"
25 [value]="serviceType">
29 <span class="invalid-feedback"
30 *ngIf="serviceForm.showError('service_type', frm, 'required')"
31 i18n>This field is required.</span>
35 <!-- backend_service -->
36 <div *ngIf="serviceForm.controls.service_type.value === 'ingress'"
37 class="form-group row">
39 class="cd-col-form-label"
40 [ngClass]="{'required': ['ingress'].includes(serviceForm.controls.service_type.value)}"
41 for="backend_service">Backend Service</label>
42 <div class="cd-col-form-input">
43 <select id="backend_service"
44 name="backend_service"
46 formControlName="backend_service"
47 (change)="prePopulateId()">
48 <option *ngIf="services === null"
50 i18n>Loading...</option>
51 <option *ngIf="services !== null && services.length === 0"
53 i18n>-- No service available --</option>
54 <option *ngIf="services !== null && services.length > 0"
56 i18n>-- Select an existing service --</option>
57 <option *ngFor="let service of services"
58 [value]="service.service_name">{{ service.service_name }}</option>
60 <span class="invalid-feedback"
61 *ngIf="serviceForm.showError('backend_service', frm, 'required')"
62 i18n>This field is required.</span>
67 <div class="form-group row"
68 *ngIf="serviceForm.controls.service_type.value !== 'snmp-gateway'">
69 <label class="cd-col-form-label"
70 [ngClass]="{'required': ['mds', 'rgw', 'nfs', 'iscsi', 'ingress'].includes(serviceForm.controls.service_type.value)}"
73 <cd-helper i18n>Used in the service name which is <service_type.service_id></cd-helper>
75 <div class="cd-col-form-input">
76 <input id="service_id"
79 formControlName="service_id">
80 <span class="invalid-feedback"
81 *ngIf="serviceForm.showError('service_id', frm, 'required')"
82 i18n>This field is required.</span>
83 <span class="invalid-feedback"
84 *ngIf="serviceForm.showError('service_id', frm, 'uniqueName')"
85 i18n>This service id is already in use.</span>
86 <span class="invalid-feedback"
87 *ngIf="serviceForm.showError('service_id', frm, 'rgwPattern')"
88 i18n>The value does not match the pattern <strong><service_id>[.<realm_name>.<zone_name>]</strong>.</span>
89 <span class="invalid-feedback"
90 *ngIf="serviceForm.showError('service_id', frm, 'mdsPattern')"
91 i18n>MDS service id must start with a letter and contain alphanumeric characters or '.', '-', and '_'</span>
96 <div class="form-group row">
97 <div class="cd-col-form-offset">
98 <div class="custom-control custom-checkbox">
99 <input class="custom-control-input"
102 formControlName="unmanaged">
103 <label class="custom-control-label"
105 i18n>Unmanaged</label>
111 <div *ngIf="!serviceForm.controls.unmanaged.value"
112 class="form-group row">
113 <label class="cd-col-form-label"
115 i18n>Placement</label>
116 <div class="cd-col-form-input">
117 <select id="placement"
119 formControlName="placement">
121 value="hosts">Hosts</option>
123 value="label">Label</option>
129 <div *ngIf="!serviceForm.controls.unmanaged.value && serviceForm.controls.placement.value === 'label'"
130 class="form-group row">
132 class="cd-col-form-label"
133 for="label">Label</label>
134 <div class="cd-col-form-input">
138 formControlName="label"
139 [ngbTypeahead]="searchLabels"
140 (focus)="labelFocus.next($any($event).target.value)"
141 (click)="labelClick.next($any($event).target.value)">
142 <span class="invalid-feedback"
143 *ngIf="serviceForm.showError('label', frm, 'required')"
144 i18n>This field is required.</span>
149 <div *ngIf="!serviceForm.controls.unmanaged.value && serviceForm.controls.placement.value === 'hosts'"
150 class="form-group row">
151 <label class="cd-col-form-label"
154 <div class="cd-col-form-input">
155 <cd-select-badges id="hosts"
156 [data]="serviceForm.controls.hosts.value"
157 [options]="hosts.options"
158 [messages]="hosts.messages">
164 <div *ngIf="!serviceForm.controls.unmanaged.value"
165 class="form-group row">
166 <label class="cd-col-form-label"
168 <span i18n>Count</span>
169 <cd-helper i18n>Only that number of daemons will be created.</cd-helper>
171 <div class="cd-col-form-input">
175 formControlName="count"
177 <span class="invalid-feedback"
178 *ngIf="serviceForm.showError('count', frm, 'min')"
179 i18n>The value must be at least 1.</span>
180 <span class="invalid-feedback"
181 *ngIf="serviceForm.showError('count', frm, 'pattern')"
182 i18n>The entered value needs to be a number.</span>
187 <ng-container *ngIf="!serviceForm.controls.unmanaged.value && serviceForm.controls.service_type.value === 'rgw'">
188 <!-- rgw_frontend_port -->
189 <div class="form-group row">
191 class="cd-col-form-label"
192 for="rgw_frontend_port">Port</label>
193 <div class="cd-col-form-input">
194 <input id="rgw_frontend_port"
197 formControlName="rgw_frontend_port"
200 <span class="invalid-feedback"
201 *ngIf="serviceForm.showError('rgw_frontend_port', frm, 'pattern')"
202 i18n>The entered value needs to be a number.</span>
203 <span class="invalid-feedback"
204 *ngIf="serviceForm.showError('rgw_frontend_port', frm, 'min')"
205 i18n>The value must be at least 1.</span>
206 <span class="invalid-feedback"
207 *ngIf="serviceForm.showError('rgw_frontend_port', frm, 'max')"
208 i18n>The value cannot exceed 65535.</span>
215 <div class="form-group row"
216 *ngIf="serviceForm.controls.service_type.value === 'iscsi'">
218 class="cd-col-form-label required"
219 for="pool">Pool</label>
220 <div class="cd-col-form-input">
224 formControlName="pool">
225 <option *ngIf="pools === null"
227 i18n>Loading...</option>
228 <option *ngIf="pools && pools.length === 0"
230 i18n>-- No pools available --</option>
231 <option *ngIf="pools && pools.length > 0"
233 i18n>-- Select a pool --</option>
234 <option *ngFor="let pool of pools"
235 [value]="pool.pool_name">{{ pool.pool_name }}</option>
237 <span class="invalid-feedback"
238 *ngIf="serviceForm.showError('pool', frm, 'required')"
239 i18n>This field is required.</span>
243 <!-- fields in iSCSI which are hidden when unmanaged is true -->
244 <ng-container *ngIf="!serviceForm.controls.unmanaged.value && serviceForm.controls.service_type.value === 'iscsi'">
245 <!-- trusted_ip_list -->
246 <div class="form-group row">
247 <label class="cd-col-form-label"
248 for="trusted_ip_list">
249 <span i18n>Trusted IPs</span>
251 <span i18n>Comma separated list of IP addresses.</span>
253 <span i18n>Please add the <b>Ceph Manager</b> IP addresses here, otherwise the iSCSI gateways can't be reached.</span>
256 <div class="cd-col-form-input">
257 <input id="trusted_ip_list"
260 formControlName="trusted_ip_list">
265 <div class="form-group row">
267 class="cd-col-form-label"
268 for="api_port">Port</label>
269 <div class="cd-col-form-input">
273 formControlName="api_port"
276 <span class="invalid-feedback"
277 *ngIf="serviceForm.showError('api_port', frm, 'pattern')"
278 i18n>The entered value needs to be a number.</span>
279 <span class="invalid-feedback"
280 *ngIf="serviceForm.showError('api_port', frm, 'min')"
281 i18n>The value must be at least 1.</span>
282 <span class="invalid-feedback"
283 *ngIf="serviceForm.showError('api_port', frm, 'max')"
284 i18n>The value cannot exceed 65535.</span>
289 <div class="form-group row">
291 class="cd-col-form-label"
292 [ngClass]="{'required': ['iscsi'].includes(serviceForm.controls.service_type.value)}"
293 for="api_user">User</label>
294 <div class="cd-col-form-input">
298 formControlName="api_user">
299 <span class="invalid-feedback"
300 *ngIf="serviceForm.showError('api_user', frm, 'required')"
301 i18n>This field is required.</span>
305 <!-- api_password -->
306 <div class="form-group row">
308 class="cd-col-form-label"
309 [ngClass]="{'required': ['iscsi'].includes(serviceForm.controls.service_type.value)}"
310 for="api_password">Password</label>
311 <div class="cd-col-form-input">
312 <div class="input-group">
313 <input id="api_password"
316 autocomplete="new-password"
317 formControlName="api_password">
318 <button type="button"
319 class="btn btn-light"
320 cdPasswordButton="api_password">
322 <cd-copy-2-clipboard-button source="api_password">
323 </cd-copy-2-clipboard-button>
324 <span class="invalid-feedback"
325 *ngIf="serviceForm.showError('api_password', frm, 'required')"
326 i18n>This field is required.</span>
333 <ng-container *ngIf="serviceForm.controls.service_type.value === 'ingress'">
335 <div class="form-group row">
336 <label class="cd-col-form-label"
337 [ngClass]="{'required': ['ingress'].includes(serviceForm.controls.service_type.value)}"
339 <span i18n>Virtual IP</span>
341 <span i18n>The virtual IP address and subnet (in CIDR notation) where the ingress service will be available.</span>
344 <div class="cd-col-form-input">
345 <input id="virtual_ip"
348 formControlName="virtual_ip">
349 <span class="invalid-feedback"
350 *ngIf="serviceForm.showError('virtual_ip', frm, 'required')"
351 i18n>This field is required.</span>
355 <!-- frontend_port -->
356 <div class="form-group row">
357 <label class="cd-col-form-label"
358 [ngClass]="{'required': ['ingress'].includes(serviceForm.controls.service_type.value)}"
360 <span i18n>Frontend Port</span>
362 <span i18n>The port used to access the ingress service.</span>
365 <div class="cd-col-form-input">
366 <input id="frontend_port"
369 formControlName="frontend_port"
372 <span class="invalid-feedback"
373 *ngIf="serviceForm.showError('frontend_port', frm, 'pattern')"
374 i18n>The entered value needs to be a number.</span>
375 <span class="invalid-feedback"
376 *ngIf="serviceForm.showError('frontend_port', frm, 'min')"
377 i18n>The value must be at least 1.</span>
378 <span class="invalid-feedback"
379 *ngIf="serviceForm.showError('frontend_port', frm, 'max')"
380 i18n>The value cannot exceed 65535.</span>
381 <span class="invalid-feedback"
382 *ngIf="serviceForm.showError('frontend_port', frm, 'required')"
383 i18n>This field is required.</span>
387 <!-- monitor_port -->
388 <div class="form-group row">
389 <label class="cd-col-form-label"
390 [ngClass]="{'required': ['ingress'].includes(serviceForm.controls.service_type.value)}"
392 <span i18n>Monitor Port</span>
394 <span i18n>The port used by haproxy for load balancer status.</span>
397 <div class="cd-col-form-input">
398 <input id="monitor_port"
401 formControlName="monitor_port"
404 <span class="invalid-feedback"
405 *ngIf="serviceForm.showError('monitor_port', frm, 'pattern')"
406 i18n>The entered value needs to be a number.</span>
407 <span class="invalid-feedback"
408 *ngIf="serviceForm.showError('monitor_port', frm, 'min')"
409 i18n>The value must be at least 1.</span>
410 <span class="invalid-feedback"
411 *ngIf="serviceForm.showError('monitor_port', frm, 'max')"
412 i18n>The value cannot exceed 65535.</span>
413 <span class="invalid-feedback"
414 *ngIf="serviceForm.showError('monitor_port', frm, 'required')"
415 i18n>This field is required.</span>
418 <!-- virtual_interface_networks -->
419 <div class="form-group row"
420 *ngIf="!serviceForm.controls.unmanaged.value">
421 <label class="cd-col-form-label"
422 for="virtual_interface_networks">
423 <span i18n>CIDR Networks</span>
425 <span i18n>A list of networks to identify which network interface to use for the virtual IP address.</span>
428 <div class="cd-col-form-input">
429 <input id="virtual_interface_networks"
432 formControlName="virtual_interface_networks">
437 <!-- SNMP-Gateway -->
438 <ng-container *ngIf="serviceForm.controls.service_type.value === 'snmp-gateway'">
439 <!-- snmp-version -->
440 <div class="form-group row">
441 <label class="cd-col-form-label required"
444 <div class="cd-col-form-input">
445 <select id="snmp_version"
448 formControlName="snmp_version"
449 (change)="clearValidations()">
451 [ngValue]="null">-- Select SNMP version --</option>
452 <option *ngFor="let snmpVersion of ['V2c', 'V3']"
453 [value]="snmpVersion">{{ snmpVersion }}</option>
455 <span class="invalid-feedback"
456 *ngIf="serviceForm.showError('snmp_version', frm, 'required')"
457 i18n>This field is required.</span>
461 <div class="form-group row">
462 <label class="cd-col-form-label required"
463 for="snmp_destination">
464 <span i18n>Destination</span>
466 <span i18n>Must be of the format hostname:port.</span>
469 <div class="cd-col-form-input">
470 <input id="snmp_destination"
473 formControlName="snmp_destination">
474 <span class="invalid-feedback"
475 *ngIf="serviceForm.showError('snmp_destination', frm, 'required')"
476 i18n>This field is required.</span>
477 <span class="invalid-feedback"
478 *ngIf="serviceForm.showError('snmp_destination', frm, 'snmpDestinationPattern')"
479 i18n>The value does not match the pattern: <strong>hostname:port</strong></span>
482 <!-- Engine id for snmp V3 -->
483 <div class="form-group row"
484 *ngIf="serviceForm.controls.snmp_version.value === 'V3'">
485 <label class="cd-col-form-label required"
487 <span i18n>Engine Id</span>
489 <span i18n>Unique identifier for the device (in hex).</span>
492 <div class="cd-col-form-input">
493 <input id="engine_id"
496 formControlName="engine_id">
497 <span class="invalid-feedback"
498 *ngIf="serviceForm.showError('engine_id', frm, 'required')"
499 i18n>This field is required.</span>
500 <span class="invalid-feedback"
501 *ngIf="serviceForm.showError('engine_id', frm, 'snmpEngineIdPattern')"
502 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>
505 <!-- Auth protocol for snmp V3 -->
506 <div class="form-group row"
507 *ngIf="serviceForm.controls.snmp_version.value === 'V3'">
508 <label class="cd-col-form-label required"
510 i18n>Auth Protocol</label>
511 <div class="cd-col-form-input">
512 <select id="auth_protocol"
515 formControlName="auth_protocol">
517 [ngValue]="null">-- Select auth protocol --</option>
518 <option *ngFor="let authProtocol of ['SHA', 'MD5']"
519 [value]="authProtocol">
523 <span class="invalid-feedback"
524 *ngIf="serviceForm.showError('auth_protocol', frm, 'required')"
525 i18n>This field is required.</span>
528 <!-- Privacy protocol for snmp V3 -->
529 <div class="form-group row"
530 *ngIf="serviceForm.controls.snmp_version.value === 'V3'">
531 <label class="cd-col-form-label"
532 for="privacy_protocol"
533 i18n>Privacy Protocol</label>
534 <div class="cd-col-form-input">
535 <select id="privacy_protocol"
536 name="privacy_protocol"
538 formControlName="privacy_protocol">
540 [ngValue]="null">-- Select privacy protocol --</option>
541 <option *ngFor="let privacyProtocol of ['DES', 'AES']"
542 [value]="privacyProtocol">
543 {{ privacyProtocol }}
550 <legend i18n>Credentials</legend>
551 <!-- snmp v2c snmp_community -->
552 <div class="form-group row"
553 *ngIf="serviceForm.controls.snmp_version.value === 'V2c'">
554 <label class="cd-col-form-label required"
555 for="snmp_community">
556 <span i18n>SNMP Community</span>
558 <div class="cd-col-form-input">
559 <input id="snmp_community"
562 formControlName="snmp_community">
563 <span class="invalid-feedback"
564 *ngIf="serviceForm.showError('snmp_community', frm, 'required')"
565 i18n>This field is required.</span>
568 <!-- snmp v3 auth username -->
569 <div class="form-group row"
570 *ngIf="serviceForm.controls.snmp_version.value === 'V3'">
571 <label class="cd-col-form-label required"
572 for="snmp_v3_auth_username">
573 <span i18n>Username</span>
575 <div class="cd-col-form-input">
576 <input id="snmp_v3_auth_username"
579 formControlName="snmp_v3_auth_username">
580 <span class="invalid-feedback"
581 *ngIf="serviceForm.showError('snmp_v3_auth_username', frm, 'required')"
582 i18n>This field is required.</span>
585 <!-- snmp v3 auth password -->
586 <div class="form-group row"
587 *ngIf="serviceForm.controls.snmp_version.value === 'V3'">
588 <label class="cd-col-form-label required"
589 for="snmp_v3_auth_password">
590 <span i18n>Password</span>
592 <div class="cd-col-form-input">
593 <input id="snmp_v3_auth_password"
596 formControlName="snmp_v3_auth_password">
597 <span class="invalid-feedback"
598 *ngIf="serviceForm.showError('snmp_v3_auth_password', frm, 'required')"
599 i18n>This field is required.</span>
602 <!-- snmp v3 priv password -->
603 <div class="form-group row"
604 *ngIf="serviceForm.controls.snmp_version.value === 'V3' && serviceForm.controls.privacy_protocol.value !== null && serviceForm.controls.privacy_protocol.value !== undefined">
605 <label class="cd-col-form-label required"
606 for="snmp_v3_priv_password">
607 <span i18n>Encryption</span>
609 <div class="cd-col-form-input">
610 <input id="snmp_v3_priv_password"
613 formControlName="snmp_v3_priv_password">
614 <span class="invalid-feedback"
615 *ngIf="serviceForm.showError('snmp_v3_priv_password', frm, 'required')"
616 i18n>This field is required.</span>
621 <!-- RGW, Ingress & iSCSI -->
622 <ng-container *ngIf="!serviceForm.controls.unmanaged.value && ['rgw', 'iscsi', 'ingress'].includes(serviceForm.controls.service_type.value)">
624 <div class="form-group row">
625 <div class="cd-col-form-offset">
626 <div class="custom-control custom-checkbox">
627 <input class="custom-control-input"
630 formControlName="ssl">
631 <label class="custom-control-label"
639 <div *ngIf="serviceForm.controls.ssl.value"
640 class="form-group row">
641 <label class="cd-col-form-label"
643 <span i18n>Certificate</span>
644 <cd-helper i18n>The SSL certificate in PEM format.</cd-helper>
646 <div class="cd-col-form-input">
647 <textarea id="ssl_cert"
648 class="form-control resize-vertical text-monospace text-pre"
649 formControlName="ssl_cert"
653 (change)="fileUpload($event.target.files, 'ssl_cert')">
654 <span class="invalid-feedback"
655 *ngIf="serviceForm.showError('ssl_cert', frm, 'required')"
656 i18n>This field is required.</span>
657 <span class="invalid-feedback"
658 *ngIf="serviceForm.showError('ssl_cert', frm, 'pattern')"
659 i18n>Invalid SSL certificate.</span>
664 <div *ngIf="serviceForm.controls.ssl.value && !(['rgw', 'ingress'].includes(serviceForm.controls.service_type.value))"
665 class="form-group row">
666 <label class="cd-col-form-label"
668 <span i18n>Private key</span>
669 <cd-helper i18n>The SSL private key in PEM format.</cd-helper>
671 <div class="cd-col-form-input">
672 <textarea id="ssl_key"
673 class="form-control resize-vertical text-monospace text-pre"
674 formControlName="ssl_key"
678 (change)="fileUpload($event.target.files,'ssl_key')">
679 <span class="invalid-feedback"
680 *ngIf="serviceForm.showError('ssl_key', frm, 'required')"
681 i18n>This field is required.</span>
682 <span class="invalid-feedback"
683 *ngIf="serviceForm.showError('ssl_key', frm, 'pattern')"
684 i18n>Invalid SSL private key.</span>
689 <ng-container *ngIf="serviceForm.controls.service_type.value === 'grafana'">
690 <div class="form-group row">
691 <label class="cd-col-form-label"
693 <span i18n>Grafana Port</span>
695 <span i18n>The default port used by grafana.</span>
698 <div class="cd-col-form-input">
699 <input id="grafana_port"
702 formControlName="grafana_port"
705 <span class="invalid-feedback"
706 *ngIf="serviceForm.showError('grafana_port', frm, 'pattern')"
707 i18n>The entered value needs to be a number.</span>
708 <span class="invalid-feedback"
709 *ngIf="serviceForm.showError('grafana_port', frm, 'min')"
710 i18n>The value must be at least 1.</span>
711 <span class="invalid-feedback"
712 *ngIf="serviceForm.showError('grafana_port', frm, 'max')"
713 i18n>The value cannot exceed 65535.</span>
714 <span class="invalid-feedback"
715 *ngIf="serviceForm.showError('grafana_port', frm, 'required')"
716 i18n>This field is required.</span>
720 <div class="form-group row">
722 class="cd-col-form-label"
723 for="grafana_admin_password">
724 <span>Grafana Password</span>
725 <cd-helper>The password of the default Grafana Admin. Set once on first-run.</cd-helper>
727 <div class="cd-col-form-input">
728 <div class="input-group">
729 <input id="grafana_admin_password"
732 autocomplete="new-password"
733 [attr.disabled]="editing ? true:null"
734 formControlName="grafana_admin_password">
735 <span class="input-group-append">
736 <button type="button"
737 class="btn btn-light"
738 cdPasswordButton="grafana_admin_password">
740 <cd-copy-2-clipboard-button source="grafana_admin_password">
741 </cd-copy-2-clipboard-button>
749 <div class="modal-footer">
750 <div class="text-right">
751 <cd-form-button-panel (submitActionEvent)="onSubmit()"
753 [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"></cd-form-button-panel>