Switch Ironic to openstacksdk for Neutron

This patch removes the dependency from ironicclient to
communicate with neutron in favor of openstacksdk.

Also:
 * Use import keystoneauth1.loading as ks_loading accross
   the project.
 * Refactor to have one 'get_client' function, removing the
   '_get_config_client' method. Setting config_client=True
   when calling 'get_client' returns a client using auth
   options values from conf parameters.

Depends-On: https://review.opendev.org/735601
Change-Id: Ib6c0fa2acfc33deb9c5b36ae724d5d8304d1dd29
This commit is contained in:
Harald Jensås 2020-06-04 22:22:06 +02:00
parent df9ce79f23
commit ff00047b4a
20 changed files with 828 additions and 893 deletions

View File

@ -233,7 +233,6 @@ default:
iso8601=WARNING
keystoneauth.session=INFO
keystonemiddleware.auth_token=INFO
neutronclient=WARNING
oslo_messaging=INFO
paramiko=WARNING
qpid.messaging=INFO
@ -241,6 +240,7 @@ default:
sqlalchemy=WARNING
stevedore=INFO
urllib3.connectionpool=WARNING
openstack=WARNING
default_management_interface = None
default_network_interface = None
default_portgroup_mode = active-backup

View File

@ -16,8 +16,8 @@
import functools
from keystoneauth1 import exceptions as kaexception
from keystoneauth1 import loading as kaloading
from keystoneauth1 import exceptions as ks_exception
from keystoneauth1 import loading as ks_loading
from keystoneauth1 import service_token
from keystoneauth1 import token_endpoint
from oslo_log import log as logging
@ -35,15 +35,15 @@ def ks_exceptions(f):
def wrapper(*args, **kwargs):
try:
return f(*args, **kwargs)
except kaexception.EndpointNotFound:
except ks_exception.EndpointNotFound:
service_type = kwargs.get('service_type', 'baremetal')
endpoint_type = kwargs.get('endpoint_type', 'internal')
raise exception.CatalogNotFound(
service_type=service_type, endpoint_type=endpoint_type)
except (kaexception.Unauthorized, kaexception.AuthorizationFailure):
except (ks_exception.Unauthorized, ks_exception.AuthorizationFailure):
raise exception.KeystoneUnauthorized()
except (kaexception.NoMatchingPlugin,
kaexception.MissingRequiredOptions) as e:
except (ks_exception.NoMatchingPlugin,
ks_exception.MissingRequiredOptions) as e:
raise exception.ConfigInvalid(str(e))
except Exception as e:
LOG.exception('Keystone request failed: %(msg)s',
@ -63,7 +63,7 @@ def get_session(group, **session_kwargs):
:param group: name of the config section to load session options from
"""
return kaloading.load_session_from_conf_options(
return ks_loading.load_session_from_conf_options(
CONF, group, **session_kwargs)
@ -81,9 +81,9 @@ def get_auth(group, **auth_kwargs):
"""
try:
auth = kaloading.load_auth_from_conf_options(CONF, group,
**auth_kwargs)
except kaexception.MissingRequiredOptions:
auth = ks_loading.load_auth_from_conf_options(CONF, group,
**auth_kwargs)
except ks_exception.MissingRequiredOptions:
LOG.error('Failed to load auth plugin from group %s', group)
raise
return auth
@ -100,8 +100,8 @@ def get_adapter(group, **adapter_kwargs):
:param group: name of the config section to load adapter options from
"""
return kaloading.load_adapter_from_conf_options(CONF, group,
**adapter_kwargs)
return ks_loading.load_adapter_from_conf_options(CONF, group,
**adapter_kwargs)
def get_endpoint(group, **adapter_kwargs):

View File

@ -13,11 +13,9 @@
import copy
import ipaddress
from keystoneauth1 import loading as ks_loading
from neutronclient.common import exceptions as neutron_exceptions
from neutronclient.v2_0 import client as clientv20
import openstack
from openstack.connection import exceptions as openstack_exc
from oslo_log import log
from oslo_utils import uuidutils
import retrying
from ironic.api.controllers.v1 import types
@ -43,9 +41,6 @@ VNIC_SMARTNIC = 'smart-nic'
PHYSNET_PARAM_NAME = 'provider:physical_network'
"""Name of the neutron network API physical network parameter."""
SEGMENTS_PARAM_NAME = 'segments'
"""Name of the neutron network API segments parameter."""
def _get_neutron_session():
global _NEUTRON_SESSION
@ -56,54 +51,35 @@ def _get_neutron_session():
return _NEUTRON_SESSION
# TODO(pas-ha) remove deprecated options handling in Rocky
# until then it might look ugly due to all if's.
def get_client(token=None, context=None):
def get_client(token=None, context=None, auth_from_config=False):
"""Retrieve a neutron client connection.
:param context: request context,
instance of ironic.common.context.RequestContext
:param auth_from_config: (boolean) When True, use auth values from
conf parameters
:returns: A neutron client.
"""
if not context:
context = ironic_context.RequestContext(auth_token=token)
# NOTE(pas-ha) neutronclient supports passing both session
# and the auth to client separately, makes things easier
session = _get_neutron_session()
service_auth = keystone.get_auth('neutron')
endpoint = keystone.get_endpoint('neutron', session=session,
auth=service_auth)
user_auth = None
if CONF.neutron.auth_type != 'none' and context.auth_token:
if (not auth_from_config and CONF.neutron.auth_type != 'none'
and context.auth_token):
user_auth = keystone.get_service_auth(context, endpoint, service_auth)
return clientv20.Client(session=session,
auth=user_auth or service_auth,
endpoint_override=endpoint,
retries=CONF.neutron.retries,
global_request_id=context.global_id,
timeout=CONF.neutron.request_timeout)
sess = keystone.get_session('neutron', timeout=CONF.neutron.timeout,
auth=user_auth or service_auth)
conn = openstack.connection.Connection(session=sess, oslo_conf=CONF)
return conn.global_request(context.global_id).network
def _get_conf_client(context):
"""Retrieve a neutron client connection using conf parameters.
:param context: request context,
instance of ironic.common.context.RequestContext
:returns: A neutron client.
"""
auth = ks_loading.load_auth_from_conf_options(CONF, 'neutron')
session = ks_loading.load_session_from_conf_options(
CONF,
'neutron',
auth=auth)
endpoint = keystone.get_endpoint('neutron', session=session,
auth=auth)
return clientv20.Client(session=session,
auth=auth,
endpoint_override=endpoint,
retries=CONF.neutron.retries,
global_request_id=context.global_id,
timeout=CONF.neutron.request_timeout)
def update_neutron_port(context, port_id, update_body, client=None):
def update_neutron_port(context, port_id, attrs, client=None):
"""Undate a neutron port
Uses neutron client from conf client to update a neutron client
@ -112,15 +88,20 @@ def update_neutron_port(context, port_id, update_body, client=None):
:param context: request context,
instance of ironic.common.context.RequestContext
:param port_id: Neutron port ID.
:param update_body: Body of update
:param attrs: The attributes to update on the port
:param client: Optional Neutron client
"""
if not client:
# verify that user can see the port before updating it
get_client(context=context).show_port(port_id)
client = _get_conf_client(context)
get_client(context=context).get_port(port_id)
# Set user_auth=False to ensure auth values from ironic.conf is used
# prevents issues where a non-admin user is not allowed to manage
# Neutron ports.
client = get_client(context=context, auth_from_config=True)
return client.update_port(port_id, update_body)
attrs = attrs.get('port', attrs)
return client.update_port(port_id, **attrs)
def unbind_neutron_port(port_id, client=None, context=None):
@ -136,21 +117,20 @@ def unbind_neutron_port(port_id, client=None, context=None):
:raises: NetworkError
"""
body_unbind = {'port': {'binding:host_id': '',
'binding:profile': {}}}
body_reset_mac = {'port': {'mac_address': None}}
attrs_unbind = {'binding:host_id': '', 'binding:profile': {}}
attrs_reset_mac = {'mac_address': None}
try:
update_neutron_port(context, port_id, body_unbind, client)
update_neutron_port(context, port_id, attrs_unbind, client)
# NOTE(hjensas): We need to reset the mac address in a separate step.
# Exception PortBound will be raised by neutron as it refuses to
# update the mac address of a bound port if we attempt to unbind and
# reset the mac in the same call.
update_neutron_port(context, port_id, body_reset_mac, client)
update_neutron_port(context, port_id, attrs_reset_mac, client)
# NOTE(vsaienko): Ignore if port was deleted before calling vif detach.
except neutron_exceptions.PortNotFoundClient:
except openstack_exc.ResourceNotFound:
LOG.info('Port %s was not found while unbinding.', port_id)
except neutron_exceptions.NeutronClientException as e:
except openstack_exc.OpenStackCloudException as e:
msg = (_('Unable to clear binding profile for '
'neutron port %(port_id)s. Error: '
'%(err)s') % {'port_id': port_id, 'err': e})
@ -168,12 +148,12 @@ def update_port_address(port_id, address, context=None):
:raises: FailedToUpdateMacOnPort
"""
client = get_client(context=context)
port_req_body = {'port': {'mac_address': address}}
port_attrs = {'mac_address': address}
try:
msg = (_("Failed to get the current binding on Neutron "
"port %s.") % port_id)
port = client.show_port(port_id).get('port', {})
port = client.get_port(port_id)
binding_host_id = port.get('binding:host_id')
binding_profile = port.get('binding:profile')
@ -186,17 +166,17 @@ def update_port_address(port_id, address, context=None):
unbind_neutron_port(port_id, context=context)
msg = (_("Failed to update MAC address on Neutron port %s.") % port_id)
update_neutron_port(context, port_id, port_req_body)
update_neutron_port(context, port_id, port_attrs)
# Restore original binding:profile and host_id
if binding_host_id:
msg = (_("Failed to update binding:host_id and profile on Neutron "
"port %s.") % port_id)
port_req_body = {'port': {'binding:host_id': binding_host_id,
'binding:profile': binding_profile}}
port_attrs = {'binding:host_id': binding_host_id,
'binding:profile': binding_profile}
update_neutron_port(context, port_id, port_req_body)
except (neutron_exceptions.NeutronClientException, exception.NetworkError):
update_neutron_port(context, port_id, port_attrs)
except (openstack_exc.OpenStackCloudException, exception.NetworkError):
LOG.exception(msg)
raise exception.FailedToUpdateMacOnPort(port_id=port_id)
@ -213,20 +193,18 @@ def _verify_security_groups(security_groups, client):
if not security_groups:
return
try:
neutron_sec_groups = (
client.list_security_groups(id=security_groups, fields='id').get(
'security_groups', []))
except neutron_exceptions.NeutronClientException as e:
neutron_sec_groups = set(
x.id for x in client.security_groups(id=security_groups))
except openstack_exc.OpenStackCloudException as e:
msg = (_("Could not retrieve security groups from neutron: %(exc)s") %
{'exc': e})
LOG.exception(msg)
raise exception.NetworkError(msg)
if set(security_groups).issubset(x['id'] for x in neutron_sec_groups):
if set(security_groups).issubset(neutron_sec_groups):
return
missing_sec_groups = set(security_groups).difference(
x['id'] for x in neutron_sec_groups)
missing_sec_groups = set(security_groups).difference(neutron_sec_groups)
msg = (_('Could not find these security groups (specified via ironic '
'config) in neutron: %(ir-sg)s')
% {'ir-sg': list(missing_sec_groups)})
@ -245,20 +223,17 @@ def _add_ip_addresses_for_ipv6_stateful(context, port, client):
:param port: A neutron port
:param client: Neutron client
"""
fixed_ips = port['port']['fixed_ips']
fixed_ips = port.fixed_ips
if (not fixed_ips
or ipaddress.ip_address(
fixed_ips[0]['ip_address']).version != 6):
or ipaddress.ip_address(fixed_ips[0]['ip_address']).version != 6):
return
subnet = client.show_subnet(
port['port']['fixed_ips'][0]['subnet_id']).get('subnet')
if subnet and subnet['ipv6_address_mode'] == 'dhcpv6-stateful':
subnet = client.get_subnet(fixed_ips[0]['subnet_id'])
if subnet and subnet.ipv6_address_mode == 'dhcpv6-stateful':
for i in range(1, CONF.neutron.dhcpv6_stateful_address_count):
fixed_ips.append({'subnet_id': subnet['id']})
body = {'port': {'fixed_ips': fixed_ips}}
update_neutron_port(context, port['port']['id'], body)
attrs = {'fixed_ips': fixed_ips}
update_neutron_port(context, port.id, attrs, client=client)
def add_ports_to_network(task, network_uuid, security_groups=None):
@ -291,27 +266,22 @@ def add_ports_to_network(task, network_uuid, security_groups=None):
{'net_iface': task.driver.network.__class__.__name__,
'node': node.uuid, 'network_uuid': network_uuid})
body = {
'port': {
'network_id': network_uuid,
'admin_state_up': True,
'binding:vnic_type': VNIC_BAREMETAL,
}
}
attrs = {'network_id': network_uuid,
'admin_state_up': True,
'binding:vnic_type': VNIC_BAREMETAL,
}
# separate out fields that can only be updated by admins
update_body = {
'port': {
'binding:host_id': node.uuid,
'device_owner': 'baremetal:none',
}
}
update_attrs = {'binding:host_id': node.uuid,
'device_owner': 'baremetal:none',
}
if security_groups:
body['port']['security_groups'] = security_groups
attrs['security_groups'] = security_groups
# Since instance_uuid will not be available during cleaning
# operations, we need to check that and populate them only when
# available
body['port']['device_id'] = node.instance_uuid or node.uuid
attrs['device_id'] = node.instance_uuid or node.uuid
ports = {}
failures = []
@ -329,23 +299,24 @@ def add_ports_to_network(task, network_uuid, security_groups=None):
for ironic_port in ports_to_create:
# Start with a clean state for each port
port_body = copy.deepcopy(body)
update_port_body = copy.deepcopy(update_body)
port_attrs = copy.deepcopy(attrs)
update_port_attrs = copy.deepcopy(update_attrs)
# Skip ports that are missing required information for deploy.
if not validate_port_info(node, ironic_port):
failures.append(ironic_port.uuid)
continue
update_port_body['port']['mac_address'] = ironic_port.address
update_port_attrs['mac_address'] = ironic_port.address
binding_profile = {'local_link_information':
[portmap[ironic_port.uuid]]}
update_port_body['port']['binding:profile'] = binding_profile
update_port_attrs['binding:profile'] = binding_profile
if not ironic_port.pxe_enabled:
LOG.debug("Adding port %(port)s to network %(net)s for "
"provisioning without an IP allocation.",
{'port': ironic_port.uuid,
'net': network_uuid})
port_body['fixed_ips'] = []
{'port': ironic_port.uuid, 'net': network_uuid})
port_attrs['fixed_ips'] = []
is_smart_nic = is_smartnic_port(ironic_port)
if is_smart_nic:
@ -354,29 +325,29 @@ def add_ports_to_network(task, network_uuid, security_groups=None):
'port %(port_id)s, hostname %(hostname)s',
{'port_id': ironic_port.uuid,
'hostname': link_info['hostname']})
update_port_body['port']['binding:host_id'] = link_info['hostname']
update_port_attrs['binding:host_id'] = link_info['hostname']
# TODO(hamdyk): use portbindings.VNIC_SMARTNIC from neutron-lib
port_body['port']['binding:vnic_type'] = VNIC_SMARTNIC
port_attrs['binding:vnic_type'] = VNIC_SMARTNIC
client_id = ironic_port.extra.get('client-id')
if client_id:
client_id_opt = {'opt_name': DHCP_CLIENT_ID,
'opt_value': client_id}
extra_dhcp_opts = port_body['port'].get('extra_dhcp_opts', [])
extra_dhcp_opts.append(client_id_opt)
port_body['port']['extra_dhcp_opts'] = extra_dhcp_opts
extra_dhcp_opts = port_attrs.get('extra_dhcp_opts', [])
extra_dhcp_opts.append(
{'opt_name': DHCP_CLIENT_ID, 'opt_value': client_id})
port_attrs['extra_dhcp_opts'] = extra_dhcp_opts
try:
if is_smart_nic:
wait_for_host_agent(
client, update_port_body['port']['binding:host_id'])
port = client.create_port(port_body)
update_neutron_port(task.context, port['port']['id'],
update_port_body)
client, update_port_attrs['binding:host_id'])
port = client.create_port(**port_attrs)
update_neutron_port(task.context, port.id, update_port_attrs)
if CONF.neutron.dhcpv6_stateful_address_count > 1:
_add_ip_addresses_for_ipv6_stateful(task.context, port, client)
if is_smart_nic:
wait_for_port_status(client, port['port']['id'], 'ACTIVE')
except neutron_exceptions.NeutronClientException as e:
wait_for_port_status(client, port.id, 'ACTIVE')
except openstack_exc.OpenStackCloudException as e:
failures.append(ironic_port.uuid)
LOG.warning("Could not create neutron port for node's "
"%(node)s port %(ir-port)s on the neutron "
@ -384,7 +355,7 @@ def add_ports_to_network(task, network_uuid, security_groups=None):
{'net': network_uuid, 'node': node.uuid,
'ir-port': ironic_port.uuid, 'exc': e})
else:
ports[ironic_port.uuid] = port['port']['id']
ports[ironic_port.uuid] = port.id
if failures:
if len(failures) == len(ports_to_create):
@ -439,15 +410,14 @@ def remove_neutron_ports(task, params):
node_uuid = task.node.uuid
try:
response = client.list_ports(**params)
except neutron_exceptions.NeutronClientException as e:
ports = client.ports(**params)
except openstack_exc.OpenStackCloudException as e:
msg = (_('Could not get given network VIF for %(node)s '
'from neutron, possible network issue. %(exc)s') %
{'node': node_uuid, 'exc': e})
LOG.exception(msg)
raise exception.NetworkError(msg)
ports = response.get('ports', [])
if not ports:
LOG.debug('No ports to remove for node %s', node_uuid)
return
@ -460,14 +430,14 @@ def remove_neutron_ports(task, params):
if is_smartnic_port(port):
wait_for_host_agent(client, port['binding:host_id'])
try:
client.delete_port(port['id'])
client.delete_port(port)
# NOTE(mgoddard): Ignore if the port was deleted by nova.
except neutron_exceptions.PortNotFoundClient:
LOG.info('Port %s was not found while deleting.', port['id'])
except neutron_exceptions.NeutronClientException as e:
except openstack_exc.ResourceNotFound:
LOG.info('Port %s was not found while deleting.', port.id)
except openstack_exc.OpenStackCloudException as e:
msg = (_('Could not remove VIF %(vif)s of node %(node)s, possibly '
'a network issue: %(exc)s') %
{'vif': port['id'], 'node': node_uuid, 'exc': e})
{'vif': port.id, 'node': node_uuid, 'exc': e})
LOG.exception(msg)
raise exception.NetworkError(msg)
@ -508,11 +478,9 @@ def get_neutron_port_data(port_id, vif_id, client=None, context=None):
client = get_client(context=context)
try:
port_config = client.show_port(
vif_id, fields=['id', 'name', 'dns_assignment', 'fixed_ips',
'mac_address', 'network_id'])
port_config = client.get_port(vif_id)
except neutron_exceptions.NeutronClientException as e:
except openstack_exc.OpenStackCloudException as e:
msg = (_('Unable to get port info for %(port_id)s. Error: '
'%(err)s') % {'port_id': vif_id, 'err': e})
LOG.exception(msg)
@ -521,17 +489,14 @@ def get_neutron_port_data(port_id, vif_id, client=None, context=None):
LOG.debug('Received port %(port)s data: %(info)s',
{'port': vif_id, 'info': port_config})
port_config = port_config['port']
port_id = port_config['name'] or port_id
network_id = port_config.get('network_id')
network_id = port_config.network_id
try:
network_config = client.show_network(
network_id, fields=['id', 'mtu', 'subnets'])
network_config = client.get_network(network_id)
except neutron_exceptions.NeutronClientException as e:
except openstack_exc.OpenStackCloudException as e:
msg = (_('Unable to get network info for %(network_id)s. Error: '
'%(err)s') % {'network_id': network_id, 'err': e})
LOG.exception(msg)
@ -540,8 +505,6 @@ def get_neutron_port_data(port_id, vif_id, client=None, context=None):
LOG.debug('Received network %(network)s data: %(info)s',
{'network': network_id, 'info': network_config})
network_config = network_config['network']
subnets_config = {}
network_data = {
@ -563,17 +526,14 @@ def get_neutron_port_data(port_id, vif_id, client=None, context=None):
subnet_id = fixed_ip['subnet_id']
try:
subnet_config = client.show_subnet(
subnet_id, fields=['id', 'name', 'enable_dhcp',
'dns_nameservers', 'host_routes',
'ip_version', 'gateway_ip', 'cidr'])
subnet_config = client.get_subnet(subnet_id)
LOG.debug('Received subnet %(subnet)s data: %(info)s',
{'subnet': subnet_id, 'info': subnet_config})
subnets_config[subnet_id] = subnet_config['subnet']
subnets_config[subnet_id] = subnet_config
except neutron_exceptions.NeutronClientException as e:
except openstack_exc.OpenStackCloudException as e:
msg = (_('Unable to get subnet info for %(subnet_id)s. Error: '
'%(err)s') % {'subnet_id': subnet_id, 'err': e})
LOG.exception(msg)
@ -582,7 +542,7 @@ def get_neutron_port_data(port_id, vif_id, client=None, context=None):
subnet_config = subnets_config[subnet_id]
subnet_network, netmask = _uncidr(
subnet_config['cidr'], subnet_config['ip_version'] == 6)
subnet_config.cidr, subnet_config.ip_version == 6)
network = {
'id': fixed_ip['subnet_id'],
@ -728,8 +688,9 @@ def validate_network(uuid_or_name, net_type=_('network'), context=None):
client = get_client(context=context)
network = _get_network_by_uuid_or_name(client, uuid_or_name,
net_type=net_type, fields=['id'])
return network['id']
net_type=net_type)
return network.id
def validate_port_info(node, port):
@ -781,12 +742,12 @@ def _validate_agent(client, **kwargs):
:raises: NetworkError in case of failure contacting Neutron.
"""
try:
agents = client.list_agents(**kwargs)['agents']
agents = client.agents(**kwargs)
for agent in agents:
if agent['alive']:
if agent.is_alive:
return True
return False
except neutron_exceptions.NeutronClientException:
except openstack_exc.OpenStackCloudException:
raise exception.NetworkError('Failed to contact Neutron server')
@ -807,67 +768,58 @@ def is_smartnic_port(port_data):
return False
def _get_network_by_uuid_or_name(client, uuid_or_name, net_type=_('network'),
**params):
def _get_network_by_uuid_or_name(client, uuid_or_name, net_type=_('network')):
"""Return a neutron network by UUID or name.
:param client: A Neutron client object.
:param uuid_or_name: network UUID or name
:param net_type: human-readable network type for error messages
:param params: Additional parameters to pass to the neutron client
list_networks method.
:returns: A dict describing the neutron network.
:raises: NetworkError on failure to contact Neutron
:raises: InvalidParameterValue for missing or duplicated network
"""
if uuidutils.is_uuid_like(uuid_or_name):
params['id'] = uuid_or_name
else:
params['name'] = uuid_or_name
try:
networks = client.list_networks(**params)
except neutron_exceptions.NeutronClientException as exc:
raise exception.NetworkError(_('Could not retrieve network list: %s') %
exc)
LOG.debug('Got list of networks matching %(cond)s: %(result)s',
{'cond': params, 'result': networks})
networks = networks.get('networks', [])
if not networks:
raise exception.InvalidParameterValue(
_('%(type)s with name or UUID %(uuid_or_name)s was not found') %
{'type': net_type, 'uuid_or_name': uuid_or_name})
elif len(networks) > 1:
network_ids = [n['id'] for n in networks]
network = client.find_network(uuid_or_name, ignore_missing=False)
except openstack_exc.DuplicateResource:
network_ids = [net.id for net in client.networks(name=uuid_or_name)]
raise exception.InvalidParameterValue(
_('More than one %(type)s was found for name %(name)s: %(nets)s') %
{'name': uuid_or_name, 'nets': ', '.join(network_ids),
'type': net_type})
return networks[0]
except openstack_exc.ResourceNotFound:
raise exception.InvalidParameterValue(
_('%(type)s with name or UUID %(uuid_or_name)s was not found') %
{'type': net_type, 'uuid_or_name': uuid_or_name})
except openstack_exc.OpenStackCloudException as exc:
raise exception.NetworkError(_('Could not retrieve network: %s') % exc)
LOG.debug('Got network matching %(uuid_or_name)s: %(result)s',
{'uuid_or_name': uuid_or_name, 'result': network})
return network
def _get_port_by_uuid(client, port_uuid, **params):
def _get_port_by_uuid(client, port_uuid):
"""Return a neutron port by UUID.
:param client: A Neutron client object.
:param port_uuid: UUID of a Neutron port to query.
:param params: Additional parameters to pass to the neutron client
show_port method.
:returns: A dict describing the neutron port.
:raises: InvalidParameterValue if the port does not exist.
:raises: NetworkError on failure to contact Neutron.
"""
try:
port = client.show_port(port_uuid, **params)
except neutron_exceptions.PortNotFoundClient:
port = client.get_port(port_uuid)
except openstack_exc.ResourceNotFound:
raise exception.InvalidParameterValue(
_('Neutron port %(port_uuid)s was not found') %
{'port_uuid': port_uuid})
except neutron_exceptions.NeutronClientException as exc:
except openstack_exc.OpenStackCloudException as exc:
raise exception.NetworkError(_('Could not retrieve neutron port: %s') %
exc)
return port['port']
return port
def get_physnets_by_port_uuid(client, port_uuid):
@ -882,27 +834,25 @@ def get_physnets_by_port_uuid(client, port_uuid):
:raises: NetworkError if the network query fails.
:raises: InvalidParameterValue for missing network.
"""
port = _get_port_by_uuid(client, port_uuid, fields=['network_id'])
network_uuid = port['network_id']
port = _get_port_by_uuid(client, port_uuid)
network_uuid = port.network_id
fields = [PHYSNET_PARAM_NAME, SEGMENTS_PARAM_NAME]
network = _get_network_by_uuid_or_name(client, network_uuid, fields=fields)
network = _get_network_by_uuid_or_name(client, network_uuid)
if SEGMENTS_PARAM_NAME in network:
if network.segments is not None:
# A network with multiple segments will have a 'segments' parameter
# which will contain a list of segments. Each segment should have a
# 'provider:physical_network' parameter which contains the physical
# network of the segment.
segments = network[SEGMENTS_PARAM_NAME]
return set(segment[PHYSNET_PARAM_NAME]
for segment in network.segments
if segment[PHYSNET_PARAM_NAME])
else:
# A network with a single segment will have a
# 'provider:physical_network' parameter which contains the network's
# physical network.
segments = [network]
return set(segment[PHYSNET_PARAM_NAME]
for segment in segments
if segment[PHYSNET_PARAM_NAME])
return (set([network.provider_physical_network])
if network.provider_physical_network else set())
@retrying.retry(
@ -963,10 +913,10 @@ def wait_for_port_status(client, port_id, status):
"""
LOG.debug('Validating Port %(port_id)s status is %(status)s',
{'port_id': port_id, 'status': status})
port_info = _get_port_by_uuid(client, port_id)
port = _get_port_by_uuid(client, port_id)
LOG.debug('Port %(port_id)s status is: %(status)s',
{'port_id': port_id, 'status': port_info['status']})
if port_info['status'] == status:
{'port_id': port_id, 'status': port.status})
if port.status == status:
return True
raise exception.NetworkError(
'Port %(port_id)s failed to reach status %(status)s' % {

View File

@ -14,7 +14,7 @@
import copy
from keystoneauth1 import loading as kaloading
from keystoneauth1 import loading as ks_loading
from oslo_config import cfg
from oslo_log import log
@ -30,9 +30,9 @@ def register_auth_opts(conf, group, service_type=None):
Registers only basic auth options shared by all auth plugins.
The rest are registered at runtime depending on auth plugin used.
"""
kaloading.register_session_conf_options(conf, group)
kaloading.register_auth_conf_options(conf, group)
kaloading.register_adapter_conf_options(conf, group)
ks_loading.register_session_conf_options(conf, group)
ks_loading.register_auth_conf_options(conf, group)
ks_loading.register_adapter_conf_options(conf, group)
conf.set_default('valid_interfaces', DEFAULT_VALID_INTERFACES, group=group)
# TODO(pas-ha) use os-service-type to try find the service_type by the
# config group name assuming it is a project name (e.g. 'glance')
@ -56,16 +56,16 @@ def add_auth_opts(options, service_type=None):
opts.append(new_opt)
opts = copy.deepcopy(options)
opts.insert(0, kaloading.get_auth_common_conf_options()[0])
opts.insert(0, ks_loading.get_auth_common_conf_options()[0])
# NOTE(dims): There are a lot of auth plugins, we just generate
# the config options for a few common ones
plugins = ['password', 'v2password', 'v3password']
for name in plugins:
plugin = kaloading.get_plugin_loader(name)
add_options(opts, kaloading.get_auth_plugin_conf_options(plugin))
add_options(opts, kaloading.get_session_conf_options())
plugin = ks_loading.get_plugin_loader(name)
add_options(opts, ks_loading.get_auth_plugin_conf_options(plugin))
add_options(opts, ks_loading.get_session_conf_options())
if service_type:
adapter_opts = kaloading.get_adapter_conf_options(
adapter_opts = ks_loading.get_adapter_conf_options(
include_deprecated=False)
# adding defaults for valid interfaces
cfg.set_defaults(adapter_opts, service_type=service_type,

View File

@ -29,7 +29,11 @@ opts = [
cfg.IntOpt('retries',
default=3,
mutable=True,
help=_('Client retries in the case of a failed request.')),
deprecated_for_removal=True,
deprecated_reason=_('Replaced by status_code_retries and '
'status_code_retry_delay.'),
help=_('DEPRECATED: Client retries in the case of a failed '
'request.')),
cfg.StrOpt('cleaning_network',
mutable=True,
help=_('Neutron network UUID or name for the ramdisk to be '

View File

@ -96,10 +96,10 @@ def update_opt_defaults():
'eventlet.wsgi.server=INFO',
'iso8601=WARNING',
'requests=WARNING',
'neutronclient=WARNING',
'glanceclient=WARNING',
'urllib3.connectionpool=WARNING',
'keystonemiddleware.auth_token=INFO',
'keystoneauth.session=INFO',
'openstack=WARNING',
]
)

View File

@ -17,7 +17,7 @@
import ipaddress
import time
from neutronclient.common import exceptions as neutron_client_exc
from openstack.connection import exceptions as openstack_exc
from oslo_log import log as logging
from ironic.common import exception
@ -62,11 +62,10 @@ class NeutronDHCPApi(base.BaseDHCP):
super(NeutronDHCPApi, self).update_port_dhcp_opts(
port_id, dhcp_options, token=token, context=context)
try:
neutron_client = neutron.get_client(token=token,
context=context)
neutron_client = neutron.get_client(token=token, context=context)
fip = None
port = neutron_client.show_port(port_id).get('port')
port = neutron_client.get_port(port_id)
try:
if port:
# TODO(TheJulia): We need to retool this down the
@ -90,9 +89,9 @@ class NeutronDHCPApi(base.BaseDHCP):
else:
LOG.error('Requested to update port for port %s, '
'however port lacks an IP address.', port_id)
port_req_body = {'port': {'extra_dhcp_opts': update_opts}}
neutron.update_neutron_port(context, port_id, port_req_body)
except neutron_client_exc.NeutronClientException:
port_attrs = {'extra_dhcp_opts': update_opts}
neutron.update_neutron_port(context, port_id, port_attrs)
except openstack_exc.OpenStackCloudException:
LOG.exception("Failed to update Neutron port %s.", port_id)
raise exception.FailedToUpdateDHCPOptOnPort(port_id=port_id)
@ -160,10 +159,10 @@ class NeutronDHCPApi(base.BaseDHCP):
LOG.debug("Waiting %d seconds for Neutron.", port_delay)
time.sleep(port_delay)
def _get_fixed_ip_address(self, port_uuid, client):
def _get_fixed_ip_address(self, port_id, client):
"""Get a Neutron port's fixed ip address.
:param port_uuid: Neutron port id.
:param port_id: Neutron port id.
:param client: Neutron client instance.
:returns: Neutron port ip address.
:raises: NetworkError
@ -172,10 +171,10 @@ class NeutronDHCPApi(base.BaseDHCP):
"""
ip_address = None
try:
neutron_port = client.show_port(port_uuid).get('port')
except neutron_client_exc.NeutronClientException:
neutron_port = client.get_port(port_id)
except openstack_exc.OpenStackCloudException:
raise exception.NetworkError(
_('Could not retrieve neutron port: %s') % port_uuid)
_('Could not retrieve neutron port: %s') % port_id)
fixed_ips = neutron_port.get('fixed_ips')
@ -192,18 +191,18 @@ class NeutronDHCPApi(base.BaseDHCP):
return ip_address
else:
LOG.error("Neutron returned invalid IP "
"address %(ip_address)s on port %(port_uuid)s.",
{'ip_address': ip_address,
'port_uuid': port_uuid})
raise exception.InvalidIPAddress(ip_address=ip_address)
"address %(ip_address)s on port %(port_id)s.",
{'ip_address': ip_address, 'port_id': port_id})
raise exception.InvalidIPv4Address(ip_address=ip_address)
except ValueError as exc:
LOG.error("An Invalid IP address was supplied and failed "
"basic validation: %s", exc)
raise exception.InvalidIPAddress(ip_address=ip_address)
else:
LOG.error("No IP address assigned to Neutron port %s.",
port_uuid)
raise exception.FailedToGetIPAddressOnPort(port_id=port_uuid)
port_id)
raise exception.FailedToGetIPAddressOnPort(port_id=port_id)
def _get_port_ip_address(self, task, p_obj, client):
"""Get ip address of ironic port/portgroup assigned by Neutron.
@ -244,8 +243,7 @@ class NeutronDHCPApi(base.BaseDHCP):
ip_addresses = []
for obj in pobj_list:
try:
vif_ip_address = self._get_port_ip_address(task, obj,
client)
vif_ip_address = self._get_port_ip_address(task, obj, client)
ip_addresses.append(vif_ip_address)
except (exception.FailedToGetIPAddressOnPort,
exception.InvalidIPv4Address,

View File

@ -15,7 +15,7 @@
import collections
from neutronclient.common import exceptions as neutron_exceptions
from openstack.connection import exceptions as openstack_exc
from oslo_config import cfg
from oslo_log import log
@ -267,47 +267,40 @@ def plug_port_to_tenant_network(task, port_like_obj, client=None):
# NOTE(sambetts) Only update required binding: attributes,
# because other port attributes may have been set by the user or
# nova.
body = {
'port': {
'binding:vnic_type': neutron.VNIC_BAREMETAL,
'binding:host_id': node.uuid,
'mac_address': port_like_obj.address
}
}
port_attrs = {'binding:vnic_type': neutron.VNIC_BAREMETAL,
'binding:host_id': node.uuid,
'mac_address': port_like_obj.address}
binding_profile = {'local_link_information': local_link_info}
if local_group_info:
binding_profile['local_group_information'] = local_group_info
body['port']['binding:profile'] = binding_profile
port_attrs['binding:profile'] = binding_profile
if client_id_opt:
body['port']['extra_dhcp_opts'] = [client_id_opt]
port_attrs['extra_dhcp_opts'] = [client_id_opt]
is_smart_nic = neutron.is_smartnic_port(port_like_obj)
if is_smart_nic:
link_info = local_link_info[0]
LOG.debug('Setting hostname as host_id in case of Smart NIC, '
'port %(port_id)s, hostname %(hostname)s',
{'port_id': vif_id,
'hostname': link_info['hostname']})
body['port']['binding:host_id'] = link_info['hostname']
body['port']['binding:vnic_type'] = neutron.VNIC_SMARTNIC
{'port_id': vif_id, 'hostname': link_info['hostname']})
port_attrs['binding:host_id'] = link_info['hostname']
port_attrs['binding:vnic_type'] = neutron.VNIC_SMARTNIC
if not client:
client = neutron.get_client(context=task.context)
if is_smart_nic:
neutron.wait_for_host_agent(client, body['port']['binding:host_id'])
neutron.wait_for_host_agent(client, port_attrs['binding:host_id'])
try:
neutron.update_neutron_port(task.context, vif_id, body)
neutron.update_neutron_port(task.context, vif_id, port_attrs)
if is_smart_nic:
neutron.wait_for_port_status(client, vif_id, 'ACTIVE')
except neutron_exceptions.ConnectionFailed as e:
except openstack_exc.OpenStackCloudException as e:
msg = (_('Could not add public network VIF %(vif)s '
'to node %(node)s, possible network issue. %(exc)s') %
{'vif': vif_id,
'node': node.uuid,
'exc': e})
{'vif': vif_id, 'node': node.uuid, 'exc': e})
LOG.error(msg)
raise exception.NetworkError(msg)
@ -467,8 +460,7 @@ class NeutronVIFPortIDMixin(VIFPortIDMixin):
original_port = objects.Port.get_by_id(context, port_obj.id)
updated_client_id = port_obj.extra.get('client-id')
if (original_port.extra.get('client-id')
!= updated_client_id):
if original_port.extra.get('client-id') != updated_client_id:
# DHCP Option with opt_value=None will remove it
# from the neutron port
if vif:
@ -485,8 +477,7 @@ class NeutronVIFPortIDMixin(VIFPortIDMixin):
"No VIF found for instance %(instance)s "
"port %(port)s when attempting to update port "
"client-id.",
{'port': port_uuid,
'instance': node.instance_uuid})
{'port': port_uuid, 'instance': node.instance_uuid})
if portgroup_obj and ((set(port_obj.obj_what_changed())
& {'pxe_enabled', 'portgroup_id'}) or vif):

View File

@ -14,7 +14,7 @@
Flat network interface. Useful for shared, flat networks.
"""
from neutronclient.common import exceptions as neutron_exceptions
from openstack.connection import exceptions as openstack_exc
from oslo_config import cfg
from oslo_log import log
@ -62,17 +62,13 @@ class FlatNetwork(common.NeutronVIFPortIDMixin,
)
if not vif_port_id:
continue
body = {
'port': {
'binding:host_id': task.node.uuid,
'binding:vnic_type': neutron.VNIC_BAREMETAL,
'mac_address': port_like_obj.address
}
}
port_attrs = {'binding:host_id': task.node.uuid,
'binding:vnic_type': neutron.VNIC_BAREMETAL,
'mac_address': port_like_obj.address}
try:
neutron.update_neutron_port(task.context,
vif_port_id, body)
except neutron_exceptions.NeutronClientException as e:
vif_port_id, port_attrs)
except openstack_exc.OpenStackCloudException as e:
msg = (_('Unable to set binding:host_id for '
'neutron port %(port_id)s. Error: '
'%(err)s') % {'port_id': vif_port_id, 'err': e})

View File

@ -21,7 +21,7 @@ from unittest import mock
from glanceclient import client as glance_client
from glanceclient import exc as glance_exc
from keystoneauth1 import loading as kaloading
from keystoneauth1 import loading as ks_loading
from oslo_config import cfg
from oslo_utils import uuidutils
import retrying
@ -353,8 +353,8 @@ class CheckImageServiceTestCase(base.TestCase):
self.context = context.RequestContext(global_request_id='global')
self.service = image_service.GlanceImageService(None, self.context)
# NOTE(pas-ha) register keystoneauth dynamic options manually
plugin = kaloading.get_plugin_loader('password')
opts = kaloading.get_auth_plugin_conf_options(plugin)
plugin = ks_loading.get_plugin_loader('password')
opts = ks_loading.get_auth_plugin_conf_options(plugin)
self.cfg_fixture.register_opts(opts, group='glance')
self.config(auth_type='password',
auth_url='viking',

View File

@ -14,7 +14,7 @@
from unittest import mock
from keystoneauth1 import loading as kaloading
from keystoneauth1 import loading as ks_loading
from oslo_config import cfg
from oslo_config import fixture
@ -38,8 +38,8 @@ class KeystoneTestCase(base.TestCase):
# NOTE(pas-ha) this is due to auth_plugin options
# being dynamically registered on first load,
# but we need to set the config before
plugin = kaloading.get_plugin_loader('password')
opts = kaloading.get_auth_plugin_conf_options(plugin)
plugin = ks_loading.get_plugin_loader('password')
opts = ks_loading.get_auth_plugin_conf_options(plugin)
self.cfg_fixture.register_opts(opts, group=self.test_group)
self.config(auth_url='http://127.0.0.1:9898',
username='fake_user',

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from keystoneauth1 import loading as kaloading
from keystoneauth1 import loading as ks_loading
from oslo_config import cfg
from ironic.conf import auth as ironic_auth
@ -31,8 +31,8 @@ class AuthConfTestCase(base.TestCase):
# NOTE(pas-ha) this is due to auth_plugin options
# being dynamically registered on first load,
# but we need to set the config before
plugin = kaloading.get_plugin_loader('password')
opts = kaloading.get_auth_plugin_conf_options(plugin)
plugin = ks_loading.get_plugin_loader('password')
opts = ks_loading.get_auth_plugin_conf_options(plugin)
self.cfg_fixture.register_opts(opts, group=self.test_group)
self.config(auth_url='http://127.0.0.1:9898',
username='fake_user',

View File

@ -16,7 +16,7 @@
from unittest import mock
from neutronclient.common import exceptions as neutron_client_exc
from openstack.connection import exceptions as openstack_exc
from oslo_utils import uuidutils
from ironic.common import dhcp_factory
@ -59,7 +59,7 @@ class TestNeutron(db_base.DbTestCase):
{'opt_name': 'server-ip-address',
'opt_value': '1.1.1.1'}]
port_id = 'fake-port-id'
expected = {'port': {'extra_dhcp_opts': opts}}
expected = {'extra_dhcp_opts': opts}
port_data = {
"id": port_id,
"fixed_ips": [
@ -68,7 +68,7 @@ class TestNeutron(db_base.DbTestCase):
}
],
}
client_mock.return_value.show_port.return_value = {'port': port_data}
client_mock.return_value.get_port.return_value = port_data
api = dhcp_factory.DHCPFactory()
with task_manager.acquire(self.context, self.node.uuid) as task:
@ -94,12 +94,13 @@ class TestNeutron(db_base.DbTestCase):
'ip_version': 6}]
port_id = 'fake-port-id'
expected = {
'port': {
'extra_dhcp_opts': [{
'extra_dhcp_opts': [
{
'opt_name': 'bootfile-url',
'opt_value': 'tftp://::1/file.name',
'ip_version': 6}]
}
'ip_version': 6
}
]
}
port_data = {
"id": port_id,
@ -109,7 +110,7 @@ class TestNeutron(db_base.DbTestCase):
}
],
}
client_mock.return_value.show_port.return_value = {'port': port_data}
client_mock.return_value.get_port.return_value = port_data
api = dhcp_factory.DHCPFactory()
with task_manager.acquire(self.context, self.node.uuid) as task:
@ -132,9 +133,8 @@ class TestNeutron(db_base.DbTestCase):
}
],
}
client_mock.return_value.show_port.return_value = {'port': port_data}
update_mock.side_effect = (
neutron_client_exc.NeutronClientException())
client_mock.return_value.get_port.return_value = port_data
update_mock.side_effect = openstack_exc.OpenStackCloudException()
api = dhcp_factory.DHCPFactory()
with task_manager.acquire(self.context, self.node.uuid) as task:
@ -262,10 +262,10 @@ class TestNeutron(db_base.DbTestCase):
"device_id": 'bece68a3-2f8b-4e66-9092-244493d6aba7',
}
fake_client = mock.Mock()
fake_client.show_port.return_value = {'port': port_data}
fake_client.get_port.return_value = port_data
result = api._get_fixed_ip_address(port_id, fake_client)
self.assertEqual(expected, result)
fake_client.show_port.assert_called_once_with(port_id)
fake_client.get_port.assert_called_once_with(port_id)
def test__get_fixed_ip_address_ipv6(self):
port_id = 'fake-port-id'
@ -286,10 +286,10 @@ class TestNeutron(db_base.DbTestCase):
"device_id": 'bece68a3-2f8b-4e66-9092-244493d6aba7',
}
fake_client = mock.Mock()
fake_client.show_port.return_value = {'port': port_data}
fake_client.get_port.return_value = port_data
result = api._get_fixed_ip_address(port_id, fake_client)
self.assertEqual(expected, result)
fake_client.show_port.assert_called_once_with(port_id)
fake_client.get_port.assert_called_once_with(port_id)
def test__get_fixed_ip_address_invalid_ip(self):
port_id = 'fake-port-id'
@ -309,22 +309,23 @@ class TestNeutron(db_base.DbTestCase):
"device_id": 'bece68a3-2f8b-4e66-9092-244493d6aba7',
}
fake_client = mock.Mock()
fake_client.show_port.return_value = {'port': port_data}
fake_client.get_port.return_value = port_data
self.assertRaises(exception.InvalidIPAddress,
api._get_fixed_ip_address,
port_id, fake_client)
fake_client.show_port.assert_called_once_with(port_id)
fake_client.get_port.assert_called_once_with(port_id)
def test__get_fixed_ip_address_with_exception(self):
port_id = 'fake-port-id'
api = dhcp_factory.DHCPFactory().provider
fake_client = mock.Mock()
fake_client.show_port.side_effect = (
neutron_client_exc.NeutronClientException())
fake_client.get_port.side_effect = (
openstack_exc.OpenStackCloudException())
self.assertRaises(exception.NetworkError,
api._get_fixed_ip_address, port_id, fake_client)
fake_client.show_port.assert_called_once_with(port_id)
fake_client.get_port.assert_called_once_with(port_id)
@mock.patch('ironic.dhcp.neutron.NeutronDHCPApi._get_fixed_ip_address',
autospec=True)

View File

@ -12,7 +12,7 @@
from unittest import mock
from neutronclient.common import exceptions as neutron_exceptions
from openstack.connection import exceptions as openstack_exc
from oslo_config import cfg
from oslo_utils import uuidutils
@ -178,9 +178,9 @@ class TestFlatInterface(db_base.DbTestCase):
utils.create_test_port(self.context, node_id=self.node.id,
address='52:54:00:cf:2d:33', extra=extra,
uuid=uuidutils.generate_uuid())
exp_body = {'port': {'binding:host_id': self.node.uuid,
'binding:vnic_type': neutron.VNIC_BAREMETAL,
'mac_address': '52:54:00:cf:2d:33'}}
exp_body = {'binding:host_id': self.node.uuid,
'binding:vnic_type': neutron.VNIC_BAREMETAL,
'mac_address': '52:54:00:cf:2d:33'}
with task_manager.acquire(self.context, self.node.id) as task:
self.interface._bind_flat_ports(task)
update_mock.assert_called_once_with(self.context, 'foo', exp_body)
@ -194,12 +194,12 @@ class TestFlatInterface(db_base.DbTestCase):
utils.create_test_port(
self.context, node_id=self.node.id, address='52:54:00:cf:2d:33',
extra={'vif_port_id': 'bar'}, uuid=uuidutils.generate_uuid())
exp_body1 = {'port': {'binding:host_id': self.node.uuid,
'binding:vnic_type': neutron.VNIC_BAREMETAL,
'mac_address': '52:54:00:cf:2d:33'}}
exp_body2 = {'port': {'binding:host_id': self.node.uuid,
'binding:vnic_type': neutron.VNIC_BAREMETAL,
'mac_address': '52:54:00:cf:2d:31'}}
exp_body1 = {'binding:host_id': self.node.uuid,
'binding:vnic_type': neutron.VNIC_BAREMETAL,
'mac_address': '52:54:00:cf:2d:33'}
exp_body2 = {'binding:host_id': self.node.uuid,
'binding:vnic_type': neutron.VNIC_BAREMETAL,
'mac_address': '52:54:00:cf:2d:31'}
with task_manager.acquire(self.context, self.node.id) as task:
self.interface._bind_flat_ports(task)
update_mock.assert_has_calls([
@ -235,7 +235,7 @@ class TestFlatInterface(db_base.DbTestCase):
@mock.patch.object(neutron, 'update_neutron_port', autospec=True)
def test__bind_flat_ports_set_binding_host_id_raise(self, update_mock):
update_mock.side_effect = (neutron_exceptions.ConnectionFailed())
update_mock.side_effect = openstack_exc.OpenStackCloudException()
extra = {'vif_port_id': 'foo'}
utils.create_test_port(self.context, node_id=self.node.id,
address='52:54:00:cf:2d:33', extra=extra,

View File

@ -13,7 +13,7 @@
import copy
from unittest import mock
from neutronclient.common import exceptions as neutron_exceptions
from openstack.connection import exceptions as openstack_exc
from oslo_config import cfg
from oslo_utils import uuidutils
@ -25,6 +25,7 @@ from ironic.drivers import base as drivers_base
from ironic.drivers.modules.network import neutron
from ironic.tests.unit.db import base as db_base
from ironic.tests.unit.objects import utils
from ironic.tests.unit import stubs
CONF = cfg.CONF
CLIENT_ID1 = '20:00:55:04:01:fe:80:00:00:00:00:00:00:00:02:c9:02:00:23:13:92'
@ -53,8 +54,9 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
self.context, node_id=self.node.id,
address='52:54:00:cf:2d:32',
extra={'vif_port_id': uuidutils.generate_uuid()})
self.neutron_port = {'id': '132f871f-eaec-4fed-9475-0d54465e0f00',
'mac_address': '52:54:00:cf:2d:32'}
self.neutron_port = stubs.FakeNeutronPort(
id='132f871f-eaec-4fed-9475-0d54465e0f00',
mac_address='52:54:00:cf:2d:32')
@mock.patch('%s.vif_list' % VIFMIXINPATH, autospec=True)
def test_vif_list(self, mock_vif_list):
@ -171,7 +173,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
validate_mock):
self.port.internal_info = {'provisioning_vif_port_id': 'vif-port-id'}
self.port.save()
add_ports_mock.return_value = {self.port.uuid: self.neutron_port['id']}
add_ports_mock.return_value = {self.port.uuid: self.neutron_port.id}
with task_manager.acquire(self.context, self.node.id) as task:
self.interface.add_provisioning_network(task)
rollback_mock.assert_called_once_with(
@ -183,7 +185,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
CONF.neutron.provisioning_network,
'provisioning network', context=task.context)
self.port.refresh()
self.assertEqual(self.neutron_port['id'],
self.assertEqual(self.neutron_port.id,
self.port.internal_info['provisioning_vif_port_id'])
@mock.patch.object(neutron_common, 'validate_network',
@ -194,7 +196,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
rollback_mock, validate_mock):
self.port.internal_info = {'provisioning_vif_port_id': 'vif-port-id'}
self.port.save()
add_ports_mock.return_value = {self.port.uuid: self.neutron_port['id']}
add_ports_mock.return_value = {self.port.uuid: self.neutron_port.id}
# Make sure that changing the network UUID works
for provisioning_network_uuid in [
'3aea0de6-4b92-44da-9aa0-52d134c83fdf',
@ -215,7 +217,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
provisioning_network_uuid,
'provisioning network', context=task.context)
self.port.refresh()
self.assertEqual(self.neutron_port['id'],
self.assertEqual(self.neutron_port.id,
self.port.internal_info['provisioning_vif_port_id'])
@mock.patch.object(neutron_common, 'validate_network',
@ -230,7 +232,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
self.config(provisioning_network_security_groups=sg_ids,
group='neutron')
add_ports_mock.return_value = {self.port.uuid: self.neutron_port['id']}
add_ports_mock.return_value = {self.port.uuid: self.neutron_port.id}
with task_manager.acquire(self.context, self.node.id) as task:
self.interface.add_provisioning_network(task)
rollback_mock.assert_called_once_with(
@ -240,7 +242,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
security_groups=(
CONF.neutron.provisioning_network_security_groups))
self.port.refresh()
self.assertEqual(self.neutron_port['id'],
self.assertEqual(self.neutron_port.id,
self.port.internal_info['provisioning_vif_port_id'])
@mock.patch.object(neutron_common, 'validate_network',
@ -290,7 +292,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
@mock.patch.object(neutron_common, 'add_ports_to_network', autospec=True)
def test_add_cleaning_network(self, add_ports_mock, rollback_mock,
validate_mock):
add_ports_mock.return_value = {self.port.uuid: self.neutron_port['id']}
add_ports_mock.return_value = {self.port.uuid: self.neutron_port.id}
with task_manager.acquire(self.context, self.node.id) as task:
res = self.interface.add_cleaning_network(task)
rollback_mock.assert_called_once_with(
@ -300,7 +302,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
CONF.neutron.cleaning_network,
'cleaning network', context=task.context)
self.port.refresh()
self.assertEqual(self.neutron_port['id'],
self.assertEqual(self.neutron_port.id,
self.port.internal_info['cleaning_vif_port_id'])
@mock.patch.object(neutron_common, 'validate_network',
@ -309,7 +311,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
@mock.patch.object(neutron_common, 'add_ports_to_network', autospec=True)
def test_add_cleaning_network_from_node(self, add_ports_mock,
rollback_mock, validate_mock):
add_ports_mock.return_value = {self.port.uuid: self.neutron_port['id']}
add_ports_mock.return_value = {self.port.uuid: self.neutron_port.id}
# Make sure that changing the network UUID works
for cleaning_network_uuid in ['3aea0de6-4b92-44da-9aa0-52d134c83fdf',
'438be438-6aae-4fb1-bbcb-613ad7a38286']:
@ -326,7 +328,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
cleaning_network_uuid,
'cleaning network', context=task.context)
self.port.refresh()
self.assertEqual(self.neutron_port['id'],
self.assertEqual(self.neutron_port.id,
self.port.internal_info['cleaning_vif_port_id'])
@mock.patch.object(neutron_common, 'validate_network',
@ -334,7 +336,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
@mock.patch.object(neutron_common, 'rollback_ports', autospec=True)
@mock.patch.object(neutron_common, 'add_ports_to_network', autospec=True)
def test_add_cleaning_network_with_sg(self, add_ports_mock, rollback_mock):
add_ports_mock.return_value = {self.port.uuid: self.neutron_port['id']}
add_ports_mock.return_value = {self.port.uuid: self.neutron_port.id}
sg_ids = []
for i in range(2):
sg_ids.append(uuidutils.generate_uuid())
@ -348,7 +350,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
task, CONF.neutron.cleaning_network)
self.assertEqual(res, add_ports_mock.return_value)
self.port.refresh()
self.assertEqual(self.neutron_port['id'],
self.assertEqual(self.neutron_port.id,
self.port.internal_info['cleaning_vif_port_id'])
@mock.patch.object(neutron_common, 'validate_network',
@ -485,7 +487,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
@mock.patch.object(neutron_common, 'rollback_ports', autospec=True)
@mock.patch.object(neutron_common, 'add_ports_to_network', autospec=True)
def test_add_rescuing_network_with_sg(self, add_ports_mock, rollback_mock):
add_ports_mock.return_value = {self.port.uuid: self.neutron_port['id']}
add_ports_mock.return_value = {self.port.uuid: self.neutron_port.id}
sg_ids = []
for i in range(2):
sg_ids.append(uuidutils.generate_uuid())
@ -499,7 +501,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
task, CONF.neutron.rescuing_network)
self.assertEqual(add_ports_mock.return_value, res)
self.port.refresh()
self.assertEqual(self.neutron_port['id'],
self.assertEqual(self.neutron_port.id,
self.port.internal_info['rescuing_vif_port_id'])
@mock.patch.object(neutron_common, 'validate_network',
@ -583,21 +585,20 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
@mock.patch.object(neutron, 'LOG', autospec=True)
def test_configure_tenant_networks_multiple_ports_one_vif_id(
self, log_mock, client_mock, update_mock, wait_agent_mock):
expected_body = {
'port': {
'binding:vnic_type': 'baremetal',
'binding:host_id': self.node.uuid,
'binding:profile': {'local_link_information':
[self.port.local_link_connection]},
'mac_address': '52:54:00:cf:2d:32'
}
expected_attrs = {
'binding:vnic_type': 'baremetal',
'binding:host_id': self.node.uuid,
'binding:profile': {
'local_link_information': [self.port.local_link_connection]
},
'mac_address': '52:54:00:cf:2d:32'
}
with task_manager.acquire(self.context, self.node.id) as task:
self.interface.configure_tenant_networks(task)
client_mock.assert_called_once_with(context=task.context)
update_mock.assert_called_once_with(self.context,
self.port.extra['vif_port_id'],
expected_body)
expected_attrs)
@mock.patch.object(neutron_common, 'wait_for_host_agent', autospec=True)
@mock.patch.object(neutron_common, 'update_neutron_port', autospec=True)
@ -605,8 +606,8 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
def test_configure_tenant_networks_update_fail(self, client_mock,
update_mock,
wait_agent_mock):
update_mock.side_effect = neutron_exceptions.ConnectionFailed(
reason='meow')
update_mock.side_effect = openstack_exc.OpenStackCloudException(
message='meow')
with task_manager.acquire(self.context, self.node.id) as task:
self.assertRaisesRegex(
exception.NetworkError, 'Could not add',
@ -645,27 +646,23 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
port.extra = extra
port.save()
expected_body = {
'port': {
'binding:vnic_type': 'baremetal',
'binding:host_id': self.node.uuid,
}
}
port1_body = copy.deepcopy(expected_body)
port1_body['port']['binding:profile'] = {
expected_attrs = {'binding:vnic_type': 'baremetal',
'binding:host_id': self.node.uuid}
port1_attrs = copy.deepcopy(expected_attrs)
port1_attrs['binding:profile'] = {
'local_link_information': [self.port.local_link_connection]
}
port1_body['port']['mac_address'] = '52:54:00:cf:2d:32'
port2_body = copy.deepcopy(expected_body)
port2_body['port']['binding:profile'] = {
port1_attrs['mac_address'] = '52:54:00:cf:2d:32'
port2_attrs = copy.deepcopy(expected_attrs)
port2_attrs['binding:profile'] = {
'local_link_information': [second_port.local_link_connection]
}
port2_body['port']['mac_address'] = '52:54:00:cf:2d:33'
port2_attrs['mac_address'] = '52:54:00:cf:2d:33'
if is_client_id:
port1_body['port']['extra_dhcp_opts'] = (
[{'opt_name': '61', 'opt_value': client_ids[0]}])
port2_body['port']['extra_dhcp_opts'] = (
[{'opt_name': '61', 'opt_value': client_ids[1]}])
port1_attrs['extra_dhcp_opts'] = [{'opt_name': '61',
'opt_value': client_ids[0]}]
port2_attrs['extra_dhcp_opts'] = [{'opt_name': '61',
'opt_value': client_ids[1]}]
with task_manager.acquire(self.context, self.node.id) as task:
self.interface.configure_tenant_networks(task)
client_mock.assert_called_once_with(context=task.context)
@ -676,8 +673,8 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
portid1 = self.port.extra['vif_port_id']
portid2 = second_port.extra['vif_port_id']
update_mock.assert_has_calls(
[mock.call(self.context, portid1, port1_body),
mock.call(self.context, portid2, port2_body)],
[mock.call(self.context, portid1, port1_attrs),
mock.call(self.context, portid2, port2_attrs)],
any_order=True
)
@ -729,24 +726,20 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
)
local_group_info = {'a': 'b'}
glgi_mock.return_value = local_group_info
expected_body = {
'port': {
'binding:vnic_type': 'baremetal',
'binding:host_id': self.node.uuid,
}
expected_attrs = {'binding:vnic_type': 'baremetal',
'binding:host_id': self.node.uuid}
call1_attrs = copy.deepcopy(expected_attrs)
call1_attrs['binding:profile'] = {
'local_link_information': [self.port.local_link_connection]
}
call1_body = copy.deepcopy(expected_body)
call1_body['port']['binding:profile'] = {
'local_link_information': [self.port.local_link_connection],
}
call1_body['port']['mac_address'] = '52:54:00:cf:2d:32'
call2_body = copy.deepcopy(expected_body)
call2_body['port']['binding:profile'] = {
call1_attrs['mac_address'] = '52:54:00:cf:2d:32'
call2_attrs = copy.deepcopy(expected_attrs)
call2_attrs['binding:profile'] = {
'local_link_information': [port1.local_link_connection,
port2.local_link_connection],
'local_group_information': local_group_info
}
call2_body['port']['mac_address'] = 'ff:54:00:cf:2d:32'
call2_attrs['mac_address'] = 'ff:54:00:cf:2d:32'
with task_manager.acquire(self.context, self.node.id) as task:
# Override task.portgroups here, to have ability to check
# that mocked get_local_group_information was called with
@ -757,9 +750,9 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
glgi_mock.assert_called_once_with(task, pg)
update_mock.assert_has_calls(
[mock.call(self.context, self.port.extra['vif_port_id'],
call1_body),
call1_attrs),
mock.call(self.context, pg.extra['vif_port_id'],
call2_body)]
call2_attrs)]
)
def test_need_power_on_true(self):
@ -778,7 +771,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
@mock.patch.object(neutron_common, 'add_ports_to_network', autospec=True)
def test_add_inspection_network(self, add_ports_mock, rollback_mock,
validate_mock):
add_ports_mock.return_value = {self.port.uuid: self.neutron_port['id']}
add_ports_mock.return_value = {self.port.uuid: self.neutron_port.id}
with task_manager.acquire(self.context, self.node.id) as task:
res = self.interface.add_inspection_network(task)
rollback_mock.assert_called_once_with(
@ -788,7 +781,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
CONF.neutron.inspection_network,
'inspection network', context=task.context)
self.port.refresh()
self.assertEqual(self.neutron_port['id'],
self.assertEqual(self.neutron_port.id,
self.port.internal_info['inspection_vif_port_id'])
@mock.patch.object(neutron_common, 'validate_network',
@ -797,7 +790,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
@mock.patch.object(neutron_common, 'add_ports_to_network', autospec=True)
def test_add_inspection_network_from_node(self, add_ports_mock,
rollback_mock, validate_mock):
add_ports_mock.return_value = {self.port.uuid: self.neutron_port['id']}
add_ports_mock.return_value = {self.port.uuid: self.neutron_port.id}
# Make sure that changing the network UUID works
for inspection_network_uuid in [
'3aea0de6-4b92-44da-9aa0-52d134c83fdf',
@ -815,7 +808,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
inspection_network_uuid,
'inspection network', context=task.context)
self.port.refresh()
self.assertEqual(self.neutron_port['id'],
self.assertEqual(self.neutron_port.id,
self.port.internal_info['inspection_vif_port_id'])
@mock.patch.object(neutron_common, 'validate_network',
@ -824,7 +817,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
@mock.patch.object(neutron_common, 'add_ports_to_network', autospec=True)
def test_add_inspection_network_with_sg(self, add_ports_mock,
rollback_mock):
add_ports_mock.return_value = {self.port.uuid: self.neutron_port['id']}
add_ports_mock.return_value = {self.port.uuid: self.neutron_port.id}
sg_ids = []
for i in range(2):
sg_ids.append(uuidutils.generate_uuid())
@ -839,7 +832,7 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
task, CONF.neutron.inspection_network)
self.assertEqual(res, add_ports_mock.return_value)
self.port.refresh()
self.assertEqual(self.neutron_port['id'],
self.assertEqual(self.neutron_port.id,
self.port.internal_info['inspection_vif_port_id'])
@mock.patch.object(neutron_common, 'validate_network',

View File

@ -76,3 +76,185 @@ class FakeImage(dict):
self[key] = value
else:
raise AttributeError(key)
class FakeNeutronPort(dict):
def __init__(self, **attrs):
PORT_ATTRS = ['admin_state_up',
'allowed_address_pairs',
'binding:host_id',
'binding:profile',
'binding:vif_details',
'binding:vif_type',
'binding:vnic_type',
'data_plane_status',
'description',
'device_id',
'device_owner',
'dns_assignment',
'dns_domain',
'dns_name',
'extra_dhcp_opts',
'fixed_ips',
'id',
'mac_address',
'name', 'network_id',
'port_security_enabled',
'security_group_ids',
'status',
'tenant_id',
'qos_network_policy_id',
'qos_policy_id',
'tags',
'uplink_status_propagation']
raw = dict.fromkeys(PORT_ATTRS)
raw.update(attrs)
super(FakeNeutronPort, self).__init__(raw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(key)
def __setattr__(self, key, value):
if key in self:
self[key] = value
else:
raise AttributeError(key)
class FakeNeutronSubnet(dict):
def __init__(self, **attrs):
SUBNET_ATTRS = ['id',
'name',
'network_id',
'cidr',
'tenant_id',
'enable_dhcp',
'dns_nameservers',
'allocation_pools',
'host_routes',
'ip_version',
'gateway_ip',
'ipv6_address_mode',
'ipv6_ra_mode',
'subnetpool_id']
raw = dict.fromkeys(SUBNET_ATTRS)
raw.update(attrs)
super(FakeNeutronSubnet, self).__init__(raw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(key)
def __setattr__(self, key, value):
if key in self:
self[key] = value
else:
raise AttributeError(key)
class FakeNeutronNetwork(dict):
def __init__(self, **attrs):
NETWORK_ATTRS = ['id',
'name',
'status',
'tenant_id',
'admin_state_up',
'segments',
'shared',
'subnets',
'provider:network_type',
'provider:physical_network',
'provider:segmentation_id',
'router:external',
'availability_zones',
'availability_zone_hints',
'is_default']
raw = dict.fromkeys(NETWORK_ATTRS)
raw.update(attrs)
raw.update({
'provider_physical_network': attrs.get(
'provider:physical_network', None)})
super(FakeNeutronNetwork, self).__init__(raw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(key)
def __setattr__(self, key, value):
if key in self:
self[key] = value
else:
raise AttributeError(key)
class FakeNeutronAgent(dict):
def __init__(self, **attrs):
AGENT_ATTRS = ['admin_state_up',
'agents',
'agent_type',
'alive',
'availability_zone',
'binary',
'configurations',
'created_at',
'description',
'heartbeat_timestamp',
'host',
'id',
'resources_synced',
'started_at',
'topic']
raw = dict.fromkeys(AGENT_ATTRS)
raw.update(attrs)
raw.update({'is_alive': attrs.get('alive', False)})
super(FakeNeutronAgent, self).__init__(raw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(key)
def __setattr__(self, key, value):
if key in self:
self[key] = value
else:
raise AttributeError(key)
class FakeNeutronSecurityGroup(dict):
def __init__(self, **attrs):
SECURITY_GROUP_ATTRS = ['id',
'name',
'description',
'stateful',
'project_id',
'tenant_id',
'security_group_rules']
raw = dict.fromkeys(SECURITY_GROUP_ATTRS)
raw.update(attrs)
super(FakeNeutronSecurityGroup, self).__init__(raw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(key)
def __setattr__(self, key, value):
if key in self:
self[key] = value
else:
raise AttributeError(key)

View File

@ -56,7 +56,7 @@ msgpack-python==0.5.6
munch==2.5.0
netaddr==0.7.19
netifaces==0.10.9
openstacksdk==0.37.0
openstacksdk==0.48.0
os-client-config==2.1.0
os-service-types==1.7.0
os-traits==0.4.0
@ -106,7 +106,6 @@ python-editor==1.0.4
python-glanceclient==2.8.0
python-keystoneclient==4.0.0
python-mimeparse==1.6.0
python-neutronclient==6.7.0
python-subunit==1.4.0
python-swiftclient==3.2.0
pytz==2013.6

View File

@ -0,0 +1,10 @@
---
deprecations:
- |
With the switch from neutronclient to openstacksdk the ``[neutron]/retries``
option has been deprecated, use ``[neutron]/status_code_retries`` and
``[neutron]/status_code_retry_delay`` instead.
other:
- |
Communication with neutron is now using openstacksdk, removing the
dependency on neutronclient.

View File

@ -8,7 +8,6 @@ automaton>=1.9.0 # Apache-2.0
eventlet!=0.18.3,!=0.20.1,>=0.18.2 # MIT
WebOb>=1.7.1 # MIT
python-cinderclient!=4.0.0,>=3.3.0 # Apache-2.0
python-neutronclient>=6.7.0 # Apache-2.0
python-glanceclient>=2.8.0 # Apache-2.0
keystoneauth1>=4.2.0 # Apache-2.0
ironic-lib>=4.3.0 # Apache-2.0
@ -43,4 +42,4 @@ jsonschema>=3.2.0 # MIT
psutil>=3.2.2 # BSD
futurist>=1.2.0 # Apache-2.0
tooz>=2.7.0 # Apache-2.0
openstacksdk>=0.37.0 # Apache-2.0
openstacksdk>=0.48.0 # Apache-2.0