[Kimchi-devel] [PATCH V1] [Kimchi] Updated code to support add, remove and list host network interface(s) to exiting template.

archus at linux.vnet.ibm.com archus at linux.vnet.ibm.com
Mon Aug 22 17:49:43 UTC 2016


From: Archana Singh <archus at linux.vnet.ibm.com>

interfaces is an additional optional attribute and hence exiting functionalities to add,
remove and list networks from/to template are not changed.
Below are the changes:

1) Added i18n error codes.
2) Added interface as new kimchitype in API.json. And ref added in update template.
    -Interface expects an object with parameters: 'name', 'type' and 'mode'.
    -Name should be name of host network interface(Ethernet, Bond, VLAN) for type 'macvtap'
     or name should be name of host openvswitch bridge interface for type ovs.
    -Mode only applicable for interface type macvtap to indicates whether packets
     has to be delivered directly to target device(bridge) or to the external bridge(vepa-capable bridge).
    -Mode is Optional.
3) Added interfaces as optional attribute in template control.
    -This attribute returns to be list of host interface attached to template,
     each interface will have above attribute.
    -Empty list if no host network interface is attached to template.
4) Added method to generate valid interface xml from the interface based on above attribute.
    -This will use below method to generate interface xml based on type and other attribute.
    -Update vm xml generate method to add generated interfaces xml to vm xml.
5) Modified xmlutils which generates interface xml based on interface type and attributes.

Signed-off-by: Archana Singh <archus at linux.vnet.ibm.com>
---
 API.json              | 29 ++++++++++++++++++++-
 control/templates.py  |  1 +
 i18n.py               |  2 ++
 vmtemplate.py         | 24 +++++++++++++++++
 xmlutils/interface.py | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 127 insertions(+), 1 deletion(-)

diff --git a/API.json b/API.json
index a3af02d..e323649 100644
--- a/API.json
+++ b/API.json
@@ -89,7 +89,29 @@
             },
             "additionalProperties": false,
             "error": "KCHTMPL0030E"
-        }
+        },
+        "interface": {
+             "description": "Host network interface, this indicates whether to configure the host network interface(Ethernet, Bond, VLAN) as direct MacVTap or to configure interface(OVS) as virtual switch to a VM",
+             "type": "object",
+             "properties": {
+                   "type": {
+                       "description": "Type of host network interface. Type should be 'macvtap' for host network interface(Ethernet, Bond, VLAN) to be connected as direct MacVTap and type ovs for openvswitch host network interface to be connected as virtual switch to a VM.",
+                       "type": "string",
+                       "pattern":  "^(macvtap|ovs)$"
+                    },
+                   "name": {
+                       "description": "The host network interface. It should be name of host network interface(Ethernet, Bond, VLAN) for type 'macvtap' and name of host openvswitch bridge interface for type ovs",
+                       "type": "string"
+                    },
+                   "mode": {
+                       "description": "Only applicable for interface type macvtap, to indicates whether packets will be delivered directly to target device(bridge) or to the external bridge(vepa-capable bridge). Optional.",
+                       "type": "string",
+                       "pattern":  "^(bridge|vepa)$"
+                    }
+             },
+            "additionalProperties": false,
+            "error": "KCHTMPL0033E"
+       }
     },
     "properties": {
         "storagepools_create": {
@@ -783,6 +805,11 @@
                     "items": { "type": "string" },
                     "error": "KCHTMPL0017E"
                 },
+                "interfaces": {
+                    "description": "list of host interfaces to be assigned to new VM",
+                    "type": "array",
+                    "items": { "ref": "#/kimchitype/interface" }
+                },
                 "folder": {
                     "description": "Folder",
                     "type": "array",
diff --git a/control/templates.py b/control/templates.py
index bb2e068..d81398a 100644
--- a/control/templates.py
+++ b/control/templates.py
@@ -68,6 +68,7 @@ class Template(Resource):
             'cdrom': self.info.get('cdrom', None),
             'disks': self.info['disks'],
             'networks': self.info['networks'],
+            'interfaces': self.info.get('interfaces', []),
             'folder': self.info.get('folder', []),
             'graphics': self.info['graphics'],
             'cpu_info': self.info.get('cpu_info')
diff --git a/i18n.py b/i18n.py
index e8d9c05..7cda46d 100644
--- a/i18n.py
+++ b/i18n.py
@@ -159,6 +159,7 @@ messages = {
     "KCHVMIF0009E": _("MAC Address %(mac)s already exists in virtual machine %(name)s"),
     "KCHVMIF0010E": _("Invalid MAC Address"),
     "KCHVMIF0011E": _("Cannot change MAC address of a running virtual machine"),
+    "KCHVMIF0012E": _("Invalid host network interface type (%(type)s). Type should be 'macvtap' for host network interface(Ethernet, Bond, VLAN) to be connected as direct MacVTap and type 'ovs' for openvswitch host network interface to be connected as virtual switch to a VM."),
 
     "KCHTMPL0001E": _("Template %(name)s already exists"),
     "KCHTMPL0002E": _("Source media %(path)s not found"),
@@ -190,6 +191,7 @@ messages = {
     "KCHTMPL0031E": _("Memory value (%(mem)sMiB) must be equal or lesser than maximum memory value (%(maxmem)sMiB)"),
     "KCHTMPL0032E": _("Unable to update template due error: %(err)s"),
     "KCHTMPL0033E": _("Parameter 'disks' requires at least one disk object"),
+    "KCHTMPL0033E": _("Interface expects an object with parameters: 'name', 'type' and 'mode'. Name should be name of host network interface(Ethernet, Bond, VLAN) for type 'macvtap' and name of host openvswitch bridge interface for type ovs. Mode only applicable for interface type macvtap to indicates whether packets will be delivered directly to target device(bridge) or to the external bridge(vepa-capable bridge) and is Optional."),
 
     "KCHPOOL0001E": _("Storage pool %(name)s already exists"),
     "KCHPOOL0002E": _("Storage pool %(name)s does not exist"),
diff --git a/vmtemplate.py b/vmtemplate.py
index 7ac0541..fed6d28 100644
--- a/vmtemplate.py
+++ b/vmtemplate.py
@@ -22,6 +22,7 @@ import stat
 import time
 import urlparse
 import uuid
+
 from lxml import etree
 from lxml.builder import E
 
@@ -295,6 +296,27 @@ class VMTemplate(object):
                                       self.info['os_version'])
         return unicode(networks, 'utf-8')
 
+    def _get_interfaces_xml(self):
+        interfaces = ""
+        params = {'model': self.info['nic_model']}
+        for interface in self.info.get('interfaces', []):
+            typ = interface['type']
+            if typ == 'macvtap':
+                params['type'] = 'direct'
+                params['mode'] = interface.get('mode', None)
+            elif typ == 'ovs':
+                params['type'] = 'bridge'
+                params['virtualport_type'] = 'openvswitch'
+            else:
+                raise InvalidParameter('KCHVMIF0012E', {'type':
+                                                        params['type']})
+
+            params['name'] = interface['name']
+            interfaces += get_iface_xml(params, self.info['arch'],
+                                        self.info['os_distro'],
+                                        self.info['os_version'])
+        return unicode(interfaces, 'utf-8')
+
     def _get_input_output_xml(self):
         sound = """
             <sound model='%(sound_model)s' />
@@ -341,6 +363,7 @@ class VMTemplate(object):
         params['name'] = vm_name
         params['uuid'] = vm_uuid
         params['networks'] = self._get_networks_xml()
+        params['interfaces'] = self._get_interfaces_xml()
         params['input_output'] = self._get_input_output_xml()
         params['qemu-namespace'] = ''
         params['cdroms'] = ''
@@ -432,6 +455,7 @@ class VMTemplate(object):
             %(disks)s
             %(cdroms)s
             %(networks)s
+            %(interfaces)s
             %(graphics)s
             %(input_output)s
             %(serial)s
diff --git a/xmlutils/interface.py b/xmlutils/interface.py
index 677ed81..255d491 100644
--- a/xmlutils/interface.py
+++ b/xmlutils/interface.py
@@ -24,6 +24,16 @@ from wok.plugins.kimchi import osinfo
 
 
 def get_iface_xml(params, arch=None, os_distro=None, os_version=None):
+    typ = params.get('type', 'network')
+    if typ == 'network':
+        return get_iface_network_xml(params, arch, os_distro, os_version)
+    elif typ == 'bridge':
+        return get_iface_ovs_xml(params, arch, os_distro, os_version)
+    elif typ == 'direct':
+        return get_iface_macvtap_xml(params, arch, os_distro, os_version)
+
+
+def get_iface_network_xml(params, arch=None, os_distro=None, os_version=None):
     """
     <interface type='network' name='ethX'>
       <start mode='onboot'/>
@@ -62,3 +72,65 @@ def get_iface_xml(params, arch=None, os_distro=None, os_version=None):
         interface.append(E.mac(address=mac))
 
     return ET.tostring(interface, encoding='utf-8', pretty_print=True)
+
+
+def get_iface_macvtap_xml(params, arch=None, os_distro=None, os_version=None):
+    """
+    <interface type="direct">
+      <source dev="bondX" mode="bridge"/>
+      <model type="virtio"/>
+    </interface>
+    """
+    device = params['name']
+    interface = E.interface(type=params['type'])
+    mode = params.get('mode', None)
+    if mode is not None:
+        interface.append(E.source(dev=device, mode=mode))
+    else:
+        interface.append(E.source(dev=device))
+
+    model = params.get('model', None)
+    # no model specified; let's try querying osinfo
+    if model is None:
+        # if os_distro and os_version are invalid, nic_model will also be None
+        model = osinfo.lookup(os_distro, os_version).get('nic_model')
+
+    # only append 'model' to the XML if it's been specified as a parameter or
+    # returned by osinfo.lookup; otherwise let libvirt use its default value
+    if model is not None:
+        interface.append(E.model(type=model))
+
+    interface.append(E.model(type=model))
+
+    return ET.tostring(interface, encoding='utf-8', pretty_print=True)
+
+
+def get_iface_ovs_xml(params, arch=None, os_distro=None, os_version=None):
+    """
+    <interface type="bridge">
+      <source bridge="vswitchX"/>
+      <virtualport type="openvswitch"/>
+      <model type="virtio"/>
+    </interface>
+    """
+    device = params['name']
+    interface = E.interface(type=params['type'])
+    interface.append(E.source(bridge=device))
+    virtualport_type = params.get('virtualport_type', 'openvswitch')
+    interface.append(E.virtualport(type=virtualport_type))
+
+    model = params.get('model', None)
+    # no model specified; let's try querying osinfo
+    if model is None:
+        # if os_distro and os_version are invalid, nic_model will also be None
+        model = osinfo.lookup(os_distro, os_version).get('nic_model')
+
+    # only append 'model' to the XML if it's been specified as a parameter or
+    # returned by osinfo.lookup; otherwise let libvirt use its default value
+
+    if model is not None:
+        interface.append(E.model(type=model))
+
+    interface.append(E.model(type=model))
+
+    return ET.tostring(interface, encoding='utf-8', pretty_print=True)
-- 
2.7.4




More information about the Kimchi-devel mailing list