From 4f8fae5c7f8f85af3ead70aeab9e3bbdb9886379 Mon Sep 17 00:00:00 2001 From: Nurmatov Mamatisa Date: Wed, 18 Aug 2021 14:32:51 +0300 Subject: [PATCH] Add Neutron Local IP CRUD Add support for neutron local ip CRUD operations Change-Id: I3134b181992863280e1a2f7de00a5039d8ebcf4f Partial-Bug: #1930200 Depends-On: https://review.opendev.org/c/openstack/neutron/+/804523 --- doc/source/user/proxies/network.rst | 10 + doc/source/user/resources/network/index.rst | 2 + .../user/resources/network/v2/local_ip.rst | 12 ++ .../network/v2/local_ip_association.rst | 13 ++ openstack/network/v2/_proxy.py | 202 ++++++++++++++++++ openstack/network/v2/local_ip.py | 61 ++++++ openstack/network/v2/local_ip_association.py | 47 ++++ .../functional/network/v2/test_local_ip.py | 68 ++++++ .../network/v2/test_local_ip_association.py | 68 ++++++ .../tests/unit/network/v2/test_local_ip.py | 68 ++++++ .../network/v2/test_local_ip_association.py | 56 +++++ openstack/tests/unit/network/v2/test_proxy.py | 101 +++++++++ 12 files changed, 708 insertions(+) create mode 100644 doc/source/user/resources/network/v2/local_ip.rst create mode 100644 doc/source/user/resources/network/v2/local_ip_association.rst create mode 100644 openstack/network/v2/local_ip.py create mode 100644 openstack/network/v2/local_ip_association.py create mode 100644 openstack/tests/functional/network/v2/test_local_ip.py create mode 100644 openstack/tests/functional/network/v2/test_local_ip_association.py create mode 100644 openstack/tests/unit/network/v2/test_local_ip.py create mode 100644 openstack/tests/unit/network/v2/test_local_ip_association.py diff --git a/doc/source/user/proxies/network.rst b/doc/source/user/proxies/network.rst index 6688ee062..f4f3a42e2 100644 --- a/doc/source/user/proxies/network.rst +++ b/doc/source/user/proxies/network.rst @@ -265,3 +265,13 @@ Service Provider Operations .. autoclass:: openstack.network.v2._proxy.Proxy :noindex: :members: service_providers + +Local IP Operations +^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: openstack.network.v2._proxy.Proxy + :noindex: + :members: create_local_ip, delete_local_ip, find_local_ip, get_local_ip, + local_ips, update_local_ip, create_local_ip_association, + delete_local_ip_association, find_local_ip_association, + get_local_ip_association, local_ip_associations diff --git a/doc/source/user/resources/network/index.rst b/doc/source/user/resources/network/index.rst index 3e54e0ed1..c8e365823 100644 --- a/doc/source/user/resources/network/index.rst +++ b/doc/source/user/resources/network/index.rst @@ -17,6 +17,8 @@ Network Resources v2/ikepolicy v2/listener v2/load_balancer + v2/local_ip + v2/local_ip_association v2/metering_label v2/metering_label_rule v2/network diff --git a/doc/source/user/resources/network/v2/local_ip.rst b/doc/source/user/resources/network/v2/local_ip.rst new file mode 100644 index 000000000..30f846ad7 --- /dev/null +++ b/doc/source/user/resources/network/v2/local_ip.rst @@ -0,0 +1,12 @@ +openstack.network.v2.local_ip +============================= + +.. automodule:: openstack.network.v2.local_ip + +The LocalIP Class +----------------- + +The ``LocalIP`` class inherits from :class:`~openstack.resource.Resource`. + +.. autoclass:: openstack.network.v2.local_ip.LocalIP + :members: diff --git a/doc/source/user/resources/network/v2/local_ip_association.rst b/doc/source/user/resources/network/v2/local_ip_association.rst new file mode 100644 index 000000000..12b59a9f2 --- /dev/null +++ b/doc/source/user/resources/network/v2/local_ip_association.rst @@ -0,0 +1,13 @@ +openstack.network.v2.local_ip_association +========================================= + +.. automodule:: openstack.network.v2.local_ip_association + +The LocalIPAssociation Class +---------------------------- + +The ``LocalIPAssociation`` class inherits from +:class:`~openstack.resource.Resource`. + +.. autoclass:: openstack.network.v2.local_ip_association.LocalIPAssociation + :members: diff --git a/openstack/network/v2/_proxy.py b/openstack/network/v2/_proxy.py index 86da25270..7a11d1fe2 100644 --- a/openstack/network/v2/_proxy.py +++ b/openstack/network/v2/_proxy.py @@ -30,6 +30,8 @@ from openstack.network.v2 import ipsec_site_connection as \ from openstack.network.v2 import l3_conntrack_helper as _l3_conntrack_helper from openstack.network.v2 import listener as _listener from openstack.network.v2 import load_balancer as _load_balancer +from openstack.network.v2 import local_ip as _local_ip +from openstack.network.v2 import local_ip_association as _local_ip_association from openstack.network.v2 import metering_label as _metering_label from openstack.network.v2 import metering_label_rule as _metering_label_rule from openstack.network.v2 import network as _network @@ -622,6 +624,206 @@ class Proxy(proxy.Proxy): return flavor.disassociate_flavor_from_service_profile( self, service_profile.id) + def create_local_ip(self, **attrs): + """Create a new local ip from attributes + + :param dict attrs: Keyword arguments which will be used to create + a :class:`~openstack.network.v2.local_ip.LocalIP`, + comprised of the properties on the LocalIP class. + + :returns: The results of local ip creation + :rtype: :class:`~openstack.network.v2.local_ip.LocalIP` + """ + return self._create(_local_ip.LocalIP, **attrs) + + def delete_local_ip(self, local_ip, ignore_missing=True, if_revision=None): + """Delete a local ip + + :param local_ip: The value can be either the ID of a local ip or a + :class:`~openstack.network.v2.local_ip.LocalIP` + instance. + :param bool ignore_missing: When set to ``False`` + :class:`~openstack.exceptions.ResourceNotFound` will be + raised when the local ip does not exist. + When set to ``True``, no exception will be set when + attempting to delete a nonexistent ip. + :param int if_revision: Revision to put in If-Match header of update + request to perform compare-and-swap update. + + :returns: ``None`` + """ + self._delete(_local_ip.LocalIP, local_ip, + ignore_missing=ignore_missing, if_revision=if_revision) + + def find_local_ip(self, name_or_id, ignore_missing=True, **args): + """Find a local IP + + :param name_or_id: The name or ID of an local IP. + :param bool ignore_missing: When set to ``False`` + :class:`~openstack.exceptions.ResourceNotFound` will be + raised when the resource does not exist. + When set to ``True``, None will be returned when + attempting to find a nonexistent resource. + :param dict args: Any additional parameters to be passed into + underlying methods. such as query filters. + :returns: One :class:`~openstack.network.v2.local_ip.LocalIP` + or None + """ + return self._find(_local_ip.LocalIP, name_or_id, + ignore_missing=ignore_missing, **args) + + def get_local_ip(self, local_ip): + """Get a single local ip + + :param local_ip: The value can be the ID of a local ip or a + :class:`~openstack.network.v2.local_ip.LocalIP` + instance. + + :returns: One :class:`~openstack.network.v2.local_ip.LocalIP` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_local_ip.LocalIP, local_ip) + + def local_ips(self, **query): + """Return a generator of local ips + + :param dict query: Optional query parameters to be sent to limit + the resources being returned. + + * ``name``: Local IP name + * ``description``: Local IP description + * ``project_id``: Owner project ID + + :returns: A generator of local ip objects + :rtype: :class:`~openstack.network.v2.local_ip.LocalIP` + """ + return self._list(_local_ip.LocalIP, **query) + + def update_local_ip(self, local_ip, if_revision=None, **attrs): + """Update a local ip + + :param local_ip: Either the id of a local ip or a + :class:`~openstack.network.v2.local_ip.LocalIP` + instance. + :param int if_revision: Revision to put in If-Match header of update + request to perform compare-and-swap update. + :param dict attrs: The attributes to update on the ip represented + by ``value``. + + :returns: The updated ip + :rtype: :class:`~openstack.network.v2.local_ip.LocalIP` + """ + return self._update(_local_ip.LocalIP, local_ip, + if_revision=if_revision, **attrs) + + def create_local_ip_association(self, local_ip, **attrs): + """Create a new local ip association from attributes + + :param local_ip: The value can be the ID of a Local IP or a + :class:`~openstack.network.v2.local_ip.LocalIP` + instance. + :param dict attrs: Keyword arguments which will be used to create + a :class:`~openstack.network.v2. + local_ip_association.LocalIPAssociation`, + comprised of the properties on the LocalIP class. + + :returns: The results of local ip association creation + :rtype: :class:`~openstack.network.v2.local_ip_association. + LocalIPAssociation` + """ + local_ip = self._get_resource(_local_ip.LocalIP, local_ip) + return self._create(_local_ip_association.LocalIPAssociation, + local_ip_id=local_ip.id, **attrs) + + def delete_local_ip_association(self, local_ip, fixed_port_id, + ignore_missing=True, if_revision=None): + """Delete a local ip association + + :param local_ip: The value can be the ID of a Local IP or a + :class:`~openstack.network.v2.local_ip.LocalIP` + instance. + :param fixed_port_id: The value can be either the fixed port ID + or a :class: + `~openstack.network.v2.local_ip_association.LocalIPAssociation` + instance. + :param bool ignore_missing: When set to ``False`` + :class:`~openstack.exceptions.ResourceNotFound` will be + raised when the local ip association does not exist. + When set to ``True``, no exception will be set when + attempting to delete a nonexistent ip. + :param int if_revision: Revision to put in If-Match header of update + request to perform compare-and-swap update. + + :returns: ``None`` + """ + local_ip = self._get_resource(_local_ip.LocalIP, local_ip) + self._delete(_local_ip_association.LocalIPAssociation, fixed_port_id, + local_ip_id=local_ip.id, + ignore_missing=ignore_missing, if_revision=if_revision) + + def find_local_ip_association(self, name_or_id, local_ip, + ignore_missing=True, **args): + """Find a local ip association + + :param name_or_id: The name or ID of local ip association. + :param local_ip: The value can be the ID of a Local IP or a + :class:`~openstack.network.v2.local_ip.LocalIP` + instance. + :param bool ignore_missing: When set to ``False`` + :class:`~openstack.exceptions.ResourceNotFound` will be + raised when the resource does not exist. + When set to ``True``, None will be returned when + attempting to find a nonexistent resource. + :param dict args: Any additional parameters to be passed into + underlying methods. such as query filters. + :returns: One :class:`~openstack.network.v2. + local_ip_association.LocalIPAssociation` + or None + """ + local_ip = self._get_resource(_local_ip.LocalIP, local_ip) + return self._find(_local_ip_association.LocalIPAssociation, name_or_id, + local_ip_id=local_ip.id, + ignore_missing=ignore_missing, **args) + + def get_local_ip_association(self, local_ip_association, local_ip): + """Get a single local ip association + + :param local_ip: The value can be the ID of a Local IP or a + :class:`~openstack.network.v2.local_ip.LocalIP` + instance. + :param local_ip_association: The value can be the ID + of a local ip association or a + :class:`~openstack.network.v2. + local_ip_association.LocalIPAssociation` + instance. + + :returns: One :class:`~openstack.network.v2. + local_ip_association.LocalIPAssociation` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + local_ip = self._get_resource(_local_ip.LocalIP, local_ip) + return self._get(_local_ip_association.LocalIPAssociation, + local_ip_association, + local_ip_id=local_ip.id) + + def local_ip_associations(self, local_ip, **query): + """Return a generator of local ip associations + + :param local_ip: The value can be the ID of a Local IP or a + :class:`~openstack.network.v2.local_ip.LocalIP` instance. + :param dict query: Optional query parameters to be sent to limit + the resources being returned. + + :returns: A generator of local ip association objects + :rtype: :class:`~openstack.network.v2. + local_ip_association.LocalIPAssociation` + """ + local_ip = self._get_resource(_local_ip.LocalIP, local_ip) + return self._list(_local_ip_association.LocalIPAssociation, + local_ip_id=local_ip.id, **query) + def create_ip(self, **attrs): """Create a new floating ip from attributes diff --git a/openstack/network/v2/local_ip.py b/openstack/network/v2/local_ip.py new file mode 100644 index 000000000..e791cbca3 --- /dev/null +++ b/openstack/network/v2/local_ip.py @@ -0,0 +1,61 @@ +# Copyright 2021 Huawei, 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. +# + +from openstack import resource + + +class LocalIP(resource.Resource): + """Local IP extension.""" + resource_name = "local ip" + resource_key = "local_ip" + resources_key = "local_ips" + base_path = "/local_ips" + + # capabilities + allow_create = True + allow_fetch = True + allow_commit = True + allow_delete = True + allow_list = True + + _allow_unknown_attrs_in_body = True + + _query_mapping = resource.QueryParameters( + "sort_key", "sort_dir", + 'name', 'description',) + + # Properties + #: Timestamp at which the floating IP was created. + created_at = resource.Body('created_at') + #: The local ip description. + description = resource.Body('description') + #: The ID of the local ip. + id = resource.Body('id') + #: The local ip ip-mode. + ip_mode = resource.Body('ip_mode') + #: The Local IP address. + local_ip_address = resource.Body('local_ip_address') + #: The ID of the port that owns the local ip. + local_port_id = resource.Body('local_port_id') + #: The local ip name. + name = resource.Body('name') + #: The ID of the network that owns the local ip. + network_id = resource.Body('network_id') + #: The ID of the project that owns the local ip. + project_id = resource.Body('project_id') + #: The local ip revision number. + revision_number = resource.Body('revision_number') + #: Timestamp at which the floating IP was last updated. + updated_at = resource.Body('updated_at') diff --git a/openstack/network/v2/local_ip_association.py b/openstack/network/v2/local_ip_association.py new file mode 100644 index 000000000..d99ef3bed --- /dev/null +++ b/openstack/network/v2/local_ip_association.py @@ -0,0 +1,47 @@ +# Copyright 2021 Huawei, 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. +# + +from openstack import resource + + +class LocalIPAssociation(resource.Resource): + """Local IP extension.""" + resource_key = "port_association" + resources_key = "port_associations" + base_path = "/local_ips/%(local_ip_id)s/port_associations" + + # capabilities + allow_create = True + allow_fetch = True + allow_commit = True + allow_delete = True + allow_list = True + + _allow_unknown_attrs_in_body = True + + _query_mapping = resource.QueryParameters( + 'local_ip_address', 'fixed_port_id', 'fixed_ip' + ) + # Properties + #: The fixed port ID. + fixed_port_id = resource.Body('fixed_port_id') + #: The fixed IP. + fixed_ip = resource.Body('fixed_ip') + #: Host + host = resource.Body('host') + #: The local ip address + local_ip_address = resource.Body('local_ip_address') + #: The ID of Local IP address + local_ip_id = resource.URI('local_ip_id') diff --git a/openstack/tests/functional/network/v2/test_local_ip.py b/openstack/tests/functional/network/v2/test_local_ip.py new file mode 100644 index 000000000..01e343aeb --- /dev/null +++ b/openstack/tests/functional/network/v2/test_local_ip.py @@ -0,0 +1,68 @@ +# Copyright 2021 Huawei, 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. +# + +from openstack.network.v2 import local_ip as _local_ip +from openstack.tests.functional import base + + +class TestLocalIP(base.BaseFunctionalTest): + + LOCAL_IP_ID = None + + def setUp(self): + super(TestLocalIP, self).setUp() + + if not self.conn.network.find_extension('local_ip'): + self.skipTest('Local IP extension disabled') + + self.LOCAL_IP_NAME = self.getUniqueString() + self.LOCAL_IP_DESCRIPTION = self.getUniqueString() + self.LOCAL_IP_NAME_UPDATED = self.getUniqueString() + self.LOCAL_IP_DESCRIPTION_UPDATED = self.getUniqueString() + local_ip = self.conn.network.create_local_ip( + name=self.LOCAL_IP_NAME, + description=self.LOCAL_IP_DESCRIPTION, + ) + assert isinstance(local_ip, _local_ip.LocalIP) + self.assertEqual(self.LOCAL_IP_NAME, local_ip.name) + self.assertEqual(self.LOCAL_IP_DESCRIPTION, + local_ip.description) + self.LOCAL_IP_ID = local_ip.id + + def tearDown(self): + sot = self.conn.network.delete_local_ip(self.LOCAL_IP_ID) + self.assertIsNone(sot) + super(TestLocalIP, self).tearDown() + + def test_find(self): + sot = self.conn.network.find_local_ip(self.LOCAL_IP_NAME) + self.assertEqual(self.LOCAL_IP_ID, sot.id) + + def test_get(self): + sot = self.conn.network.get_local_ip(self.LOCAL_IP_ID) + self.assertEqual(self.LOCAL_IP_NAME, sot.name) + + def test_list(self): + names = [local_ip.name for local_ip in self.conn.network.local_ips()] + self.assertIn(self.LOCAL_IP_NAME, names) + + def test_update(self): + sot = self.conn.network.update_local_ip( + self.LOCAL_IP_ID, + name=self.LOCAL_IP_NAME_UPDATED, + description=self.LOCAL_IP_DESCRIPTION_UPDATED) + self.assertEqual(self.LOCAL_IP_NAME_UPDATED, sot.name) + self.assertEqual(self.LOCAL_IP_DESCRIPTION_UPDATED, + sot.description) diff --git a/openstack/tests/functional/network/v2/test_local_ip_association.py b/openstack/tests/functional/network/v2/test_local_ip_association.py new file mode 100644 index 000000000..e4f1dbb48 --- /dev/null +++ b/openstack/tests/functional/network/v2/test_local_ip_association.py @@ -0,0 +1,68 @@ +# Copyright 2021 Huawei, 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. +# + +from openstack.network.v2 import local_ip_association as _local_ip_association +from openstack.tests.functional import base + + +class TestLocalIPAssociation(base.BaseFunctionalTest): + LOCAL_IP_ID = None + FIXED_PORT_ID = None + FIXED_IP = None + + def setUp(self): + super(TestLocalIPAssociation, self).setUp() + + if not self.conn.network.find_extension('local_ip'): + self.skipTest('Local IP extension disabled') + + self.LOCAL_IP_ID = self.getUniqueString() + self.FIXED_PORT_ID = self.getUniqueString() + self.FIXED_IP = self.getUniqueString() + local_ip_association = self.conn.network.create_local_ip_association( + local_ip=self.LOCAL_IP_ID, + fixed_port_id=self.FIXED_PORT_ID, + fixed_ip=self.FIXED_IP + ) + assert isinstance(local_ip_association, + _local_ip_association.LocalIPAssociation) + self.assertEqual(self.LOCAL_IP_ID, local_ip_association.local_ip_id) + self.assertEqual(self.FIXED_PORT_ID, + local_ip_association.fixed_port_id) + self.assertEqual(self.FIXED_IP, + local_ip_association.fixed_ip) + + def tearDown(self): + sot = self.conn.network.delete_local_ip_association( + self.LOCAL_IP_ID, + self.FIXED_PORT_ID) + self.assertIsNone(sot) + super(TestLocalIPAssociation, self).tearDown() + + def test_find(self): + sot = self.conn.network.find_local_ip_association(self.FIXED_PORT_ID, + self.LOCAL_IP_ID) + self.assertEqual(self.FIXED_PORT_ID, sot.fixed_port_id) + + def test_get(self): + sot = self.conn.network.get_local_ip_association(self.FIXED_PORT_ID, + self.LOCAL_IP_ID) + self.assertEqual(self.FIXED_PORT_ID, sot.fixed_port_id) + + def test_list(self): + fixed_port_id = [obj.fixed_port_id for obj in + self.conn.network.local_ip_associations( + self.LOCAL_IP_ID)] + self.assertIn(self.FIXED_PORT_ID, fixed_port_id) diff --git a/openstack/tests/unit/network/v2/test_local_ip.py b/openstack/tests/unit/network/v2/test_local_ip.py new file mode 100644 index 000000000..2dce8576a --- /dev/null +++ b/openstack/tests/unit/network/v2/test_local_ip.py @@ -0,0 +1,68 @@ +# Copyright 2021 Huawei, 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. +# + +from openstack.network.v2 import local_ip +from openstack.tests.unit import base + +IDENTIFIER = 'IDENTIFIER' +EXAMPLE = { + 'created_at': '0', + 'id': IDENTIFIER, + 'name': '1', + 'description': '2', + 'project_id': '3', + 'local_port_id': '4', + 'network_id': '5', + 'local_ip_address': '127.0.0.1', + 'ip_mode': 'translate', + 'revision_number': '6', + 'updated_at': '7', +} + + +class TestLocalIP(base.TestCase): + + def test_basic(self): + sot = local_ip.LocalIP() + self.assertEqual('local_ip', sot.resource_key) + self.assertEqual('local_ips', sot.resources_key) + self.assertEqual('/local_ips', sot.base_path) + self.assertTrue(sot.allow_create) + self.assertTrue(sot.allow_fetch) + self.assertTrue(sot.allow_commit) + self.assertTrue(sot.allow_delete) + self.assertTrue(sot.allow_list) + + self.assertDictEqual({"name": "name", + "description": "description", + "sort_key": "sort_key", + "sort_dir": "sort_dir", + "limit": "limit", + "marker": "marker"}, + sot._query_mapping._mapping) + + def test_make_it(self): + sot = local_ip.LocalIP(**EXAMPLE) + self.assertEqual(EXAMPLE['created_at'], sot.created_at) + self.assertEqual(EXAMPLE['id'], sot.id) + self.assertEqual(EXAMPLE['name'], sot.name) + self.assertEqual(EXAMPLE['description'], sot.description) + self.assertEqual(EXAMPLE['project_id'], sot.project_id) + self.assertEqual(EXAMPLE['local_port_id'], sot.local_port_id) + self.assertEqual(EXAMPLE['network_id'], sot.network_id) + self.assertEqual(EXAMPLE['local_ip_address'], sot.local_ip_address) + self.assertEqual(EXAMPLE['ip_mode'], sot.ip_mode) + self.assertEqual(EXAMPLE['revision_number'], sot.revision_number) + self.assertEqual(EXAMPLE['updated_at'], sot.updated_at) diff --git a/openstack/tests/unit/network/v2/test_local_ip_association.py b/openstack/tests/unit/network/v2/test_local_ip_association.py new file mode 100644 index 000000000..5e55f959e --- /dev/null +++ b/openstack/tests/unit/network/v2/test_local_ip_association.py @@ -0,0 +1,56 @@ +# Copyright 2021 Huawei, 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. +# + +from openstack.network.v2 import local_ip_association +from openstack.tests.unit import base + +EXAMPLE = { + 'local_ip_id': '0', + 'local_ip_address': '127.0.0.1', + 'fixed_port_id': '1', + 'fixed_ip': '127.0.0.2', + 'host': '2', +} + + +class TestLocalIP(base.TestCase): + + def test_basic(self): + sot = local_ip_association.LocalIPAssociation() + self.assertEqual('port_association', sot.resource_key) + self.assertEqual('port_associations', sot.resources_key) + self.assertEqual('/local_ips/%(local_ip_id)s/port_associations', + sot.base_path) + self.assertTrue(sot.allow_create) + self.assertTrue(sot.allow_fetch) + self.assertTrue(sot.allow_commit) + self.assertTrue(sot.allow_delete) + self.assertTrue(sot.allow_list) + + self.assertDictEqual( + {'local_ip_address': 'local_ip_address', + 'fixed_port_id': 'fixed_port_id', + 'fixed_ip': 'fixed_ip', + 'limit': 'limit', + 'marker': 'marker'}, + sot._query_mapping._mapping) + + def test_make_it(self): + sot = local_ip_association.LocalIPAssociation(**EXAMPLE) + self.assertEqual(EXAMPLE['local_ip_id'], sot.local_ip_id) + self.assertEqual(EXAMPLE['local_ip_address'], sot.local_ip_address) + self.assertEqual(EXAMPLE['fixed_port_id'], sot.fixed_port_id) + self.assertEqual(EXAMPLE['fixed_ip'], sot.fixed_ip) + self.assertEqual(EXAMPLE['host'], sot.host) diff --git a/openstack/tests/unit/network/v2/test_proxy.py b/openstack/tests/unit/network/v2/test_proxy.py index 6b6d2d98c..57ffe83fc 100644 --- a/openstack/tests/unit/network/v2/test_proxy.py +++ b/openstack/tests/unit/network/v2/test_proxy.py @@ -31,6 +31,8 @@ from openstack.network.v2 import ipsec_site_connection from openstack.network.v2 import l3_conntrack_helper from openstack.network.v2 import listener from openstack.network.v2 import load_balancer +from openstack.network.v2 import local_ip +from openstack.network.v2 import local_ip_association from openstack.network.v2 import metering_label from openstack.network.v2 import metering_label_rule from openstack.network.v2 import network @@ -67,6 +69,7 @@ AGENT_ID = 'agent-id-' + uuid.uuid4().hex ROUTER_ID = 'router-id-' + uuid.uuid4().hex FIP_ID = 'fip-id-' + uuid.uuid4().hex CT_HELPER_ID = 'ct-helper-id-' + uuid.uuid4().hex +LOCAL_IP_ID = 'lip-id-' + uuid.uuid4().hex class TestNetworkProxy(test_proxy_base.TestProxyBase): @@ -493,6 +496,104 @@ class TestNetworkFlavor(TestNetworkProxy): self.verify_list(self.proxy.flavors, flavor.Flavor) +class TestNetworkLocalIp(TestNetworkProxy): + def test_local_ip_create_attrs(self): + self.verify_create(self.proxy.create_local_ip, local_ip.LocalIP) + + def test_local_ip_delete(self): + self.verify_delete(self.proxy.delete_local_ip, local_ip.LocalIP, + False, expected_kwargs={'if_revision': None}) + + def test_local_ip_delete_ignore(self): + self.verify_delete(self.proxy.delete_local_ip, local_ip.LocalIP, + True, expected_kwargs={'if_revision': None}) + + def test_local_ip_delete_if_revision(self): + self.verify_delete(self.proxy.delete_local_ip, local_ip.LocalIP, + True, method_kwargs={'if_revision': 42}, + expected_kwargs={'if_revision': 42}) + + def test_local_ip_find(self): + self.verify_find(self.proxy.find_local_ip, local_ip.LocalIP) + + def test_local_ip_get(self): + self.verify_get(self.proxy.get_local_ip, local_ip.LocalIP) + + def test_local_ips(self): + self.verify_list(self.proxy.local_ips, local_ip.LocalIP) + + def test_local_ip_update(self): + self.verify_update(self.proxy.update_local_ip, local_ip.LocalIP, + expected_kwargs={'x': 1, 'y': 2, 'z': 3, + 'if_revision': None}) + + def test_local_ip_update_if_revision(self): + self.verify_update(self.proxy.update_local_ip, local_ip.LocalIP, + method_kwargs={'x': 1, 'y': 2, 'z': 3, + 'if_revision': 42}, + expected_kwargs={'x': 1, 'y': 2, 'z': 3, + 'if_revision': 42}) + + +class TestNetworkLocalIpAssociation(TestNetworkProxy): + def test_local_ip_association_create_attrs(self): + self.verify_create(self.proxy.create_local_ip_association, + local_ip_association.LocalIPAssociation, + method_kwargs={'local_ip': LOCAL_IP_ID}, + expected_kwargs={'local_ip_id': LOCAL_IP_ID}) + + def test_local_ip_association_delete(self): + self.verify_delete( + self.proxy.delete_local_ip_association, + local_ip_association.LocalIPAssociation, + ignore_missing=False, + method_args=[LOCAL_IP_ID, "resource_or_id"], + expected_args=["resource_or_id"], + expected_kwargs={'if_revision': None, + 'local_ip_id': LOCAL_IP_ID}) + + def test_local_ip_association_delete_ignore(self): + self.verify_delete( + self.proxy.delete_local_ip_association, + local_ip_association.LocalIPAssociation, + ignore_missing=True, + method_args=[LOCAL_IP_ID, "resource_or_id"], + expected_args=["resource_or_id"], + expected_kwargs={'if_revision': None, + 'local_ip_id': LOCAL_IP_ID}) + + def test_local_ip_association_find(self): + lip = local_ip.LocalIP.new(id=LOCAL_IP_ID) + + self._verify( + 'openstack.proxy.Proxy._find', + self.proxy.find_local_ip_association, + method_args=['local_ip_association_id', lip], + expected_args=[ + local_ip_association.LocalIPAssociation, + 'local_ip_association_id'], + expected_kwargs={ + 'ignore_missing': True, 'local_ip_id': LOCAL_IP_ID}) + + def test_local_ip_association_get(self): + lip = local_ip.LocalIP.new(id=LOCAL_IP_ID) + + self._verify( + 'openstack.proxy.Proxy._get', + self.proxy.get_local_ip_association, + method_args=['local_ip_association_id', lip], + expected_args=[ + local_ip_association.LocalIPAssociation, + 'local_ip_association_id'], + expected_kwargs={'local_ip_id': LOCAL_IP_ID}) + + def test_local_ip_associations(self): + self.verify_list(self.proxy.local_ip_associations, + local_ip_association.LocalIPAssociation, + method_kwargs={'local_ip': LOCAL_IP_ID}, + expected_kwargs={'local_ip_id': LOCAL_IP_ID}) + + class TestNetworkServiceProfile(TestNetworkProxy): def test_service_profile_create_attrs(self): self.verify_create(self.proxy.create_service_profile,