Add neutron driver for binding
Add new neutron plugin which enables port bind actions for network fabrics. This driver waits until all ports are in state "active" and sets the binding host flag. Default vNIC type is set to "baremetal" in order to benefit from the code already in place for Ironic. It's also possible to switch to 'normal' which assumes an neutron agent in place. The feature can be tested using the docker driver. DocImpact Co-Authored-By: Daniel Gonzalez <daniel@gonzalez-nothnagel.de> Partially-Implements: bp manila-hpb-support Change-Id: I3156d7468d48f84f1b46885780a2426f9b99a387
This commit is contained in:
parent
bb767e8ece
commit
78e10bc060
@ -75,6 +75,12 @@ function configure_default_backends {
|
|||||||
iniset $MANILA_CONF $group_name service_instance_user $MANILA_SERVICE_INSTANCE_USER
|
iniset $MANILA_CONF $group_name service_instance_user $MANILA_SERVICE_INSTANCE_USER
|
||||||
iniset $MANILA_CONF $group_name driver_handles_share_servers True
|
iniset $MANILA_CONF $group_name driver_handles_share_servers True
|
||||||
|
|
||||||
|
if [ "$SHARE_DRIVER" == $MANILA_CONTAINER_DRIVER ]; then
|
||||||
|
iniset $MANILA_CONF $group_name network_api_class $MANILA_NETWORK_API_CLASS
|
||||||
|
iniset $MANILA_CONF $group_name neutron_host_id $(hostname)
|
||||||
|
iniset $MANILA_CONF $group_name neutron_vnic_type $MANILA_NEUTRON_VNIC_TYPE
|
||||||
|
fi
|
||||||
|
|
||||||
if [ $(trueorfalse False MANILA_USE_SERVICE_INSTANCE_PASSWORD) == True ]; then
|
if [ $(trueorfalse False MANILA_USE_SERVICE_INSTANCE_PASSWORD) == True ]; then
|
||||||
iniset $MANILA_CONF $group_name service_instance_password $MANILA_SERVICE_INSTANCE_PASSWORD
|
iniset $MANILA_CONF $group_name service_instance_password $MANILA_SERVICE_INSTANCE_PASSWORD
|
||||||
fi
|
fi
|
||||||
@ -522,7 +528,6 @@ function init_manila {
|
|||||||
elif [ "$SHARE_DRIVER" == $MANILA_CONTAINER_DRIVER ]; then
|
elif [ "$SHARE_DRIVER" == $MANILA_CONTAINER_DRIVER ]; then
|
||||||
if is_service_enabled m-shr; then
|
if is_service_enabled m-shr; then
|
||||||
SHARE_GROUP=$MANILA_CONTAINER_VOLUME_GROUP_NAME
|
SHARE_GROUP=$MANILA_CONTAINER_VOLUME_GROUP_NAME
|
||||||
iniset $MANILA_CONF DEFAULT neutron_host_id $(hostname)
|
|
||||||
configure_backing_file
|
configure_backing_file
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -166,6 +166,10 @@ MANILA_CONTAINER_VOLUME_GROUP_NAME=${MANILA_CONTAINER_VOLUME_GROUP_NAME:-"manila
|
|||||||
# permanent one as soon as possible.
|
# permanent one as soon as possible.
|
||||||
MANILA_DOCKER_IMAGE_URL=${MANILA_DOCKER_IMAGE_URL:-"https://github.com/a-ovchinnikov/manila-image-elements-lxd-images/releases/download/0.1.0/manila-docker-container.tar.gz"}
|
MANILA_DOCKER_IMAGE_URL=${MANILA_DOCKER_IMAGE_URL:-"https://github.com/a-ovchinnikov/manila-image-elements-lxd-images/releases/download/0.1.0/manila-docker-container.tar.gz"}
|
||||||
|
|
||||||
|
# Network Plugin
|
||||||
|
MANILA_NETWORK_API_CLASS=${MANILA_NETWORK_API_CLASS:-"manila.network.neutron.neutron_network_plugin.NeutronBindNetworkPlugin"}
|
||||||
|
MANILA_NEUTRON_VNIC_TYPE=${MANILA_NEUTRON_VNIC_TYPE:-"normal"}
|
||||||
|
|
||||||
# Enable manila services
|
# Enable manila services
|
||||||
# ----------------------
|
# ----------------------
|
||||||
# We have to add Manila to enabled services for screen_it to work
|
# We have to add Manila to enabled services for screen_it to work
|
||||||
|
@ -77,6 +77,13 @@ There are three different network plugins and five python classes in Manila:
|
|||||||
`neutron_net_id` and `neutron_subnet_id` from the Manila configuration
|
`neutron_net_id` and `neutron_subnet_id` from the Manila configuration
|
||||||
file and uses one network for all shares.
|
file and uses one network for all shares.
|
||||||
|
|
||||||
|
1.3 `manila.network.neutron.neutron_network_plugin.NeutronBindNetworkPlugin`.
|
||||||
|
This driver waits for active binding and fails if a Neutron port can't be
|
||||||
|
bound or an error occurs. This plugin is useful for agent based binding
|
||||||
|
(like OVS with docker driver) and fabric binding where real HW
|
||||||
|
reconfiguration is taking place. The existing
|
||||||
|
`NeutronBindSingleNetworkPlugin` is a combination of 1.2 and 1.3.
|
||||||
|
|
||||||
When only a single network is needed, the NeutronSingleNetworkPlugin (1.2)
|
When only a single network is needed, the NeutronSingleNetworkPlugin (1.2)
|
||||||
is a simple solution. Otherwise NeutronNetworkPlugin (1.1) should be chosen.
|
is a simple solution. Otherwise NeutronNetworkPlugin (1.1) should be chosen.
|
||||||
|
|
||||||
|
@ -114,6 +114,10 @@ class NetworkException(ManilaException):
|
|||||||
message = _("Exception due to network failure.")
|
message = _("Exception due to network failure.")
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkBindException(ManilaException):
|
||||||
|
message = _("Exception due to failed port status in binding.")
|
||||||
|
|
||||||
|
|
||||||
class NetworkBadConfigurationException(NetworkException):
|
class NetworkBadConfigurationException(NetworkException):
|
||||||
message = _("Bad network configuration: %(reason)s.")
|
message = _("Bad network configuration: %(reason)s.")
|
||||||
|
|
||||||
|
@ -65,6 +65,17 @@ class NetworkBaseAPI(db_base.Base):
|
|||||||
"'%s'.") % share_server_id
|
"'%s'.") % share_server_id
|
||||||
raise exception.NetworkBadConfigurationException(reason=msg)
|
raise exception.NetworkBadConfigurationException(reason=msg)
|
||||||
|
|
||||||
|
def update_network_allocation(self, context, share_server):
|
||||||
|
"""Update network allocation.
|
||||||
|
|
||||||
|
Optional method to be called by the manager after share server creation
|
||||||
|
which can be overloaded in case the port state has to be updated.
|
||||||
|
|
||||||
|
:param context: RequestContext object
|
||||||
|
:param share_server: share server object
|
||||||
|
:return: list of updated ports or None if nothing was updated
|
||||||
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def allocate_network(self, context, share_server, share_network=None,
|
def allocate_network(self, context, share_server, share_network=None,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
|
@ -164,7 +164,8 @@ class API(object):
|
|||||||
|
|
||||||
def create_port(self, tenant_id, network_id, host_id=None, subnet_id=None,
|
def create_port(self, tenant_id, network_id, host_id=None, subnet_id=None,
|
||||||
fixed_ip=None, device_owner=None, device_id=None,
|
fixed_ip=None, device_owner=None, device_id=None,
|
||||||
mac_address=None, security_group_ids=None, dhcp_opts=None):
|
mac_address=None, security_group_ids=None, dhcp_opts=None,
|
||||||
|
**kwargs):
|
||||||
try:
|
try:
|
||||||
port_req_body = {'port': {}}
|
port_req_body = {'port': {}}
|
||||||
port_req_body['port']['network_id'] = network_id
|
port_req_body['port']['network_id'] = network_id
|
||||||
@ -187,6 +188,8 @@ class API(object):
|
|||||||
port_req_body['port']['device_owner'] = device_owner
|
port_req_body['port']['device_owner'] = device_owner
|
||||||
if device_id:
|
if device_id:
|
||||||
port_req_body['port']['device_id'] = device_id
|
port_req_body['port']['device_id'] = device_id
|
||||||
|
if kwargs:
|
||||||
|
port_req_body['port'].update(kwargs)
|
||||||
port = self.client.create_port(port_req_body).get('port', {})
|
port = self.client.create_port(port_req_body).get('port', {})
|
||||||
return port
|
return port
|
||||||
except neutron_client_exc.NeutronClientException as e:
|
except neutron_client_exc.NeutronClientException as e:
|
||||||
|
@ -15,3 +15,8 @@
|
|||||||
|
|
||||||
PROVIDER_NW_EXT = 'Provider Network'
|
PROVIDER_NW_EXT = 'Provider Network'
|
||||||
PORTBINDING_EXT = 'Port Binding'
|
PORTBINDING_EXT = 'Port Binding'
|
||||||
|
|
||||||
|
PORT_STATUS_ERROR = 'ERROR'
|
||||||
|
PORT_STATUS_ACTIVE = 'ACTIVE'
|
||||||
|
|
||||||
|
VIF_TYPE_BINDING_FAILED = 'binding_failed'
|
||||||
|
@ -14,15 +14,21 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import socket
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
from oslo_log import log
|
||||||
|
|
||||||
from manila.common import constants
|
from manila.common import constants
|
||||||
from manila import exception
|
from manila import exception
|
||||||
|
from manila.i18n import _
|
||||||
from manila import network
|
from manila import network
|
||||||
from manila.network.neutron import api as neutron_api
|
from manila.network.neutron import api as neutron_api
|
||||||
from manila.network.neutron import constants as neutron_constants
|
from manila.network.neutron import constants as neutron_constants
|
||||||
from manila import utils
|
from manila import utils
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
neutron_single_network_plugin_opts = [
|
neutron_single_network_plugin_opts = [
|
||||||
cfg.StrOpt(
|
cfg.StrOpt(
|
||||||
'neutron_net_id',
|
'neutron_net_id',
|
||||||
@ -39,12 +45,18 @@ neutron_single_network_plugin_opts = [
|
|||||||
deprecated_group='DEFAULT'),
|
deprecated_group='DEFAULT'),
|
||||||
]
|
]
|
||||||
|
|
||||||
neutron_network_plugin_opts = [
|
neutron_bind_network_plugin_opts = [
|
||||||
|
cfg.StrOpt(
|
||||||
|
'neutron_vnic_type',
|
||||||
|
help="vNIC type used for binding.",
|
||||||
|
choices=['baremetal', 'normal', 'direct',
|
||||||
|
'direct-physical', 'macvtap'],
|
||||||
|
default='baremetal'),
|
||||||
cfg.StrOpt(
|
cfg.StrOpt(
|
||||||
"neutron_host_id",
|
"neutron_host_id",
|
||||||
help="Host ID to be used when creating neutron port. Hostname of "
|
help="Host ID to be used when creating neutron port. If not set "
|
||||||
"a controller running Neutron should be used in a general case.",
|
"host is set to manila-share host by default.",
|
||||||
deprecated_group='DEFAULT'),
|
default=socket.gethostname()),
|
||||||
]
|
]
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
@ -59,9 +71,6 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
|
|||||||
self._neutron_api_args = args
|
self._neutron_api_args = args
|
||||||
self._neutron_api_kwargs = kwargs
|
self._neutron_api_kwargs = kwargs
|
||||||
self._label = kwargs.pop('label', 'user')
|
self._label = kwargs.pop('label', 'user')
|
||||||
CONF.register_opts(
|
|
||||||
neutron_network_plugin_opts,
|
|
||||||
group=self.neutron_api.config_group_name)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def label(self):
|
def label(self):
|
||||||
@ -124,13 +133,22 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
|
|||||||
for port in ports:
|
for port in ports:
|
||||||
self._delete_port(context, port)
|
self._delete_port(context, port)
|
||||||
|
|
||||||
|
def _get_port_create_args(self, share_server, share_network,
|
||||||
|
device_owner):
|
||||||
|
return {
|
||||||
|
"network_id": share_network['neutron_net_id'],
|
||||||
|
"subnet_id": share_network['neutron_subnet_id'],
|
||||||
|
"device_owner": 'manila:' + device_owner,
|
||||||
|
"device_id": share_server.get('id'),
|
||||||
|
}
|
||||||
|
|
||||||
def _create_port(self, context, share_server, share_network, device_owner):
|
def _create_port(self, context, share_server, share_network, device_owner):
|
||||||
host_id = self.neutron_api.configuration.neutron_host_id
|
create_args = self._get_port_create_args(share_server, share_network,
|
||||||
|
device_owner)
|
||||||
|
|
||||||
port = self.neutron_api.create_port(
|
port = self.neutron_api.create_port(
|
||||||
share_network['project_id'],
|
share_network['project_id'], **create_args)
|
||||||
network_id=share_network['neutron_net_id'],
|
|
||||||
subnet_id=share_network['neutron_subnet_id'],
|
|
||||||
device_owner='manila:' + device_owner, host_id=host_id)
|
|
||||||
port_dict = {
|
port_dict = {
|
||||||
'id': port['id'],
|
'id': port['id'],
|
||||||
'share_server_id': share_server['id'],
|
'share_server_id': share_server['id'],
|
||||||
@ -214,7 +232,7 @@ class NeutronSingleNetworkPlugin(NeutronNetworkPlugin):
|
|||||||
'neutron_net_id': self.net,
|
'neutron_net_id': self.net,
|
||||||
'neutron_subnet_id': self.subnet,
|
'neutron_subnet_id': self.subnet,
|
||||||
}
|
}
|
||||||
super(NeutronSingleNetworkPlugin, self).allocate_network(
|
return super(NeutronSingleNetworkPlugin, self).allocate_network(
|
||||||
context, share_server, share_network, **kwargs)
|
context, share_server, share_network, **kwargs)
|
||||||
|
|
||||||
def _verify_net_and_subnet(self):
|
def _verify_net_and_subnet(self):
|
||||||
@ -261,3 +279,73 @@ class NeutronSingleNetworkPlugin(NeutronNetworkPlugin):
|
|||||||
share_network = self.db.share_network_update(
|
share_network = self.db.share_network_update(
|
||||||
context, share_network['id'], upd)
|
context, share_network['id'], upd)
|
||||||
return share_network
|
return share_network
|
||||||
|
|
||||||
|
|
||||||
|
class NeutronBindNetworkPlugin(NeutronNetworkPlugin):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(NeutronBindNetworkPlugin, self).__init__(*args, **kwargs)
|
||||||
|
CONF.register_opts(
|
||||||
|
neutron_bind_network_plugin_opts,
|
||||||
|
group=self.neutron_api.config_group_name)
|
||||||
|
self.config = self.neutron_api.configuration
|
||||||
|
|
||||||
|
def update_network_allocation(self, context, share_server):
|
||||||
|
if self.config.neutron_vnic_type == 'normal':
|
||||||
|
ports = self.db.network_allocations_get_for_share_server(
|
||||||
|
context,
|
||||||
|
share_server['id'])
|
||||||
|
self._wait_for_ports_bind(ports, share_server)
|
||||||
|
return ports
|
||||||
|
|
||||||
|
@utils.retry(exception.NetworkBindException, retries=20)
|
||||||
|
def _wait_for_ports_bind(self, ports, share_server):
|
||||||
|
inactive_ports = []
|
||||||
|
for port in ports:
|
||||||
|
port = self._neutron_api.show_port(port['id'])
|
||||||
|
if (port['status'] == neutron_constants.PORT_STATUS_ERROR or
|
||||||
|
('binding:vif_type' in port and
|
||||||
|
port['binding:vif_type'] ==
|
||||||
|
neutron_constants.VIF_TYPE_BINDING_FAILED)):
|
||||||
|
msg = _("Port binding %s failed.") % port['id']
|
||||||
|
raise exception.NetworkException(msg)
|
||||||
|
elif port['status'] != neutron_constants.PORT_STATUS_ACTIVE:
|
||||||
|
LOG.debug("The port %(id)s is in state %(state)s. "
|
||||||
|
"Wait for active state.", {
|
||||||
|
"id": port['id'],
|
||||||
|
"state": port['status']})
|
||||||
|
inactive_ports.append(port['id'])
|
||||||
|
if len(inactive_ports) == 0:
|
||||||
|
return
|
||||||
|
msg = _("Ports are not fully bound for share server "
|
||||||
|
"'%(s_id)s' (inactive ports: %(ports)s)") % {
|
||||||
|
"s_id": share_server['id'],
|
||||||
|
"ports": inactive_ports}
|
||||||
|
raise exception.NetworkBindException(msg)
|
||||||
|
|
||||||
|
def _get_port_create_args(self, share_server, share_network,
|
||||||
|
device_owner):
|
||||||
|
arguments = super(
|
||||||
|
NeutronBindNetworkPlugin, self)._get_port_create_args(
|
||||||
|
share_network, share_network, device_owner)
|
||||||
|
arguments['host_id'] = self.config.neutron_host_id
|
||||||
|
arguments['binding:vnic_type'] = self.config.neutron_vnic_type
|
||||||
|
return arguments
|
||||||
|
|
||||||
|
def allocate_network(self, context, share_server, share_network=None,
|
||||||
|
**kwargs):
|
||||||
|
ports = super(NeutronBindNetworkPlugin, self).allocate_network(
|
||||||
|
context, share_server, share_network, **kwargs)
|
||||||
|
# If vnic type is 'normal' we expect a neutron agent to bind the
|
||||||
|
# ports. This action requires a vnic to be spawned by the driver.
|
||||||
|
# Therefore we do not wait for the port binding here, but
|
||||||
|
# return the unbound ports and expect the share manager to call
|
||||||
|
# update_network_allocation after the share server was created, in
|
||||||
|
# order to update the ports with the correct binding.
|
||||||
|
if self.config.neutron_vnic_type != 'normal':
|
||||||
|
self._wait_for_ports_bind(ports, share_server)
|
||||||
|
return ports
|
||||||
|
|
||||||
|
|
||||||
|
class NeutronBindSingleNetworkPlugin(NeutronSingleNetworkPlugin,
|
||||||
|
NeutronBindNetworkPlugin):
|
||||||
|
pass
|
||||||
|
@ -100,7 +100,7 @@ _global_opt_lists = [
|
|||||||
manila.network.linux.interface.OPTS,
|
manila.network.linux.interface.OPTS,
|
||||||
manila.network.network_opts,
|
manila.network.network_opts,
|
||||||
manila.network.neutron.neutron_network_plugin.
|
manila.network.neutron.neutron_network_plugin.
|
||||||
neutron_network_plugin_opts,
|
neutron_bind_network_plugin_opts,
|
||||||
manila.network.neutron.neutron_network_plugin.
|
manila.network.neutron.neutron_network_plugin.
|
||||||
neutron_single_network_plugin_opts,
|
neutron_single_network_plugin_opts,
|
||||||
manila.network.nova_network_plugin.nova_single_network_plugin_opts,
|
manila.network.nova_network_plugin.nova_single_network_plugin_opts,
|
||||||
|
@ -570,6 +570,17 @@ class ShareDriver(object):
|
|||||||
def get_admin_network_allocations_number(self):
|
def get_admin_network_allocations_number(self):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def update_network_allocation(self, context, share_server):
|
||||||
|
"""Update network allocation after share server creation."""
|
||||||
|
self.network_api.update_network_allocation(context, share_server)
|
||||||
|
|
||||||
|
def update_admin_network_allocation(self, context, share_server):
|
||||||
|
"""Update admin network allocation after share server creation."""
|
||||||
|
if (self.get_admin_network_allocations_number() and
|
||||||
|
self.admin_network_api):
|
||||||
|
self.admin_network_api.update_network_allocation(context,
|
||||||
|
share_server)
|
||||||
|
|
||||||
def allocate_network(self, context, share_server, share_network,
|
def allocate_network(self, context, share_server, share_network,
|
||||||
count=None, **kwargs):
|
count=None, **kwargs):
|
||||||
"""Allocate network resources using given network information."""
|
"""Allocate network resources using given network information."""
|
||||||
|
@ -2375,6 +2375,9 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||||||
server_info = self.driver.setup_server(
|
server_info = self.driver.setup_server(
|
||||||
network_info, metadata=metadata)
|
network_info, metadata=metadata)
|
||||||
|
|
||||||
|
self.driver.update_network_allocation(context, share_server)
|
||||||
|
self.driver.update_admin_network_allocation(context, share_server)
|
||||||
|
|
||||||
if server_info and isinstance(server_info, dict):
|
if server_info and isinstance(server_info, dict):
|
||||||
self.db.share_server_backend_details_set(
|
self.db.share_server_backend_details_set(
|
||||||
context, share_server['id'], server_info)
|
context, share_server['id'], server_info)
|
||||||
|
@ -164,6 +164,25 @@ class NeutronApiTest(test.TestCase):
|
|||||||
self.neutron_api._has_port_binding_extension.assert_called_once_with()
|
self.neutron_api._has_port_binding_extension.assert_called_once_with()
|
||||||
self.assertTrue(clientv20.Client.called)
|
self.assertTrue(clientv20.Client.called)
|
||||||
|
|
||||||
|
def test_create_port_with_additional_kwargs(self):
|
||||||
|
# Set up test data
|
||||||
|
self.mock_object(self.neutron_api, '_has_port_binding_extension',
|
||||||
|
mock.Mock(return_value=True))
|
||||||
|
port_args = {'tenant_id': 'test tenant', 'network_id': 'test net',
|
||||||
|
'binding_arg': 'foo'}
|
||||||
|
|
||||||
|
# Execute method 'create_port'
|
||||||
|
port = self.neutron_api.create_port(**port_args)
|
||||||
|
|
||||||
|
# Verify results
|
||||||
|
self.assertEqual(port_args['tenant_id'], port['tenant_id'])
|
||||||
|
self.assertEqual(port_args['network_id'],
|
||||||
|
port['network_id'])
|
||||||
|
self.assertEqual(port_args['binding_arg'],
|
||||||
|
port['binding_arg'])
|
||||||
|
self.neutron_api._has_port_binding_extension.assert_called_once_with()
|
||||||
|
self.assertTrue(clientv20.Client.called)
|
||||||
|
|
||||||
@mock.patch.object(neutron_api.LOG, 'exception', mock.Mock())
|
@mock.patch.object(neutron_api.LOG, 'exception', mock.Mock())
|
||||||
def test_create_port_exception(self):
|
def test_create_port_exception(self):
|
||||||
# Set up test data
|
# Set up test data
|
||||||
|
@ -14,8 +14,11 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import copy
|
||||||
import ddt
|
import ddt
|
||||||
import mock
|
import mock
|
||||||
|
import time
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
|
||||||
from manila.common import constants
|
from manila.common import constants
|
||||||
@ -31,7 +34,7 @@ from manila.tests import utils as test_utils
|
|||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
|
||||||
fake_neutron_port = {
|
fake_neutron_port = {
|
||||||
"status": "test_port_status",
|
"status": "ACTIVE",
|
||||||
"allowed_address_pairs": [],
|
"allowed_address_pairs": [],
|
||||||
"admin_state_up": True,
|
"admin_state_up": True,
|
||||||
"network_id": "test_net_id",
|
"network_id": "test_net_id",
|
||||||
@ -132,7 +135,8 @@ class NeutronNetworkPluginTest(test.TestCase):
|
|||||||
fake_share_network['project_id'],
|
fake_share_network['project_id'],
|
||||||
network_id=fake_share_network['neutron_net_id'],
|
network_id=fake_share_network['neutron_net_id'],
|
||||||
subnet_id=fake_share_network['neutron_subnet_id'],
|
subnet_id=fake_share_network['neutron_subnet_id'],
|
||||||
device_owner='manila:share', host_id=None)
|
device_owner='manila:share',
|
||||||
|
device_id=fake_share_network['id'])
|
||||||
db_api.network_allocation_create.assert_called_once_with(
|
db_api.network_allocation_create.assert_called_once_with(
|
||||||
self.fake_context,
|
self.fake_context,
|
||||||
fake_network_allocation)
|
fake_network_allocation)
|
||||||
@ -141,54 +145,6 @@ class NeutronNetworkPluginTest(test.TestCase):
|
|||||||
save_nw_data.stop()
|
save_nw_data.stop()
|
||||||
save_subnet_data.stop()
|
save_subnet_data.stop()
|
||||||
|
|
||||||
@mock.patch.object(db_api, 'network_allocation_create',
|
|
||||||
mock.Mock(return_values=fake_network_allocation))
|
|
||||||
@mock.patch.object(db_api, 'share_network_get',
|
|
||||||
mock.Mock(return_value=fake_share_network))
|
|
||||||
@mock.patch.object(db_api, 'share_server_get',
|
|
||||||
mock.Mock(return_value=fake_share_server))
|
|
||||||
def test_allocate_network_host_id_prconfigured(self):
|
|
||||||
has_provider_nw_ext = mock.patch.object(
|
|
||||||
self.plugin, '_has_provider_network_extension').start()
|
|
||||||
has_provider_nw_ext.return_value = True
|
|
||||||
save_nw_data = mock.patch.object(self.plugin,
|
|
||||||
'_save_neutron_network_data').start()
|
|
||||||
save_subnet_data = mock.patch.object(
|
|
||||||
self.plugin,
|
|
||||||
'_save_neutron_subnet_data').start()
|
|
||||||
|
|
||||||
config_data = {
|
|
||||||
'DEFAULT': {
|
|
||||||
'neutron_host_id': 'fake_host_id',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
with test_utils.create_temp_config_with_opts(config_data):
|
|
||||||
with mock.patch.object(self.plugin.neutron_api, 'create_port',
|
|
||||||
mock.Mock(return_value=fake_neutron_port)):
|
|
||||||
self.plugin.allocate_network(
|
|
||||||
self.fake_context,
|
|
||||||
fake_share_server,
|
|
||||||
fake_share_network,
|
|
||||||
allocation_info={'count': 1})
|
|
||||||
|
|
||||||
has_provider_nw_ext.assert_any_call()
|
|
||||||
save_nw_data.assert_called_once_with(self.fake_context,
|
|
||||||
fake_share_network)
|
|
||||||
save_subnet_data.assert_called_once_with(self.fake_context,
|
|
||||||
fake_share_network)
|
|
||||||
self.plugin.neutron_api.create_port.assert_called_once_with(
|
|
||||||
fake_share_network['project_id'],
|
|
||||||
network_id=fake_share_network['neutron_net_id'],
|
|
||||||
subnet_id=fake_share_network['neutron_subnet_id'],
|
|
||||||
device_owner='manila:share', host_id='fake_host_id')
|
|
||||||
db_api.network_allocation_create.assert_called_once_with(
|
|
||||||
self.fake_context,
|
|
||||||
fake_network_allocation)
|
|
||||||
|
|
||||||
has_provider_nw_ext.stop()
|
|
||||||
save_nw_data.stop()
|
|
||||||
save_subnet_data.stop()
|
|
||||||
|
|
||||||
@mock.patch.object(db_api, 'network_allocation_create',
|
@mock.patch.object(db_api, 'network_allocation_create',
|
||||||
mock.Mock(return_values=fake_network_allocation))
|
mock.Mock(return_values=fake_network_allocation))
|
||||||
@mock.patch.object(db_api, 'share_network_get',
|
@mock.patch.object(db_api, 'share_network_get',
|
||||||
@ -217,11 +173,13 @@ class NeutronNetworkPluginTest(test.TestCase):
|
|||||||
mock.call(fake_share_network['project_id'],
|
mock.call(fake_share_network['project_id'],
|
||||||
network_id=fake_share_network['neutron_net_id'],
|
network_id=fake_share_network['neutron_net_id'],
|
||||||
subnet_id=fake_share_network['neutron_subnet_id'],
|
subnet_id=fake_share_network['neutron_subnet_id'],
|
||||||
device_owner='manila:share', host_id=None),
|
device_owner='manila:share',
|
||||||
|
device_id=fake_share_network['id']),
|
||||||
mock.call(fake_share_network['project_id'],
|
mock.call(fake_share_network['project_id'],
|
||||||
network_id=fake_share_network['neutron_net_id'],
|
network_id=fake_share_network['neutron_net_id'],
|
||||||
subnet_id=fake_share_network['neutron_subnet_id'],
|
subnet_id=fake_share_network['neutron_subnet_id'],
|
||||||
device_owner='manila:share', host_id=None),
|
device_owner='manila:share',
|
||||||
|
device_id=fake_share_network['id']),
|
||||||
]
|
]
|
||||||
db_api_calls = [
|
db_api_calls = [
|
||||||
mock.call(self.fake_context, fake_network_allocation),
|
mock.call(self.fake_context, fake_network_allocation),
|
||||||
@ -541,3 +499,559 @@ class NeutronSingleNetworkPluginTest(test.TestCase):
|
|||||||
plugin.NeutronNetworkPlugin.allocate_network.assert_called_once_with(
|
plugin.NeutronNetworkPlugin.allocate_network.assert_called_once_with(
|
||||||
self.context, share_server, share_network_upd, count=count,
|
self.context, share_server, share_network_upd, count=count,
|
||||||
device_owner=device_owner)
|
device_owner=device_owner)
|
||||||
|
plugin.NeutronNetworkPlugin.allocate_network.reset_mock()
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class NeutronBindNetworkPluginTest(test.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(NeutronBindNetworkPluginTest, self).setUp()
|
||||||
|
self.fake_context = context.RequestContext(user_id='fake user',
|
||||||
|
project_id='fake project',
|
||||||
|
is_admin=False)
|
||||||
|
self.has_binding_ext_mock = self.mock_object(
|
||||||
|
neutron_api.API, '_has_port_binding_extension')
|
||||||
|
self.has_binding_ext_mock.return_value = True
|
||||||
|
self.bind_plugin = plugin.NeutronBindNetworkPlugin()
|
||||||
|
self.bind_plugin.db = db_api
|
||||||
|
self.sleep_mock = self.mock_object(time, 'sleep')
|
||||||
|
|
||||||
|
def test_wait_for_bind(self):
|
||||||
|
self.mock_object(self.bind_plugin.neutron_api, 'show_port')
|
||||||
|
self.bind_plugin.neutron_api.show_port.return_value = fake_neutron_port
|
||||||
|
|
||||||
|
self.bind_plugin._wait_for_ports_bind([fake_neutron_port],
|
||||||
|
fake_share_server)
|
||||||
|
|
||||||
|
self.bind_plugin.neutron_api.show_port.assert_called_once_with(
|
||||||
|
fake_neutron_port['id'])
|
||||||
|
self.sleep_mock.assert_not_called()
|
||||||
|
|
||||||
|
def test_wait_for_bind_error(self):
|
||||||
|
fake_neut_port = copy.copy(fake_neutron_port)
|
||||||
|
fake_neut_port['status'] = 'ERROR'
|
||||||
|
self.mock_object(self.bind_plugin.neutron_api, 'show_port')
|
||||||
|
self.bind_plugin.neutron_api.show_port.return_value = fake_neut_port
|
||||||
|
|
||||||
|
self.assertRaises(exception.ManilaException,
|
||||||
|
self.bind_plugin._wait_for_ports_bind,
|
||||||
|
[fake_neut_port, fake_neut_port],
|
||||||
|
fake_share_server)
|
||||||
|
|
||||||
|
self.bind_plugin.neutron_api.show_port.assert_called_once_with(
|
||||||
|
fake_neutron_port['id'])
|
||||||
|
self.sleep_mock.assert_not_called()
|
||||||
|
|
||||||
|
@ddt.data(('DOWN', 'ACTIVE'), ('DOWN', 'DOWN'), ('ACTIVE', 'DOWN'))
|
||||||
|
@mock.patch.object(time, 'time', side_effect=[1, 1, 3])
|
||||||
|
def test_wait_for_bind_two_ports_no_bind(self, state, time_mock):
|
||||||
|
fake_neut_port1 = copy.copy(fake_neutron_port)
|
||||||
|
fake_neut_port1['status'] = state[0]
|
||||||
|
fake_neut_port2 = copy.copy(fake_neutron_port)
|
||||||
|
fake_neut_port2['status'] = state[1]
|
||||||
|
self.mock_object(self.bind_plugin.neutron_api, 'show_port')
|
||||||
|
self.bind_plugin.neutron_api.show_port.side_effect = [fake_neut_port1,
|
||||||
|
fake_neut_port2]
|
||||||
|
|
||||||
|
self.assertRaises(exception.ManilaException,
|
||||||
|
self.bind_plugin._wait_for_ports_bind.__wrapped__,
|
||||||
|
self.bind_plugin,
|
||||||
|
[fake_neut_port1, fake_neut_port2],
|
||||||
|
fake_share_server)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, 'network_allocation_create',
|
||||||
|
mock.Mock(return_values=fake_network_allocation))
|
||||||
|
@mock.patch.object(db_api, 'share_network_get',
|
||||||
|
mock.Mock(return_value=fake_share_network))
|
||||||
|
@mock.patch.object(db_api, 'share_server_get',
|
||||||
|
mock.Mock(return_value=fake_share_server))
|
||||||
|
def test_allocate_network_one_allocation(self):
|
||||||
|
self.mock_object(self.bind_plugin, '_has_provider_network_extension')
|
||||||
|
self.bind_plugin._has_provider_network_extension.return_value = True
|
||||||
|
save_nw_data = self.mock_object(self.bind_plugin,
|
||||||
|
'_save_neutron_network_data')
|
||||||
|
save_subnet_data = self.mock_object(self.bind_plugin,
|
||||||
|
'_save_neutron_subnet_data')
|
||||||
|
self.mock_object(self.bind_plugin, '_wait_for_ports_bind')
|
||||||
|
neutron_host_id_opts = plugin.neutron_bind_network_plugin_opts[1]
|
||||||
|
self.mock_object(neutron_host_id_opts, 'default')
|
||||||
|
neutron_host_id_opts.default = 'foohost1'
|
||||||
|
self.mock_object(db_api, 'network_allocation_create')
|
||||||
|
|
||||||
|
with mock.patch.object(self.bind_plugin.neutron_api, 'create_port',
|
||||||
|
mock.Mock(return_value=fake_neutron_port)):
|
||||||
|
self.bind_plugin.allocate_network(
|
||||||
|
self.fake_context,
|
||||||
|
fake_share_server,
|
||||||
|
fake_share_network,
|
||||||
|
allocation_info={'count': 1})
|
||||||
|
|
||||||
|
self.bind_plugin._has_provider_network_extension.assert_any_call()
|
||||||
|
save_nw_data.assert_called_once_with(self.fake_context,
|
||||||
|
fake_share_network)
|
||||||
|
save_subnet_data.assert_called_once_with(self.fake_context,
|
||||||
|
fake_share_network)
|
||||||
|
expected_kwargs = {
|
||||||
|
'binding:vnic_type': 'baremetal',
|
||||||
|
'host_id': 'foohost1',
|
||||||
|
'network_id': fake_share_network['neutron_net_id'],
|
||||||
|
'subnet_id': fake_share_network['neutron_subnet_id'],
|
||||||
|
'device_owner': 'manila:share',
|
||||||
|
'device_id': fake_share_network['id'],
|
||||||
|
}
|
||||||
|
self.bind_plugin.neutron_api.create_port.assert_called_once_with(
|
||||||
|
fake_share_network['project_id'], **expected_kwargs)
|
||||||
|
db_api.network_allocation_create.assert_called_once_with(
|
||||||
|
self.fake_context,
|
||||||
|
fake_network_allocation)
|
||||||
|
self.bind_plugin._wait_for_ports_bind.assert_called_once_with(
|
||||||
|
[db_api.network_allocation_create()], fake_share_server)
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class NeutronBindSingleNetworkPluginTest(test.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(NeutronBindSingleNetworkPluginTest, self).setUp()
|
||||||
|
self.context = 'fake_context'
|
||||||
|
self.fake_context = context.RequestContext(user_id='fake user',
|
||||||
|
project_id='fake project',
|
||||||
|
is_admin=False)
|
||||||
|
self.has_binding_ext_mock = self.mock_object(
|
||||||
|
neutron_api.API, '_has_port_binding_extension')
|
||||||
|
self.has_binding_ext_mock.return_value = True
|
||||||
|
self.bind_plugin = plugin.NeutronBindNetworkPlugin()
|
||||||
|
self.bind_plugin.db = db_api
|
||||||
|
self.sleep_mock = self.mock_object(time, 'sleep')
|
||||||
|
fake_net_id = 'fake net id'
|
||||||
|
fake_subnet_id = 'fake subnet id'
|
||||||
|
config_data = {
|
||||||
|
'DEFAULT': {
|
||||||
|
'neutron_net_id': fake_net_id,
|
||||||
|
'neutron_subnet_id': fake_subnet_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fake_net = {'subnets': ['fake1', 'fake2', fake_subnet_id]}
|
||||||
|
self.mock_object(
|
||||||
|
neutron_api.API, 'get_network', mock.Mock(return_value=fake_net))
|
||||||
|
|
||||||
|
with test_utils.create_temp_config_with_opts(config_data):
|
||||||
|
self.bind_plugin = plugin.NeutronBindSingleNetworkPlugin()
|
||||||
|
self.bind_plugin.db = db_api
|
||||||
|
|
||||||
|
def test_init_valid(self):
|
||||||
|
fake_net_id = 'fake_net_id'
|
||||||
|
fake_subnet_id = 'fake_subnet_id'
|
||||||
|
config_data = {
|
||||||
|
'DEFAULT': {
|
||||||
|
'neutron_net_id': fake_net_id,
|
||||||
|
'neutron_subnet_id': fake_subnet_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fake_net = {'subnets': ['fake1', 'fake2', fake_subnet_id]}
|
||||||
|
self.mock_object(
|
||||||
|
neutron_api.API, 'get_network', mock.Mock(return_value=fake_net))
|
||||||
|
|
||||||
|
with test_utils.create_temp_config_with_opts(config_data):
|
||||||
|
instance = plugin.NeutronSingleNetworkPlugin()
|
||||||
|
|
||||||
|
self.assertEqual(fake_net_id, instance.net)
|
||||||
|
self.assertEqual(fake_subnet_id, instance.subnet)
|
||||||
|
neutron_api.API.get_network.assert_called_once_with(fake_net_id)
|
||||||
|
|
||||||
|
@ddt.data(
|
||||||
|
{'net': None, 'subnet': None},
|
||||||
|
{'net': 'fake_net_id', 'subnet': None},
|
||||||
|
{'net': None, 'subnet': 'fake_subnet_id'})
|
||||||
|
@ddt.unpack
|
||||||
|
def test_init_invalid(self, net, subnet):
|
||||||
|
config_data = dict()
|
||||||
|
# Simulate absence of set values
|
||||||
|
if net:
|
||||||
|
config_data['neutron_net_id'] = net
|
||||||
|
if subnet:
|
||||||
|
config_data['neutron_subnet_id'] = subnet
|
||||||
|
config_data = dict(DEFAULT=config_data)
|
||||||
|
|
||||||
|
with test_utils.create_temp_config_with_opts(config_data):
|
||||||
|
self.assertRaises(
|
||||||
|
exception.NetworkBadConfigurationException,
|
||||||
|
plugin.NeutronSingleNetworkPlugin)
|
||||||
|
|
||||||
|
@ddt.data({}, {'subnets': []}, {'subnets': ['different_foo_subnet']})
|
||||||
|
def test_init_subnet_does_not_belong_to_net(self, fake_net):
|
||||||
|
fake_net_id = 'fake_net_id'
|
||||||
|
config_data = {
|
||||||
|
'DEFAULT': {
|
||||||
|
'neutron_net_id': fake_net_id,
|
||||||
|
'neutron_subnet_id': 'fake_subnet_id',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.mock_object(
|
||||||
|
neutron_api.API, 'get_network', mock.Mock(return_value=fake_net))
|
||||||
|
|
||||||
|
with test_utils.create_temp_config_with_opts(config_data):
|
||||||
|
self.assertRaises(
|
||||||
|
exception.NetworkBadConfigurationException,
|
||||||
|
plugin.NeutronSingleNetworkPlugin)
|
||||||
|
neutron_api.API.get_network.assert_called_once_with(fake_net_id)
|
||||||
|
|
||||||
|
def _get_neutron_single_network_plugin_instance(self):
|
||||||
|
fake_subnet_id = 'fake_subnet_id'
|
||||||
|
config_data = {
|
||||||
|
'DEFAULT': {
|
||||||
|
'neutron_net_id': 'fake_net_id',
|
||||||
|
'neutron_subnet_id': fake_subnet_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fake_net = {'subnets': [fake_subnet_id]}
|
||||||
|
self.mock_object(
|
||||||
|
neutron_api.API, 'get_network', mock.Mock(return_value=fake_net))
|
||||||
|
with test_utils.create_temp_config_with_opts(config_data):
|
||||||
|
instance = plugin.NeutronSingleNetworkPlugin()
|
||||||
|
return instance
|
||||||
|
|
||||||
|
def test___update_share_network_net_data_same_values(self):
|
||||||
|
instance = self._get_neutron_single_network_plugin_instance()
|
||||||
|
share_network = {
|
||||||
|
'neutron_net_id': instance.net,
|
||||||
|
'neutron_subnet_id': instance.subnet,
|
||||||
|
}
|
||||||
|
|
||||||
|
result = instance._update_share_network_net_data(
|
||||||
|
self.context, share_network)
|
||||||
|
|
||||||
|
self.assertEqual(share_network, result)
|
||||||
|
|
||||||
|
def test___update_share_network_net_data_different_values_empty(self):
|
||||||
|
instance = self._get_neutron_single_network_plugin_instance()
|
||||||
|
share_network_input = {
|
||||||
|
'id': 'fake_share_network_id',
|
||||||
|
}
|
||||||
|
share_network_result = {
|
||||||
|
'neutron_net_id': instance.net,
|
||||||
|
'neutron_subnet_id': instance.subnet,
|
||||||
|
}
|
||||||
|
self.mock_object(
|
||||||
|
instance.db, 'share_network_update',
|
||||||
|
mock.Mock(return_value='foo'))
|
||||||
|
|
||||||
|
instance._update_share_network_net_data(
|
||||||
|
self.context, share_network_input)
|
||||||
|
|
||||||
|
instance.db.share_network_update.assert_called_once_with(
|
||||||
|
self.context, share_network_input['id'], share_network_result)
|
||||||
|
|
||||||
|
@ddt.data(
|
||||||
|
{'n': 'fake_net_id', 's': 'bar'},
|
||||||
|
{'n': 'foo', 's': 'fake_subnet_id'})
|
||||||
|
@ddt.unpack
|
||||||
|
def test___update_share_network_net_data_different_values(self, n, s):
|
||||||
|
instance = self._get_neutron_single_network_plugin_instance()
|
||||||
|
share_network = {
|
||||||
|
'id': 'fake_share_network_id',
|
||||||
|
'neutron_net_id': n,
|
||||||
|
'neutron_subnet_id': s,
|
||||||
|
}
|
||||||
|
self.mock_object(
|
||||||
|
instance.db, 'share_network_update',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exception.NetworkBadConfigurationException,
|
||||||
|
instance._update_share_network_net_data,
|
||||||
|
self.context, share_network)
|
||||||
|
self.assertFalse(instance.db.share_network_update.called)
|
||||||
|
|
||||||
|
def test___update_share_network_net_data_nova_net_id_present(self):
|
||||||
|
instance = self._get_neutron_single_network_plugin_instance()
|
||||||
|
share_network = {
|
||||||
|
'id': 'fake_share_network_id',
|
||||||
|
'nova_net_id': 'foo',
|
||||||
|
}
|
||||||
|
self.mock_object(
|
||||||
|
instance.db, 'share_network_update',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exception.NetworkBadConfigurationException,
|
||||||
|
instance._update_share_network_net_data,
|
||||||
|
self.context, share_network)
|
||||||
|
self.assertFalse(instance.db.share_network_update.called)
|
||||||
|
|
||||||
|
@mock.patch.object(
|
||||||
|
plugin.NeutronNetworkPlugin, "allocate_network", mock.Mock())
|
||||||
|
def test_allocate_network(self):
|
||||||
|
instance = self._get_neutron_single_network_plugin_instance()
|
||||||
|
share_server = 'fake_share_server'
|
||||||
|
share_network = 'fake_share_network'
|
||||||
|
share_network_upd = 'updated_fake_share_network'
|
||||||
|
count = 2
|
||||||
|
device_owner = 'fake_device_owner'
|
||||||
|
self.mock_object(
|
||||||
|
instance, '_update_share_network_net_data',
|
||||||
|
mock.Mock(return_value=share_network_upd))
|
||||||
|
|
||||||
|
instance.allocate_network(
|
||||||
|
self.context, share_server, share_network, count=count,
|
||||||
|
device_owner=device_owner)
|
||||||
|
|
||||||
|
instance._update_share_network_net_data.assert_called_once_with(
|
||||||
|
self.context, share_network)
|
||||||
|
plugin.NeutronNetworkPlugin.allocate_network.assert_called_once_with(
|
||||||
|
self.context, share_server, share_network_upd, count=count,
|
||||||
|
device_owner=device_owner)
|
||||||
|
plugin.NeutronNetworkPlugin.allocate_network.reset_mock()
|
||||||
|
|
||||||
|
def test_wait_for_bind(self):
|
||||||
|
self.mock_object(self.bind_plugin.neutron_api, 'show_port')
|
||||||
|
self.bind_plugin.neutron_api.show_port.return_value = fake_neutron_port
|
||||||
|
|
||||||
|
self.bind_plugin._wait_for_ports_bind([fake_neutron_port],
|
||||||
|
fake_share_server)
|
||||||
|
|
||||||
|
self.bind_plugin.neutron_api.show_port.assert_called_once_with(
|
||||||
|
fake_neutron_port['id'])
|
||||||
|
self.sleep_mock.assert_not_called()
|
||||||
|
|
||||||
|
def test_wait_for_bind_error(self):
|
||||||
|
fake_neut_port = copy.copy(fake_neutron_port)
|
||||||
|
fake_neut_port['status'] = 'ERROR'
|
||||||
|
self.mock_object(self.bind_plugin.neutron_api, 'show_port')
|
||||||
|
self.bind_plugin.neutron_api.show_port.return_value = fake_neut_port
|
||||||
|
|
||||||
|
self.assertRaises(exception.ManilaException,
|
||||||
|
self.bind_plugin._wait_for_ports_bind,
|
||||||
|
[fake_neut_port, fake_neut_port],
|
||||||
|
fake_share_server)
|
||||||
|
|
||||||
|
self.bind_plugin.neutron_api.show_port.assert_called_once_with(
|
||||||
|
fake_neutron_port['id'])
|
||||||
|
self.sleep_mock.assert_not_called()
|
||||||
|
|
||||||
|
@ddt.data(('DOWN', 'ACTIVE'), ('DOWN', 'DOWN'), ('ACTIVE', 'DOWN'))
|
||||||
|
@mock.patch.object(time, 'time', side_effect=[1, 1, 3])
|
||||||
|
def test_wait_for_bind_two_ports_no_bind(self, state, time_mock):
|
||||||
|
fake_neut_port1 = copy.copy(fake_neutron_port)
|
||||||
|
fake_neut_port1['status'] = state[0]
|
||||||
|
fake_neut_port2 = copy.copy(fake_neutron_port)
|
||||||
|
fake_neut_port2['status'] = state[1]
|
||||||
|
self.mock_object(self.bind_plugin.neutron_api, 'show_port')
|
||||||
|
self.bind_plugin.neutron_api.show_port.side_effect = [fake_neut_port1,
|
||||||
|
fake_neut_port2]
|
||||||
|
|
||||||
|
self.assertRaises(exception.NetworkBindException,
|
||||||
|
self.bind_plugin._wait_for_ports_bind.__wrapped__,
|
||||||
|
self.bind_plugin,
|
||||||
|
[fake_neut_port1, fake_neut_port2],
|
||||||
|
fake_share_server)
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, 'network_allocation_create',
|
||||||
|
mock.Mock(return_values=fake_network_allocation))
|
||||||
|
@mock.patch.object(db_api, 'share_network_get',
|
||||||
|
mock.Mock(return_value=fake_share_network))
|
||||||
|
@mock.patch.object(db_api, 'share_server_get',
|
||||||
|
mock.Mock(return_value=fake_share_server))
|
||||||
|
def test_allocate_network_one_allocation(self):
|
||||||
|
self.mock_object(self.bind_plugin, '_has_provider_network_extension')
|
||||||
|
self.bind_plugin._has_provider_network_extension.return_value = True
|
||||||
|
save_nw_data = self.mock_object(self.bind_plugin,
|
||||||
|
'_save_neutron_network_data')
|
||||||
|
save_subnet_data = self.mock_object(self.bind_plugin,
|
||||||
|
'_save_neutron_subnet_data')
|
||||||
|
self.mock_object(self.bind_plugin, '_wait_for_ports_bind')
|
||||||
|
neutron_host_id_opts = plugin.neutron_bind_network_plugin_opts[1]
|
||||||
|
self.mock_object(neutron_host_id_opts, 'default')
|
||||||
|
neutron_host_id_opts.default = 'foohost1'
|
||||||
|
self.mock_object(db_api, 'network_allocation_create')
|
||||||
|
|
||||||
|
with mock.patch.object(self.bind_plugin.neutron_api, 'create_port',
|
||||||
|
mock.Mock(return_value=fake_neutron_port)):
|
||||||
|
self.bind_plugin.allocate_network(
|
||||||
|
self.fake_context,
|
||||||
|
fake_share_server,
|
||||||
|
fake_share_network,
|
||||||
|
allocation_info={'count': 1})
|
||||||
|
|
||||||
|
self.bind_plugin._has_provider_network_extension.assert_any_call()
|
||||||
|
save_nw_data.assert_called_once_with(self.fake_context,
|
||||||
|
fake_share_network)
|
||||||
|
save_subnet_data.assert_called_once_with(self.fake_context,
|
||||||
|
fake_share_network)
|
||||||
|
expected_kwargs = {
|
||||||
|
'binding:vnic_type': 'baremetal',
|
||||||
|
'host_id': 'foohost1',
|
||||||
|
'network_id': fake_share_network['neutron_net_id'],
|
||||||
|
'subnet_id': fake_share_network['neutron_subnet_id'],
|
||||||
|
'device_owner': 'manila:share',
|
||||||
|
'device_id': fake_share_network['id'],
|
||||||
|
}
|
||||||
|
self.bind_plugin.neutron_api.create_port.assert_called_once_with(
|
||||||
|
fake_share_network['project_id'], **expected_kwargs)
|
||||||
|
db_api.network_allocation_create.assert_called_once_with(
|
||||||
|
self.fake_context,
|
||||||
|
fake_network_allocation)
|
||||||
|
self.bind_plugin._wait_for_ports_bind.assert_called_once_with(
|
||||||
|
[db_api.network_allocation_create()], fake_share_server)
|
||||||
|
|
||||||
|
|
||||||
|
class NeutronBindNetworkPluginWithNormalTypeTest(test.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(NeutronBindNetworkPluginWithNormalTypeTest, self).setUp()
|
||||||
|
config_data = {
|
||||||
|
'DEFAULT': {
|
||||||
|
'neutron_vnic_type': 'normal',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.plugin = plugin.NeutronNetworkPlugin()
|
||||||
|
self.plugin.db = db_api
|
||||||
|
self.fake_context = context.RequestContext(user_id='fake user',
|
||||||
|
project_id='fake project',
|
||||||
|
is_admin=False)
|
||||||
|
|
||||||
|
with test_utils.create_temp_config_with_opts(config_data):
|
||||||
|
self.bind_plugin = plugin.NeutronBindNetworkPlugin()
|
||||||
|
self.bind_plugin.db = db_api
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, 'network_allocation_create',
|
||||||
|
mock.Mock(return_values=fake_network_allocation))
|
||||||
|
@mock.patch.object(db_api, 'share_network_get',
|
||||||
|
mock.Mock(return_value=fake_share_network))
|
||||||
|
@mock.patch.object(db_api, 'share_server_get',
|
||||||
|
mock.Mock(return_value=fake_share_server))
|
||||||
|
def test_allocate_network_one_allocation(self):
|
||||||
|
self.mock_object(self.bind_plugin, '_has_provider_network_extension')
|
||||||
|
self.bind_plugin._has_provider_network_extension.return_value = True
|
||||||
|
save_nw_data = self.mock_object(self.bind_plugin,
|
||||||
|
'_save_neutron_network_data')
|
||||||
|
save_subnet_data = self.mock_object(self.bind_plugin,
|
||||||
|
'_save_neutron_subnet_data')
|
||||||
|
self.mock_object(self.bind_plugin, '_wait_for_ports_bind')
|
||||||
|
neutron_host_id_opts = plugin.neutron_bind_network_plugin_opts[1]
|
||||||
|
self.mock_object(neutron_host_id_opts, 'default')
|
||||||
|
neutron_host_id_opts.default = 'foohost1'
|
||||||
|
self.mock_object(db_api, 'network_allocation_create')
|
||||||
|
|
||||||
|
with mock.patch.object(self.bind_plugin.neutron_api, 'create_port',
|
||||||
|
mock.Mock(return_value=fake_neutron_port)):
|
||||||
|
self.bind_plugin.allocate_network(
|
||||||
|
self.fake_context,
|
||||||
|
fake_share_server,
|
||||||
|
fake_share_network,
|
||||||
|
allocation_info={'count': 1})
|
||||||
|
|
||||||
|
self.bind_plugin._has_provider_network_extension.assert_any_call()
|
||||||
|
save_nw_data.assert_called_once_with(self.fake_context,
|
||||||
|
fake_share_network)
|
||||||
|
save_subnet_data.assert_called_once_with(self.fake_context,
|
||||||
|
fake_share_network)
|
||||||
|
expected_kwargs = {
|
||||||
|
'binding:vnic_type': 'normal',
|
||||||
|
'host_id': 'foohost1',
|
||||||
|
'network_id': fake_share_network['neutron_net_id'],
|
||||||
|
'subnet_id': fake_share_network['neutron_subnet_id'],
|
||||||
|
'device_owner': 'manila:share',
|
||||||
|
'device_id': fake_share_network['id'],
|
||||||
|
}
|
||||||
|
self.bind_plugin.neutron_api.create_port.assert_called_once_with(
|
||||||
|
fake_share_network['project_id'], **expected_kwargs)
|
||||||
|
db_api.network_allocation_create.assert_called_once_with(
|
||||||
|
self.fake_context,
|
||||||
|
fake_network_allocation)
|
||||||
|
self.bind_plugin._wait_for_ports_bind.assert_not_called()
|
||||||
|
|
||||||
|
def test_update_network_allocation(self):
|
||||||
|
self.mock_object(self.bind_plugin, '_wait_for_ports_bind')
|
||||||
|
self.mock_object(db_api, 'network_allocations_get_for_share_server')
|
||||||
|
db_api.network_allocations_get_for_share_server.return_value = [
|
||||||
|
fake_neutron_port]
|
||||||
|
|
||||||
|
self.bind_plugin.update_network_allocation(self.fake_context,
|
||||||
|
fake_share_server)
|
||||||
|
|
||||||
|
self.bind_plugin._wait_for_ports_bind.assert_called_once_with(
|
||||||
|
[fake_neutron_port], fake_share_server)
|
||||||
|
|
||||||
|
|
||||||
|
class NeutronBindSingleNetworkPluginWithNormalTypeTest(test.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(NeutronBindSingleNetworkPluginWithNormalTypeTest, self).setUp()
|
||||||
|
fake_net_id = 'fake net id'
|
||||||
|
fake_subnet_id = 'fake subnet id'
|
||||||
|
config_data = {
|
||||||
|
'DEFAULT': {
|
||||||
|
'neutron_net_id': fake_net_id,
|
||||||
|
'neutron_subnet_id': fake_subnet_id,
|
||||||
|
'neutron_vnic_type': 'normal',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fake_net = {'subnets': ['fake1', 'fake2', fake_subnet_id]}
|
||||||
|
self.mock_object(
|
||||||
|
neutron_api.API, 'get_network', mock.Mock(return_value=fake_net))
|
||||||
|
self.plugin = plugin.NeutronNetworkPlugin()
|
||||||
|
self.plugin.db = db_api
|
||||||
|
self.fake_context = context.RequestContext(user_id='fake user',
|
||||||
|
project_id='fake project',
|
||||||
|
is_admin=False)
|
||||||
|
|
||||||
|
with test_utils.create_temp_config_with_opts(config_data):
|
||||||
|
self.bind_plugin = plugin.NeutronBindSingleNetworkPlugin()
|
||||||
|
self.bind_plugin.db = db_api
|
||||||
|
|
||||||
|
@mock.patch.object(db_api, 'network_allocation_create',
|
||||||
|
mock.Mock(return_values=fake_network_allocation))
|
||||||
|
@mock.patch.object(db_api, 'share_network_get',
|
||||||
|
mock.Mock(return_value=fake_share_network))
|
||||||
|
@mock.patch.object(db_api, 'share_server_get',
|
||||||
|
mock.Mock(return_value=fake_share_server))
|
||||||
|
def test_allocate_network_one_allocation(self):
|
||||||
|
self.mock_object(self.bind_plugin, '_has_provider_network_extension')
|
||||||
|
self.bind_plugin._has_provider_network_extension.return_value = True
|
||||||
|
save_nw_data = self.mock_object(self.bind_plugin,
|
||||||
|
'_save_neutron_network_data')
|
||||||
|
save_subnet_data = self.mock_object(self.bind_plugin,
|
||||||
|
'_save_neutron_subnet_data')
|
||||||
|
self.mock_object(self.bind_plugin, '_wait_for_ports_bind')
|
||||||
|
neutron_host_id_opts = plugin.neutron_bind_network_plugin_opts[1]
|
||||||
|
self.mock_object(neutron_host_id_opts, 'default')
|
||||||
|
neutron_host_id_opts.default = 'foohost1'
|
||||||
|
self.mock_object(db_api, 'network_allocation_create')
|
||||||
|
|
||||||
|
with mock.patch.object(self.bind_plugin.neutron_api, 'create_port',
|
||||||
|
mock.Mock(return_value=fake_neutron_port)):
|
||||||
|
self.bind_plugin.allocate_network(
|
||||||
|
self.fake_context,
|
||||||
|
fake_share_server,
|
||||||
|
fake_share_network,
|
||||||
|
allocation_info={'count': 1})
|
||||||
|
|
||||||
|
self.bind_plugin._has_provider_network_extension.assert_any_call()
|
||||||
|
save_nw_data.assert_called_once_with(self.fake_context,
|
||||||
|
fake_share_network)
|
||||||
|
save_subnet_data.assert_called_once_with(self.fake_context,
|
||||||
|
fake_share_network)
|
||||||
|
expected_kwargs = {
|
||||||
|
'binding:vnic_type': 'normal',
|
||||||
|
'host_id': 'foohost1',
|
||||||
|
'network_id': fake_share_network['neutron_net_id'],
|
||||||
|
'subnet_id': fake_share_network['neutron_subnet_id'],
|
||||||
|
'device_owner': 'manila:share',
|
||||||
|
'device_id': fake_share_network['id'],
|
||||||
|
}
|
||||||
|
self.bind_plugin.neutron_api.create_port.assert_called_once_with(
|
||||||
|
fake_share_network['project_id'], **expected_kwargs)
|
||||||
|
db_api.network_allocation_create.assert_called_once_with(
|
||||||
|
self.fake_context,
|
||||||
|
fake_network_allocation)
|
||||||
|
self.bind_plugin._wait_for_ports_bind.assert_not_called()
|
||||||
|
|
||||||
|
def test_update_network_allocation(self):
|
||||||
|
self.mock_object(self.bind_plugin, '_wait_for_ports_bind')
|
||||||
|
self.mock_object(db_api, 'network_allocations_get_for_share_server')
|
||||||
|
db_api.network_allocations_get_for_share_server.return_value = [
|
||||||
|
fake_neutron_port]
|
||||||
|
|
||||||
|
self.bind_plugin.update_network_allocation(self.fake_context,
|
||||||
|
fake_share_server)
|
||||||
|
|
||||||
|
self.bind_plugin._wait_for_ports_bind.assert_called_once_with(
|
||||||
|
[fake_neutron_port], fake_share_server)
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Added neutron driver for port bind actions.
|
Loading…
x
Reference in New Issue
Block a user