Implement admin network in generic driver
Implemented admin network support in generic driver by creating extra ports in service instance. In order to implement admin export location, Admin must specify admin_network_id and admin_subnet_id in driver configuration in manila.conf to create ports between host and network of choice. Possible scenarios are covered by this change: *1: service network. *2: service network and tenant network. *3: service network and admin network. *4: tenant network and admin network. Admin network and tenant network configurations have higher priority than service network. If both are present, service network is not used. Only admin network export locations are is_admin_only = True. Included additional admin_only export location when creating shares and creating shares from snapshots. Removed deprecated 'service_ip' property of server backend details. Implements: blueprint admin-network-generic-driver Change-Id: I8d8694ac3d83aa12a756112dfefebd7e17e32383
This commit is contained in:
parent
86c05e9bf7
commit
447f2b1656
@ -268,25 +268,39 @@ function create_manila_service_keypair {
|
||||
# driver, and only if it is configured to mode without handling of share servers.
|
||||
function create_service_share_servers {
|
||||
private_net_id=$(nova net-list | grep ' private ' | get_field 1)
|
||||
created_admin_network=false
|
||||
for BE in ${MANILA_ENABLED_BACKENDS//,/ }; do
|
||||
driver_handles_share_servers=$(iniget $MANILA_CONF $BE driver_handles_share_servers)
|
||||
share_driver=$(iniget $MANILA_CONF $BE share_driver)
|
||||
generic_driver='manila.share.drivers.generic.GenericShareDriver'
|
||||
if [[ $(trueorfalse False driver_handles_share_servers) == False && $share_driver == $generic_driver ]]; then
|
||||
vm_name='manila_service_share_server_'$BE
|
||||
nova boot $vm_name \
|
||||
--flavor $MANILA_SERVICE_VM_FLAVOR_NAME \
|
||||
--image $MANILA_SERVICE_IMAGE_NAME \
|
||||
--nic net-id=$private_net_id \
|
||||
--security-groups $MANILA_SERVICE_SECGROUP \
|
||||
--key-name $MANILA_SERVICE_KEYPAIR_NAME
|
||||
if [[ $share_driver == $generic_driver ]]; then
|
||||
if [[ $(trueorfalse False driver_handles_share_servers) == False ]]; then
|
||||
vm_name='manila_service_share_server_'$BE
|
||||
nova boot $vm_name \
|
||||
--flavor $MANILA_SERVICE_VM_FLAVOR_NAME \
|
||||
--image $MANILA_SERVICE_IMAGE_NAME \
|
||||
--nic net-id=$private_net_id \
|
||||
--security-groups $MANILA_SERVICE_SECGROUP \
|
||||
--key-name $MANILA_SERVICE_KEYPAIR_NAME
|
||||
|
||||
vm_id=$(nova show $vm_name | grep ' id ' | get_field 2)
|
||||
vm_id=$(nova show $vm_name | grep ' id ' | get_field 2)
|
||||
|
||||
iniset $MANILA_CONF $BE service_instance_name_or_id $vm_id
|
||||
iniset $MANILA_CONF $BE service_net_name_or_ip private
|
||||
iniset $MANILA_CONF $BE tenant_net_name_or_ip private
|
||||
iniset $MANILA_CONF $BE migration_data_copy_node_ip $PUBLIC_NETWORK_GATEWAY
|
||||
iniset $MANILA_CONF $BE service_instance_name_or_id $vm_id
|
||||
iniset $MANILA_CONF $BE service_net_name_or_ip private
|
||||
iniset $MANILA_CONF $BE tenant_net_name_or_ip private
|
||||
iniset $MANILA_CONF $BE migration_data_copy_node_ip $PUBLIC_NETWORK_GATEWAY
|
||||
else
|
||||
if is_service_enabled neutron; then
|
||||
if [ $created_admin_network == false ]; then
|
||||
admin_net_id=$(neutron net-create --tenant-id $TENANT_ID admin_net | grep ' id ' | get_field 2)
|
||||
admin_subnet_id=$(neutron subnet-create --tenant-id $TENANT_ID --ip_version 4 --no-gateway --name admin_subnet --subnetpool None $admin_net_id $FIXED_RANGE | grep ' id ' | get_field 2)
|
||||
created_admin_network=true
|
||||
fi
|
||||
iniset $MANILA_CONF $BE admin_network_id $admin_net_id
|
||||
iniset $MANILA_CONF $BE admin_subnet_id $admin_subnet_id
|
||||
iniset $MANILA_CONF $BE migration_data_copy_node_ip $FIXED_RANGE
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
@ -237,7 +237,11 @@ class ShareMigrationFailed(ManilaException):
|
||||
|
||||
|
||||
class ServiceIPNotFound(ManilaException):
|
||||
message = _("Share migration failed: %(reason)s")
|
||||
message = _("Service IP for instance not found: %(reason)s")
|
||||
|
||||
|
||||
class AdminIPNotFound(ManilaException):
|
||||
message = _("Admin port IP for service instance not found: %(reason)s")
|
||||
|
||||
|
||||
class ShareServerNotCreated(ManilaException):
|
||||
|
@ -376,6 +376,52 @@ class IpRouteCommand(IpDeviceCommandBase):
|
||||
self._as_root('append', subnet, 'proto', 'kernel',
|
||||
'dev', device)
|
||||
|
||||
def clear_outdated_routes(self, cidr):
|
||||
"""Removes duplicated routes for a certain network CIDR.
|
||||
|
||||
Removes all routes related to supplied CIDR except for the one
|
||||
related to this interface device.
|
||||
|
||||
:param cidr: The network CIDR to be cleared.
|
||||
"""
|
||||
routes = self.list()
|
||||
items = [x for x in routes
|
||||
if x['Destination'] == cidr and x.get('Device') and
|
||||
x['Device'] != self.name]
|
||||
for item in items:
|
||||
self.delete_net_route(item['Destination'], item['Device'])
|
||||
|
||||
def list(self):
|
||||
"""List all routes
|
||||
|
||||
:return: A dictionary with field 'Destination' and 'Device' for each
|
||||
route entry. 'Gateway' field is included if route has a gateway.
|
||||
"""
|
||||
routes = []
|
||||
output = self._as_root('list')
|
||||
lines = output.split('\n')
|
||||
for line in lines:
|
||||
items = line.split()
|
||||
if len(items) > 0:
|
||||
item = {'Destination': items[0]}
|
||||
if len(items) > 1:
|
||||
if items[1] == 'via':
|
||||
item['Gateway'] = items[2]
|
||||
if len(items) > 3 and items[3] == 'dev':
|
||||
item['Device'] = items[4]
|
||||
if items[1] == 'dev':
|
||||
item['Device'] = items[2]
|
||||
routes.append(item)
|
||||
return routes
|
||||
|
||||
def delete_net_route(self, cidr, device):
|
||||
"""Deletes a route according to suplied CIDR and interface device.
|
||||
|
||||
:param cidr: The network CIDR to be removed.
|
||||
:param device: The network interface device to be removed.
|
||||
"""
|
||||
self._as_root('delete', cidr, 'dev', device)
|
||||
|
||||
|
||||
class IpNetnsCommand(IpCommandBase):
|
||||
COMMAND = 'netns'
|
||||
|
@ -340,21 +340,30 @@ class ShareDriver(object):
|
||||
"""
|
||||
return None, None
|
||||
|
||||
def get_driver_migration_info(self, context, share_instance, share_server):
|
||||
"""Is called to provide necessary driver migration logic."""
|
||||
def get_driver_migration_info(self, context, share, share_server):
|
||||
"""Is called to provide necessary driver migration logic.
|
||||
|
||||
:param context: The 'context.RequestContext' object for the request.
|
||||
:param share: Reference to the share being migrated.
|
||||
:param share_server: Share server model or None.
|
||||
:return: A dictionary with migration information.
|
||||
"""
|
||||
return None
|
||||
|
||||
def get_migration_info(self, context, share_instance, share_server):
|
||||
"""Is called to provide necessary generic migration logic."""
|
||||
def get_migration_info(self, context, share, share_server):
|
||||
"""Is called to provide necessary generic migration logic.
|
||||
|
||||
mount_cmd = self._get_mount_command(context, share_instance,
|
||||
share_server)
|
||||
:param context: The 'context.RequestContext' object for the request.
|
||||
:param share: Reference to the share being migrated.
|
||||
:param share_server: Share server model or None.
|
||||
:return: A dictionary with migration information.
|
||||
"""
|
||||
mount_cmd = self._get_mount_command(context, share, share_server)
|
||||
|
||||
umount_cmd = self._get_unmount_command(context, share_instance,
|
||||
share_server)
|
||||
umount_cmd = self._get_unmount_command(context, share, share_server)
|
||||
|
||||
access = self._get_access_rule_for_data_copy(
|
||||
context, share_instance, share_server)
|
||||
context, share, share_server)
|
||||
return {'mount': mount_cmd,
|
||||
'umount': umount_cmd,
|
||||
'access': access}
|
||||
@ -382,17 +391,18 @@ class ShareDriver(object):
|
||||
return ['mount', '-t', share_instance['share_proto'].lower()]
|
||||
|
||||
def _get_mount_ip(self, share_instance, share_server):
|
||||
# Note(ganso): DHSS = true drivers may need to override this method
|
||||
# and use information saved in share_server structure.
|
||||
mount_ip = self.configuration.safe_get('migration_mounting_backend_ip')
|
||||
old_ip = share_instance['export_locations'][0]['path']
|
||||
if mount_ip:
|
||||
# NOTE(ganso): Does not currently work with hostnames and ipv6.
|
||||
p = re.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")
|
||||
new_ip = p.sub(mount_ip, old_ip)
|
||||
return new_ip
|
||||
else:
|
||||
return old_ip
|
||||
|
||||
path = next((x['path'] for x in share_instance['export_locations']
|
||||
if x['is_admin_only']), None)
|
||||
if not path:
|
||||
mount_ip = self.configuration.safe_get(
|
||||
'migration_mounting_backend_ip')
|
||||
path = share_instance['export_locations'][0]['path']
|
||||
if mount_ip:
|
||||
# NOTE(ganso): Does not currently work with hostnames and ipv6.
|
||||
p = re.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")
|
||||
path = p.sub(mount_ip, path)
|
||||
return path
|
||||
|
||||
def _get_unmount_command(self, context, share_instance, share_server):
|
||||
return ['umount',
|
||||
|
@ -215,16 +215,6 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
||||
"No protocol helpers selected for Generic Driver. "
|
||||
"Please specify using config option 'share_helpers'.")
|
||||
|
||||
def _get_access_rule_for_data_copy(self, context, share, share_server):
|
||||
if not self.driver_handles_share_servers:
|
||||
service_ip = self.configuration.safe_get(
|
||||
'migration_data_copy_node_ip')
|
||||
else:
|
||||
service_ip = share_server['backend_details']['service_ip']
|
||||
return {'access_type': 'ip',
|
||||
'access_level': 'rw',
|
||||
'access_to': service_ip}
|
||||
|
||||
@ensure_server
|
||||
def create_share(self, context, share, share_server=None):
|
||||
"""Creates share."""
|
||||
@ -241,15 +231,28 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
||||
location = helper.create_export(
|
||||
server_details,
|
||||
share['name'])
|
||||
return {
|
||||
export_list = [{
|
||||
"path": location,
|
||||
"is_admin_only": False,
|
||||
"metadata": {
|
||||
# TODO(vponomaryov): remove this fake metadata when proper
|
||||
# appears.
|
||||
# TODO(vponomaryov): remove this fake metadata when
|
||||
# proper appears.
|
||||
"export_location_metadata_example": "example",
|
||||
},
|
||||
}
|
||||
}]
|
||||
if server_details.get('admin_ip'):
|
||||
admin_location = location.replace(
|
||||
server_details['public_address'], server_details['admin_ip'])
|
||||
export_list.append({
|
||||
"path": admin_location,
|
||||
"is_admin_only": True,
|
||||
"metadata": {
|
||||
# TODO(vponomaryov): remove this fake metadata when
|
||||
# proper appears.
|
||||
"export_location_metadata_example": "example",
|
||||
},
|
||||
})
|
||||
return export_list
|
||||
|
||||
@utils.retry(exception.ProcessExecutionError, backoff_rate=1)
|
||||
def _is_device_file_available(self, server_details, volume):
|
||||
@ -618,6 +621,7 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
||||
share_server=None):
|
||||
"""Is called to create share from snapshot."""
|
||||
helper = self._get_helper(share)
|
||||
server_details = share_server['backend_details']
|
||||
volume = self._allocate_container(self.admin_context, share, snapshot)
|
||||
volume = self._attach_volume(
|
||||
self.admin_context, share,
|
||||
@ -625,7 +629,28 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
||||
self._mount_device(share, share_server['backend_details'], volume)
|
||||
location = helper.create_export(share_server['backend_details'],
|
||||
share['name'])
|
||||
return location
|
||||
export_list = [{
|
||||
"path": location,
|
||||
"is_admin_only": False,
|
||||
"metadata": {
|
||||
# TODO(vponomaryov): remove this fake metadata when
|
||||
# proper appears.
|
||||
"export_location_metadata_example": "example",
|
||||
},
|
||||
}]
|
||||
if server_details.get('admin_ip'):
|
||||
admin_location = location.replace(
|
||||
server_details['public_address'], server_details['admin_ip'])
|
||||
export_list.append({
|
||||
"path": admin_location,
|
||||
"is_admin_only": True,
|
||||
"metadata": {
|
||||
# TODO(vponomaryov): remove this fake metadata when
|
||||
# proper appears.
|
||||
"export_location_metadata_example": "example",
|
||||
},
|
||||
})
|
||||
return export_list
|
||||
|
||||
@ensure_server
|
||||
def extend_share(self, share, new_size, share_server=None):
|
||||
|
@ -106,7 +106,16 @@ share_servers_handling_mode_opts = [
|
||||
"service_instance_network_helper_type",
|
||||
default=NEUTRON_NAME,
|
||||
help="Allowed values are %s. " % [NOVA_NAME, NEUTRON_NAME] +
|
||||
"Only used if driver_handles_share_servers=True.")
|
||||
"Only used if driver_handles_share_servers=True."),
|
||||
cfg.StrOpt(
|
||||
"admin_network_id",
|
||||
help="ID of neutron network used to communicate with admin network,"
|
||||
" to create additional admin export locations on."),
|
||||
cfg.StrOpt(
|
||||
"admin_subnet_id",
|
||||
help="ID of neutron subnet used to communicate with admin network,"
|
||||
" to create additional admin export locations on. "
|
||||
"Related to 'admin_network_id'."),
|
||||
]
|
||||
|
||||
no_share_servers_handling_mode_opts = [
|
||||
@ -431,14 +440,18 @@ class ServiceInstanceManager(object):
|
||||
'password': self.get_config_option('service_instance_password'),
|
||||
'username': self.get_config_option('service_instance_user'),
|
||||
'public_address': server['public_address'],
|
||||
'service_ip': server['service_ip'],
|
||||
}
|
||||
if server.get('admin_ip'):
|
||||
instance_details['admin_ip'] = server['admin_ip']
|
||||
if server.get('router_id'):
|
||||
instance_details['router_id'] = server['router_id']
|
||||
if server.get('service_port_id'):
|
||||
instance_details['service_port_id'] = server['service_port_id']
|
||||
if server.get('public_port_id'):
|
||||
instance_details['public_port_id'] = server['public_port_id']
|
||||
if server.get('admin_port_id'):
|
||||
instance_details['admin_port_id'] = server['admin_port_id']
|
||||
|
||||
for key in ('password', 'pk_path', 'subnet_id'):
|
||||
if not instance_details[key]:
|
||||
instance_details.pop(key)
|
||||
@ -520,6 +533,9 @@ class ServiceInstanceManager(object):
|
||||
if network_data.get('public_port'):
|
||||
fail_safe_data['public_port_id'] = (
|
||||
network_data['public_port']['id'])
|
||||
if network_data.get('admin_port'):
|
||||
fail_safe_data['admin_port_id'] = (
|
||||
network_data['admin_port']['id'])
|
||||
try:
|
||||
create_kwargs = self._get_service_instance_create_kwargs()
|
||||
service_instance = self.compute_api.server_create(
|
||||
@ -553,11 +569,13 @@ class ServiceInstanceManager(object):
|
||||
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']
|
||||
ip = (network_data.get('service_port',
|
||||
network_data.get(
|
||||
'admin_port'))['fixed_ips'])
|
||||
service_instance['ip'] = ip[0]['ip_address']
|
||||
public_ip = (network_data.get(
|
||||
'public_port', network_data.get(
|
||||
'service_port'))['fixed_ips'])
|
||||
service_instance['public_address'] = public_ip[0]['ip_address']
|
||||
else:
|
||||
net_name = self.network_helper.get_network_name(network_info)
|
||||
@ -575,7 +593,15 @@ class ServiceInstanceManager(object):
|
||||
if pair[0] in network_data and 'id' in network_data[pair[0]]:
|
||||
service_instance[pair[1]] = network_data[pair[0]]['id']
|
||||
|
||||
service_instance['service_ip'] = network_data.get('service_ip')
|
||||
admin_port = network_data.get('admin_port')
|
||||
if admin_port:
|
||||
try:
|
||||
service_instance['admin_ip'] = (
|
||||
admin_port['fixed_ips'][0]['ip_address'])
|
||||
except Exception:
|
||||
msg = _("Admin port is being used but Admin IP was not found.")
|
||||
LOG.exception(msg)
|
||||
raise exception.AdminIPNotFound(reason=msg)
|
||||
|
||||
return service_instance
|
||||
|
||||
@ -700,11 +726,21 @@ class NeutronNetworkHelper(BaseNetworkhelper):
|
||||
else:
|
||||
self._network_config_group = None
|
||||
|
||||
self.use_admin_port = False
|
||||
self.use_service_network = True
|
||||
self._neutron_api = None
|
||||
self._service_network_id = None
|
||||
self.connect_share_server_to_tenant_network = (
|
||||
self.get_config_option('connect_share_server_to_tenant_network'))
|
||||
|
||||
self.admin_network_id = self.get_config_option('admin_network_id')
|
||||
self.admin_subnet_id = self.get_config_option('admin_subnet_id')
|
||||
|
||||
if self.admin_network_id and self.admin_subnet_id:
|
||||
self.use_admin_port = True
|
||||
if self.use_admin_port and self.connect_share_server_to_tenant_network:
|
||||
self.use_service_network = False
|
||||
|
||||
@property
|
||||
def NAME(self):
|
||||
return NEUTRON_NAME
|
||||
@ -759,7 +795,8 @@ class NeutronNetworkHelper(BaseNetworkhelper):
|
||||
|
||||
service_port_id = server_details.get("service_port_id")
|
||||
public_port_id = server_details.get("public_port_id")
|
||||
for port_id in (service_port_id, public_port_id):
|
||||
admin_port_id = server_details.get("admin_port_id")
|
||||
for port_id in (service_port_id, public_port_id, admin_port_id):
|
||||
if port_id:
|
||||
try:
|
||||
self.neutron_api.delete_port(port_id)
|
||||
@ -810,11 +847,16 @@ class NeutronNetworkHelper(BaseNetworkhelper):
|
||||
subnet_name = ('service_subnet_for_handling_of_share_server_for_'
|
||||
'tenant_subnet_%s' % neutron_subnet_id)
|
||||
|
||||
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.admin_project_id, self.service_network_id, subnet_name,
|
||||
self._get_cidr_for_subnet())
|
||||
if self.use_service_network:
|
||||
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.admin_project_id, self.service_network_id,
|
||||
subnet_name, self._get_cidr_for_subnet()))
|
||||
|
||||
network_data['ports'] = []
|
||||
|
||||
if not self.connect_share_server_to_tenant_network:
|
||||
network_data['router'] = self._get_private_router(
|
||||
@ -830,24 +872,28 @@ class NeutronNetworkHelper(BaseNetworkhelper):
|
||||
'router %(router_id)s.',
|
||||
{'subnet_id': network_data['service_subnet']['id'],
|
||||
'router_id': network_data['router']['id']})
|
||||
|
||||
network_data['service_port'] = self.neutron_api.create_port(
|
||||
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:
|
||||
else:
|
||||
network_data['public_port'] = self.neutron_api.create_port(
|
||||
self.admin_project_id, neutron_net_id,
|
||||
subnet_id=neutron_subnet_id, device_owner='manila')
|
||||
network_data['ports'].append(network_data['public_port'])
|
||||
|
||||
if self.use_service_network:
|
||||
network_data['service_port'] = self.neutron_api.create_port(
|
||||
self.admin_project_id, self.service_network_id,
|
||||
subnet_id=network_data['service_subnet']['id'],
|
||||
device_owner='manila')
|
||||
network_data['ports'].append(network_data['service_port'])
|
||||
|
||||
if self.use_admin_port:
|
||||
network_data['admin_port'] = self.neutron_api.create_port(
|
||||
self.admin_project_id, self.admin_network_id,
|
||||
subnet_id=self.admin_subnet_id, device_owner='manila')
|
||||
network_data['ports'].append(network_data['admin_port'])
|
||||
|
||||
try:
|
||||
port = self.setup_connectivity_with_service_instances()
|
||||
service_ip = self._get_service_ip(
|
||||
port, network_data['service_subnet']['id'])
|
||||
except Exception as e:
|
||||
self.setup_connectivity_with_service_instances()
|
||||
except Exception:
|
||||
for port in network_data['ports']:
|
||||
self.neutron_api.delete_port(port['id'])
|
||||
raise
|
||||
@ -855,19 +901,11 @@ class NeutronNetworkHelper(BaseNetworkhelper):
|
||||
network_data['nics'] = [
|
||||
{'port-id': port['id']} for port in network_data['ports']]
|
||||
public_ip = network_data.get(
|
||||
'public_port', network_data['service_port'])
|
||||
'public_port', network_data.get('service_port'))
|
||||
network_data['ip_address'] = public_ip['fixed_ips'][0]['ip_address']
|
||||
network_data['service_ip'] = service_ip
|
||||
|
||||
return network_data
|
||||
|
||||
def _get_service_ip(self, port, subnet_id):
|
||||
for fixed_ips in port['fixed_ips']:
|
||||
if subnet_id == fixed_ips['subnet_id']:
|
||||
return fixed_ips['ip_address']
|
||||
msg = _("Service IP not found for Share Server.")
|
||||
raise exception.ServiceIPNotFound(reason=msg)
|
||||
|
||||
def _get_cidr_for_subnet(self):
|
||||
"""Returns not used cidr for service subnet creating."""
|
||||
subnets = self._get_all_service_subnets()
|
||||
@ -885,12 +923,30 @@ class NeutronNetworkHelper(BaseNetworkhelper):
|
||||
def setup_connectivity_with_service_instances(self):
|
||||
"""Sets up connectivity with service instances.
|
||||
|
||||
Creates creating port in service network, creating and setting up
|
||||
required network devices.
|
||||
Creates host port in service network and/or admin network, creating
|
||||
and setting up required network devices.
|
||||
"""
|
||||
port = self._get_service_port()
|
||||
port = self._add_fixed_ips_to_service_port(port)
|
||||
interface_name = self.vif_driver.get_device_name(port)
|
||||
if self.use_service_network:
|
||||
port = self._get_service_port(
|
||||
self.service_network_id, None, 'manila-share')
|
||||
port = self._add_fixed_ips_to_service_port(port)
|
||||
interface_name = self.vif_driver.get_device_name(port)
|
||||
device = ip_lib.IPDevice(interface_name)
|
||||
self._plug_interface_in_host(interface_name, device, port)
|
||||
|
||||
if self.use_admin_port:
|
||||
port = self._get_service_port(
|
||||
self.admin_network_id, self.admin_subnet_id,
|
||||
'manila-admin-share')
|
||||
interface_name = self.vif_driver.get_device_name(port)
|
||||
device = ip_lib.IPDevice(interface_name)
|
||||
for fixed_ip in port['fixed_ips']:
|
||||
subnet = self.neutron_api.get_subnet(fixed_ip['subnet_id'])
|
||||
device.route.clear_outdated_routes(subnet['cidr'])
|
||||
self._plug_interface_in_host(interface_name, device, port)
|
||||
|
||||
def _plug_interface_in_host(self, interface_name, device, port):
|
||||
|
||||
self.vif_driver.plug(interface_name, port['id'], port['mac_address'])
|
||||
ip_cidrs = []
|
||||
for fixed_ip in port['fixed_ips']:
|
||||
@ -902,14 +958,11 @@ class NeutronNetworkHelper(BaseNetworkhelper):
|
||||
self.vif_driver.init_l3(interface_name, ip_cidrs)
|
||||
|
||||
# ensure that interface is first in the list
|
||||
device = ip_lib.IPDevice(interface_name)
|
||||
device.route.pullup_route(interface_name)
|
||||
|
||||
# here we are checking for garbage devices from removed service port
|
||||
self._remove_outdated_interfaces(device)
|
||||
|
||||
return port
|
||||
|
||||
@utils.synchronized(
|
||||
"service_instance_remove_outdated_interfaces", external=True)
|
||||
def _remove_outdated_interfaces(self, device):
|
||||
@ -940,13 +993,13 @@ class NeutronNetworkHelper(BaseNetworkhelper):
|
||||
return cidrs
|
||||
|
||||
@utils.synchronized("service_instance_get_service_port", external=True)
|
||||
def _get_service_port(self):
|
||||
def _get_service_port(self, network_id, subnet_id, device_id):
|
||||
"""Find or creates service neutron port.
|
||||
|
||||
This port will be used for connectivity with service instances.
|
||||
"""
|
||||
host = socket.gethostname()
|
||||
search_opts = {'device_id': 'manila-share',
|
||||
search_opts = {'device_id': device_id,
|
||||
'binding:host_id': host}
|
||||
ports = [port for port in self.neutron_api.
|
||||
list_ports(**search_opts)]
|
||||
@ -955,9 +1008,8 @@ class NeutronNetworkHelper(BaseNetworkhelper):
|
||||
_('Error. Ambiguous service ports.'))
|
||||
elif not ports:
|
||||
port = self.neutron_api.create_port(
|
||||
self.admin_project_id, self.service_network_id,
|
||||
device_id='manila-share', device_owner='manila:share',
|
||||
host_id=host)
|
||||
self.admin_project_id, network_id, subnet_id=subnet_id,
|
||||
device_id=device_id, device_owner='manila:share', host_id=host)
|
||||
else:
|
||||
port = ports[0]
|
||||
return port
|
||||
@ -1056,7 +1108,6 @@ class NovaNetworkHelper(BaseNetworkhelper):
|
||||
def setup_network(self, network_info):
|
||||
net = self._get_nova_network(network_info['nova_net_id'])
|
||||
network_info['nics'] = [{'net-id': net['id']}]
|
||||
network_info['service_ip'] = net['gateway']
|
||||
return network_info
|
||||
|
||||
def get_network_name(self, network_info):
|
||||
|
@ -90,6 +90,14 @@ GATEWAY_SAMPLE4 = ("""
|
||||
default via 10.35.19.254
|
||||
""")
|
||||
|
||||
GATEWAY_SAMPLE5 = ("""
|
||||
default via 172.24.47.1 dev eth0
|
||||
10.0.0.0/24 dev tapc226b810-a0 proto kernel scope link src 10.0.0.3
|
||||
10.254.0.0/28 dev tap6de90453-1c proto kernel scope link src 10.254.0.4
|
||||
10.35.16.0/22 proto kernel scope link src 10.35.17.97
|
||||
172.24.4.0/24 via 10.35.19.254 metric 100
|
||||
""")
|
||||
|
||||
DEVICE_ROUTE_SAMPLE = ("10.0.0.0/24 scope link src 10.0.0.2")
|
||||
|
||||
SUBNET_SAMPLE1 = ("10.0.0.0/24 dev qr-23380d11-d2 scope link src 10.0.0.1\n"
|
||||
@ -619,6 +627,42 @@ class TestIpRouteCommand(TestIPCmdBase):
|
||||
# Check two calls - device get and subnet get
|
||||
self.assertEqual(2, len(self.parent._run.mock_calls))
|
||||
|
||||
def test_list(self):
|
||||
self.route_cmd._as_root = mock.Mock(return_value=GATEWAY_SAMPLE5)
|
||||
expected = [{'Destination': 'default',
|
||||
'Device': 'eth0',
|
||||
'Gateway': '172.24.47.1'},
|
||||
{'Destination': '10.0.0.0/24',
|
||||
'Device': 'tapc226b810-a0'},
|
||||
{'Destination': '10.254.0.0/28',
|
||||
'Device': 'tap6de90453-1c'},
|
||||
{'Destination': '10.35.16.0/22'},
|
||||
{'Destination': '172.24.4.0/24',
|
||||
'Gateway': '10.35.19.254'}]
|
||||
result = self.route_cmd.list()
|
||||
self.assertEqual(expected, result)
|
||||
self.route_cmd._as_root.assert_called_once_with('list')
|
||||
|
||||
def test_delete_net_route(self):
|
||||
self.route_cmd._as_root = mock.Mock()
|
||||
self.route_cmd.delete_net_route('10.0.0.0/24', 'br-ex')
|
||||
self.route_cmd._as_root.assert_called_once_with(
|
||||
'delete', '10.0.0.0/24', 'dev', 'br-ex')
|
||||
|
||||
def test_clear_outdated_routes(self):
|
||||
self.route_cmd.delete_net_route = mock.Mock()
|
||||
list_result = [{'Destination': 'default',
|
||||
'Device': 'eth0',
|
||||
'Gateway': '172.24.47.1'},
|
||||
{'Destination': '10.0.0.0/24',
|
||||
'Device': 'eth0'},
|
||||
{'Destination': '10.0.0.0/24',
|
||||
'Device': 'br-ex'}]
|
||||
self.route_cmd.list = mock.Mock(return_value=list_result)
|
||||
self.route_cmd.clear_outdated_routes('10.0.0.0/24')
|
||||
self.route_cmd.delete_net_route.assert_called_once_with(
|
||||
'10.0.0.0/24', 'br-ex')
|
||||
|
||||
|
||||
class TestIpNetnsCommand(TestIPCmdBase):
|
||||
def setUp(self):
|
||||
|
@ -313,29 +313,6 @@ class GenericShareDriverTestCase(test.TestCase):
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._driver._setup_helpers)
|
||||
|
||||
def test__get_access_rule_for_data_copy_dhss_true(self):
|
||||
get_access_return = {
|
||||
'access_level': 'rw',
|
||||
'access_to': 'fake_ip',
|
||||
'access_type': 'ip'
|
||||
}
|
||||
|
||||
result = self._driver._get_access_rule_for_data_copy(
|
||||
self._context, self.share, self.server)
|
||||
self.assertEqual(get_access_return, result)
|
||||
|
||||
def test__get_access_rule_for_data_copy_dhss_false(self):
|
||||
get_access_return = {
|
||||
'access_level': 'rw',
|
||||
'access_to': 'fake_ip',
|
||||
'access_type': 'ip'
|
||||
}
|
||||
CONF.set_default('driver_handles_share_servers', False)
|
||||
CONF.set_default('migration_data_copy_node_ip', 'fake_ip')
|
||||
result = self._driver._get_access_rule_for_data_copy(
|
||||
self._context, self.share, self.server)
|
||||
self.assertEqual(get_access_return, result)
|
||||
|
||||
def test_create_share(self):
|
||||
volume = 'fake_volume'
|
||||
volume2 = 'fake_volume2'
|
||||
@ -346,11 +323,11 @@ class GenericShareDriverTestCase(test.TestCase):
|
||||
mock.Mock(return_value=volume2))
|
||||
self.mock_object(self._driver, '_format_device')
|
||||
self.mock_object(self._driver, '_mount_device')
|
||||
expected_el = {
|
||||
expected_el = [{
|
||||
'is_admin_only': False,
|
||||
'path': 'fakelocation',
|
||||
'metadata': {'export_location_metadata_example': 'example'},
|
||||
}
|
||||
}]
|
||||
|
||||
result = self._driver.create_share(
|
||||
self._context, self.share, share_server=self.server)
|
||||
@ -999,6 +976,11 @@ class GenericShareDriverTestCase(test.TestCase):
|
||||
vol1 = 'fake_vol1'
|
||||
vol2 = 'fake_vol2'
|
||||
self._helper_nfs.create_export.return_value = 'fakelocation'
|
||||
expected_el = [{
|
||||
'is_admin_only': False,
|
||||
'path': 'fakelocation',
|
||||
'metadata': {'export_location_metadata_example': 'example'},
|
||||
}]
|
||||
self.mock_object(self._driver, '_allocate_container',
|
||||
mock.Mock(return_value=vol1))
|
||||
self.mock_object(self._driver, '_attach_volume',
|
||||
@ -1011,7 +993,7 @@ class GenericShareDriverTestCase(test.TestCase):
|
||||
self.snapshot,
|
||||
share_server=self.server)
|
||||
|
||||
self.assertEqual('fakelocation', result)
|
||||
self.assertEqual(expected_el, result)
|
||||
self._driver._allocate_container.assert_called_once_with(
|
||||
self._driver.admin_context, self.share, self.snapshot)
|
||||
self._driver._attach_volume.assert_called_once_with(
|
||||
|
@ -73,6 +73,10 @@ def fake_get_config_option(key):
|
||||
return 'fake_service_network_name'
|
||||
elif key == 'interface_driver':
|
||||
return 'i.am.fake.VifDriver'
|
||||
elif key == 'admin_network_id':
|
||||
return None
|
||||
elif key == 'admin_subnet_id':
|
||||
return None
|
||||
else:
|
||||
return mock.Mock()
|
||||
|
||||
@ -493,13 +497,14 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
public_port_id='fake_public_port_id'),
|
||||
)
|
||||
def test_set_up_service_instance(self, update_data):
|
||||
fake_network_info = dict(foo='bar', server_id='fake_server_id',
|
||||
service_ip='fake_ip')
|
||||
fake_server = dict(
|
||||
id='fake', ip='1.2.3.4', public_address='1.2.3.4', pk_path=None,
|
||||
subnet_id='fake-subnet-id', router_id='fake-router-id',
|
||||
username=self._manager.get_config_option('service_instance_user'),
|
||||
service_ip='fake_ip')
|
||||
fake_network_info = {'foo': 'bar', 'server_id': 'fake_server_id'}
|
||||
fake_server = {
|
||||
'id': 'fake', 'ip': '1.2.3.4', 'public_address': '1.2.3.4',
|
||||
'pk_path': None, 'subnet_id': 'fake-subnet-id',
|
||||
'router_id': 'fake-router-id',
|
||||
'username': self._manager.get_config_option(
|
||||
'service_instance_user'),
|
||||
'admin_ip': 'admin_ip'}
|
||||
fake_server.update(update_data)
|
||||
expected_details = fake_server.copy()
|
||||
expected_details.pop('pk_path')
|
||||
@ -519,13 +524,14 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
self.assertEqual(expected_details, result)
|
||||
|
||||
def test_set_up_service_instance_not_available(self):
|
||||
fake_network_info = dict(foo='bar', server_id='fake_server_id',
|
||||
service_ip='fake_ip')
|
||||
fake_server = dict(
|
||||
id='fake', ip='1.2.3.4', public_address='1.2.3.4', pk_path=None,
|
||||
subnet_id='fake-subnet-id', router_id='fake-router-id',
|
||||
username=self._manager.get_config_option('service_instance_user'),
|
||||
service_ip='fake_ip')
|
||||
fake_network_info = {'foo': 'bar', 'server_id': 'fake_server_id'}
|
||||
fake_server = {
|
||||
'id': 'fake', 'ip': '1.2.3.4', 'public_address': '1.2.3.4',
|
||||
'pk_path': None, 'subnet_id': 'fake-subnet-id',
|
||||
'router_id': 'fake-router-id',
|
||||
'username': self._manager.get_config_option(
|
||||
'service_instance_user'),
|
||||
'admin_ip': 'admin_ip'}
|
||||
expected_details = fake_server.copy()
|
||||
expected_details.pop('pk_path')
|
||||
expected_details['instance_id'] = expected_details.pop('id')
|
||||
@ -958,8 +964,7 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
key_data = 'fake_key_name', 'fake_key_path'
|
||||
instance_name = 'fake_instance_name'
|
||||
network_info = dict()
|
||||
network_data = dict(nics=['fake_nic1', 'fake_nic2'],
|
||||
service_ip='fake_ip')
|
||||
network_data = {'nics': ['fake_nic1', 'fake_nic2']}
|
||||
if helper_type == service_instance.NEUTRON_NAME:
|
||||
network_data['router'] = dict(id='fake_router_id')
|
||||
server_get = dict(
|
||||
@ -970,7 +975,9 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
public_port=dict(id='fake_public_port',
|
||||
fixed_ips=[dict(ip_address=ip_address)]),
|
||||
service_port=dict(id='fake_service_port',
|
||||
fixed_ips=[dict(ip_address=ip_address)])))
|
||||
fixed_ips=[{'ip_address': ip_address}]),
|
||||
admin_port={'id': 'fake_admin_port',
|
||||
'fixed_ips': [{'ip_address': ip_address}]}))
|
||||
self.mock_object(service_instance.time, 'time',
|
||||
mock.Mock(return_value=5))
|
||||
self.mock_object(self._manager.network_helper, 'setup_network',
|
||||
@ -989,21 +996,22 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
mock.Mock(return_value=server_get))
|
||||
self.mock_object(self._manager.compute_api,
|
||||
'add_security_group_to_server')
|
||||
expected = dict(
|
||||
id=server_get['id'],
|
||||
status=server_get['status'],
|
||||
pk_path=key_data[1],
|
||||
public_address=ip_address,
|
||||
router_id=network_data.get('router_id'),
|
||||
subnet_id=network_data.get('subnet_id'),
|
||||
instance_id=server_get['id'],
|
||||
ip=ip_address,
|
||||
networks=server_get['networks'],
|
||||
service_ip='fake_ip')
|
||||
expected = {
|
||||
'id': server_get['id'],
|
||||
'status': server_get['status'],
|
||||
'pk_path': key_data[1],
|
||||
'public_address': ip_address,
|
||||
'router_id': network_data.get('router_id'),
|
||||
'subnet_id': network_data.get('subnet_id'),
|
||||
'instance_id': server_get['id'],
|
||||
'ip': ip_address,
|
||||
'networks': server_get['networks']}
|
||||
if helper_type == service_instance.NEUTRON_NAME:
|
||||
expected['router_id'] = network_data['router']['id']
|
||||
expected['public_port_id'] = 'fake_public_port'
|
||||
expected['service_port_id'] = 'fake_service_port'
|
||||
expected['admin_port_id'] = 'fake_admin_port'
|
||||
expected['admin_ip'] = 'fake_ip_address'
|
||||
|
||||
result = self._manager._create_service_instance(
|
||||
self._manager.admin_context, instance_name, network_info)
|
||||
@ -1037,6 +1045,83 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
self._manager.network_helper.get_network_name.\
|
||||
assert_called_once_with(network_info)
|
||||
|
||||
def test___create_service_instance_neutron_no_admin_ip(self):
|
||||
self.mock_object(service_instance, 'NeutronNetworkHelper',
|
||||
mock.Mock(side_effect=FakeNetworkHelper))
|
||||
config_data = {'DEFAULT': {
|
||||
'driver_handles_share_servers': True,
|
||||
'service_instance_user': 'fake_user',
|
||||
'service_instance_network_helper_type': (
|
||||
service_instance.NEUTRON_NAME)}}
|
||||
with test_utils.create_temp_config_with_opts(config_data):
|
||||
self._manager = service_instance.ServiceInstanceManager()
|
||||
|
||||
server_create = {'id': 'fakeid', 'status': 'CREATING', 'networks': {}}
|
||||
net_name = self._manager.get_config_option("service_network_name")
|
||||
sg = type('FakeSG', (object, ), {'id': 'fakeid', 'name': 'fakename'})
|
||||
ip_address = 'fake_ip_address'
|
||||
service_image_id = 'fake_service_image_id'
|
||||
key_data = 'fake_key_name', 'fake_key_path'
|
||||
instance_name = 'fake_instance_name'
|
||||
network_info = {}
|
||||
network_data = {
|
||||
'nics': ['fake_nic1', 'fake_nic2'],
|
||||
'router_id': 'fake_router_id', 'subnet_id': 'fake_subnet_id',
|
||||
'public_port': {'id': 'fake_public_port',
|
||||
'fixed_ips': [{'ip_address': ip_address}]},
|
||||
'service_port': {'id': 'fake_service_port',
|
||||
'fixed_ips': [{'ip_address': ip_address}]},
|
||||
'admin_port': {'id': 'fake_admin_port',
|
||||
'fixed_ips': []},
|
||||
'router': {'id': 'fake_router_id'}}
|
||||
server_get = {
|
||||
'id': 'fakeid', 'status': 'ACTIVE', 'networks':
|
||||
{net_name: [ip_address]}}
|
||||
|
||||
self.mock_object(service_instance.time, 'time',
|
||||
mock.Mock(return_value=5))
|
||||
self.mock_object(self._manager.network_helper, 'setup_network',
|
||||
mock.Mock(return_value=network_data))
|
||||
self.mock_object(self._manager.network_helper, 'get_network_name',
|
||||
mock.Mock(return_value=net_name))
|
||||
self.mock_object(self._manager, '_get_service_image',
|
||||
mock.Mock(return_value=service_image_id))
|
||||
self.mock_object(self._manager, '_get_key',
|
||||
mock.Mock(return_value=key_data))
|
||||
self.mock_object(self._manager, '_get_or_create_security_group',
|
||||
mock.Mock(return_value=sg))
|
||||
self.mock_object(self._manager.compute_api, 'server_create',
|
||||
mock.Mock(return_value=server_create))
|
||||
self.mock_object(self._manager.compute_api, 'server_get',
|
||||
mock.Mock(return_value=server_get))
|
||||
self.mock_object(self._manager.compute_api,
|
||||
'add_security_group_to_server')
|
||||
|
||||
self.assertRaises(
|
||||
exception.AdminIPNotFound, self._manager._create_service_instance,
|
||||
self._manager.admin_context, instance_name, network_info)
|
||||
|
||||
self.assertTrue(service_instance.time.time.called)
|
||||
self._manager.network_helper.setup_network.assert_called_once_with(
|
||||
network_info)
|
||||
self._manager._get_service_image.assert_called_once_with(
|
||||
self._manager.admin_context)
|
||||
self._manager._get_key.assert_called_once_with(
|
||||
self._manager.admin_context)
|
||||
self._manager._get_or_create_security_group.assert_called_once_with(
|
||||
self._manager.admin_context)
|
||||
self._manager.compute_api.server_create.assert_called_once_with(
|
||||
self._manager.admin_context, name=instance_name,
|
||||
image=service_image_id, flavor=100,
|
||||
key_name=key_data[0], nics=network_data['nics'],
|
||||
availability_zone=service_instance.CONF.storage_availability_zone)
|
||||
self._manager.compute_api.server_get.assert_called_once_with(
|
||||
self._manager.admin_context, server_create['id'])
|
||||
self._manager.compute_api.add_security_group_to_server.\
|
||||
assert_called_once_with(
|
||||
self._manager.admin_context, server_get['id'], sg.id)
|
||||
self._manager.network_helper.get_network_name.assert_has_calls([])
|
||||
|
||||
@ddt.data(
|
||||
dict(
|
||||
instance_id_included=False,
|
||||
@ -1652,15 +1737,14 @@ class NeutronNetworkHelperTestCase(test.TestCase):
|
||||
instance, '_get_cidr_for_subnet', mock.Mock(return_value=cidr))
|
||||
self.mock_object(
|
||||
instance, '_get_service_subnet', mock.Mock(return_value=None))
|
||||
self.mock_object(
|
||||
instance, '_get_service_ip', mock.Mock(return_value='fake_ip'))
|
||||
expected = dict(
|
||||
ip_address=self.public_port['fixed_ips'][0]['ip_address'],
|
||||
public_port=self.public_port, service_ip='fake_ip',
|
||||
service_port=self.service_port, service_subnet=service_subnet,
|
||||
ports=[self.service_port, self.public_port],
|
||||
nics=[{'port-id': self.service_port['id']},
|
||||
{'port-id': self.public_port['id']}])
|
||||
expected = {
|
||||
'ip_address': self.public_port['fixed_ips'][0]['ip_address'],
|
||||
'public_port': self.public_port,
|
||||
'service_port': self.service_port,
|
||||
'service_subnet': service_subnet,
|
||||
'ports': [self.public_port, self.service_port],
|
||||
'nics': [{'port-id': self.public_port['id']},
|
||||
{'port-id': self.service_port['id']}]}
|
||||
|
||||
result = instance.setup_network(network_info)
|
||||
|
||||
@ -1671,7 +1755,54 @@ class NeutronNetworkHelperTestCase(test.TestCase):
|
||||
instance._get_cidr_for_subnet.assert_called_once_with()
|
||||
self.assertTrue(service_instance.neutron.API.subnet_create.called)
|
||||
self.assertTrue(service_instance.neutron.API.create_port.called)
|
||||
self.assertTrue(instance._get_service_ip.called)
|
||||
|
||||
def test_setup_network_and_connect_share_server_to_tenant_net_admin(self):
|
||||
def fake_create_port(*aargs, **kwargs):
|
||||
if aargs[1] == 'fake_admin_network_id':
|
||||
return self.admin_port
|
||||
elif aargs[1] == 'fake_tenant_network_id':
|
||||
return self.public_port
|
||||
else:
|
||||
raise exception.ManilaException('Got unexpected data')
|
||||
|
||||
admin_project_id = 'fake_admin_project_id'
|
||||
network_info = {
|
||||
'neutron_net_id': 'fake_tenant_network_id',
|
||||
'neutron_subnet_id': 'fake_tenant_subnet_id'}
|
||||
self.admin_port = {
|
||||
'id': 'fake_admin_port_id',
|
||||
'fixed_ips': [{'ip_address': 'fake_admin_port_ip_address'}]}
|
||||
self.public_port = {
|
||||
'id': 'fake_tenant_port_id',
|
||||
'fixed_ips': [{'ip_address': 'fake_public_port_ip_address'}]}
|
||||
instance = self._init_neutron_network_plugin()
|
||||
instance.use_admin_port = True
|
||||
instance.use_service_network = False
|
||||
instance.admin_network_id = 'fake_admin_network_id'
|
||||
instance.admin_subnet_id = 'fake_admin_subnet_id'
|
||||
instance.connect_share_server_to_tenant_network = True
|
||||
self.mock_object(
|
||||
service_instance.neutron.API, 'admin_project_id',
|
||||
mock.Mock(return_value=admin_project_id))
|
||||
self.mock_object(
|
||||
service_instance.neutron.API, 'create_port',
|
||||
mock.Mock(side_effect=fake_create_port))
|
||||
self.mock_object(
|
||||
instance, 'setup_connectivity_with_service_instances')
|
||||
expected = {
|
||||
'ip_address': self.public_port['fixed_ips'][0]['ip_address'],
|
||||
'public_port': self.public_port,
|
||||
'admin_port': self.admin_port,
|
||||
'ports': [self.public_port, self.admin_port],
|
||||
'nics': [{'port-id': self.public_port['id']},
|
||||
{'port-id': self.admin_port['id']}]}
|
||||
|
||||
result = instance.setup_network(network_info)
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
instance.setup_connectivity_with_service_instances.\
|
||||
assert_called_once_with()
|
||||
self.assertTrue(service_instance.neutron.API.create_port.called)
|
||||
|
||||
@ddt.data(None, exception.NetworkException(code=400))
|
||||
def test_setup_network_using_router_success(self, return_obj):
|
||||
@ -1680,11 +1811,17 @@ class NeutronNetworkHelperTestCase(test.TestCase):
|
||||
neutron_net_id='fake_tenant_network_id',
|
||||
neutron_subnet_id='fake_tenant_subnet_id')
|
||||
cidr = '13.0.0.0/24'
|
||||
self.admin_port = {
|
||||
'id': 'fake_admin_port_id',
|
||||
'fixed_ips': [{'ip_address': 'fake_admin_port_ip_address'}]}
|
||||
self.service_port = dict(
|
||||
id='fake_service_port_id',
|
||||
fixed_ips=[dict(ip_address='fake_service_port_ip_address')])
|
||||
service_subnet = dict(id='fake_service_subnet')
|
||||
instance = self._init_neutron_network_plugin()
|
||||
instance.use_admin_port = True
|
||||
instance.admin_network_id = 'fake_admin_network_id'
|
||||
instance.admin_subnet_id = 'fake_admin_subnet_id'
|
||||
instance.connect_share_server_to_tenant_network = False
|
||||
self.mock_object(instance, '_get_service_network_id',
|
||||
mock.Mock(return_value='fake_service_network_id'))
|
||||
@ -1694,7 +1831,7 @@ class NeutronNetworkHelperTestCase(test.TestCase):
|
||||
mock.Mock(return_value=admin_project_id))
|
||||
self.mock_object(
|
||||
service_instance.neutron.API, 'create_port',
|
||||
mock.Mock(return_value=self.service_port))
|
||||
mock.Mock(side_effect=[self.service_port, self.admin_port]))
|
||||
self.mock_object(
|
||||
service_instance.neutron.API, 'subnet_create',
|
||||
mock.Mock(return_value=service_subnet))
|
||||
@ -1708,13 +1845,14 @@ class NeutronNetworkHelperTestCase(test.TestCase):
|
||||
instance, '_get_cidr_for_subnet', mock.Mock(return_value=cidr))
|
||||
self.mock_object(
|
||||
instance, '_get_service_subnet', mock.Mock(return_value=None))
|
||||
self.mock_object(
|
||||
instance, '_get_service_ip', mock.Mock(return_value='fake_ip'))
|
||||
expected = dict(
|
||||
ip_address=self.service_port['fixed_ips'][0]['ip_address'],
|
||||
service_port=self.service_port, service_subnet=service_subnet,
|
||||
ports=[self.service_port], router=router, service_ip='fake_ip',
|
||||
nics=[{'port-id': self.service_port['id']}])
|
||||
expected = {
|
||||
'ip_address': self.service_port['fixed_ips'][0]['ip_address'],
|
||||
'service_port': self.service_port,
|
||||
'service_subnet': service_subnet,
|
||||
'admin_port': self.admin_port, 'router': router,
|
||||
'ports': [self.service_port, self.admin_port],
|
||||
'nics': [{'port-id': self.service_port['id']},
|
||||
{'port-id': self.admin_port['id']}]}
|
||||
|
||||
result = instance.setup_network(network_info)
|
||||
|
||||
@ -1729,7 +1867,6 @@ class NeutronNetworkHelperTestCase(test.TestCase):
|
||||
network_info['neutron_net_id'], network_info['neutron_subnet_id'])
|
||||
service_instance.neutron.API.router_add_interface.\
|
||||
assert_called_once_with(router['id'], service_subnet['id'])
|
||||
self.assertTrue(instance._get_service_ip.called)
|
||||
|
||||
def test_setup_network_using_router_addon_of_interface_failed(self):
|
||||
network_info = dict(
|
||||
@ -1813,36 +1950,6 @@ class NeutronNetworkHelperTestCase(test.TestCase):
|
||||
service_instance.neutron.API.delete_port.assert_has_calls([
|
||||
mock.call(self.service_port['id'])])
|
||||
|
||||
def test__get_service_ip(self):
|
||||
fake_division_mask = fake_get_config_option(
|
||||
'service_network_division_mask')
|
||||
fake_subnet = fake_network.FakeSubnet(
|
||||
cidr='10.254.0.0/%s' % fake_division_mask)
|
||||
fake_port = fake_network.FakePort(fixed_ips=[
|
||||
{'subnet_id': fake_subnet['id'], 'ip_address': '10.254.0.2'}],
|
||||
mac_address='fake_mac_address')
|
||||
|
||||
instance = self._init_neutron_network_plugin()
|
||||
result = instance._get_service_ip(fake_port, fake_subnet['id'])
|
||||
|
||||
# result should be equal to fake_port.fixed_ips[0]['ip_address']
|
||||
self.assertEqual(fake_port.fixed_ips[0]['ip_address'], result)
|
||||
|
||||
def test__get_service_ip_exception(self):
|
||||
|
||||
fake_division_mask = fake_get_config_option(
|
||||
'service_network_division_mask')
|
||||
fake_subnet = fake_network.FakeSubnet(
|
||||
cidr='10.254.0.0/%s' % fake_division_mask)
|
||||
fake_port = fake_network.FakePort(fixed_ips=[
|
||||
{'subnet_id': 'another_fake_id', 'ip_address': '10.254.0.2'}],
|
||||
mac_address='fake_mac_address')
|
||||
|
||||
instance = self._init_neutron_network_plugin()
|
||||
self.assertRaises(
|
||||
exception.ServiceIPNotFound,
|
||||
instance._get_service_ip, fake_port, fake_subnet['id'])
|
||||
|
||||
def test__get_cidr_for_subnet_success(self):
|
||||
expected = (
|
||||
fake_get_config_option('service_network_cidr').split('/')[0] +
|
||||
@ -1877,47 +1984,70 @@ class NeutronNetworkHelperTestCase(test.TestCase):
|
||||
|
||||
def test_setup_connectivity_with_service_instances(self):
|
||||
instance = self._init_neutron_network_plugin()
|
||||
interface_name = 'fake_interface_name'
|
||||
instance.use_admin_port = True
|
||||
instance.admin_network_id = 'fake_admin_network_id'
|
||||
instance.admin_subnet_id = 'fake_admin_subnet_id'
|
||||
interface_name_service = 'fake_interface_name_service'
|
||||
interface_name_admin = 'fake_interface_name_admin'
|
||||
fake_division_mask = fake_get_config_option(
|
||||
'service_network_division_mask')
|
||||
fake_subnet = fake_network.FakeSubnet(
|
||||
fake_subnet_service = fake_network.FakeSubnet(
|
||||
cidr='10.254.0.0/%s' % fake_division_mask)
|
||||
fake_port = fake_network.FakePort(fixed_ips=[
|
||||
{'subnet_id': fake_subnet['id'], 'ip_address': '10.254.0.2'}],
|
||||
fake_subnet_admin = fake_network.FakeSubnet(id='fake_admin_subnet_id',
|
||||
cidr='10.0.0.0/24')
|
||||
fake_service_port = fake_network.FakePort(fixed_ips=[
|
||||
{'subnet_id': fake_subnet_service['id'],
|
||||
'ip_address': '10.254.0.2'}], mac_address='fake_mac_address')
|
||||
fake_admin_port = fake_network.FakePort(fixed_ips=[
|
||||
{'subnet_id': fake_subnet_admin['id'], 'ip_address': '10.0.0.4'}],
|
||||
mac_address='fake_mac_address')
|
||||
|
||||
self.mock_object(instance, '_get_service_port',
|
||||
mock.Mock(return_value=fake_port))
|
||||
mock.Mock(side_effect=[fake_service_port,
|
||||
fake_admin_port]))
|
||||
self.mock_object(instance, '_add_fixed_ips_to_service_port',
|
||||
mock.Mock(return_value=fake_port))
|
||||
mock.Mock(return_value=fake_service_port))
|
||||
self.mock_object(instance.vif_driver, 'get_device_name',
|
||||
mock.Mock(return_value=interface_name))
|
||||
mock.Mock(side_effect=[interface_name_service,
|
||||
interface_name_admin]))
|
||||
self.mock_object(instance.neutron_api, 'get_subnet',
|
||||
mock.Mock(return_value=fake_subnet))
|
||||
mock.Mock(side_effect=[fake_subnet_service,
|
||||
fake_subnet_admin,
|
||||
fake_subnet_admin]))
|
||||
self.mock_object(instance, '_remove_outdated_interfaces')
|
||||
self.mock_object(instance.vif_driver, 'plug')
|
||||
device_mock = mock.Mock()
|
||||
self.mock_object(service_instance.ip_lib, 'IPDevice',
|
||||
mock.Mock(return_value=device_mock))
|
||||
|
||||
result = instance.setup_connectivity_with_service_instances()
|
||||
instance.setup_connectivity_with_service_instances()
|
||||
|
||||
instance._get_service_port.assert_called_once_with()
|
||||
instance.vif_driver.get_device_name.assert_called_once_with(fake_port)
|
||||
instance.vif_driver.plug.assert_called_once_with(
|
||||
interface_name, fake_port['id'], fake_port['mac_address'])
|
||||
instance.neutron_api.get_subnet.assert_called_once_with(
|
||||
fake_subnet['id'])
|
||||
instance.vif_driver.init_l3.assert_called_once_with(
|
||||
interface_name, ['10.254.0.2/%s' % fake_division_mask])
|
||||
service_instance.ip_lib.IPDevice.assert_called_once_with(
|
||||
interface_name)
|
||||
device_mock.route.pullup_route.assert_called_once_with(interface_name)
|
||||
instance._remove_outdated_interfaces.assert_called_once_with(
|
||||
device_mock)
|
||||
|
||||
# result should be equal to fake_port
|
||||
self.assertEqual(fake_port, result)
|
||||
instance._get_service_port.assert_has_calls([
|
||||
mock.call(instance.service_network_id, None, 'manila-share'),
|
||||
mock.call('fake_admin_network_id', 'fake_admin_subnet_id',
|
||||
'manila-admin-share')])
|
||||
instance.vif_driver.get_device_name.assert_has_calls([
|
||||
mock.call(fake_service_port), mock.call(fake_admin_port)])
|
||||
instance.vif_driver.plug.assert_has_calls([
|
||||
mock.call(interface_name_service, fake_service_port['id'],
|
||||
fake_service_port['mac_address']),
|
||||
mock.call(interface_name_admin, fake_admin_port['id'],
|
||||
fake_admin_port['mac_address'])])
|
||||
instance.neutron_api.get_subnet.assert_has_calls([
|
||||
mock.call(fake_subnet_service['id']),
|
||||
mock.call(fake_subnet_admin['id']),
|
||||
mock.call(fake_subnet_admin['id'])])
|
||||
instance.vif_driver.init_l3.assert_has_calls([
|
||||
mock.call(interface_name_service,
|
||||
['10.254.0.2/%s' % fake_division_mask]),
|
||||
mock.call(interface_name_admin, ['10.0.0.4/24'])])
|
||||
service_instance.ip_lib.IPDevice.assert_has_calls([
|
||||
mock.call(interface_name_service),
|
||||
mock.call(interface_name_admin)])
|
||||
device_mock.route.pullup_route.assert_has_calls([
|
||||
mock.call(interface_name_service),
|
||||
mock.call(interface_name_admin)])
|
||||
instance._remove_outdated_interfaces.assert_called_with(device_mock)
|
||||
|
||||
def test__get_set_of_device_cidrs(self):
|
||||
device = fake_network.FakeDevice('foo')
|
||||
@ -1970,14 +2100,15 @@ class NeutronNetworkHelperTestCase(test.TestCase):
|
||||
self.mock_object(instance.neutron_api, 'update_port_fixed_ips',
|
||||
mock.Mock(return_value=fake_service_port))
|
||||
|
||||
result = instance._get_service_port()
|
||||
result = instance._get_service_port(instance.service_network_id,
|
||||
None, 'manila-share')
|
||||
|
||||
instance.neutron_api.list_ports.assert_called_once_with(
|
||||
**fake_port_values)
|
||||
instance.neutron_api.create_port.assert_called_once_with(
|
||||
instance.admin_project_id, instance.service_network_id,
|
||||
device_id='manila-share', device_owner='manila:share',
|
||||
host_id='fake_host')
|
||||
host_id='fake_host', subnet_id=None)
|
||||
service_instance.socket.gethostname.assert_called_once_with()
|
||||
self.assertFalse(instance.neutron_api.update_port_fixed_ips.called)
|
||||
self.assertEqual(fake_service_port, result)
|
||||
@ -1996,7 +2127,8 @@ class NeutronNetworkHelperTestCase(test.TestCase):
|
||||
self.mock_object(instance.neutron_api, 'update_port_fixed_ips',
|
||||
mock.Mock(return_value=fake_service_port))
|
||||
|
||||
result = instance._get_service_port()
|
||||
result = instance._get_service_port(instance.service_network_id,
|
||||
None, 'manila-share')
|
||||
|
||||
instance.neutron_api.list_ports.assert_called_once_with(
|
||||
**fake_port_values)
|
||||
@ -2022,14 +2154,15 @@ class NeutronNetworkHelperTestCase(test.TestCase):
|
||||
self.mock_object(instance.neutron_api, 'update_port_fixed_ips',
|
||||
mock.Mock(return_value=fake_service_port))
|
||||
|
||||
result = instance._get_service_port()
|
||||
result = instance._get_service_port(instance.service_network_id,
|
||||
None, 'manila-share')
|
||||
|
||||
instance.neutron_api.list_ports.assert_called_once_with(
|
||||
**fake_port)
|
||||
instance.neutron_api.create_port.assert_called_once_with(
|
||||
instance.admin_project_id, instance.service_network_id,
|
||||
device_id='manila-share', device_owner='manila:share',
|
||||
host_id='fake_host')
|
||||
host_id='fake_host', subnet_id=None)
|
||||
service_instance.socket.gethostname.assert_called_once_with()
|
||||
self.assertFalse(instance.neutron_api.update_port_fixed_ips.called)
|
||||
self.assertEqual(fake_service_port, result)
|
||||
@ -2046,7 +2179,8 @@ class NeutronNetworkHelperTestCase(test.TestCase):
|
||||
self.mock_object(instance.neutron_api, 'create_port',
|
||||
mock.Mock(return_value=fake_service_port))
|
||||
self.assertRaises(
|
||||
exception.ServiceInstanceException, instance._get_service_port)
|
||||
exception.ServiceInstanceException, instance._get_service_port,
|
||||
instance.service_network_id, None, 'manila-share')
|
||||
self.assertFalse(instance.neutron_api.create_port.called)
|
||||
|
||||
def test__add_fixed_ips_to_service_port(self):
|
||||
@ -2244,10 +2378,9 @@ class NovaNetworkHelperTestCase(test.TestCase):
|
||||
instance = service_instance.NovaNetworkHelper(self.fake_manager)
|
||||
self.mock_object(instance.compute_api, 'network_get',
|
||||
mock.Mock(return_value=network))
|
||||
expected = dict(
|
||||
nova_net_id=network_info['nova_net_id'],
|
||||
nics=[{'net-id': network['id']}],
|
||||
service_ip='fake_gateway_ip')
|
||||
expected = {
|
||||
'nova_net_id': network_info['nova_net_id'],
|
||||
'nics': [{'net-id': network['id']}]}
|
||||
|
||||
result = instance.setup_network(network_info)
|
||||
|
||||
|
@ -492,7 +492,8 @@ class ShareDriverTestCase(test.TestCase):
|
||||
'access_to': None}}
|
||||
fake_share = {'id': 'fake_id',
|
||||
'share_proto': 'fake_proto',
|
||||
'export_locations': [{'path': '/fake/fake_id'}]}
|
||||
'export_locations': [{'path': '/fake/fake_id',
|
||||
'is_admin_only': True}]}
|
||||
|
||||
driver.CONF.set_default('driver_handles_share_servers', False)
|
||||
share_driver = driver.ShareDriver(False)
|
||||
@ -514,7 +515,9 @@ class ShareDriverTestCase(test.TestCase):
|
||||
'access_to': '100.100.100.100'}}
|
||||
|
||||
fake_share = {'id': 'fake_id',
|
||||
'export_locations': [{'path': '/5.5.5.5/fake_id'}]}
|
||||
'share_proto': 'fake_proto',
|
||||
'export_locations': [{'path': '/5.5.5.5/fake_id',
|
||||
'is_admin_only': False}]}
|
||||
|
||||
driver.CONF.set_default('driver_handles_share_servers', False)
|
||||
driver.CONF.set_default('migration_protocol_mount_command',
|
||||
|
@ -175,7 +175,15 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
|
||||
instance = self.boot_instance()
|
||||
self.allow_access_ip(self.share['id'], instance=instance)
|
||||
ssh_client = self.init_ssh(instance)
|
||||
for location in self.share['export_locations']:
|
||||
|
||||
if utils.is_microversion_lt(CONF.share.max_api_microversion, "2.9"):
|
||||
locations = self.share['export_locations']
|
||||
else:
|
||||
exports = self.shares_v2_client.list_share_export_locations(
|
||||
self.share['id'])
|
||||
locations = [x['path'] for x in exports]
|
||||
|
||||
for location in locations:
|
||||
self.mount_share(location, ssh_client)
|
||||
self.umount_share(ssh_client)
|
||||
self.servers_client.delete_server(instance['id'])
|
||||
@ -192,10 +200,14 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
|
||||
self.allow_access_ip(self.share['id'], instance=instance1)
|
||||
ssh_client_inst1 = self.init_ssh(instance1)
|
||||
|
||||
# TODO(vponomaryov): use separate API for getting export location for
|
||||
# share when "v2" client is used.
|
||||
first_location = self.share['export_locations'][0]
|
||||
self.mount_share(first_location, ssh_client_inst1)
|
||||
if utils.is_microversion_lt(CONF.share.max_api_microversion, "2.9"):
|
||||
locations = self.share['export_locations']
|
||||
else:
|
||||
exports = self.shares_v2_client.list_share_export_locations(
|
||||
self.share['id'])
|
||||
locations = [x['path'] for x in exports]
|
||||
|
||||
self.mount_share(locations[0], ssh_client_inst1)
|
||||
self.addCleanup(self.umount_share,
|
||||
ssh_client_inst1)
|
||||
self.write_data(test_data, ssh_client_inst1)
|
||||
@ -204,7 +216,7 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
|
||||
instance2 = self.boot_instance()
|
||||
self.allow_access_ip(self.share['id'], instance=instance2)
|
||||
ssh_client_inst2 = self.init_ssh(instance2)
|
||||
self.mount_share(first_location, ssh_client_inst2)
|
||||
self.mount_share(locations[0], ssh_client_inst2)
|
||||
self.addCleanup(self.umount_share,
|
||||
ssh_client_inst2)
|
||||
data = self.read_data(ssh_client_inst2)
|
||||
@ -244,10 +256,14 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
|
||||
cleanup=False)
|
||||
ssh_client = self.init_ssh(instance1)
|
||||
|
||||
# TODO(vponomaryov): use separate API for getting export location for
|
||||
# share when "v2" client is used.
|
||||
first_location = self.share['export_locations'][0]
|
||||
self.mount_share(first_location, ssh_client)
|
||||
if utils.is_microversion_lt(CONF.share.max_api_microversion, "2.9"):
|
||||
locations = self.share['export_locations']
|
||||
else:
|
||||
exports = self.shares_v2_client.list_share_export_locations(
|
||||
self.share['id'])
|
||||
locations = [x['path'] for x in exports]
|
||||
|
||||
self.mount_share(locations[0], ssh_client)
|
||||
|
||||
ssh_client.exec_command("mkdir -p /mnt/f1")
|
||||
ssh_client.exec_command("mkdir -p /mnt/f2")
|
||||
@ -271,20 +287,20 @@ class ShareBasicOpsBase(manager.ShareScenarioTest):
|
||||
self.umount_share(ssh_client)
|
||||
|
||||
share = self.migrate_share(share['id'], dest_pool)
|
||||
if utils.is_microversion_supported("2.9"):
|
||||
second_location = (
|
||||
self.shares_v2_client.list_share_export_locations(
|
||||
share['id'])[0]['path'])
|
||||
if utils.is_microversion_lt(CONF.share.max_api_microversion, "2.9"):
|
||||
new_locations = self.share['export_locations']
|
||||
else:
|
||||
# NOTE(vponomaryov): following approach is valid for picking up
|
||||
# export location only using microversions lower than '2.9'.
|
||||
second_location = share['export_locations'][0]
|
||||
new_exports = self.shares_v2_client.list_share_export_locations(
|
||||
self.share['id'])
|
||||
new_locations = [x['path'] for x in new_exports]
|
||||
|
||||
self.assertEqual(dest_pool, share['host'])
|
||||
self.assertNotEqual(first_location, second_location)
|
||||
locations.sort()
|
||||
new_locations.sort()
|
||||
self.assertNotEqual(locations, new_locations)
|
||||
self.assertEqual('migration_success', share['task_state'])
|
||||
|
||||
self.mount_share(second_location, ssh_client)
|
||||
self.mount_share(new_locations[0], ssh_client)
|
||||
|
||||
output = ssh_client.exec_command("ls -lRA --ignore=lost+found /mnt")
|
||||
|
||||
@ -301,7 +317,7 @@ class TestShareBasicOpsNFS(ShareBasicOpsBase):
|
||||
protocol = "NFS"
|
||||
|
||||
def mount_share(self, location, ssh_client):
|
||||
ssh_client.exec_command("sudo mount \"%s\" /mnt" % location)
|
||||
ssh_client.exec_command("sudo mount -vt nfs \"%s\" /mnt" % location)
|
||||
|
||||
|
||||
class TestShareBasicOpsCIFS(ShareBasicOpsBase):
|
||||
|
Loading…
x
Reference in New Issue
Block a user