On 13-04-2016 14:22, Aline Manera wrote:
On 04/12/2016 11:47 AM, Lucio Correia wrote:
> Signed-off-by: Lucio Correia <luciojhc(a)linux.vnet.ibm.com>
> ---
> API.json | 31 +++++++++++++++++++++++++++++++
> control/networks.py | 1 +
> docs/API.md | 8 ++++++++
> i18n.py | 9 ++++++---
> model/networks.py | 50
> +++++++++++++++++++++++++++++++++++++++++++++++++-
> 5 files changed, 95 insertions(+), 4 deletions(-)
>
> diff --git a/API.json b/API.json
> index 6f0b484..2205be6 100644
> --- a/API.json
> +++ b/API.json
> @@ -395,6 +395,37 @@
> }
> }
> },
> + "network_update": {
> + "type": "object",
> + "error": "KCHAPI0001E",
> + "properties": {
> + "name": {
> + "description": "The new name of the
network",
> + "type": "string",
> + "minLength": 1,
> + "pattern": "^[^/\"]*$",
> + "required": true,
I should be able to update all the other fields without changing the
name. So there is no need to set is as required.
OK
> + "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"
> + },
Set the minLength as 1 - so we make sure to have at least one interface.
OK
> + "vlan_id": {
> + "description": "Network's VLAN ID",
> + "type": "integer",
> + "maximum": 4094,
> + "minimum": 1,
> + "error": "KCHNET0015E"
> + }
> + }
> + },
> "vmifaces_create": {
> "type": "object",
> "error": "KCHVMIF0007E",
> 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..491e887 100644
> --- a/docs/API.md
> +++ b/docs/API.md
> @@ -736,6 +736,14 @@ 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
networks, you can specify multiple interfaces'
OK
> + * 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 6214687..b413dcd 100644
> --- a/i18n.py
> +++ b/i18n.py
> @@ -255,10 +255,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"),
It'd be better to have separated error message for update instead of
trying to reuse an existing one.
The same line of code generates each message, since the update is
implemented as delete + create.
> "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 (\")"),
> @@ -267,7 +267,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."),
Is there a problem to edit a network in use if the user does not change
the name?
Maybe, we only need to block the name in this case (and proper add an
information about it on UI)
That comes from delete method, since update is implemented as delete +
create.
> "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."),
> @@ -279,6 +279,9 @@ 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": _("Invalid parameter 'connection'. Virtual
network
> type cannot be changed."),
To avoid the need to manually check it, you can add
"additionalProperties: false' to API.json
That way, only the parameters specified there will be allowed.
For example:
"additionalProperties": false,
"error": "<error code>"
The error message will be something like: "To update a virtual network
only the following parameters are allowed: name, subnet, .."
Great, I didn't know that field. Thanks!
> + "KCHNET0032E": _("Subnet is not a valid
parameter for this type
> of virtual network."),
> + "KCHNET0033E": _("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..fdf102a 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,47 @@ 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 parameters
> + if 'connection' in params:
> + raise InvalidParameter("KCHNET0031E")
> +
If you change API.json as I commented above, this verification is not
needed.
OK
> + connection = info['connection']
> + if connection in ['bridge', 'macvtap', 'vepa']:
> + if params.get('subnet'):
> + raise InvalidParameter("KCHNET0032E")
> + elif connection in ['nat', 'isolated']:
> + if params.get('vlan_id') or params.get('interfaces'):
> + raise InvalidParameter("KCHNET0033E")
> +
> + # get target device if bridge was created by Kimchi
> + if connection == 'bridge':
> + iface = info['interfaces'][0]
Verify only ONE interface is passed for bridge and macvtap and raise an
error otherwise.
Multiples interfaces are only allowed for VEPA networks.
This is just discovering the interface that is the port of the bridge
used by the already existent network that will be updated.
> + if is_bridge(iface) and
> iface.startswith(KIMCHI_BRIDGE_PREFIX):
> + port = ports(iface)[0]
> + if is_vlan(port):
> + info['interfaces'] = [get_vlan_device(port)]
> + # nic
> + else:
> + info['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
--
Lucio Correia
Software Engineer
IBM LTC Brazil