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:
gongysh 2013-03-21 14:34:19 +08:00 committed by Gerrit Code Review
parent 8581676fea
commit 73900fd0f4
9 changed files with 363 additions and 47 deletions

View File

@ -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",

View File

@ -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')

View 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])

View File

@ -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},

View File

@ -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):

View File

@ -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):

View File

@ -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))

View File

@ -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

View File

@ -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