From b980fdb3a296e7b9cc084638071518dcd1959150 Mon Sep 17 00:00:00 2001 From: Abhishek Raut Date: Mon, 16 Jan 2017 10:13:20 -0800 Subject: [PATCH] Add support for IPSet CRUD operations This patch adds IPSet CRUD operations under the security module. This patch also adds a util method for IPSets to return reference dict for IPSet objects. Change-Id: Ie5157055e80ec1976159cabc172d8285314570c4 --- vmware_nsxlib/tests/unit/v3/test_constants.py | 11 ++++ vmware_nsxlib/tests/unit/v3/test_security.py | 56 +++++++++++++++++++ vmware_nsxlib/v3/__init__.py | 2 + vmware_nsxlib/v3/nsx_constants.py | 1 + vmware_nsxlib/v3/security.py | 46 +++++++++++++++ 5 files changed, 116 insertions(+) diff --git a/vmware_nsxlib/tests/unit/v3/test_constants.py b/vmware_nsxlib/tests/unit/v3/test_constants.py index 447b329a..286c461c 100644 --- a/vmware_nsxlib/tests/unit/v3/test_constants.py +++ b/vmware_nsxlib/tests/unit/v3/test_constants.py @@ -18,6 +18,7 @@ from oslo_utils import uuidutils FAKE_NAME = "fake_name" FAKE_SWITCH_UUID = uuidutils.generate_uuid() +FAKE_IP_SET_UUID = uuidutils.generate_uuid() FAKE_PORT_UUID = uuidutils.generate_uuid() FAKE_PORT = { @@ -181,3 +182,13 @@ FAKE_IP_POOL = { "cidr": "2002:a70:cbfa:0:0:0:0:0/24" }], } + +FAKE_IP_SET = { + "id": FAKE_IP_SET_UUID, + "display_name": FAKE_NAME, + "resource_type": "IPSet", + "ip_addresses": [ + "192.168.1.1-192.168.1.6", + "192.168.1.8", + "192.168.4.8/24"] +} diff --git a/vmware_nsxlib/tests/unit/v3/test_security.py b/vmware_nsxlib/tests/unit/v3/test_security.py index e46787dc..167973b5 100644 --- a/vmware_nsxlib/tests/unit/v3/test_security.py +++ b/vmware_nsxlib/tests/unit/v3/test_security.py @@ -15,7 +15,11 @@ import mock +from oslo_utils import uuidutils + from vmware_nsxlib.tests.unit.v3 import nsxlib_testcase +from vmware_nsxlib.tests.unit.v3 import test_constants +from vmware_nsxlib.v3 import nsx_constants as const class TestNsxLibFirewallSection(nsxlib_testcase.NsxLibTestCase): @@ -81,3 +85,55 @@ class TestNsxLibFirewallSection(nsxlib_testcase.NsxLibTestCase): resource = 'firewall/sections?operation=insert_bottom' \ '&action=create_with_rules' create.assert_called_with(resource, expected_body) + + +class TestNsxLibIPSet(nsxlib_testcase.NsxClientTestCase): + """Tests for vmware_nsxlib.v3.security.NsxLibIPSet""" + + def test_get_ipset_reference(self): + mock_ip_set = uuidutils.generate_uuid() + result = self.nsxlib.ip_set.get_ipset_reference( + mock_ip_set) + expected = { + 'target_id': mock_ip_set, + 'target_type': const.IP_SET + } + self.assertEqual(expected, result) + + def test_create_ip_set(self): + fake_ip_set = test_constants.FAKE_IP_SET.copy() + data = { + 'display_name': fake_ip_set['display_name'], + 'ip_addresses': fake_ip_set['ip_addresses'], + 'description': 'ipset-desc', + 'tags': [] + } + with mock.patch.object(self.nsxlib.client, 'create') as create: + self.nsxlib.ip_set.create( + fake_ip_set['display_name'], 'ipset-desc', + ip_addresses=fake_ip_set['ip_addresses']) + resource = 'ip-sets' + create.assert_called_with(resource, data) + + def test_delete_ip_set(self): + with mock.patch.object(self.nsxlib.client, 'delete') as delete: + fake_ip_set = test_constants.FAKE_IP_SET.copy() + self.nsxlib.ip_set.delete(fake_ip_set['id']) + delete.assert_called_with('ip-sets/%s' % fake_ip_set['id']) + + def test_update_ip_set(self): + fake_ip_set = test_constants.FAKE_IP_SET.copy() + new_ip_addresses = ['10.0.0.0'] + data = { + 'id': fake_ip_set['id'], + 'display_name': fake_ip_set['display_name'], + 'ip_addresses': new_ip_addresses, + 'resource_type': 'IPSet' + } + with mock.patch.object(self.nsxlib.client, 'get', + return_value=fake_ip_set): + with mock.patch.object(self.nsxlib.client, 'update') as update: + self.nsxlib.ip_set.update( + fake_ip_set['id'], ip_addresses=new_ip_addresses) + resource = 'ip-sets/%s' % fake_ip_set['id'] + update.assert_called_with(resource, data) diff --git a/vmware_nsxlib/v3/__init__.py b/vmware_nsxlib/v3/__init__.py index 9cf3ea04..1e9c69b0 100644 --- a/vmware_nsxlib/v3/__init__.py +++ b/vmware_nsxlib/v3/__init__.py @@ -75,6 +75,8 @@ class NsxLib(object): self.client, nsxlib_config) self.ip_block = NsxLibIpBlock( self.client, nsxlib_config) + self.ip_set = security.NsxLibIPSet( + self.client, nsxlib_config) super(NsxLib, self).__init__() diff --git a/vmware_nsxlib/v3/nsx_constants.py b/vmware_nsxlib/v3/nsx_constants.py index 55e80639..c30978fc 100644 --- a/vmware_nsxlib/v3/nsx_constants.py +++ b/vmware_nsxlib/v3/nsx_constants.py @@ -46,6 +46,7 @@ LROUTERPORT_LINKONTIER1 = "LogicalRouterLinkPortOnTIER1" SERVICE_DHCP = "dhcp" # NSX-V3 Distributed Firewall constants +IP_SET = 'IPSet' NSGROUP = 'NSGroup' NSGROUP_SIMPLE_EXP = 'NSGroupSimpleExpression' NSGROUP_TAG_EXP = 'NSGroupTagExpression' diff --git a/vmware_nsxlib/v3/security.py b/vmware_nsxlib/v3/security.py index 0b2c99a8..b20c1613 100644 --- a/vmware_nsxlib/v3/security.py +++ b/vmware_nsxlib/v3/security.py @@ -553,3 +553,49 @@ class NsxLibFirewallSection(utils.NsxLibApiBase): dhcp_client_rule_in, block_rule]) return section['id'] + + +class NsxLibIPSet(utils.NsxLibApiBase): + + def create(self, display_name, description=None, ip_addresses=None, + tags=None): + resource = 'ip-sets' + body = { + 'display_name': display_name, + 'description': description or '', + 'ip_addresses': ip_addresses or [], + 'tags': tags or [] + } + return self.client.create(resource, body) + + def update(self, ip_set_id, display_name=None, description=None, + ip_addresses=None, tags_update=None): + # Using internal method so we can access max_attempts in the decorator + @utils.retry_upon_exception( + exceptions.StaleRevision, + max_attempts=self.nsxlib_config.max_attempts) + def _do_update(): + resource = 'ip-sets/%s' % ip_set_id + ip_set = self.read(ip_set_id) + tags = ip_set.get('tags', []) + if tags_update: + tags = utils.update_v3_tags(tags, tags_update) + if display_name is not None: + ip_set['display_name'] = display_name + if description is not None: + ip_set['description'] = description + if ip_addresses: + ip_set['ip_addresses'] = ip_addresses + return self.client.update(resource, ip_set) + + return _do_update() + + def read(self, ip_set_id): + return self.client.get('ip-sets/%s' % ip_set_id) + + def delete(self, ip_set_id): + return self.client.delete('ip-sets/%s' % ip_set_id) + + def get_ipset_reference(self, ip_set_id): + return {'target_id': ip_set_id, + 'target_type': consts.IP_SET}