add db to save host for port
blueprint portbinding-ex-db related patch in nova: https://review.openstack.org/#/c/21141/ Only OVS and linux bridge plugins now support this feature. Change-Id: I42d9bc59130e2758dd6a221d8953d63ec10e1f3c
This commit is contained in:
parent
8581676fea
commit
73900fd0f4
@ -15,6 +15,12 @@
|
|||||||
|
|
||||||
"extension:port_binding:view": "rule:admin_only",
|
"extension:port_binding:view": "rule:admin_only",
|
||||||
"extension:port_binding:set": "rule:admin_only",
|
"extension:port_binding:set": "rule:admin_only",
|
||||||
|
"get_port:binding:host_id": "rule:admin_only",
|
||||||
|
"get_port:binding:vif_type": "rule:admin_only",
|
||||||
|
"get_port:binding:profile": "rule:admin_only",
|
||||||
|
"get_port:binding:capabilities": "rule:admin_only",
|
||||||
|
"create_port:binding:host_id": "rule:admin_only",
|
||||||
|
"update_port:binding:host_id": "rule:admin_only",
|
||||||
|
|
||||||
"subnets:private:read": "rule:admin_or_owner",
|
"subnets:private:read": "rule:admin_or_owner",
|
||||||
"subnets:private:write": "rule:admin_or_owner",
|
"subnets:private:write": "rule:admin_or_owner",
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright 2013 OpenStack Foundation
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""Add portbindings db
|
||||||
|
|
||||||
|
Revision ID: 176a85fc7d79
|
||||||
|
Revises: grizzly
|
||||||
|
Create Date: 2013-03-21 14:59:53.052600
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '176a85fc7d79'
|
||||||
|
down_revision = 'grizzly'
|
||||||
|
|
||||||
|
# Change to ['*'] if this migration applies to all plugins
|
||||||
|
|
||||||
|
migration_for_plugins = [
|
||||||
|
'quantum.plugins.openvswitch.ovs_quantum_plugin.OVSQuantumPluginV2',
|
||||||
|
'quantum.plugins.linuxbridge.lb_quantum_plugin.LinuxBridgePluginV2',
|
||||||
|
]
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
from quantum.db import migration
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(active_plugin=None, options=None):
|
||||||
|
if not migration.should_run(active_plugin, migration_for_plugins):
|
||||||
|
return
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
'portbindingports',
|
||||||
|
sa.Column('port_id', sa.String(length=36), nullable=False),
|
||||||
|
sa.Column('host', sa.String(length=255), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['port_id'], ['ports.id'], ondelete='CASCADE'),
|
||||||
|
sa.PrimaryKeyConstraint('port_id')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(active_plugin=None, options=None):
|
||||||
|
if not migration.should_run(active_plugin, migration_for_plugins):
|
||||||
|
return
|
||||||
|
op.drop_table('portbindingports')
|
124
quantum/db/portbindings_db.py
Normal file
124
quantum/db/portbindings_db.py
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2013 IBM Corp.
|
||||||
|
# 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.
|
||||||
|
# @author: Yong Sheng Gong, IBM, Corp.
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy import orm
|
||||||
|
|
||||||
|
from quantum.api.v2 import attributes
|
||||||
|
from quantum.db import db_base_plugin_v2
|
||||||
|
from quantum.db import model_base
|
||||||
|
from quantum.db import models_v2
|
||||||
|
from quantum.extensions import portbindings
|
||||||
|
from quantum.openstack.common import log as logging
|
||||||
|
from quantum import policy
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class PortBindingPort(model_base.BASEV2):
|
||||||
|
port_id = sa.Column(sa.String(36),
|
||||||
|
sa.ForeignKey('ports.id', ondelete="CASCADE"),
|
||||||
|
primary_key=True)
|
||||||
|
host = sa.Column(sa.String(255), nullable=False)
|
||||||
|
port = orm.relationship(
|
||||||
|
models_v2.Port,
|
||||||
|
backref=orm.backref("portbinding",
|
||||||
|
lazy='joined', uselist=False,
|
||||||
|
cascade='delete'))
|
||||||
|
|
||||||
|
|
||||||
|
class PortBindingMixin(object):
|
||||||
|
extra_binding_dict = None
|
||||||
|
|
||||||
|
def _port_model_hook(self, context, original_model, query):
|
||||||
|
query = query.outerjoin(PortBindingPort,
|
||||||
|
(original_model.id ==
|
||||||
|
PortBindingPort.port_id))
|
||||||
|
return query
|
||||||
|
|
||||||
|
def _port_result_filter_hook(self, query, filters):
|
||||||
|
values = filters and filters.get(portbindings.HOST_ID, [])
|
||||||
|
if not values:
|
||||||
|
return query
|
||||||
|
if len(values) == 1:
|
||||||
|
query = query.filter(PortBindingPort.host == values[0])
|
||||||
|
else:
|
||||||
|
query = query.filter(PortBindingPort.host.in_(values))
|
||||||
|
return query
|
||||||
|
|
||||||
|
db_base_plugin_v2.QuantumDbPluginV2.register_model_query_hook(
|
||||||
|
models_v2.Port,
|
||||||
|
"portbindings_port",
|
||||||
|
_port_model_hook,
|
||||||
|
None,
|
||||||
|
_port_result_filter_hook)
|
||||||
|
|
||||||
|
def _check_portbindings_view_auth(self, context, port):
|
||||||
|
#TODO(salv-orlando): Remove this as part of bp/make-authz-orthogonal
|
||||||
|
keys_to_delete = []
|
||||||
|
for key in port:
|
||||||
|
if key.startswith('binding'):
|
||||||
|
policy_rule = "get_port:%s" % key
|
||||||
|
if not policy.check(context, policy_rule, port):
|
||||||
|
keys_to_delete.append(key)
|
||||||
|
for key in keys_to_delete:
|
||||||
|
del port[key]
|
||||||
|
return port
|
||||||
|
|
||||||
|
def _process_portbindings_create_and_update(self, context, port_data,
|
||||||
|
port):
|
||||||
|
host = port_data.get(portbindings.HOST_ID)
|
||||||
|
host_set = attributes.is_attr_set(host)
|
||||||
|
if not host_set:
|
||||||
|
_extend_port_dict_binding_host(self, port, None)
|
||||||
|
return
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
bind_port = context.session.query(
|
||||||
|
PortBindingPort).filter_by(port_id=port['id']).first()
|
||||||
|
if not bind_port:
|
||||||
|
context.session.add(PortBindingPort(port_id=port['id'],
|
||||||
|
host=host))
|
||||||
|
else:
|
||||||
|
bind_port.host = host
|
||||||
|
_extend_port_dict_binding_host(self, port, host)
|
||||||
|
|
||||||
|
def get_port_host(self, context, port_id):
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
bind_port = context.session.query(
|
||||||
|
PortBindingPort).filter_by(port_id=port_id).first()
|
||||||
|
return bind_port and bind_port.host or None
|
||||||
|
|
||||||
|
|
||||||
|
def _extend_port_dict_binding_host(plugin, port_res, host):
|
||||||
|
port_res[portbindings.HOST_ID] = host
|
||||||
|
if plugin.extra_binding_dict:
|
||||||
|
port_res.update(plugin.extra_binding_dict)
|
||||||
|
return port_res
|
||||||
|
|
||||||
|
|
||||||
|
def _extend_port_dict_binding(plugin, port_res, port_db):
|
||||||
|
if not isinstance(plugin, PortBindingMixin):
|
||||||
|
return
|
||||||
|
host = (port_db.portbinding and port_db.portbinding.host or None)
|
||||||
|
return _extend_port_dict_binding_host(
|
||||||
|
plugin, port_res, host)
|
||||||
|
|
||||||
|
# Register dict extend functions for ports
|
||||||
|
db_base_plugin_v2.QuantumDbPluginV2.register_dict_extend_funcs(
|
||||||
|
attributes.PORTS, [_extend_port_dict_binding])
|
@ -49,7 +49,8 @@ EXTENDED_ATTRIBUTES_2_0 = {
|
|||||||
'is_visible': True},
|
'is_visible': True},
|
||||||
HOST_ID: {'allow_post': True, 'allow_put': True,
|
HOST_ID: {'allow_post': True, 'allow_put': True,
|
||||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
'default': attributes.ATTR_NOT_SPECIFIED,
|
||||||
'is_visible': True},
|
'is_visible': True,
|
||||||
|
'enforce_policy': True},
|
||||||
PROFILE: {'allow_post': True, 'allow_put': True,
|
PROFILE: {'allow_post': True, 'allow_put': True,
|
||||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
'default': attributes.ATTR_NOT_SPECIFIED,
|
||||||
'validate': {'type:dict': None},
|
'validate': {'type:dict': None},
|
||||||
|
@ -32,6 +32,7 @@ from quantum.db import db_base_plugin_v2
|
|||||||
from quantum.db import dhcp_rpc_base
|
from quantum.db import dhcp_rpc_base
|
||||||
from quantum.db import extraroute_db
|
from quantum.db import extraroute_db
|
||||||
from quantum.db import l3_rpc_base
|
from quantum.db import l3_rpc_base
|
||||||
|
from quantum.db import portbindings_db
|
||||||
from quantum.db import quota_db # noqa
|
from quantum.db import quota_db # noqa
|
||||||
from quantum.db import securitygroups_rpc_base as sg_db_rpc
|
from quantum.db import securitygroups_rpc_base as sg_db_rpc
|
||||||
from quantum.extensions import portbindings
|
from quantum.extensions import portbindings
|
||||||
@ -176,7 +177,8 @@ class AgentNotifierApi(proxy.RpcProxy,
|
|||||||
class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||||
extraroute_db.ExtraRoute_db_mixin,
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
sg_db_rpc.SecurityGroupServerRpcMixin,
|
sg_db_rpc.SecurityGroupServerRpcMixin,
|
||||||
agentschedulers_db.AgentSchedulerDbMixin):
|
agentschedulers_db.AgentSchedulerDbMixin,
|
||||||
|
portbindings_db.PortBindingMixin):
|
||||||
"""Implement the Quantum abstractions using Linux bridging.
|
"""Implement the Quantum abstractions using Linux bridging.
|
||||||
|
|
||||||
A new VLAN is created for each network. An agent is relied upon
|
A new VLAN is created for each network. An agent is relied upon
|
||||||
@ -214,10 +216,13 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
|
|
||||||
network_view = "extension:provider_network:view"
|
network_view = "extension:provider_network:view"
|
||||||
network_set = "extension:provider_network:set"
|
network_set = "extension:provider_network:set"
|
||||||
binding_view = "extension:port_binding:view"
|
|
||||||
binding_set = "extension:port_binding:set"
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self.extra_binding_dict = {
|
||||||
|
portbindings.VIF_TYPE: portbindings.VIF_TYPE_BRIDGE,
|
||||||
|
portbindings.CAPABILITIES: {
|
||||||
|
portbindings.CAP_PORT_FILTER:
|
||||||
|
'security-group' in self.supported_extension_aliases}}
|
||||||
db.initialize()
|
db.initialize()
|
||||||
self._parse_network_vlan_ranges()
|
self._parse_network_vlan_ranges()
|
||||||
db.sync_network_states(self.network_vlan_ranges)
|
db.sync_network_states(self.network_vlan_ranges)
|
||||||
@ -441,21 +446,12 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
|
|
||||||
return [self._fields(net, fields) for net in nets]
|
return [self._fields(net, fields) for net in nets]
|
||||||
|
|
||||||
def _extend_port_dict_binding(self, context, port):
|
|
||||||
if self._check_view_auth(context, port, self.binding_view):
|
|
||||||
port[portbindings.VIF_TYPE] = portbindings.VIF_TYPE_BRIDGE
|
|
||||||
port[portbindings.CAPABILITIES] = {
|
|
||||||
portbindings.CAP_PORT_FILTER:
|
|
||||||
'security-group' in self.supported_extension_aliases}
|
|
||||||
return port
|
|
||||||
|
|
||||||
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(LinuxBridgePluginV2, self).get_port(context,
|
port = super(LinuxBridgePluginV2, self).get_port(context,
|
||||||
id,
|
id,
|
||||||
fields)
|
fields)
|
||||||
self._extend_port_dict_binding(context, port),
|
return self._check_portbindings_view_auth(context, port)
|
||||||
return self._fields(port, fields)
|
|
||||||
|
|
||||||
def get_ports(self, context, filters=None, fields=None,
|
def get_ports(self, context, filters=None, fields=None,
|
||||||
sorts=None, limit=None, marker=None, page_reverse=False):
|
sorts=None, limit=None, marker=None, page_reverse=False):
|
||||||
@ -464,14 +460,14 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
ports = super(LinuxBridgePluginV2,
|
ports = super(LinuxBridgePluginV2,
|
||||||
self).get_ports(context, filters, fields, sorts,
|
self).get_ports(context, filters, fields, sorts,
|
||||||
limit, marker, page_reverse)
|
limit, marker, page_reverse)
|
||||||
#TODO(nati) filter by security group
|
|
||||||
for port in ports:
|
for port in ports:
|
||||||
self._extend_port_dict_binding(context, port)
|
self._check_portbindings_view_auth(context, port)
|
||||||
res_ports.append(self._fields(port, fields))
|
res_ports.append(port)
|
||||||
return res_ports
|
return res_ports
|
||||||
|
|
||||||
def create_port(self, context, port):
|
def create_port(self, context, port):
|
||||||
session = context.session
|
session = context.session
|
||||||
|
port_data = port['port']
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
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)
|
||||||
@ -480,10 +476,13 @@ 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_portbindings_create_and_update(context,
|
||||||
|
port_data,
|
||||||
|
port)
|
||||||
self._process_port_create_security_group(
|
self._process_port_create_security_group(
|
||||||
context, port, sgids)
|
context, port, sgids)
|
||||||
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._check_portbindings_view_auth(context, port)
|
||||||
|
|
||||||
def update_port(self, context, id, port):
|
def update_port(self, context, id, port):
|
||||||
original_port = self.get_port(context, id)
|
original_port = self.get_port(context, id)
|
||||||
@ -493,6 +492,9 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
updated_port = super(LinuxBridgePluginV2, self).update_port(
|
updated_port = super(LinuxBridgePluginV2, self).update_port(
|
||||||
context, id, port)
|
context, id, port)
|
||||||
|
self._process_portbindings_create_and_update(context,
|
||||||
|
port['port'],
|
||||||
|
updated_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)
|
||||||
|
|
||||||
@ -504,7 +506,7 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
|
|
||||||
if need_port_update_notify:
|
if need_port_update_notify:
|
||||||
self._notify_port_updated(context, updated_port)
|
self._notify_port_updated(context, updated_port)
|
||||||
return self._extend_port_dict_binding(context, updated_port)
|
return self._check_portbindings_view_auth(context, updated_port)
|
||||||
|
|
||||||
def delete_port(self, context, id, l3_port_check=True):
|
def delete_port(self, context, id, l3_port_check=True):
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ from quantum.db import db_base_plugin_v2
|
|||||||
from quantum.db import dhcp_rpc_base
|
from quantum.db import dhcp_rpc_base
|
||||||
from quantum.db import extraroute_db
|
from quantum.db import extraroute_db
|
||||||
from quantum.db import l3_rpc_base
|
from quantum.db import l3_rpc_base
|
||||||
|
from quantum.db import portbindings_db
|
||||||
from quantum.db import quota_db # noqa
|
from quantum.db import quota_db # noqa
|
||||||
from quantum.db import securitygroups_rpc_base as sg_db_rpc
|
from quantum.db import securitygroups_rpc_base as sg_db_rpc
|
||||||
from quantum.extensions import portbindings
|
from quantum.extensions import portbindings
|
||||||
@ -214,7 +215,8 @@ class AgentNotifierApi(proxy.RpcProxy,
|
|||||||
class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
||||||
extraroute_db.ExtraRoute_db_mixin,
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
sg_db_rpc.SecurityGroupServerRpcMixin,
|
sg_db_rpc.SecurityGroupServerRpcMixin,
|
||||||
agentschedulers_db.AgentSchedulerDbMixin):
|
agentschedulers_db.AgentSchedulerDbMixin,
|
||||||
|
portbindings_db.PortBindingMixin):
|
||||||
|
|
||||||
"""Implement the Quantum abstractions using Open vSwitch.
|
"""Implement the Quantum abstractions using Open vSwitch.
|
||||||
|
|
||||||
@ -254,10 +256,13 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
|
|
||||||
network_view = "extension:provider_network:view"
|
network_view = "extension:provider_network:view"
|
||||||
network_set = "extension:provider_network:set"
|
network_set = "extension:provider_network:set"
|
||||||
binding_view = "extension:port_binding:view"
|
|
||||||
binding_set = "extension:port_binding:set"
|
|
||||||
|
|
||||||
def __init__(self, configfile=None):
|
def __init__(self, configfile=None):
|
||||||
|
self.extra_binding_dict = {
|
||||||
|
portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS,
|
||||||
|
portbindings.CAPABILITIES: {
|
||||||
|
portbindings.CAP_PORT_FILTER:
|
||||||
|
'security-group' in self.supported_extension_aliases}}
|
||||||
ovs_db_v2.initialize()
|
ovs_db_v2.initialize()
|
||||||
self._parse_network_vlan_ranges()
|
self._parse_network_vlan_ranges()
|
||||||
ovs_db_v2.sync_vlan_allocations(self.network_vlan_ranges)
|
ovs_db_v2.sync_vlan_allocations(self.network_vlan_ranges)
|
||||||
@ -530,44 +535,39 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
|
|||||||
|
|
||||||
return [self._fields(net, fields) for net in nets]
|
return [self._fields(net, fields) for net in nets]
|
||||||
|
|
||||||
def _extend_port_dict_binding(self, context, port):
|
|
||||||
if self._check_view_auth(context, port, self.binding_view):
|
|
||||||
port[portbindings.VIF_TYPE] = portbindings.VIF_TYPE_OVS
|
|
||||||
port[portbindings.CAPABILITIES] = {
|
|
||||||
portbindings.CAP_PORT_FILTER:
|
|
||||||
'security-group' in self.supported_extension_aliases}
|
|
||||||
return port
|
|
||||||
|
|
||||||
def create_port(self, context, port):
|
def create_port(self, context, port):
|
||||||
# Set port status as 'DOWN'. This will be updated by agent
|
# Set port status as 'DOWN'. This will be updated by agent
|
||||||
port['port']['status'] = q_const.PORT_STATUS_DOWN
|
port['port']['status'] = q_const.PORT_STATUS_DOWN
|
||||||
|
port_data = port['port']
|
||||||
session = context.session
|
session = context.session
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
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_portbindings_create_and_update(context,
|
||||||
|
port_data, port)
|
||||||
self._process_port_create_security_group(context, port, sgids)
|
self._process_port_create_security_group(context, port, sgids)
|
||||||
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._check_portbindings_view_auth(context, port)
|
||||||
|
|
||||||
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(OVSQuantumPluginV2, self).get_port(context,
|
port = super(OVSQuantumPluginV2, self).get_port(context,
|
||||||
id, fields)
|
id,
|
||||||
self._extend_port_dict_binding(context, port)
|
fields)
|
||||||
return self._fields(port, fields)
|
return self._check_portbindings_view_auth(context, port)
|
||||||
|
|
||||||
def get_ports(self, context, filters=None, fields=None,
|
def get_ports(self, context, filters=None, fields=None,
|
||||||
sorts=None, limit=None, marker=None,
|
sorts=None, limit=None, marker=None, page_reverse=False):
|
||||||
page_reverse=False):
|
res_ports = []
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
ports = super(OVSQuantumPluginV2, self).get_ports(
|
ports = super(OVSQuantumPluginV2,
|
||||||
context, filters, fields, sorts, limit, marker,
|
self).get_ports(context, filters, fields, sorts,
|
||||||
page_reverse)
|
limit, marker, page_reverse)
|
||||||
#TODO(nati) filter by security group
|
|
||||||
for port in ports:
|
for port in ports:
|
||||||
self._extend_port_dict_binding(context, port)
|
self._check_portbindings_view_auth(context, port)
|
||||||
return [self._fields(port, fields) for port in ports]
|
res_ports.append(port)
|
||||||
|
return res_ports
|
||||||
|
|
||||||
def update_port(self, context, id, port):
|
def update_port(self, context, id, port):
|
||||||
session = context.session
|
session = context.session
|
||||||
@ -579,6 +579,9 @@ 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)
|
||||||
|
self._process_portbindings_create_and_update(context,
|
||||||
|
port['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']:
|
||||||
@ -591,7 +594,7 @@ 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._check_portbindings_view_auth(context, updated_port)
|
||||||
|
|
||||||
def delete_port(self, context, id, l3_port_check=True):
|
def delete_port(self, context, id, l3_port_check=True):
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
import contextlib
|
import contextlib
|
||||||
|
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
|
from webob import exc
|
||||||
|
|
||||||
from quantum import context
|
from quantum import context
|
||||||
from quantum.extensions import portbindings
|
from quantum.extensions import portbindings
|
||||||
@ -48,21 +49,21 @@ class PortBindingsTestCase(test_db_plugin.QuantumDbPluginV2TestCase):
|
|||||||
self.assertFalse(portbindings.CAPABILITIES in port)
|
self.assertFalse(portbindings.CAPABILITIES in port)
|
||||||
|
|
||||||
def test_port_vif_details(self):
|
def test_port_vif_details(self):
|
||||||
plugin = QuantumManager.get_plugin()
|
|
||||||
with self.port(name='name') as port:
|
with self.port(name='name') as port:
|
||||||
port_id = port['port']['id']
|
port_id = port['port']['id']
|
||||||
# Check a response of create_port
|
# Check a response of create_port
|
||||||
self._check_response_portbindings(port['port'])
|
self._check_response_portbindings(port['port'])
|
||||||
# Check a response of get_port
|
# Check a response of get_port
|
||||||
ctx = context.get_admin_context()
|
ctx = context.get_admin_context()
|
||||||
port = plugin.get_port(ctx, port_id)
|
port = self._show('ports', port_id, quantum_context=ctx)['port']
|
||||||
self._check_response_portbindings(port)
|
self._check_response_portbindings(port)
|
||||||
# By default user is admin - now test non admin user
|
# By default user is admin - now test non admin user
|
||||||
ctx = context.Context(user_id=None,
|
ctx = context.Context(user_id=None,
|
||||||
tenant_id=self._tenant_id,
|
tenant_id=self._tenant_id,
|
||||||
is_admin=False,
|
is_admin=False,
|
||||||
read_deleted="no")
|
read_deleted="no")
|
||||||
non_admin_port = plugin.get_port(ctx, port_id)
|
non_admin_port = self._show(
|
||||||
|
'ports', port_id, quantum_context=ctx)['port']
|
||||||
self._check_response_no_portbindings(non_admin_port)
|
self._check_response_no_portbindings(non_admin_port)
|
||||||
|
|
||||||
def test_ports_vif_details(self):
|
def test_ports_vif_details(self):
|
||||||
@ -79,7 +80,115 @@ class PortBindingsTestCase(test_db_plugin.QuantumDbPluginV2TestCase):
|
|||||||
tenant_id=self._tenant_id,
|
tenant_id=self._tenant_id,
|
||||||
is_admin=False,
|
is_admin=False,
|
||||||
read_deleted="no")
|
read_deleted="no")
|
||||||
ports = plugin.get_ports(ctx)
|
ports = self._list('ports', quantum_context=ctx)['ports']
|
||||||
self.assertEqual(len(ports), 2)
|
self.assertEqual(len(ports), 2)
|
||||||
for non_admin_port in ports:
|
for non_admin_port in ports:
|
||||||
self._check_response_no_portbindings(non_admin_port)
|
self._check_response_no_portbindings(non_admin_port)
|
||||||
|
|
||||||
|
|
||||||
|
class PortBindingsHostTestCaseMixin(object):
|
||||||
|
fmt = 'json'
|
||||||
|
hostname = 'testhost'
|
||||||
|
|
||||||
|
def _check_response_portbindings_host(self, port):
|
||||||
|
self.assertEqual(port[portbindings.HOST_ID], self.hostname)
|
||||||
|
|
||||||
|
def _check_response_no_portbindings_host(self, port):
|
||||||
|
self.assertIn('status', port)
|
||||||
|
self.assertNotIn(portbindings.HOST_ID, port)
|
||||||
|
|
||||||
|
def test_port_vif_non_admin(self):
|
||||||
|
with self.network(set_context=True,
|
||||||
|
tenant_id='test') as net1:
|
||||||
|
with self.subnet(network=net1) as subnet1:
|
||||||
|
host_arg = {portbindings.HOST_ID: self.hostname}
|
||||||
|
try:
|
||||||
|
with self.port(subnet=subnet1,
|
||||||
|
expected_res_status=403,
|
||||||
|
arg_list=(portbindings.HOST_ID,),
|
||||||
|
set_context=True,
|
||||||
|
tenant_id='test',
|
||||||
|
**host_arg):
|
||||||
|
pass
|
||||||
|
except exc.HTTPClientError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_port_vif_host(self):
|
||||||
|
host_arg = {portbindings.HOST_ID: self.hostname}
|
||||||
|
with self.port(name='name', arg_list=(portbindings.HOST_ID,),
|
||||||
|
**host_arg) as port:
|
||||||
|
port_id = port['port']['id']
|
||||||
|
# Check a response of create_port
|
||||||
|
self._check_response_portbindings_host(port['port'])
|
||||||
|
# Check a response of get_port
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
port = self._show('ports', port_id, quantum_context=ctx)['port']
|
||||||
|
self._check_response_portbindings_host(port)
|
||||||
|
# By default user is admin - now test non admin user
|
||||||
|
ctx = context.Context(user_id=None,
|
||||||
|
tenant_id=self._tenant_id,
|
||||||
|
is_admin=False,
|
||||||
|
read_deleted="no")
|
||||||
|
non_admin_port = self._show(
|
||||||
|
'ports', port_id, quantum_context=ctx)['port']
|
||||||
|
self._check_response_no_portbindings_host(non_admin_port)
|
||||||
|
|
||||||
|
def test_ports_vif_host(self):
|
||||||
|
cfg.CONF.set_default('allow_overlapping_ips', True)
|
||||||
|
host_arg = {portbindings.HOST_ID: self.hostname}
|
||||||
|
with contextlib.nested(
|
||||||
|
self.port(name='name1',
|
||||||
|
arg_list=(portbindings.HOST_ID,),
|
||||||
|
**host_arg),
|
||||||
|
self.port(name='name2')):
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
ports = self._list('ports', quantum_context=ctx)['ports']
|
||||||
|
self.assertEqual(2, len(ports))
|
||||||
|
for port in ports:
|
||||||
|
if port['name'] == 'name1':
|
||||||
|
self._check_response_portbindings_host(port)
|
||||||
|
else:
|
||||||
|
self.assertFalse(port[portbindings.HOST_ID])
|
||||||
|
# By default user is admin - now test non admin user
|
||||||
|
ctx = context.Context(user_id=None,
|
||||||
|
tenant_id=self._tenant_id,
|
||||||
|
is_admin=False,
|
||||||
|
read_deleted="no")
|
||||||
|
ports = self._list('ports', quantum_context=ctx)['ports']
|
||||||
|
self.assertEqual(2, len(ports))
|
||||||
|
for non_admin_port in ports:
|
||||||
|
self._check_response_no_portbindings_host(non_admin_port)
|
||||||
|
|
||||||
|
def test_ports_vif_host_update(self):
|
||||||
|
cfg.CONF.set_default('allow_overlapping_ips', True)
|
||||||
|
host_arg = {portbindings.HOST_ID: self.hostname}
|
||||||
|
with contextlib.nested(
|
||||||
|
self.port(name='name1',
|
||||||
|
arg_list=(portbindings.HOST_ID,),
|
||||||
|
**host_arg),
|
||||||
|
self.port(name='name2')) as (port1, port2):
|
||||||
|
data = {'port': {portbindings.HOST_ID: 'testhosttemp'}}
|
||||||
|
req = self.new_update_request('ports', data, port1['port']['id'])
|
||||||
|
req.get_response(self.api)
|
||||||
|
req = self.new_update_request('ports', data, port2['port']['id'])
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
req.get_response(self.api)
|
||||||
|
ports = self._list('ports', quantum_context=ctx)['ports']
|
||||||
|
self.assertEqual(2, len(ports))
|
||||||
|
for port in ports:
|
||||||
|
self.assertEqual('testhosttemp', port[portbindings.HOST_ID])
|
||||||
|
|
||||||
|
def test_ports_vif_host_list(self):
|
||||||
|
cfg.CONF.set_default('allow_overlapping_ips', True)
|
||||||
|
host_arg = {portbindings.HOST_ID: self.hostname}
|
||||||
|
with contextlib.nested(
|
||||||
|
self.port(name='name1',
|
||||||
|
arg_list=(portbindings.HOST_ID,),
|
||||||
|
**host_arg),
|
||||||
|
self.port(name='name2'),
|
||||||
|
self.port(name='name3',
|
||||||
|
arg_list=(portbindings.HOST_ID,),
|
||||||
|
**host_arg),) as (port1, _port2, port3):
|
||||||
|
self._test_list_resources(
|
||||||
|
'port', (port1, port3),
|
||||||
|
query_params='%s=%s' % (portbindings.HOST_ID, self.hostname))
|
||||||
|
@ -69,3 +69,9 @@ class TestLinuxBridgePortBinding(LinuxBridgePluginV2TestCase,
|
|||||||
class TestLinuxBridgePortBindingNoSG(TestLinuxBridgePortBinding):
|
class TestLinuxBridgePortBindingNoSG(TestLinuxBridgePortBinding):
|
||||||
HAS_PORT_FILTER = False
|
HAS_PORT_FILTER = False
|
||||||
FIREWALL_DRIVER = test_sg_rpc.FIREWALL_NOOP_DRIVER
|
FIREWALL_DRIVER = test_sg_rpc.FIREWALL_NOOP_DRIVER
|
||||||
|
|
||||||
|
|
||||||
|
class TestOpenvswitchPortBindingHost(
|
||||||
|
LinuxBridgePluginV2TestCase,
|
||||||
|
test_bindings.PortBindingsHostTestCaseMixin):
|
||||||
|
pass
|
||||||
|
@ -67,3 +67,9 @@ class TestOpenvswitchPortBinding(OpenvswitchPluginV2TestCase,
|
|||||||
class TestOpenvswitchPortBindingNoSG(TestOpenvswitchPortBinding):
|
class TestOpenvswitchPortBindingNoSG(TestOpenvswitchPortBinding):
|
||||||
HAS_PORT_FILTER = False
|
HAS_PORT_FILTER = False
|
||||||
FIREWALL_DRIVER = test_sg_rpc.FIREWALL_NOOP_DRIVER
|
FIREWALL_DRIVER = test_sg_rpc.FIREWALL_NOOP_DRIVER
|
||||||
|
|
||||||
|
|
||||||
|
class TestOpenvswitchPortBindingHost(
|
||||||
|
OpenvswitchPluginV2TestCase,
|
||||||
|
test_bindings.PortBindingsHostTestCaseMixin):
|
||||||
|
pass
|
||||||
|
Loading…
Reference in New Issue
Block a user