[pve-devel] [PATCH RFC manager 2/2] cloudinit: introduce panel for LXCs

Leo Nunner l.nunner at proxmox.com
Thu May 11 13:12:49 CEST 2023


based on the already existing panel for VMs. Some things have been
changed, there is no network configuration, and a separate "enable"
options toggles cloud-init (simillar to adding/removing a cloud-init
drive for VMs).

Signed-off-by: Leo Nunner <l.nunner at proxmox.com>
---
 www/manager6/Makefile         |   1 +
 www/manager6/lxc/CloudInit.js | 219 ++++++++++++++++++++++++++++++++++
 www/manager6/lxc/Config.js    |   6 +
 3 files changed, 226 insertions(+)
 create mode 100644 www/manager6/lxc/CloudInit.js

diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 2b577c8e..27ac9068 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -168,6 +168,7 @@ JSSRC= 							\
 	dc/UserTagAccessEdit.js				\
 	dc/RegisteredTagsEdit.js			\
 	lxc/CmdMenu.js					\
+	lxc/CloudInit.js				\
 	lxc/Config.js					\
 	lxc/CreateWizard.js				\
 	lxc/DNS.js					\
diff --git a/www/manager6/lxc/CloudInit.js b/www/manager6/lxc/CloudInit.js
new file mode 100644
index 00000000..2e4e26ba
--- /dev/null
+++ b/www/manager6/lxc/CloudInit.js
@@ -0,0 +1,219 @@
+Ext.define('PVE.lxc.CloudInit', {
+    extend: 'Proxmox.grid.PendingObjectGrid',
+    xtype: 'pveLxcCiPanel',
+
+    tbar: [
+	{
+	    xtype: 'proxmoxButton',
+	    disabled: true,
+	    dangerous: true,
+	    confirmMsg: function(rec) {
+		let view = this.up('grid');
+		var warn = gettext('Are you sure you want to remove entry {0}');
+
+		var entry = rec.data.key;
+		var msg = Ext.String.format(warn, "'"
+		    + view.renderKey(entry, {}, rec) + "'");
+
+		return msg;
+	    },
+	    enableFn: function(record) {
+		let view = this.up('grid');
+		var caps = Ext.state.Manager.get('GuiCap');
+		if (view.rows[record.data.key].never_delete ||
+		    !caps.vms['VM.Config.Network']) {
+		    return false;
+		}
+
+		if (record.data.key === 'cipassword' && !record.data.value) {
+		    return false;
+		}
+		return true;
+	    },
+	    handler: function() {
+		let view = this.up('grid');
+		let records = view.getSelection();
+		if (!records || !records.length) {
+		    return;
+		}
+
+		var id = records[0].data.key;
+
+		var params = {};
+		params.delete = id;
+		Proxmox.Utils.API2Request({
+		    url: view.baseurl + '/config',
+		    waitMsgTarget: view,
+		    method: 'PUT',
+		    params: params,
+		    failure: function(response, opts) {
+			Ext.Msg.alert('Error', response.htmlStatus);
+		    },
+		    callback: function() {
+			view.reload();
+		    },
+		});
+	    },
+	    text: gettext('Remove'),
+	},
+	{
+	    xtype: 'proxmoxButton',
+	    disabled: true,
+	    enableFn: function(rec) {
+		let view = this.up('pveLxcCiPanel');
+		return !!view.rows[rec.data.key].editor;
+	    },
+	    handler: function() {
+		let view = this.up('grid');
+		view.run_editor();
+	    },
+	    text: gettext('Edit'),
+	},
+    ],
+
+    border: false,
+
+    renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
+	var me = this;
+	var rows = me.rows;
+	var rowdef = rows[key] || {};
+
+	var icon = "";
+	if (rowdef.iconCls) {
+	    icon = '<i class="' + rowdef.iconCls + '"></i> ';
+	}
+	return icon + (rowdef.header || key);
+    },
+
+    listeners: {
+	activate: function() {
+	    var me = this;
+	    me.rstore.startUpdate();
+	},
+	itemdblclick: function() {
+	    var me = this;
+	    me.run_editor();
+	},
+    },
+
+    initComponent: function() {
+	var me = this;
+
+	var nodename = me.pveSelNode.data.node;
+	if (!nodename) {
+	    throw "no node name specified";
+	}
+
+	var vmid = me.pveSelNode.data.vmid;
+	if (!vmid) {
+	    throw "no VM ID specified";
+	}
+	var caps = Ext.state.Manager.get('GuiCap');
+	me.baseurl = '/api2/extjs/nodes/' + nodename + '/lxc/' + vmid;
+	me.url = me.baseurl + '/pending';
+	me.editorConfig.url = me.baseurl + '/config';
+	me.editorConfig.pveSelNode = me.pveSelNode;
+
+	let caps_ci = caps.vms['VM.Config.Cloudinit'] || caps.vms['VM.Config.Network'];
+	/* editor is string and object */
+	me.rows = {
+	    cienable: {
+		header: gettext('Enable'),
+		iconCls: 'fa fa-cloud',
+		never_delete: true,
+		defaultValue: false,
+		editor: caps_ci ? {
+		    xtype: 'proxmoxWindowEdit',
+		    subject: gettext('Enable Cloud-Init'),
+		    items: [
+			{
+			    xtype: 'proxmoxcheckbox',
+			    deleteEmpty: true,
+			    fieldLabel: gettext('Enable'),
+			    name: 'cienable',
+			},
+		    ],
+		} : undefined,
+		renderer: Proxmox.Utils.format_boolean,
+	    },
+	    ciuser: {
+		header: gettext('User'),
+		iconCls: 'fa fa-user',
+		never_delete: true,
+		defaultValue: '',
+		editor: caps_ci ? {
+		    xtype: 'proxmoxWindowEdit',
+		    subject: gettext('User'),
+		    items: [
+			{
+			    xtype: 'proxmoxtextfield',
+			    deleteEmpty: true,
+			    emptyText: Proxmox.Utils.defaultText,
+			    fieldLabel: gettext('User'),
+			    name: 'ciuser',
+			},
+		    ],
+		} : undefined,
+		renderer: function(value) {
+		    return value || Proxmox.Utils.defaultText;
+		},
+	    },
+	    cipassword: {
+		header: gettext('Password'),
+		iconCls: 'fa fa-unlock',
+		defaultValue: '',
+		editor: caps_ci ? {
+		    xtype: 'proxmoxWindowEdit',
+		    subject: gettext('Password'),
+		    items: [
+			{
+			    xtype: 'proxmoxtextfield',
+			    inputType: 'password',
+			    deleteEmpty: true,
+			    emptyText: Proxmox.Utils.noneText,
+			    fieldLabel: gettext('Password'),
+			    name: 'cipassword',
+			},
+		    ],
+		} : undefined,
+		renderer: function(value) {
+		    return value || Proxmox.Utils.noneText;
+		},
+	    },
+	    sshkeys: {
+		header: gettext('SSH public key'),
+		iconCls: 'fa fa-key',
+		editor: caps_ci ? 'PVE.qemu.SSHKeyEdit' : undefined,
+		never_delete: true,
+		renderer: function(value) {
+		    value = decodeURIComponent(value);
+		    var keys = value.split('\n');
+		    var text = [];
+		    keys.forEach(function(key) {
+			if (key.length) {
+			    let res = PVE.Parser.parseSSHKey(key);
+			    if (res) {
+				key = Ext.String.htmlEncode(res.comment);
+				if (res.options) {
+				    key += ' <span style="color:gray">(' + gettext('with options') + ')</span>';
+				}
+				text.push(key);
+				return;
+			    }
+			    // Most likely invalid at this point, so just stick to
+			    // the old value.
+			    text.push(Ext.String.htmlEncode(key));
+			}
+		    });
+		    if (text.length) {
+			return text.join('<br>');
+		    } else {
+			return Proxmox.Utils.noneText;
+		    }
+		},
+		defaultValue: '',
+	    },
+	};
+	me.callParent();
+    },
+});
diff --git a/www/manager6/lxc/Config.js b/www/manager6/lxc/Config.js
index 23c17d2e..bd86b93b 100644
--- a/www/manager6/lxc/Config.js
+++ b/www/manager6/lxc/Config.js
@@ -260,6 +260,12 @@ Ext.define('PVE.lxc.Config', {
 		itemId: 'dns',
 		xtype: 'pveLxcDNS',
 	    },
+	    {
+		title: 'Cloud-Init',
+		itemId: 'cloudinit',
+		iconCls: 'fa fa-cloud',
+		xtype: 'pveLxcCiPanel',
+	    },
 	    {
 		title: gettext('Options'),
 		itemId: 'options',
-- 
2.30.2






More information about the pve-devel mailing list