[PATCH V2] [Kimchi 0/2] Add support for editing virtual networks

Lucio Correia (2): Add backend support for editing virtual networks Add network update tests Changes in V2: - code review - bugfix in restoring original network API.json | 32 ++++++++++++++++++++++++++++++ control/networks.py | 1 + docs/API.md | 9 +++++++++ i18n.py | 8 +++++--- model/networks.py | 48 ++++++++++++++++++++++++++++++++++++++++++++- tests/test_model_network.py | 19 +++++++++++++++++- 6 files changed, 112 insertions(+), 5 deletions(-) -- 1.9.1

Signed-off-by: Lucio Correia <luciojhc@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

Signed-off-by: Lucio Correia <luciojhc@linux.vnet.ibm.com> --- tests/test_model_network.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/test_model_network.py b/tests/test_model_network.py index e27036d..14d7288 100644 --- a/tests/test_model_network.py +++ b/tests/test_model_network.py @@ -92,8 +92,25 @@ def _do_network_test(self, model, params): network = json.loads(resp.read()) self.assertEquals('inactive', network['state']) + # Define network update parameters + updateParams = {'name': net_name + u'renamed'} + connection = params.get('connection') + if connection in ['isolated', 'nat'] and 'subnet' in params: + updateParams['subnet'] = '127.0.200.0/24' + elif connection == 'bridge' and 'vlan_id' in params: + updateParams['vlan_id'] = 389 + + # Test network update + req = json.dumps(updateParams) + resp = self.request(uri, req, 'PUT') + self.assertEquals(303, resp.status) + + # Assert old name does not exist anymore + resp = self.request(uri, '{}', 'GET') + self.assertEquals(404, resp.status) + # Delete the network - resp = self.request(uri, '{}', 'DELETE') + resp = self.request(uri + 'renamed'.encode('utf-8'), '{}', 'DELETE') self.assertEquals(204, resp.status) -- 1.9.1

Reviewed-by: Daniel Barboza <dhbarboza82@gmail.com> On 04/14/2016 06:11 PM, Lucio Correia wrote:
Lucio Correia (2): Add backend support for editing virtual networks Add network update tests
Changes in V2: - code review - bugfix in restoring original network
API.json | 32 ++++++++++++++++++++++++++++++ control/networks.py | 1 + docs/API.md | 9 +++++++++ i18n.py | 8 +++++--- model/networks.py | 48 ++++++++++++++++++++++++++++++++++++++++++++- tests/test_model_network.py | 19 +++++++++++++++++- 6 files changed, 112 insertions(+), 5 deletions(-)
participants (3)
-
Aline Manera
-
Daniel Henrique Barboza
-
Lucio Correia