[pve-devel] [PATCH v6 manager 6/6] added basic ability to install ceph via gui

Tim Marx t.marx at proxmox.com
Mon Mar 4 11:58:58 CET 2019


Just for the records, I recap here what we already discussed off list.
> Dominik Csapak <d.csapak at proxmox.com> hat am 28. Februar 2019 um 11:46 geschrieben:
> 
> 
> high level comments:
> 
> closing the wizard right after opening it, produces an error in the 
> console (stopUpdate on undefined, or something similar)
> 

I will fix this, its due to the on destroy of the second tab and not checking if a store even exists already.

> after initializing i get the error: rados_connect failed - No such file 
> or directory (500)
> 
> maybe a 'mon create' in the wizard could also be done? (optionally)

I will sum up the next steps to do in the last tab, including a hint to our docs. As there is already an option to install the mon via gui I don't think that this is really necessary, but I do agree that it would be nice to have.

> 
> also when installing, the next button got activated early, but
> i did not click on it, is there any better way to detect
> when it is finished?
> 

If there is a better way to check if the installation is finished, I would rework it, for now I use the APIs check_ceph_inited method and this checks for the mon binary.

> also when we already have ceph installed from the beginning, does it
> make sense to show the install tab at all?
> 

I think it does no harm and as it is called a installation wizard it do make sense for me to show it.

> some more comments inline
> 
> On 2/27/19 3:01 PM, Tim Marx wrote:
> > Signed-off-by: Tim Marx <t.marx at proxmox.com>
> > ---
> >   www/css/ext6-pve.css                   |   5 +
> >   www/manager6/Makefile                  |   3 +
> >   www/manager6/Utils.js                  |  31 ++++
> >   www/manager6/ceph/CephInstallWizard.js | 259 +++++++++++++++++++++++++++++++++
> >   www/manager6/ceph/Config.js            |  16 ++
> >   www/manager6/ceph/Crush.js             |  16 ++
> >   www/manager6/ceph/FS.js                |  42 +++++-
> >   www/manager6/ceph/Log.js               |  70 +++++++++
> >   www/manager6/ceph/Monitor.js           |  19 ++-
> >   www/manager6/ceph/OSD.js               |  19 ++-
> >   www/manager6/ceph/Pool.js              |  18 ++-
> >   www/manager6/ceph/Status.js            |  21 ++-
> >   www/manager6/node/Config.js            |   5 +-
> >   www/manager6/window/CephInstall.js     |  66 +++++++++
> >   14 files changed, 582 insertions(+), 8 deletions(-)
> >   create mode 100644 www/manager6/ceph/CephInstallWizard.js
> >   create mode 100644 www/manager6/ceph/Log.js
> >   create mode 100644 www/manager6/window/CephInstall.js
> > 
> > diff --git a/www/css/ext6-pve.css b/www/css/ext6-pve.css
> > index 174511ac..7ac35603 100644
> > --- a/www/css/ext6-pve.css
> > +++ b/www/css/ext6-pve.css
> > @@ -582,3 +582,8 @@ table.osds td:first-of-type {
> >       right: 0px;
> >       background-color: #555;
> >   }
> > +
> > +.install-mask {
> > +    background-color: rgb(245, 245, 245);
> > +    color: #000;
> > +}
> > \ No newline at end of file
> > diff --git a/www/manager6/Makefile b/www/manager6/Makefile
> > index e75f0de6..db5ced2d 100644
> > --- a/www/manager6/Makefile
> > +++ b/www/manager6/Makefile
> > @@ -83,6 +83,7 @@ JSSRC= 				                 	\
> >   	window/BackupConfig.js				\
> >   	window/Settings.js				\
> >   	window/StartupEdit.js				\
> > +	window/CephInstall.js				\
> >   	panel/NotesView.js				\
> >   	grid/ResourceGrid.js				\
> >   	grid/PoolMembers.js				\
> > @@ -101,6 +102,8 @@ JSSRC= 				                 	\
> >   	ceph/Status.js					\
> >   	ceph/StatusDetail.js				\
> >   	ceph/Config.js					\
> > +	ceph/Log.js					\
> > +	ceph/CephInstallWizard.js				\
> >   	node/Disks.js					\
> >   	node/LVM.js					\
> >   	node/LVMThin.js					\
> > diff --git a/www/manager6/Utils.js b/www/manager6/Utils.js
> > index b9fa25b7..83ff8a3e 100644
> > --- a/www/manager6/Utils.js
> > +++ b/www/manager6/Utils.js
> > @@ -1091,6 +1091,37 @@ Ext.define('PVE.Utils', { utilities: {
> >   		return;
> >   	    }
> >   	}
> > +    },
> > +
> > +    handleStoreErrorOrMask: function(me, store, regex, callback) {
> > +
> > +	if (!(store.proxy instanceof Proxmox.RestProxy)) {
> > +	    throw "Proxy must implement afterload event!";
> > +	}
> > +
> > +	me.mon(store.proxy, 'afterload', function (proxy, request, success) {
> > +
> > +	    if (success) {
> > +		Proxmox.Utils.setErrorMask(me, false);
> > +		return;
> > +	    }
> > +	    var msg;
> > +	    /*jslint nomen: true */
> > +	    var operation = request._operation;
> > +	    var error = operation.getError();
> > +
> > +	    if (error.statusText) {
> > +		if (error.statusText.match(regex)) {
> > +		    callback(me, error);
> > +		    return;
> > +		} else {
> > +		    msg = error.statusText + ' (' + error.status + ')';
> > +		}
> > +	    } else {
> > +		msg = gettext('Connection error');
> > +	    }
> > +	    Proxmox.Utils.setErrorMask(me, msg);
> > +	});
> >       }
> 
> like discussed off-list, i think it would be better to use the
> stores 'load' event, since we get the operation object directly
> as parameter (saves us the access of private properties and the jslint 
> override)

I will change it.

> 
> >   },
> >   
> > diff --git a/www/manager6/ceph/CephInstallWizard.js b/www/manager6/ceph/CephInstallWizard.js
> > new file mode 100644
> > index 00000000..a6789a88
> > --- /dev/null
> > +++ b/www/manager6/ceph/CephInstallWizard.js
> > @@ -0,0 +1,259 @@
> > +Ext.define('PVE.ceph.CephInstallWizard', {
> > +	extend: 'PVE.window.Wizard',
> > +	alias: 'widget.pveCephInstallWizard',
> > +	mixins: ['Proxmox.Mixin.CBind'],
> > +	resizable: false,
> > +	nodename: undefined,
> > +	viewModel: {
> > +	    data: {
> > +		nodename: ''
> > +	    }
> > +	},
> > +	cbindData: {
> > +	    nodename: undefined
> > +	},
> > +	title: gettext('Installation'),
> > +	items: [
> > +	    {
> > +		title: gettext('Info'),
> > +		xtype: 'panel',
> > +		border: false,
> > +		bodyBorder: false,
> > +		onlineHelp: 'chapter_pveceph',
> > +		html: '<h3>Ceph?</h3>'+
> > +		'<blockquote cite="https://ceph.com/"><p>"<b>Ceph</b> is a unified, distributed storage system designed for excellent performance, reliability and scalability."</p></blockquote>'+
> > +		'<p><b>Ceph</b> is currently <b>not installed</b> on this node, click on the next button below to start the installation.'+
> > +		' This wizard will guide you through the nessecery steps, after the inital installation you will be offered to create a inital configuration.'+
> > +		' The configuration step is only needed once per cluster and will be skipped if a config is already present.</p>'+
> > +		'<p>If you want to learn more visit <a href="http://docs.ceph.com/docs/master/">ceph.com</a> or click the help button below.</p>',
> > +		listeners: {
> > +		    activate: function() {
> > +			// notify owning container that it should display a help button
> > +			if (this.onlineHelp) {
> > +			    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
> > +			}
> > +		    },
> > +		    deactivate: function() {
> > +			if (this.onlineHelp) {
> > +			    Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
> > +			}
> > +		    }
> > +		}
> > +	    },
> > +	    {
> > +		title: gettext('Installation'),
> > +		xtype: 'panel',
> > +		layout: 'fit',
> > +		cbind:{
> > +		    nodename: '{nodename}'
> > +		},
> > +		listeners: {
> > +		    afterrender: function() {
> > +			var me = this;
> > +			me.down('pveNoVncConsole').fireEvent('activate');
> > +		    },
> > +		    activate: function() {
> > +			var me = this;
> > +			var nodename = me.nodename;
> > +			me.store = Ext.create('Proxmox.data.UpdateStore', {
> 
> i would not use the 'store' property, since extjs may use that. e.g. 
> destroy it on the destroy event (i think)
> maybe 'updateStore' just to be safe
> 

Ok

> > +				storeid: 'ceph-status-' + nodename,
> > +				interval: 1000,
> > +				proxy: {
> > +				    type: 'proxmox',
> > +				    url: '/api2/json/nodes/' + nodename + '/ceph/status',
> > +				    listeners: {
> > +					exception: function(proxy, response, options){
> > +						
> > +					    if(response.statusText.match("not initialized", "i")){
> 
> nit: space after if and between ) and {
> 
> > +						me.store.stopUpdate();
> > +						me.down('textfield').setValue('success');
> > +					    } else if (!response.statusText.match("not installed", "i")) {
> 
> are you sure this code path is correct?
> we have a failing api call but are neither in 'not initialized' nor 'not 
> installed' state... what do we do then?
> 

I could try to mask the window with the error message.

> > +						me.store.stopUpdate();
> > +						var wizard = me.up('#wizcontent');
> > +						var tabs = wizard.items;
> > +						var lastTab = tabs.items[tabs.length-1];
> > +						lastTab.enable();
> > +						wizard.setActiveTab(lastTab);
> > +					    }
> > +					}
> > +				    }
> 
> any particular reason why the use of this listener?
> wouldn't it be possible to use the load event with !success and the 
> operation argument (the 4th that you did not specify)
> 

will check that.

> > +				},
> > +				listeners: {
> > +				    load: function(rec, response, success){
> > +					if(success){
> 
> nit: spaces around ()
> 
> > +					    me.store.stopUpdate();
> > +					    var wizard = me.up('#wizcontent');
> > +					    var tabs = wizard.items;
> > +					    var lastTab = tabs.items[tabs.length-1];
> > +					    lastTab.enable();
> > +					    wizard.setActiveTab(lastTab);
> > +					}
> > +				    }
> > +				}
> > +			});
> > +			me.store.startUpdate();
> > +		    },
> > +		    destroy: function(){
> > +			var me = this;
> > +			me.store.stopUpdate();
> > +		    }
> 
> i guess we want the 'deactivate' event, not destroy? or both?
> also check if the store exists, since it does not have to (exit on first 
> panel for example)

Answered at the beginning.

> 
> > +		},
> > +		items: [
> > +		    {
> > +			itemId: 'jsconsole',
> > +			consoleType: 'cmd',
> > +			xtermjs: true,
> > +			xtype: 'pveNoVncConsole',
> > +			cbind:{
> > +			    nodename: '{nodename}'
> > +			},
> > +			cmd: 'ceph_install'
> > +		    },
> > +		    {
> > +			xtype: 'textfield',
> > +			name: 'installSuccess',
> > +			value: '',
> > +			allowBlank: false,
> > +			submitValue: false,
> > +			hidden: true	
> > +		    }
> > +		]
> > +	    },
> > +	    {
> > +		xtype: 'inputpanel',
> > +		title: gettext('Configuration'),
> > +		onlineHelp: 'chapter_pveceph',
> > +		cbind: {
> > +		    nodename: '{nodename}'
> > +		},
> > +		listeners: {
> > +		    activate: function() {
> > +			this.up('pveCephInstallWizard').down('#submit').setText(gettext('Next'));
> > +		    },
> > +		    deactivate: function() {
> > +			this.up('pveCephInstallWizard').down('#submit').setText(gettext('Finish'));
> > +		    }
> > +		},
> > +		column1: [
> > +		    {
> > +			xtype: 'displayfield',
> > +			name: 'nodename',
> > +			fieldLabel: gettext('Node'),
> > +			cbind: {
> > +			    value: '{nodename}'
> > +			},
> > +			padding: 5
> > +		    },
> > +		    {
> > +			xtype: 'textfield',
> > +			name: 'network',
> > +			vtype: 'IPCIDRAddress',
> > +			value: '',
> > +			fieldLabel: 'Network IPv4/CIDR',
> > +			allowBlank: false
> > +		    },
> > +		    {
> > +			xtype: 'textfield',
> > +			name: 'cluster-network',
> > +			vtype: 'IPCIDRAddress',
> > +			fieldLabel: 'Cluster-Network IPv4/CIDR',
> > +			allowBlank: true,
> > +			emptyText: gettext('default')
> > +		    }
> > +		],
> > +		advancedColumn1: [
> > +		    {
> > +			xtype: 'numberfield',
> > +			name: 'size',
> > +			fieldLabel: gettext('Number of replicas'),
> > +			value: '',
> > +			maxValue: 7,
> > +			minValue: 1,
> > +			allowBlank: true,
> > +			emptyText: gettext('default')
> > +		    },
> > +		    {
> > +			xtype: 'numberfield',
> > +			name: 'min_size',
> > +			fieldLabel: gettext('Minimum replicas'),
> > +			value: '',
> > +			maxValue: 7,
> > +			minValue: 1,
> > +			allowBlank: true,
> > +			emptyText: gettext('default')
> > +		    },
> > +		    {
> > +			xtype: 'numberfield',
> > +			name: 'pg_bits',
> > +			fieldLabel: 'Placement group bits',
> > +			value: '',
> > +			maxValue: 14,
> > +			minValue: 6,
> > +			allowBlank: true,
> > +			emptyText: gettext('default')
> > +		    }
> 
> i would prefer if we use the same gettexts as with the pools
> (while i like yours better, so maybe change the fieldlabels for pools? 
> can ofc be done later on)
> 
> also it is not really clear that this are the defaults we are setting,
> maybe 'Default number of replicas' ? etc.
> 

ok

> > +		],
> > +		onGetValues: function(values) {
> > +		    ['cluster-network', 'size', 'min_size', 'pg_bits'].forEach(function(field) {
> > +			if (!values[field]) {
> > +			    delete values[field];
> > +			}
> > +		    });
> > +		    return values;
> > +		},
> > +		onSubmit: function() {
> > +		    var me = this;
> > +		    var wizard = me.up('window');
> > +		    var kv = wizard.getValues();
> > +		    delete kv['delete'];
> > +		    var nodename = me.nodename;
> > +		    delete kv.nodename;
> > +		    Proxmox.Utils.API2Request({
> > +			url: '/nodes/'+nodename+'/ceph/init',
> > +			waitMsgTarget: wizard,
> > +			method: 'POST',
> > +			params: kv,
> > +			success: function() {
> > +			    var tp = me.up('#wizcontent');
> > +			    var atab = tp.getActiveTab();
> > +
> > +			    var next = tp.items.indexOf(atab) + 1;
> > +			    var ntab = tp.items.getAt(next);
> > +			    if (ntab) {
> > +				ntab.enable();
> > +				tp.setActiveTab(ntab);
> > +			    }
> > +			},
> > +			failure: function(response, opts) {
> > +			    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
> > +			}
> > +		    });
> > +		}
> > +	    },
> > +	    {
> > +		title: gettext('Success'),
> > +		xtype: 'panel',
> > +		border: false,
> > +		bodyBorder: false,
> > +		onlineHelp: 'chapter_pveceph',
> > +		html: '<h3>Installation successfull!</h3>',
> > +		listeners: {
> > +		    activate: function() {
> > +			// notify owning container that it should display a help button
> > +			if (this.onlineHelp) {
> > +			    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
> > +			}
> 
> maybe deactivate all old panels/backbutton here? else i can get back and 
> submit again

ok

> 
> > +		    },
> > +		    deactivate: function() {
> > +			if (this.onlineHelp) {
> > +			    Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
> > +			}
> > +		    }
> > +		},
> > +		onSubmit: function() {
> > +		    var wizard = this.up('pveCephInstallWizard');
> > +		    wizard.close();	
> > +		}
> > +	    }
> > +	]
> > +    });
> > \ No newline at end of file
> > diff --git a/www/manager6/ceph/Config.js b/www/manager6/ceph/Config.js
> > index 04124684..447a9682 100644
> > --- a/www/manager6/ceph/Config.js
> > +++ b/www/manager6/ceph/Config.js
> > @@ -14,6 +14,22 @@ Ext.define('PVE.node.CephConfig', {
> >   	    waitMsgTarget: me,
> >   	    failure: function(response, opts) {
> >   		me.update(gettext('Error') + " " + response.htmlStatus);
> > +		var msg = response.htmlStatus;
> > +		var regex = new RegExp("(not installed|not initialized)", "i");
> 
> a better regex: 'not (installed|initialized)'

ok

> 
> > +		if (msg.match(regex)) {
> > +		    if (Proxmox.UserName === 'root at pam') {
> > +			me.ownerCt.el.mask();
> > +			if (!me.ownerCt.down('pveCephInstallWindow')){
> > +			    var win = Ext.create('PVE.ceph.Install', {
> > +				nodename: me.pveSelNode.data.node
> > +			    });
> > +			    me.ownerCt.add(win);
> > +			    win.show();
> > +			}
> > +		    } else {
> > +			me.ownerCt.mask(Ext.String.format(gettext('{0} not installed.') + gettext(' Log in as root to install.'), 'Ceph'), ['pve-static-mask']);
> > +		    }
> > +		}
> >   	    },
> >   	    success: function(response, opts) {
> >   		var data = response.result.data;
> > diff --git a/www/manager6/ceph/Crush.js b/www/manager6/ceph/Crush.js
> > index ebd46c83..7cdfdf6d 100644
> > --- a/www/manager6/ceph/Crush.js
> > +++ b/www/manager6/ceph/Crush.js
> > @@ -15,6 +15,22 @@ Ext.define('PVE.node.CephCrushMap', {
> >   	    waitMsgTarget: me,
> >   	    failure: function(response, opts) {
> >   		me.update(gettext('Error') + " " + response.htmlStatus);
> > +		var msg = response.htmlStatus;
> > +		var regex = new RegExp("(not installed|not initialized)", "i");
> > +		if (msg.match(regex)) {
> > +		    if (Proxmox.UserName === 'root at pam') {
> > +			me.ownerCt.el.mask();
> > +			if (!me.ownerCt.down('pveCephInstallWindow')){
> > +			    var win = Ext.create('PVE.ceph.Install', {
> > +				nodename: me.pveSelNode.data.node
> > +			    });
> > +			    me.ownerCt.add(win);
> > +			    win.show();
> > +			}
> > +		    } else {
> > +			me.ownerCt.mask(Ext.String.format(gettext('{0} not installed.') + gettext(' Log in as root to install.'), 'Ceph'), ['pve-static-mask']);
> > +		    }
> > +		}
> 
> this code looks very much like it could be factored out
> 

will take a look.

> >   	    },
> >   	    success: function(response, opts) {
> >   		var data = response.result.data;
> > diff --git a/www/manager6/ceph/FS.js b/www/manager6/ceph/FS.js
> > index a1c34d73..bff1837b 100644
> > --- a/www/manager6/ceph/FS.js
> > +++ b/www/manager6/ceph/FS.js
> > @@ -161,7 +161,26 @@ Ext.define('PVE.NodeCephFSPanel', {
> >   			    order: 'DESC'
> >   			}
> >   		    }));
> > -		    Proxmox.Utils.monStoreErrors(view, view.rstore);
> > +		    var regex = new RegExp("(not installed|not initialized)", "i");
> > +		    PVE.Utils.handleStoreErrorOrMask(view, view.rstore, regex, function(me, error){
> > +			me.rstore.stopUpdate();
> > +			if (Proxmox.UserName === 'root at pam') {
> > +			    me.ownerCt.el.mask();
> > +
> > +			    if (!me.ownerCt.down('pveCephInstallWindow')){
> > +				var win = Ext.create('PVE.ceph.Install', {
> > +				    nodename: view.nodename
> > +				});
> > +				me.ownerCt.add(win);
> > +				me.ownerCt.mon(win, 'cephInstallWindowClosed', function(){
> > +				    me.rstore.startUpdate();
> > +				});
> > +				win.show();
> > +			    }
> > +			} else {
> > +			    me.ownerCt.mask(Ext.String.format(gettext('{0} not installed.') + gettext(' Log in as root to install.'), 'Ceph'), ['pve-static-mask']);
> > +			}
> > +		    });
> >   		    view.rstore.on('load', this.onLoad, this);
> >   		    view.on('destroy', view.rstore.stopUpdate);
> >   		},
> > @@ -244,7 +263,26 @@ Ext.define('PVE.NodeCephFSPanel', {
> >   			    order: 'DESC'
> >   			}
> >   		    }));
> > -		    Proxmox.Utils.monStoreErrors(view, view.rstore);
> > +		    var regex = new RegExp("(not installed|not initialized)", "i");
> > +		    PVE.Utils.handleStoreErrorOrMask(view, view.rstore, regex, function(me, error){
> > +			me.rstore.stopUpdate();
> > +			if (Proxmox.UserName === 'root at pam') {
> > +			    me.ownerCt.el.mask();
> > +	
> > +			    if (!me.ownerCt.down('pveCephInstallWindow')){
> > +				var win = Ext.create('PVE.ceph.Install', {
> > +				    nodename: view.nodename
> > +				});
> > +				me.ownerCt.add(win);
> > +				me.ownerCt.mon(win, 'cephInstallWindowClosed', function(){
> > +				    me.rstore.startUpdate();
> > +				});
> > +				win.show();
> > +			    }
> > +			} else {
> > +			    me.ownerCt.mask(Ext.String.format(gettext('{0} not installed.') + gettext(' Log in as root to install.'), 'Ceph'), ['pve-static-mask']);
> > +			}
> > +		    });
> 
> same here, those two codepaths look very much alike
> 
> >   		    view.rstore.on('load', this.onLoad, this);
> >   		    view.on('destroy', view.rstore.stopUpdate);
> >   		},
> > diff --git a/www/manager6/ceph/Log.js b/www/manager6/ceph/Log.js
> > new file mode 100644
> > index 00000000..25178923
> > --- /dev/null
> > +++ b/www/manager6/ceph/Log.js
> > @@ -0,0 +1,70 @@
> > +Ext.define('PVE.ceph.Log', {
> > +    extend: 'Proxmox.panel.LogView',
> > +    xtype: 'cephLogView',
> > +    nodename: undefined,
> > +    doAttemptLoad: function(start) {
> > +        var me = this;
> > +
> > +	var req_params = {
> > +	    start: start,
> > +	    limit: me.pageSize
> > +	};
> > +
> > +	if (me.log_select_timespan) {
> > +	    // always show log until the end of the selected day
> > +	    req_params.until = Ext.Date.format(me.until_date, 'Y-m-d') + ' 23:59:59';
> > +	    req_params.since = Ext.Date.format(me.since_date, 'Y-m-d');
> > +	}
> > +
> > +	Proxmox.Utils.API2Request({
> > +	    url: me.url,
> > +	    params: req_params,
> > +	    method: 'GET',
> > +	    success: function(response) {
> > +		Proxmox.Utils.setErrorMask(me, false);
> > +		var list = response.result.data;
> > +		var total = response.result.total;
> > +		var first = 0, last = 0;
> > +		var text = '';
> > +		Ext.Array.each(list, function(item) {
> > +		    if (!first|| item.n < first) {
> > +			first = item.n;
> > +		    }
> > +		    if (!last || item.n > last) {
> > +			last = item.n;
> > +		    }
> > +		    text = text + Ext.htmlEncode(item.t) + "
";
> > +		});
> > +
> > +		if (first && last && total) {
> > +		    me.updateView(first -1 , last -1, total, text);
> > +		} else {
> > +		    me.updateView(0, 0, 0, '');
> > +		}
> > +	    },
> > +	    failure: function(response) {
> > +		var msg = response.htmlStatus;
> > +		var regex = new RegExp("(not installed|not initialized)", "i");
> > +		if (msg.match(regex)) {
> > +		    if (Proxmox.UserName === 'root at pam') {
> > +			me.el.mask();
> > +
> > +			if (!me.down('pveCephInstallWindow')){
> > +			    var win = Ext.create('PVE.ceph.Install', {
> > +				nodename: me.nodename
> > +			    });
> > +			    me.add(win);
> > +			    win.show();
> > +			}
> > +
> > +		    } else {
> > +			me.mask(Ext.String.format(gettext('{0} not installed.') + gettext(' Log in as root to install.'), 'Ceph'), ['pve-static-mask']);
> > +		    }
> > +
> > +		} else {
> > +		    Proxmox.Utils.setErrorMask(me, msg);
> > +		}
> > +	    }
> > +	});
> > +    }
> > +});
> > \ No newline at end of file
> > diff --git a/www/manager6/ceph/Monitor.js b/www/manager6/ceph/Monitor.js
> > index a3a18a83..476ed8cc 100644
> > --- a/www/manager6/ceph/Monitor.js
> > +++ b/www/manager6/ceph/Monitor.js
> > @@ -82,7 +82,6 @@ Ext.define('PVE.node.CephMonList', {
> >   	    sorters: [{ property: 'name'}]
> >   	});
> >   
> > -	Proxmox.Utils.monStoreErrors(me, rstore);
> >   
> >   	var service_cmd = function(cmd) {
> >   	    var rec = sm.getSelection()[0];
> > @@ -211,6 +210,24 @@ Ext.define('PVE.node.CephMonList', {
> >   	    }
> >   	});
> >   
> > +	var regex = new RegExp("(not installed|not initialized)", "i");
> > +	PVE.Utils.handleStoreErrorOrMask(me, rstore, regex, function(me, error){
> > +	    me.store.rstore.stopUpdate();
> > +	    if (Proxmox.UserName === 'root at pam') {
> > +		me.el.mask();
> > +		var win = Ext.create('PVE.ceph.Install', {
> > +		    nodename: nodename
> > +		});
> > +		me.add(win);
> > +		me.mon(win, 'cephInstallWindowClosed', function(){
> > +		    me.store.rstore.startUpdate();
> > +		});
> > +		win.show();
> > +	    } else {
> > +		me.el.mask(Ext.String.format(gettext('{0} not installed.') + gettext(' Log in as root to install.'), 'Ceph'), ['pve-static-mask']);
> > +	    }
> > +	});
> > +
> >   	me.callParent();
> >       }
> >   }, function() {
> > diff --git a/www/manager6/ceph/OSD.js b/www/manager6/ceph/OSD.js
> > index 144fab7e..f635cbd6 100644
> > --- a/www/manager6/ceph/OSD.js
> > +++ b/www/manager6/ceph/OSD.js
> > @@ -281,7 +281,24 @@ Ext.define('PVE.node.CephOsdTree', {
> >   		waitMsgTarget: me,
> >   		method: 'GET',
> >   		failure: function(response, opts) {
> > -		    Proxmox.Utils.setErrorMask(me, response.htmlStatus);
> > +		    var msg = response.htmlStatus;
> > +		    var regex = new RegExp("(not installed|not initialized)", "i");
> > +		    if (msg.match(regex)) {
> > +			if (Proxmox.UserName === 'root at pam') {
> > +			    me.el.mask();
> > +			    if (!me.down('pveCephInstallWindow')){
> > +				var win = Ext.create('PVE.ceph.Install', {
> > +				    nodename: me.pveSelNode.data.node
> > +				});
> > +				me.add(win);
> > +				win.show();
> > +			    }
> > +			} else {
> > +			    me.mask(Ext.String.format(gettext('{0} not installed.') + gettext(' Log in as root to install.'), 'Ceph'), ['pve-static-mask']);
> > +			}
> > +		    } else {
> > +			Proxmox.Utils.setErrorMask(me, msg);
> > +		    }
> >   		},
> >   		success: function(response, opts) {
> >   		    sm.deselectAll();
> > diff --git a/www/manager6/ceph/Pool.js b/www/manager6/ceph/Pool.js
> > index 27eba024..c7dd2248 100644
> > --- a/www/manager6/ceph/Pool.js
> > +++ b/www/manager6/ceph/Pool.js
> > @@ -164,7 +164,23 @@ Ext.define('PVE.node.CephPoolList', {
> >   
> >   	var store = Ext.create('Proxmox.data.DiffStore', { rstore: rstore });
> >   
> > -	Proxmox.Utils.monStoreErrors(me, rstore);
> > +	var regex = new RegExp("(not installed|not initialized)", "i");
> > +	PVE.Utils.handleStoreErrorOrMask(me, rstore, regex, function(me, error){
> > +	    me.store.rstore.stopUpdate();
> > +	    if (Proxmox.UserName === 'root at pam') {
> > +		me.el.mask();
> > +		var win = Ext.create('PVE.ceph.Install', {
> > +		    nodename: nodename
> > +		});
> > +		me.add(win);
> > +		me.mon(win, 'cephInstallWindowClosed', function(){
> > +		    me.store.rstore.startUpdate();
> > +		});
> > +		win.show();
> > +	    } else {
> > +		me.el.mask(Ext.String.format(gettext('{0} not installed.') + gettext(' Log in as root to install.'), 'Ceph'), ['pve-static-mask']);
> > +	    }
> > +	});
> >   
> >   	var create_btn = new Ext.Button({
> >   	    text: gettext('Create'),
> > diff --git a/www/manager6/ceph/Status.js b/www/manager6/ceph/Status.js
> > index 78fa1cf8..ea4e27e7 100644
> > --- a/www/manager6/ceph/Status.js
> > +++ b/www/manager6/ceph/Status.js
> > @@ -308,7 +308,26 @@ Ext.define('PVE.node.CephStatus', {
> >   	me.version = me.sp.get('ceph-version');
> >   	me.change_version(me.version);
> >   
> > -	Proxmox.Utils.monStoreErrors(me,me.store);
> > +	var regex = new RegExp("(not installed|not initialized)", "i");
> > +	PVE.Utils.handleStoreErrorOrMask(me, me.store, regex, function(me, error){
> > +	    me.store.stopUpdate();
> > +	    if (Proxmox.UserName === 'root at pam') {
> > +		me.el.mask();
> > +		if (!me.down('PVE.ceph.Install')){
> > +		    var win = Ext.create('PVE.ceph.Install', {
> > +			nodename: nodename
> > +		    });
> > +		    me.add(win);
> > +		    me.mon(win, 'cephInstallWindowClosed', function(){
> > +			me.store.startUpdate();
> > +		    });
> > +		    win.show();
> > +		}
> > +	    } else {
> > +		me.el.mask(Ext.String.format(gettext('{0} not installed.') + gettext(' Log in as root to install.'), 'Ceph'), ['pve-static-mask']);
> > +	    }
> > +	});
> 
> most of these look very much alike and should be refactored imo
> 
> > +
> >   	me.mon(me.store, 'load', me.updateAll, me);
> >   	me.on('destroy', me.store.stopUpdate);
> >   	me.store.startUpdate();
> > diff --git a/www/manager6/node/Config.js b/www/manager6/node/Config.js
> > index f9a62670..831d2e02 100644
> > --- a/www/manager6/node/Config.js
> > +++ b/www/manager6/node/Config.js
> > @@ -375,8 +375,9 @@ Ext.define('PVE.node.Config', {
> >   		    iconCls: 'fa fa-list',
> >   		    groups: ['ceph'],
> >   		    onlineHelp: 'chapter_pveceph',
> > -		    xtype: 'proxmoxLogView',
> > -		    url: "/api2/extjs/nodes/" + nodename + "/ceph/log"
> > +		    xtype: 'cephLogView',
> > +		    url: "/api2/extjs/nodes/" + nodename + "/ceph/log",
> > +		    nodename: nodename
> >   		});
> >   	}
> >   
> > diff --git a/www/manager6/window/CephInstall.js b/www/manager6/window/CephInstall.js
> > new file mode 100644
> > index 00000000..20ecdd16
> > --- /dev/null
> > +++ b/www/manager6/window/CephInstall.js
> > @@ -0,0 +1,66 @@
> > +/*jslint confusion: true*/
> > +Ext.define('PVE.ceph.Install', {
> > +    extend: 'Ext.window.Window',
> > +    xtype: 'pveCephInstallWindow',
> > +    mixins: ['Proxmox.Mixin.CBind'],
> > +
> > +    width: 220,
> > +    header: false,
> > +    resizable: false,
> > +    draggable: false,
> > +    modal: true,
> > +    nodename: undefined,
> > +    shadow: false,
> > +    border: false,
> > +    bodyBorder: false,
> > +    closable: false,
> > +    cls: 'install-mask',
> > +    bodyCls: 'install-mask',
> 
> i think for the padding issue, a
> padding: 5
> or
> bodyPadding: 5
> here could help
> 
> > +    layout: {
> > +        align: 'stretch',
> > +        pack: 'center',
> > +	type: 'vbox'
> > +    },
> > +    viewModel: {
> > +	parent: null,
> > +	data: {
> > +	      cephVersion: 'luminous'
> > +	},
> > +	formulas: {
> > +	    buttonText: function (get){
> > +		return gettext('Install Ceph-') + get('cephVersion');
> > +	    }
> > +	}
> > +    },
> > +    items: [
> > +	{
> > +	    html: '<p class="install-mask">' + Ext.String.format(gettext('{0} is not installed on this node.'), 'Ceph') + '
' +
> > +	    gettext('Would you like to install it now?') + '</p>',
> > +	    border: false,
> > +	    padding: 5,
> > +	    bodyCls: 'install-mask'
> > +	
> > +	},
> > +	{
> > +	    xtype: 'button',
> > +	    bind: {
> > +		text: '{buttonText}'
> > +	    },
> > +	    cbind: {
> > +		nodename: '{nodename}'
> > +	    },
> > +	    handler: function() {
> > +		var me = this.up('pveCephInstallWindow');
> > +		var win = Ext.create('PVE.ceph.CephInstallWizard',{
> > +		    nodename: me.nodename
> > +		});
> > +		win.show();
> > +		me.mon(win,'beforeClose', function(){
> > +		    me.fireEvent("cephInstallWindowClosed");
> > +		    me.close();
> > +		});
> > +
> > +	    }
> > +	}
> > +    ]
> > +});
> > 
> 
> 
> _______________________________________________
> pve-devel mailing list
> pve-devel at pve.proxmox.com
> https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel




More information about the pve-devel mailing list