]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/ceph/CephInstallWizard.js
ui: make remaining content views not stateful
[pve-manager.git] / www / manager6 / ceph / CephInstallWizard.js
CommitLineData
37e75d86
TL
1Ext.define('PVE.ceph.CephInstallWizardInfo', {
2 extend: 'Ext.panel.Panel',
3 xtype: 'pveCephInstallWizardInfo',
4
5 html: `<h3>Ceph?</h3>
6 <blockquote cite="https://ceph.com/"><p>"<b>Ceph</b> is a unified,
7 distributed storage system designed for excellent performance, reliability
8 and scalability."</p></blockquote>
9 <p>
10 <b>Ceph</b> is currently <b>not installed</b> on this node, click on the
11 next button below to start the installation. This wizard will guide you
12 through the necessary steps, after the initial installation you will be
13 offered to create an initial configuration. The configuration step is only
14 needed once per cluster and will be skipped if a config is already present.
15 </p>
16 <p>
17 Please take a look at our documentation, by clicking the help button below,
18 before starting the installation, if you want to gain deeper knowledge about
19 Ceph visit <a target="_blank" href="http://docs.ceph.com/docs/master/">ceph.com</a>.
20 </p>`,
21});
22
c3035c01
TL
23Ext.define('PVE.ceph.CephVersionSelector', {
24 extend: 'Ext.form.field.ComboBox',
25 xtype: 'pveCephVersionSelector',
26
27 fieldLabel: gettext('Ceph version to install'),
28
29 displayField: 'display',
30 valueField: 'release',
31
32 queryMode: 'local',
33 editable: false,
34 forceSelection: true,
35
36 store: {
37 fields: [
38 'release',
39 'version',
40 {
41 name: 'display',
42 calculate: d => `${d.release} (${d.version})`,
43 },
44 ],
45 proxy: {
46 type: 'memory',
47 reader: {
48 type: 'json',
49 },
50 },
51 data: [
52 {release: "nautilus", version: "14.2"},
53 {release: "octopus", version: "15.2"},
54 //{release: "pacific", version: "16.1"},
55 ],
56 },
57});
58
59Ext.define('PVE.ceph.CephHighestVersionDisplay', {
60 extend: 'Ext.form.field.Display',
61 xtype: 'pveCephHighestVersionDisplay',
62
63 fieldLabel: gettext('Ceph in the cluster'),
64
65 value: 'unknown',
66
67 // called on success with (release, versionTxt, versionParts)
68 gotNewestVersion: Ext.emptyFn,
69
70 initComponent: function() {
71 let me = this;
72
73 me.callParent(arguments);
74
75 Proxmox.Utils.API2Request({
76 method: 'GET',
77 url: '/cluster/ceph/metadata',
78 params: {
79 scope: 'versions',
80 },
81 waitMsgTarget: me,
82 success: (response) => {
83 let res = response.result;
84 if (!res || !res.data || !res.data.node) {
85 me.setValue(
86 gettext('Could not detect a ceph installation in the cluster'),
87 );
88 return;
89 }
90 let nodes = res.data.node;
91 if (me.nodename) {
92 // can happen on ceph purge, we do not yet cleanup old version data
93 delete nodes[me.nodename];
94 }
95
96 let maxversion = [];
97 let maxversiontext = "";
98 for (const [nodename, data] of Object.entries(nodes)) {
99 let version = data.version.parts;
100 if (PVE.Utils.compare_ceph_versions(version, maxversion) > 0) {
101 maxversion = version;
102 maxversiontext = data.version.str;
103 }
104 }
105 // FIXME: get from version selector store
106 const major2release = {
107 13: 'luminous',
108 14: 'nautilus',
109 15: 'octopus',
110 16: 'pacific',
111 };
112 let release = major2release[maxversion[0]] || 'unknown';
113 let newestVersionTxt = `${Ext.String.capitalize(release)} (${maxversiontext})`;
114
115 if (release === 'unknown') {
116 me.setValue(
117 gettext('Could not detect a ceph installation in the cluster'),
118 );
119 } else {
120 me.setValue(Ext.String.format(
121 gettext('Newest ceph version in cluster is {0}'),
122 newestVersionTxt,
123 ));
124 }
125 me.gotNewestVersion(release, maxversiontext, maxversion);
126 },
127 failure: function(response, opts) {
128 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
129 }
130 });
131 },
132});
133
4616a55b
TM
134Ext.define('PVE.ceph.CephInstallWizard', {
135 extend: 'PVE.window.Wizard',
136 alias: 'widget.pveCephInstallWizard',
137 mixins: ['Proxmox.Mixin.CBind'],
37e75d86 138
4616a55b
TM
139 resizable: false,
140 nodename: undefined,
37e75d86 141
4616a55b
TM
142 viewModel: {
143 data: {
8ba2d669 144 nodename: '',
c3035c01 145 cephRelease: 'octopus',
f992ef80 146 configuration: true,
37e75d86 147 isInstalled: false,
4616a55b
TM
148 }
149 },
150 cbindData: {
151 nodename: undefined
152 },
37e75d86 153
f992ef80 154 title: gettext('Setup'),
8ba2d669
TM
155 navigateNext: function() {
156 var tp = this.down('#wizcontent');
157 var atab = tp.getActiveTab();
158
159 var next = tp.items.indexOf(atab) + 1;
160 var ntab = tp.items.getAt(next);
161 if (ntab) {
162 ntab.enable();
163 tp.setActiveTab(ntab);
164 }
165 },
4e36fbab
TM
166 setInitialTab: function (index) {
167 var tp = this.down('#wizcontent');
168 var initialTab = tp.items.getAt(index);
169 initialTab.enable();
170 tp.setActiveTab(initialTab);
171 },
172 onShow: function() {
173 this.callParent(arguments);
174 var isInstalled = this.getViewModel().get('isInstalled');
175 if (isInstalled) {
176 this.getViewModel().set('configuration', false);
177 this.setInitialTab(2);
178 }
179 },
4616a55b
TM
180 items: [
181 {
4616a55b 182 xtype: 'panel',
37e75d86 183 title: gettext('Info'),
c3035c01 184 viewModel: {}, // needed to inherit parent viewModel data
4616a55b
TM
185 border: false,
186 bodyBorder: false,
187 onlineHelp: 'chapter_pveceph',
37e75d86
TL
188 layout: {
189 type: 'vbox',
190 align: 'stretch',
191 },
192 defaults: {
193 border: false,
194 bodyBorder: false,
195 },
196 items: [
197 {
198 xtype: 'pveCephInstallWizardInfo',
199 },
c3035c01
TL
200 {
201 flex: 1,
202 },
203 {
204 xtype: 'pveCephHighestVersionDisplay',
205 labelWidth: 180,
206 cbind:{
207 nodename: '{nodename}'
208 },
209 gotNewestVersion: function(release, maxversiontext, maxversion) {
210 if (release === 'unknown') {
211 return;
212 }
213 let wizard = this.up('pveCephInstallWizard');
214 wizard.getViewModel().set('cephRelease', release);
215 },
216 },
217 {
218 xtype: 'pveCephVersionSelector',
219 labelWidth: 180,
220 submitValue: false,
221 bind: {
222 value: '{cephRelease}',
223 },
224 listeners: {
225 change: function(field, release) {
226 let wizard = this.up('pveCephInstallWizard');
227 wizard.down('#next').setText(
228 Ext.String.format(gettext('Start {0} installation'), release),
229 );
230 },
231 },
232 },
37e75d86 233 ],
4616a55b
TM
234 listeners: {
235 activate: function() {
236 // notify owning container that it should display a help button
237 if (this.onlineHelp) {
238 Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
239 }
c3035c01
TL
240 let wizard = this.up('pveCephInstallWizard');
241 let release = wizard.getViewModel().get('cephRelease');
242 wizard.down('#back').hide(true);
243 wizard.down('#next').setText(
244 Ext.String.format(gettext('Start {0} installation'), release),
245 );
4616a55b
TM
246 },
247 deactivate: function() {
248 if (this.onlineHelp) {
249 Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
250 }
fc360d85 251 this.up('pveCephInstallWizard').down('#next').setText(gettext('Next'));
4616a55b
TM
252 }
253 }
254 },
255 {
256 title: gettext('Installation'),
257 xtype: 'panel',
258 layout: 'fit',
259 cbind:{
260 nodename: '{nodename}'
261 },
f992ef80 262 viewModel: {}, // needed to inherit parent viewModel data
4616a55b
TM
263 listeners: {
264 afterrender: function() {
265 var me = this;
f992ef80
TM
266 if (this.getViewModel().get('isInstalled')) {
267 this.mask("Ceph is already installed, click next to create your configuration.",['pve-static-mask']);
268 } else {
269 me.down('pveNoVncConsole').fireEvent('activate');
270 }
4616a55b
TM
271 },
272 activate: function() {
c3035c01
TL
273 let me = this;
274 const nodename = me.nodename;
4616a55b
TM
275 me.updateStore = Ext.create('Proxmox.data.UpdateStore', {
276 storeid: 'ceph-status-' + nodename,
277 interval: 1000,
278 proxy: {
279 type: 'proxmox',
280 url: '/api2/json/nodes/' + nodename + '/ceph/status'
281 },
282 listeners: {
283 load: function(rec, response, success, operation) {
8ba2d669 284
4616a55b
TM
285 if (success) {
286 me.updateStore.stopUpdate();
8ba2d669 287 me.down('textfield').setValue('success');
4616a55b
TM
288 } else if (operation.error.statusText.match("not initialized", "i")) {
289 me.updateStore.stopUpdate();
8ba2d669 290 me.up('pveCephInstallWizard').getViewModel().set('configuration',false);
4616a55b
TM
291 me.down('textfield').setValue('success');
292 } else if (operation.error.statusText.match("rados_connect failed", "i")) {
293 me.updateStore.stopUpdate();
8ba2d669
TM
294 me.up('pveCephInstallWizard').getViewModel().set('configuration',true);
295 me.down('textfield').setValue('success');
4616a55b
TM
296 } else if (!operation.error.statusText.match("not installed", "i")) {
297 Proxmox.Utils.setErrorMask(me, operation.error.statusText);
298 }
299 }
300 }
301 });
302 me.updateStore.startUpdate();
303 },
304 destroy: function() {
305 var me = this;
306 if (me.updateStore) {
307 me.updateStore.stopUpdate();
308 }
309 }
310 },
311 items: [
312 {
c3035c01 313 xtype: 'pveNoVncConsole',
4616a55b
TM
314 itemId: 'jsconsole',
315 consoleType: 'cmd',
316 xtermjs: true,
c3035c01
TL
317 cbind: {
318 nodename: '{nodename}',
319 },
320 beforeLoad: function() {
321 let me = this;
322 let wizard = me.up('pveCephInstallWizard');
323 let release = wizard.getViewModel().get('cephRelease');
324 me.cmdOpts = `--version\0${release}`;
4616a55b 325 },
c3035c01 326 cmd: 'ceph_install',
4616a55b
TM
327 },
328 {
329 xtype: 'textfield',
330 name: 'installSuccess',
331 value: '',
332 allowBlank: false,
333 submitValue: false,
334 hidden: true
335 }
336 ]
337 },
338 {
339 xtype: 'inputpanel',
340 title: gettext('Configuration'),
341 onlineHelp: 'chapter_pveceph',
342 cbind: {
343 nodename: '{nodename}'
344 },
836d66f7
TM
345 viewModel: {
346 data: {
347 replicas: undefined,
348 minreplicas: undefined
349 }
350 },
4616a55b
TM
351 listeners: {
352 activate: function() {
353 this.up('pveCephInstallWizard').down('#submit').setText(gettext('Next'));
354 },
8ba2d669
TM
355 beforeshow: function() {
356 if (this.up('pveCephInstallWizard').getViewModel().get('configuration')) {
4ed5c138 357 this.mask("Configuration already initialized",['pve-static-mask']);
8ba2d669
TM
358 } else {
359 this.unmask();
360 }
361 },
4616a55b
TM
362 deactivate: function() {
363 this.up('pveCephInstallWizard').down('#submit').setText(gettext('Finish'));
364 }
365 },
366 column1: [
8ba2d669 367 {
218c9be5
TL
368 xtype: 'displayfield',
369 value: gettext('Ceph cluster configuration') + ':'
4616a55b
TM
370 },
371 {
6c7b8e23 372 xtype: 'proxmoxNetworkSelector',
4616a55b 373 name: 'network',
4616a55b 374 value: '',
2248c6c8 375 fieldLabel: 'Public Network IP/CIDR',
8ba2d669
TM
376 bind: {
377 allowBlank: '{configuration}'
a19aa238
ML
378 },
379 cbind: {
380 nodename: '{nodename}'
8ba2d669 381 }
4616a55b
TM
382 },
383 {
6c7b8e23 384 xtype: 'proxmoxNetworkSelector',
4616a55b 385 name: 'cluster-network',
2248c6c8 386 fieldLabel: 'Cluster Network IP/CIDR',
4616a55b 387 allowBlank: true,
6c7b8e23 388 autoSelect: false,
a19aa238
ML
389 emptyText: gettext('Same as Public Network'),
390 cbind: {
391 nodename: '{nodename}'
392 }
4616a55b 393 }
218c9be5 394 // FIXME: add hint about cluster network and/or reference user to docs??
4616a55b 395 ],
8ba2d669
TM
396 column2: [
397 {
218c9be5
TL
398 xtype: 'displayfield',
399 value: gettext('First Ceph monitor') + ':'
8ba2d669
TM
400 },
401 {
402 xtype: 'pveNodeSelector',
403 fieldLabel: gettext('Monitor node'),
404 name: 'mon-node',
405 selectCurNode: true,
406 allowBlank: false
71798b4b
TL
407 },
408 {
409 xtype: 'displayfield',
410 value: gettext('Additional monitors are recommended. They can be created at any time in the Monitor tab.'),
f71b7c28 411 userCls: 'pmx-hint'
8ba2d669
TM
412 }
413 ],
4616a55b
TM
414 advancedColumn1: [
415 {
416 xtype: 'numberfield',
417 name: 'size',
0b985d6f 418 fieldLabel: 'Number of replicas',
836d66f7 419 bind: {
8134b6b7 420 value: '{replicas}'
836d66f7 421 },
4616a55b 422 maxValue: 7,
8134b6b7
TL
423 minValue: 2,
424 emptyText: '3'
4616a55b
TM
425 },
426 {
427 xtype: 'numberfield',
428 name: 'min_size',
0b985d6f 429 fieldLabel: 'Minimum replicas',
836d66f7
TM
430 bind: {
431 maxValue: '{replicas}',
8134b6b7 432 value: '{minreplicas}'
836d66f7 433 },
8134b6b7
TL
434 minValue: 2,
435 maxValue: 3,
436 setMaxValue: function(value) {
437 this.maxValue = Ext.Number.from(value, 2);
438 // allow enough to avoid split brains with max 'size', but more makes simply no sense
439 if (this.maxValue > 4) {
440 this.maxValue = 4;
441 }
442 this.toggleSpinners();
836d66f7 443 this.validate();
8134b6b7
TL
444 },
445 emptyText: '2'
4616a55b
TM
446 }
447 ],
448 onGetValues: function(values) {
bf996912 449 ['cluster-network', 'size', 'min_size'].forEach(function(field) {
4616a55b
TM
450 if (!values[field]) {
451 delete values[field];
452 }
453 });
454 return values;
455 },
456 onSubmit: function() {
457 var me = this;
8ba2d669
TM
458 if (!this.up('pveCephInstallWizard').getViewModel().get('configuration')) {
459 var wizard = me.up('window');
460 var kv = wizard.getValues();
461 delete kv['delete'];
462 var monNode = kv['mon-node'];
463 delete kv['mon-node'];
464 var nodename = me.nodename;
465 delete kv.nodename;
466 Proxmox.Utils.API2Request({
467 url: '/nodes/' + nodename + '/ceph/init',
468 waitMsgTarget: wizard,
469 method: 'POST',
470 params: kv,
471 success: function() {
472 Proxmox.Utils.API2Request({
ca62eebd 473 url: '/nodes/' + monNode + '/ceph/mon/' + monNode,
8ba2d669
TM
474 waitMsgTarget: wizard,
475 method: 'POST',
476 success: function() {
477 me.up('pveCephInstallWizard').navigateNext();
478 },
479 failure: function(response, opts) {
480 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
481 }
482 });
483 },
484 failure: function(response, opts) {
485 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
4616a55b 486 }
8ba2d669
TM
487 });
488
489 } else {
490 me.up('pveCephInstallWizard').navigateNext();
491 }
4616a55b
TM
492 }
493 },
494 {
495 title: gettext('Success'),
496 xtype: 'panel',
497 border: false,
498 bodyBorder: false,
499 onlineHelp: 'pve_ceph_install',
500 html: '<h3>Installation successful!</h3>'+
501 '<p>The basic installation and configuration is completed, depending on your setup some of the following steps are required to start using Ceph:</p>'+
4711d998 502 '<ol><li>Install Ceph on other nodes</li>'+
fc29d138
WL
503 '<li>Create additional Ceph Monitors</li>'+
504 '<li>Create Ceph OSDs</li>'+
505 '<li>Create Ceph Pools</li></ol>'+
4616a55b
TM
506 '<p>To learn more click on the help button below.</p>',
507 listeners: {
508 activate: function() {
509 // notify owning container that it should display a help button
510 if (this.onlineHelp) {
511 Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
512 }
513
514 var tp = this.up('#wizcontent');
515 var idx = tp.items.indexOf(this)-1;
516 for(;idx >= 0;idx--) {
517 var nc = tp.items.getAt(idx);
518 if (nc) {
519 nc.disable();
520 }
521 }
522 },
523 deactivate: function() {
524 if (this.onlineHelp) {
525 Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
526 }
527 }
528 },
529 onSubmit: function() {
530 var wizard = this.up('pveCephInstallWizard');
531 wizard.close();
532 }
533 }
534 ]
c3035c01 535});