this lets the user edit the cloud init config
like username, sshkey, ipconfig, etc.

Signed-off-by: Dominik Csapak <[email protected]>
---
 www/manager6/Makefile          |   1 +
 www/manager6/StateProvider.js  |   1 +
 www/manager6/qemu/CloudInit.js | 293 +++++++++++++++++++++++++++++++++++++++++
 www/manager6/qemu/Config.js    |   6 +
 4 files changed, 301 insertions(+)
 create mode 100644 www/manager6/qemu/CloudInit.js

diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 1c7fdf92..646e7759 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -129,6 +129,7 @@ JSSRC=                                                      
\
        qemu/CreateWizard.js                            \
        qemu/USBEdit.js                                 \
        qemu/AgentIPView.js                             \
+       qemu/CloudInit.js                               \
        qemu/CIDriveEdit.js                             \
        qemu/SSHKey.js                                  \
        qemu/IPConfigEdit.js                            \
diff --git a/www/manager6/StateProvider.js b/www/manager6/StateProvider.js
index db00e8b2..80e82c04 100644
--- a/www/manager6/StateProvider.js
+++ b/www/manager6/StateProvider.js
@@ -49,6 +49,7 @@ Ext.define('PVE.StateProvider', {
     hprefix: 'v1',
 
     compDict: {
+       cloudinit: 52,
        replication: 51,
        system: 50,
        monitor: 49,
diff --git a/www/manager6/qemu/CloudInit.js b/www/manager6/qemu/CloudInit.js
new file mode 100644
index 00000000..52bbf542
--- /dev/null
+++ b/www/manager6/qemu/CloudInit.js
@@ -0,0 +1,293 @@
+Ext.define('PVE.qemu.CloudInit', {
+    extend: 'Proxmox.grid.PendingObjectGrid',
+    xtype: 'pveCiPanel',
+
+    tbar: [
+       {
+           xtype: 'proxmoxButton',
+           disabled: true,
+           dangerous: true,
+           confirmMsg: function(rec) {
+               var me = 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, "'"
+                   + me.renderKey(entry, {}, rec) + "'");
+
+               return msg;
+           },
+           enableFn: function(record) {
+               var me = this.up('grid');
+               var caps = Ext.state.Manager.get('GuiCap');
+               if (me.rows[record.data.key].never_delete ||
+                   !caps.vms['VM.Config.Network']) {
+                   return false;
+               }
+               return true;
+           },
+           handler: function() {
+               var me = this.up('grid');
+           },
+           text: gettext('Remove')
+       },
+       {
+           xtype: 'proxmoxButton',
+           disabled: true,
+           handler: function() {
+               var me = this.up('grid');
+               me.run_editor();
+           },
+           text: gettext('Edit')
+       },
+       '-',
+       {
+           xtype: 'button',
+           itemId: 'savebtn',
+           text: gettext('Regenerate Image'),
+           handler: function() {
+               var me = this.up('grid');
+               var eject_params = {};
+               var insert_params = {};
+               var disk = PVE.Parser.parseQemuDrive(me.ciDriveId, me.ciDrive);
+               var storage = '';
+               var stormatch = disk.file.match(/^([^\:]+)\:/);
+               if (stormatch) {
+                   storage = stormatch[1];
+               }
+               eject_params[me.ciDriveId] = 'none,media=cdrom';
+               insert_params[me.ciDriveId] = storage + ':cloudinit';
+
+               var failure = function(response, opts) {
+                   Ext.Msg.alert('Error', response.htmlStatus);
+               };
+
+               Proxmox.Utils.API2Request({
+                   url: me.baseurl + '/config',
+                   waitMsgTarget: me,
+                   method: 'PUT',
+                   params: eject_params,
+                   failure: failure,
+                   callback: function() {
+                       Proxmox.Utils.API2Request({
+                           url: me.baseurl + '/config',
+                           waitMsgTarget: me,
+                           method: 'PUT',
+                           params: insert_params,
+                           failure: failure,
+                           callback: function() {
+                               me.reload();
+                           }
+                       });
+                   }
+               });
+           }
+       }
+    ],
+
+    border: false,
+
+    set_button_status: function(rstore, records, success) {
+       if (!success || records.length < 1) {
+           return;
+       }
+       var me = this;
+       var found;
+       records.forEach(function(record) {
+           if (found) {
+               return;
+           }
+           var id = record.data.key;
+           var value = record.data.value;
+           var ciregex = new RegExp("vm-" + me.pveSelNode.data.vmid + 
"-cloudinit");
+               if (id.match(/^(ide|scsi|sata)\d+$/) && ciregex.test(value)) {
+                   found = id;
+                   me.ciDriveId = found;
+                   me.ciDrive = value;
+               }
+       });
+
+       me.down('#savebtn').setDisabled(!found);
+       me.setDisabled(!found);
+       if (!found) {
+           me.getView().mask(gettext('No CloudInit Drive found'), 
['pve-static-mask']);
+       } else {
+           me.getView().unmask();
+       }
+    },
+
+    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 + '/qemu/' + vmid;
+       me.url =  me.baseurl + '/pending';
+       me.editorConfig.url = me.baseurl + '/config';
+       me.editorConfig.pveSelNode = me.pveSelNode;
+
+       /*jslint confusion: true*/
+       /* editor is string and object */
+       me.rows = {
+           ciuser: {
+               header: gettext('User'),
+               iconCls: 'fa fa-user',
+               never_delete: true,
+               defaultValue: '',
+               editor: caps.vms['VM.Config.Options'] ? {
+                   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',
+               never_delete: true,
+               defaultValue: '',
+               editor: caps.vms['VM.Config.Options'] ? {
+                   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;
+               }
+           },
+           searchdomain: {
+               header: gettext('DNS domain'),
+               iconCls: 'fa fa-globe',
+               editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : 
undefined,
+               never_delete: true,
+               defaultValue: gettext('use host settings')
+           },
+           nameserver: {
+               header: gettext('DNS servers'),
+               iconCls: 'fa fa-globe',
+               editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : 
undefined,
+               never_delete: true,
+               defaultValue: gettext('use host settings')
+           },
+           sshkeys: {
+               header: gettext('SSH public key'),
+               iconCls: 'fa fa-key',
+               editor: caps.vms['VM.Config.Network'] ? '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) {
+                           // First erase all quoted strings (eg. command="foo"
+                           var v = key.replace(/"(?:\\.|[^"\\])*"/g, '');
+                           // Now try to detect the comment:
+                           var res = 
v.match(/^\s*(\S+\s+)?(?:ssh-(?:dss|rsa|ed25519)|ecdsa-sha2-nistp\d+)\s+\S+\s+(.*?)\s*$/,
 '');
+                           if (res) {
+                               key = Ext.String.htmlEncode(res[2]);
+                               if (res[1]) {
+                                   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: ''
+           }
+       };
+       var i;
+       var ipconfig_renderer = function(value, md, record, ri, ci, store, 
pending) {
+           var id = record.data.key;
+           var match = id.match(/^net(\d+)$/);
+           var val = '';
+           if (match) {
+               val = me.getObjectValue('ipconfig'+match[1], '', pending);
+           }
+           return val;
+       };
+       for (i = 0; i < 32; i++) {
+           // we want to show an entry for every network device
+           // even if it is empty
+           me.rows['net' + i.toString()] = {
+               multiKey: ['ipconfig' + i.toString(), 'net' + i.toString()],
+               header: gettext('IP Config') + ' (net' + i.toString() +')',
+               editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.IPConfigEdit' 
: undefined,
+               iconCls: 'fa fa-exchange',
+               renderer: ipconfig_renderer
+           };
+           me.rows['ipconfig' + i.toString()] = {
+               visible: false
+           };
+       }
+       /*jslint confusion: false*/
+
+       PVE.Utils.forEachBus(['ide', 'scsi', 'sata'], function(type, id) {
+           me.rows[type+id] = {
+               visible: false
+           };
+       });
+       me.callParent();
+       me.mon(me.rstore, 'load', me.set_button_status, me);
+    }
+});
diff --git a/www/manager6/qemu/Config.js b/www/manager6/qemu/Config.js
index 4620fd20..5de39fc3 100644
--- a/www/manager6/qemu/Config.js
+++ b/www/manager6/qemu/Config.js
@@ -210,6 +210,12 @@ Ext.define('PVE.qemu.Config', {
                xtype: 'PVE.qemu.HardwareView'
            },
            {
+               title: 'Cloud-Init',
+               itemId: 'cloudinit',
+               iconCls: 'fa fa-cloud',
+               xtype: 'pveCiPanel'
+           },
+           {
                title: gettext('Options'),
                iconCls: 'fa fa-gear',
                itemId: 'options',
-- 
2.11.0


_______________________________________________
pve-devel mailing list
[email protected]
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to