Signed-off-by: Lucio Correia <luciojhc(a)linux.vnet.ibm.com>
---
API.json | 32 ++++++++++++++++++++++++++++++++
control/networks.py | 1 +
docs/API.md | 9 +++++++++
i18n.py | 8 +++++---
model/networks.py | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 94 insertions(+), 4 deletions(-)
diff --git a/API.json b/API.json
index ff505b1..86cd406 100644
--- a/API.json
+++ b/API.json
@@ -384,6 +384,38 @@
"interfaces": {
"description": "An array of network interfaces of the
host",
"type": "array",
+ "minItems": 1,
+ "error": "KCHNET0014E"
+ },
+ "vlan_id": {
+ "description": "Network's VLAN ID",
+ "type": "integer",
+ "maximum": 4094,
+ "minimum": 1,
+ "error": "KCHNET0015E"
+ }
+ }
+ },
+ "network_update": {
+ "type": "object",
+ "additionalProperties": false,
+ "error": "KCHAPI0001E",
+ "properties": {
+ "name": {
+ "description": "The new name of the network",
+ "type": "string",
+ "minLength": 1,
+ "pattern": "^[^/\"]*$",
+ "error": "KCHNET0011E"
+ },
+ "subnet": {
+ "description": "Network segment in slash-separated
format with ip address and prefix or netmask",
+ "type": "string",
+ "error": "KCHNET0013E"
+ },
+ "interfaces": {
+ "description": "An array of network interfaces of the
host",
+ "type": "array",
"error": "KCHNET0014E"
},
"vlan_id": {
diff --git a/control/networks.py b/control/networks.py
index 8ba2206..c87b5a6 100644
--- a/control/networks.py
+++ b/control/networks.py
@@ -27,6 +27,7 @@ NETWORKS_REQUESTS = {
NETWORK_REQUESTS = {
'DELETE': {'default': "Remove virtual network
'%(ident)s'"},
+ 'PUT': {'default': "Update virtual network
'%(ident)s'"},
'POST': {
'activate': "Activate virtual network '%(ident)s'",
'deactivate': "Deactivate virtual network
'%(ident)s'",
diff --git a/docs/API.md b/docs/API.md
index f1a13b4..a94f0f9 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -736,6 +736,15 @@ A interface represents available interface on host.
* **DELETE**: Remove the Network
* **POST**: *See Network Actions*
+* **PUT**: Update the Network. The network type cannot be changed.
+ * name *(optional)*: The new name of the Network
+ * subnet *(optional)*: Network segment in slash-separated format with ip address and
prefix.
+ Applies only to NAT and isolated networks
+ * interfaces *(optional)*: An array of network interfaces that belongs to this
network.
+ Applies only to bridge, macvtap and VEPA networks. For bridge and
macvtap,
+ only one interface is allowed. For VEPA, you can specify multiple
interfaces.
+ * vlan_id *(optional)*: VLAN tagging ID for the bridge network.
+
**Actions (POST):**
* activate: Activate an inactive Network
diff --git a/i18n.py b/i18n.py
index 7cce796..3712a02 100644
--- a/i18n.py
+++ b/i18n.py
@@ -253,10 +253,10 @@ messages = {
"KCHNET0002E": _("Network %(name)s does not exist"),
"KCHNET0003E": _("Subnet %(subnet)s specified for network %(network)s
is not valid."),
"KCHNET0004E": _("Specify a network interface to create bridged or
macvtap networks."),
- "KCHNET0005E": _("Unable to delete active network %(name)s"),
+ "KCHNET0005E": _("Unable to delete or update active network
%(name)s"),
"KCHNET0006E": _("Interface %(iface)s specified for network
%(network)s is already in use"),
"KCHNET0007E": _("Interface should be bare NIC, bonding or bridge
device."),
- "KCHNET0008E": _("Unable to create network %(name)s. Details:
%(err)s"),
+ "KCHNET0008E": _("Unable to create or update network %(name)s.
Details: %(err)s"),
"KCHNET0009E": _("Unable to find a free IP address for network
'%(name)s'"),
"KCHNET0010E": _("The interface %(iface)s already exists."),
"KCHNET0011E": _("Network name must be a string without slashes (/) or
quotes (\")"),
@@ -265,7 +265,7 @@ messages = {
"KCHNET0014E": _("Network interfaces must be an array."),
"KCHNET0015E": _("Network VLAN ID must be an integer between 1 and
4094"),
"KCHNET0016E": _("Specify name and type to create a Network"),
- "KCHNET0017E": _("Unable to delete network %(name)s. There are some
virtual machines %(vms)s and/or templates linked to this network."),
+ "KCHNET0017E": _("Unable to delete or update network %(name)s. There
are some virtual machines %(vms)s and/or templates linked to this network."),
"KCHNET0018E": _("Unable to deactivate network %(name)s. There are
some virtual machines %(vms)s and/or templates linked to this network."),
"KCHNET0019E": _("Bridge device %(name)s can not be the trunk device
of a VLAN."),
"KCHNET0020E": _("Failed to activate interface %(iface)s:
%(err)s."),
@@ -277,6 +277,8 @@ messages = {
"KCHNET0028E": _("Interface should be bare NIC or bonding."),
"KCHNET0029E": _("Network interfaces parameter must contain at least
one interface."),
"KCHNET0030E": _("Only one interface is allowed for 'bridge'
and 'macvtap' networks."),
+ "KCHNET0031E": _("Subnet is not a valid parameter for this type of
virtual network."),
+ "KCHNET0032E": _("VLAN ID and interfaces are not valid parameters for
this type of virtual network."),
"KCHSR0001E": _("Storage server %(server)s was not used by
Kimchi"),
diff --git a/model/networks.py b/model/networks.py
index 2664af3..08b2690 100644
--- a/model/networks.py
+++ b/model/networks.py
@@ -17,6 +17,7 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+import copy
import ipaddr
import libvirt
import sys
@@ -33,6 +34,8 @@ from wok.plugins.kimchi import netinfo
from wok.plugins.kimchi import network as knetwork
from wok.plugins.kimchi.config import kimchiPaths
from wok.plugins.kimchi.model.config import CapabilitiesModel
+from wok.plugins.kimchi.netinfo import get_vlan_device, is_bridge, is_vlan
+from wok.plugins.kimchi.netinfo import ports
from wok.plugins.kimchi.osinfo import defaults as tmpl_defaults
from wok.plugins.kimchi.xmlutils.interface import get_iface_xml
from wok.plugins.kimchi.xmlutils.network import create_linux_bridge_xml
@@ -109,7 +112,7 @@ class NetworksModel(object):
try:
network = conn.networkDefineXML(xml.encode("utf-8"))
- network.setAutostart(True)
+ network.setAutostart(params.get('autostart', True))
except libvirt.libvirtError as e:
raise OperationFailed("KCHNET0008E",
{'name': name, 'err':
e.get_error_message()})
@@ -339,6 +342,7 @@ class NetworkModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
+ self.collection = NetworksModel(**kargs)
def lookup(self, name):
network = self.get_network(self.conn.get(), name)
@@ -499,3 +503,45 @@ class NetworkModel(object):
iface = conn.interfaceLookupByName(bridge)
iface.isActive() and iface.destroy(0)
iface.undefine()
+
+ def update(self, name, params):
+ info = self.lookup(name)
+ original = copy.deepcopy(info)
+ original['name'] = name
+
+ # validate update parameters
+ connection = info['connection']
+ if connection in ['bridge', 'macvtap', 'vepa']:
+ if params.get('subnet'):
+ raise InvalidParameter("KCHNET0031E")
+ elif connection in ['nat', 'isolated']:
+ if params.get('vlan_id') or params.get('interfaces'):
+ raise InvalidParameter("KCHNET0032E")
+
+ # get target device if bridge was created by Kimchi
+ if connection == 'bridge':
+ iface = info['interfaces'][0]
+ if is_bridge(iface) and iface.startswith(KIMCHI_BRIDGE_PREFIX):
+ port = ports(iface)[0]
+ if is_vlan(port):
+ dev = get_vlan_device(port)
+ info['interfaces'] = original['interfaces'] = [dev]
+ # nic
+ else:
+ info['interfaces'] = original['interfaces'] = [port]
+
+ # merge parameters
+ info.update(params)
+
+ # delete original network
+ self.delete(name)
+
+ try:
+ # create new network
+ network = self.collection.create(info)
+ except:
+ # restore original network
+ self.collection.create(original)
+ raise
+
+ return network
--
1.9.1