summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary Kotton <gkotton@vmware.com>2018-09-02 02:06:26 -0700
committerGary Kotton <gkotton@vmware.com>2018-09-04 04:29:56 -0700
commit04f82ae934fda23612f78b2be9dfb24b06268c87 (patch)
tree27621c1235a1102e49e02bfd77bdf005a4e83f60
parenta47f0d0c4f766219bf61d122205c05034a97399c (diff)
downloadoslo-vmware-04f82ae934fda23612f78b2be9dfb24b06268c87.tar.gz
Add DVS utility methods2.32.12.32.0
Provide methods that wil enable nova/neutron to manage port groups. Change-Id: I81fc039e86b56388881427a6fbc4efd41207fafa
-rw-r--r--oslo_vmware/dvs_util.py159
-rw-r--r--oslo_vmware/tests/test_dvs_util.py139
2 files changed, 298 insertions, 0 deletions
diff --git a/oslo_vmware/dvs_util.py b/oslo_vmware/dvs_util.py
new file mode 100644
index 0000000..9ee54dd
--- /dev/null
+++ b/oslo_vmware/dvs_util.py
@@ -0,0 +1,159 @@
+# Copyright (c) 2018 VMware, Inc.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import logging
+
+from oslo_vmware import vim_util
+
+
+LOG = logging.getLogger(__name__)
+
+
+def get_dvs_moref(value):
+ """Get managed DVS object reference.
+
+ :param value: value of the DVS managed object
+ :returns: managed object reference with given value and type
+ 'VmwareDistributedVirtualSwitch'
+ """
+
+ return vim_util.get_moref(value, 'VmwareDistributedVirtualSwitch')
+
+
+def get_vlan_spec(session, vlan_id):
+ """Gets portgroup vlan spec.
+
+ :param session: vCenter soap session
+ :param vlan_id: the vlan_id for the port
+ :returns: The configuration when a single vlan_id is used for a port
+ """
+ # Create the spec for the vlan tag
+ client_factory = session.vim.client.factory
+ spec_ns = 'ns0:VmwareDistributedVirtualSwitchVlanIdSpec'
+ vl_spec = client_factory.create(spec_ns)
+ vl_spec.vlanId = vlan_id
+ vl_spec.inherited = '0'
+ return vl_spec
+
+
+def get_trunk_vlan_spec(session, start=0, end=4094):
+ """Gets portgroup trunk vlan spec.
+
+ :param session: vCenter soap session
+ :param start: the starting id
+ :param end: then end id
+ :returns: The configuration when a port uses trunk mode. This allows
+ a guest to manage the vlan id.
+ """
+ client_factory = session.vim.client.factory
+ spec_ns = 'ns0:VmwareDistributedVirtualSwitchTrunkVlanSpec'
+ vlan_id = client_factory.create('ns0:NumericRange')
+ vlan_id.start = start
+ vlan_id.end = end
+ vl_spec = client_factory.create(spec_ns)
+ vl_spec.vlanId = vlan_id
+ vl_spec.inherited = '0'
+ return vl_spec
+
+
+def get_port_group_spec(session, name, vlan_id, trunk_mode=False):
+ """Gets the port group spec for a distributed port group
+
+ :param session: vCenter soap session
+ :param name: the name of the port group
+ :param vlan_id: vlan_id for the port
+ :param trunk_mode: indicates if the port will have trunk mode or use
+ specific tag above
+ :returns: The configuration for a port group.
+ """
+ client_factory = session.vim.client.factory
+ pg_spec = client_factory.create('ns0:DVPortgroupConfigSpec')
+ pg_spec.name = name
+ pg_spec.type = 'ephemeral'
+ config = client_factory.create('ns0:VMwareDVSPortSetting')
+ if trunk_mode:
+ config.vlan = get_trunk_vlan_spec(session)
+ elif vlan_id:
+ config.vlan = get_vlan_spec(session, vlan_id)
+ pg_spec.defaultPortConfig = config
+ return pg_spec
+
+
+def add_port_group(session, dvs_moref, name, vlan_id=None,
+ trunk_mode=False):
+ """Add a new port group to the dvs_moref
+
+ :param session: vCenter soap session
+ :param dvs_moref: managed DVS object reference
+ :param name: the name of the port group
+ :param vlan_id: vlan_id for the port
+ :param trunk_mode: indicates if the port will have trunk mode or use
+ specific tag above
+ :returns: The new portgroup moref
+ """
+ pg_spec = get_port_group_spec(session, name, vlan_id,
+ trunk_mode=trunk_mode)
+ task = session.invoke_api(session.vim,
+ 'CreateDVPortgroup_Task',
+ dvs_moref,
+ spec=pg_spec)
+ task_info = session.wait_for_task(task)
+ LOG.info("%(name)s create on %(dvs)s with %(value)s.",
+ {'name': name,
+ 'dvs': dvs_moref.value,
+ 'value': task_info.result.value})
+ return task_info.result
+
+
+def get_portgroups(session, dvs_moref):
+ """Gets all configured portgroups on the dvs_moref
+
+ :param session: vCenter soap session
+ :param dvs_moref: managed DVS object reference
+ :returns: List of tuples that have the following format:
+ (portgroup name, port group moref)
+ """
+ pgs = []
+ port_groups = session.invoke_api(vim_util,
+ 'get_object_properties',
+ session.vim,
+ dvs_moref,
+ ['portgroup'])
+ while port_groups:
+ if len(port_groups) and hasattr(port_groups[0], 'propSet'):
+ for prop in port_groups[0].propSet:
+ for val in prop.val[0]:
+ props = session.invoke_api(vim_util,
+ 'get_object_properties',
+ session.vim,
+ val, ['name'])
+ if len(props) and hasattr(props[0], 'propSet'):
+ for prop in props[0].propSet:
+ pgs.append((prop.val, val))
+ port_groups = session._call_method(vim_util, 'continue_retrieval',
+ port_groups)
+ return pgs
+
+
+def delete_port_group(session, portgroup_moref):
+ """Delete a specific port group
+
+ :param session: vCenter soap session
+ :param portgroup_moref: managed portgroup object reference
+ """
+ task = session.invoke_api(session.vim,
+ 'Destroy_Task',
+ portgroup_moref)
+ session.wait_for_task(task)
diff --git a/oslo_vmware/tests/test_dvs_util.py b/oslo_vmware/tests/test_dvs_util.py
new file mode 100644
index 0000000..1179d46
--- /dev/null
+++ b/oslo_vmware/tests/test_dvs_util.py
@@ -0,0 +1,139 @@
+# Copyright (c) 2018 VMware, Inc.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""
+Unit tests for VMware DVS utility module.
+"""
+
+import collections
+
+import mock
+
+from oslo_vmware import dvs_util
+from oslo_vmware.tests import base
+from oslo_vmware import vim_util
+
+ObjectContent = collections.namedtuple('ObjectContent', ['obj', 'propSet'])
+DynamicProperty = collections.namedtuple('Property', ['name', 'val'])
+Moref = collections.namedtuple('Moref', ['name', 'type'])
+
+
+class DvsUtilTest(base.TestCase):
+ """Test class for utility methods in dvs_util."""
+
+ def test_get_dvs_moref(self):
+ moref = dvs_util.get_dvs_moref('dvs-123')
+ self.assertEqual('dvs-123', moref.value)
+ self.assertEqual('VmwareDistributedVirtualSwitch', moref._type)
+
+ def test_get_vlan_spec(self):
+ session = mock.Mock()
+ spec = dvs_util.get_vlan_spec(session, 7)
+ self.assertEqual(7, spec.vlanId)
+
+ def test_get_trunk_vlan_spec(self):
+ session = mock.Mock()
+ spec = dvs_util.get_trunk_vlan_spec(session, start=1, end=2)
+ self.assertEqual(1, spec.vlanId.start)
+ self.assertEqual(2, spec.vlanId.end)
+
+ def test_get_port_group_spec(self):
+ session = mock.Mock()
+ spec = dvs_util.get_port_group_spec(session, 'pg', 7)
+ self.assertEqual('pg', spec.name)
+ self.assertEqual('ephemeral', spec.type)
+ self.assertEqual(7, spec.defaultPortConfig.vlan.vlanId)
+
+ def test_get_port_group_spec_trunk(self):
+ session = mock.Mock()
+ spec = dvs_util.get_port_group_spec(session, 'pg', None,
+ trunk_mode=True)
+ self.assertEqual('pg', spec.name)
+ self.assertEqual('ephemeral', spec.type)
+ self.assertEqual(0, spec.defaultPortConfig.vlan.start)
+ self.assertEqual(4094, spec.defaultPortConfig.vlan.end)
+
+ @mock.patch.object(dvs_util, 'get_port_group_spec')
+ def test_add_port_group(self, mock_spec):
+ session = mock.Mock()
+ dvs_moref = dvs_util.get_dvs_moref('dvs-123')
+ spec = dvs_util.get_port_group_spec(session, 'pg', 7)
+ mock_spec.return_value = spec
+ pg_moref = vim_util.get_moref('dvportgroup-7',
+ 'DistributedVirtualPortgroup')
+
+ def wait_for_task_side_effect(task):
+ task_info = mock.Mock()
+ task_info.result = pg_moref
+ return task_info
+
+ session.wait_for_task.side_effect = wait_for_task_side_effect
+ pg = dvs_util.add_port_group(session, dvs_moref, 'pg',
+ vlan_id=7)
+ self.assertEqual(pg, pg_moref)
+ session.invoke_api.assert_called_once_with(
+ session.vim, 'CreateDVPortgroup_Task', dvs_moref,
+ spec=spec)
+
+ @mock.patch.object(dvs_util, 'get_port_group_spec')
+ def test_add_port_group_trunk(self, mock_spec):
+ session = mock.Mock()
+ dvs_moref = dvs_util.get_dvs_moref('dvs-123')
+ spec = dvs_util.get_port_group_spec(session, 'pg', None,
+ trunk_mode=True)
+ mock_spec.return_value = spec
+ dvs_util.add_port_group(session, dvs_moref, 'pg',
+ trunk_mode=True)
+ session.invoke_api.assert_called_once_with(
+ session.vim, 'CreateDVPortgroup_Task', dvs_moref,
+ spec=spec)
+
+ def test_get_portgroups_empty(self):
+ session = mock.Mock()
+ dvs_moref = dvs_util.get_dvs_moref('dvs-123')
+ session.invoke_api.return_value = []
+ pgs = dvs_util.get_portgroups(session, dvs_moref)
+ self.assertEqual([], pgs)
+
+ def test_get_portgroups(self):
+ session = mock.Mock()
+ dvs_moref = dvs_util.get_dvs_moref('dvs-123')
+ pg_moref = vim_util.get_moref('dvportgroup-7',
+ 'DistributedVirtualPortgroup')
+
+ def session_invoke_api_side_effect(module, method, *args, **kwargs):
+ if module == vim_util and method == 'get_object_properties':
+ if ['portgroup'] in args:
+ propSet = [DynamicProperty(name='portgroup',
+ val=[[pg_moref]])]
+ return [ObjectContent(obj=dvs_moref,
+ propSet=propSet)]
+ if ['name'] in args:
+ propSet = [DynamicProperty(name='name',
+ val='pg-name')]
+ return [ObjectContent(obj=pg_moref,
+ propSet=propSet)]
+
+ session.invoke_api.side_effect = session_invoke_api_side_effect
+ session._call_method.return_value = []
+ pgs = dvs_util.get_portgroups(session, dvs_moref)
+ result = [('pg-name', pg_moref)]
+ self.assertEqual(result, pgs)
+
+ def test_delete_port_group(self):
+ session = mock.Mock()
+ dvs_util.delete_port_group(session, 'pg-moref')
+ session.invoke_api.assert_called_once_with(
+ session.vim, 'Destroy_Task', 'pg-moref')