Add Nova-network support to service_instance module
Till that moment it was possible to use Generic driver only with Neutron. Nova network still is used in various deployments, so add support for it. List of changes: - Split service_instance to two parts - compute and networking. - Implement networking part as 'network helpers'. - Add new config option 'service_instance_network_helper_type' that supports only two values - 'nova' and 'neutron' respectively. It is required option. Default value is 'neutron'. Details on Nova-network approach: - Due to resctrictions of Nova network, where security group rules are applied to all VM network interfaces, no need to create service network, because it will be just duplication. Service instance will use only one network that is provided within share-network entity. - Host of manila-share service should have network connectivity for all networks, that are going to be used for share creations. - Nova network helper does not create resources, so, network is not configured by Manila in that case. So, network infrastructure can be either flat or using VLAN segmentation as well. Implements BP nova-network-support-in-generic-driver Implements BP split-service-instance Change-Id: I7462fe3d6fa944d391628b8e2b374cf5593924ea
This commit is contained in:
parent
46857b6ffc
commit
79949476ed
@ -135,6 +135,15 @@ def _untranslate_server_summary_view(server):
|
||||
return d
|
||||
|
||||
|
||||
def _to_dict(obj):
|
||||
if isinstance(obj, dict):
|
||||
return obj
|
||||
elif hasattr(obj, 'to_dict'):
|
||||
return obj.to_dict()
|
||||
else:
|
||||
return obj.__dict__
|
||||
|
||||
|
||||
def translate_server_exception(method):
|
||||
"""Transforms the exception for the instance.
|
||||
|
||||
@ -308,3 +317,7 @@ class API(base.Base):
|
||||
|
||||
def security_group_rule_delete(self, context, rule):
|
||||
return novaclient(context).security_group_rules.delete(rule)
|
||||
|
||||
def network_get(self, context, network_id):
|
||||
"""Return network data by its ID."""
|
||||
return _to_dict(novaclient(context).networks.get(network_id))
|
||||
|
@ -47,10 +47,11 @@ neutron_opts = [
|
||||
deprecated_group='DEFAULT',
|
||||
secret=True),
|
||||
cfg.StrOpt(
|
||||
'neutron_admin_tenant_name',
|
||||
'neutron_admin_project_name',
|
||||
default='service',
|
||||
deprecated_group='DEFAULT',
|
||||
help='Tenant name for connecting to neutron in admin context.'),
|
||||
deprecated_name='neutron_admin_tenant_name',
|
||||
help='Project name for connecting to Neutron in admin context.'),
|
||||
cfg.StrOpt(
|
||||
'neutron_admin_auth_url',
|
||||
default='http://localhost:5000/v2.0',
|
||||
@ -105,7 +106,7 @@ class API(base.Base):
|
||||
else:
|
||||
params['username'] = self.configuration.neutron_admin_username
|
||||
params['tenant_name'] = (
|
||||
self.configuration.neutron_admin_tenant_name)
|
||||
self.configuration.neutron_admin_project_name)
|
||||
params['password'] = self.configuration.neutron_admin_password
|
||||
params['auth_url'] = self.configuration.neutron_admin_auth_url
|
||||
params['auth_strategy'] = self.configuration.neutron_auth_strategy
|
||||
@ -121,7 +122,7 @@ class API(base.Base):
|
||||
return self._get_client(token=token)
|
||||
|
||||
@property
|
||||
def admin_tenant_id(self):
|
||||
def admin_project_id(self):
|
||||
if self.client.httpclient.auth_token is None:
|
||||
try:
|
||||
self.client.httpclient.authenticate()
|
||||
@ -130,8 +131,8 @@ class API(base.Base):
|
||||
message=e.message)
|
||||
return self.client.httpclient.auth_tenant_id
|
||||
|
||||
def get_all_tenant_networks(self, tenant_id):
|
||||
search_opts = {'tenant_id': tenant_id, 'shared': False}
|
||||
def get_all_admin_project_networks(self):
|
||||
search_opts = {'tenant_id': self.admin_project_id, 'shared': False}
|
||||
nets = self.client.list_networks(**search_opts).get('networks', [])
|
||||
return nets
|
||||
|
||||
|
@ -618,11 +618,7 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
||||
msg = "Creating share server '%s'."
|
||||
LOG.debug(msg % network_info['server_id'])
|
||||
server = self.service_instance_manager.set_up_service_instance(
|
||||
self.admin_context,
|
||||
network_info['server_id'],
|
||||
network_info['neutron_net_id'],
|
||||
network_info['neutron_subnet_id'],
|
||||
)
|
||||
self.admin_context, network_info)
|
||||
for helper in self._helpers.values():
|
||||
helper.init_helper(server)
|
||||
return server
|
||||
@ -632,8 +628,7 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
||||
LOG.debug("Removing share infrastructure for service instance '%s'.",
|
||||
instance_id)
|
||||
self.service_instance_manager.delete_service_instance(
|
||||
self.admin_context, instance_id, server_details['subnet_id'],
|
||||
server_details.get('router_id'))
|
||||
self.admin_context, server_details)
|
||||
|
||||
|
||||
class NASHelperBase(object):
|
||||
|
@ -16,9 +16,9 @@
|
||||
|
||||
"""Module for managing nova instances for share drivers."""
|
||||
|
||||
import abc
|
||||
import os
|
||||
import socket
|
||||
import threading
|
||||
import time
|
||||
|
||||
import netaddr
|
||||
@ -38,48 +38,66 @@ from manila.network.neutron import api as neutron
|
||||
from manila import utils
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
NEUTRON_NAME = "neutron"
|
||||
NOVA_NAME = "nova"
|
||||
|
||||
share_servers_handling_mode_opts = [
|
||||
cfg.StrOpt('service_image_name',
|
||||
default='manila-service-image',
|
||||
help="Name of image in glance, that will be used to create "
|
||||
"service instance."),
|
||||
cfg.StrOpt('service_instance_name_template',
|
||||
default='manila_service_instance_%s',
|
||||
cfg.StrOpt(
|
||||
"service_image_name",
|
||||
default="manila-service-image",
|
||||
help="Name of image in Glance, that will be used for service instance "
|
||||
"creation."),
|
||||
cfg.StrOpt(
|
||||
"service_instance_name_template",
|
||||
default="manila_service_instance_%s",
|
||||
help="Name of service instance."),
|
||||
cfg.StrOpt('manila_service_keypair_name',
|
||||
default='manila-service',
|
||||
help="Name of keypair that will be created and used "
|
||||
"for service instance."),
|
||||
cfg.StrOpt('path_to_public_key',
|
||||
default='~/.ssh/id_rsa.pub',
|
||||
help="Path to hosts public key."),
|
||||
cfg.StrOpt('service_instance_security_group',
|
||||
cfg.StrOpt(
|
||||
"manila_service_keypair_name",
|
||||
default="manila-service",
|
||||
help="Name of security group, that will be used for "
|
||||
help="Keypair name that will be created and used for service "
|
||||
"instances."),
|
||||
cfg.StrOpt(
|
||||
"path_to_public_key",
|
||||
default="~/.ssh/id_rsa.pub",
|
||||
help="Path to hosts public key."),
|
||||
cfg.StrOpt(
|
||||
"service_instance_security_group",
|
||||
default="manila-service",
|
||||
help="Security group name, that will be used for "
|
||||
"service instance creation."),
|
||||
cfg.IntOpt('service_instance_flavor_id',
|
||||
cfg.IntOpt(
|
||||
"service_instance_flavor_id",
|
||||
default=100,
|
||||
help="ID of flavor, that will be used for service instance "
|
||||
"creation."),
|
||||
cfg.StrOpt('service_network_name',
|
||||
default='manila_service_network',
|
||||
help="Name of manila service network."),
|
||||
cfg.StrOpt('service_network_cidr',
|
||||
default='10.254.0.0/16',
|
||||
help="CIDR of manila service network."),
|
||||
cfg.IntOpt('service_network_division_mask',
|
||||
cfg.StrOpt(
|
||||
"service_network_name",
|
||||
default="manila_service_network",
|
||||
help="Name of manila service network. Used only with Neutron."),
|
||||
cfg.StrOpt(
|
||||
"service_network_cidr",
|
||||
default="10.254.0.0/16",
|
||||
help="CIDR of manila service network. Used only with Neutron."),
|
||||
cfg.IntOpt(
|
||||
"service_network_division_mask",
|
||||
default=28,
|
||||
help="This mask is used for dividing service network into "
|
||||
"subnets, IP capacity of subnet with this mask directly "
|
||||
"defines possible amount of created service VMs "
|
||||
"per tenant's subnet."),
|
||||
cfg.StrOpt('interface_driver',
|
||||
default='manila.network.linux.interface.OVSInterfaceDriver',
|
||||
help="Vif driver."),
|
||||
cfg.BoolOpt('connect_share_server_to_tenant_network',
|
||||
"per tenant's subnet. Used only with Neutron."),
|
||||
cfg.StrOpt(
|
||||
"interface_driver",
|
||||
default="manila.network.linux.interface.OVSInterfaceDriver",
|
||||
help="Vif driver. Used only with Neutron."),
|
||||
cfg.BoolOpt(
|
||||
"connect_share_server_to_tenant_network",
|
||||
default=False,
|
||||
help='Attach share server directly to share network.'),
|
||||
help="Attach share server directly to share network. "
|
||||
"Used only with Neutron."),
|
||||
cfg.StrOpt(
|
||||
"service_instance_network_helper_type",
|
||||
default=NEUTRON_NAME,
|
||||
help="Allowed values are %s." % [NOVA_NAME, NEUTRON_NAME])
|
||||
]
|
||||
|
||||
no_share_servers_handling_mode_opts = [
|
||||
@ -121,11 +139,6 @@ common_opts = [
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(common_opts)
|
||||
CONF.register_opts(no_share_servers_handling_mode_opts)
|
||||
CONF.register_opts(share_servers_handling_mode_opts)
|
||||
|
||||
lock = threading.Lock()
|
||||
|
||||
|
||||
class ServiceInstanceManager(object):
|
||||
@ -148,19 +161,32 @@ class ServiceInstanceManager(object):
|
||||
first priority is driver's config,
|
||||
second priority is global config.
|
||||
"""
|
||||
value = None
|
||||
if self.driver_config:
|
||||
value = self.driver_config.safe_get(key)
|
||||
else:
|
||||
value = CONF.get(key)
|
||||
return value
|
||||
return self.driver_config.safe_get(key)
|
||||
return CONF.get(key)
|
||||
|
||||
def __init__(self, db, driver_config):
|
||||
"""Do initialization."""
|
||||
def _get_network_helper(self):
|
||||
network_helper_type = (
|
||||
self.get_config_option(
|
||||
"service_instance_network_helper_type").lower())
|
||||
if network_helper_type == NEUTRON_NAME:
|
||||
return NeutronNetworkHelper(self)
|
||||
elif network_helper_type == NOVA_NAME:
|
||||
return NovaNetworkHelper(self)
|
||||
else:
|
||||
raise exception.ManilaException(
|
||||
_("Wrong value '%(provided)s' for config opt "
|
||||
"'service_instance_network_helper_type'. "
|
||||
"Allowed values are %(allowed)s.") % dict(
|
||||
provided=network_helper_type,
|
||||
allowed=[NOVA_NAME, NEUTRON_NAME]))
|
||||
|
||||
def __init__(self, db, driver_config=None):
|
||||
super(ServiceInstanceManager, self).__init__()
|
||||
self.db = db
|
||||
self.driver_config = driver_config
|
||||
|
||||
if self.driver_config:
|
||||
self.driver_config.append_config_values(common_opts)
|
||||
if self.get_config_option("driver_handles_share_servers"):
|
||||
self.driver_config.append_config_values(
|
||||
@ -168,44 +194,31 @@ class ServiceInstanceManager(object):
|
||||
else:
|
||||
self.driver_config.append_config_values(
|
||||
no_share_servers_handling_mode_opts)
|
||||
else:
|
||||
CONF.register_opts(common_opts)
|
||||
if self.get_config_option("driver_handles_share_servers"):
|
||||
CONF.register_opts(share_servers_handling_mode_opts)
|
||||
else:
|
||||
CONF.register_opts(no_share_servers_handling_mode_opts)
|
||||
|
||||
if not self.get_config_option("service_instance_user"):
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Service instance user is not specified.'))
|
||||
self.admin_context = context.get_admin_context()
|
||||
self._execute = utils.execute
|
||||
|
||||
self.compute_api = compute.API()
|
||||
|
||||
self.path_to_private_key = self.get_config_option(
|
||||
"path_to_private_key")
|
||||
self.max_time_to_build_instance = self.get_config_option(
|
||||
"max_time_to_build_instance")
|
||||
|
||||
if self.get_config_option("driver_handles_share_servers"):
|
||||
self.neutron_api = neutron.API()
|
||||
self.path_to_public_key = self.get_config_option(
|
||||
"path_to_public_key")
|
||||
self.connect_share_server_to_tenant_network = (
|
||||
self.get_config_option(
|
||||
'connect_share_server_to_tenant_network'))
|
||||
self._get_service_tenant_id()
|
||||
self.service_network_id = self._get_service_network()
|
||||
self.vif_driver = importutils.import_class(
|
||||
self.get_config_option("interface_driver"))()
|
||||
self._setup_connectivity_with_service_instances()
|
||||
|
||||
def _get_service_tenant_id(self):
|
||||
attempts = 5
|
||||
while attempts:
|
||||
try:
|
||||
self.service_tenant_id = self.neutron_api.admin_tenant_id
|
||||
break
|
||||
except exception.NetworkException:
|
||||
LOG.debug('Connection to neutron failed.')
|
||||
attempts -= 1
|
||||
time.sleep(3)
|
||||
else:
|
||||
raise exception.ServiceInstanceException(_('Can not receive '
|
||||
'service tenant id.'))
|
||||
self.network_helper = self._get_network_helper()
|
||||
self.network_helper.setup_connectivity_with_service_instances()
|
||||
|
||||
def get_common_server(self):
|
||||
data = {
|
||||
@ -258,38 +271,20 @@ class ServiceInstanceManager(object):
|
||||
net_ips = [addr['addr'] for addr in server['addresses'][net_name]]
|
||||
return net_ips
|
||||
|
||||
@utils.synchronized("service_instance_get_service_network", external=True)
|
||||
def _get_service_network(self):
|
||||
"""Finds existing or creates new service network."""
|
||||
service_network_name = self.get_config_option("service_network_name")
|
||||
networks = [network for network in self.neutron_api.
|
||||
get_all_tenant_networks(self.service_tenant_id)
|
||||
if network['name'] == service_network_name]
|
||||
if len(networks) > 1:
|
||||
raise exception.ServiceInstanceException(_('Ambiguous service '
|
||||
'networks.'))
|
||||
elif not networks:
|
||||
return self.neutron_api.network_create(self.service_tenant_id,
|
||||
service_network_name)['id']
|
||||
else:
|
||||
return networks[0]['id']
|
||||
|
||||
def _get_service_instance_name(self, share_server_id):
|
||||
"""Returns service vms name."""
|
||||
if self.driver_config:
|
||||
# Make service instance name unique for multibackend installation
|
||||
name = "%s_%s" % (self.driver_config.config_group,
|
||||
share_server_id)
|
||||
name = "%s_%s" % (self.driver_config.config_group, share_server_id)
|
||||
else:
|
||||
name = share_server_id
|
||||
return self.get_config_option("service_instance_name_template") % name
|
||||
|
||||
def _get_server_ip(self, server):
|
||||
"""Returns service vms ip address."""
|
||||
net_name = self.get_config_option("service_network_name")
|
||||
def _get_server_ip(self, server, net_name):
|
||||
"""Returns service IP address of service instance."""
|
||||
net_ips = self._get_addresses_by_network_name(net_name, server)
|
||||
if not net_ips:
|
||||
msg = _("Failed to get service instance ip address. "
|
||||
msg = _("Failed to get service instance IP address. "
|
||||
"Service network name is '%(net_name)s' "
|
||||
"and provided data are '%(data)s'.")
|
||||
msg = msg % {'net_name': net_name, 'data': six.text_type(server)}
|
||||
@ -379,35 +374,39 @@ class ServiceInstanceManager(object):
|
||||
"Giving up.") % {
|
||||
'id': server_id, 's': self.max_time_to_build_instance})
|
||||
|
||||
def set_up_service_instance(self, context, instance_name, neutron_net_id,
|
||||
neutron_subnet_id):
|
||||
def set_up_service_instance(self, context, network_info):
|
||||
"""Finds or creates and sets up service vm.
|
||||
|
||||
:param context: defines context, that should be used
|
||||
:param instance_name: provides name for service VM
|
||||
:param neutron_net_id: provides network id for service VM
|
||||
:param neutron_subnet_id: provides subnet id for service VM
|
||||
:param network_info: network info for getting allocations
|
||||
:returns: dict with service instance details
|
||||
:raises: exception.ServiceInstanceException
|
||||
"""
|
||||
instance_name = network_info['server_id']
|
||||
server = self._create_service_instance(
|
||||
context, instance_name, neutron_net_id, neutron_subnet_id)
|
||||
|
||||
context, instance_name, network_info)
|
||||
instance_details = {
|
||||
'instance_id': server['id'],
|
||||
'ip': server['ip'],
|
||||
'pk_path': server['pk_path'],
|
||||
'subnet_id': server['subnet_id'],
|
||||
'pk_path': server.get('pk_path'),
|
||||
'subnet_id': server.get('subnet_id'),
|
||||
'password': self.get_config_option('service_instance_password'),
|
||||
'username': self.get_config_option('service_instance_user'),
|
||||
'public_address': server['public_address'],
|
||||
}
|
||||
if 'router_id' in server:
|
||||
if server.get('router_id'):
|
||||
instance_details['router_id'] = server['router_id']
|
||||
for key in ('password', 'pk_path'):
|
||||
for key in ('password', 'pk_path', 'subnet_id'):
|
||||
if not instance_details[key]:
|
||||
instance_details.pop(key)
|
||||
|
||||
if not self._check_server_availability(server):
|
||||
raise exception.ServiceInstanceException(
|
||||
_('SSH connection has not been '
|
||||
'established to %(server)s in %(time)ss. Giving up.') % {
|
||||
'server': server['ip'],
|
||||
'time': self.max_time_to_build_instance})
|
||||
|
||||
return instance_details
|
||||
|
||||
@utils.synchronized("service_instance_get_key", external=True)
|
||||
@ -432,18 +431,17 @@ class ServiceInstanceManager(object):
|
||||
|
||||
public_key, __ = self._execute('cat', path_to_public_key)
|
||||
if not keypairs:
|
||||
keypair = self.compute_api.keypair_import(context,
|
||||
keypair_name,
|
||||
public_key)
|
||||
keypair = self.compute_api.keypair_import(
|
||||
context, keypair_name, public_key)
|
||||
else:
|
||||
keypair = keypairs[0]
|
||||
if keypair.public_key != public_key:
|
||||
LOG.debug('Public key differs from existing keypair. '
|
||||
'Creating new keypair.')
|
||||
self.compute_api.keypair_delete(context, keypair.id)
|
||||
keypair = self.compute_api.keypair_import(context,
|
||||
keypair_name,
|
||||
public_key)
|
||||
keypair = self.compute_api.keypair_import(
|
||||
context, keypair_name, public_key)
|
||||
|
||||
return keypair.name, path_to_private_key
|
||||
|
||||
def _get_service_image(self, context):
|
||||
@ -454,66 +452,55 @@ class ServiceInstanceManager(object):
|
||||
if len(images) == 1:
|
||||
return images[0]
|
||||
elif not images:
|
||||
raise exception.ServiceInstanceException(_('No appropriate '
|
||||
'image was found.'))
|
||||
raise exception.ServiceInstanceException(
|
||||
_("Image with name '%s' not found.") % service_image_name)
|
||||
else:
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Ambiguous image name.'))
|
||||
_("Found more than one image by name '%s'.") %
|
||||
service_image_name)
|
||||
|
||||
def _create_service_instance(self, context, instance_name, neutron_net_id,
|
||||
neutron_subnet_id):
|
||||
def _create_service_instance(self, context, instance_name, network_info):
|
||||
"""Creates service vm and sets up networking for it."""
|
||||
service_image_id = self._get_service_image(context)
|
||||
|
||||
with lock:
|
||||
key_name, key_path = self._get_key(context)
|
||||
if not (self.get_config_option("service_instance_password") or
|
||||
key_name):
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Neither service '
|
||||
'instance password nor key are available.'))
|
||||
_('Neither service instance password nor key are available.'))
|
||||
if not key_path:
|
||||
str_params = {
|
||||
'private_path': self.path_to_private_key,
|
||||
'public_path': self.path_to_public_key,
|
||||
}
|
||||
LOG.warning(_LW('No key path is available. May be '
|
||||
'non-existent key path is provided. Check '
|
||||
'path_to_private_key (current value '
|
||||
'%(private_path)s) and '
|
||||
'path_to_public_key (current value '
|
||||
'%(public_path)s) in manila '
|
||||
'configuration file.'), str_params)
|
||||
|
||||
security_group = self._get_or_create_security_group(context)
|
||||
network_data = self._setup_network_for_instance(neutron_net_id,
|
||||
neutron_subnet_id)
|
||||
LOG.warning(_LW(
|
||||
'No key path is available. May be non-existent key path is '
|
||||
'provided. Check path_to_private_key (current value '
|
||||
'%(private_path)s) and path_to_public_key (current value '
|
||||
'%(public_path)s) in manila configuration file.'), dict(
|
||||
private_path=self.path_to_private_key,
|
||||
public_path=self.path_to_public_key))
|
||||
network_data = self.network_helper.setup_network(network_info)
|
||||
fail_safe_data = dict(
|
||||
router_id=network_data.get('router_id'),
|
||||
subnet_id=network_data.get('subnet_id'))
|
||||
try:
|
||||
self._setup_connectivity_with_service_instances()
|
||||
except Exception as e:
|
||||
LOG.debug(e)
|
||||
for port in network_data['ports']:
|
||||
self.neutron_api.delete_port(port['id'])
|
||||
raise
|
||||
|
||||
service_instance = self.compute_api.server_create(
|
||||
context,
|
||||
name=instance_name,
|
||||
image=service_image_id,
|
||||
flavor=self.get_config_option("service_instance_flavor_id"),
|
||||
key_name=key_name,
|
||||
nics=[{'port-id': port['id']} for port in network_data['ports']])
|
||||
nics=network_data['nics'])
|
||||
|
||||
fail_safe_data['instance_id'] = service_instance['id']
|
||||
|
||||
t = time.time()
|
||||
while time.time() - t < self.max_time_to_build_instance:
|
||||
# NOTE(vponomaryov): emptiness of 'networks' field is checked as
|
||||
# NOTE(vponomaryov): emptiness of 'networks' field checked as
|
||||
# workaround for nova/neutron bug #1210483.
|
||||
if (service_instance['status'] == 'ACTIVE' and
|
||||
service_instance.get('networks', {})):
|
||||
break
|
||||
if service_instance['status'] == 'ERROR':
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Failed to build service instance.'))
|
||||
_("Failed to build service instance '%s'.") %
|
||||
service_instance['id'])
|
||||
time.sleep(1)
|
||||
try:
|
||||
service_instance = self.compute_api.server_get(
|
||||
@ -523,61 +510,163 @@ class ServiceInstanceManager(object):
|
||||
LOG.debug(e)
|
||||
else:
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Instance have not been spawned in %ss. Giving up.') %
|
||||
self.max_time_to_build_instance)
|
||||
_("Instance '%(ins)s' has not been spawned in %(timeout)s "
|
||||
"seconds. Giving up.") % dict(
|
||||
ins=service_instance['id'],
|
||||
timeout=self.max_time_to_build_instance))
|
||||
|
||||
security_group = self._get_or_create_security_group(context)
|
||||
if security_group:
|
||||
LOG.debug("Adding security group "
|
||||
"'%s' to server '%s'." % (security_group.id,
|
||||
service_instance["id"]))
|
||||
if self.network_helper.NAME == NOVA_NAME:
|
||||
# NOTE(vponomaryov): Nova-network allows to assign
|
||||
# secgroups only by names.
|
||||
sg_id = security_group.name
|
||||
else:
|
||||
sg_id = security_group.id
|
||||
LOG.debug(
|
||||
"Adding security group '%(sg)s' to server '%(si)s'.",
|
||||
dict(sg=sg_id, si=service_instance["id"]))
|
||||
self.compute_api.add_security_group_to_server(
|
||||
context,
|
||||
service_instance["id"], security_group.id)
|
||||
context, service_instance["id"], sg_id)
|
||||
|
||||
if self.network_helper.NAME == NEUTRON_NAME:
|
||||
service_instance['ip'] = self._get_server_ip(
|
||||
service_instance,
|
||||
self.get_config_option("service_network_name"))
|
||||
public_ip = network_data.get(
|
||||
'public_port', network_data['service_port'])['fixed_ips']
|
||||
service_instance['public_address'] = public_ip[0]['ip_address']
|
||||
else:
|
||||
net_name = self.network_helper.get_network_name(network_info)
|
||||
service_instance['ip'] = self._get_server_ip(
|
||||
service_instance, net_name)
|
||||
service_instance['public_address'] = service_instance['ip']
|
||||
|
||||
except Exception as e:
|
||||
e.detail_data = {'server_details': fail_safe_data}
|
||||
raise
|
||||
|
||||
service_instance['ip'] = self._get_server_ip(service_instance)
|
||||
service_instance['pk_path'] = key_path
|
||||
if 'router' in network_data and 'id' in network_data['router']:
|
||||
service_instance['router_id'] = network_data['router']['id']
|
||||
service_instance['subnet_id'] = network_data['service_subnet']['id']
|
||||
service_instance['port_id'] = network_data['service_port']['id']
|
||||
|
||||
try:
|
||||
public_ip = network_data['public_port']
|
||||
except KeyError:
|
||||
public_ip = network_data['service_port']
|
||||
public_ip = public_ip['fixed_ips']
|
||||
public_ip = public_ip[0]
|
||||
public_ip = public_ip['ip_address']
|
||||
|
||||
service_instance['public_address'] = public_ip
|
||||
|
||||
if not self._check_server_availability(service_instance):
|
||||
raise exception.ServiceInstanceException(
|
||||
_('SSH connection have not been '
|
||||
'established in %ss. Giving up.') %
|
||||
self.max_time_to_build_instance)
|
||||
for pair in [('router', 'router_id'), ('service_subnet', 'subnet_id')]:
|
||||
if pair[0] in network_data and 'id' in network_data[pair[0]]:
|
||||
service_instance[pair[1]] = network_data[pair[0]]['id']
|
||||
|
||||
return service_instance
|
||||
|
||||
def _check_server_availability(self, server):
|
||||
t = time.time()
|
||||
while time.time() - t < self.max_time_to_build_instance:
|
||||
LOG.debug('Checking service vm availablity.')
|
||||
LOG.debug('Checking service VM availablity.')
|
||||
try:
|
||||
socket.socket().connect((server['ip'], 22))
|
||||
LOG.debug('Service vm is available via ssh.')
|
||||
LOG.debug('Service VM is available via SSH.')
|
||||
return True
|
||||
except socket.error as e:
|
||||
LOG.debug(e)
|
||||
LOG.debug('Server is not available through ssh. Waiting...')
|
||||
LOG.debug("Server %s is not available via SSH. Waiting...",
|
||||
server['ip'])
|
||||
time.sleep(5)
|
||||
return False
|
||||
|
||||
def delete_service_instance(self, context, server_details):
|
||||
"""Removes share infrastructure.
|
||||
|
||||
Deletes service vm and subnet, associated to share network.
|
||||
"""
|
||||
instance_id = server_details.get("instance_id")
|
||||
self._delete_server(context, instance_id)
|
||||
self.network_helper.teardown_network(server_details)
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class BaseNetworkhelper(object):
|
||||
|
||||
@abc.abstractproperty
|
||||
def NAME(self):
|
||||
"""Returns code name of network helper."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def __init__(self, service_instance_manager):
|
||||
"""Instantiates class and its attrs."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_network_name(self, network_info):
|
||||
"""Returns name of network for service instance."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def setup_connectivity_with_service_instances(self):
|
||||
"""Sets up connectivity between Manila host and service instances."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def setup_network(self, network_info):
|
||||
"""Sets up network for service instance."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def teardown_network(self, server_details):
|
||||
"""Teardowns network resources provided for service instance."""
|
||||
|
||||
|
||||
class NeutronNetworkHelper(BaseNetworkhelper):
|
||||
|
||||
def __init__(self, service_instance_manager):
|
||||
self.get_config_option = service_instance_manager.get_config_option
|
||||
self.vif_driver = importutils.import_class(
|
||||
self.get_config_option("interface_driver"))()
|
||||
self.neutron_api = neutron.API()
|
||||
self.service_network_id = self.get_service_network_id()
|
||||
self.connect_share_server_to_tenant_network = (
|
||||
self.get_config_option('connect_share_server_to_tenant_network'))
|
||||
|
||||
@property
|
||||
def NAME(self):
|
||||
return NEUTRON_NAME
|
||||
|
||||
@property
|
||||
def admin_project_id(self):
|
||||
return self.neutron_api.admin_project_id
|
||||
|
||||
def get_network_name(self, network_info):
|
||||
"""Returns name of network for service instance."""
|
||||
net = self.neutron_api.get_network(network_info['neutron_net_id'])
|
||||
return net['name']
|
||||
|
||||
@utils.synchronized("service_instance_get_service_network", external=True)
|
||||
def get_service_network_id(self):
|
||||
"""Finds existing or creates new service network."""
|
||||
service_network_name = self.get_config_option("service_network_name")
|
||||
networks = []
|
||||
for network in self.neutron_api.get_all_admin_project_networks():
|
||||
if network['name'] == service_network_name:
|
||||
networks.append(network)
|
||||
if len(networks) > 1:
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Ambiguous service networks.'))
|
||||
elif not networks:
|
||||
return self.neutron_api.network_create(
|
||||
self.admin_project_id, service_network_name)['id']
|
||||
else:
|
||||
return networks[0]['id']
|
||||
|
||||
def teardown_network(self, server_details):
|
||||
subnet_id = server_details.get("subnet_id")
|
||||
router_id = server_details.get("router_id")
|
||||
if router_id and subnet_id:
|
||||
try:
|
||||
self.neutron_api.router_remove_interface(
|
||||
router_id, subnet_id)
|
||||
except exception.NetworkException as e:
|
||||
if e.kwargs['code'] != 404:
|
||||
raise
|
||||
LOG.debug('Subnet %(subnet_id)s is not attached to the '
|
||||
'router %(router_id)s.',
|
||||
{'subnet_id': subnet_id, 'router_id': router_id})
|
||||
self.neutron_api.update_subnet(subnet_id, '')
|
||||
|
||||
@utils.synchronized(
|
||||
"service_instance_setup_network_for_instance", external=True)
|
||||
def _setup_network_for_instance(self, neutron_net_id, neutron_subnet_id):
|
||||
"""Sets up network for service vm."""
|
||||
|
||||
def setup_network(self, network_info):
|
||||
neutron_net_id = network_info['neutron_net_id']
|
||||
neutron_subnet_id = network_info['neutron_subnet_id']
|
||||
network_data = dict()
|
||||
subnet_name = ('service_subnet_for_handling_of_share_server_for_'
|
||||
'tenant_subnet_%s' % neutron_subnet_id)
|
||||
@ -585,9 +674,7 @@ class ServiceInstanceManager(object):
|
||||
network_data['service_subnet'] = self._get_service_subnet(subnet_name)
|
||||
if not network_data['service_subnet']:
|
||||
network_data['service_subnet'] = self.neutron_api.subnet_create(
|
||||
self.service_tenant_id,
|
||||
self.service_network_id,
|
||||
subnet_name,
|
||||
self.admin_project_id, self.service_network_id, subnet_name,
|
||||
self._get_cidr_for_subnet())
|
||||
|
||||
if not self.connect_share_server_to_tenant_network:
|
||||
@ -606,43 +693,47 @@ class ServiceInstanceManager(object):
|
||||
'router_id': network_data['router']['id']})
|
||||
|
||||
network_data['service_port'] = self.neutron_api.create_port(
|
||||
self.service_tenant_id,
|
||||
self.service_network_id,
|
||||
self.admin_project_id, self.service_network_id,
|
||||
subnet_id=network_data['service_subnet']['id'],
|
||||
device_owner='manila')
|
||||
|
||||
network_data['ports'] = [network_data['service_port']]
|
||||
if self.connect_share_server_to_tenant_network:
|
||||
network_data['public_port'] = self.neutron_api.create_port(
|
||||
self.service_tenant_id, neutron_net_id,
|
||||
self.admin_project_id, neutron_net_id,
|
||||
subnet_id=neutron_subnet_id, device_owner='manila')
|
||||
network_data['ports'].append(network_data['public_port'])
|
||||
|
||||
try:
|
||||
self.setup_connectivity_with_service_instances()
|
||||
except Exception as e:
|
||||
for port in network_data['ports']:
|
||||
self.neutron_api.delete_port(port['id'])
|
||||
raise
|
||||
|
||||
network_data['nics'] = [
|
||||
{'port-id': port['id']} for port in network_data['ports']]
|
||||
public_ip = network_data.get(
|
||||
'public_port', network_data['service_port'])
|
||||
network_data['ip_address'] = public_ip['fixed_ips'][0]['ip_address']
|
||||
|
||||
return network_data
|
||||
|
||||
@utils.synchronized("service_instance_get_private_router", external=True)
|
||||
def _get_private_router(self, neutron_net_id, neutron_subnet_id):
|
||||
"""Returns router attached to private subnet gateway."""
|
||||
private_subnet = self.neutron_api.get_subnet(neutron_subnet_id)
|
||||
if not private_subnet['gateway_ip']:
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Subnet must have gateway.'))
|
||||
private_network_ports = [p for p in self.neutron_api.list_ports(
|
||||
network_id=neutron_net_id)]
|
||||
for p in private_network_ports:
|
||||
fixed_ip = p['fixed_ips'][0]
|
||||
if (fixed_ip['subnet_id'] == private_subnet['id'] and
|
||||
fixed_ip['ip_address'] == private_subnet['gateway_ip']):
|
||||
private_subnet_gateway_port = p
|
||||
break
|
||||
def _get_cidr_for_subnet(self):
|
||||
"""Returns not used cidr for service subnet creating."""
|
||||
subnets = self._get_all_service_subnets()
|
||||
used_cidrs = set(subnet['cidr'] for subnet in subnets)
|
||||
serv_cidr = netaddr.IPNetwork(
|
||||
self.get_config_option("service_network_cidr"))
|
||||
division_mask = self.get_config_option("service_network_division_mask")
|
||||
for subnet in serv_cidr.subnet(division_mask):
|
||||
cidr = six.text_type(subnet.cidr)
|
||||
if cidr not in used_cidrs:
|
||||
return cidr
|
||||
else:
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Subnet gateway is not attached the router.'))
|
||||
private_subnet_router = self.neutron_api.show_router(
|
||||
private_subnet_gateway_port['device_id'])
|
||||
return private_subnet_router
|
||||
raise exception.ServiceInstanceException(_('No available cidrs.'))
|
||||
|
||||
def _setup_connectivity_with_service_instances(self):
|
||||
def setup_connectivity_with_service_instances(self):
|
||||
"""Sets up connectivity with service instances.
|
||||
|
||||
Creates creating port in service network, creating and setting up
|
||||
@ -672,21 +763,19 @@ class ServiceInstanceManager(object):
|
||||
"service_instance_remove_outdated_interfaces", external=True)
|
||||
def _remove_outdated_interfaces(self, device):
|
||||
"""Finds and removes unused network device."""
|
||||
list_dev = []
|
||||
device_cidr_set = self._get_set_of_device_cidrs(device)
|
||||
for dev in ip_lib.IPWrapper().get_devices():
|
||||
if dev.name != device.name and dev.name[:3] == device.name[:3]:
|
||||
cidr_set = set()
|
||||
for a in dev.addr.list():
|
||||
if a['ip_version'] == 4:
|
||||
cidr_set.add(str(netaddr.IPNetwork(a['cidr']).cidr))
|
||||
list_dev.append((dev.name, cidr_set))
|
||||
device_cidr_set = set(str(netaddr.IPNetwork(a['cidr']).cidr)
|
||||
for a in device.addr.list()
|
||||
if a['ip_version'] == 4)
|
||||
|
||||
for dev_name, cidr_set in list_dev:
|
||||
cidr_set = self._get_set_of_device_cidrs(dev)
|
||||
if device_cidr_set & cidr_set:
|
||||
self.vif_driver.unplug(dev_name)
|
||||
self.vif_driver.unplug(dev.name)
|
||||
|
||||
def _get_set_of_device_cidrs(self, device):
|
||||
cidrs = set()
|
||||
for addr in device.addr.list():
|
||||
if addr['ip_version'] == 4:
|
||||
cidrs.add(six.text_type(netaddr.IPNetwork(addr['cidr']).cidr))
|
||||
return cidrs
|
||||
|
||||
@utils.synchronized("service_instance_get_service_port", external=True)
|
||||
def _get_service_port(self):
|
||||
@ -700,17 +789,10 @@ class ServiceInstanceManager(object):
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Error. Ambiguous service ports.'))
|
||||
elif not ports:
|
||||
try:
|
||||
stdout, stderr = self._execute('hostname')
|
||||
host = stdout.strip()
|
||||
except exception.ProcessExecutionError as e:
|
||||
msg = _('Unable to get host. %s') % e.stderr
|
||||
raise exception.ManilaException(msg)
|
||||
host = socket.gethostname()
|
||||
port = self.neutron_api.create_port(
|
||||
self.service_tenant_id,
|
||||
self.service_network_id,
|
||||
device_id='manila-share',
|
||||
device_owner='manila:share',
|
||||
self.admin_project_id, self.service_network_id,
|
||||
device_id='manila-share', device_owner='manila:share',
|
||||
host_id=host)
|
||||
else:
|
||||
port = ports[0]
|
||||
@ -737,46 +819,27 @@ class ServiceInstanceManager(object):
|
||||
|
||||
return port
|
||||
|
||||
def _get_cidr_for_subnet(self):
|
||||
"""Returns not used cidr for service subnet creating."""
|
||||
subnets = self._get_all_service_subnets()
|
||||
used_cidrs = set(subnet['cidr'] for subnet in subnets)
|
||||
serv_cidr = netaddr.IPNetwork(
|
||||
self.get_config_option("service_network_cidr"))
|
||||
division_mask = self.get_config_option("service_network_division_mask")
|
||||
for subnet in serv_cidr.subnet(division_mask):
|
||||
cidr = str(subnet.cidr)
|
||||
if cidr not in used_cidrs:
|
||||
return cidr
|
||||
@utils.synchronized("service_instance_get_private_router", external=True)
|
||||
def _get_private_router(self, neutron_net_id, neutron_subnet_id):
|
||||
"""Returns router attached to private subnet gateway."""
|
||||
private_subnet = self.neutron_api.get_subnet(neutron_subnet_id)
|
||||
if not private_subnet['gateway_ip']:
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Subnet must have gateway.'))
|
||||
private_network_ports = [p for p in self.neutron_api.list_ports(
|
||||
network_id=neutron_net_id)]
|
||||
for p in private_network_ports:
|
||||
fixed_ip = p['fixed_ips'][0]
|
||||
if (fixed_ip['subnet_id'] == private_subnet['id'] and
|
||||
fixed_ip['ip_address'] == private_subnet['gateway_ip']):
|
||||
private_subnet_gateway_port = p
|
||||
break
|
||||
else:
|
||||
raise exception.ServiceInstanceException(_('No available cidrs.'))
|
||||
|
||||
def delete_service_instance(self, context, instance_id, subnet_id,
|
||||
router_id=None):
|
||||
"""Removes share infrastructure.
|
||||
|
||||
Deletes service vm and subnet, associated to share network.
|
||||
"""
|
||||
self._delete_server(context, instance_id)
|
||||
if router_id and subnet_id:
|
||||
try:
|
||||
self.neutron_api.router_remove_interface(router_id,
|
||||
subnet_id)
|
||||
except exception.NetworkException as e:
|
||||
if e.kwargs['code'] != 404:
|
||||
raise
|
||||
LOG.debug('Subnet %(subnet_id)s is not attached to the '
|
||||
'router %(router_id)s.',
|
||||
{'subnet_id': subnet_id,
|
||||
'router_id': router_id})
|
||||
self.neutron_api.update_subnet(subnet_id, '')
|
||||
|
||||
@utils.synchronized(
|
||||
"service_instance_get_all_service_subnets", external=True)
|
||||
def _get_all_service_subnets(self):
|
||||
service_network = self.neutron_api.get_network(self.service_network_id)
|
||||
return [self.neutron_api.get_subnet(subnet_id)
|
||||
for subnet_id in service_network['subnets']]
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Subnet gateway is not attached to the router.'))
|
||||
private_subnet_router = self.neutron_api.show_router(
|
||||
private_subnet_gateway_port['device_id'])
|
||||
return private_subnet_router
|
||||
|
||||
@utils.synchronized("service_instance_get_service_subnet", external=True)
|
||||
def _get_service_subnet(self, subnet_name):
|
||||
@ -790,10 +853,66 @@ class ServiceInstanceManager(object):
|
||||
if subnet['name'] == '']
|
||||
if unused_service_subnets:
|
||||
service_subnet = unused_service_subnets[0]
|
||||
self.neutron_api.update_subnet(service_subnet['id'],
|
||||
subnet_name)
|
||||
self.neutron_api.update_subnet(
|
||||
service_subnet['id'], subnet_name)
|
||||
return service_subnet
|
||||
return None
|
||||
else:
|
||||
raise exception.ServiceInstanceException(_('Ambiguous service '
|
||||
'subnets.'))
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Ambiguous service subnets.'))
|
||||
|
||||
@utils.synchronized(
|
||||
"service_instance_get_all_service_subnets", external=True)
|
||||
def _get_all_service_subnets(self):
|
||||
service_network = self.neutron_api.get_network(self.service_network_id)
|
||||
subnets = []
|
||||
for subnet_id in service_network['subnets']:
|
||||
subnets.append(self.neutron_api.get_subnet(subnet_id))
|
||||
return subnets
|
||||
|
||||
|
||||
class NovaNetworkHelper(BaseNetworkhelper):
|
||||
"""Nova network helper for Manila service instances.
|
||||
|
||||
All security-group rules are applied to all interfaces of Nova VM
|
||||
using Nova-network. In that case there is no need to create additional
|
||||
service network. Only one thing should be satisfied - Manila host
|
||||
should have access to all tenant networks.
|
||||
This network helper does not create resources.
|
||||
"""
|
||||
|
||||
def __init__(self, service_instance_manager):
|
||||
self.compute_api = service_instance_manager.compute_api
|
||||
self.admin_context = service_instance_manager.admin_context
|
||||
|
||||
@property
|
||||
def NAME(self):
|
||||
return NOVA_NAME
|
||||
|
||||
def setup_network(self, network_info):
|
||||
net = self._get_nova_network(network_info['nova_net_id'])
|
||||
network_info['nics'] = [{'net-id': net['id']}]
|
||||
return network_info
|
||||
|
||||
def get_network_name(self, network_info):
|
||||
"""Returns name of network for service instance."""
|
||||
return self._get_nova_network(network_info['nova_net_id'])['label']
|
||||
|
||||
def teardown_network(self, server_details):
|
||||
"""Nothing to do. Placeholder."""
|
||||
|
||||
def setup_connectivity_with_service_instances(self):
|
||||
"""Nothing to do. Placeholder."""
|
||||
|
||||
def _get_nova_network(self, nova_network_id):
|
||||
"""Returns network to be used for service instance.
|
||||
|
||||
:param nova_network_id: string with id of network.
|
||||
:returns: dict -- network data as dict
|
||||
:raises: exception.ManilaException
|
||||
"""
|
||||
if not nova_network_id:
|
||||
raise exception.ManilaException(
|
||||
_('Nova network for service instance is not provided.'))
|
||||
net = self.compute_api.network_get(self.admin_context, nova_network_id)
|
||||
return net
|
||||
|
@ -469,6 +469,7 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
'cidr': share_network['cidr'],
|
||||
'neutron_net_id': share_network['neutron_net_id'],
|
||||
'neutron_subnet_id': share_network['neutron_subnet_id'],
|
||||
'nova_net_id': share_network['nova_net_id'],
|
||||
'security_services': share_network['security_services'],
|
||||
'network_allocations': network_allocations,
|
||||
'backend_details': share_server.get('backend_details'),
|
||||
@ -485,14 +486,13 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
share_network = self.db.share_network_get(
|
||||
context, share_server['share_network_id'])
|
||||
|
||||
network_info = self._form_server_setup_info(context, share_server,
|
||||
share_network)
|
||||
server_info = self.driver.setup_server(network_info,
|
||||
metadata=metadata)
|
||||
network_info = self._form_server_setup_info(
|
||||
context, share_server, share_network)
|
||||
server_info = self.driver.setup_server(
|
||||
network_info, metadata=metadata)
|
||||
if server_info and isinstance(server_info, dict):
|
||||
self.db.share_server_backend_details_set(context,
|
||||
share_server['id'],
|
||||
server_info)
|
||||
self.db.share_server_backend_details_set(
|
||||
context, share_server['id'], server_info)
|
||||
return self.db.share_server_update(
|
||||
context, share_server['id'],
|
||||
{'status': constants.STATUS_ACTIVE})
|
||||
|
@ -30,6 +30,12 @@ class Volume(object):
|
||||
self.name = volume_id
|
||||
|
||||
|
||||
class Network(object):
|
||||
def __init__(self, net_id):
|
||||
self.id = net_id
|
||||
self.label = 'fake_label_%s' % net_id
|
||||
|
||||
|
||||
class FakeNovaClient(object):
|
||||
class Servers(object):
|
||||
def get(self, instance_id):
|
||||
@ -57,10 +63,15 @@ class FakeNovaClient(object):
|
||||
def __getattr__(self, item):
|
||||
return None
|
||||
|
||||
class Networks(object):
|
||||
def get(self, net_id):
|
||||
return Network(net_id)
|
||||
|
||||
def __init__(self):
|
||||
self.servers = self.Servers()
|
||||
self.volumes = self.Volumes()
|
||||
self.keypairs = self.servers
|
||||
self.networks = self.Networks()
|
||||
|
||||
|
||||
class NovaApiTestCase(test.TestCase):
|
||||
@ -209,3 +220,42 @@ class NovaApiTestCase(test.TestCase):
|
||||
def test_keypair_list(self):
|
||||
self.assertEqual([{'id': 'id1'}, {'id': 'id2'}],
|
||||
self.api.keypair_list(self.ctx))
|
||||
|
||||
def test_network_get(self):
|
||||
net_id = 'fake_net_id'
|
||||
net = self.api.network_get(self.ctx, net_id)
|
||||
self.assertTrue(isinstance(net, dict))
|
||||
self.assertEqual(net_id, net['id'])
|
||||
|
||||
|
||||
class ToDictTestCase(test.TestCase):
|
||||
|
||||
def test_dict_provided(self):
|
||||
fake_dict = {'foo_key': 'foo_value', 'bar_key': 'bar_value'}
|
||||
result = nova._to_dict(fake_dict)
|
||||
self.assertEqual(fake_dict, result)
|
||||
|
||||
def test_obj_provided_with_to_dict_method(self):
|
||||
expected = {'foo': 'bar'}
|
||||
|
||||
class FakeObj(object):
|
||||
def __init__(self):
|
||||
self.fake_attr = 'fake_attr_value'
|
||||
|
||||
def to_dict(self):
|
||||
return expected
|
||||
|
||||
fake_obj = FakeObj()
|
||||
result = nova._to_dict(fake_obj)
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_obj_provided_without_to_dict_method(self):
|
||||
expected = {'foo': 'bar'}
|
||||
|
||||
class FakeObj(object):
|
||||
def __init__(self):
|
||||
self.foo = expected['foo']
|
||||
|
||||
fake_obj = FakeObj()
|
||||
result = nova._to_dict(fake_obj)
|
||||
self.assertEqual(expected, result)
|
||||
|
@ -72,9 +72,27 @@ class FakeRouter(object):
|
||||
setattr(self, attr, value)
|
||||
|
||||
|
||||
class FakeDeviceAddr(object):
|
||||
def __init__(self, list_of_addresses=None):
|
||||
self.addresses = list_of_addresses or [
|
||||
dict(ip_version=4, cidr='1.0.0.0/27'),
|
||||
dict(ip_version=4, cidr='2.0.0.0/27'),
|
||||
dict(ip_version=6, cidr='3.0.0.0/27'),
|
||||
]
|
||||
|
||||
def list(self):
|
||||
return self.addresses
|
||||
|
||||
|
||||
class FakeDevice(object):
|
||||
def __init__(self, name=None, list_of_addresses=None):
|
||||
self.addr = FakeDeviceAddr(list_of_addresses)
|
||||
self.name = name or 'fake_device_name'
|
||||
|
||||
|
||||
class API(object):
|
||||
"""Fake Network API."""
|
||||
admin_tenant_id = 'fake admin tenant id'
|
||||
admin_project_id = 'fake_admin_project_id'
|
||||
|
||||
network = {
|
||||
"status": "ACTIVE",
|
||||
@ -105,13 +123,13 @@ class API(object):
|
||||
"device_id": "fake_device_id"
|
||||
}
|
||||
|
||||
def get_all_tenant_networks(self, tenant_id):
|
||||
def get_all_admin_project_networks(self):
|
||||
net1 = self.network.copy()
|
||||
net1['tenant_id'] = tenant_id
|
||||
net1['tenant_id'] = self.admin_project_id
|
||||
net1['id'] = str(uuid.uuid4())
|
||||
|
||||
net2 = self.network.copy()
|
||||
net2['tenant_id'] = tenant_id
|
||||
net2['tenant_id'] = self.admin_project_id
|
||||
net2['id'] = str(uuid.uuid4())
|
||||
return [net1, net2]
|
||||
|
||||
|
@ -566,3 +566,65 @@ class NeutronApiTest(test.TestCase):
|
||||
self.neutron_api.client.add_interface_router.assert_called_once_with(
|
||||
router_id, {'subnet_id': subnet_id, 'port_id': port_id})
|
||||
self.assertTrue(clientv20.Client.called)
|
||||
|
||||
def test_admin_project_id_exist(self):
|
||||
fake_admin_project_id = 'fake_admin_project_id_value'
|
||||
self.neutron_api.client.httpclient = mock.Mock()
|
||||
self.neutron_api.client.httpclient.auth_token = mock.Mock()
|
||||
self.neutron_api.client.httpclient.auth_tenant_id = (
|
||||
fake_admin_project_id)
|
||||
|
||||
admin_project_id = self.neutron_api.admin_project_id
|
||||
|
||||
self.assertEqual(fake_admin_project_id, admin_project_id)
|
||||
self.neutron_api.client.httpclient.auth_token.called
|
||||
|
||||
def test_admin_project_id_not_exist(self):
|
||||
fake_admin_project_id = 'fake_admin_project_id_value'
|
||||
self.neutron_api.client.httpclient = mock.Mock()
|
||||
self.neutron_api.client.httpclient.auth_token = mock.Mock(
|
||||
return_value=None)
|
||||
self.neutron_api.client.httpclient.authenticate = mock.Mock()
|
||||
self.neutron_api.client.httpclient.auth_tenant_id = (
|
||||
fake_admin_project_id)
|
||||
|
||||
admin_project_id = self.neutron_api.admin_project_id
|
||||
|
||||
self.assertEqual(fake_admin_project_id, admin_project_id)
|
||||
self.neutron_api.client.httpclient.auth_token.called
|
||||
self.neutron_api.client.httpclient.authenticate.called
|
||||
|
||||
def test_admin_project_id_not_exist_with_failure(self):
|
||||
self.neutron_api.client.httpclient = mock.Mock()
|
||||
self.neutron_api.client.httpclient.auth_token = None
|
||||
self.neutron_api.client.httpclient.authenticate = mock.Mock(
|
||||
side_effect=neutron_client_exc.NeutronClientException)
|
||||
self.neutron_api.client.httpclient.auth_tenant_id = mock.Mock()
|
||||
|
||||
try:
|
||||
self.neutron_api.admin_project_id
|
||||
except exception.NetworkException:
|
||||
pass
|
||||
else:
|
||||
raise Exception('Expected error was not raised')
|
||||
|
||||
self.assertTrue(self.neutron_api.client.httpclient.authenticate.called)
|
||||
self.assertFalse(
|
||||
self.neutron_api.client.httpclient.auth_tenant_id.called)
|
||||
|
||||
def test_get_all_admin_project_networks(self):
|
||||
fake_networks = {'networks': ['fake_net_1', 'fake_net_2']}
|
||||
self.mock_object(
|
||||
self.neutron_api.client, 'list_networks',
|
||||
mock.Mock(return_value=fake_networks))
|
||||
self.neutron_api.client.httpclient = mock.Mock()
|
||||
self.neutron_api.client.httpclient.auth_token = mock.Mock()
|
||||
self.neutron_api.client.httpclient.auth_tenant_id = mock.Mock()
|
||||
|
||||
networks = self.neutron_api.get_all_admin_project_networks()
|
||||
|
||||
self.assertEqual(fake_networks['networks'], networks)
|
||||
self.neutron_api.client.httpclient.auth_token.called
|
||||
self.neutron_api.client.httpclient.auth_tenant_id.called
|
||||
self.neutron_api.client.list_networks.assert_called_once_with(
|
||||
tenant_id=self.neutron_api.admin_project_id, shared=False)
|
||||
|
@ -861,15 +861,14 @@ class GenericShareDriverTestCase(test.TestCase):
|
||||
|
||||
def test__setup_server(self):
|
||||
sim = self._driver.instance_manager
|
||||
net_info = {'server_id': 'fake',
|
||||
net_info = {
|
||||
'server_id': 'fake',
|
||||
'neutron_net_id': 'fake-net-id',
|
||||
'neutron_subnet_id': 'fake-subnet-id'}
|
||||
'neutron_subnet_id': 'fake-subnet-id',
|
||||
}
|
||||
self._driver.setup_server(net_info)
|
||||
sim.set_up_service_instance.assert_called_once_with(
|
||||
self._context,
|
||||
'fake',
|
||||
'fake-net-id',
|
||||
'fake-subnet-id')
|
||||
self._context, net_info)
|
||||
|
||||
def test__setup_server_revert(self):
|
||||
|
||||
@ -895,8 +894,7 @@ class GenericShareDriverTestCase(test.TestCase):
|
||||
self._driver.teardown_server(server_details)
|
||||
self._driver.service_instance_manager.delete_service_instance.\
|
||||
assert_called_once_with(
|
||||
self._driver.admin_context, server_details['instance_id'],
|
||||
server_details['subnet_id'], server_details['router_id'])
|
||||
self._driver.admin_context, server_details)
|
||||
|
||||
def test_ssh_exec_connection_not_exist(self):
|
||||
ssh_output = 'fake_ssh_output'
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1001,3 +1001,35 @@ class ShareManagerTestCase(test.TestCase):
|
||||
get_admin_context(),
|
||||
fake_share)
|
||||
self.assertEqual(1, mock_LOG.error.call_count)
|
||||
|
||||
def test__form_server_setup_info(self):
|
||||
fake_network_allocations = ['foo', 'bar']
|
||||
self.mock_object(
|
||||
self.share_manager.db, 'network_allocations_get_for_share_server',
|
||||
mock.Mock(return_value=fake_network_allocations))
|
||||
fake_share_server = dict(
|
||||
id='fake_share_server_id', backend_details=dict(foo='bar'))
|
||||
fake_share_network = dict(
|
||||
segmentation_id='fake_segmentation_id',
|
||||
cidr='fake_cidr',
|
||||
neutron_net_id='fake_neutron_net_id',
|
||||
neutron_subnet_id='fake_neutron_subnet_id',
|
||||
nova_net_id='fake_nova_net_id',
|
||||
security_services='fake_security_services')
|
||||
expected = dict(
|
||||
server_id=fake_share_server['id'],
|
||||
segmentation_id=fake_share_network['segmentation_id'],
|
||||
cidr=fake_share_network['cidr'],
|
||||
neutron_net_id=fake_share_network['neutron_net_id'],
|
||||
neutron_subnet_id=fake_share_network['neutron_subnet_id'],
|
||||
nova_net_id=fake_share_network['nova_net_id'],
|
||||
security_services=fake_share_network['security_services'],
|
||||
network_allocations=fake_network_allocations,
|
||||
backend_details=fake_share_server['backend_details'])
|
||||
|
||||
network_info = self.share_manager._form_server_setup_info(
|
||||
self.context, fake_share_server, fake_share_network)
|
||||
|
||||
self.assertEqual(expected, network_info)
|
||||
self.share_manager.db.network_allocations_get_for_share_server.\
|
||||
assert_called_once_with(self.context, fake_share_server['id'])
|
||||
|
Loading…
Reference in New Issue
Block a user