def test_get_security_group_states_nonempty(self, mock_get_fields): rc = sg_client.SecurityGroupsClient() mock_get_fields.return_value = [ None, '{}', '{"%s": False}' % sg_client.SECURITY_GROUP_ACK, '{"%s": True}' % sg_client.SECURITY_GROUP_ACK, '{"%s": "1-2-3"}' % sg_client.SECURITY_GROUP_ACK ] recs = [{"MAC": 2}, {"MAC": 4}, {"MAC": 6}, {"MAC": 8}, {"MAC": 0}] new_interfaces = ([ VIF(1, recs[0], 9), VIF(3, recs[1], 0), VIF(5, recs[2], 1), VIF(7, recs[3], 2), VIF(9, recs[4], 3) ]) group_states = rc.get_security_group_states(new_interfaces) mock_get_fields.assert_called_once_with([ "1.000000000002", "3.000000000004", "5.000000000006", "7.000000000008", "9.000000000000" ], sg_client.SECURITY_GROUP_ACK) self.assertEqual(group_states, { new_interfaces[2]: False, new_interfaces[3]: True })
def setUp(self): self.vif_recs = [ self._vif_rec(1, False), self._vif_rec(2, True), self._vif_rec(3, True), self._vif_rec(4, False), self._vif_rec(5, False) ] self.interfaces = [ xapi.VIF("added", self.vif_recs[0], "added_ref"), xapi.VIF("updated", self.vif_recs[1], "updated_ref"), xapi.VIF("removed", self.vif_recs[2], "removed_ref"), xapi.VIF("no groups", self.vif_recs[3], "no groups ref"), xapi.VIF("self heal", self.vif_recs[4], "self heal ref") ] self.ack = sg.SECURITY_GROUP_ACK self.rules = sg.SECURITY_GROUP_HASH_ATTR self.sg_states = { self.interfaces[0]: { self.ack: False, self.rules: [] }, self.interfaces[1]: { self.ack: False, self.rules: [] }, self.interfaces[4]: { self.ack: True, self.rules: [] } } self.client = sg.SecurityGroupsClient()
def test_get_security_group_states_empty(self, mock_get_fields): rc = sg_client.SecurityGroupsClient() mock_get_fields.return_value = [] group_states = rc.get_security_group_states([]) mock_get_fields.assert_called_once_with([], sg_client.SECURITY_GROUP_ACK) self.assertEqual(group_states, {})
def test_apply_rules_with_slave_fails(self, strict_redis, vif_key, conn_pool): client = sg_client.SecurityGroupsClient() port_id = 1 mac_address = netaddr.EUI("AA:BB:CC:DD:EE:FF") with self.assertRaises(q_exc.RedisSlaveWritesForbidden): client.apply_rules(port_id, mac_address.value, [])
def test_delete_vif(self, strict_redis, conn_pool, uuid4): client = sg_client.SecurityGroupsClient(use_master=True) device_id = "device" uuid4.return_value = "uuid" mac_address = netaddr.EUI("AA:BB:CC:DD:EE:FF") redis_key = client.vif_key(device_id, mac_address.value) client.delete_vif(device_id, mac_address) client._client.delete.assert_called_with(redis_key)
def _delete_port_security_groups(self, **kwargs): # Contacting redis is cheaper than hitting the database to find out # if we have rules to delete, and deleting an absence of rules is a # NOOP, so this is a safe operation try: client = sg_client.SecurityGroupsClient(use_master=True) client.delete_vif(kwargs["device_id"], kwargs["mac_address"]) except Exception: LOG.exception("Failed to reach the security groups backend")
def _get_connection(self, giveup=True): client = sg_client.SecurityGroupsClient() try: if client.ping(): return client except Exception as e: print(e) if giveup: print("Giving up...") sys.exit(1)
def _update_port_security_groups(self, **kwargs): if "security_groups" in kwargs: client = sg_client.SecurityGroupsClient(use_master=True) if kwargs["security_groups"]: payload = client.serialize_groups(kwargs["security_groups"]) client.apply_rules(kwargs["device_id"], kwargs["mac_address"], payload) else: client.delete_vif_rules(kwargs["device_id"], kwargs["mac_address"])
def delete_port(self, **kwargs): client = sg_client.SecurityGroupsClient() try: device_id = kwargs.get('device_id') mac_address = kwargs.get('mac_address') if not device_id or not mac_address: LOG.warning('device_id or mac_address not given, ignored.') return client.delete_vif(device_id, mac_address) except Exception: LOG.exception("Failed to reach the security groups backend")
def test_get_security_group_states_empty(self, strict_redis): mock_redis = mock.MagicMock() mock_pipeline = mock.MagicMock() strict_redis.return_value = mock_redis mock_redis.pipeline.return_value = mock_pipeline rc = sg_client.SecurityGroupsClient() group_uuids = rc.get_security_group_states(set()) mock_redis.pipeline.assert_called_once_with() self.assertEqual(mock_pipeline.get.call_count, 0) mock_pipeline.execute.assert_called_once_with() self.assertEqual(group_uuids, {})
def _get_connection(self, use_master=False, giveup=True): client = sg_client.SecurityGroupsClient(use_master=use_master) try: # You have to use the connection determine it's functional result = client.echo("connected") if result == "connected": return client except Exception as e: print(e) if giveup: print("Giving up...") sys.exit(1)
def test_apply_rules_set_fails_gracefully(self, conn_pool): port_id = 1 mac_address = netaddr.EUI("AA:BB:CC:DD:EE:FF") conn_err = redis.ConnectionError with mock.patch("redis.StrictRedis") as redis_mock: mocked_redis_cli = mock.MagicMock() redis_mock.return_value = mocked_redis_cli client = sg_client.SecurityGroupsClient(use_master=True) mocked_redis_cli.hset.side_effect = conn_err with self.assertRaises(q_exc.RedisConnectionFailure): client.apply_rules(port_id, mac_address.value, [])
def test_apply_rules_set_fails_gracefully(self): port_id = 1 mac_address = netaddr.EUI("AA:BB:CC:DD:EE:FF") conn_err = redis.ConnectionError with mock.patch("quark.cache.security_groups_client." "redis_base.ClientBase") as redis_mock: mocked_redis_cli = mock.MagicMock() redis_mock.return_value = mocked_redis_cli client = sg_client.SecurityGroupsClient() mocked_redis_cli.master.hset.side_effect = conn_err with self.assertRaises(q_exc.RedisConnectionFailure): client.apply_rules(port_id, mac_address.value, [])
def update_port(self, **kwargs): client = sg_client.SecurityGroupsClient() if "security_groups" in kwargs: device_id = kwargs.get('device_id') mac_address = kwargs.get('mac_address') if not device_id or not mac_address: LOG.warning('device_id or mac_address not given, ignored.') return if kwargs["security_groups"]: payload = client.serialize_groups(kwargs["security_groups"]) client.apply_rules(device_id, mac_address, payload) else: client.delete_vif_rules(device_id, mac_address)
def run(): """Fetches changes and applies them to VIFs periodically Process as of RM11449: * Get all groups from redis * Fetch ALL VIFs from Xen * Walk ALL VIFs and partition them into added, updated and removed * Walk the final "modified" VIFs list and apply flows to each """ groups_client = sg_cli.SecurityGroupsClient() xapi_client = xapi.XapiClient() interfaces = set() while True: try: interfaces = xapi_client.get_interfaces() except Exception: LOG.exception("Unable to get instances/interfaces from xapi") _sleep() continue try: sg_states = groups_client.get_security_group_states(interfaces) new_sg, updated_sg, removed_sg = partition_vifs(xapi_client, interfaces, sg_states) xapi_client.update_interfaces(new_sg, updated_sg, removed_sg) groups_to_ack = [v for v in new_sg + updated_sg if v.success] # NOTE(quade): This solves a race condition where a security group # rule may have changed between the time the sg_states were called # and when they were officially ack'd. It functions as a compare # and set. This is a fix until we get onto a proper messaging # queue. NCP-2287 sg_sts_curr = groups_client.get_security_group_states(interfaces) groups_to_ack = get_groups_to_ack(groups_to_ack, sg_states, sg_sts_curr) # This list will contain all the security group rules that do not # match ack_groups(groups_client, groups_to_ack) except Exception: LOG.exception("Unable to get security groups from registry and " "apply them to xapi") _sleep() continue _sleep()
def test_apply_rules(self, strict_redis, conn_pool, uuid4): client = sg_client.SecurityGroupsClient(use_master=True) device_id = "device" uuid4.return_value = "uuid" mac_address = netaddr.EUI("AA:BB:CC:DD:EE:FF") client.apply_rules(device_id, mac_address.value, []) self.assertTrue(client._client.hset.called) redis_key = client.vif_key(device_id, mac_address.value) rule_dict = {"rules": []} client._client.hset.assert_any_call( redis_key, sg_client.SECURITY_GROUP_HASH_ATTR, json.dumps(rule_dict)) client._client.hset.assert_any_call( redis_key, sg_client.SECURITY_GROUP_ACK, False)
def test_serialize_filters_dest_v4_net(self, strict_redis, conn_pool): rule_dict = {"ethertype": 0x800, "protocol": 1, "direction": "egress", "remote_ip_prefix": "192.168.0.0/0"} client = sg_client.SecurityGroupsClient() group = models.SecurityGroup() rule = models.SecurityGroupRule() rule.update(rule_dict) group.rules.append(rule) payload = client.serialize_groups([group]) rule = payload[0] self.assertEqual(0x800, rule["ethertype"]) self.assertEqual(1, rule["protocol"]) self.assertEqual(None, rule["icmp type"]) self.assertEqual(None, rule["icmp code"]) self.assertEqual("allow", rule["action"]) self.assertEqual("egress", rule["direction"]) self.assertEqual("", rule["source network"]) self.assertEqual("", rule["destination network"])
def test_serialize_group_with_rules(self, strict_redis, conn_pool): rule_dict = {"ethertype": 0x800, "protocol": 6, "port_range_min": 80, "port_range_max": 443, "direction": "ingress"} client = sg_client.SecurityGroupsClient() group = models.SecurityGroup() rule = models.SecurityGroupRule() rule.update(rule_dict) group.rules.append(rule) payload = client.serialize_groups([group]) rule = payload[0] self.assertEqual(0x800, rule["ethertype"]) self.assertEqual(6, rule["protocol"]) self.assertEqual(80, rule["port start"]) self.assertEqual(443, rule["port end"]) self.assertEqual("allow", rule["action"]) self.assertEqual("ingress", rule["direction"]) self.assertEqual("", rule["source network"]) self.assertEqual("", rule["destination network"])
def test_serialize_filters_source_v6_net(self, strict_redis): rule_dict = { "ethertype": 0x86DD, "protocol": 58, "direction": "ingress", "remote_ip_prefix": "feed::/0" } client = sg_client.SecurityGroupsClient() group = models.SecurityGroup() rule = models.SecurityGroupRule() rule.update(rule_dict) group.rules.append(rule) payload = client.serialize_groups([group]) rule = payload[0] self.assertEqual(0x86DD, rule["ethertype"]) self.assertEqual(58, rule["protocol"]) self.assertEqual(None, rule["icmp type"]) self.assertEqual(None, rule["icmp code"]) self.assertEqual("allow", rule["action"]) self.assertEqual("ingress", rule["direction"]) self.assertEqual("", rule["source network"]) self.assertEqual("", rule["destination network"])
def run(): """Fetches changes and applies them to VIFs periodically Process as of RM11449: * Get all groups from redis * Fetch ALL VIFs from Xen * Walk ALL VIFs and partition them into added, updated and removed * Walk the final "modified" VIFs list and apply flows to each """ groups_client = sg_cli.SecurityGroupsClient() xapi_client = xapi.XapiClient() interfaces = set() while True: try: interfaces = xapi_client.get_interfaces() except Exception: LOG.exception("Unable to get instances/interfaces from xapi") _sleep() continue try: sg_states = groups_client.get_security_group_states(interfaces) new_sg, updated_sg, removed_sg = partition_vifs(xapi_client, interfaces, sg_states) xapi_client.update_interfaces(new_sg, updated_sg, removed_sg) groups_to_ack = [v for v in new_sg + updated_sg if v.success] ack_groups(groups_client, groups_to_ack) except Exception: LOG.exception("Unable to get security groups from registry and " "apply them to xapi") _sleep() continue _sleep()
def ack_groups(groups): if len(groups) > 0: write_groups_client = sg_cli.SecurityGroupsClient(use_master=True) write_groups_client.update_group_states_for_vifs(groups, True)
def test_serialize_group_no_rules(self, strict_redis, conn_pool): client = sg_client.SecurityGroupsClient() group = models.SecurityGroup() payload = client.serialize_groups([group]) self.assertEqual([], payload)