Edward Haas has uploaded a new change for review. Change subject: virt net: Support VM migration on OVS based networks ......................................................................
virt net: Support VM migration on OVS based networks With the introduction of OVS as a network implementation, the migration of VM/s betweeni hosts requires special handling. This patch enables VM/s to migrate between networks of the same king or mixed. Change-Id: Ie7d32f9605f9ca99d1e07062108f2567806ac59c Signed-off-by: Edward Haas <[email protected]> --- M vdsm.spec.in M vdsm/virt/Makefile.am M vdsm/virt/libvirt-hook.sh A vdsm/virt/vm_migrate_hook.py 4 files changed, 166 insertions(+), 1 deletion(-) git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/45/59645/1 diff --git a/vdsm.spec.in b/vdsm.spec.in index a99edf8..c1818ba 100644 --- a/vdsm.spec.in +++ b/vdsm.spec.in @@ -947,6 +947,7 @@ %{_datadir}/%{vdsm_name}/virt/recovery.py* %{_datadir}/%{vdsm_name}/virt/vmtune.py* %{_datadir}/%{vdsm_name}/virt/vm.py* +%{_datadir}/%{vdsm_name}/virt/vm_migrate_hook.py* %{_datadir}/%{vdsm_name}/virt/vmxml.py* %{_datadir}/%{vdsm_name}/virt/vmdevices/__init__.py* %{_datadir}/%{vdsm_name}/virt/vmdevices/common.py* @@ -979,6 +980,7 @@ %{_libexecdir}/%{vdsm_name}/ovirt_functions.sh %{_libexecdir}/%{vdsm_name}/vdsm-gencerts.sh %{_libexecdir}/%{vdsm_name}/vdsmd_init_common.sh +%{_libexecdir}/%{vdsm_name}/vm_migrate_hook.py %{_libexecdir}/%{vdsm_name}/kvm2ovirt %{_libexecdir}/%{vdsm_name}/wait_for_ipv4s %{_datadir}/%{vdsm_name}/supervdsm_api/__init__.py* diff --git a/vdsm/virt/Makefile.am b/vdsm/virt/Makefile.am index a178fe1..89835af 100644 --- a/vdsm/virt/Makefile.am +++ b/vdsm/virt/Makefile.am @@ -29,10 +29,15 @@ migration.py \ recovery.py \ vm.py \ + vm_migrate_hook.py \ vmtune.py \ vmxml.py \ $(NULL) +dist_vdsmexec_SCRIPTS = \ + vm_migrate_hook.py \ + $(NULL) + EXTRA_DIST = \ libvirt-hook.sh \ $(NULL) diff --git a/vdsm/virt/libvirt-hook.sh b/vdsm/virt/libvirt-hook.sh index 9a2692a..01daf6e 100644 --- a/vdsm/virt/libvirt-hook.sh +++ b/vdsm/virt/libvirt-hook.sh @@ -17,7 +17,9 @@ # Fix VMs migrating to host with libvirt >= 1.2.8 # See https://bugzilla.redhat.com/show_bug.cgi?id=1138340 -if [ -x /usr/libexec/vdsm/ovs_migrate.py ]; then +if [ -x /usr/libexec/vdsm/vm_migrate_hook.py ]; then + sed -e 's|<min_guarantee[^>]*>[0-9 ]*</min_guarantee>||g' | /usr/libexec/vdsm/vm_migrate_hook.py $DOMAIN $EVENT $PHASE +elif [ -x /usr/libexec/vdsm/ovs_migrate.py ]; then sed -e 's|<min_guarantee[^>]*>[0-9 ]*</min_guarantee>||g' | /usr/libexec/vdsm/ovs_migrate.py $DOMAIN $EVENT $PHASE else sed -e 's|<min_guarantee[^>]*>[0-9 ]*</min_guarantee>||g' diff --git a/vdsm/virt/vm_migrate_hook.py b/vdsm/virt/vm_migrate_hook.py new file mode 100755 index 0000000..de4737f --- /dev/null +++ b/vdsm/virt/vm_migrate_hook.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python +# Copyright 2016 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# Refer to the README and COPYING files for full details of the license +# +from __future__ import print_function + +import sys +import xml.etree.cElementTree as ET + +from vdsm import jsonrpcvdscli +from vdsm.config import config +from vdsm.network import api as net_api + + +_DEBUG_MODE = False + +if _DEBUG_MODE: + LOG_FILE = '/tmp/libvirthook_ovs_migrate.log' + log = open(LOG_FILE, 'w') + + +def main(domain, event, phase, *args, **kwargs): + if event not in ('migrate', 'restore'): + sys.exit(0) + + if _DEBUG_MODE: + print('Hook input args are: ', domain, event, phase, file=log) + + stdin = kwargs.get('stdin', sys.stdin) + + tree = ET.parse(stdin) + _process_domxml(tree) + + stdout = kwargs.get('stdout', sys.stdout) + tree.write(stdout) + + if _DEBUG_MODE: + tree.write(log) + print('\nEnd of hook', file=log) + + +def _process_domxml(tree): + root = tree.getroot() + vm_uuid = root.find('uuid') + devices = root.find('devices') + + target_vm_info, = _vmlist(_vdscli(), vm_id=vm_uuid) + + _set_graphics(devices, target_vm_info) + + target_vm_nets_by_mac = [{dev['macAddr']: dev['network']} + for dev in target_vm_info['devices'] + if dev['type'] == 'interface'] + + for interface in devices.findall('interface'): + if interface.get('type') == 'bridge': + _bind_iface_to_bridge(interface, target_vm_nets_by_mac) + + +def _bind_iface_to_bridge(interface, target_vm_nets_by_mac): + elem_macaddr = interface.find('mac') + mac_addr = elem_macaddr.get('address') + + target_vm_net = target_vm_nets_by_mac[mac_addr] + target_ovs_bridge = net_api.ovs_bridge(target_vm_net) + if target_ovs_bridge: + _bind_iface_to_ovs_bridge(interface, target_ovs_bridge, target_vm_net) + else: + _bind_iface_to_linux_bridge(interface, target_vm_net) + + +def _bind_iface_to_ovs_bridge(interface, target_ovs_bridge, target_vm_net): + _set_source_bridge(interface, target_ovs_bridge) + _set_virtualport(interface) + + vlan_tag = net_api.net2vlan(target_vm_net) + if vlan_tag: + _set_vlan(interface, vlan_tag) + + +def _set_vlan(interface, vlan_tag): + elem_vlan = interface.find('vlan') + if elem_vlan is None: + elem_vlan = ET.SubElement(interface, 'vlan') + elem_tag = ET.SubElement(elem_vlan, 'tag') + elem_tag.set('id', str(vlan_tag)) + + +def _set_virtualport(interface): + elem_virtualport = interface.find('virtualport') + if elem_virtualport is None: + elem_virtualport = ET.SubElement(interface, 'virtualport') + elem_virtualport.set('type', 'openvswitch') + elem_virtualport.tail = ' ' + + +def _bind_iface_to_linux_bridge(interface, target_linux_bridge): + _set_source_bridge(interface, target_linux_bridge) + + elem_virtualport = interface.find('virtualport') + if elem_virtualport is not None: + interface.remove(elem_virtualport) + + elem_vlan = interface.find('vlan') + if elem_vlan is not None: + interface.remove(elem_vlan) + + +def _set_source_bridge(interface, bridge): + elem_source = interface.find('source') + elem_source.set('bridge', bridge) + + +def _set_graphics(devices, target_vm_info): + graphics = devices.find('graphics') + graphics_listen = graphics.find('listen') + + target_display_network = target_vm_info['displayNetwork'] + + if net_api.ovs_bridge(target_display_network): + graphics_listen.set('type', 'address') + graphics_listen.set('address', target_vm_info['displayIp']) + else: + libvirt_network = net_api.netname_o2l(target_display_network) + graphics_listen.set('type', 'network') + graphics_listen.set('network', libvirt_network) + + +def _vmlist(vdscli, vm_id=None): + result = vdscli.fullList(fullStatus=True, vmList=(vm_id,) if vm_id else ()) + return result['items'] + + +def _vdscli(): + requestQueues = config.get('addresses', 'request_queues') + requestQueue = requestQueues.split(",")[0] + return jsonrpcvdscli.connect(requestQueue) + + +if __name__ == '__main__': + main(*sys.argv[1:]) -- To view, visit https://gerrit.ovirt.org/59645 To unsubscribe, visit https://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ie7d32f9605f9ca99d1e07062108f2567806ac59c Gerrit-PatchSet: 1 Gerrit-Project: vdsm Gerrit-Branch: master Gerrit-Owner: Edward Haas <[email protected]> _______________________________________________ vdsm-patches mailing list [email protected] https://lists.fedorahosted.org/admin/lists/[email protected]
