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:
parent
df9ce79f23
commit
ff00047b4a
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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' % {
|
||||
|
@ -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,
|
||||
|
@ -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 '
|
||||
|
@ -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',
|
||||
]
|
||||
)
|
||||
|
@ -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,
|
||||
|
@ -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):
|
||||
|
@ -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})
|
||||
|
@ -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',
|
||||
|
@ -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
@ -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',
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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',
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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.
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user