Use build-in selector and respect limits in client
Use the new built-in selector option, as well as respecting node limits, when performing migrate or move actions on a VM via the clients.
This commit is contained in:
		@@ -425,12 +425,12 @@ def vm_stop(name):
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    return flask.jsonify(output), retcode
 | 
					    return flask.jsonify(output), retcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def vm_move(name, node, selector):
 | 
					def vm_move(name, node):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Move a VM to another node.
 | 
					    Move a VM to another node.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    zk_conn = pvc_common.startZKConnection(config['coordinators'])
 | 
					    zk_conn = pvc_common.startZKConnection(config['coordinators'])
 | 
				
			||||||
    retflag, retdata = pvc_vm.move_vm(zk_conn, name, node, selector)
 | 
					    retflag, retdata = pvc_vm.move_vm(zk_conn, name, node)
 | 
				
			||||||
    if retflag:
 | 
					    if retflag:
 | 
				
			||||||
        retcode = 200
 | 
					        retcode = 200
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
@@ -442,12 +442,12 @@ def vm_move(name, node, selector):
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    return flask.jsonify(output), retcode
 | 
					    return flask.jsonify(output), retcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def vm_migrate(name, node, selector, flag_force):
 | 
					def vm_migrate(name, node, flag_force):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Temporarily migrate a VM to another node.
 | 
					    Temporarily migrate a VM to another node.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    zk_conn = pvc_common.startZKConnection(config['coordinators'])
 | 
					    zk_conn = pvc_common.startZKConnection(config['coordinators'])
 | 
				
			||||||
    retflag, retdata = pvc_vm.migrate_vm(zk_conn, name, node, selector, flag_force)
 | 
					    retflag, retdata = pvc_vm.migrate_vm(zk_conn, name, node, flag_force)
 | 
				
			||||||
    if retflag:
 | 
					    if retflag:
 | 
				
			||||||
        retcode = 200
 | 
					        retcode = 200
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -338,11 +338,6 @@ def api_vm_node(vm):
 | 
				
			|||||||
            node = flask.request.values['node']
 | 
					            node = flask.request.values['node']
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            node = None
 | 
					            node = None
 | 
				
			||||||
        # Get target selector
 | 
					 | 
				
			||||||
        if 'selector' in flask.request.values:
 | 
					 | 
				
			||||||
            selector = flask.request.values['selector']
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            selector = None
 | 
					 | 
				
			||||||
        # Get permanent flag
 | 
					        # Get permanent flag
 | 
				
			||||||
        if 'permanent' in flask.request.values and flask.request.values['permanent']:
 | 
					        if 'permanent' in flask.request.values and flask.request.values['permanent']:
 | 
				
			||||||
            flag_permanent = True
 | 
					            flag_permanent = True
 | 
				
			||||||
@@ -358,9 +353,9 @@ def api_vm_node(vm):
 | 
				
			|||||||
        is_migrated = pvcapi.vm_is_migrated(vm)
 | 
					        is_migrated = pvcapi.vm_is_migrated(vm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if action == 'migrate' and not flag_permanent:
 | 
					        if action == 'migrate' and not flag_permanent:
 | 
				
			||||||
            return pvcapi.vm_migrate(vm, node, selector, flag_force)
 | 
					            return pvcapi.vm_migrate(vm, node, flag_force)
 | 
				
			||||||
        if action == 'migrate' and flag_permanent:
 | 
					        if action == 'migrate' and flag_permanent:
 | 
				
			||||||
            return pvcapi.vm_move(vm, node, selector)
 | 
					            return pvcapi.vm_move(vm, node)
 | 
				
			||||||
        if action == 'unmigrate' and is_migrated:
 | 
					        if action == 'unmigrate' and is_migrated:
 | 
				
			||||||
            return pvcapi.vm_unmigrate(vm)
 | 
					            return pvcapi.vm_unmigrate(vm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -520,19 +520,14 @@ def vm_stop(domain):
 | 
				
			|||||||
    '-t', '--target', 'target_node', default=None,
 | 
					    '-t', '--target', 'target_node', default=None,
 | 
				
			||||||
    help='Target node to migrate to; autodetect if unspecified.'
 | 
					    help='Target node to migrate to; autodetect if unspecified.'
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@click.option(
 | 
					def vm_move(domain, target_node):
 | 
				
			||||||
    '-s', '--selector', 'selector', default='mem', show_default=True,
 | 
					 | 
				
			||||||
    type=click.Choice(['mem','load','vcpus','vms']),
 | 
					 | 
				
			||||||
    help='Method to determine optimal target node during autodetect.'
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
def vm_move(domain, target_node, selector):
 | 
					 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Permanently move virtual machine DOMAIN, via live migration if running and possible, to another node. DOMAIN may be a UUID or name.
 | 
					    Permanently move virtual machine DOMAIN, via live migration if running and possible, to another node. DOMAIN may be a UUID or name.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Open a Zookeeper connection
 | 
					    # Open a Zookeeper connection
 | 
				
			||||||
    zk_conn = pvc_common.startZKConnection(zk_host)
 | 
					    zk_conn = pvc_common.startZKConnection(zk_host)
 | 
				
			||||||
    retcode, retmsg = pvc_vm.move_vm(zk_conn, domain, target_node, selector)
 | 
					    retcode, retmsg = pvc_vm.move_vm(zk_conn, domain, target_node)
 | 
				
			||||||
    cleanup(retcode, retmsg, zk_conn)
 | 
					    cleanup(retcode, retmsg, zk_conn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
###############################################################################
 | 
					###############################################################################
 | 
				
			||||||
@@ -546,23 +541,18 @@ def vm_move(domain, target_node, selector):
 | 
				
			|||||||
    '-t', '--target', 'target_node', default=None,
 | 
					    '-t', '--target', 'target_node', default=None,
 | 
				
			||||||
    help='Target node to migrate to; autodetect if unspecified.'
 | 
					    help='Target node to migrate to; autodetect if unspecified.'
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@click.option(
 | 
					 | 
				
			||||||
    '-s', '--selector', 'selector', default='mem', show_default=True,
 | 
					 | 
				
			||||||
    type=click.Choice(['mem','load','vcpus','vms']),
 | 
					 | 
				
			||||||
    help='Method to determine optimal target node during autodetect.'
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
@click.option(
 | 
					@click.option(
 | 
				
			||||||
    '-f', '--force', 'force_migrate', is_flag=True, default=False,
 | 
					    '-f', '--force', 'force_migrate', is_flag=True, default=False,
 | 
				
			||||||
    help='Force migrate an already migrated VM; does not replace an existing previous node value.'
 | 
					    help='Force migrate an already migrated VM; does not replace an existing previous node value.'
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
def vm_migrate(domain, target_node, selector, force_migrate):
 | 
					def vm_migrate(domain, target_node, force_migrate):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Temporarily migrate running virtual machine DOMAIN, via live migration if possible, to another node. DOMAIN may be a UUID or name. If DOMAIN is not running, it will be started on the target node.
 | 
					    Temporarily migrate running virtual machine DOMAIN, via live migration if possible, to another node. DOMAIN may be a UUID or name. If DOMAIN is not running, it will be started on the target node.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Open a Zookeeper connection
 | 
					    # Open a Zookeeper connection
 | 
				
			||||||
    zk_conn = pvc_common.startZKConnection(zk_host)
 | 
					    zk_conn = pvc_common.startZKConnection(zk_host)
 | 
				
			||||||
    retcode, retmsg = pvc_vm.migrate_vm(zk_conn, domain, target_node, selector, force_migrate, is_cli=True)
 | 
					    retcode, retmsg = pvc_vm.migrate_vm(zk_conn, domain, target_node, force_migrate, is_cli=True)
 | 
				
			||||||
    cleanup(retcode, retmsg, zk_conn)
 | 
					    cleanup(retcode, retmsg, zk_conn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
###############################################################################
 | 
					###############################################################################
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -288,18 +288,46 @@ def getPrimaryNode(zk_conn):
 | 
				
			|||||||
    return primary_node
 | 
					    return primary_node
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Get the list of valid target nodes
 | 
					# Find a migration target
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
def getNodes(zk_conn, dom_uuid):
 | 
					def findTargetHypervisor(zk_conn, config, dom_uuid):
 | 
				
			||||||
 | 
					    # Determine VM node limits; set config value if read fails
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        node_limit = zkhandler.readdata(zk_conn, '/domains/{}/node_limit'.format(node)).split(',')
 | 
				
			||||||
 | 
					    except:
 | 
				
			||||||
 | 
					        node_limit = None
 | 
				
			||||||
 | 
					        zkhandler.writedata(zk_conn, { '/domains/{}/node_limit'.format(node): 'None' })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Determine VM search field or use default; set config value if read fails
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        search_field = zkhandler.readdata(zk_conn, '/domains/{}/node_selector'.format(node)).split(',')
 | 
				
			||||||
 | 
					    except:
 | 
				
			||||||
 | 
					        search_field = config.migration_target_selector
 | 
				
			||||||
 | 
					        zkhandler.writedata(zk_conn, { '/domains/{}/node_selector'.format(node): config.migration_target_selector })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Execute the search
 | 
				
			||||||
 | 
					    if search_field == 'mem':
 | 
				
			||||||
 | 
					        return findTargetHypervisorMem(zk_conn, node_limit, dom_uuid)
 | 
				
			||||||
 | 
					    if search_field == 'load':
 | 
				
			||||||
 | 
					        return findTargetHypervisorLoad(zk_conn, node_limit, dom_uuid)
 | 
				
			||||||
 | 
					    if search_field == 'vcpus':
 | 
				
			||||||
 | 
					        return findTargetHypervisorVCPUs(zk_conn, node_limit, dom_uuid)
 | 
				
			||||||
 | 
					    if search_field == 'vms':
 | 
				
			||||||
 | 
					        return findTargetHypervisorVMs(zk_conn, node_limit, dom_uuid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Nothing was found
 | 
				
			||||||
 | 
					    return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Get the list of valid target nodes
 | 
				
			||||||
 | 
					def getHypervisors(zk_conn, node_limit, dom_uuid):
 | 
				
			||||||
    valid_node_list = []
 | 
					    valid_node_list = []
 | 
				
			||||||
    full_node_list = zkhandler.listchildren(zk_conn, '/nodes')
 | 
					    full_node_list = zkhandler.listchildren(zk_conn, '/nodes')
 | 
				
			||||||
 | 
					    current_node = zkhandler.readdata(zk_conn, '/domains/{}/node'.format(dom_uuid))
 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        current_node = zkhandler.readdata(zk_conn, '/domains/{}/node'.format(dom_uuid))
 | 
					 | 
				
			||||||
    except:
 | 
					 | 
				
			||||||
        current_node = None
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for node in full_node_list:
 | 
					    for node in full_node_list:
 | 
				
			||||||
 | 
					        if node_limit and node not in node_limit:
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        daemon_state = zkhandler.readdata(zk_conn, '/nodes/{}/daemonstate'.format(node))
 | 
					        daemon_state = zkhandler.readdata(zk_conn, '/nodes/{}/daemonstate'.format(node))
 | 
				
			||||||
        domain_state = zkhandler.readdata(zk_conn, '/nodes/{}/domainstate'.format(node))
 | 
					        domain_state = zkhandler.readdata(zk_conn, '/nodes/{}/domainstate'.format(node))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -311,64 +339,50 @@ def getNodes(zk_conn, dom_uuid):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        valid_node_list.append(node)
 | 
					        valid_node_list.append(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if not valid_node_list:
 | 
					 | 
				
			||||||
        # We found no valid nodes; possibly they're all flushed or all down. Return the entire list instead.
 | 
					 | 
				
			||||||
        valid_node_list = full_node_list
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return valid_node_list
 | 
					    return valid_node_list
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Find a migration target
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
def findTargetNode(zk_conn, search_field, dom_uuid):
 | 
					 | 
				
			||||||
    if search_field == 'mem':
 | 
					 | 
				
			||||||
        return findTargetNodeMem(zk_conn, dom_uuid)
 | 
					 | 
				
			||||||
    if search_field == 'load':
 | 
					 | 
				
			||||||
        return findTargetNodeLoad(zk_conn, dom_uuid)
 | 
					 | 
				
			||||||
    if search_field == 'vcpus':
 | 
					 | 
				
			||||||
        return findTargetNodeVCPUs(zk_conn, dom_uuid)
 | 
					 | 
				
			||||||
    if search_field == 'vms':
 | 
					 | 
				
			||||||
        return findTargetNodeVMs(zk_conn, dom_uuid)
 | 
					 | 
				
			||||||
    return None
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# via allocated memory
 | 
					# via free memory (relative to allocated memory)
 | 
				
			||||||
def findTargetNodeMem(zk_conn, dom_uuid):
 | 
					def findTargetHypervisorMem(zk_conn, node_limit, dom_uuid):
 | 
				
			||||||
    least_alloc = math.inf
 | 
					    most_allocfree = 0
 | 
				
			||||||
    target_node = None
 | 
					    target_node = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    node_list = getNodes(zk_conn, dom_uuid)
 | 
					    node_list = getHypervisors(zk_conn, node_limit, dom_uuid)
 | 
				
			||||||
    for node in node_list:
 | 
					    for node in node_list:
 | 
				
			||||||
        alloc = float(zkhandler.readdata(zk_conn, '/nodes/{}/memalloc'.format(node)))
 | 
					        memalloc = int(zkhandler.readdata(zk_conn, '/nodes/{}/memalloc'.format(node)))
 | 
				
			||||||
 | 
					        memused = int(zkhandler.readdata(zk_conn, '/nodes/{}/memused'.format(node)))
 | 
				
			||||||
 | 
					        memfree = int(zkhandler.readdata(zk_conn, '/nodes/{}/memfree'.format(node)))
 | 
				
			||||||
 | 
					        memtotal = memused + memfree
 | 
				
			||||||
 | 
					        allocfree = memtotal - memalloc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if alloc < least_alloc:
 | 
					        if allocfree > most_allocfree:
 | 
				
			||||||
            least_alloc = alloc
 | 
					            most_allocfree = allocfree
 | 
				
			||||||
            target_node = node
 | 
					            target_node = node
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return target_node
 | 
					    return target_node
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# via load average
 | 
					# via load average
 | 
				
			||||||
def findTargetNodeLoad(zk_conn, dom_uuid):
 | 
					def findTargetHypervisorLoad(zk_conn, node_limit, dom_uuid):
 | 
				
			||||||
    least_load = math.inf
 | 
					    least_load = 9999
 | 
				
			||||||
    target_node = None
 | 
					    target_node = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    node_list = getNodes(zk_conn, dom_uuid)
 | 
					    node_list = getHypervisors(zk_conn, node_limit, dom_uuid)
 | 
				
			||||||
    for node in node_list:
 | 
					    for node in node_list:
 | 
				
			||||||
        load = float(zkhandler.readdata(zk_conn, '/nodes/{}/cpuload'.format(node)))
 | 
					        load = int(zkhandler.readdata(zk_conn, '/nodes/{}/load'.format(node)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if load < least_load:
 | 
					        if load < least_load:
 | 
				
			||||||
            least_load = load
 | 
					            least_load = load
 | 
				
			||||||
            target_node = node
 | 
					            target_hypevisor = node
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return target_node
 | 
					    return target_node
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# via total vCPUs
 | 
					# via total vCPUs
 | 
				
			||||||
def findTargetNodeVCPUs(zk_conn, dom_uuid):
 | 
					def findTargetHypervisorVCPUs(zk_conn, node_limit, dom_uuid):
 | 
				
			||||||
    least_vcpus = math.inf
 | 
					    least_vcpus = 9999
 | 
				
			||||||
    target_node = None
 | 
					    target_node = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    node_list = getNodes(zk_conn, dom_uuid)
 | 
					    node_list = getHypervisors(zk_conn, node_limit, dom_uuid)
 | 
				
			||||||
    for node in node_list:
 | 
					    for node in node_list:
 | 
				
			||||||
        vcpus = float(zkhandler.readdata(zk_conn, '/nodes/{}/vcpualloc'.format(node)))
 | 
					        vcpus = int(zkhandler.readdata(zk_conn, '/nodes/{}/vcpualloc'.format(node)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if vcpus < least_vcpus:
 | 
					        if vcpus < least_vcpus:
 | 
				
			||||||
            least_vcpus = vcpus
 | 
					            least_vcpus = vcpus
 | 
				
			||||||
@@ -377,13 +391,13 @@ def findTargetNodeVCPUs(zk_conn, dom_uuid):
 | 
				
			|||||||
    return target_node
 | 
					    return target_node
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# via total VMs
 | 
					# via total VMs
 | 
				
			||||||
def findTargetNodeVMs(zk_conn, dom_uuid):
 | 
					def findTargetHypervisorVMs(zk_conn, node_limit, dom_uuid):
 | 
				
			||||||
    least_vms = math.inf
 | 
					    least_vms = 9999
 | 
				
			||||||
    target_node = None
 | 
					    target_node = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    node_list = getNodes(zk_conn, dom_uuid)
 | 
					    node_list = getHypervisors(zk_conn, node_limit, dom_uuid)
 | 
				
			||||||
    for node in node_list:
 | 
					    for node in node_list:
 | 
				
			||||||
        vms = float(zkhandler.readdata(zk_conn, '/nodes/{}/domainscount'.format(node)))
 | 
					        vms = int(zkhandler.readdata(zk_conn, '/nodes/{}/domainscount'.format(node)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if vms < least_vms:
 | 
					        if vms < least_vms:
 | 
				
			||||||
            least_vms = vms
 | 
					            least_vms = vms
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -398,7 +398,7 @@ def stop_vm(zk_conn, domain):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return True, 'Forcibly stopping VM "{}".'.format(domain)
 | 
					    return True, 'Forcibly stopping VM "{}".'.format(domain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def move_vm(zk_conn, domain, target_node, selector):
 | 
					def move_vm(zk_conn, domain, target_node):
 | 
				
			||||||
    # Validate that VM exists in cluster
 | 
					    # Validate that VM exists in cluster
 | 
				
			||||||
    dom_uuid = getDomainUUID(zk_conn, domain)
 | 
					    dom_uuid = getDomainUUID(zk_conn, domain)
 | 
				
			||||||
    if not dom_uuid:
 | 
					    if not dom_uuid:
 | 
				
			||||||
@@ -408,13 +408,18 @@ def move_vm(zk_conn, domain, target_node, selector):
 | 
				
			|||||||
    current_node = zkhandler.readdata(zk_conn, '/domains/{}/node'.format(dom_uuid))
 | 
					    current_node = zkhandler.readdata(zk_conn, '/domains/{}/node'.format(dom_uuid))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if not target_node:
 | 
					    if not target_node:
 | 
				
			||||||
        target_node = common.findTargetNode(zk_conn, selector, dom_uuid)
 | 
					        target_node = common.findTargetNode(zk_conn, dom_uuid)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        # Verify node is valid
 | 
					        # Verify node is valid
 | 
				
			||||||
        valid_node = common.verifyNode(zk_conn, target_node)
 | 
					        valid_node = common.verifyNode(zk_conn, target_node)
 | 
				
			||||||
        if not valid_node:
 | 
					        if not valid_node:
 | 
				
			||||||
            return False, 'Specified node "{}" is invalid.'.format(target_node)
 | 
					            return False, 'Specified node "{}" is invalid.'.format(target_node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Check if node is within the limit
 | 
				
			||||||
 | 
					        limit = zkhandler.readdata(zk_conn, '/domains/{}/node_limit'.format(dom_uuid).split(',')
 | 
				
			||||||
 | 
					        if target_node not in limit:
 | 
				
			||||||
 | 
					            return False, 'Specified node "{}" is not in the allowed list of nodes for VM "{}".'.format(target_node, domain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Verify if node is current node
 | 
					        # Verify if node is current node
 | 
				
			||||||
        if target_node == current_node:
 | 
					        if target_node == current_node:
 | 
				
			||||||
            common.stopZKConnection(zk_conn)
 | 
					            common.stopZKConnection(zk_conn)
 | 
				
			||||||
@@ -435,7 +440,7 @@ def move_vm(zk_conn, domain, target_node, selector):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return True, 'Permanently migrating VM "{}" to node "{}".'.format(domain, target_node)
 | 
					    return True, 'Permanently migrating VM "{}" to node "{}".'.format(domain, target_node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def migrate_vm(zk_conn, domain, target_node, selector, force_migrate, is_cli=False):
 | 
					def migrate_vm(zk_conn, domain, target_node, force_migrate, is_cli=False):
 | 
				
			||||||
    # Validate that VM exists in cluster
 | 
					    # Validate that VM exists in cluster
 | 
				
			||||||
    dom_uuid = getDomainUUID(zk_conn, domain)
 | 
					    dom_uuid = getDomainUUID(zk_conn, domain)
 | 
				
			||||||
    if not dom_uuid:
 | 
					    if not dom_uuid:
 | 
				
			||||||
@@ -463,13 +468,18 @@ def migrate_vm(zk_conn, domain, target_node, selector, force_migrate, is_cli=Fal
 | 
				
			|||||||
            return False, 'ERROR: VM "{}" has been previously migrated.'.format(domain)
 | 
					            return False, 'ERROR: VM "{}" has been previously migrated.'.format(domain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if not target_node:
 | 
					    if not target_node:
 | 
				
			||||||
        target_node = common.findTargetNode(zk_conn, selector, dom_uuid)
 | 
					        target_node = common.findTargetNode(zk_conn, dom_uuid)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        # Verify node is valid
 | 
					        # Verify node is valid
 | 
				
			||||||
        valid_node = common.verifyNode(zk_conn, target_node)
 | 
					        valid_node = common.verifyNode(zk_conn, target_node)
 | 
				
			||||||
        if not valid_node:
 | 
					        if not valid_node:
 | 
				
			||||||
            return False, 'Specified node "{}" is invalid.'.format(target_node)
 | 
					            return False, 'Specified node "{}" is invalid.'.format(target_node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Check if node is within the limit
 | 
				
			||||||
 | 
					        limit = zkhandler.readdata(zk_conn, '/domains/{}/node_limit'.format(dom_uuid).split(',')
 | 
				
			||||||
 | 
					        if target_node not in limit:
 | 
				
			||||||
 | 
					            return False, 'Specified node "{}" is not in the allowed list of nodes for VM "{}".'.format(target_node, domain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Verify if node is current node
 | 
					        # Verify if node is current node
 | 
				
			||||||
        if target_node == current_node:
 | 
					        if target_node == current_node:
 | 
				
			||||||
            common.stopZKConnection(zk_conn)
 | 
					            common.stopZKConnection(zk_conn)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user