You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
658 lines
25 KiB
658 lines
25 KiB
# All Rights Reserved. |
|
# |
|
# 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. |
|
|
|
import netaddr |
|
from neutron_lib import constants |
|
from neutron_lib.objects import common_types |
|
from neutron_lib.utils import net as net_utils |
|
from oslo_log import log as logging |
|
from oslo_utils import versionutils |
|
from oslo_versionedobjects import fields as obj_fields |
|
|
|
from neutron.common import _constants |
|
from neutron.common import utils |
|
from neutron.db.models import dns as dns_models |
|
from neutron.db.models import l3 |
|
from neutron.db.models import securitygroup as sg_models |
|
from neutron.db import models_v2 |
|
from neutron.objects import base |
|
from neutron.objects.db import api as obj_db_api |
|
from neutron.objects.qos import binding |
|
from neutron.plugins.ml2 import models as ml2_models |
|
|
|
LOG = logging.getLogger(__name__) |
|
|
|
|
|
class PortBindingBase(base.NeutronDbObject): |
|
|
|
foreign_keys = { |
|
'Port': {'port_id': 'id'}, |
|
} |
|
|
|
@classmethod |
|
def modify_fields_to_db(cls, fields): |
|
result = super(PortBindingBase, cls).modify_fields_to_db(fields) |
|
for field in ['profile', 'vif_details']: |
|
if field in result: |
|
# dump field into string, set '' if empty '{}' or None |
|
result[field] = ( |
|
cls.filter_to_json_str(result[field], default='')) |
|
return result |
|
|
|
@classmethod |
|
def modify_fields_from_db(cls, db_obj): |
|
fields = super(PortBindingBase, cls).modify_fields_from_db(db_obj) |
|
if 'vif_details' in fields: |
|
# load string from DB into dict, set None if vif_details is '' |
|
fields['vif_details'] = ( |
|
cls.load_json_from_str(fields['vif_details'])) |
|
if 'profile' in fields: |
|
# load string from DB into dict, set {} if profile is '' |
|
fields['profile'] = ( |
|
cls.load_json_from_str(fields['profile'], default={})) |
|
return fields |
|
|
|
|
|
@base.NeutronObjectRegistry.register |
|
class PortBinding(PortBindingBase): |
|
# Version 1.0: Initial version |
|
VERSION = '1.0' |
|
|
|
db_model = ml2_models.PortBinding |
|
|
|
fields = { |
|
'port_id': common_types.UUIDField(), |
|
'host': obj_fields.StringField(), |
|
'profile': common_types.DictOfMiscValuesField(), |
|
'vif_type': obj_fields.StringField(), |
|
'vif_details': common_types.DictOfMiscValuesField(nullable=True), |
|
'vnic_type': obj_fields.StringField(), |
|
'status': common_types.PortBindingStatusEnumField( |
|
default=constants.ACTIVE), |
|
} |
|
|
|
primary_keys = ['port_id', 'host'] |
|
|
|
|
|
@base.NeutronObjectRegistry.register |
|
class DistributedPortBinding(PortBindingBase): |
|
# Version 1.0: Initial version |
|
VERSION = '1.0' |
|
|
|
db_model = ml2_models.DistributedPortBinding |
|
|
|
fields = { |
|
'port_id': common_types.UUIDField(), |
|
'host': obj_fields.StringField(), |
|
'profile': common_types.DictOfMiscValuesField(), |
|
'vif_type': obj_fields.StringField(), |
|
'vif_details': common_types.DictOfMiscValuesField(nullable=True), |
|
'vnic_type': obj_fields.StringField(), |
|
# NOTE(ihrachys): Fields below are specific to this type of binding. In |
|
# the future, we could think of converging different types of bindings |
|
# into a single field |
|
'status': obj_fields.StringField(), |
|
'router_id': obj_fields.StringField(nullable=True), |
|
} |
|
|
|
primary_keys = ['host', 'port_id'] |
|
|
|
|
|
@base.NeutronObjectRegistry.register |
|
class PortBindingLevel(base.NeutronDbObject): |
|
# Version 1.0: Initial version |
|
# Version 1.1: Added segment_id |
|
VERSION = '1.1' |
|
|
|
db_model = ml2_models.PortBindingLevel |
|
|
|
primary_keys = ['port_id', 'host', 'level'] |
|
|
|
fields = { |
|
'port_id': common_types.UUIDField(), |
|
'host': obj_fields.StringField(), |
|
'level': obj_fields.IntegerField(), |
|
'driver': obj_fields.StringField(nullable=True), |
|
'segment': obj_fields.ObjectField( |
|
'NetworkSegment', nullable=True |
|
), |
|
# arguably redundant but allows us to define foreign key for 'segment' |
|
# synthetic field inside NetworkSegment definition |
|
'segment_id': common_types.UUIDField(nullable=True), |
|
} |
|
|
|
synthetic_fields = ['segment'] |
|
|
|
foreign_keys = { |
|
'Port': {'port_id': 'id'}, |
|
} |
|
|
|
@classmethod |
|
def get_objects(cls, context, _pager=None, validate_filters=True, |
|
**kwargs): |
|
if not _pager: |
|
_pager = base.Pager() |
|
if not _pager.sorts: |
|
# (NOTE) True means ASC, False is DESC |
|
_pager.sorts = [('port_id', True), ('level', True)] |
|
return super(PortBindingLevel, cls).get_objects( |
|
context, _pager, validate_filters, **kwargs) |
|
|
|
def obj_make_compatible(self, primitive, target_version): |
|
_target_version = versionutils.convert_version_to_tuple(target_version) |
|
if _target_version < (1, 1): |
|
primitive.pop('segment_id', None) |
|
|
|
|
|
@base.NeutronObjectRegistry.register |
|
class IPAllocation(base.NeutronDbObject): |
|
# Version 1.0: Initial version |
|
VERSION = '1.0' |
|
|
|
db_model = models_v2.IPAllocation |
|
|
|
fields = { |
|
'port_id': common_types.UUIDField(nullable=True), |
|
'subnet_id': common_types.UUIDField(), |
|
'network_id': common_types.UUIDField(), |
|
'ip_address': obj_fields.IPAddressField(), |
|
} |
|
|
|
fields_no_update = fields.keys() |
|
|
|
primary_keys = ['subnet_id', 'network_id', 'ip_address'] |
|
|
|
foreign_keys = { |
|
'Port': {'port_id': 'id'}, |
|
} |
|
|
|
# TODO(rossella_s): get rid of it once we switch the db model to using |
|
# custom types. |
|
@classmethod |
|
def modify_fields_to_db(cls, fields): |
|
result = super(IPAllocation, cls).modify_fields_to_db(fields) |
|
if 'ip_address' in result: |
|
result['ip_address'] = cls.filter_to_str(result['ip_address']) |
|
return result |
|
|
|
# TODO(rossella_s): get rid of it once we switch the db model to using |
|
# custom types. |
|
@classmethod |
|
def modify_fields_from_db(cls, db_obj): |
|
fields = super(IPAllocation, cls).modify_fields_from_db(db_obj) |
|
if 'ip_address' in fields: |
|
fields['ip_address'] = netaddr.IPAddress(fields['ip_address']) |
|
return fields |
|
|
|
@classmethod |
|
def get_alloc_by_subnet_id(cls, context, subnet_id, device_owner, |
|
exclude=True): |
|
# need to join with ports table as IPAllocation's port |
|
# is not joined eagerly and thus producing query which yields |
|
# incorrect results |
|
if exclude: |
|
alloc_db = (context.session.query(models_v2.IPAllocation). |
|
filter_by(subnet_id=subnet_id).join(models_v2.Port). |
|
filter(~models_v2.Port.device_owner. |
|
in_(device_owner)).first()) |
|
else: |
|
alloc_db = (context.session.query(models_v2.IPAllocation). |
|
filter_by(subnet_id=subnet_id).join(models_v2.Port). |
|
filter(models_v2.Port.device_owner. |
|
in_(device_owner)).first()) |
|
if exclude and alloc_db: |
|
return super(IPAllocation, cls)._load_object(context, alloc_db) |
|
if alloc_db: |
|
return True |
|
|
|
@classmethod |
|
def delete_alloc_by_subnet_id(cls, context, subnet_id): |
|
allocs = context.session.query(models_v2.IPAllocation).filter_by( |
|
subnet_id=subnet_id).all() |
|
for alloc in allocs: |
|
alloc_obj = super(IPAllocation, cls)._load_object(context, alloc) |
|
alloc_obj.delete() |
|
|
|
|
|
@base.NeutronObjectRegistry.register |
|
class PortDNS(base.NeutronDbObject): |
|
# Version 1.0: Initial version |
|
# Version 1.1: Add dns_domain attribute |
|
VERSION = '1.1' |
|
|
|
db_model = dns_models.PortDNS |
|
|
|
primary_keys = ['port_id'] |
|
|
|
foreign_keys = { |
|
'Port': {'port_id': 'id'}, |
|
} |
|
|
|
fields = { |
|
'port_id': common_types.UUIDField(), |
|
'current_dns_name': common_types.DomainNameField(), |
|
'current_dns_domain': common_types.DomainNameField(), |
|
'previous_dns_name': common_types.DomainNameField(), |
|
'previous_dns_domain': common_types.DomainNameField(), |
|
'dns_name': common_types.DomainNameField(), |
|
'dns_domain': common_types.DomainNameField(), |
|
} |
|
|
|
|
|
@base.NeutronObjectRegistry.register |
|
class SecurityGroupPortBinding(base.NeutronDbObject): |
|
|
|
# Version 1.0: Initial version |
|
VERSION = '1.0' |
|
|
|
db_model = sg_models.SecurityGroupPortBinding |
|
|
|
fields = { |
|
'port_id': common_types.UUIDField(), |
|
'security_group_id': common_types.UUIDField(), |
|
} |
|
|
|
primary_keys = ['port_id', 'security_group_id'] |
|
|
|
|
|
@base.NeutronObjectRegistry.register |
|
class Port(base.NeutronDbObject): |
|
# Version 1.0: Initial version |
|
# Version 1.1: Add data_plane_status field |
|
# Version 1.2: Added segment_id to binding_levels |
|
# Version 1.3: distributed_binding -> distributed_bindings |
|
# Version 1.4: Attribute binding becomes ListOfObjectsField |
|
# Version 1.5: Added qos_network_policy_id field |
|
VERSION = '1.5' |
|
|
|
db_model = models_v2.Port |
|
|
|
fields = { |
|
'id': common_types.UUIDField(), |
|
'project_id': obj_fields.StringField(nullable=True), |
|
'name': obj_fields.StringField(nullable=True), |
|
'network_id': common_types.UUIDField(), |
|
'mac_address': common_types.MACAddressField(), |
|
'admin_state_up': obj_fields.BooleanField(), |
|
'device_id': obj_fields.StringField(), |
|
'device_owner': obj_fields.StringField(), |
|
'status': obj_fields.StringField(), |
|
|
|
'allowed_address_pairs': obj_fields.ListOfObjectsField( |
|
'AllowedAddressPair', nullable=True |
|
), |
|
'bindings': obj_fields.ListOfObjectsField( |
|
'PortBinding', nullable=True |
|
), |
|
'data_plane_status': obj_fields.ObjectField( |
|
'PortDataPlaneStatus', nullable=True |
|
), |
|
'dhcp_options': obj_fields.ListOfObjectsField( |
|
'ExtraDhcpOpt', nullable=True |
|
), |
|
'distributed_bindings': obj_fields.ListOfObjectsField( |
|
'DistributedPortBinding', nullable=True |
|
), |
|
'dns': obj_fields.ObjectField('PortDNS', nullable=True), |
|
'fixed_ips': obj_fields.ListOfObjectsField( |
|
'IPAllocation', nullable=True |
|
), |
|
# TODO(ihrachys): consider converting to boolean |
|
'security': obj_fields.ObjectField( |
|
'PortSecurity', nullable=True |
|
), |
|
'security_group_ids': common_types.SetOfUUIDsField( |
|
nullable=True, |
|
# TODO(ihrachys): how do we safely pass a mutable default? |
|
default=None, |
|
), |
|
'qos_policy_id': common_types.UUIDField(nullable=True, default=None), |
|
'qos_network_policy_id': common_types.UUIDField(nullable=True, |
|
default=None), |
|
|
|
'binding_levels': obj_fields.ListOfObjectsField( |
|
'PortBindingLevel', nullable=True |
|
), |
|
|
|
# TODO(ihrachys): consider adding a 'dns_assignment' fully synthetic |
|
# field in later object iterations |
|
} |
|
|
|
extra_filter_names = {'security_group_ids'} |
|
|
|
fields_no_update = ['project_id', 'network_id'] |
|
|
|
synthetic_fields = [ |
|
'allowed_address_pairs', |
|
'bindings', |
|
'binding_levels', |
|
'data_plane_status', |
|
'dhcp_options', |
|
'distributed_bindings', |
|
'dns', |
|
'fixed_ips', |
|
'qos_policy_id', |
|
'qos_network_policy_id', |
|
'security', |
|
'security_group_ids', |
|
] |
|
|
|
fields_need_translation = { |
|
'bindings': 'port_bindings', |
|
'dhcp_options': 'dhcp_opts', |
|
'distributed_bindings': 'distributed_port_binding', |
|
'security': 'port_security', |
|
} |
|
|
|
def create(self): |
|
fields = self.obj_get_changes() |
|
with self.db_context_writer(self.obj_context): |
|
sg_ids = self.security_group_ids |
|
if sg_ids is None: |
|
sg_ids = set() |
|
qos_policy_id = self.qos_policy_id |
|
super(Port, self).create() |
|
if 'security_group_ids' in fields: |
|
self._attach_security_groups(sg_ids) |
|
if 'qos_policy_id' in fields: |
|
self._attach_qos_policy(qos_policy_id) |
|
|
|
def update(self): |
|
fields = self.obj_get_changes() |
|
with self.db_context_writer(self.obj_context): |
|
super(Port, self).update() |
|
if 'security_group_ids' in fields: |
|
self._attach_security_groups(fields['security_group_ids']) |
|
if 'qos_policy_id' in fields: |
|
self._attach_qos_policy(fields['qos_policy_id']) |
|
|
|
def _attach_qos_policy(self, qos_policy_id): |
|
binding.QosPolicyPortBinding.delete_objects( |
|
self.obj_context, port_id=self.id) |
|
if qos_policy_id: |
|
port_binding_obj = binding.QosPolicyPortBinding( |
|
self.obj_context, policy_id=qos_policy_id, port_id=self.id) |
|
port_binding_obj.create() |
|
|
|
self.qos_policy_id = qos_policy_id |
|
self.obj_reset_changes(['qos_policy_id']) |
|
|
|
def _attach_security_groups(self, sg_ids): |
|
# TODO(ihrachys): consider introducing an (internal) object for the |
|
# binding to decouple database operations a bit more |
|
obj_db_api.delete_objects( |
|
SecurityGroupPortBinding, self.obj_context, port_id=self.id) |
|
if sg_ids: |
|
for sg_id in sg_ids: |
|
self._attach_security_group(sg_id) |
|
self.security_group_ids = sg_ids |
|
self.obj_reset_changes(['security_group_ids']) |
|
|
|
def _attach_security_group(self, sg_id): |
|
obj_db_api.create_object( |
|
SecurityGroupPortBinding, self.obj_context, |
|
{'port_id': self.id, 'security_group_id': sg_id} |
|
) |
|
|
|
@classmethod |
|
@utils.timecost |
|
def get_objects(cls, context, _pager=None, validate_filters=True, |
|
security_group_ids=None, **kwargs): |
|
if security_group_ids: |
|
ports_with_sg = cls.get_ports_ids_by_security_groups( |
|
context, security_group_ids) |
|
port_ids = kwargs.get("id", []) |
|
if port_ids: |
|
kwargs['id'] = list(set(port_ids) & set(ports_with_sg)) |
|
else: |
|
kwargs['id'] = ports_with_sg |
|
port_array = super(Port, cls).get_objects(context, _pager, |
|
validate_filters, |
|
**kwargs) |
|
sg_count = len(security_group_ids) if security_group_ids else 0 |
|
LOG.debug("Time-cost: Fetching %(port_count)s ports in %(sg_count)s " |
|
"security groups", |
|
{'port_count': len(port_array), |
|
'sg_count': sg_count}) |
|
return port_array |
|
|
|
@classmethod |
|
def get_auto_deletable_port_ids_and_proper_port_count_by_segment( |
|
cls, context, segment_id): |
|
|
|
query = context.session.query(models_v2.Port.id) |
|
query = query.join( |
|
ml2_models.PortBindingLevel, |
|
ml2_models.PortBindingLevel.port_id == models_v2.Port.id) |
|
query = query.filter( |
|
ml2_models.PortBindingLevel.segment_id == segment_id) |
|
|
|
q_delete = query.filter( |
|
models_v2.Port.device_owner.in_( |
|
_constants.AUTO_DELETE_PORT_OWNERS)) |
|
|
|
q_proper = query.filter( |
|
~models_v2.Port.device_owner.in_( |
|
_constants.AUTO_DELETE_PORT_OWNERS)) |
|
|
|
return ([r.id for r in q_delete.all()], q_proper.count()) |
|
|
|
@classmethod |
|
def modify_fields_to_db(cls, fields): |
|
result = super(Port, cls).modify_fields_to_db(fields) |
|
|
|
# TODO(rossella_s): get rid of it once we switch the db model to using |
|
# custom types. |
|
if 'mac_address' in result: |
|
result['mac_address'] = cls.filter_to_str(result['mac_address']) |
|
|
|
# convert None to [] |
|
if 'distributed_port_binding' in result: |
|
result['distributed_port_binding'] = ( |
|
result['distributed_port_binding'] or [] |
|
) |
|
return result |
|
|
|
@classmethod |
|
def modify_fields_from_db(cls, db_obj): |
|
fields = super(Port, cls).modify_fields_from_db(db_obj) |
|
|
|
# TODO(rossella_s): get rid of it once we switch the db model to using |
|
# custom types. |
|
if 'mac_address' in fields: |
|
fields['mac_address'] = net_utils.AuthenticEUI( |
|
fields['mac_address']) |
|
|
|
distributed_port_binding = fields.get('distributed_bindings') |
|
if distributed_port_binding: |
|
# TODO(ihrachys) support multiple bindings |
|
fields['distributed_bindings'] = fields['distributed_bindings'][0] |
|
else: |
|
fields['distributed_bindings'] = [] |
|
return fields |
|
|
|
def from_db_object(self, db_obj): |
|
super(Port, self).from_db_object(db_obj) |
|
# extract security group bindings |
|
if db_obj.get('security_groups', []): |
|
self.security_group_ids = { |
|
sg.security_group_id |
|
for sg in db_obj.security_groups |
|
} |
|
else: |
|
self.security_group_ids = set() |
|
fields_to_change = ['security_group_ids'] |
|
|
|
# extract qos policy binding |
|
if db_obj.get('qos_policy_binding'): |
|
self.qos_policy_id = db_obj.qos_policy_binding.policy_id |
|
fields_to_change.append('qos_policy_id') |
|
if db_obj.get('qos_network_policy_binding'): |
|
self.qos_network_policy_id = ( |
|
db_obj.qos_network_policy_binding.policy_id) |
|
fields_to_change.append('qos_network_policy_binding') |
|
|
|
self.obj_reset_changes(fields_to_change) |
|
|
|
def obj_make_compatible(self, primitive, target_version): |
|
_target_version = versionutils.convert_version_to_tuple(target_version) |
|
if _target_version < (1, 2): |
|
binding_levels = primitive.get('binding_levels', []) |
|
for lvl in binding_levels: |
|
lvl['versioned_object.version'] = '1.0' |
|
lvl['versioned_object.data'].pop('segment_id', None) |
|
if _target_version < (1, 3): |
|
bindings = primitive.pop('distributed_bindings', []) |
|
primitive['distributed_binding'] = (bindings[0] |
|
if bindings else None) |
|
if _target_version < (1, 4): |
|
# In version 1.4 we add support for multiple port bindings. |
|
# Previous versions only support one port binding. The following |
|
# lines look for the active port binding, which is the only one |
|
# needed in previous versions |
|
if 'bindings' in primitive: |
|
original_bindings = primitive.pop('bindings') |
|
primitive['binding'] = None |
|
for a_binding in original_bindings: |
|
if (a_binding['versioned_object.data']['status'] == |
|
constants.ACTIVE): |
|
primitive['binding'] = a_binding |
|
break |
|
if _target_version < (1, 5): |
|
primitive.pop('qos_network_policy_id', None) |
|
|
|
@classmethod |
|
def get_ports_by_router_and_network(cls, context, router_id, owner, |
|
network_id): |
|
"""Returns port objects filtering by router ID, owner and network ID""" |
|
rports_filter = (models_v2.Port.network_id == network_id, ) |
|
router_filter = (models_v2.Port.network_id == network_id, ) |
|
return cls._get_ports_by_router(context, router_id, owner, |
|
rports_filter, router_filter) |
|
|
|
@classmethod |
|
def get_ports_by_router_and_port(cls, context, router_id, owner, port_id): |
|
"""Returns port objects filtering by router ID, owner and port ID""" |
|
rports_filter = (l3.RouterPort.port_id == port_id, ) |
|
router_filter = (models_v2.Port.id == port_id, ) |
|
return cls._get_ports_by_router(context, router_id, owner, |
|
rports_filter, router_filter) |
|
|
|
@classmethod |
|
def _get_ports_by_router(cls, context, router_id, owner, rports_filter, |
|
router_filter): |
|
"""Returns port objects filtering by router id and owner |
|
|
|
The method will receive extra filters depending of the caller (filter |
|
by network or filter by port). |
|
|
|
The ports are retrieved using: |
|
- The RouterPort registers. Each time a port is assigned to a router, |
|
a new RouterPort register is added to the DB. |
|
- The port owner and device_id information. |
|
|
|
Both searches should return the same result. If not, a warning message |
|
is logged and the port list to be returned is completed with the |
|
missing ones. |
|
""" |
|
rports_filter += (l3.RouterPort.router_id == router_id, |
|
l3.RouterPort.port_type == owner) |
|
router_filter += (models_v2.Port.device_id == router_id, |
|
models_v2.Port.device_owner == owner) |
|
|
|
ports = context.session.query(models_v2.Port).join( |
|
l3.RouterPort).filter(*rports_filter) |
|
ports_rports = [cls._load_object(context, db_obj) |
|
for db_obj in ports.all()] |
|
|
|
ports = context.session.query(models_v2.Port).filter(*router_filter) |
|
ports_router = [cls._load_object(context, db_obj) |
|
for db_obj in ports.all()] |
|
|
|
ports_rports_ids = {p.id for p in ports_rports} |
|
ports_router_ids = {p.id for p in ports_router} |
|
missing_port_ids = ports_router_ids - ports_rports_ids |
|
if missing_port_ids: |
|
LOG.warning('The following ports, assigned to router ' |
|
'%(router_id)s, do not have a "routerport" register: ' |
|
'%(port_ids)s', {'router_id': router_id, |
|
'port_ids': missing_port_ids}) |
|
port_objs = [p for p in ports_router if p.id in missing_port_ids] |
|
ports_rports += port_objs |
|
|
|
return ports_rports |
|
|
|
@classmethod |
|
def get_ports_ids_by_security_groups(cls, context, security_group_ids, |
|
excluded_device_owners=None): |
|
query = context.session.query(sg_models.SecurityGroupPortBinding) |
|
query = query.filter( |
|
sg_models.SecurityGroupPortBinding.security_group_id.in_( |
|
security_group_ids)) |
|
if excluded_device_owners: |
|
query = query.join(models_v2.Port) |
|
query = query.filter( |
|
~models_v2.Port.device_owner.in_(excluded_device_owners)) |
|
return [port_binding['port_id'] for port_binding in query.all()] |
|
|
|
@classmethod |
|
def get_ports_by_binding_type_and_host(cls, context, |
|
binding_type, host): |
|
query = context.session.query(models_v2.Port).join( |
|
ml2_models.PortBinding) |
|
query = query.filter( |
|
ml2_models.PortBinding.vif_type == binding_type, |
|
ml2_models.PortBinding.host == host) |
|
return [cls._load_object(context, db_obj) for db_obj in query.all()] |
|
|
|
@classmethod |
|
def get_ports_by_vnic_type_and_host( |
|
cls, context, vnic_type, host): |
|
query = context.session.query(models_v2.Port).join( |
|
ml2_models.PortBinding) |
|
query = query.filter( |
|
ml2_models.PortBinding.vnic_type == vnic_type, |
|
ml2_models.PortBinding.host == host) |
|
return [cls._load_object(context, db_obj) for db_obj in query.all()] |
|
|
|
@classmethod |
|
def check_network_ports_by_binding_types( |
|
cls, context, network_id, binding_types, negative_search=False): |
|
"""This method is to check whether networks have ports with given |
|
binding_types. |
|
|
|
:param context: |
|
:param network_id: ID of network to check |
|
:param binding_types: list of binding types to look for |
|
:param negative_search: if set to true, ports with with binding_type |
|
other than "binding_types" will be counted |
|
:return: True if any port is found, False otherwise |
|
""" |
|
query = context.session.query(models_v2.Port).join( |
|
ml2_models.PortBinding) |
|
query = query.filter(models_v2.Port.network_id == network_id) |
|
if negative_search: |
|
query = query.filter( |
|
ml2_models.PortBinding.vif_type.notin_(binding_types)) |
|
else: |
|
query = query.filter( |
|
ml2_models.PortBinding.vif_type.in_(binding_types)) |
|
return bool(query.count()) |
|
|
|
@classmethod |
|
def get_ports_allocated_by_subnet_id(cls, context, subnet_id): |
|
"""Return ports with fixed IPs in a subnet""" |
|
return context.session.query(models_v2.Port).filter( |
|
models_v2.IPAllocation.port_id == models_v2.Port.id).filter( |
|
models_v2.IPAllocation.subnet_id == subnet_id).all()
|
|
|