]>
git.proxmox.com Git - pve-manager.git/blob - www/manager6/window/GuestImport.js
1 Ext
.define('PVE.window.GuestImport', {
2 extend
: 'Proxmox.window.Edit', // fixme: Proxmox.window.Edit?
3 alias
: 'widget.pveGuestImportWindow',
5 title
: gettext('Import Guest'),
7 submitUrl: function() {
9 return `/nodes/${me.nodename}/qemu`;
14 submitText
: gettext('Import'),
18 loadUrl: function(_url
, { storage
, nodename
, volumeName
}) {
19 let args
= Ext
.Object
.toQueryString({ volume
: volumeName
});
20 return `/nodes/${nodename}/storage/${storage}/import-metadata?${args}`;
24 xclass
: 'Ext.app.ViewController',
26 setNodename: function(_column
, widget
) {
28 let view
= me
.getView();
29 widget
.setNodename(view
.nodename
);
32 diskStorageChange: function(storageSelector
, value
) {
35 let grid
= me
.lookup('diskGrid');
36 let rec
= storageSelector
.getWidgetRecord();
37 let validFormats
= storageSelector
.store
.getById(value
)?.data
.format
;
38 grid
.query('pveDiskFormatSelector').some((selector
) => {
39 if (selector
.getWidgetRecord().data
.id
!== rec
.data
.id
) {
43 if (validFormats
?.[0]?.qcow2
) {
44 selector
.setDisabled(false);
45 selector
.setValue('qcow2');
47 selector
.setValue('raw');
48 selector
.setDisabled(true);
55 isoStorageChange: function(storageSelector
, value
) {
58 let grid
= me
.lookup('cdGrid');
59 let rec
= storageSelector
.getWidgetRecord();
60 grid
.query('pveFileSelector').some((selector
) => {
61 if (selector
.getWidgetRecord().data
.id
!== rec
.data
.id
) {
65 selector
.setStorage(value
);
67 selector
.setValue('');
74 onOSBaseChange: function(_field
, value
) {
76 let ostype
= me
.lookup('ostype');
77 let store
= ostype
.getStore();
78 store
.setData(PVE
.Utils
.kvm_ostypes
[value
]);
79 let old_val
= ostype
.getValue();
80 if (old_val
&& store
.find('val', old_val
) !== -1) {
81 ostype
.setValue(old_val
);
83 ostype
.setValue(store
.getAt(0));
87 calculateConfig: function() {
89 let inputPanel
= me
.lookup('mainInputPanel');
90 let summaryGrid
= me
.lookup('summaryGrid');
91 let values
= inputPanel
.getValues();
92 summaryGrid
.getStore().setData(Object
.entries(values
).map(([key
, value
]) => ({ key
, value
})));
97 // update records from widgetcolumns
98 change: function(widget
, value
) {
99 let rec
= widget
.getWidgetRecord();
100 rec
.set(widget
.name
, value
);
104 'grid[reference=diskGrid] pveStorageSelector': {
105 change
: 'diskStorageChange',
107 'grid[reference=cdGrid] pveStorageSelector': {
108 change
: 'isoStorageChange',
110 'field[name=osbase]': {
111 change
: 'onOSBaseChange',
113 'panel[reference=summaryTab]': {
114 activate
: 'calculateConfig',
128 totalCoreCount
: get => get('socketCount') * get('coreCount'),
129 hideWarnings
: get => get('warnings').length
=== 0,
130 warningsText
: get => '<ul style="margin: 0; padding-left: 20px;">'
131 + get('warnings').map(w
=> `<li>${w}</li>`).join('') + '</ul>',
132 liveImportNote
: get => !get('liveImport') ? ''
133 : gettext('Note: If anything goes wrong during the live-import, new data written by the VM may be lost.'),
148 title
: gettext('General'),
150 reference
: 'mainInputPanel',
151 onGetValues: function(values
) {
153 let grid
= me
.up('pveGuestImportWindow');
155 // from pveDiskStorageSelector
156 let defaultStorage
= values
.hdstorage
;
157 let defaultFormat
= values
.diskformat
;
158 delete values
.hdstorage
;
159 delete values
.diskformat
;
161 let defaultBridge
= values
.defaultBridge
;
162 delete values
.defaultBridge
;
164 let config
= Ext
.apply(grid
.vmConfig
, values
);
167 config
.scsi0
= config
.scsi0
.replace('local:0,', 'local:0,format=qcow2,');
170 grid
.lookup('diskGrid').getStore().each((rec
) => {
171 if (!rec
.data
.enable
) {
174 let id
= rec
.data
.id
;
182 data
.file
= defaultStorage
;
183 data
.format
= defaultFormat
;
185 data
.file
+= ':0'; // for our special api format
186 if (id
=== 'efidisk0') {
187 delete data
['import-from'];
189 config
[id
] = PVE
.Parser
.printQemuDrive(data
);
192 grid
.lookup('netGrid').getStore().each((rec
) => {
193 if (!rec
.data
.enable
) {
196 let id
= rec
.data
.id
;
203 data
.bridge
= defaultBridge
;
205 config
[id
] = PVE
.Parser
.printQemuNetwork(data
);
208 grid
.lookup('cdGrid').getStore().each((rec
) => {
209 if (!rec
.data
.enable
) {
212 let id
= rec
.data
.id
;
215 file
: rec
.data
.file
? rec
.data
.file
: 'none',
217 config
[id
] = PVE
.Parser
.printPropertyString(cd
);
220 if (grid
.lookup('liveimport').getValue()) {
221 config
['live-restore'] = 1;
229 xtype
: 'pveGuestIDSelector',
233 loadNextFreeID
: true,
236 xtype
: 'proxmoxintegerfield',
237 fieldLabel
: gettext('Sockets'),
239 reference
: 'socketsField',
245 value
: '{socketCount}',
249 xtype
: 'proxmoxintegerfield',
250 fieldLabel
: gettext('Cores'),
252 reference
: 'coresField',
258 value
: '{coreCount}',
262 xtype
: 'pveMemoryField',
263 fieldLabel
: gettext('Memory'),
265 reference
: 'memoryField',
271 xtype
: 'displayfield',
274 xtype
: 'pveDiskStorageSelector',
275 reference
: 'defaultStorage',
276 storageLabel
: gettext('Default Storage'),
277 storageContent
: 'images',
280 name
: 'defaultStorage',
287 fieldLabel
: gettext('Name'),
290 reference
: 'nameField',
294 xtype
: 'CPUModelSelector',
296 reference
: 'cputype',
297 value
: 'x86-64-v2-AES',
298 fieldLabel
: gettext('Type'),
301 xtype
: 'displayfield',
302 fieldLabel
: gettext('Total cores'),
306 value
: '{totalCoreCount}',
313 fieldLabel
: gettext('OS Type'),
317 store
: Object
.keys(PVE
.Utils
.kvm_ostypes
),
323 fieldLabel
: gettext('Version'),
329 displayField
: 'desc',
331 fields
: ['desc', 'val'],
332 data
: PVE
.Utils
.kvm_ostypes
.Linux
,
336 xtype
: 'PVE.form.BridgeSelector',
337 reference
: 'defaultBridge',
338 name
: 'defaultBridge',
340 fieldLabel
: gettext('Default Bridge'),
346 xtype
: 'proxmoxcheckbox',
347 fieldLabel
: gettext('Live Import'),
348 reference
: 'liveimport',
350 boxLabelCls
: 'pmx-hint black x-form-cb-label',
352 value
: '{liveImport}',
353 boxLabel
: '{liveImportNote}',
357 xtype
: 'displayfield',
358 fieldLabel
: gettext('Warnings'),
362 hidden
: '{hideWarnings}',
366 xtype
: 'displayfield',
367 reference
: 'warningText',
371 hidden
: '{hideWarnings}',
372 value
: '{warningsText}',
378 title
: gettext('Advanced'),
382 xtype
: 'displayfield',
383 fieldLabel
: gettext('Disks'),
388 reference
: 'diskGrid',
399 xtype
: 'checkcolumn',
400 header
: gettext('Use'),
404 checkchange: function(_column
, _rowIndex
, _checked
, record
) {
410 text
: gettext('Disk'),
414 text
: gettext('Source'),
415 dataIndex
: 'import-from',
417 renderer: function(value
) {
418 return value
.replace(/^.*\//, '');
422 text
: gettext('Size'),
424 renderer
: (value
) => {
425 if (Ext
.isNumeric(value
)) {
426 return Proxmox
.Utils
.render_size(value
);
428 return value
?? Proxmox
.Utils
.unknownText
;
432 text
: gettext('Storage'),
434 xtype
: 'widgetcolumn',
437 xtype
: 'pveStorageSelector',
441 emptyText
: gettext('From Default'),
443 storageContent
: 'images',
445 onWidgetAttach
: 'setNodename',
448 text
: gettext('Format'),
450 xtype
: 'widgetcolumn',
453 xtype
: 'pveDiskFormatSelector',
457 matchFieldWidth
: false,
463 xtype
: 'displayfield',
464 fieldLabel
: gettext('CD/DVD Drives'),
480 xtype
: 'checkcolumn',
481 header
: gettext('Use'),
485 checkchange: function(_column
, _rowIndex
, _checked
, record
) {
491 text
: gettext('Slot'),
496 text
: gettext('Storage'),
497 xtype
: 'widgetcolumn',
500 xtype
: 'pveStorageSelector',
504 emptyText
: Proxmox
.Utils
.noneText
,
505 storageContent
: 'iso',
507 onWidgetAttach
: 'setNodename',
510 text
: gettext('ISO'),
512 xtype
: 'widgetcolumn',
515 xtype
: 'pveFileSelector',
519 emptyText
: Proxmox
.Utils
.noneText
,
520 storageContent
: 'iso',
522 onWidgetAttach
: 'setNodename',
527 xtype
: 'displayfield',
528 fieldLabel
: gettext('Network Interfaces'),
535 reference
: 'netGrid',
544 xtype
: 'checkcolumn',
545 header
: gettext('Use'),
549 checkchange: function(_column
, _rowIndex
, _checked
, record
) {
559 text
: gettext('MAC address'),
561 dataIndex
: 'macaddr',
562 renderer
: value
=> value
?? 'auto',
565 text
: gettext('Model'),
568 xtype
: 'widgetcolumn',
570 xtype
: 'pveNetworkCardSelector',
577 text
: gettext('Bridge'),
579 xtype
: 'widgetcolumn',
582 xtype
: 'PVE.form.BridgeSelector',
587 emptyText
: gettext('From Default'),
589 onWidgetAttach
: 'setNodename',
596 title
: gettext('Resulting Config'),
597 reference
: 'summaryTab',
601 reference
: 'summaryGrid',
612 { header
: 'Key', width
: 150, dataIndex
: 'key' },
613 { header
: 'Value', flex
: 1, dataIndex
: 'value' },
622 initComponent: function() {
625 if (!me
.volumeName
) {
626 throw "no volumeName given";
630 throw "no storage given";
634 throw "no nodename given";
639 me
.setTitle(Ext
.String
.format(gettext('Import Guest - {0}'), `${me.storage}:${me.volumeName}`));
641 me
.lookup('defaultStorage').setNodename(me
.nodename
);
642 me
.lookup('defaultBridge').setNodename(me
.nodename
);
644 let renderWarning
= w
=> {
645 const warningsCatalogue
= {
646 'cdrom-image-ignored': gettext("CD-ROM images cannot get imported, if required you can reconfigure the '{0}' drive in the 'Advanced' tab."),
647 'nvme-unsupported': gettext("NVMe disks are currently not supported, '{0}' will get attaced as SCSI"),
648 'ovmf-with-lsi-unsupported': gettext("OVMF is built without LSI drivers, scsi hardware was set to '{1}'"),
649 'serial-port-socket-only': gettext("Serial socket '{0}' will be mapped to a socket"),
650 'guest-is-running': gettext('Virtual guest seems to be running on source host. Import might fail or have inconsistent state!'),
652 let message
= warningsCatalogue
[w
.type
];
653 if (!w
.type
|| !message
) {
654 return w
.message
?? w
.type
?? gettext('Unknown warning');
656 return Ext
.String
.format(message
, w
.key
?? 'unknown', w
.value
?? 'unknown');
660 success: function(response
) {
661 let data
= response
.result
.data
;
662 me
.vmConfig
= data
['create-args'];
665 for (const [id
, value
] of Object
.entries(data
.disks
?? {})) {
666 let volid
= Ext
.htmlEncode('<none>');
668 if (Ext
.isObject(value
)) {
676 'import-from': volid
,
682 for (const [id
, parsed
] of Object
.entries(data
.net
?? {})) {
684 parsed
.enable
= true;
689 for (const [id
, value
] of Object
.entries(me
.vmConfig
)) {
690 if (!Ext
.isString(value
) || !value
.match(/media=cdrom/)) {
697 delete me
.vmConfig
[id
];
699 me
.lookup('diskGrid').getStore().setData(disks
);
700 me
.lookup('netGrid').getStore().setData(nets
);
701 me
.lookup('cdGrid').getStore().setData(cdroms
);
703 me
.getViewModel().set('warnings', data
.warnings
.map(w
=> renderWarning(w
)));
705 let osinfo
= PVE
.Utils
.get_kvm_osinfo(me
.vmConfig
.ostype
?? '');