def _validate_security_group_rule(context, rule): # TODO(mdietz): As per RM8615, Remote groups are not currently supported if rule.get("remote_group_id"): raise exceptions.InvalidInput( error_message="Remote groups are not currently supported") if "direction" in rule and rule["direction"] != "ingress": raise exceptions.InvalidInput( error_message="Non-ingress rules are not currently supported") protocol = rule.pop('protocol') port_range_min = rule['port_range_min'] port_range_max = rule['port_range_max'] if protocol: protocol = protocols.translate_protocol(protocol, rule["ethertype"]) protocols.validate_protocol_with_port_ranges(protocol, port_range_min, port_range_max) rule['protocol'] = protocol else: if port_range_min is not None or port_range_max is not None: raise sg_ext.SecurityGroupProtocolRequiredWithPorts() ethertype = protocols.translate_ethertype(rule["ethertype"]) rule["ethertype"] = ethertype protocols.validate_remote_ip_prefix(ethertype, rule.get("remote_ip_prefix")) return rule
def test_update_security_group_rule(self): sg_dict = {"id": 0} sg = models.SecurityGroup() sg.update(sg_dict) rule_dict = {"id": 1, "direction": "ingress", "port_range_min": 80, "port_range_max": 100, "remote_ip_prefix": None, "ethertype": protocols.translate_ethertype("IPv4"), "tenant_id": "foo", "protocol": "UDP", "group_id": 1, "external_service_id": None, "external_service": None} rule = models.SecurityGroupRule() rule.update(rule_dict) updated_part = {'external_service_id': 'aaa', 'external_service': 'bbb'} with mock.patch('quark.db.api.security_group_rule_find') as db_find, \ mock.patch('quark.db.api.security_group_rule_update') \ as db_update, \ mock.patch('quark.db.api.security_group_find') as sg_find: db_find.return_value = rule rule_dict.update(updated_part) new_rule = models.SecurityGroupRule() new_rule.update(rule_dict) db_update.return_value = new_rule sg_find.return_value = sg update = dict(security_group_rule=updated_part) resp = self.plugin.update_security_group_rule(self.context, 1, update) self.assertEqual(resp['external_service_id'], updated_part['external_service_id']) self.assertEqual(resp['external_service'], updated_part['external_service'])
def _validate_security_group_rule(context, rule): # TODO(mdietz): As per RM8615, Remote groups are not currently supported if rule.get("remote_group_id"): raise n_exc.InvalidInput( error_message="Remote groups are not currently supported") direction = rule.get("direction") if direction == Capabilities.EGRESS: if Capabilities.EGRESS not in CONF.QUARK.environment_capabilities: raise q_exc.EgressSecurityGroupRulesNotEnabled() protocol = rule.pop('protocol') port_range_min = rule['port_range_min'] port_range_max = rule['port_range_max'] ethertype = protocols.translate_ethertype(rule["ethertype"]) if protocol: protocol = protocols.translate_protocol(protocol, rule["ethertype"]) protocols.validate_protocol_with_port_ranges(ethertype, protocol, port_range_min, port_range_max) rule['protocol'] = protocol else: if port_range_min is not None or port_range_max is not None: raise sg_ext.SecurityGroupProtocolRequiredWithPorts() rule["ethertype"] = ethertype protocols.validate_remote_ip_prefix(ethertype, rule.get("remote_ip_prefix")) return rule
def _validate_security_group_rule(context, rule): # TODO(mdietz): As per RM8615, Remote groups are not currently supported if rule.get("remote_group_id"): raise n_exc.InvalidInput( error_message="Remote groups are not currently supported") direction = rule.get("direction") if direction == env.Capabilities.EGRESS: if env.Capabilities.EGRESS not in CONF.QUARK.environment_capabilities: raise q_exc.EgressSecurityGroupRulesNotEnabled() protocol = rule.pop('protocol') # NOTE(roaet): these are not required by spec port_range_min = rule.get('port_range_min') port_range_max = rule.get('port_range_max') # TODO(anyone): this will error as None, so defaulting to ipv4 et = rule.get('ethertype', 'IPv4') ethertype = protocols.translate_ethertype(et) if protocol: protocol = protocols.translate_protocol(protocol, et) protocols.validate_protocol_with_port_ranges(ethertype, protocol, port_range_min, port_range_max) rule['protocol'] = protocol else: if port_range_min is not None or port_range_max is not None: raise sg_ext.SecurityGroupProtocolRequiredWithPorts() rule["ethertype"] = ethertype protocols.validate_remote_ip_prefix(ethertype, rule.get("remote_ip_prefix")) return rule
def _validate_security_group_rule(context, rule): # TODO(mdietz): As per RM8615, Remote groups are not currently supported if rule.get("remote_group_id"): raise exceptions.InvalidInput( error_message="Remote groups are not currently supported") if "direction" in rule and rule["direction"] != "ingress": raise exceptions.InvalidInput( error_message="Non-ingress rules are not currently supported") protocol = rule.pop('protocol') port_range_min = rule['port_range_min'] port_range_max = rule['port_range_max'] ethertype = protocols.translate_ethertype(rule["ethertype"]) if protocol: protocol = protocols.translate_protocol(protocol, rule["ethertype"]) protocols.validate_protocol_with_port_ranges(ethertype, protocol, port_range_min, port_range_max) rule['protocol'] = protocol else: if port_range_min is not None or port_range_max is not None: raise sg_ext.SecurityGroupProtocolRequiredWithPorts() rule["ethertype"] = ethertype protocols.validate_remote_ip_prefix(ethertype, rule.get("remote_ip_prefix")) return rule
def _validate_security_group_rule(context, rule): # TODO(mdietz): As per RM8615, Remote groups are not currently supported if rule.get("remote_group_id"): raise exceptions.InvalidInput( error_message="Remote groups are not currently supported") direction = rule.get("direction") if direction == Capabilities.EGRESS: if Capabilities.EGRESS not in CONF.QUARK.environment_capabilities: raise q_exc.EgressSecurityGroupRulesNotEnabled() protocol = rule.pop('protocol') port_range_min = rule['port_range_min'] port_range_max = rule['port_range_max'] ethertype = protocols.translate_ethertype(rule["ethertype"]) if protocol: protocol = protocols.translate_protocol(protocol, rule["ethertype"]) protocols.validate_protocol_with_port_ranges(ethertype, protocol, port_range_min, port_range_max) rule['protocol'] = protocol else: if port_range_min is not None or port_range_max is not None: raise sg_ext.SecurityGroupProtocolRequiredWithPorts() rule["ethertype"] = ethertype protocols.validate_remote_ip_prefix(ethertype, rule.get("remote_ip_prefix")) return rule
def test_get_security_group_rule(self): rule = {"id": 1, "remote_group_id": 2, "direction": "ingress", "port_range_min": 80, "port_range_max": 100, "remote_ip_prefix": None, "ethertype": protocols.translate_ethertype("IPv4"), "tenant_id": "foo", "protocol": "UDP", "group_id": 1} expected = rule.copy() expected["security_group_id"] = expected.pop("group_id") expected["ethertype"] = "IPv4" with self._stubs(rule): resp = self.plugin.get_security_group_rule(self.context, 1) for key in expected.keys(): self.assertTrue(key in resp) self.assertEqual(resp[key], expected[key])
def test_update_security_group_rule(self): sg_dict = {"id": 0} sg = models.SecurityGroup() sg.update(sg_dict) rule_dict = { "id": 1, "direction": "ingress", "port_range_min": 80, "port_range_max": 100, "remote_ip_prefix": None, "ethertype": protocols.translate_ethertype("IPv4"), "tenant_id": "foo", "protocol": "UDP", "group_id": 1, "external_service_id": None, "external_service": None } rule = models.SecurityGroupRule() rule.update(rule_dict) updated_part = { 'external_service_id': 'aaa', 'external_service': 'bbb' } with mock.patch('quark.db.api.security_group_rule_find') as db_find, \ mock.patch('quark.db.api.security_group_rule_update') \ as db_update, \ mock.patch('quark.db.api.security_group_find') as sg_find: db_find.return_value = rule rule_dict.update(updated_part) new_rule = models.SecurityGroupRule() new_rule.update(rule_dict) db_update.return_value = new_rule sg_find.return_value = sg update = dict(security_group_rule=updated_part) resp = self.plugin.update_security_group_rule( self.context, 1, update) self.assertEqual(resp['external_service_id'], updated_part['external_service_id']) self.assertEqual(resp['external_service'], updated_part['external_service'])
def _model_query(context, model, filters, fields=None): filters = filters or {} model_filters = [] eq_filters = [ "address", "cidr", "deallocated", "ip_version", "mac_address_range_id", "transaction_id" ] in_filters = [ "device_id", "device_owner", "group_id", "id", "mac_address", "name", "network_id", "segment_id", "subnet_id", "used_by_tenant_id", "version" ] # Sanitize incoming filters to only attributes that exist in the model. # NOTE: Filters for unusable attributes are silently dropped here. # NOTE: When the filter key != attribute key, a conditional must be added # here. model_attrs = _model_attrs(model) filters = { x: y for x, y in filters.items() if x in model_attrs or (x == "tenant_id" and model == models.IPAddress) or (x == "ip_address" and model == models.IPAddress) or (x == "reuse_after" and model in (models.IPAddress, models.MacAddress)) } # Inject the tenant id if none is set. We don't need unqualified queries. # This works even when a non-shared, other-tenant owned network is passed # in because the authZ checks that happen in Neutron above us yank it back # out of the result set. if not filters.get("tenant_id") and not context.is_admin: filters["tenant_id"] = [context.tenant_id] if model == models.SecurityGroupRule: sg_rule_attribs = ["direction", "port_range_max", "port_range_min"] eq_filters.extend(sg_rule_attribs) for key, value in filters.items(): # This is mostly for unittests, as they're configured to send in None if value is None: continue if key in in_filters: model_type = getattr(model, key) model_filters.append(model_type.in_(value)) elif key in eq_filters: model_type = getattr(model, key) model_filters.append(model_type == value) elif key == "_deallocated": if value: model_filters.append(model._deallocated == 1) else: model_filters.append(model._deallocated != 1) elif key == "ethertype": etypes = [] for etype in value: etypes.append(protocols.translate_ethertype(etype)) model_filters.append(model.ethertype.in_(etypes)) elif key == "ip_address": model_filters.append( model.address.in_([ip.ipv6().value for ip in value])) elif key == 'protocol': pnums = [] for version in (protocols.PROTOCOLS_V4, protocols.PROTOCOLS_V6): pnums.extend([y for x, y in version.items() if x in value]) model_filters.append(model.protocol.in_(pnums)) elif key == "reuse_after": reuse = (timeutils.utcnow() - datetime.timedelta(seconds=value)) # NOTE(asadoughi): should this allow for deallocated_at = null? model_filters.append(model.deallocated_at <= reuse) elif key == "tenant_id": if model == models.IPAddress: model_filters.append(model.used_by_tenant_id.in_(value)) else: model_filters.append(model.tenant_id.in_(value)) return model_filters
def _model_query(context, model, filters, fields=None): filters = filters or {} model_filters = [] eq_filters = ["address", "cidr", "deallocated", "ip_version", "service", "mac_address_range_id", "transaction_id", "lock_id", "address_type"] in_filters = ["device_id", "device_owner", "group_id", "id", "mac_address", "name", "network_id", "segment_id", "subnet_id", "used_by_tenant_id", "version"] # Sanitize incoming filters to only attributes that exist in the model. # NOTE: Filters for unusable attributes are silently dropped here. # NOTE: When the filter key != attribute key, a conditional must be added # here. model_attrs = _model_attrs(model) filters = {x: y for x, y in filters.items() if x in model_attrs or (x == "tenant_id" and model == models.IPAddress) or (x == "ip_address" and model == models.IPAddress) or (x == "reuse_after" and model in (models.IPAddress, models.MacAddress))} # Inject the tenant id if none is set. We don't need unqualified queries. # This works even when a non-shared, other-tenant owned network is passed # in because the authZ checks that happen in Neutron above us yank it back # out of the result set. if not filters.get("tenant_id") and not context.is_admin: filters["tenant_id"] = [context.tenant_id] if model == models.SecurityGroupRule: sg_rule_attribs = ["direction", "port_range_max", "port_range_min"] eq_filters.extend(sg_rule_attribs) for key, value in filters.items(): if key in in_filters: model_type = getattr(model, key) model_filters.append(model_type.in_(value)) elif key in eq_filters: model_type = getattr(model, key) model_filters.append(model_type == value) elif key == "_deallocated": if value: model_filters.append(model._deallocated == 1) else: model_filters.append(model._deallocated != 1) elif key == "ethertype": etypes = [] for etype in value: etypes.append(protocols.translate_ethertype(etype)) model_filters.append(model.ethertype.in_(etypes)) elif key == "ip_address": model_filters.append(model.address.in_( [ip.ipv6().value for ip in value])) elif key == 'protocol': pnums = [] for version in (protocols.PROTOCOLS_V4, protocols.PROTOCOLS_V6): pnums.extend([y for x, y in version.items() if x in value]) model_filters.append(model.protocol.in_(pnums)) elif key == "reuse_after": reuse = (timeutils.utcnow() - datetime.timedelta(seconds=value)) # NOTE(asadoughi): should this allow for deallocated_at = null? model_filters.append(model.deallocated_at <= reuse) elif key == "port_id": if model == models.PortIpAssociation: model_filters.append(model.port_id == value) elif key == "tenant_id": if model == models.IPAddress: model_filters.append(model.used_by_tenant_id.in_(value)) elif model in _NO_TENANT_MODELS: pass else: model_filters.append(model.tenant_id.in_(value)) return model_filters