]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/host-form/host-form.component.ts
bump version to 18.2.2-pve1
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / cluster / hosts / host-form / host-form.component.ts
1 import { Component, OnInit } from '@angular/core';
2 import { UntypedFormControl, Validators } from '@angular/forms';
3 import { Router } from '@angular/router';
4
5 import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
6 import expand from 'brace-expansion';
7
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 { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context';
16 import { FinishedTask } from '~/app/shared/models/finished-task';
17 import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
18
19 @Component({
20 selector: 'cd-host-form',
21 templateUrl: './host-form.component.html',
22 styleUrls: ['./host-form.component.scss']
23 })
24 export class HostFormComponent extends CdForm implements OnInit {
25 hostForm: CdFormGroup;
26 action: string;
27 resource: string;
28 hostnames: string[];
29 hostnameArray: string[] = [];
30 addr: string;
31 status: string;
32 allLabels: string[];
33 pageURL: string;
34 hostPattern = false;
35 labelsOption: Array<SelectOption> = [];
36 hideMaintenance: boolean;
37
38 messages = new SelectMessages({
39 empty: $localize`There are no labels.`,
40 filter: $localize`Filter or add labels`,
41 add: $localize`Add label`
42 });
43
44 constructor(
45 private router: Router,
46 private actionLabels: ActionLabelsI18n,
47 private hostService: HostService,
48 private taskWrapper: TaskWrapperService,
49 public activeModal: NgbActiveModal
50 ) {
51 super();
52 this.resource = $localize`host`;
53 this.action = this.actionLabels.ADD;
54 }
55
56 ngOnInit() {
57 if (this.router.url.includes('hosts')) {
58 this.pageURL = 'hosts';
59 }
60 this.createForm();
61 const hostContext = new CdTableFetchDataContext(() => undefined);
62 this.hostService.list(hostContext.toParams(), 'false').subscribe((resp: any[]) => {
63 this.hostnames = resp.map((host) => {
64 return host['hostname'];
65 });
66 this.loadingReady();
67 });
68
69 this.hostService.getLabels().subscribe((resp: string[]) => {
70 const uniqueLabels = new Set(resp.concat(this.hostService.predefinedLabels));
71 this.labelsOption = Array.from(uniqueLabels).map((label) => {
72 return { enabled: true, name: label, selected: false, description: null };
73 });
74 });
75 }
76
77 // check if hostname is a single value or pattern to hide network address field
78 checkHostNameValue() {
79 const hostNames = this.hostForm.get('hostname').value;
80 hostNames.match(/[()\[\]{},]/g) ? (this.hostPattern = true) : (this.hostPattern = false);
81 }
82
83 private createForm() {
84 this.hostForm = new CdFormGroup({
85 hostname: new UntypedFormControl('', {
86 validators: [
87 Validators.required,
88 CdValidators.custom('uniqueName', (hostname: string) => {
89 return this.hostnames && this.hostnames.indexOf(hostname) !== -1;
90 })
91 ]
92 }),
93 addr: new UntypedFormControl('', {
94 validators: [CdValidators.ip()]
95 }),
96 labels: new UntypedFormControl([]),
97 maintenance: new UntypedFormControl(false)
98 });
99 }
100
101 private isCommaSeparatedPattern(hostname: string) {
102 // eg. ceph-node-01.cephlab.com,ceph-node-02.cephlab.com
103 return hostname.includes(',');
104 }
105
106 private isRangeTypePattern(hostname: string) {
107 // check if it is a range expression or comma separated range expression
108 // eg. ceph-mon-[01-05].lab.com,ceph-osd-[02-08].lab.com,ceph-rgw-[01-09]
109 return hostname.includes('[') && hostname.includes(']') && !hostname.match(/(?![^(]*\)),/g);
110 }
111
112 private replaceBraces(hostname: string) {
113 // pattern to replace range [0-5] to [0..5](valid expression for brace expansion)
114 // replace any kind of brackets with curly braces
115 return hostname
116 .replace(/(\d)\s*-\s*(\d)/g, '$1..$2')
117 .replace(/\(/g, '{')
118 .replace(/\)/g, '}')
119 .replace(/\[/g, '{')
120 .replace(/]/g, '}');
121 }
122
123 // expand hostnames in case hostname is a pattern
124 private checkHostNamePattern(hostname: string) {
125 if (this.isRangeTypePattern(hostname)) {
126 const hostnameRange = this.replaceBraces(hostname);
127 this.hostnameArray = expand(hostnameRange);
128 } else if (this.isCommaSeparatedPattern(hostname)) {
129 let hostArray = [];
130 hostArray = hostname.split(',');
131 hostArray.forEach((host: string) => {
132 if (this.isRangeTypePattern(host)) {
133 const hostnameRange = this.replaceBraces(host);
134 this.hostnameArray = this.hostnameArray.concat(expand(hostnameRange));
135 } else {
136 this.hostnameArray.push(host);
137 }
138 });
139 } else {
140 // single hostname
141 this.hostnameArray.push(hostname);
142 }
143 }
144
145 submit() {
146 const hostname = this.hostForm.get('hostname').value;
147 this.checkHostNamePattern(hostname);
148 this.addr = this.hostForm.get('addr').value;
149 this.status = this.hostForm.get('maintenance').value ? 'maintenance' : '';
150 this.allLabels = this.hostForm.get('labels').value;
151 if (this.pageURL !== 'hosts' && !this.allLabels.includes('_no_schedule')) {
152 this.allLabels.push('_no_schedule');
153 }
154 this.hostnameArray.forEach((hostName: string) => {
155 this.taskWrapper
156 .wrapTaskAroundCall({
157 task: new FinishedTask('host/' + URLVerbs.ADD, {
158 hostname: hostName
159 }),
160 call: this.hostService.create(hostName, this.addr, this.allLabels, this.status)
161 })
162 .subscribe({
163 error: () => {
164 this.hostForm.setErrors({ cdSubmitButton: true });
165 },
166 complete: () => {
167 this.pageURL === 'hosts'
168 ? this.router.navigate([this.pageURL, { outlets: { modal: null } }])
169 : this.activeModal.close();
170 }
171 });
172 });
173 }
174 }