
Signed-off-by: Jose Ricardo Ziviani <joserz@linux.vnet.ibm.com> --- src/kimchi/API.json | 13 +++------- src/kimchi/i18n.py | 4 ++- src/kimchi/model/vmifaces.py | 60 +++++++++++++++++++++++++++++++------------- 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/src/kimchi/API.json b/src/kimchi/API.json index 474661c..a2b759b 100644 --- a/src/kimchi/API.json +++ b/src/kimchi/API.json @@ -378,19 +378,12 @@ "type": "object", "error": "KCHVMIF0008E", "properties": { - "network": { - "description": "the name of one available network", - "minLength": 1, + "mac": { + "description": "Network Interface Card MAC address", "type": "string", "error": "KCHVMIF0005E" - }, - "model": { - "description": "model of emulated network interface card", - "enum": ["ne2k_pci", "i82551", "i82557b", "i82559er", "rtl8139", "e1000", "pcnet", "virtio", "spapr-vlan"], - "error": "KCHVMIF0006E" } - }, - "additionalProperties": false + } }, "templates_create": { "type": "object", diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py index 18e84bc..f69e067 100644 --- a/src/kimchi/i18n.py +++ b/src/kimchi/i18n.py @@ -126,7 +126,9 @@ messages = { "KCHVMIF0005E": _("Network name for virtual machine interface must be a string"), "KCHVMIF0006E": _("Invalid network model card specified for virtual machine interface"), "KCHVMIF0007E": _("Specify type and network to add a new virtual machine interface"), - "KCHVMIF0008E": _("Specify type and network to update a virtual machine interface"), + "KCHVMIF0008E": _("MAC Address must respect this format FF:FF:FF:FF:FF:FF"), + "KCHVMIF0009E": _("MAC Address %(mac)s already exists in virtual machine %(name)s"), + "KCHVMIF0010E": _("Invalid MAC Address %(mac)s"), "KCHTMPL0001E": _("Template %(name)s already exists"), "KCHTMPL0003E": _("Network '%(network)s' specified for template %(template)s does not exist"), diff --git a/src/kimchi/model/vmifaces.py b/src/kimchi/model/vmifaces.py index 8bf6b3d..4c0a2a9 100644 --- a/src/kimchi/model/vmifaces.py +++ b/src/kimchi/model/vmifaces.py @@ -20,6 +20,7 @@ import random import libvirt +import re from lxml import etree, objectify from kimchi.exception import InvalidParameter, MissingParameter, NotFoundError @@ -27,6 +28,8 @@ from kimchi.model.config import CapabilitiesModel from kimchi.model.vms import DOM_STATE_MAP, VMModel from kimchi.xmlutils.interface import get_iface_xml +RE_MACADDR = '^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$' + class VMIfacesModel(object): def __init__(self, **kargs): @@ -57,10 +60,24 @@ class VMIfacesModel(object): macs = (iface.mac.get('address') for iface in self.get_vmifaces(vm, self.conn)) - while True: - params['mac'] = VMIfacesModel.random_mac() - if params['mac'] not in macs: - break + # user defined customized mac address + if 'mac' in params and params['mac']: + # make sure it is unique + if params['mac'] in macs: + raise InvalidParameter('KCHVMIF0009E', + {'name': vm, 'mac': params['mac']}) + + # invalid mac address + if not re.match(RE_MACADDR, params['mac']): + raise InvalidParameter('KCHVMIF0010E', + {'name': vm, 'mac': params['mac']}) + + # otherwise choose a random mac address + else: + while True: + params['mac'] = VMIfacesModel.random_mac() + if params['mac'] not in macs: + break dom = VMModel.get_vm(vm, self.conn) @@ -147,22 +164,31 @@ class VMIfaceModel(object): if iface is None: raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface': mac}) + # mac address is a required parameter + if 'mac' not in params: + raise MissingParameter('KCHVMIF0008E') + + # invalid mac address + if not re.match(RE_MACADDR, params['mac']): + raise InvalidParameter('KCHVMIF0010E', + {'name': vm, 'mac': params['mac']}) + + # new mac address must be unique + if self._get_vmiface(vm, params['mac']): + raise InvalidParameter('KCHVMIF0009E', + {'name': vm, 'mac': params['mac']}) + flags = 0 if dom.isPersistent(): flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG - if DOM_STATE_MAP[dom.info()[0]] != "shutoff": - flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE - - if iface.attrib['type'] == 'network' and 'network' in params: - iface.source.attrib['network'] = params['network'] - xml = etree.tostring(iface) - - dom.updateDeviceFlags(xml, flags=flags) - if 'model' in params: - iface.model.attrib["type"] = params['model'] - xml = etree.tostring(iface) + # remove the current nic + xml = etree.tostring(iface) + dom.detachDeviceFlags(xml, flags=flags) - dom.updateDeviceFlags(xml, flags=flags) + # add the nic with the desired mac address + iface.mac.attrib['address'] = params['mac'] + xml = etree.tostring(iface) + dom.attachDeviceFlags(xml, flags=flags) - return mac + return [vm, params['mac']] -- 1.9.1