diff --git a/doc/source/user/proxies/network.rst b/doc/source/user/proxies/network.rst index a742f9996..4e5ef4dfb 100644 --- a/doc/source/user/proxies/network.rst +++ b/doc/source/user/proxies/network.rst @@ -357,3 +357,11 @@ SFC operations update_sfc_port_pair_group, create_sfc_service_graph, delete_sfc_service_graph, find_sfc_service_graph, get_sfc_service_graph, update_sfc_service_graph + +Tap Mirror operations +^^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: openstack.network.v2._proxy.Proxy + :noindex: + :members: create_tap_mirror, delete_tap_mirror, find_tap_mirror, + get_tap_mirror, tap_mirrors, update_tap_mirror diff --git a/doc/source/user/resources/network/v2/tap_mirror.rst b/doc/source/user/resources/network/v2/tap_mirror.rst new file mode 100644 index 000000000..8697b1973 --- /dev/null +++ b/doc/source/user/resources/network/v2/tap_mirror.rst @@ -0,0 +1,12 @@ +openstack.network.v2.tap_mirror +=============================== + +.. automodule:: openstack.network.v2.tap_mirror + +The TapMirror Class +------------------- + +The ``TapMirror`` class inherits from :class:`~openstack.resource.Resource`. + +.. autoclass:: openstack.network.v2.tap_mirror.TapMirror + :members: diff --git a/openstack/network/v2/_proxy.py b/openstack/network/v2/_proxy.py index 70ed80193..be363bfce 100644 --- a/openstack/network/v2/_proxy.py +++ b/openstack/network/v2/_proxy.py @@ -89,6 +89,7 @@ from openstack.network.v2 import sfc_service_graph as _sfc_sservice_graph from openstack.network.v2 import subnet as _subnet from openstack.network.v2 import subnet_pool as _subnet_pool from openstack.network.v2 import tap_flow as _tap_flow +from openstack.network.v2 import tap_mirror as _tap_mirror from openstack.network.v2 import tap_service as _tap_service from openstack.network.v2 import trunk as _trunk from openstack.network.v2 import vpn_endpoint_group as _vpn_endpoint_group @@ -178,6 +179,7 @@ class Proxy(proxy.Proxy): "subnet": _subnet.Subnet, "subnet_pool": _subnet_pool.SubnetPool, "tap_flow": _tap_flow.TapFlow, + "tap_mirror": _tap_mirror.TapMirror, "tap_service": _tap_service.TapService, "trunk": _trunk.Trunk, "vpn_endpoint_group": _vpn_endpoint_group.VpnEndpointGroup, @@ -6328,6 +6330,37 @@ class Proxy(proxy.Proxy): """Return a generator of Tap Flows""" return self._list(_tap_flow.TapFlow, **query) + def create_tap_mirror(self, **attrs): + """Create a new Tap Mirror from attributes""" + return self._create(_tap_mirror.TapMirror, **attrs) + + def delete_tap_mirror(self, tap_mirror, ignore_missing=True): + """Delete a Tap Mirror""" + self._delete( + _tap_mirror.TapMirror, tap_mirror, ignore_missing=ignore_missing + ) + + def find_tap_mirror(self, name_or_id, ignore_missing=True, **query): + """Find a single Tap Mirror""" + return self._find( + _tap_mirror.TapMirror, + name_or_id, + ignore_missing=ignore_missing, + **query, + ) + + def get_tap_mirror(self, tap_mirror): + """Get a signle Tap Mirror""" + return self._get(_tap_mirror.TapMirror, tap_mirror) + + def update_tap_mirror(self, tap_mirror, **attrs): + """Update a Tap Mirror""" + return self._update(_tap_mirror.TapMirror, tap_mirror, **attrs) + + def tap_mirrors(self, **query): + """Return a generator of Tap Mirrors""" + return self._list(_tap_mirror.TapMirror, **query) + def create_tap_service(self, **attrs): """Create a new Tap Service from attributes""" return self._create(_tap_service.TapService, **attrs) diff --git a/openstack/network/v2/tap_mirror.py b/openstack/network/v2/tap_mirror.py new file mode 100644 index 000000000..562c91039 --- /dev/null +++ b/openstack/network/v2/tap_mirror.py @@ -0,0 +1,54 @@ +# 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 TapMirror(resource.Resource): + """Tap Mirror""" + + resource_key = 'tap_mirror' + resources_key = 'tap_mirrors' + base_path = '/taas/tap_mirrors' + + # 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', 'project_id' + ) + + # Properties + #: The ID of the Tap Mirror. + id = resource.Body('id') + #: The Tap Mirror name. + name = resource.Body('name') + #: The Tap Mirror description. + description = resource.Body('description') + #: The ID of the project that owns the Tap Mirror. + project_id = resource.Body('project_id', alias='tenant_id') + #: Tenant_id (deprecated attribute). + tenant_id = resource.Body('tenant_id', deprecated=True) + #: The id of the port the Tap Mirror is associated with + port_id = resource.Body('port_id') + #: The status for the tap service. + directions = resource.Body('directions') + #: The destination IP address of the Tap Mirror + remote_ip = resource.Body('remote_ip') + #: The type of the Tap Mirror, it can be gre or erspanv1 + mirror_type = resource.Body('mirror_type') diff --git a/openstack/tests/functional/network/v2/test_tap_mirror.py b/openstack/tests/functional/network/v2/test_tap_mirror.py new file mode 100644 index 000000000..aa781441f --- /dev/null +++ b/openstack/tests/functional/network/v2/test_tap_mirror.py @@ -0,0 +1,83 @@ +# 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 network as _network +from openstack.network.v2 import port as _port +from openstack.network.v2 import tap_mirror as _tap_mirror +from openstack.tests.functional import base + + +class TestTapMirror(base.BaseFunctionalTest): + def setUp(self): + super().setUp() + + if not self.user_cloud.network.find_extension("tap-mirror"): + self.skipTest("Neutron Tap Mirror Extension disabled") + + self.TAP_M_NAME = 'my_tap_mirror' + self.getUniqueString() + net = self.user_cloud.network.create_network() + assert isinstance(net, _network.Network) + self.MIRROR_NET_ID = net.id + + port = self.user_cloud.network.create_port( + network_id=self.MIRROR_NET_ID + ) + assert isinstance(port, _port.Port) + self.MIRROR_PORT_ID = port.id + + self.REMOTE_IP = '193.10.10.2' + self.MIRROR_TYPE = 'erspanv1' + + tap_mirror = self.user_cloud.network.create_tap_mirror( + name=self.TAP_M_NAME, + port_id=self.MIRROR_PORT_ID, + remote_ip=self.REMOTE_IP, + mirror_type=self.MIRROR_TYPE, + directions={'IN': 99}, + ) + assert isinstance(tap_mirror, _tap_mirror.TapMirror) + self.TAP_MIRROR = tap_mirror + + def tearDown(self): + sot = self.user_cloud.network.delete_tap_mirror( + self.TAP_MIRROR.id, ignore_missing=False + ) + self.assertIsNone(sot) + sot = self.user_cloud.network.delete_port(self.MIRROR_PORT_ID) + self.assertIsNone(sot) + sot = self.user_cloud.network.delete_network(self.MIRROR_NET_ID) + self.assertIsNone(sot) + + super().tearDown() + + def test_find_tap_mirror(self): + sot = self.user_cloud.network.find_tap_mirror(self.TAP_MIRROR.name) + self.assertEqual(self.MIRROR_PORT_ID, sot.port_id) + self.assertEqual(self.TAP_M_NAME, sot.name) + + def test_get_tap_mirror(self): + sot = self.user_cloud.network.get_tap_mirror(self.TAP_MIRROR.id) + self.assertEqual(self.MIRROR_PORT_ID, sot.port_id) + self.assertEqual(self.TAP_M_NAME, sot.name) + + def test_list_tap_mirrors(self): + tap_mirror_ids = [ + tm.id for tm in self.user_cloud.network.tap_mirrors() + ] + self.assertIn(self.TAP_MIRROR.id, tap_mirror_ids) + + def test_update_tap_mirror(self): + description = 'My Tap Mirror' + sot = self.user_cloud.network.update_tap_mirror( + self.TAP_MIRROR.id, description=description + ) + self.assertEqual(description, sot.description) diff --git a/openstack/tests/unit/network/v2/test_proxy.py b/openstack/tests/unit/network/v2/test_proxy.py index 844e844a4..45560a3eb 100644 --- a/openstack/tests/unit/network/v2/test_proxy.py +++ b/openstack/tests/unit/network/v2/test_proxy.py @@ -64,6 +64,7 @@ from openstack.network.v2 import service_profile from openstack.network.v2 import service_provider from openstack.network.v2 import subnet from openstack.network.v2 import subnet_pool +from openstack.network.v2 import tap_mirror from openstack.network.v2 import vpn_endpoint_group from openstack.network.v2 import vpn_ike_policy from openstack.network.v2 import vpn_ipsec_policy @@ -2638,3 +2639,30 @@ class TestNetworkBGPVPN(TestNetworkProxy): expected_args=[self.ROUTER_ASSOCIATION], expected_kwargs={'bgpvpn_id': BGPVPN_ID}, ) + + +class TestNetworkTapMirror(TestNetworkProxy): + def test_create_tap_mirror(self): + self.verify_create(self.proxy.create_tap_mirror, tap_mirror.TapMirror) + + def test_delete_tap_mirror(self): + self.verify_delete( + self.proxy.delete_tap_mirror, tap_mirror.TapMirror, False + ) + + def test_delete_tap_mirror_ignore(self): + self.verify_delete( + self.proxy.delete_tap_mirror, tap_mirror.TapMirror, True + ) + + def test_find_tap_mirror(self): + self.verify_find(self.proxy.find_tap_mirror, tap_mirror.TapMirror) + + def test_get_tap_mirror(self): + self.verify_get(self.proxy.get_tap_mirror, tap_mirror.TapMirror) + + def test_tap_mirrors(self): + self.verify_list(self.proxy.tap_mirrors, tap_mirror.TapMirror) + + def test_update_tap_mirror(self): + self.verify_update(self.proxy.update_tap_mirror, tap_mirror.TapMirror) diff --git a/openstack/tests/unit/network/v2/test_tap_mirror.py b/openstack/tests/unit/network/v2/test_tap_mirror.py new file mode 100644 index 000000000..f7bd92edc --- /dev/null +++ b/openstack/tests/unit/network/v2/test_tap_mirror.py @@ -0,0 +1,62 @@ +# 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 tap_mirror +from openstack.tests.unit import base + + +IDENTIFIER = 'IDENTIFIER' +PORT_ID = 'PORT_ID' +EXAMPLE = { + 'name': 'my_tap_mirror', + 'port_id': PORT_ID, + 'directions': {'IN': 99}, + 'remote_ip': '193.10.10.1', + 'mirror_type': 'erspanv1', + 'id': IDENTIFIER, + 'project_id': '42', +} + + +class TestTapMirror(base.TestCase): + def test_basic(self): + sot = tap_mirror.TapMirror() + self.assertEqual('tap_mirror', sot.resource_key) + self.assertEqual('tap_mirrors', sot.resources_key) + self.assertEqual('/taas/tap_mirrors', 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) + + def test_make_it(self): + sot = tap_mirror.TapMirror(**EXAMPLE) + self.assertEqual(EXAMPLE['name'], sot.name) + self.assertEqual(EXAMPLE['port_id'], sot.port_id) + self.assertEqual(EXAMPLE['directions'], sot.directions) + self.assertEqual(EXAMPLE['remote_ip'], sot.remote_ip) + self.assertEqual(EXAMPLE['mirror_type'], sot.mirror_type) + self.assertEqual(EXAMPLE['id'], sot.id) + self.assertEqual(EXAMPLE['project_id'], sot.project_id) + + self.assertDictEqual( + { + 'limit': 'limit', + 'marker': 'marker', + 'name': 'name', + 'project_id': 'project_id', + 'sort_key': 'sort_key', + 'sort_dir': 'sort_dir', + }, + sot._query_mapping._mapping, + ) diff --git a/releasenotes/notes/network-add-tap-mirror-46376bd98ee69c81.yaml b/releasenotes/notes/network-add-tap-mirror-46376bd98ee69c81.yaml new file mode 100644 index 000000000..d0253fbdf --- /dev/null +++ b/releasenotes/notes/network-add-tap-mirror-46376bd98ee69c81.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Add ``Tap Mirror`` and introduce the support for creating, reading, + updating and deleting ``tap_mirrors``. diff --git a/zuul.d/functional-jobs.yaml b/zuul.d/functional-jobs.yaml index b0933a8f9..89cea4d5b 100644 --- a/zuul.d/functional-jobs.yaml +++ b/zuul.d/functional-jobs.yaml @@ -152,6 +152,7 @@ required-projects: - openstack/neutron-fwaas - openstack/neutron-vpnaas + - openstack/tap-as-a-service vars: INSTALL_OVN: False configure_swap_size: 4096 @@ -184,17 +185,19 @@ agent: availability_zone: nova devstack_localrc: - Q_SERVICE_PLUGIN_CLASSES: qos,trunk - NETWORK_API_EXTENSIONS: "agent,binding,dhcp_agent_scheduler,external-net,ext-gw-mode,extra_dhcp_opts,quotas,router,security-group,subnet_allocation,network-ip-availability,auto-allocated-topology,timestamp_core,tag,service-type,rbac-policies,standard-attr-description,pagination,sorting,project-id,fwaas_v2,vpnaas" + Q_SERVICE_PLUGIN_CLASSES: qos,trunk,taas + NETWORK_API_EXTENSIONS: "agent,binding,dhcp_agent_scheduler,external-net,ext-gw-mode,extra_dhcp_opts,quotas,router,security-group,subnet_allocation,network-ip-availability,auto-allocated-topology,timestamp_core,tag,service-type,rbac-policies,standard-attr-description,pagination,sorting,project-id,fwaas_v2,vpnaas,taas,tap_mirror" Q_AGENT: openvswitch Q_ML2_TENANT_NETWORK_TYPE: vxlan Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch IPSEC_PACKAGE: libreswan + TAAS_SERVICE_DRIVER: TAAS:TAAS:neutron_taas.services.taas.service_drivers.taas_rpc.TaasRpcDriver:default devstack_plugins: designate: https://opendev.org/openstack/designate octavia: https://opendev.org/openstack/octavia neutron-fwaas: https://opendev.org/openstack/neutron-fwaas.git neutron-vpnaas: https://opendev.org/openstack/neutron-vpnaas.git + tap-as-a-service: https://opendev.org/openstack/tap-as-a-service.git devstack_services: designate: true octavia: true @@ -211,6 +214,8 @@ h-api: false h-api-cfn: false q-fwaas-v2: true + taas: true + tap_mirror: true tox_environment: OPENSTACKSDK_HAS_DESIGNATE: 1 OPENSTACKSDK_HAS_SWIFT: 0