Merge "Switch Ironic to openstacksdk for Neutron"

This commit is contained in:
Zuul 2020-09-07 15:41:31 +00:00 committed by Gerrit Code Review
commit 30a9d33577
20 changed files with 828 additions and 893 deletions

View File

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

View File

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

View File

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

View File

@ -14,7 +14,7 @@
import copy import copy
from keystoneauth1 import loading as kaloading from keystoneauth1 import loading as ks_loading
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log 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. Registers only basic auth options shared by all auth plugins.
The rest are registered at runtime depending on auth plugin used. The rest are registered at runtime depending on auth plugin used.
""" """
kaloading.register_session_conf_options(conf, group) ks_loading.register_session_conf_options(conf, group)
kaloading.register_auth_conf_options(conf, group) ks_loading.register_auth_conf_options(conf, group)
kaloading.register_adapter_conf_options(conf, group) ks_loading.register_adapter_conf_options(conf, group)
conf.set_default('valid_interfaces', DEFAULT_VALID_INTERFACES, group=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 # 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') # 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.append(new_opt)
opts = copy.deepcopy(options) 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 # NOTE(dims): There are a lot of auth plugins, we just generate
# the config options for a few common ones # the config options for a few common ones
plugins = ['password', 'v2password', 'v3password'] plugins = ['password', 'v2password', 'v3password']
for name in plugins: for name in plugins:
plugin = kaloading.get_plugin_loader(name) plugin = ks_loading.get_plugin_loader(name)
add_options(opts, kaloading.get_auth_plugin_conf_options(plugin)) add_options(opts, ks_loading.get_auth_plugin_conf_options(plugin))
add_options(opts, kaloading.get_session_conf_options()) add_options(opts, ks_loading.get_session_conf_options())
if service_type: if service_type:
adapter_opts = kaloading.get_adapter_conf_options( adapter_opts = ks_loading.get_adapter_conf_options(
include_deprecated=False) include_deprecated=False)
# adding defaults for valid interfaces # adding defaults for valid interfaces
cfg.set_defaults(adapter_opts, service_type=service_type, cfg.set_defaults(adapter_opts, service_type=service_type,

View File

@ -29,7 +29,11 @@ opts = [
cfg.IntOpt('retries', cfg.IntOpt('retries',
default=3, default=3,
mutable=True, 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', cfg.StrOpt('cleaning_network',
mutable=True, mutable=True,
help=_('Neutron network UUID or name for the ramdisk to be ' 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', 'eventlet.wsgi.server=INFO',
'iso8601=WARNING', 'iso8601=WARNING',
'requests=WARNING', 'requests=WARNING',
'neutronclient=WARNING',
'glanceclient=WARNING', 'glanceclient=WARNING',
'urllib3.connectionpool=WARNING', 'urllib3.connectionpool=WARNING',
'keystonemiddleware.auth_token=INFO', 'keystonemiddleware.auth_token=INFO',
'keystoneauth.session=INFO', 'keystoneauth.session=INFO',
'openstack=WARNING',
] ]
) )

View File

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

View File

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

View File

@ -14,7 +14,7 @@
Flat network interface. Useful for shared, flat networks. 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_config import cfg
from oslo_log import log from oslo_log import log
@ -62,17 +62,13 @@ class FlatNetwork(common.NeutronVIFPortIDMixin,
) )
if not vif_port_id: if not vif_port_id:
continue continue
body = { port_attrs = {'binding:host_id': task.node.uuid,
'port': { 'binding:vnic_type': neutron.VNIC_BAREMETAL,
'binding:host_id': task.node.uuid, 'mac_address': port_like_obj.address}
'binding:vnic_type': neutron.VNIC_BAREMETAL,
'mac_address': port_like_obj.address
}
}
try: try:
neutron.update_neutron_port(task.context, neutron.update_neutron_port(task.context,
vif_port_id, body) vif_port_id, port_attrs)
except neutron_exceptions.NeutronClientException as e: except openstack_exc.OpenStackCloudException as e:
msg = (_('Unable to set binding:host_id for ' msg = (_('Unable to set binding:host_id for '
'neutron port %(port_id)s. Error: ' 'neutron port %(port_id)s. Error: '
'%(err)s') % {'port_id': vif_port_id, 'err': e}) '%(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 client as glance_client
from glanceclient import exc as glance_exc 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_config import cfg
from oslo_utils import uuidutils from oslo_utils import uuidutils
import retrying import retrying
@ -353,8 +353,8 @@ class CheckImageServiceTestCase(base.TestCase):
self.context = context.RequestContext(global_request_id='global') self.context = context.RequestContext(global_request_id='global')
self.service = image_service.GlanceImageService(None, self.context) self.service = image_service.GlanceImageService(None, self.context)
# NOTE(pas-ha) register keystoneauth dynamic options manually # NOTE(pas-ha) register keystoneauth dynamic options manually
plugin = kaloading.get_plugin_loader('password') plugin = ks_loading.get_plugin_loader('password')
opts = kaloading.get_auth_plugin_conf_options(plugin) opts = ks_loading.get_auth_plugin_conf_options(plugin)
self.cfg_fixture.register_opts(opts, group='glance') self.cfg_fixture.register_opts(opts, group='glance')
self.config(auth_type='password', self.config(auth_type='password',
auth_url='viking', auth_url='viking',

View File

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

View File

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

View File

@ -12,7 +12,7 @@
from unittest import mock 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_config import cfg
from oslo_utils import uuidutils 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, utils.create_test_port(self.context, node_id=self.node.id,
address='52:54:00:cf:2d:33', extra=extra, address='52:54:00:cf:2d:33', extra=extra,
uuid=uuidutils.generate_uuid()) uuid=uuidutils.generate_uuid())
exp_body = {'port': {'binding:host_id': self.node.uuid, exp_body = {'binding:host_id': self.node.uuid,
'binding:vnic_type': neutron.VNIC_BAREMETAL, 'binding:vnic_type': neutron.VNIC_BAREMETAL,
'mac_address': '52:54:00:cf:2d:33'}} 'mac_address': '52:54:00:cf:2d:33'}
with task_manager.acquire(self.context, self.node.id) as task: with task_manager.acquire(self.context, self.node.id) as task:
self.interface._bind_flat_ports(task) self.interface._bind_flat_ports(task)
update_mock.assert_called_once_with(self.context, 'foo', exp_body) update_mock.assert_called_once_with(self.context, 'foo', exp_body)
@ -194,12 +194,12 @@ class TestFlatInterface(db_base.DbTestCase):
utils.create_test_port( utils.create_test_port(
self.context, node_id=self.node.id, address='52:54:00:cf:2d:33', self.context, node_id=self.node.id, address='52:54:00:cf:2d:33',
extra={'vif_port_id': 'bar'}, uuid=uuidutils.generate_uuid()) extra={'vif_port_id': 'bar'}, uuid=uuidutils.generate_uuid())
exp_body1 = {'port': {'binding:host_id': self.node.uuid, exp_body1 = {'binding:host_id': self.node.uuid,
'binding:vnic_type': neutron.VNIC_BAREMETAL, 'binding:vnic_type': neutron.VNIC_BAREMETAL,
'mac_address': '52:54:00:cf:2d:33'}} 'mac_address': '52:54:00:cf:2d:33'}
exp_body2 = {'port': {'binding:host_id': self.node.uuid, exp_body2 = {'binding:host_id': self.node.uuid,
'binding:vnic_type': neutron.VNIC_BAREMETAL, 'binding:vnic_type': neutron.VNIC_BAREMETAL,
'mac_address': '52:54:00:cf:2d:31'}} 'mac_address': '52:54:00:cf:2d:31'}
with task_manager.acquire(self.context, self.node.id) as task: with task_manager.acquire(self.context, self.node.id) as task:
self.interface._bind_flat_ports(task) self.interface._bind_flat_ports(task)
update_mock.assert_has_calls([ update_mock.assert_has_calls([
@ -235,7 +235,7 @@ class TestFlatInterface(db_base.DbTestCase):
@mock.patch.object(neutron, 'update_neutron_port', autospec=True) @mock.patch.object(neutron, 'update_neutron_port', autospec=True)
def test__bind_flat_ports_set_binding_host_id_raise(self, update_mock): 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'} extra = {'vif_port_id': 'foo'}
utils.create_test_port(self.context, node_id=self.node.id, utils.create_test_port(self.context, node_id=self.node.id,
address='52:54:00:cf:2d:33', extra=extra, address='52:54:00:cf:2d:33', extra=extra,

View File

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

View File

@ -76,3 +76,185 @@ class FakeImage(dict):
self[key] = value self[key] = value
else: else:
raise AttributeError(key) 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

@ -52,7 +52,7 @@ msgpack-python==0.5.6
munch==2.5.0 munch==2.5.0
netaddr==0.7.19 netaddr==0.7.19
netifaces==0.10.9 netifaces==0.10.9
openstacksdk==0.37.0 openstacksdk==0.48.0
os-client-config==2.1.0 os-client-config==2.1.0
os-service-types==1.7.0 os-service-types==1.7.0
os-traits==0.4.0 os-traits==0.4.0
@ -101,7 +101,6 @@ python-editor==1.0.4
python-glanceclient==2.8.0 python-glanceclient==2.8.0
python-keystoneclient==4.0.0 python-keystoneclient==4.0.0
python-mimeparse==1.6.0 python-mimeparse==1.6.0
python-neutronclient==6.7.0
python-subunit==1.4.0 python-subunit==1.4.0
python-swiftclient==3.2.0 python-swiftclient==3.2.0
pytz==2013.6 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 eventlet!=0.18.3,!=0.20.1,>=0.18.2 # MIT
WebOb>=1.7.1 # MIT WebOb>=1.7.1 # MIT
python-cinderclient!=4.0.0,>=3.3.0 # Apache-2.0 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 python-glanceclient>=2.8.0 # Apache-2.0
keystoneauth1>=4.2.0 # Apache-2.0 keystoneauth1>=4.2.0 # Apache-2.0
ironic-lib>=4.3.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 psutil>=3.2.2 # BSD
futurist>=1.2.0 # Apache-2.0 futurist>=1.2.0 # Apache-2.0
tooz>=2.7.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