]>
git.proxmox.com Git - pve-manager.git/blob - www/manager6/window/Migrate.js
1 /*jslint confusion: true*/
2 Ext
.define('PVE.window.Migrate', {
3 extend
: 'Ext.window.Window',
16 onlineHelp
: 'qm_migration',
20 onlineHelp
: 'pct_migration',
26 'with-local-disks': 0,
28 allowedNodes
: undefined
34 setMigrationMode: function(get) {
36 if (get('vmtype') === 'qemu') {
37 return gettext('Online');
39 return gettext('Restart Mode');
42 return gettext('Offline');
45 setStorageselectorHidden: function(get) {
46 if (get('migration.with-local-disks') && get('running')) {
56 xclass
: 'Ext.app.ViewController',
58 'panel[reference=formPanel]': {
59 validityChange: function(panel
, isValid
) {
60 this.getViewModel().set('migration.possible', isValid
);
61 this.checkMigratePreconditions();
66 init: function(view
) {
68 vm
= view
.getViewModel();
71 throw "missing custom view config: nodename";
73 vm
.set('nodename', view
.nodename
);
76 throw "missing custom view config: vmid";
78 vm
.set('vmid', view
.vmid
);
81 throw "missing custom view config: vmtype";
83 vm
.set('vmtype', view
.vmtype
);
87 Ext
.String
.format('{0} {1}{2}', gettext('Migrate'), vm
.get(view
.vmtype
).commonName
, view
.vmid
)
89 me
.lookup('proxmoxHelpButton').setHelpConfig({
90 onlineHelp
: vm
.get(view
.vmtype
).onlineHelp
92 me
.checkMigratePreconditions();
93 me
.lookup('formPanel').isValid();
97 onTargetChange: function (nodeSelector
) {
98 //Always display the storages of the currently seleceted migration target
99 this.lookup('pveDiskStorageSelector').setNodename(nodeSelector
.value
);
100 this.checkMigratePreconditions();
103 startMigration: function() {
106 vm
= me
.getViewModel();
108 var values
= me
.lookup('formPanel').getValues();
110 target
: values
.target
113 if (vm
.get('migration.mode')) {
114 params
[vm
.get('migration.mode')] = 1;
116 if (vm
.get('migration.with-local-disks')) {
117 params
['with-local-disks'] = 1;
119 //only submit targetstorage if vm is running, storage migration to different storage is only possible online
120 if (vm
.get('migration.with-local-disks') && vm
.get('running')) {
121 params
.targetstorage
= values
.targetstorage
;
124 Proxmox
.Utils
.API2Request({
126 url
: '/nodes/' + vm
.get('nodename') + '/' + vm
.get('vmtype') + '/' + vm
.get('vmid') + '/migrate',
129 failure: function(response
, opts
) {
130 Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
);
132 success: function(response
, options
) {
133 var upid
= response
.result
.data
;
134 var extraTitle
= Ext
.String
.format(' ({0} ---> {1})', vm
.get('nodename'), params
.target
);
136 Ext
.create('Proxmox.window.TaskViewer', {
138 extraTitle
: extraTitle
147 checkMigratePreconditions: function() {
149 vm
= me
.getViewModel();
152 var vmrec
= PVE
.data
.ResourceStore
.findRecord('vmid', vm
.get('vmid'),
153 0, false, false, true);
154 if (vmrec
&& vmrec
.data
&& vmrec
.data
.running
) {
155 vm
.set('running', true);
158 if (vm
.get('vmtype') === 'qemu') {
159 me
.checkQemuPreconditions();
161 me
.checkLxcPreconditions();
163 me
.lookup('pveNodeSelector').disallowedNodes
= [vm
.get('nodename')];
165 // Only allow nodes where the local storage is available in case of offline migration
166 // where storage migration is not possible
167 me
.lookup('pveNodeSelector').allowedNodes
= vm
.get('migration.allowedNodes');
169 me
.lookup('formPanel').isValid();
173 checkQemuPreconditions: function() {
175 vm
= me
.getViewModel(),
178 if (vm
.get('running')) {
179 vm
.set('migration.mode', 'online');
182 Proxmox
.Utils
.API2Request({
183 url
: '/nodes/' + vm
.get('nodename') + '/' + vm
.get('vmtype') + '/' + vm
.get('vmid') + '/migrate',
185 failure: function(response
, opts
) {
186 Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
);
188 success: function(response
, options
) {
189 migrateStats
= response
.result
.data
;
190 if (migrateStats
.running
) {
191 vm
.set('running', true);
193 // Get migration object from viewmodel to prevent
194 // to many bind callbacks
195 var migration
= vm
.get('migration');
196 migration
.preconditions
= [];
198 if (migrateStats
.allowed_nodes
) {
199 migration
.allowedNodes
= migrateStats
.allowed_nodes
;
200 var target
= me
.lookup('pveNodeSelector').value
;
201 if (target
.length
&& !migrateStats
.allowed_nodes
.includes(target
)) {
202 let disallowed
= migrateStats
.not_allowed_nodes
[target
];
203 let missing_storages
= disallowed
.unavailable_storages
.join(', ');
205 migration
.possible
= false;
206 migration
.preconditions
.push({
207 text
: 'Storage (' + missing_storages
+ ') not available on selected target. ' +
208 'Start VM to use live storage migration or select other target node',
214 if (migrateStats
.local_resources
.length
) {
215 migration
.possible
= false;
216 migration
.preconditions
.push({
217 text
: 'Can\'t migrate VM with local resources: '+ migrateStats
.local_resources
.join(', '),
222 if (migrateStats
.local_disks
.length
) {
224 migrateStats
.local_disks
.forEach(function (disk
) {
225 if (disk
.cdrom
&& disk
.cdrom
=== 1) {
226 migration
.possible
= false;
227 migration
.preconditions
.push({
228 text
: "Can't migrate VM with local CD/DVD",
232 } else if (!disk
.referenced_in_config
) {
233 migration
.possible
= false;
234 migration
.preconditions
.push({
235 text
: 'Found not referenced/unused disk via storage: '+ disk
.volid
,
239 migration
['with-local-disks'] = 1;
240 migration
.preconditions
.push({
241 text
:'Migration with local disk might take long: ' + disk
.volid
242 +' (' + PVE
.Utils
.render_size(disk
.size
) + ')',
250 vm
.set('migration', migration
);
255 checkLxcPreconditions: function() {
257 vm
= me
.getViewModel();
258 if (vm
.get('running')) {
259 vm
.set('migration.mode', 'restart');
276 reference
: 'formPanel',
287 xtype
: 'displayfield',
289 fieldLabel
: gettext('Source node'),
295 xtype
: 'displayfield',
296 reference
: 'migrationMode',
297 fieldLabel
: gettext('Mode'),
299 value
: '{setMigrationMode}'
307 xtype
: 'pveNodeSelector',
308 reference
: 'pveNodeSelector',
310 fieldLabel
: gettext('Target node'),
312 disallowedNodes
: undefined,
313 onlineValidator
: true,
315 change
: 'onTargetChange'
319 xtype
: 'pveStorageSelector',
320 reference
: 'pveDiskStorageSelector',
321 name
: 'targetstorage',
322 fieldLabel
: gettext('Target storage'),
323 storageContent
: 'images',
325 hidden
: '{setStorageselectorHidden}'
333 reference
: 'preconditionGrid',
338 dataIndex
: 'severity',
339 renderer: function(v
) {
342 return '<i class="fa fa-exclamation-triangle warning"></i> ';
344 return '<i class="fa fa-times critical"></i>';
358 hidden
: '{!migration.preconditions.length}',
360 fields
: ['severity','text'],
361 data
: '{migration.preconditions}'
369 xtype
: 'proxmoxHelpButton',
370 reference
: 'proxmoxHelpButton',
371 onlineHelp
: 'pct_migration',
372 listenToGlobalEvent
: false,
378 reference
: 'submitButton',
379 text
: gettext('Migrate'),
380 handler
: 'startMigration',
382 disabled
: '{!migration.possible}'