Perform a joined query for ports and security group associations
bug 1174111 Instead of loading security group associations with a separate query each time a port is loaded from the database, perform the load operation with a join using a joined sqlalchemy relationship. Also, this patch removes the need for invoking the mixin method 'extend_port_dict_security_group' from the plugin code. Change-Id: I40b22281d45ff4f4bf8149211883799a9051c1a0
This commit is contained in:
parent
11799aaa65
commit
b15ba94e9b
@ -451,6 +451,13 @@ validators = {'type:dict': _validate_dict,
|
|||||||
'type:uuid_list': _validate_uuid_list,
|
'type:uuid_list': _validate_uuid_list,
|
||||||
'type:values': _validate_values}
|
'type:values': _validate_values}
|
||||||
|
|
||||||
|
# Define constants for base resource name
|
||||||
|
NETWORK = 'network'
|
||||||
|
NETWORKS = '%ss' % NETWORK
|
||||||
|
PORT = 'port'
|
||||||
|
PORTS = '%ss' % PORT
|
||||||
|
SUBNET = 'subnet'
|
||||||
|
SUBNETS = '%ss' % SUBNET
|
||||||
# Note: a default of ATTR_NOT_SPECIFIED indicates that an
|
# Note: a default of ATTR_NOT_SPECIFIED indicates that an
|
||||||
# attribute is not required, but will be generated by the plugin
|
# attribute is not required, but will be generated by the plugin
|
||||||
# if it is not specified. Particularly, a value of ATTR_NOT_SPECIFIED
|
# if it is not specified. Particularly, a value of ATTR_NOT_SPECIFIED
|
||||||
@ -475,7 +482,7 @@ validators = {'type:dict': _validate_dict,
|
|||||||
# mechanism, ie: there might be rules which refer to this attribute.
|
# mechanism, ie: there might be rules which refer to this attribute.
|
||||||
|
|
||||||
RESOURCE_ATTRIBUTE_MAP = {
|
RESOURCE_ATTRIBUTE_MAP = {
|
||||||
'networks': {
|
NETWORKS: {
|
||||||
'id': {'allow_post': False, 'allow_put': False,
|
'id': {'allow_post': False, 'allow_put': False,
|
||||||
'validate': {'type:uuid': None},
|
'validate': {'type:uuid': None},
|
||||||
'is_visible': True,
|
'is_visible': True,
|
||||||
@ -504,7 +511,7 @@ RESOURCE_ATTRIBUTE_MAP = {
|
|||||||
'required_by_policy': True,
|
'required_by_policy': True,
|
||||||
'enforce_policy': True},
|
'enforce_policy': True},
|
||||||
},
|
},
|
||||||
'ports': {
|
PORTS: {
|
||||||
'id': {'allow_post': False, 'allow_put': False,
|
'id': {'allow_post': False, 'allow_put': False,
|
||||||
'validate': {'type:uuid': None},
|
'validate': {'type:uuid': None},
|
||||||
'is_visible': True,
|
'is_visible': True,
|
||||||
@ -546,7 +553,7 @@ RESOURCE_ATTRIBUTE_MAP = {
|
|||||||
'status': {'allow_post': False, 'allow_put': False,
|
'status': {'allow_post': False, 'allow_put': False,
|
||||||
'is_visible': True},
|
'is_visible': True},
|
||||||
},
|
},
|
||||||
'subnets': {
|
SUBNETS: {
|
||||||
'id': {'allow_post': False, 'allow_put': False,
|
'id': {'allow_post': False, 'allow_put': False,
|
||||||
'validate': {'type:uuid': None},
|
'validate': {'type:uuid': None},
|
||||||
'is_visible': True,
|
'is_visible': True,
|
||||||
@ -606,13 +613,13 @@ RESOURCE_ATTRIBUTE_MAP = {
|
|||||||
# Resources without parents, such as networks, are not in this list
|
# Resources without parents, such as networks, are not in this list
|
||||||
|
|
||||||
RESOURCE_HIERARCHY_MAP = {
|
RESOURCE_HIERARCHY_MAP = {
|
||||||
'ports': {'parent': 'networks', 'identified_by': 'network_id'},
|
PORTS: {'parent': NETWORKS, 'identified_by': 'network_id'},
|
||||||
'subnets': {'parent': 'networks', 'identified_by': 'network_id'}
|
SUBNETS: {'parent': NETWORKS, 'identified_by': 'network_id'}
|
||||||
}
|
}
|
||||||
|
|
||||||
PLURALS = {'networks': 'network',
|
PLURALS = {NETWORKS: NETWORK,
|
||||||
'ports': 'port',
|
PORTS: PORT,
|
||||||
'subnets': 'subnet',
|
SUBNETS: SUBNET,
|
||||||
'dns_nameservers': 'dns_nameserver',
|
'dns_nameservers': 'dns_nameserver',
|
||||||
'host_routes': 'host_route',
|
'host_routes': 'host_route',
|
||||||
'allocation_pools': 'allocation_pool',
|
'allocation_pools': 'allocation_pool',
|
||||||
|
@ -70,6 +70,10 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
# To this aim, the register_model_query_hook and unregister_query_hook
|
# To this aim, the register_model_query_hook and unregister_query_hook
|
||||||
# from this class should be invoked
|
# from this class should be invoked
|
||||||
_model_query_hooks = {}
|
_model_query_hooks = {}
|
||||||
|
# This dictionary will store methods for extending attributes of
|
||||||
|
# api resources. Mixins can use this dict for adding their own methods
|
||||||
|
# TODO(salvatore-orlando): Avoid using class-level variables
|
||||||
|
_dict_extend_functions = {}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# NOTE(jkoelker) This is an incomlete implementation. Subclasses
|
# NOTE(jkoelker) This is an incomlete implementation. Subclasses
|
||||||
@ -117,6 +121,12 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
query = query.filter(query_filter)
|
query = query.filter(query_filter)
|
||||||
return query
|
return query
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def register_dict_extend_funcs(cls, resource, funcs):
|
||||||
|
cur_funcs = cls._dict_extend_functions.get(resource, [])
|
||||||
|
cur_funcs.extend(funcs)
|
||||||
|
cls._dict_extend_functions[resource] = cur_funcs
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def register_model_query_hook(cls, model, name, query_hook, filter_hook,
|
def register_model_query_hook(cls, model, name, query_hook, filter_hook,
|
||||||
result_filters=None):
|
result_filters=None):
|
||||||
@ -142,6 +152,14 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
model_hooks[name] = {'query': query_hook, 'filter': filter_hook,
|
model_hooks[name] = {'query': query_hook, 'filter': filter_hook,
|
||||||
'result_filters': result_filters}
|
'result_filters': result_filters}
|
||||||
|
|
||||||
|
def _filter_non_model_columns(self, data, model):
|
||||||
|
"""Remove all the attributes from data which are not columns of
|
||||||
|
the model passed as second parameter.
|
||||||
|
"""
|
||||||
|
columns = [c.name for c in model.__table__.columns]
|
||||||
|
return dict((k, v) for (k, v) in
|
||||||
|
data.iteritems() if k in columns)
|
||||||
|
|
||||||
def _get_by_id(self, context, model, id):
|
def _get_by_id(self, context, model, id):
|
||||||
query = self._model_query(context, model)
|
query = self._model_query(context, model)
|
||||||
return query.filter(model.id == id).one()
|
return query.filter(model.id == id).one()
|
||||||
@ -909,7 +927,8 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
}
|
}
|
||||||
return self._fields(res, fields)
|
return self._fields(res, fields)
|
||||||
|
|
||||||
def _make_port_dict(self, port, fields=None):
|
def _make_port_dict(self, port, fields=None,
|
||||||
|
process_extensions=True):
|
||||||
res = {"id": port["id"],
|
res = {"id": port["id"],
|
||||||
'name': port['name'],
|
'name': port['name'],
|
||||||
"network_id": port["network_id"],
|
"network_id": port["network_id"],
|
||||||
@ -922,6 +941,11 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
for ip in port["fixed_ips"]],
|
for ip in port["fixed_ips"]],
|
||||||
"device_id": port["device_id"],
|
"device_id": port["device_id"],
|
||||||
"device_owner": port["device_owner"]}
|
"device_owner": port["device_owner"]}
|
||||||
|
# Call auxiliary extend functions, if any
|
||||||
|
if process_extensions:
|
||||||
|
for func in self._dict_extend_functions.get(attributes.PORTS,
|
||||||
|
[]):
|
||||||
|
func(self, res, port)
|
||||||
return self._fields(res, fields)
|
return self._fields(res, fields)
|
||||||
|
|
||||||
def _create_bulk(self, resource, context, request_items):
|
def _create_bulk(self, resource, context, request_items):
|
||||||
@ -1331,7 +1355,7 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
)
|
)
|
||||||
context.session.add(allocated)
|
context.session.add(allocated)
|
||||||
|
|
||||||
return self._make_port_dict(port)
|
return self._make_port_dict(port, process_extensions=False)
|
||||||
|
|
||||||
def update_port(self, context, id, port):
|
def update_port(self, context, id, port):
|
||||||
p = port['port']
|
p = port['port']
|
||||||
@ -1342,15 +1366,12 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
if 'fixed_ips' in p:
|
if 'fixed_ips' in p:
|
||||||
self._recycle_expired_ip_allocations(context,
|
self._recycle_expired_ip_allocations(context,
|
||||||
port['network_id'])
|
port['network_id'])
|
||||||
original = self._make_port_dict(port)
|
original = self._make_port_dict(port, process_extensions=False)
|
||||||
ips = self._update_ips_for_port(context,
|
ips = self._update_ips_for_port(context,
|
||||||
port["network_id"],
|
port["network_id"],
|
||||||
id,
|
id,
|
||||||
original["fixed_ips"],
|
original["fixed_ips"],
|
||||||
p['fixed_ips'])
|
p['fixed_ips'])
|
||||||
# 'fixed_ip's not part of DB so it is deleted
|
|
||||||
del p['fixed_ips']
|
|
||||||
|
|
||||||
# Update ips if necessary
|
# Update ips if necessary
|
||||||
for ip in ips:
|
for ip in ips:
|
||||||
allocated = models_v2.IPAllocation(
|
allocated = models_v2.IPAllocation(
|
||||||
@ -1358,8 +1379,9 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
ip_address=ip['ip_address'], subnet_id=ip['subnet_id'],
|
ip_address=ip['ip_address'], subnet_id=ip['subnet_id'],
|
||||||
expiration=self._default_allocation_expiration())
|
expiration=self._default_allocation_expiration())
|
||||||
context.session.add(allocated)
|
context.session.add(allocated)
|
||||||
|
# Remove all attributes in p which are not in the port DB model
|
||||||
port.update(p)
|
# and then update the port
|
||||||
|
port.update(self._filter_non_model_columns(p, models_v2.Port))
|
||||||
|
|
||||||
return self._make_port_dict(port)
|
return self._make_port_dict(port)
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ from sqlalchemy.orm import exc
|
|||||||
from sqlalchemy.orm import scoped_session
|
from sqlalchemy.orm import scoped_session
|
||||||
|
|
||||||
from quantum.api.v2 import attributes as attr
|
from quantum.api.v2 import attributes as attr
|
||||||
|
from quantum.db import db_base_plugin_v2
|
||||||
from quantum.db import model_base
|
from quantum.db import model_base
|
||||||
from quantum.db import models_v2
|
from quantum.db import models_v2
|
||||||
from quantum.extensions import securitygroup as ext_sg
|
from quantum.extensions import securitygroup as ext_sg
|
||||||
@ -46,6 +47,13 @@ class SecurityGroupPortBinding(model_base.BASEV2):
|
|||||||
sa.ForeignKey("securitygroups.id"),
|
sa.ForeignKey("securitygroups.id"),
|
||||||
primary_key=True)
|
primary_key=True)
|
||||||
|
|
||||||
|
# Add a relationship to the Port model in order to instruct SQLAlchemy to
|
||||||
|
# eagerly load security group bindings
|
||||||
|
ports = orm.relationship(
|
||||||
|
models_v2.Port,
|
||||||
|
backref=orm.backref("security_groups",
|
||||||
|
lazy='joined', cascade='delete'))
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupRule(model_base.BASEV2, models_v2.HasId,
|
class SecurityGroupRule(model_base.BASEV2, models_v2.HasId,
|
||||||
models_v2.HasTenant):
|
models_v2.HasTenant):
|
||||||
@ -385,25 +393,29 @@ class SecurityGroupDbMixin(ext_sg.SecurityGroupPluginBase):
|
|||||||
rule = self._get_security_group_rule(context, id)
|
rule = self._get_security_group_rule(context, id)
|
||||||
context.session.delete(rule)
|
context.session.delete(rule)
|
||||||
|
|
||||||
def _extend_port_dict_security_group(self, context, port):
|
def _extend_port_dict_security_group(self, port_res, port_db):
|
||||||
filters = {'port_id': [port['id']]}
|
# If port_db is provided, security groups will be accessed via
|
||||||
fields = {'security_group_id': None}
|
# sqlalchemy models. As they're loaded together with ports this
|
||||||
security_group_id = self._get_port_security_group_bindings(
|
# will not cause an extra query.
|
||||||
context, filters, fields)
|
security_group_ids = [sec_group_mapping['security_group_id'] for
|
||||||
|
sec_group_mapping in port_db.security_groups]
|
||||||
|
port_res[ext_sg.SECURITYGROUPS] = security_group_ids
|
||||||
|
return port_res
|
||||||
|
|
||||||
port[ext_sg.SECURITYGROUPS] = []
|
# Register dict extend functions for ports
|
||||||
for security_group_id in security_group_id:
|
db_base_plugin_v2.QuantumDbPluginV2.register_dict_extend_funcs(
|
||||||
port[ext_sg.SECURITYGROUPS].append(
|
attr.PORTS, [_extend_port_dict_security_group])
|
||||||
security_group_id['security_group_id'])
|
|
||||||
return port
|
|
||||||
|
|
||||||
def _process_port_create_security_group(self, context, port_id,
|
def _process_port_create_security_group(self, context, port,
|
||||||
security_group_id):
|
security_group_ids):
|
||||||
if not attr.is_attr_set(security_group_id):
|
if attr.is_attr_set(security_group_ids):
|
||||||
return
|
for security_group_id in security_group_ids:
|
||||||
for security_group_id in security_group_id:
|
self._create_port_security_group_binding(context, port['id'],
|
||||||
self._create_port_security_group_binding(context, port_id,
|
|
||||||
security_group_id)
|
security_group_id)
|
||||||
|
# Convert to list as a set might be passed here and
|
||||||
|
# this has to be serialized
|
||||||
|
port[ext_sg.SECURITYGROUPS] = (security_group_ids and
|
||||||
|
list(security_group_ids) or [])
|
||||||
|
|
||||||
def _ensure_default_security_group(self, context, tenant_id):
|
def _ensure_default_security_group(self, context, tenant_id):
|
||||||
"""Create a default security group if one doesn't exist.
|
"""Create a default security group if one doesn't exist.
|
||||||
|
@ -77,10 +77,12 @@ class SecurityGroupServerRpcMixin(sg_db.SecurityGroupDbMixin):
|
|||||||
self._delete_port_security_group_bindings(context, id)
|
self._delete_port_security_group_bindings(context, id)
|
||||||
self._process_port_create_security_group(
|
self._process_port_create_security_group(
|
||||||
context,
|
context,
|
||||||
id,
|
updated_port,
|
||||||
port['port'][ext_sg.SECURITYGROUPS])
|
port['port'][ext_sg.SECURITYGROUPS])
|
||||||
need_notify = True
|
need_notify = True
|
||||||
self._extend_port_dict_security_group(context, updated_port)
|
else:
|
||||||
|
updated_port[ext_sg.SECURITYGROUPS] = (
|
||||||
|
original_port[ext_sg.SECURITYGROUPS])
|
||||||
return need_notify
|
return need_notify
|
||||||
|
|
||||||
def is_security_group_member_updated(self, context,
|
def is_security_group_member_updated(self, context,
|
||||||
|
@ -382,15 +382,16 @@ class BrocadePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
port['port'][ext_sg.SECURITYGROUPS] = (
|
port['port'][ext_sg.SECURITYGROUPS] = (
|
||||||
self._get_security_groups_on_port(context, port))
|
self._get_security_groups_on_port(context, port))
|
||||||
self._delete_port_security_group_bindings(context, port_id)
|
self._delete_port_security_group_bindings(context, port_id)
|
||||||
|
# process_port_create_security_group also needs port id
|
||||||
|
port['port']['id'] = port_id
|
||||||
self._process_port_create_security_group(
|
self._process_port_create_security_group(
|
||||||
context,
|
context,
|
||||||
port_id,
|
port['port'],
|
||||||
port['port'][ext_sg.SECURITYGROUPS])
|
port['port'][ext_sg.SECURITYGROUPS])
|
||||||
port_updated = True
|
port_updated = True
|
||||||
|
|
||||||
port = super(BrocadePluginV2, self).update_port(
|
port = super(BrocadePluginV2, self).update_port(
|
||||||
context, port_id, port)
|
context, port_id, port)
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
|
|
||||||
if original_port['admin_state_up'] != port['admin_state_up']:
|
if original_port['admin_state_up'] != port['admin_state_up']:
|
||||||
port_updated = True
|
port_updated = True
|
||||||
@ -411,7 +412,6 @@ class BrocadePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
port = super(BrocadePluginV2, self).get_port(
|
port = super(BrocadePluginV2, self).get_port(
|
||||||
context, port_id, fields)
|
context, port_id, fields)
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
self._extend_port_dict_binding(context, port)
|
self._extend_port_dict_binding(context, port)
|
||||||
|
|
||||||
return self._fields(port, fields)
|
return self._fields(port, fields)
|
||||||
@ -423,7 +423,6 @@ class BrocadePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
filters,
|
filters,
|
||||||
fields)
|
fields)
|
||||||
for port in ports:
|
for port in ports:
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
self._extend_port_dict_binding(context, port)
|
self._extend_port_dict_binding(context, port)
|
||||||
res_ports.append(self._fields(port, fields))
|
res_ports.append(self._fields(port, fields))
|
||||||
|
|
||||||
|
@ -471,7 +471,6 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
port = super(LinuxBridgePluginV2, self).get_port(context,
|
port = super(LinuxBridgePluginV2, self).get_port(context,
|
||||||
id,
|
id,
|
||||||
fields)
|
fields)
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
self._extend_port_dict_binding(context, port),
|
self._extend_port_dict_binding(context, port),
|
||||||
return self._fields(port, fields)
|
return self._fields(port, fields)
|
||||||
|
|
||||||
@ -484,7 +483,6 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
limit, marker, page_reverse)
|
limit, marker, page_reverse)
|
||||||
#TODO(nati) filter by security group
|
#TODO(nati) filter by security group
|
||||||
for port in ports:
|
for port in ports:
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
self._extend_port_dict_binding(context, port)
|
self._extend_port_dict_binding(context, port)
|
||||||
res_ports.append(self._fields(port, fields))
|
res_ports.append(self._fields(port, fields))
|
||||||
return res_ports
|
return res_ports
|
||||||
@ -500,8 +498,7 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
port = super(LinuxBridgePluginV2,
|
port = super(LinuxBridgePluginV2,
|
||||||
self).create_port(context, port)
|
self).create_port(context, port)
|
||||||
self._process_port_create_security_group(
|
self._process_port_create_security_group(
|
||||||
context, port['id'], sgids)
|
context, port, sgids)
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
self.notify_security_groups_member_updated(context, port)
|
self.notify_security_groups_member_updated(context, port)
|
||||||
return self._extend_port_dict_binding(context, port)
|
return self._extend_port_dict_binding(context, port)
|
||||||
|
|
||||||
|
@ -422,7 +422,9 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
port_db_entry = super(MidonetPluginV2,
|
port_db_entry = super(MidonetPluginV2,
|
||||||
self).create_port(context, port)
|
self).create_port(context, port)
|
||||||
self._extend_port_dict_security_group(context, port_db_entry)
|
# Caveat: port_db_entry is not a db model instance
|
||||||
|
sg_ids = self._get_security_groups_on_port(context, port)
|
||||||
|
self._process_port_create_security_group(context, port, sg_ids)
|
||||||
if is_compute_interface:
|
if is_compute_interface:
|
||||||
# Create a DHCP entry if needed.
|
# Create a DHCP entry if needed.
|
||||||
if 'ip_address' in (port_db_entry['fixed_ips'] or [{}])[0]:
|
if 'ip_address' in (port_db_entry['fixed_ips'] or [{}])[0]:
|
||||||
@ -453,8 +455,6 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
# get the quantum port from DB.
|
# get the quantum port from DB.
|
||||||
port_db_entry = super(MidonetPluginV2, self).get_port(context,
|
port_db_entry = super(MidonetPluginV2, self).get_port(context,
|
||||||
id, fields)
|
id, fields)
|
||||||
self._extend_port_dict_security_group(context, port_db_entry)
|
|
||||||
|
|
||||||
# verify that corresponding port exists in MidoNet.
|
# verify that corresponding port exists in MidoNet.
|
||||||
try:
|
try:
|
||||||
self.mido_api.get_port(id)
|
self.mido_api.get_port(id)
|
||||||
@ -477,7 +477,6 @@ class MidonetPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
try:
|
try:
|
||||||
for port in ports_db_entry:
|
for port in ports_db_entry:
|
||||||
self.mido_api.get_port(port['id'])
|
self.mido_api.get_port(port['id'])
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
except w_exc.HTTPNotFound:
|
except w_exc.HTTPNotFound:
|
||||||
raise MidonetResourceNotFound(resource_type='Port',
|
raise MidonetResourceNotFound(resource_type='Port',
|
||||||
id=port['id'])
|
id=port['id'])
|
||||||
|
@ -380,8 +380,7 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
sgids = self._get_security_groups_on_port(context, port)
|
sgids = self._get_security_groups_on_port(context, port)
|
||||||
port = super(NECPluginV2, self).create_port(context, port)
|
port = super(NECPluginV2, self).create_port(context, port)
|
||||||
self._process_port_create_security_group(
|
self._process_port_create_security_group(
|
||||||
context, port['id'], sgids)
|
context, port, sgids)
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
self.notify_security_groups_member_updated(context, port)
|
self.notify_security_groups_member_updated(context, port)
|
||||||
self._update_resource_status(context, "port", port['id'],
|
self._update_resource_status(context, "port", port['id'],
|
||||||
OperationalStatus.BUILD)
|
OperationalStatus.BUILD)
|
||||||
@ -416,9 +415,6 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
else:
|
else:
|
||||||
self.deactivate_port(context, old_port)
|
self.deactivate_port(context, old_port)
|
||||||
|
|
||||||
# NOTE: _extend_port_dict_security_group() is called in
|
|
||||||
# update_security_group_on_port() above, so we don't need to
|
|
||||||
# call it here.
|
|
||||||
return self._extend_port_dict_binding(context, new_port)
|
return self._extend_port_dict_binding(context, new_port)
|
||||||
|
|
||||||
def delete_port(self, context, id, l3_port_check=True):
|
def delete_port(self, context, id, l3_port_check=True):
|
||||||
@ -452,7 +448,6 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
def get_port(self, context, id, fields=None):
|
def get_port(self, context, id, fields=None):
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
port = super(NECPluginV2, self).get_port(context, id, fields)
|
port = super(NECPluginV2, self).get_port(context, id, fields)
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
self._extend_port_dict_binding(context, port)
|
self._extend_port_dict_binding(context, port)
|
||||||
return self._fields(port, fields)
|
return self._fields(port, fields)
|
||||||
|
|
||||||
@ -462,7 +457,6 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
fields)
|
fields)
|
||||||
# TODO(amotoki) filter by security group
|
# TODO(amotoki) filter by security group
|
||||||
for port in ports:
|
for port in ports:
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
self._extend_port_dict_binding(context, port)
|
self._extend_port_dict_binding(context, port)
|
||||||
return [self._fields(port, fields) for port in ports]
|
return [self._fields(port, fields) for port in ports]
|
||||||
|
|
||||||
|
@ -183,6 +183,7 @@ class NvpPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
self.nvp_opts.nvp_gen_timeout)
|
self.nvp_opts.nvp_gen_timeout)
|
||||||
|
|
||||||
db.configure_db()
|
db.configure_db()
|
||||||
|
# Extend the fault map
|
||||||
self._extend_fault_map()
|
self._extend_fault_map()
|
||||||
# Set up RPC interface for DHCP agent
|
# Set up RPC interface for DHCP agent
|
||||||
self.setup_rpc()
|
self.setup_rpc()
|
||||||
@ -1041,7 +1042,6 @@ class NvpPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
context, filters)
|
context, filters)
|
||||||
for quantum_lport in quantum_lports:
|
for quantum_lport in quantum_lports:
|
||||||
self._extend_port_port_security_dict(context, quantum_lport)
|
self._extend_port_port_security_dict(context, quantum_lport)
|
||||||
self._extend_port_dict_security_group(context, quantum_lport)
|
|
||||||
if (filters.get('network_id') and len(filters.get('network_id')) and
|
if (filters.get('network_id') and len(filters.get('network_id')) and
|
||||||
self._network_is_external(context, filters['network_id'][0])):
|
self._network_is_external(context, filters['network_id'][0])):
|
||||||
# Do not perform check on NVP platform
|
# Do not perform check on NVP platform
|
||||||
@ -1173,7 +1173,7 @@ class NvpPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
port_data[ext_sg.SECURITYGROUPS] = (
|
port_data[ext_sg.SECURITYGROUPS] = (
|
||||||
self._get_security_groups_on_port(context, port))
|
self._get_security_groups_on_port(context, port))
|
||||||
self._process_port_create_security_group(
|
self._process_port_create_security_group(
|
||||||
context, quantum_db['id'], port_data[ext_sg.SECURITYGROUPS])
|
context, port_data, port_data[ext_sg.SECURITYGROUPS])
|
||||||
# QoS extension checks
|
# QoS extension checks
|
||||||
port_data[ext_qos.QUEUE] = self._check_for_queue_and_create(
|
port_data[ext_qos.QUEUE] = self._check_for_queue_and_create(
|
||||||
context, port_data)
|
context, port_data)
|
||||||
@ -1201,7 +1201,6 @@ class NvpPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
# remove since it will be added in extend based on policy
|
# remove since it will be added in extend based on policy
|
||||||
del port_data[ext_qos.QUEUE]
|
del port_data[ext_qos.QUEUE]
|
||||||
self._extend_port_port_security_dict(context, port_data)
|
self._extend_port_port_security_dict(context, port_data)
|
||||||
self._extend_port_dict_security_group(context, port_data)
|
|
||||||
self._extend_port_qos_queue(context, port_data)
|
self._extend_port_qos_queue(context, port_data)
|
||||||
net = self.get_network(context, port_data['network_id'])
|
net = self.get_network(context, port_data['network_id'])
|
||||||
self.schedule_network(context, net)
|
self.schedule_network(context, net)
|
||||||
@ -1218,7 +1217,9 @@ class NvpPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
ret_port = super(NvpPluginV2, self).update_port(
|
ret_port = super(NvpPluginV2, self).update_port(
|
||||||
context, id, port)
|
context, id, port)
|
||||||
# copy values over
|
# copy values over - except fixed_ips as
|
||||||
|
# they've alreaby been processed
|
||||||
|
port['port'].pop('fixed_ips', None)
|
||||||
ret_port.update(port['port'])
|
ret_port.update(port['port'])
|
||||||
tenant_id = self._get_tenant_id_for_create(context, ret_port)
|
tenant_id = self._get_tenant_id_for_create(context, ret_port)
|
||||||
# populate port_security setting
|
# populate port_security setting
|
||||||
@ -1246,7 +1247,8 @@ class NvpPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
# delete the port binding and read it with the new rules.
|
# delete the port binding and read it with the new rules.
|
||||||
self._delete_port_security_group_bindings(context, id)
|
self._delete_port_security_group_bindings(context, id)
|
||||||
sgids = self._get_security_groups_on_port(context, port)
|
sgids = self._get_security_groups_on_port(context, port)
|
||||||
self._process_port_create_security_group(context, id, sgids)
|
self._process_port_create_security_group(context, ret_port,
|
||||||
|
sgids)
|
||||||
|
|
||||||
if psec.PORTSECURITY in port['port']:
|
if psec.PORTSECURITY in port['port']:
|
||||||
self._update_port_security_binding(
|
self._update_port_security_binding(
|
||||||
@ -1257,8 +1259,7 @@ class NvpPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
self._delete_port_queue_mapping(context, ret_port['id'])
|
self._delete_port_queue_mapping(context, ret_port['id'])
|
||||||
self._process_port_queue_mapping(context, ret_port)
|
self._process_port_queue_mapping(context, ret_port)
|
||||||
self._extend_port_port_security_dict(context, ret_port)
|
self._extend_port_port_security_dict(context, ret_port)
|
||||||
self._extend_port_dict_security_group(context, ret_port)
|
LOG.warn(_("Update port request: %s"), port)
|
||||||
LOG.debug(_("Update port request: %s"), port)
|
|
||||||
nvp_port_id = self._nvp_get_port_id(
|
nvp_port_id = self._nvp_get_port_id(
|
||||||
context, self.cluster, ret_port)
|
context, self.cluster, ret_port)
|
||||||
nvplib.update_port(self.cluster,
|
nvplib.update_port(self.cluster,
|
||||||
@ -1335,7 +1336,6 @@ class NvpPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
quantum_db_port = super(NvpPluginV2, self).get_port(context,
|
quantum_db_port = super(NvpPluginV2, self).get_port(context,
|
||||||
id, fields)
|
id, fields)
|
||||||
self._extend_port_port_security_dict(context, quantum_db_port)
|
self._extend_port_port_security_dict(context, quantum_db_port)
|
||||||
self._extend_port_dict_security_group(context, quantum_db_port)
|
|
||||||
self._extend_port_qos_queue(context, quantum_db_port)
|
self._extend_port_qos_queue(context, quantum_db_port)
|
||||||
|
|
||||||
if self._network_is_external(context,
|
if self._network_is_external(context,
|
||||||
|
@ -563,9 +563,7 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
self._ensure_default_security_group_on_port(context, port)
|
self._ensure_default_security_group_on_port(context, port)
|
||||||
sgids = self._get_security_groups_on_port(context, port)
|
sgids = self._get_security_groups_on_port(context, port)
|
||||||
port = super(OVSQuantumPluginV2, self).create_port(context, port)
|
port = super(OVSQuantumPluginV2, self).create_port(context, port)
|
||||||
self._process_port_create_security_group(
|
self._process_port_create_security_group(context, port, sgids)
|
||||||
context, port['id'], sgids)
|
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
self.notify_security_groups_member_updated(context, port)
|
self.notify_security_groups_member_updated(context, port)
|
||||||
return self._extend_port_dict_binding(context, port)
|
return self._extend_port_dict_binding(context, port)
|
||||||
|
|
||||||
@ -573,7 +571,6 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
port = super(OVSQuantumPluginV2, self).get_port(context,
|
port = super(OVSQuantumPluginV2, self).get_port(context,
|
||||||
id, fields)
|
id, fields)
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
self._extend_port_dict_binding(context, port)
|
self._extend_port_dict_binding(context, port)
|
||||||
return self._fields(port, fields)
|
return self._fields(port, fields)
|
||||||
|
|
||||||
@ -586,13 +583,11 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
page_reverse)
|
page_reverse)
|
||||||
#TODO(nati) filter by security group
|
#TODO(nati) filter by security group
|
||||||
for port in ports:
|
for port in ports:
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
self._extend_port_dict_binding(context, port)
|
self._extend_port_dict_binding(context, port)
|
||||||
return [self._fields(port, fields) for port in ports]
|
return [self._fields(port, fields) for port in ports]
|
||||||
|
|
||||||
def update_port(self, context, id, port):
|
def update_port(self, context, id, port):
|
||||||
session = context.session
|
session = context.session
|
||||||
|
|
||||||
need_port_update_notify = False
|
need_port_update_notify = False
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
original_port = super(OVSQuantumPluginV2, self).get_port(
|
original_port = super(OVSQuantumPluginV2, self).get_port(
|
||||||
@ -601,10 +596,8 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
context, id, port)
|
context, id, port)
|
||||||
need_port_update_notify = self.update_security_group_on_port(
|
need_port_update_notify = self.update_security_group_on_port(
|
||||||
context, id, port, original_port, updated_port)
|
context, id, port, original_port, updated_port)
|
||||||
|
|
||||||
need_port_update_notify |= self.is_security_group_member_updated(
|
need_port_update_notify |= self.is_security_group_member_updated(
|
||||||
context, original_port, updated_port)
|
context, original_port, updated_port)
|
||||||
|
|
||||||
if original_port['admin_state_up'] != updated_port['admin_state_up']:
|
if original_port['admin_state_up'] != updated_port['admin_state_up']:
|
||||||
need_port_update_notify = True
|
need_port_update_notify = True
|
||||||
|
|
||||||
@ -615,7 +608,6 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
binding.network_type,
|
binding.network_type,
|
||||||
binding.segmentation_id,
|
binding.segmentation_id,
|
||||||
binding.physical_network)
|
binding.physical_network)
|
||||||
|
|
||||||
return self._extend_port_dict_binding(context, updated_port)
|
return self._extend_port_dict_binding(context, updated_port)
|
||||||
|
|
||||||
def delete_port(self, context, id, l3_port_check=True):
|
def delete_port(self, context, id, l3_port_check=True):
|
||||||
|
@ -100,7 +100,6 @@ class RyuQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
|
|
||||||
def __init__(self, configfile=None):
|
def __init__(self, configfile=None):
|
||||||
db.configure_db()
|
db.configure_db()
|
||||||
|
|
||||||
self.tunnel_key = db_api_v2.TunnelKey(
|
self.tunnel_key = db_api_v2.TunnelKey(
|
||||||
cfg.CONF.OVS.tunnel_key_min, cfg.CONF.OVS.tunnel_key_max)
|
cfg.CONF.OVS.tunnel_key_min, cfg.CONF.OVS.tunnel_key_max)
|
||||||
self.ofp_api_host = cfg.CONF.OVS.openflow_rest_api
|
self.ofp_api_host = cfg.CONF.OVS.openflow_rest_api
|
||||||
@ -203,8 +202,7 @@ class RyuQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
sgids = self._get_security_groups_on_port(context, port)
|
sgids = self._get_security_groups_on_port(context, port)
|
||||||
port = super(RyuQuantumPluginV2, self).create_port(context, port)
|
port = super(RyuQuantumPluginV2, self).create_port(context, port)
|
||||||
self._process_port_create_security_group(
|
self._process_port_create_security_group(
|
||||||
context, port['id'], sgids)
|
context, port, sgids)
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
self.notify_security_groups_member_updated(context, port)
|
self.notify_security_groups_member_updated(context, port)
|
||||||
self.iface_client.create_network_id(port['id'], port['network_id'])
|
self.iface_client.create_network_id(port['id'], port['network_id'])
|
||||||
return port
|
return port
|
||||||
@ -253,13 +251,10 @@ class RyuQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
port = super(RyuQuantumPluginV2, self).get_port(context, id,
|
port = super(RyuQuantumPluginV2, self).get_port(context, id,
|
||||||
fields)
|
fields)
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
return self._fields(port, fields)
|
return self._fields(port, fields)
|
||||||
|
|
||||||
def get_ports(self, context, filters=None, fields=None):
|
def get_ports(self, context, filters=None, fields=None):
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
ports = super(RyuQuantumPluginV2, self).get_ports(
|
ports = super(RyuQuantumPluginV2, self).get_ports(
|
||||||
context, filters, fields)
|
context, filters, fields)
|
||||||
for port in ports:
|
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
return [self._fields(port, fields) for port in ports]
|
return [self._fields(port, fields) for port in ports]
|
||||||
|
@ -116,9 +116,8 @@ class PortSecurityTestPlugin(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
|
|
||||||
if (p.get(ext_sg.SECURITYGROUPS) and p[psec.PORTSECURITY]):
|
if (p.get(ext_sg.SECURITYGROUPS) and p[psec.PORTSECURITY]):
|
||||||
self._process_port_create_security_group(
|
self._process_port_create_security_group(
|
||||||
context, p['id'], p[ext_sg.SECURITYGROUPS])
|
context, p, p[ext_sg.SECURITYGROUPS])
|
||||||
|
|
||||||
self._extend_port_dict_security_group(context, p)
|
|
||||||
self._extend_port_port_security_dict(context, p)
|
self._extend_port_port_security_dict(context, p)
|
||||||
|
|
||||||
return port['port']
|
return port['port']
|
||||||
@ -132,7 +131,8 @@ class PortSecurityTestPlugin(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
ret_port = super(PortSecurityTestPlugin, self).update_port(
|
ret_port = super(PortSecurityTestPlugin, self).update_port(
|
||||||
context, id, port)
|
context, id, port)
|
||||||
# copy values over
|
# copy values over - but not fixed_ips
|
||||||
|
port['port'].pop('fixed_ips', None)
|
||||||
ret_port.update(port['port'])
|
ret_port.update(port['port'])
|
||||||
|
|
||||||
# populate port_security setting
|
# populate port_security setting
|
||||||
@ -164,14 +164,16 @@ class PortSecurityTestPlugin(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
# delete the port binding and read it with the new rules.
|
# delete the port binding and read it with the new rules.
|
||||||
self._delete_port_security_group_bindings(context, id)
|
self._delete_port_security_group_bindings(context, id)
|
||||||
sgids = self._get_security_groups_on_port(context, port)
|
sgids = self._get_security_groups_on_port(context, port)
|
||||||
self._process_port_create_security_group(context, id, sgids)
|
# process port create sec groups needs port id
|
||||||
|
port['id'] = id
|
||||||
|
self._process_port_create_security_group(context,
|
||||||
|
ret_port, sgids)
|
||||||
|
|
||||||
if psec.PORTSECURITY in port['port']:
|
if psec.PORTSECURITY in port['port']:
|
||||||
self._update_port_security_binding(
|
self._update_port_security_binding(
|
||||||
context, id, ret_port[psec.PORTSECURITY])
|
context, id, ret_port[psec.PORTSECURITY])
|
||||||
|
|
||||||
self._extend_port_port_security_dict(context, ret_port)
|
self._extend_port_port_security_dict(context, ret_port)
|
||||||
self._extend_port_dict_security_group(context, ret_port)
|
|
||||||
|
|
||||||
return ret_port
|
return ret_port
|
||||||
|
|
||||||
@ -301,13 +303,12 @@ class TestPortSecurity(PortSecurityDBTestCase):
|
|||||||
psec.PORTSECURITY: False}}
|
psec.PORTSECURITY: False}}
|
||||||
req = self.new_update_request('ports', update_port,
|
req = self.new_update_request('ports', update_port,
|
||||||
port['port']['id'])
|
port['port']['id'])
|
||||||
|
|
||||||
port = self.deserialize('json', req.get_response(self.api))
|
port = self.deserialize('json', req.get_response(self.api))
|
||||||
self.assertEqual(port['port'][psec.PORTSECURITY], False)
|
self.assertEqual(port['port'][psec.PORTSECURITY], False)
|
||||||
self.assertEqual(len(port['port'][ext_sg.SECURITYGROUPS]), 0)
|
self.assertEqual(len(port['port'][ext_sg.SECURITYGROUPS]), 0)
|
||||||
self._delete('ports', port['port']['id'])
|
self._delete('ports', port['port']['id'])
|
||||||
|
|
||||||
def test_update_port_remove_port_security_security_group_readd(self):
|
def test_update_port_remove_port_security_security_group_read(self):
|
||||||
if self._skip_security_group:
|
if self._skip_security_group:
|
||||||
self.skipTest("Plugin does not support security groups")
|
self.skipTest("Plugin does not support security groups")
|
||||||
with self.network() as net:
|
with self.network() as net:
|
||||||
|
@ -192,9 +192,8 @@ class SecurityGroupTestPlugin(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
sgids = self._get_security_groups_on_port(context, port)
|
sgids = self._get_security_groups_on_port(context, port)
|
||||||
port = super(SecurityGroupTestPlugin, self).create_port(context,
|
port = super(SecurityGroupTestPlugin, self).create_port(context,
|
||||||
port)
|
port)
|
||||||
self._process_port_create_security_group(context, port['id'],
|
self._process_port_create_security_group(context, port,
|
||||||
sgids)
|
sgids)
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
return port
|
return port
|
||||||
|
|
||||||
def update_port(self, context, id, port):
|
def update_port(self, context, id, port):
|
||||||
@ -205,11 +204,12 @@ class SecurityGroupTestPlugin(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
self._get_security_groups_on_port(context, port))
|
self._get_security_groups_on_port(context, port))
|
||||||
# delete the port binding and read it with the new rules
|
# delete the port binding and read it with the new rules
|
||||||
self._delete_port_security_group_bindings(context, id)
|
self._delete_port_security_group_bindings(context, id)
|
||||||
|
port['port']['id'] = id
|
||||||
self._process_port_create_security_group(
|
self._process_port_create_security_group(
|
||||||
context, id, port['port'].get(ext_sg.SECURITYGROUPS))
|
context, port['port'],
|
||||||
|
port['port'].get(ext_sg.SECURITYGROUPS))
|
||||||
port = super(SecurityGroupTestPlugin, self).update_port(
|
port = super(SecurityGroupTestPlugin, self).update_port(
|
||||||
context, id, port)
|
context, id, port)
|
||||||
self._extend_port_dict_security_group(context, port)
|
|
||||||
return port
|
return port
|
||||||
|
|
||||||
def create_network(self, context, network):
|
def create_network(self, context, network):
|
||||||
@ -224,8 +224,6 @@ class SecurityGroupTestPlugin(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
quantum_lports = super(SecurityGroupTestPlugin, self).get_ports(
|
quantum_lports = super(SecurityGroupTestPlugin, self).get_ports(
|
||||||
context, filters, sorts=sorts, limit=limit, marker=marker,
|
context, filters, sorts=sorts, limit=limit, marker=marker,
|
||||||
page_reverse=page_reverse)
|
page_reverse=page_reverse)
|
||||||
for quantum_lport in quantum_lports:
|
|
||||||
self._extend_port_dict_security_group(context, quantum_lport)
|
|
||||||
return quantum_lports
|
return quantum_lports
|
||||||
|
|
||||||
|
|
||||||
@ -721,11 +719,10 @@ class TestSecurityGroups(SecurityGroupDBTestCase):
|
|||||||
def test_list_ports_security_group(self):
|
def test_list_ports_security_group(self):
|
||||||
with self.network() as n:
|
with self.network() as n:
|
||||||
with self.subnet(n):
|
with self.subnet(n):
|
||||||
res = self._create_port(self.fmt, n['network']['id'])
|
self._create_port(self.fmt, n['network']['id'])
|
||||||
self.deserialize(self.fmt, res)
|
req = self.new_list_request('ports')
|
||||||
res = self.new_list_request('ports')
|
res = req.get_response(self.api)
|
||||||
ports = self.deserialize(self.fmt,
|
ports = self.deserialize(self.fmt, res)
|
||||||
res.get_response(self.api))
|
|
||||||
port = ports['ports'][0]
|
port = ports['ports'][0]
|
||||||
self.assertEqual(len(port[ext_sg.SECURITYGROUPS]), 1)
|
self.assertEqual(len(port[ext_sg.SECURITYGROUPS]), 1)
|
||||||
self._delete('ports', port['id'])
|
self._delete('ports', port['id'])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user