Signed-off-by: Jose Ricardo Ziviani <joserz(a)linux.vnet.ibm.com>
---
src/kimchi/API.json | 13 ++++++++++
src/kimchi/i18n.py | 4 ++-
src/kimchi/model/vmifaces.py | 60 +++++++++++++++++++++++++++++++-------------
3 files changed, 59 insertions(+), 18 deletions(-)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json
index 474661c..71d7a72 100644
--- a/src/kimchi/API.json
+++ b/src/kimchi/API.json
@@ -382,12 +382,25 @@
"description": "the name of one available
network",
"minLength": 1,
"type": "string",
+ "required": true,
"error": "KCHVMIF0005E"
},
+ "type": {
+ "description": "The type of VM network interface that
libvirt supports",
+ "type": "string",
+ "pattern": "^network$",
+ "required": true,
+ "error": "KCHVMIF0004E"
+ },
"model": {
"description": "model of emulated network interface
card",
"enum": ["ne2k_pci", "i82551",
"i82557b", "i82559er", "rtl8139", "e1000",
"pcnet", "virtio", "spapr-vlan"],
"error": "KCHVMIF0006E"
+ },
+ "mac": {
+ "description": "Network Interface Card MAC
address",
+ "type": "string",
+ "error": "KCHVMIF0005E"
}
},
"additionalProperties": false
diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
index 18e84bc..f04f54e 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": _("Specify MAC Address to update a virtual machine
interface"),
+ "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