[pve-devel] [RFC manager 4/5] ui: add cluster join window POC

Thomas Lamprecht t.lamprecht at proxmox.com
Thu Mar 29 11:30:06 CEST 2018


The "Join successful, possible new node SSL certificate, tell user and
try to reload" semantic to work nicely the not yet reviewed
"API/Cluster: autoflush STDOUT for join and create" series is needed,
just FYI.

On 3/27/18 3:45 PM, Thomas Lamprecht wrote:
> Signed-off-by: Thomas Lamprecht <t.lamprecht at proxmox.com>
> ---
>  www/manager6/dc/Cluster.js     |  21 +++++
>  www/manager6/dc/ClusterEdit.js | 190 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 211 insertions(+)
> 
> diff --git a/www/manager6/dc/Cluster.js b/www/manager6/dc/Cluster.js
> index ca43c8f9..11e24c66 100644
> --- a/www/manager6/dc/Cluster.js
> +++ b/www/manager6/dc/Cluster.js
> @@ -113,6 +113,19 @@ Ext.define('PVE.ClusterAdministration', {
>  			}
>  		    });
>  		    win.show();
> +		},
> +
> +		onJoin: function() {
> +		    var view = this.getView();
> +		    view.store.stopUpdate();
> +		    var win = Ext.create('PVE.ClusterJoinNodeWindow', {
> +			autoShow: true,
> +			listeners: {
> +			    destroy: function() {
> +				view.store.startUpdate();
> +			    }
> +			}
> +		    });
>  		}
>  	    },
>  	    tbar: [
> @@ -131,6 +144,14 @@ Ext.define('PVE.ClusterAdministration', {
>  		    bind: {
>  			disabled: '{!isInCluster}'
>  		    }
> +		},
> +		{
> +		    text: gettext('Join Cluster'),
> +		    reference: 'joinButton',
> +		    handler: 'onJoin',
> +		    bind: {
> +			disabled: '{isInCluster}'
> +		    }
>  		}
>  	    ],
>  	    layout: 'hbox',
> diff --git a/www/manager6/dc/ClusterEdit.js b/www/manager6/dc/ClusterEdit.js
> index 249801c3..25ca6607 100644
> --- a/www/manager6/dc/ClusterEdit.js
> +++ b/www/manager6/dc/ClusterEdit.js
> @@ -105,3 +105,193 @@ Ext.define('PVE.ClusterInfoWindow', {
>  	}]
>      }]
>  });
> +
> +Ext.define('PVE.ClusterJoinNodeWindow', {
> +    extend: 'Proxmox.window.Edit',
> +    xtype: 'pveClusterJoinNodeWindow',
> +
> +    title: gettext('Cluster Join'),
> +    width: 800,
> +
> +    method: 'POST',
> +    url: '/cluster/config/join',
> +
> +    defaultFocus: 'textarea[name=serializedinfo]',
> +    isCreate: true,
> +    submitText: gettext('Join'),
> +    showTaskViewer: true,
> +
> +    onlineHelp: 'chapter_pvecm',
> +
> +    viewModel: {
> +	parent: null,
> +	data: {
> +	    info: {
> +		fp: '',
> +		ip: '',
> +		ring1Possible: false,
> +		ring1Needed: false
> +	    }
> +	}
> +    },
> +
> +    controller: {
> +	xclass: 'Ext.app.ViewController',
> +	control: {
> +	    'proxmoxcheckbox[name=assistedInput]': {
> +		change: 'onInputTypeChange'
> +	    },
> +	    'textarea[name=serializedinfo]': {
> +		change: 'recomputeSerializedInfo',
> +		enable: 'resetField'
> +	    },
> +	    'proxmoxtextfield[name=ring1_addr]': {
> +		enable: 'ring1Needed'
> +	    },
> +	    'textfield': {
> +		disable: 'resetField'
> +	    }
> +	},
> +	resetField: function(field) {
> +	    field.reset();
> +	},
> +	ring1Needed: function(f) {
> +	    var vm = this.getViewModel();
> +	    f.allowBlank = !vm.get('info.ring1Needed');
> +	},
> +	onInputTypeChange: function(field, assistedInput) {
> +	    var vm = this.getViewModel();
> +	    if (!assistedInput) {
> +		vm.set('info.ring1Possible', true);
> +	    }
> +	},
> +	recomputeSerializedInfo: function(field, value) {
> +	    var vm = this.getViewModel();
> +	    var jsons = Ext.util.Base64.decode(value);
> +	    var joinInfo = Ext.JSON.decode(jsons, true);
> +
> +	    var info = {
> +		fp: '',
> +		ring1Needed: false,
> +		ring1Possible: false,
> +		ip: ''
> +	    };
> +
> +	    var totem = {};
> +	    if (!(joinInfo && joinInfo.totem)) {
> +		field.valid = false;
> +	    } else {
> +		info = {
> +		    ip: joinInfo.ipAddress,
> +		    fp: joinInfo.fingerprint,
> +		    ring1Possible: !!joinInfo.totem['interface']['1'],
> +		    ring1Needed: !!joinInfo.totem['interface']['1']
> +		};
> +		totem = joinInfo.totem;
> +		field.valid = true;
> +	    }
> +
> +	    vm.set('info', info);
> +	}
> +    },
> +
> +    taskDone: function(success) {
> +	if (success) {
> +	    var txt = gettext('Cluster join task finished, node certificate may have changed, reload GUI!');
> +	    // ensure user cannot do harm
> +	    Ext.getBody().mask(txt, ['pve-static-mask']);
> +	    // TaskView may hide above mask, so tell him directly
> +	    Ext.Msg.show({
> +		title: gettext('Join Task Finished'),
> +		icon: Ext.Msg.INFO,
> +		msg: txt
> +	    });
> +	    // reload always (if user wasn't faster), but wait a bit for pveproxy
> +	    Ext.defer(function() {
> +		window.location.reload(true);
> +	    }, 5000);
> +	}
> +    },
> +
> +    items: [{
> +	xtype: 'proxmoxcheckbox',
> +	reference: 'assistedEntry',
> +	submitValue: false,
> +	value: true,
> +	autoEl: {
> +	    tag: 'div',
> +	    'data-qtip': gettext('Select if join information should be extracted from pasted cluster information, deselect for manual entering')
> +	},
> +	boxLabel: gettext('Assisted join: Paste encoded cluster join information and enter password.')
> +    },
> +    {
> +	xtype: 'textarea',
> +	name: 'serializedinfo',
> +	submitValue: false,
> +	allowBlank: false,
> +	fieldLabel: gettext('Information'),
> +	emptyText: gettext('Paste encoded Cluster Information here'),
> +	validator: function(val) {
> +	    return val === '' || this.valid ||
> +	       gettext('Does not seem like a valid encoded Cluster Information!');
> +	},
> +	bind: {
> +	    disabled: '{!assistedEntry.checked}',
> +	    hidden: '{!assistedEntry.checked}'
> +	},
> +	value: ''
> +    },
> +    {
> +	xtype: 'inputpanel',
> +	column1: [
> +	    {
> +		xtype: 'textfield',
> +		fieldLabel: gettext('Peer Address'),
> +		allowBlank: false,
> +		bind: {
> +		    value: '{info.ip}',
> +		    readOnly: '{assistedEntry.checked}'
> +		},
> +		name: 'hostname'
> +	    },
> +	    {
> +		xtype: 'textfield',
> +		inputType: 'password',
> +		emptyText: gettext("Peer's root password"),
> +		fieldLabel: gettext('Password'),
> +		allowBlank: false,
> +		name: 'password'
> +	    }
> +	],
> +	column2: [
> +	    {
> +		xtype: 'proxmoxtextfield',
> +		fieldLabel: gettext('Corosync Ring 0'),
> +		emptyText: gettext("Default: IP resolved by node's hostname"),
> +		skipEmptyText: true,
> +		name: 'ring0_addr'
> +	    },
> +	    {
> +		xtype: 'proxmoxtextfield',
> +		fieldLabel: gettext('Corosync Ring 1'),
> +		skipEmptyText: true,
> +		bind: {
> +		    disabled: '{!info.ring1Possible}'
> +		},
> +		name: 'ring1_addr'
> +	    }
> +	],
> +	columnB: [
> +	    {
> +		xtype: 'textfield',
> +		fieldLabel: gettext('Fingerprint'),
> +		allowBlank: false,
> +		bind: {
> +		    value: '{info.fp}',
> +		    readOnly: '{assistedEntry.checked}'
> +		},
> +		name: 'fingerprint'
> +	    }
> +	]
> +    }]
> +});
> 





More information about the pve-devel mailing list