]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/qemu/CloudInit.js
change permissions for non-network cloudinit settings
[pve-manager.git] / www / manager6 / qemu / CloudInit.js
CommitLineData
4c507192
DC
1Ext.define('PVE.qemu.CloudInit', {
2 extend: 'Proxmox.grid.PendingObjectGrid',
3 xtype: 'pveCiPanel',
4
16dedd0f
DC
5 onlineHelp: 'qm_cloud_init',
6
4c507192
DC
7 tbar: [
8 {
9 xtype: 'proxmoxButton',
10 disabled: true,
11 dangerous: true,
12 confirmMsg: function(rec) {
13 var me = this.up('grid');
14 var warn = gettext('Are you sure you want to remove entry {0}');
15
16 var entry = rec.data.key;
17 var msg = Ext.String.format(warn, "'"
18 + me.renderKey(entry, {}, rec) + "'");
19
20 return msg;
21 },
22 enableFn: function(record) {
23 var me = this.up('grid');
24 var caps = Ext.state.Manager.get('GuiCap');
25 if (me.rows[record.data.key].never_delete ||
26 !caps.vms['VM.Config.Network']) {
27 return false;
28 }
2ed6dceb
DC
29
30 if (record.data.key === 'cipassword' && !record.data.value) {
31 return false;
32 }
4c507192
DC
33 return true;
34 },
35 handler: function() {
36 var me = this.up('grid');
2ed6dceb
DC
37 var records = me.getSelection();
38 if (!records || !records.length) {
39 return;
40 }
41
42 var id = records[0].data.key;
43 var match = id.match(/^net(\d+)$/);
44 if (match) {
45 id = 'ipconfig' + match[1];
46 }
47
48 var params = {};
49 params['delete'] = id;
50 Proxmox.Utils.API2Request({
51 url: me.baseurl + '/config',
52 waitMsgTarget: me,
53 method: 'PUT',
54 params: params,
55 failure: function(response, opts) {
56 Ext.Msg.alert('Error', response.htmlStatus);
57 },
58 callback: function() {
59 me.reload();
60 }
61 });
4c507192
DC
62 },
63 text: gettext('Remove')
64 },
65 {
66 xtype: 'proxmoxButton',
67 disabled: true,
d790a1b4
DC
68 enableFn: function(rec) {
69 let me = this.up('pveCiPanel');
70 return !!me.rows[rec.data.key].editor;
71 },
4c507192
DC
72 handler: function() {
73 var me = this.up('grid');
74 me.run_editor();
75 },
76 text: gettext('Edit')
77 },
78 '-',
79 {
80 xtype: 'button',
81 itemId: 'savebtn',
82 text: gettext('Regenerate Image'),
83 handler: function() {
84 var me = this.up('grid');
85 var eject_params = {};
86 var insert_params = {};
87 var disk = PVE.Parser.parseQemuDrive(me.ciDriveId, me.ciDrive);
88 var storage = '';
89 var stormatch = disk.file.match(/^([^\:]+)\:/);
90 if (stormatch) {
91 storage = stormatch[1];
92 }
93 eject_params[me.ciDriveId] = 'none,media=cdrom';
94 insert_params[me.ciDriveId] = storage + ':cloudinit';
95
96 var failure = function(response, opts) {
97 Ext.Msg.alert('Error', response.htmlStatus);
98 };
99
100 Proxmox.Utils.API2Request({
101 url: me.baseurl + '/config',
102 waitMsgTarget: me,
103 method: 'PUT',
104 params: eject_params,
105 failure: failure,
106 callback: function() {
107 Proxmox.Utils.API2Request({
108 url: me.baseurl + '/config',
109 waitMsgTarget: me,
110 method: 'PUT',
111 params: insert_params,
112 failure: failure,
113 callback: function() {
114 me.reload();
115 }
116 });
117 }
118 });
119 }
120 }
121 ],
122
123 border: false,
124
125 set_button_status: function(rstore, records, success) {
126 if (!success || records.length < 1) {
127 return;
128 }
129 var me = this;
130 var found;
131 records.forEach(function(record) {
132 if (found) {
133 return;
134 }
135 var id = record.data.key;
136 var value = record.data.value;
137 var ciregex = new RegExp("vm-" + me.pveSelNode.data.vmid + "-cloudinit");
138 if (id.match(/^(ide|scsi|sata)\d+$/) && ciregex.test(value)) {
139 found = id;
140 me.ciDriveId = found;
141 me.ciDrive = value;
142 }
143 });
144
145 me.down('#savebtn').setDisabled(!found);
146 me.setDisabled(!found);
147 if (!found) {
148 me.getView().mask(gettext('No CloudInit Drive found'), ['pve-static-mask']);
149 } else {
150 me.getView().unmask();
151 }
152 },
153
154 renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
155 var me = this;
156 var rows = me.rows;
157 var rowdef = rows[key] || {};
158
159 var icon = "";
160 if (rowdef.iconCls) {
161 icon = '<i class="' + rowdef.iconCls + '"></i> ';
162 }
163 return icon + (rowdef.header || key);
164 },
165
166 listeners: {
167 activate: function () {
168 var me = this;
169 me.rstore.startUpdate();
170 },
171 itemdblclick: function() {
172 var me = this;
173 me.run_editor();
174 }
175 },
176
177 initComponent: function() {
178 var me = this;
179
180 var nodename = me.pveSelNode.data.node;
181 if (!nodename) {
182 throw "no node name specified";
183 }
184
185 var vmid = me.pveSelNode.data.vmid;
186 if (!vmid) {
187 throw "no VM ID specified";
188 }
189 var caps = Ext.state.Manager.get('GuiCap');
190 me.baseurl = '/api2/extjs/nodes/' + nodename + '/qemu/' + vmid;
191 me.url = me.baseurl + '/pending';
192 me.editorConfig.url = me.baseurl + '/config';
193 me.editorConfig.pveSelNode = me.pveSelNode;
194
044b08f2
ML
195 let caps_ci = caps.vms['VM.Config.Cloudinit'];
196 || caps.vms['VM.Config.Network'];
4c507192
DC
197 /* editor is string and object */
198 me.rows = {
199 ciuser: {
200 header: gettext('User'),
201 iconCls: 'fa fa-user',
202 never_delete: true,
203 defaultValue: '',
044b08f2 204 editor: caps_ci ? {
4c507192
DC
205 xtype: 'proxmoxWindowEdit',
206 subject: gettext('User'),
207 items: [
208 {
209 xtype: 'proxmoxtextfield',
210 deleteEmpty: true,
211 emptyText: Proxmox.Utils.defaultText,
212 fieldLabel: gettext('User'),
213 name: 'ciuser'
214 }
215 ]
216 } : undefined,
217 renderer: function(value) {
218 return value || Proxmox.Utils.defaultText;
219 }
220 },
221 cipassword: {
222 header: gettext('Password'),
223 iconCls: 'fa fa-unlock',
4c507192 224 defaultValue: '',
044b08f2 225 editor: caps_ci ? {
4c507192
DC
226 xtype: 'proxmoxWindowEdit',
227 subject: gettext('Password'),
228 items: [
229 {
230 xtype: 'proxmoxtextfield',
231 inputType: 'password',
232 deleteEmpty: true,
233 emptyText: Proxmox.Utils.noneText,
234 fieldLabel: gettext('Password'),
235 name: 'cipassword'
236 }
237 ]
238 } : undefined,
239 renderer: function(value) {
240 return value || Proxmox.Utils.noneText;
241 }
242 },
243 searchdomain: {
244 header: gettext('DNS domain'),
245 iconCls: 'fa fa-globe',
246 editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
247 never_delete: true,
248 defaultValue: gettext('use host settings')
249 },
250 nameserver: {
251 header: gettext('DNS servers'),
252 iconCls: 'fa fa-globe',
253 editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
254 never_delete: true,
255 defaultValue: gettext('use host settings')
256 },
257 sshkeys: {
258 header: gettext('SSH public key'),
259 iconCls: 'fa fa-key',
044b08f2 260 editor: caps_ci ? 'PVE.qemu.SSHKeyEdit' : undefined,
4c507192
DC
261 never_delete: true,
262 renderer: function(value) {
263 value = decodeURIComponent(value);
264 var keys = value.split('\n');
265 var text = [];
266 keys.forEach(function(key) {
267 if (key.length) {
268 // First erase all quoted strings (eg. command="foo"
269 var v = key.replace(/"(?:\\.|[^"\\])*"/g, '');
270 // Now try to detect the comment:
271 var res = v.match(/^\s*(\S+\s+)?(?:ssh-(?:dss|rsa|ed25519)|ecdsa-sha2-nistp\d+)\s+\S+\s+(.*?)\s*$/, '');
272 if (res) {
273 key = Ext.String.htmlEncode(res[2]);
274 if (res[1]) {
275 key += ' <span style="color:gray">(' + gettext('with options') + ')</span>';
276 }
277 text.push(key);
278 return;
279 }
280 // Most likely invalid at this point, so just stick to
281 // the old value.
282 text.push(Ext.String.htmlEncode(key));
283 }
284 });
285 if (text.length) {
286 return text.join('<br>');
287 } else {
288 return Proxmox.Utils.noneText;
289 }
290 },
291 defaultValue: ''
292 }
293 };
294 var i;
295 var ipconfig_renderer = function(value, md, record, ri, ci, store, pending) {
296 var id = record.data.key;
297 var match = id.match(/^net(\d+)$/);
298 var val = '';
299 if (match) {
300 val = me.getObjectValue('ipconfig'+match[1], '', pending);
301 }
302 return val;
303 };
304 for (i = 0; i < 32; i++) {
305 // we want to show an entry for every network device
306 // even if it is empty
307 me.rows['net' + i.toString()] = {
308 multiKey: ['ipconfig' + i.toString(), 'net' + i.toString()],
309 header: gettext('IP Config') + ' (net' + i.toString() +')',
310 editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.IPConfigEdit' : undefined,
311 iconCls: 'fa fa-exchange',
312 renderer: ipconfig_renderer
313 };
314 me.rows['ipconfig' + i.toString()] = {
315 visible: false
316 };
317 }
4c507192
DC
318
319 PVE.Utils.forEachBus(['ide', 'scsi', 'sata'], function(type, id) {
320 me.rows[type+id] = {
321 visible: false
322 };
323 });
324 me.callParent();
325 me.mon(me.rstore, 'load', me.set_button_status, me);
326 }
327});