]> git.proxmox.com Git - pve-manager.git/blobdiff - www/manager6/window/Migrate.js
ui: guest import: move live import checkbox into panel
[pve-manager.git] / www / manager6 / window / Migrate.js
index 817d99ed3ec2c2b8f64d3fc68fd6b8a9bb73e255..5473821b9416b70accefa9e4adba0883979f62be 100644 (file)
@@ -92,19 +92,17 @@ Ext.define('PVE.window.Migrate', {
            }
            vm.set('vmtype', view.vmtype);
 
-
            view.setTitle(
                Ext.String.format('{0} {1} {2}', gettext('Migrate'), vm.get(view.vmtype).commonName, view.vmid),
            );
            me.lookup('proxmoxHelpButton').setHelpConfig({
                onlineHelp: vm.get(view.vmtype).onlineHelp,
            });
-           me.checkMigratePreconditions();
            me.lookup('formPanel').isValid();
        },
 
        onTargetChange: function(nodeSelector) {
-           //Always display the storages of the currently seleceted migration target
+           // Always display the storages of the currently seleceted migration target
            this.lookup('pveDiskStorageSelector').setNodename(nodeSelector.value);
            this.checkMigratePreconditions();
        },
@@ -157,7 +155,7 @@ Ext.define('PVE.window.Migrate', {
            });
        },
 
-       checkMigratePreconditions: function(resetMigrationPossible) {
+       checkMigratePreconditions: async function(resetMigrationPossible) {
            var me = this,
                vm = me.getViewModel();
 
@@ -167,12 +165,13 @@ Ext.define('PVE.window.Migrate', {
                vm.set('running', true);
            }
 
+           me.lookup('pveNodeSelector').disallowedNodes = [vm.get('nodename')];
+
            if (vm.get('vmtype') === 'qemu') {
-               me.checkQemuPreconditions(resetMigrationPossible);
+               await me.checkQemuPreconditions(resetMigrationPossible);
            } else {
                me.checkLxcPreconditions(resetMigrationPossible);
            }
-           me.lookup('pveNodeSelector').disallowedNodes = [vm.get('nodename')];
 
            // Only allow nodes where the local storage is available in case of offline migration
            // where storage migration is not possible
@@ -181,8 +180,8 @@ Ext.define('PVE.window.Migrate', {
            me.lookup('formPanel').isValid();
        },
 
-       checkQemuPreconditions: function(resetMigrationPossible) {
-           var me = this,
+       checkQemuPreconditions: async function(resetMigrationPossible) {
+           let me = this,
                vm = me.getViewModel(),
                migrateStats;
 
@@ -190,103 +189,128 @@ Ext.define('PVE.window.Migrate', {
                vm.set('migration.mode', 'online');
            }
 
-           Proxmox.Utils.API2Request({
-               url: '/nodes/' + vm.get('nodename') + '/' + vm.get('vmtype') + '/' + vm.get('vmid') + '/migrate',
-               method: 'GET',
-               failure: function(response, opts) {
-                   Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-               },
-               success: function(response, options) {
-                   migrateStats = response.result.data;
-                   if (migrateStats.running) {
-                       vm.set('running', true);
+           try {
+               if (me.fetchingNodeMigrateInfo && me.fetchingNodeMigrateInfo === vm.get('nodename')) {
+                   return;
+               }
+               me.fetchingNodeMigrateInfo = vm.get('nodename');
+               let { result } = await Proxmox.Async.api2({
+                   url: `/nodes/${vm.get('nodename')}/${vm.get('vmtype')}/${vm.get('vmid')}/migrate`,
+                   method: 'GET',
+               });
+               migrateStats = result.data;
+               me.fetchingNodeMigrateInfo = false;
+           } catch (error) {
+               Ext.Msg.alert(gettext('Error'), error.htmlStatus);
+               return;
+           }
+
+           if (migrateStats.running) {
+               vm.set('running', true);
+           }
+           // Get migration object from viewmodel to prevent to many bind callbacks
+           let migration = vm.get('migration');
+           if (resetMigrationPossible) {
+               migration.possible = true;
+           }
+           migration.preconditions = [];
+
+           if (migrateStats.allowed_nodes) {
+               migration.allowedNodes = migrateStats.allowed_nodes;
+               let target = me.lookup('pveNodeSelector').value;
+               if (target.length && !migrateStats.allowed_nodes.includes(target)) {
+                   let disallowed = migrateStats.not_allowed_nodes[target] ?? {};
+                   if (disallowed.unavailable_storages !== undefined) {
+                       let missingStorages = disallowed.unavailable_storages.join(', ');
+
+                       migration.possible = false;
+                       migration.preconditions.push({
+                           text: 'Storage (' + missingStorages + ') not available on selected target. ' +
+                             'Start VM to use live storage migration or select other target node',
+                           severity: 'error',
+                       });
                    }
-                   // Get migration object from viewmodel to prevent
-                   // to many bind callbacks
-                   var migration = vm.get('migration');
-                   if (resetMigrationPossible) migration.possible = true;
-                   migration.preconditions = [];
-
-                   if (migrateStats.allowed_nodes) {
-                       migration.allowedNodes = migrateStats.allowed_nodes;
-                       var target = me.lookup('pveNodeSelector').value;
-                       if (target.length && !migrateStats.allowed_nodes.includes(target)) {
-                           let disallowed = migrateStats.not_allowed_nodes[target];
-                           let missing_storages = disallowed.unavailable_storages.join(', ');
 
-                           migration.possible = false;
-                           migration.preconditions.push({
-                               text: 'Storage (' + missing_storages + ') not available on selected target. ' +
-                                 'Start VM to use live storage migration or select other target node',
-                               severity: 'error',
-                           });
-                       }
+                   if (disallowed['unavailable-resources'] !== undefined) {
+                       let unavailableResources = disallowed['unavailable-resources'].join(', ');
+
+                       migration.possible = false;
+                       migration.preconditions.push({
+                           text: 'Mapped Resources (' + unavailableResources + ') not available on selected target. ',
+                           severity: 'error',
+                       });
                    }
+               }
+           }
+
+           let blockingResources = [];
+           let mappedResources = migrateStats['mapped-resources'] ?? [];
 
-                   if (migrateStats.local_resources.length) {
-                       migration.hasLocalResources = true;
-                       if (!migration.overwriteLocalResourceCheck || vm.get('running')) {
+           for (const res of migrateStats.local_resources) {
+               if (mappedResources.indexOf(res) === -1) {
+                   blockingResources.push(res);
+               }
+           }
+
+           if (blockingResources.length) {
+               migration.hasLocalResources = true;
+               if (!migration.overwriteLocalResourceCheck || vm.get('running')) {
+                   migration.possible = false;
+                   migration.preconditions.push({
+                       text: Ext.String.format('Can\'t migrate VM with local resources: {0}',
+                       blockingResources.join(', ')),
+                       severity: 'error',
+                   });
+               } else {
+                   migration.preconditions.push({
+                       text: Ext.String.format('Migrate VM with local resources: {0}. ' +
+                       'This might fail if resources aren\'t available on the target node.',
+                       blockingResources.join(', ')),
+                       severity: 'warning',
+                   });
+               }
+           }
+
+           if (mappedResources && mappedResources.length) {
+               if (vm.get('running')) {
+                   migration.possible = false;
+                   migration.preconditions.push({
+                       text: Ext.String.format('Can\'t migrate running VM with mapped resources: {0}',
+                       mappedResources.join(', ')),
+                       severity: 'error',
+                   });
+               }
+           }
+
+           if (migrateStats.local_disks.length) {
+               migrateStats.local_disks.forEach(function(disk) {
+                   if (disk.cdrom && disk.cdrom === 1) {
+                       if (!disk.volid.includes('vm-' + vm.get('vmid') + '-cloudinit')) {
                            migration.possible = false;
                            migration.preconditions.push({
-                               text: Ext.String.format('Can\'t migrate VM with local resources: {0}',
-                               migrateStats.local_resources.join(', ')),
+                               text: "Can't migrate VM with local CD/DVD",
                                severity: 'error',
                            });
-                       } else {
-                           migration.preconditions.push({
-                               text: Ext.String.format('Migrate VM with local resources: {0}. ' +
-                               'This might fail if resources aren\'t available on the target node.',
-                               migrateStats.local_resources.join(', ')),
-                               severity: 'warning',
-                           });
                        }
-                   }
-
-                   if (migrateStats.local_disks.length) {
-                       migrateStats.local_disks.forEach(function(disk) {
-                           if (disk.cdrom && disk.cdrom === 1) {
-                               if (disk.volid.includes('vm-'+vm.get('vmid')+'-cloudinit')) {
-                                   if (migrateStats.running) {
-                                       migration.possible = false;
-                                       migration.preconditions.push({
-                                            text: "Can't live migrate VM with local cloudinit disk, use shared storage instead",
-                                            severity: 'error',
-                                       });
-                                   } else {
-                                       return;
-                                   }
-                               } else {
-                                   migration.possible = false;
-                                   migration.preconditions.push({
-                                       text: "Can't migrate VM with local CD/DVD",
-                                       severity: 'error',
-                                   });
-                               }
-                           } else {
-                               var size_string = disk.size ? '(' + PVE.Utils.render_size(disk.size) + ')' : '';
-                               migration['with-local-disks'] = 1;
-                               migration.preconditions.push({
-                                   text: Ext.String.format('Migration with local disk might take long: {0} {1}',
-                                         disk.volid, size_string),
-                                   severity: 'warning',
-                               });
-                           }
+                   } else {
+                       let size = disk.size ? '(' + Proxmox.Utils.render_size(disk.size) + ')' : '';
+                       migration['with-local-disks'] = 1;
+                       migration.preconditions.push({
+                           text: Ext.String.format('Migration with local disk might take long: {0} {1}', disk.volid, size),
+                           severity: 'warning',
                        });
                    }
+               });
+           }
 
-                   vm.set('migration', migration);
-               },
-           });
+           vm.set('migration', migration);
        },
        checkLxcPreconditions: function(resetMigrationPossible) {
-           var me = this,
-               vm = me.getViewModel();
+           let vm = this.getViewModel();
            if (vm.get('running')) {
                vm.set('migration.mode', 'restart');
            }
        },
-
-
     },
 
     width: 600,
@@ -365,7 +389,10 @@ Ext.define('PVE.window.Migrate', {
                            value: '{migration.overwriteLocalResourceCheck}',
                        },
                        listeners: {
-                           change: { fn: 'checkMigratePreconditions', extraArg: true },
+                           change: {
+                               fn: 'checkMigratePreconditions',
+                               extraArg: true,
+                           },
                        },
                }],
                },