1 import { Component, OnInit } from '@angular/core';
2 import { FormControl, Validators } from '@angular/forms';
3 import { Router } from '@angular/router';
5 import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
6 import expand from 'brace-expansion';
8 import { HostService } from '~/app/shared/api/host.service';
9 import { SelectMessages } from '~/app/shared/components/select/select-messages.model';
10 import { SelectOption } from '~/app/shared/components/select/select-option.model';
11 import { ActionLabelsI18n, URLVerbs } from '~/app/shared/constants/app.constants';
12 import { CdForm } from '~/app/shared/forms/cd-form';
13 import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
14 import { CdValidators } from '~/app/shared/forms/cd-validators';
15 import { FinishedTask } from '~/app/shared/models/finished-task';
16 import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
19 selector: 'cd-host-form',
20 templateUrl: './host-form.component.html',
21 styleUrls: ['./host-form.component.scss']
23 export class HostFormComponent extends CdForm implements OnInit {
24 hostForm: CdFormGroup;
28 hostnameArray: string[] = [];
34 labelsOption: Array<SelectOption> = [];
35 hideMaintenance: boolean;
37 messages = new SelectMessages({
38 empty: $localize`There are no labels.`,
39 filter: $localize`Filter or add labels`,
40 add: $localize`Add label`
44 private router: Router,
45 private actionLabels: ActionLabelsI18n,
46 private hostService: HostService,
47 private taskWrapper: TaskWrapperService,
48 public activeModal: NgbActiveModal
51 this.resource = $localize`host`;
52 this.action = this.actionLabels.ADD;
56 if (this.router.url.includes('hosts')) {
57 this.pageURL = 'hosts';
60 this.hostService.list('false').subscribe((resp: any[]) => {
61 this.hostnames = resp.map((host) => {
62 return host['hostname'];
67 this.hostService.getLabels().subscribe((resp: string[]) => {
68 const uniqueLabels = new Set(resp.concat(this.hostService.predefinedLabels));
69 this.labelsOption = Array.from(uniqueLabels).map((label) => {
70 return { enabled: true, name: label, selected: false, description: null };
75 // check if hostname is a single value or pattern to hide network address field
76 checkHostNameValue() {
77 const hostNames = this.hostForm.get('hostname').value;
78 hostNames.match(/[()\[\]{},]/g) ? (this.hostPattern = true) : (this.hostPattern = false);
81 private createForm() {
82 this.hostForm = new CdFormGroup({
83 hostname: new FormControl('', {
86 CdValidators.custom('uniqueName', (hostname: string) => {
87 return this.hostnames && this.hostnames.indexOf(hostname) !== -1;
91 addr: new FormControl('', {
92 validators: [CdValidators.ip()]
94 labels: new FormControl([]),
95 maintenance: new FormControl(false)
99 private isCommaSeparatedPattern(hostname: string) {
100 // eg. ceph-node-01.cephlab.com,ceph-node-02.cephlab.com
101 return hostname.includes(',');
104 private isRangeTypePattern(hostname: string) {
105 // check if it is a range expression or comma separated range expression
106 // eg. ceph-mon-[01-05].lab.com,ceph-osd-[02-08].lab.com,ceph-rgw-[01-09]
107 return hostname.includes('[') && hostname.includes(']') && !hostname.match(/(?![^(]*\)),/g);
110 private replaceBraces(hostname: string) {
111 // pattern to replace range [0-5] to [0..5](valid expression for brace expansion)
112 // replace any kind of brackets with curly braces
114 .replace(/(\d)\s*-\s*(\d)/g, '$1..$2')
121 // expand hostnames in case hostname is a pattern
122 private checkHostNamePattern(hostname: string) {
123 if (this.isRangeTypePattern(hostname)) {
124 const hostnameRange = this.replaceBraces(hostname);
125 this.hostnameArray = expand(hostnameRange);
126 } else if (this.isCommaSeparatedPattern(hostname)) {
128 hostArray = hostname.split(',');
129 hostArray.forEach((host: string) => {
130 if (this.isRangeTypePattern(host)) {
131 const hostnameRange = this.replaceBraces(host);
132 this.hostnameArray = this.hostnameArray.concat(expand(hostnameRange));
134 this.hostnameArray.push(host);
139 this.hostnameArray.push(hostname);
144 const hostname = this.hostForm.get('hostname').value;
145 this.checkHostNamePattern(hostname);
146 this.addr = this.hostForm.get('addr').value;
147 this.status = this.hostForm.get('maintenance').value ? 'maintenance' : '';
148 this.allLabels = this.hostForm.get('labels').value;
149 if (this.pageURL !== 'hosts' && !this.allLabels.includes('_no_schedule')) {
150 this.allLabels.push('_no_schedule');
152 this.hostnameArray.forEach((hostName: string) => {
154 .wrapTaskAroundCall({
155 task: new FinishedTask('host/' + URLVerbs.ADD, {
158 call: this.hostService.create(hostName, this.addr, this.allLabels, this.status)
162 this.hostForm.setErrors({ cdSubmitButton: true });
165 this.pageURL === 'hosts'
166 ? this.router.navigate([this.pageURL, { outlets: { modal: null } }])
167 : this.activeModal.close();