neutron/neutron/db/models_v2.py

279 lines
12 KiB
Python

# Copyright (c) 2012 OpenStack Foundation.
# 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.
from neutron_lib.api.definitions import network as net_def
from neutron_lib.api.definitions import port as port_def
from neutron_lib.api.definitions import subnet as subnet_def
from neutron_lib.api.definitions import subnetpool as subnetpool_def
from neutron_lib import constants
from neutron_lib.db import constants as db_const
from neutron_lib.db import model_base
import sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy import sql
from neutron.db.network_dhcp_agent_binding import models as ndab_model
from neutron.db import rbac_db_models
from neutron.db import standard_attr
class IPAllocationPool(model_base.BASEV2, model_base.HasId):
"""Representation of an allocation pool in a Neutron subnet."""
subnet_id = sa.Column(sa.String(36), sa.ForeignKey('subnets.id',
ondelete="CASCADE"),
nullable=True)
first_ip = sa.Column(sa.String(64), nullable=False)
last_ip = sa.Column(sa.String(64), nullable=False)
def __repr__(self):
return "%s - %s" % (self.first_ip, self.last_ip)
class IPAllocation(model_base.BASEV2):
"""Internal representation of allocated IP addresses in a Neutron subnet.
"""
port_id = sa.Column(sa.String(36), sa.ForeignKey('ports.id',
ondelete="CASCADE"),
nullable=True)
ip_address = sa.Column(sa.String(64), nullable=False, primary_key=True)
subnet_id = sa.Column(sa.String(36), sa.ForeignKey('subnets.id',
ondelete="CASCADE"),
nullable=False, primary_key=True)
network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id",
ondelete="CASCADE"),
nullable=False, primary_key=True)
revises_on_change = ('port', )
class Route(object):
"""mixin of a route."""
destination = sa.Column(sa.String(64), nullable=False, primary_key=True)
nexthop = sa.Column(sa.String(64), nullable=False, primary_key=True)
class SubnetRoute(model_base.BASEV2, Route):
subnet_id = sa.Column(sa.String(36),
sa.ForeignKey('subnets.id',
ondelete="CASCADE"),
primary_key=True)
class Port(standard_attr.HasStandardAttributes, model_base.BASEV2,
model_base.HasId, model_base.HasProject):
"""Represents a port on a Neutron v2 network."""
name = sa.Column(sa.String(db_const.NAME_FIELD_SIZE))
network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id"),
nullable=False)
fixed_ips = orm.relationship(IPAllocation,
backref=orm.backref('port',
load_on_pending=True),
lazy='subquery',
cascade='all, delete-orphan',
order_by=(IPAllocation.ip_address,
IPAllocation.subnet_id))
mac_address = sa.Column(sa.String(32), nullable=False)
admin_state_up = sa.Column(sa.Boolean(), nullable=False)
status = sa.Column(sa.String(16), nullable=False)
device_id = sa.Column(sa.String(db_const.DEVICE_ID_FIELD_SIZE),
nullable=False)
device_owner = sa.Column(sa.String(db_const.DEVICE_OWNER_FIELD_SIZE),
nullable=False)
ip_allocation = sa.Column(sa.String(16))
__table_args__ = (
sa.Index(
'ix_ports_network_id_mac_address', 'network_id', 'mac_address'),
sa.Index(
'ix_ports_network_id_device_owner', 'network_id', 'device_owner'),
sa.Index('ix_ports_device_id', 'device_id'),
sa.UniqueConstraint(
network_id, mac_address,
name='uniq_ports0network_id0mac_address'),
model_base.BASEV2.__table_args__
)
api_collections = [port_def.COLLECTION_NAME]
collection_resource_map = {port_def.COLLECTION_NAME:
port_def.RESOURCE_NAME}
tag_support = True
def __init__(self, id=None, tenant_id=None, project_id=None, name=None,
network_id=None, mac_address=None, admin_state_up=None,
status=None, device_id=None, device_owner=None,
fixed_ips=None, **kwargs):
super(Port, self).__init__(**kwargs)
self.id = id
self.project_id = project_id or tenant_id
self.name = name
self.network_id = network_id
self.mac_address = mac_address
self.admin_state_up = admin_state_up
self.device_owner = device_owner
self.device_id = device_id
# Since this is a relationship only set it if one is passed in.
if fixed_ips:
self.fixed_ips = fixed_ips
# NOTE(arosen): status must be set last as an event is triggered on!
self.status = status
class DNSNameServer(model_base.BASEV2):
"""Internal representation of a DNS nameserver."""
address = sa.Column(sa.String(128), nullable=False, primary_key=True)
subnet_id = sa.Column(sa.String(36),
sa.ForeignKey('subnets.id',
ondelete="CASCADE"),
primary_key=True)
order = sa.Column(sa.Integer, nullable=False, server_default='0')
class Subnet(standard_attr.HasStandardAttributes, model_base.BASEV2,
model_base.HasId, model_base.HasProject):
"""Represents a neutron subnet.
When a subnet is created the first and last entries will be created. These
are used for the IP allocation.
"""
name = sa.Column(sa.String(db_const.NAME_FIELD_SIZE))
network_id = sa.Column(sa.String(36), sa.ForeignKey('networks.id'))
# Added by the segments service plugin
segment_id = sa.Column(sa.String(36), sa.ForeignKey('networksegments.id'))
subnetpool_id = sa.Column(sa.String(36), index=True)
# NOTE: Explicitly specify join conditions for the relationship because
# subnetpool_id in subnet might be 'prefix_delegation' when the IPv6 Prefix
# Delegation is enabled
subnetpool = orm.relationship(
'SubnetPool', lazy='joined',
foreign_keys='Subnet.subnetpool_id',
primaryjoin='Subnet.subnetpool_id==SubnetPool.id')
ip_version = sa.Column(sa.Integer, nullable=False)
cidr = sa.Column(sa.String(64), nullable=False)
gateway_ip = sa.Column(sa.String(64))
network_standard_attr = orm.relationship(
'StandardAttribute', lazy='subquery', viewonly=True,
secondary='networks', uselist=False,
load_on_pending=True)
revises_on_change = ('network_standard_attr', )
allocation_pools = orm.relationship(IPAllocationPool,
backref='subnet',
lazy="subquery",
cascade='delete')
enable_dhcp = sa.Column(sa.Boolean())
dns_nameservers = orm.relationship(DNSNameServer,
backref='subnet',
cascade='all, delete, delete-orphan',
order_by=DNSNameServer.order,
lazy='subquery')
routes = orm.relationship(SubnetRoute,
backref='subnet',
cascade='all, delete, delete-orphan',
lazy='subquery')
ipv6_ra_mode = sa.Column(sa.Enum(constants.IPV6_SLAAC,
constants.DHCPV6_STATEFUL,
constants.DHCPV6_STATELESS,
name='ipv6_ra_modes'),
nullable=True)
ipv6_address_mode = sa.Column(sa.Enum(constants.IPV6_SLAAC,
constants.DHCPV6_STATEFUL,
constants.DHCPV6_STATELESS,
name='ipv6_address_modes'),
nullable=True)
# subnets don't have their own rbac_entries, they just inherit from
# the network rbac entries
rbac_entries = orm.relationship(
rbac_db_models.NetworkRBAC, lazy='subquery', uselist=True,
foreign_keys='Subnet.network_id',
primaryjoin='Subnet.network_id==NetworkRBAC.object_id')
api_collections = [subnet_def.COLLECTION_NAME]
collection_resource_map = {subnet_def.COLLECTION_NAME:
subnet_def.RESOURCE_NAME}
tag_support = True
class SubnetPoolPrefix(model_base.BASEV2):
"""Represents a neutron subnet pool prefix
"""
__tablename__ = 'subnetpoolprefixes'
cidr = sa.Column(sa.String(64), nullable=False, primary_key=True)
subnetpool_id = sa.Column(sa.String(36),
sa.ForeignKey('subnetpools.id',
ondelete='CASCADE'),
nullable=False,
primary_key=True)
class SubnetPool(standard_attr.HasStandardAttributes, model_base.BASEV2,
model_base.HasId, model_base.HasProject):
"""Represents a neutron subnet pool.
"""
name = sa.Column(sa.String(db_const.NAME_FIELD_SIZE))
ip_version = sa.Column(sa.Integer, nullable=False)
default_prefixlen = sa.Column(sa.Integer, nullable=False)
min_prefixlen = sa.Column(sa.Integer, nullable=False)
max_prefixlen = sa.Column(sa.Integer, nullable=False)
shared = sa.Column(sa.Boolean, nullable=False)
is_default = sa.Column(sa.Boolean, nullable=False,
server_default=sql.false())
default_quota = sa.Column(sa.Integer, nullable=True)
hash = sa.Column(sa.String(36), nullable=False, server_default='')
address_scope_id = sa.Column(sa.String(36), nullable=True)
prefixes = orm.relationship(SubnetPoolPrefix,
backref='subnetpools',
cascade='all, delete, delete-orphan',
lazy='subquery')
api_collections = [subnetpool_def.COLLECTION_NAME]
collection_resource_map = {subnetpool_def.COLLECTION_NAME:
subnetpool_def.RESOURCE_NAME}
tag_support = True
class Network(standard_attr.HasStandardAttributes, model_base.BASEV2,
model_base.HasId, model_base.HasProject):
"""Represents a v2 neutron network."""
name = sa.Column(sa.String(db_const.NAME_FIELD_SIZE))
subnets = orm.relationship(
Subnet,
lazy="subquery")
status = sa.Column(sa.String(16))
admin_state_up = sa.Column(sa.Boolean)
vlan_transparent = sa.Column(sa.Boolean, nullable=True)
rbac_entries = orm.relationship(rbac_db_models.NetworkRBAC,
backref=orm.backref('network',
load_on_pending=True),
lazy='subquery',
cascade='all, delete, delete-orphan')
availability_zone_hints = sa.Column(sa.String(255))
# TODO(ihrachys) provide data migration path to fill in mtus for existing
# networks in Queens when all controllers run Pike+ code
mtu = sa.Column(sa.Integer, nullable=True)
dhcp_agents = orm.relationship(
'Agent', lazy='subquery', viewonly=True,
secondary=ndab_model.NetworkDhcpAgentBinding.__table__)
api_collections = [net_def.COLLECTION_NAME]
collection_resource_map = {net_def.COLLECTION_NAME: net_def.RESOURCE_NAME}
tag_support = True