Use openstacksdk for ironic notifiers
This patch removes the dependency from ironicclient for the ironic event notifiers in favor of openstacksdk. Also, increasing minimum required versions for mock and openstacksdk. Change-Id: Ib76e19d29f0ae3db6d181578b638da699181f60d
This commit is contained in:
parent
9baec38435
commit
c6ff9c922e
@ -49,7 +49,7 @@ logutils==0.3.5
|
|||||||
Mako==0.4.0
|
Mako==0.4.0
|
||||||
MarkupSafe==1.0
|
MarkupSafe==1.0
|
||||||
mccabe==0.2.1
|
mccabe==0.2.1
|
||||||
mock==2.0.0
|
mock==3.0.0
|
||||||
monotonic==0.6;python_version<'3.3'
|
monotonic==0.6;python_version<'3.3'
|
||||||
mox3==0.20.0
|
mox3==0.20.0
|
||||||
msgpack-python==0.4.0
|
msgpack-python==0.4.0
|
||||||
@ -58,7 +58,7 @@ netaddr==0.7.18
|
|||||||
netifaces==0.10.4
|
netifaces==0.10.4
|
||||||
neutron-lib==1.29.1
|
neutron-lib==1.29.1
|
||||||
openstackdocstheme==1.30.0
|
openstackdocstheme==1.30.0
|
||||||
openstacksdk==0.11.2
|
openstacksdk==0.31.2
|
||||||
os-client-config==1.28.0
|
os-client-config==1.28.0
|
||||||
os-ken==0.3.0
|
os-ken==0.3.0
|
||||||
os-service-types==1.2.0
|
os-service-types==1.2.0
|
||||||
@ -111,7 +111,6 @@ pyroute2==0.5.3
|
|||||||
python-dateutil==2.5.3
|
python-dateutil==2.5.3
|
||||||
python-designateclient==2.7.0
|
python-designateclient==2.7.0
|
||||||
python-editor==1.0.3
|
python-editor==1.0.3
|
||||||
python-ironicclient==2.7.0
|
|
||||||
python-keystoneclient==3.8.0
|
python-keystoneclient==3.8.0
|
||||||
python-mimeparse==1.6.0
|
python-mimeparse==1.6.0
|
||||||
python-neutronclient==6.7.0
|
python-neutronclient==6.7.0
|
||||||
|
@ -77,6 +77,8 @@ ks_loading.register_auth_conf_options(cfg.CONF,
|
|||||||
common_config.IRONIC_CONF_SECTION)
|
common_config.IRONIC_CONF_SECTION)
|
||||||
ks_loading.register_session_conf_options(cfg.CONF,
|
ks_loading.register_session_conf_options(cfg.CONF,
|
||||||
common_config.IRONIC_CONF_SECTION)
|
common_config.IRONIC_CONF_SECTION)
|
||||||
|
ks_loading.register_adapter_conf_options(cfg.CONF,
|
||||||
|
common_config.IRONIC_CONF_SECTION)
|
||||||
common_config.register_ironic_opts()
|
common_config.register_ironic_opts()
|
||||||
|
|
||||||
|
|
||||||
|
@ -198,33 +198,6 @@ ironic_opts = [
|
|||||||
cfg.BoolOpt('enable_notifications', default=False,
|
cfg.BoolOpt('enable_notifications', default=False,
|
||||||
help=_("Send notification events to ironic. (For example on "
|
help=_("Send notification events to ironic. (For example on "
|
||||||
"relevant port status changes.)")),
|
"relevant port status changes.)")),
|
||||||
cfg.StrOpt('region_name',
|
|
||||||
help=_('Name of region used to get Ironic endpoints. Useful if '
|
|
||||||
'keystone manages more than one region.')),
|
|
||||||
cfg.StrOpt('endpoint_type',
|
|
||||||
default='public',
|
|
||||||
choices=['public', 'admin', 'internal'],
|
|
||||||
help=_('Type of the ironic endpoint to use. This endpoint '
|
|
||||||
'will be looked up in the keystone catalog and should '
|
|
||||||
'be one of public, internal or admin.')),
|
|
||||||
cfg.StrOpt('auth_strategy',
|
|
||||||
default='keystone',
|
|
||||||
choices=('keystone', 'noauth'),
|
|
||||||
help=_('Method to use for authentication: noauth or '
|
|
||||||
'keystone.')),
|
|
||||||
cfg.StrOpt('ironic_url',
|
|
||||||
default='http://localhost:6385/',
|
|
||||||
help=_('Ironic API URL, used to set Ironic API URL when '
|
|
||||||
'auth_strategy option is noauth to work with standalone '
|
|
||||||
'Ironic without keystone.')),
|
|
||||||
cfg.IntOpt('retry_interval',
|
|
||||||
default=2,
|
|
||||||
help=_('Interval between retries in case of conflict error '
|
|
||||||
'(HTTP 409).')),
|
|
||||||
cfg.IntOpt('max_retries',
|
|
||||||
default=30,
|
|
||||||
help=_('Maximum number of retries in case of conflict error '
|
|
||||||
'(HTTP 409).')),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,8 +13,6 @@
|
|||||||
# 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 ironicclient import client
|
|
||||||
from ironicclient import exc as ironic_exc
|
|
||||||
from keystoneauth1 import loading as ks_loading
|
from keystoneauth1 import loading as ks_loading
|
||||||
from neutron_lib.api.definitions import port as port_def
|
from neutron_lib.api.definitions import port as port_def
|
||||||
from neutron_lib.api.definitions import portbindings as portbindings_def
|
from neutron_lib.api.definitions import portbindings as portbindings_def
|
||||||
@ -22,6 +20,8 @@ from neutron_lib.callbacks import events
|
|||||||
from neutron_lib.callbacks import registry
|
from neutron_lib.callbacks import registry
|
||||||
from neutron_lib.callbacks import resources
|
from neutron_lib.callbacks import resources
|
||||||
from neutron_lib import constants as n_const
|
from neutron_lib import constants as n_const
|
||||||
|
from openstack import connection
|
||||||
|
from openstack import exceptions as os_exc
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
@ -61,33 +61,23 @@ class Notifier(object):
|
|||||||
def _get_ironic_client(self):
|
def _get_ironic_client(self):
|
||||||
"""Get Ironic client instance."""
|
"""Get Ironic client instance."""
|
||||||
|
|
||||||
# NOTE: To support standalone ironic without keystone
|
global IRONIC_SESSION
|
||||||
if cfg.CONF.ironic.auth_strategy == 'noauth':
|
|
||||||
args = {'token': 'noauth',
|
if not IRONIC_SESSION:
|
||||||
'endpoint': cfg.CONF.ironic.ironic_url}
|
IRONIC_SESSION = self._get_session(IRONIC_CONF_SECTION)
|
||||||
else:
|
|
||||||
global IRONIC_SESSION
|
return connection.Connection(
|
||||||
if not IRONIC_SESSION:
|
session=IRONIC_SESSION, oslo_conf=cfg.CONF).baremetal
|
||||||
IRONIC_SESSION = self._get_session(IRONIC_CONF_SECTION)
|
|
||||||
args = {'session': IRONIC_SESSION,
|
|
||||||
'region_name': cfg.CONF.ironic.region_name,
|
|
||||||
'endpoint_type': cfg.CONF.ironic.endpoint_type}
|
|
||||||
args['os_ironic_api_version'] = IRONIC_API_VERSION
|
|
||||||
args['max_retries'] = cfg.CONF.ironic.max_retries
|
|
||||||
args['retry_interval'] = cfg.CONF.ironic.retry_interval
|
|
||||||
return client.Client(IRONIC_CLIENT_VERSION, **args)
|
|
||||||
|
|
||||||
def send_events(self, batched_events):
|
def send_events(self, batched_events):
|
||||||
# NOTE(TheJulia): Friendly exception handling so operators
|
|
||||||
# can decouple updates.
|
|
||||||
try:
|
try:
|
||||||
self.irclient.events.create(events=batched_events)
|
response = self.irclient.post('/events',
|
||||||
except ironic_exc.NotFound:
|
json={'events': batched_events},
|
||||||
LOG.error('The ironic API appears to not support posting events. '
|
microversion='1.54')
|
||||||
'The API likely needs to be upgraded.')
|
os_exc.raise_from_response(response)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error('Unknown error encountered posting the event to '
|
LOG.exception('Error encountered posting the event to '
|
||||||
'ironic. {error}'.format(error=e))
|
'ironic. {error}'.format(error=e))
|
||||||
|
|
||||||
@registry.receives(resources.PORT, [events.AFTER_UPDATE])
|
@registry.receives(resources.PORT, [events.AFTER_UPDATE])
|
||||||
def process_port_update_event(self, resource, event, trigger,
|
def process_port_update_event(self, resource, event, trigger,
|
||||||
|
@ -16,10 +16,9 @@
|
|||||||
import eventlet
|
import eventlet
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from ironicclient import client
|
|
||||||
from ironicclient import exc as ironic_exc
|
|
||||||
from neutron_lib.api.definitions import portbindings as portbindings_def
|
from neutron_lib.api.definitions import portbindings as portbindings_def
|
||||||
from neutron_lib import constants as n_const
|
from neutron_lib import constants as n_const
|
||||||
|
from openstack import connection
|
||||||
|
|
||||||
from neutron.notifiers import batch_notifier
|
from neutron.notifiers import batch_notifier
|
||||||
from neutron.notifiers import ironic
|
from neutron.notifiers import ironic
|
||||||
@ -40,13 +39,13 @@ def get_fake_port():
|
|||||||
class TestIronicNotifier(base.BaseTestCase):
|
class TestIronicNotifier(base.BaseTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestIronicNotifier, self).setUp()
|
super(TestIronicNotifier, self).setUp()
|
||||||
|
with mock.patch.object(connection.Connection, 'baremetal',
|
||||||
|
autospec=False):
|
||||||
|
self.ironic_notifier = ironic.Notifier()
|
||||||
|
|
||||||
@mock.patch.object(batch_notifier.BatchNotifier, 'queue_event',
|
@mock.patch.object(batch_notifier.BatchNotifier, 'queue_event',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch.object(client, 'Client', autospec=False)
|
def test_process_port_update_event_bind_port(self, mock_queue_event):
|
||||||
def test_process_port_update_event_bind_port(self, mock_client,
|
|
||||||
mock_queue_event):
|
|
||||||
self.ironic_notifier = ironic.Notifier()
|
|
||||||
port = get_fake_port()
|
port = get_fake_port()
|
||||||
port.update({'status': n_const.PORT_STATUS_ACTIVE})
|
port.update({'status': n_const.PORT_STATUS_ACTIVE})
|
||||||
original_port = get_fake_port()
|
original_port = get_fake_port()
|
||||||
@ -66,10 +65,7 @@ class TestIronicNotifier(base.BaseTestCase):
|
|||||||
|
|
||||||
@mock.patch.object(batch_notifier.BatchNotifier, 'queue_event',
|
@mock.patch.object(batch_notifier.BatchNotifier, 'queue_event',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch.object(client, 'Client', autospec=False)
|
def test_process_port_update_event_bind_port_err(self, mock_queue_event):
|
||||||
def test_process_port_update_event_bind_port_err(self, mock_client,
|
|
||||||
mock_queue_event):
|
|
||||||
self.ironic_notifier = ironic.Notifier()
|
|
||||||
port = get_fake_port()
|
port = get_fake_port()
|
||||||
port.update({'status': n_const.PORT_STATUS_ERROR})
|
port.update({'status': n_const.PORT_STATUS_ERROR})
|
||||||
original_port = get_fake_port()
|
original_port = get_fake_port()
|
||||||
@ -89,10 +85,7 @@ class TestIronicNotifier(base.BaseTestCase):
|
|||||||
|
|
||||||
@mock.patch.object(batch_notifier.BatchNotifier, 'queue_event',
|
@mock.patch.object(batch_notifier.BatchNotifier, 'queue_event',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch.object(client, 'Client', autospec=False)
|
def test_process_port_update_event_unbind_port(self, mock_queue_event):
|
||||||
def test_process_port_update_event_unbind_port(self, mock_client,
|
|
||||||
mock_queue_event):
|
|
||||||
self.ironic_notifier = ironic.Notifier()
|
|
||||||
port = get_fake_port()
|
port = get_fake_port()
|
||||||
port.update({'status': n_const.PORT_STATUS_DOWN})
|
port.update({'status': n_const.PORT_STATUS_DOWN})
|
||||||
original_port = get_fake_port()
|
original_port = get_fake_port()
|
||||||
@ -112,10 +105,7 @@ class TestIronicNotifier(base.BaseTestCase):
|
|||||||
|
|
||||||
@mock.patch.object(batch_notifier.BatchNotifier, 'queue_event',
|
@mock.patch.object(batch_notifier.BatchNotifier, 'queue_event',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch.object(client, 'Client', autospec=False)
|
def test_process_port_update_event_unbind_port_err(self, mock_queue_event):
|
||||||
def test_process_port_update_event_unbind_port_err(self, mock_client,
|
|
||||||
mock_queue_event):
|
|
||||||
self.ironic_notifier = ironic.Notifier()
|
|
||||||
port = get_fake_port()
|
port = get_fake_port()
|
||||||
port.update({'status': n_const.PORT_STATUS_ERROR})
|
port.update({'status': n_const.PORT_STATUS_ERROR})
|
||||||
original_port = get_fake_port()
|
original_port = get_fake_port()
|
||||||
@ -135,9 +125,7 @@ class TestIronicNotifier(base.BaseTestCase):
|
|||||||
|
|
||||||
@mock.patch.object(batch_notifier.BatchNotifier, 'queue_event',
|
@mock.patch.object(batch_notifier.BatchNotifier, 'queue_event',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch.object(client, 'Client', autospec=False)
|
def test_process_port_delete_event(self, mock_queue_event):
|
||||||
def test_process_port_delete_event(self, mock_client, mock_queue_event):
|
|
||||||
self.ironic_notifier = ironic.Notifier()
|
|
||||||
port = get_fake_port()
|
port = get_fake_port()
|
||||||
self.ironic_notifier.process_port_delete_event(
|
self.ironic_notifier.process_port_delete_event(
|
||||||
'fake_resource', 'fake_event', 'fake_trigger', original_port=None,
|
'fake_resource', 'fake_event', 'fake_trigger', original_port=None,
|
||||||
@ -154,10 +142,7 @@ class TestIronicNotifier(base.BaseTestCase):
|
|||||||
|
|
||||||
@mock.patch.object(batch_notifier.BatchNotifier, 'queue_event',
|
@mock.patch.object(batch_notifier.BatchNotifier, 'queue_event',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch.object(client, 'Client', autospec=False)
|
def test_process_port_event_empty_uuid_field(self, mock_queue_event):
|
||||||
def test_process_port_event_empty_uuid_field(self, mock_client,
|
|
||||||
mock_queue_event):
|
|
||||||
self.ironic_notifier = ironic.Notifier()
|
|
||||||
port = get_fake_port()
|
port = get_fake_port()
|
||||||
port.update({'device_id': ''})
|
port.update({'device_id': ''})
|
||||||
self.ironic_notifier.process_port_delete_event(
|
self.ironic_notifier.process_port_delete_event(
|
||||||
@ -173,9 +158,7 @@ class TestIronicNotifier(base.BaseTestCase):
|
|||||||
'status': 'DELETED'})
|
'status': 'DELETED'})
|
||||||
|
|
||||||
@mock.patch.object(eventlet, 'spawn_n', autospec=True)
|
@mock.patch.object(eventlet, 'spawn_n', autospec=True)
|
||||||
@mock.patch.object(client, 'Client', autospec=False)
|
def test_queue_events(self, mock_spawn_n):
|
||||||
def test_queue_events(self, mock_client, mock_spawn_n):
|
|
||||||
self.ironic_notifier = ironic.Notifier()
|
|
||||||
port = get_fake_port()
|
port = get_fake_port()
|
||||||
self.ironic_notifier.process_port_delete_event(
|
self.ironic_notifier.process_port_delete_event(
|
||||||
'fake_resource', 'fake_event', 'fake_trigger', original_port=None,
|
'fake_resource', 'fake_event', 'fake_trigger', original_port=None,
|
||||||
@ -193,31 +176,18 @@ class TestIronicNotifier(base.BaseTestCase):
|
|||||||
2, len(self.ironic_notifier.batch_notifier._pending_events.queue))
|
2, len(self.ironic_notifier.batch_notifier._pending_events.queue))
|
||||||
self.assertEqual(2, mock_spawn_n.call_count)
|
self.assertEqual(2, mock_spawn_n.call_count)
|
||||||
|
|
||||||
@mock.patch.object(client, 'Client', autospec=False)
|
@mock.patch.object(connection.Connection, 'baremetal', autospec=True)
|
||||||
def test_send_events(self, mock_client):
|
def test_send_events(self, mock_client):
|
||||||
self.ironic_notifier = ironic.Notifier()
|
|
||||||
self.ironic_notifier.irclient = mock_client
|
self.ironic_notifier.irclient = mock_client
|
||||||
self.ironic_notifier.send_events(['test', 'events'])
|
self.ironic_notifier.send_events(['test', 'events'])
|
||||||
mock_client.events.create.assert_called_with(events=['test', 'events'])
|
mock_client.post.assert_called_with(
|
||||||
|
'/events', json={'events': ['test', 'events']},
|
||||||
|
microversion='1.54')
|
||||||
|
|
||||||
@mock.patch.object(ironic.LOG, 'error', autospec=True)
|
@mock.patch.object(ironic.LOG, 'exception', autospec=True)
|
||||||
@mock.patch.object(client, 'Client', autospec=False)
|
@mock.patch.object(connection.Connection, 'baremetal', autospec=True)
|
||||||
def test_send_event_method_not_found(self, mock_client, mock_log):
|
|
||||||
self.ironic_notifier = ironic.Notifier()
|
|
||||||
self.ironic_notifier.irclient = mock_client
|
|
||||||
exception = ironic_exc.NotFound()
|
|
||||||
mock_client.events.create.side_effect = exception
|
|
||||||
self.ironic_notifier.send_events(['test', 'events'])
|
|
||||||
self.assertEqual(1, mock_log.call_count)
|
|
||||||
mock_log.assert_called_with('The ironic API appears to not support '
|
|
||||||
'posting events. The API likely needs to '
|
|
||||||
'be upgraded.')
|
|
||||||
|
|
||||||
@mock.patch.object(ironic.LOG, 'error', autospec=True)
|
|
||||||
@mock.patch.object(client, 'Client', autospec=False)
|
|
||||||
def test_send_event_exception(self, mock_client, mock_log):
|
def test_send_event_exception(self, mock_client, mock_log):
|
||||||
self.ironic_notifier = ironic.Notifier()
|
|
||||||
self.ironic_notifier.irclient = mock_client
|
self.ironic_notifier.irclient = mock_client
|
||||||
mock_client.events.create.side_effect = Exception()
|
mock_client.post.side_effect = Exception()
|
||||||
self.ironic_notifier.send_events(['test', 'events'])
|
self.ironic_notifier.send_events(['test', 'events'])
|
||||||
self.assertEqual(1, mock_log.call_count)
|
self.assertEqual(1, mock_log.call_count)
|
||||||
|
@ -52,7 +52,7 @@ pyroute2>=0.5.3;sys_platform!='win32' # Apache-2.0 (+ dual licensed GPL2)
|
|||||||
weakrefmethod>=1.0.2;python_version=='2.7' # PSF
|
weakrefmethod>=1.0.2;python_version=='2.7' # PSF
|
||||||
|
|
||||||
python-novaclient>=9.1.0 # Apache-2.0
|
python-novaclient>=9.1.0 # Apache-2.0
|
||||||
python-ironicclient!=2.7.1,>=2.7.0 # Apache-2.0
|
openstacksdk>=0.31.2 # Apache-2.0
|
||||||
python-designateclient>=2.7.0 # Apache-2.0
|
python-designateclient>=2.7.0 # Apache-2.0
|
||||||
os-xenapi>=0.3.1 # Apache-2.0
|
os-xenapi>=0.3.1 # Apache-2.0
|
||||||
os-vif>=1.15.1 # Apache-2.0
|
os-vif>=1.15.1 # Apache-2.0
|
||||||
|
@ -8,7 +8,7 @@ coverage!=4.4,>=4.0 # Apache-2.0
|
|||||||
fixtures>=3.0.0 # Apache-2.0/BSD
|
fixtures>=3.0.0 # Apache-2.0/BSD
|
||||||
flake8-import-order==0.12 # LGPLv3
|
flake8-import-order==0.12 # LGPLv3
|
||||||
pycodestyle>=2.0.0 # MIT
|
pycodestyle>=2.0.0 # MIT
|
||||||
mock>=2.0.0 # BSD
|
mock>=3.0.0 # BSD
|
||||||
python-subunit>=1.0.0 # Apache-2.0/BSD
|
python-subunit>=1.0.0 # Apache-2.0/BSD
|
||||||
testtools>=2.2.0 # MIT
|
testtools>=2.2.0 # MIT
|
||||||
testresources>=2.0.0 # Apache-2.0/BSD
|
testresources>=2.0.0 # Apache-2.0/BSD
|
||||||
|
Loading…
Reference in New Issue
Block a user