]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/dc/ClusterEdit.js
drop jslint lines
[pve-manager.git] / www / manager6 / dc / ClusterEdit.js
1 Ext.define('PVE.ClusterCreateWindow', {
2 extend: 'Proxmox.window.Edit',
3 xtype: 'pveClusterCreateWindow',
4
5 title: gettext('Create Cluster'),
6 width: 600,
7
8 method: 'POST',
9 url: '/cluster/config',
10
11 isCreate: true,
12 subject: gettext('Cluster'),
13 showTaskViewer: true,
14
15 onlineHelp: 'pvecm_create_cluster',
16
17 items: {
18 xtype: 'inputpanel',
19 items: [{
20 xtype: 'textfield',
21 fieldLabel: gettext('Cluster Name'),
22 allowBlank: false,
23 maxLength: 15,
24 name: 'clustername'
25 },
26 {
27 xtype: 'fieldcontainer',
28 fieldLabel: gettext("Cluster Network"),
29 items: [
30 {
31 xtype: 'pveCorosyncLinkEditor',
32 infoText: gettext("Multiple links are used as failover, lower numbers have higher priority."),
33 name: 'links'
34 },
35 ]
36 }]
37 }
38 });
39
40 Ext.define('PVE.ClusterInfoWindow', {
41 extend: 'Ext.window.Window',
42 xtype: 'pveClusterInfoWindow',
43 mixins: ['Proxmox.Mixin.CBind'],
44
45 width: 800,
46 modal: true,
47 resizable: false,
48 title: gettext('Cluster Join Information'),
49
50 joinInfo: {
51 ipAddress: undefined,
52 fingerprint: undefined,
53 totem: {}
54 },
55
56 items: [
57 {
58 xtype: 'component',
59 border: false,
60 padding: '10 10 10 10',
61 html: gettext("Copy the Join Information here and use it on the node you want to add.")
62 },
63 {
64 xtype: 'container',
65 layout: 'form',
66 border: false,
67 padding: '0 10 10 10',
68 items: [
69 {
70 xtype: 'textfield',
71 fieldLabel: gettext('IP Address'),
72 cbind: {
73 value: '{joinInfo.ipAddress}',
74 },
75 editable: false,
76 },
77 {
78 xtype: 'textfield',
79 fieldLabel: gettext('Fingerprint'),
80 cbind: {
81 value: '{joinInfo.fingerprint}',
82 },
83 editable: false,
84 },
85 {
86 xtype: 'textarea',
87 inputId: 'pveSerializedClusterInfo',
88 fieldLabel: gettext('Join Information'),
89 grow: true,
90 cbind: {
91 joinInfo: '{joinInfo}',
92 },
93 editable: false,
94 listeners: {
95 afterrender: function(field) {
96 if (!field.joinInfo) {
97 return;
98 }
99 var jsons = Ext.JSON.encode(field.joinInfo);
100 var base64s = Ext.util.Base64.encode(jsons);
101 field.setValue(base64s);
102 }
103 }
104 }
105 ]
106 }
107 ],
108 dockedItems: [{
109 dock: 'bottom',
110 xtype: 'toolbar',
111 items: [{
112 xtype: 'button',
113 handler: function(b) {
114 var el = document.getElementById('pveSerializedClusterInfo');
115 el.select();
116 document.execCommand("copy");
117 },
118 text: gettext('Copy Information')
119 }]
120 }]
121 });
122
123 Ext.define('PVE.ClusterJoinNodeWindow', {
124 extend: 'Proxmox.window.Edit',
125 xtype: 'pveClusterJoinNodeWindow',
126
127 title: gettext('Cluster Join'),
128 width: 800,
129
130 method: 'POST',
131 url: '/cluster/config/join',
132
133 defaultFocus: 'textarea[name=serializedinfo]',
134 isCreate: true,
135 bind: {
136 submitText: '{submittxt}',
137 },
138 showTaskViewer: true,
139
140 onlineHelp: 'pvecm_join_node_to_cluster',
141
142 viewModel: {
143 parent: null,
144 data: {
145 info: {
146 fp: '',
147 ip: '',
148 clusterName: ''
149 },
150 hasAssistedInfo: false,
151 },
152 formulas: {
153 submittxt: function(get) {
154 let cn = get('info.clusterName');
155 if (cn) {
156 return Ext.String.format(gettext('Join {0}'), `'${cn}'`);
157 }
158 return gettext('Join');
159 },
160 showClusterFields: (get) => {
161 let manualMode = !get('assistedEntry.checked');
162 return get('hasAssistedInfo') || manualMode;
163 },
164 },
165 },
166
167 controller: {
168 xclass: 'Ext.app.ViewController',
169 control: {
170 '#': {
171 close: function() {
172 delete PVE.Utils.silenceAuthFailures;
173 }
174 },
175 'proxmoxcheckbox[name=assistedEntry]': {
176 change: 'onInputTypeChange'
177 },
178 'textarea[name=serializedinfo]': {
179 change: 'recomputeSerializedInfo',
180 enable: 'resetField'
181 },
182 'textfield': {
183 disable: 'resetField'
184 }
185 },
186 resetField: function(field) {
187 field.reset();
188 },
189 onInputTypeChange: function(field, assistedInput) {
190 let linkEditor = this.lookup('linkEditor');
191
192 // this also clears all links
193 linkEditor.setAllowNumberEdit(!assistedInput);
194
195 if (!assistedInput) {
196 linkEditor.setInfoText();
197 linkEditor.setDefaultLinks();
198 }
199 },
200 recomputeSerializedInfo: function(field, value) {
201 let vm = this.getViewModel();
202
203 let assistedEntryBox = this.lookup('assistedEntry');
204
205 if (!assistedEntryBox.getValue()) {
206 // not in assisted entry mode, nothing to do
207 vm.set('hasAssistedInfo', false);
208 return;
209 }
210
211 let linkEditor = this.lookup('linkEditor');
212
213 let jsons = Ext.util.Base64.decode(value);
214 let joinInfo = Ext.JSON.decode(jsons, true);
215
216 let info = {
217 fp: '',
218 ip: '',
219 clusterName: ''
220 };
221
222 if (!(joinInfo && joinInfo.totem)) {
223 field.valid = false;
224 linkEditor.setLinks([]);
225 linkEditor.setInfoText();
226 vm.set('hasAssistedInfo', false);
227 } else {
228 let interfaces = joinInfo.totem.interface;
229 let links = Object.values(interfaces).map(iface => {
230 let linkNumber = iface.linknumber;
231 let peerLink;
232 if (joinInfo.peerLinks) {
233 peerLink = joinInfo.peerLinks[linkNumber];
234 }
235 return {
236 number: linkNumber,
237 value: '',
238 text: peerLink ? Ext.String.format(gettext("peer's link address: {0}"), peerLink) : '',
239 allowBlank: false
240 };
241 });
242
243 linkEditor.setInfoText();
244 if (links.length == 1 && joinInfo.ring_addr !== undefined &&
245 joinInfo.ring_addr[0] === joinInfo.ipAddress) {
246
247 links[0].allowBlank = true;
248 links[0].emptyText = gettext("IP resolved by node's hostname");
249 }
250
251 linkEditor.setLinks(links);
252
253 info = {
254 ip: joinInfo.ipAddress,
255 fp: joinInfo.fingerprint,
256 clusterName: joinInfo.totem.cluster_name
257 };
258 field.valid = true;
259 vm.set('hasAssistedInfo', true);
260 }
261 vm.set('info', info);
262 }
263 },
264
265 submit: function() {
266 // joining may produce temporarily auth failures, ignore as long the task runs
267 PVE.Utils.silenceAuthFailures = true;
268 this.callParent();
269 },
270
271 taskDone: function(success) {
272 delete PVE.Utils.silenceAuthFailures;
273 if (success) {
274 // reload always (if user wasn't faster), but wait a bit for pveproxy
275 Ext.defer(function() {
276 window.location.reload(true);
277 }, 5000);
278 var txt = gettext('Cluster join task finished, node certificate may have changed, reload GUI!');
279 // ensure user cannot do harm
280 Ext.getBody().mask(txt, ['pve-static-mask']);
281 // TaskView may hide above mask, so tell him directly
282 Ext.Msg.show({
283 title: gettext('Join Task Finished'),
284 icon: Ext.Msg.INFO,
285 msg: txt
286 });
287 }
288 },
289
290 items: [{
291 xtype: 'proxmoxcheckbox',
292 reference: 'assistedEntry',
293 name: 'assistedEntry',
294 itemId: 'assistedEntry',
295 submitValue: false,
296 value: true,
297 autoEl: {
298 tag: 'div',
299 'data-qtip': gettext('Select if join information should be extracted from pasted cluster information, deselect for manual entering')
300 },
301 boxLabel: gettext('Assisted join: Paste encoded cluster join information and enter password.')
302 },
303 {
304 xtype: 'textarea',
305 name: 'serializedinfo',
306 submitValue: false,
307 allowBlank: false,
308 fieldLabel: gettext('Information'),
309 emptyText: gettext('Paste encoded Cluster Information here'),
310 validator: function(val) {
311 return val === '' || this.valid ||
312 gettext('Does not seem like a valid encoded Cluster Information!');
313 },
314 bind: {
315 disabled: '{!assistedEntry.checked}',
316 hidden: '{!assistedEntry.checked}'
317 },
318 value: ''
319 },
320 {
321 xtype: 'panel',
322 width: 776,
323 layout: {
324 type: 'hbox',
325 align: 'center'
326 },
327 bind: {
328 hidden: '{!showClusterFields}',
329 },
330 items: [
331 {
332 xtype: 'textfield',
333 flex: 1,
334 margin: '0 5px 0 0',
335 fieldLabel: gettext('Peer Address'),
336 allowBlank: false,
337 bind: {
338 value: '{info.ip}',
339 readOnly: '{assistedEntry.checked}',
340 },
341 name: 'hostname'
342 },
343 {
344 xtype: 'textfield',
345 flex: 1,
346 margin: '0 0 10px 5px',
347 inputType: 'password',
348 emptyText: gettext("Peer's root password"),
349 fieldLabel: gettext('Password'),
350 allowBlank: false,
351 name: 'password'
352 },
353 ]
354 },
355 {
356 xtype: 'textfield',
357 fieldLabel: gettext('Fingerprint'),
358 allowBlank: false,
359 bind: {
360 value: '{info.fp}',
361 readOnly: '{assistedEntry.checked}',
362 hidden: '{!showClusterFields}',
363 },
364 name: 'fingerprint'
365 },
366 {
367 xtype: 'fieldcontainer',
368 fieldLabel: gettext("Cluster Network"),
369 bind: {
370 hidden: '{!showClusterFields}',
371 },
372 items: [
373 {
374 xtype: 'pveCorosyncLinkEditor',
375 itemId: 'linkEditor',
376 reference: 'linkEditor',
377 allowNumberEdit: false
378 },
379 ]
380 }]
381 });