diff --git a/.zuul.yaml b/.zuul.yaml index 7f75d8c..b58c2cb 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -3,3 +3,12 @@ - check-requirements - openstack-python-jobs - openstack-python35-jobs-nonvoting + + check: + jobs: + - requirements-check: + voting: false + gate: + jobs: + - requirements-check: + voting: false diff --git a/masakarimonitors/cmd/__init__.py b/masakarimonitors/cmd/__init__.py index e69de29..57ec14c 100644 --- a/masakarimonitors/cmd/__init__.py +++ b/masakarimonitors/cmd/__init__.py @@ -0,0 +1,47 @@ +# Copyright 2018 NTT DATA. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import importlib +import warnings + + +def masakari_service_filter_class(service_type): + package_name = 'openstack.{service_type}'.format( + service_type=service_type).replace('-', '_') + module_name = service_type.replace('-', '_') + '_service' + class_name = ''.join( + [part.capitalize() for part in module_name.split('_')]) + try: + import_name = '.'.join([package_name, module_name]) + if (class_name == "InstanceHaService" and + import_name == "openstack.instance_ha." + "instance_ha_service"): + class_name = "HAService" + import_name = "masakariclient.sdk.ha.ha_service" + + service_filter_module = importlib.import_module(import_name) + except ImportError as e: + # ImportWarning is ignored by default. This warning is here + # as an opt-in for people trying to figure out why something + # didn't work. + warnings.warn( + "Could not import {service_type} service filter: {e}".format( + service_type=service_type, e=str(e)), + ImportWarning) + return None + # There are no cases in which we should have a module but not the class + # inside it. + service_filter_class = getattr(service_filter_module, class_name) + return service_filter_class diff --git a/masakarimonitors/cmd/hostmonitor.py b/masakarimonitors/cmd/hostmonitor.py index 19f30c1..6e29740 100644 --- a/masakarimonitors/cmd/hostmonitor.py +++ b/masakarimonitors/cmd/hostmonitor.py @@ -14,6 +14,7 @@ """Starter script for Masakari Host Monitor.""" +import pbr.version import sys from oslo_log import log as logging @@ -32,6 +33,21 @@ def main(): logging.setup(CONF, "masakarimonitors") utils.monkey_patch() + # From openstacksdk version 0.11.1 onwards, there is no way + # you can add service to the connection. Hence we need to monkey patch + # _find_service_filter_class method from sdk to allow + # to point to the correct service filter class implemented in + # masakari-monitors. + sdk_ver = pbr.version.VersionInfo('openstacksdk').version_string() + if sdk_ver in ['0.11.1', '0.11.2', '0.11.3']: + utils.monkey_patch_for_openstacksdk("openstack._meta:masakarimonitors." + "cmd." + "masakari_service_filter_class") + if sdk_ver in ['0.12.0']: + utils.monkey_patch_for_openstacksdk("openstack._meta.connection:" + "masakarimonitors.cmd." + "masakari_service_filter_class") + server = service.Service.create(binary='masakarimonitors-hostmonitor') service.serve(server) service.wait() diff --git a/masakarimonitors/cmd/instancemonitor.py b/masakarimonitors/cmd/instancemonitor.py index 1d37557..7613a95 100644 --- a/masakarimonitors/cmd/instancemonitor.py +++ b/masakarimonitors/cmd/instancemonitor.py @@ -14,6 +14,7 @@ """Starter script for Masakari Instance Monitor.""" +import pbr.version import sys from oslo_log import log as logging @@ -32,6 +33,21 @@ def main(): logging.setup(CONF, "masakarimonitors") utils.monkey_patch() + # From openstacksdk version 0.11.1 onwards, there is no way + # you can add service to the connection. Hence we need to monkey patch + # _find_service_filter_class method from sdk to allow + # to point to the correct service filter class implemented in + # masakari-monitors. + sdk_ver = pbr.version.VersionInfo('openstacksdk').version_string() + if sdk_ver in ['0.11.1', '0.11.2', '0.11.3']: + utils.monkey_patch_for_openstacksdk("openstack._meta:masakarimonitors." + "cmd." + "masakari_service_filter_class") + if sdk_ver in ['0.12.0']: + utils.monkey_patch_for_openstacksdk("openstack._meta.connection:" + "masakarimonitors.cmd." + "masakari_service_filter_class") + server = service.Service.create(binary='masakarimonitors-instancemonitor') service.serve(server) service.wait() diff --git a/masakarimonitors/cmd/processmonitor.py b/masakarimonitors/cmd/processmonitor.py index ed123c3..d024640 100644 --- a/masakarimonitors/cmd/processmonitor.py +++ b/masakarimonitors/cmd/processmonitor.py @@ -14,6 +14,7 @@ """Starter script for Masakari Process Monitor.""" +import pbr.version import sys from oslo_log import log as logging @@ -32,6 +33,21 @@ def main(): logging.setup(CONF, "masakarimonitors") utils.monkey_patch() + # From openstacksdk version 0.11.1 onwards, there is no way + # you can add service to the connection. Hence we need to monkey patch + # _find_service_filter_class method from sdk to allow + # to point to the correct service filter class implemented in + # masakari-monitors. + sdk_ver = pbr.version.VersionInfo('openstacksdk').version_string() + if sdk_ver in ['0.11.1', '0.11.2', '0.11.3']: + utils.monkey_patch_for_openstacksdk("openstack._meta:masakarimonitors." + "cmd." + "masakari_service_filter_class") + if sdk_ver in ['0.12.0']: + utils.monkey_patch_for_openstacksdk("openstack._meta.connection:" + "masakarimonitors.cmd." + "masakari_service_filter_class") + server = service.Service.create(binary='masakarimonitors-processmonitor') service.serve(server) service.wait() diff --git a/masakarimonitors/ha/masakari.py b/masakarimonitors/ha/masakari.py index 29c0566..1a40a31 100644 --- a/masakarimonitors/ha/masakari.py +++ b/masakarimonitors/ha/masakari.py @@ -13,12 +13,18 @@ # limitations under the License. import eventlet +import pbr.version + +from keystoneauth1.identity.generic import password as ks_password +from keystoneauth1 import session as ks_session from openstack import connection +sdk_ver = pbr.version.VersionInfo('openstacksdk').version_string() +if sdk_ver in ['0.11.0']: + from masakariclient.sdk.ha.v1 import _proxy + from openstack import service_description from openstack import exceptions -from openstack import profile from oslo_log import log as oslo_logging -from masakariclient.sdk.ha import ha_service import masakarimonitors.conf LOG = oslo_logging.getLogger(__name__) @@ -34,23 +40,25 @@ class SendNotification(object): project_name, username, password, project_domain_id, user_domain_id): - # Create profile object. - prof = profile.Profile() - prof._add_service(ha_service.HAService(version=api_version)) - prof.set_name(PROFILE_TYPE, PROFILE_NAME) - prof.set_region(PROFILE_TYPE, region) - prof.set_version(PROFILE_TYPE, api_version) - prof.set_interface(PROFILE_TYPE, interface) - - # Get connection. - conn = connection.Connection( + auth = ks_password.Password( auth_url=auth_url, - project_name=project_name, username=username, password=password, - project_domain_id=project_domain_id, user_domain_id=user_domain_id, - profile=prof) + project_name=project_name, + project_domain_id=project_domain_id) + session = ks_session.Session(auth=auth) + + # Get connection. + if sdk_ver >= '0.11.1': + conn = connection.Connection(session=session, interface=interface, + region_name=region) + elif sdk_ver in ['0.11.0']: + desc = service_description.ServiceDescription(service_type='ha', + proxy_class=_proxy.Proxy) + conn = connection.Connection(session=session, interface=interface, + region_name=region) + conn.add_service(desc) return conn diff --git a/masakarimonitors/tests/unit/ha/test_masakari.py b/masakarimonitors/tests/unit/ha/test_masakari.py index 8dc7b00..5b9ce1d 100644 --- a/masakarimonitors/tests/unit/ha/test_masakari.py +++ b/masakarimonitors/tests/unit/ha/test_masakari.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from keystoneauth1 import session import mock import testtools import uuid @@ -19,10 +20,8 @@ import uuid import eventlet from openstack import connection from openstack import exceptions -from openstack import profile from oslo_utils import timeutils -from masakariclient.sdk.ha import ha_service from masakarimonitors.ha import masakari from masakarimonitors.objects import event_constants as ec @@ -60,55 +59,31 @@ class TestSendNotification(testtools.TestCase): } @mock.patch.object(connection, 'Connection') - @mock.patch.object(profile, 'Profile') def test_send_notification(self, - mock_Profile, - mock_Connection): - - mock_prof = mock.Mock() - mock_Profile.return_value = mock_prof - mock_conn = mock.Mock() - mock_Connection.return_value = mock_conn + mock_connection): + mock_session = mock.Mock(spec=session.Session) + mock_session.auth = mock.Mock() + mock_session.auth.auth_url = 'https://auth.example.com' + mock_connection = connection.Connection(session=mock_session) notifier = masakari.SendNotification() notifier.send_notification( self.api_retry_max, self.api_retry_interval, self.event) - mock_prof._add_service.assert_called_once_with( - ha_service.HAService(version='v1')) - mock_prof.set_name.assert_called_once_with( - PROFILE_TYPE, PROFILE_NAME) - mock_prof.set_region.assert_called_once_with( - PROFILE_TYPE, 'RegionOne') - mock_prof.set_version.assert_called_once_with( - PROFILE_TYPE, 'v1') - mock_prof.set_interface.assert_called_once_with( - PROFILE_TYPE, 'public') - - mock_Connection.assert_called_once_with( - auth_url=None, - project_name=None, - username=None, - password=None, - project_domain_id=None, - user_domain_id=None, - profile=mock_prof) - mock_conn.ha.create_notification.assert_called_once_with( + mock_connection.ha.create_notification.assert_called_once_with( type=self.event['notification']['type'], hostname=self.event['notification']['hostname'], generated_time=self.event['notification']['generated_time'], payload=self.event['notification']['payload']) @mock.patch.object(connection, 'Connection') - @mock.patch.object(profile, 'Profile') def test_send_notification_409_error(self, - mock_Profile, - mock_Connection): + mock_connection): - mock_prof = mock.Mock() - mock_Profile.return_value = mock_prof - mock_conn = mock.Mock() - mock_Connection.return_value = mock_conn + mock_session = mock.Mock(spec=session.Session) + mock_session.auth = mock.Mock() + mock_session.auth.auth_url = 'https://auth.example.com' + mock_connection = connection.Connection(session=mock_session) # TODO(samP): Remove attribute check and else case if # openstacksdk is bumped up from '>=0.9.19' to '>=0.10.0' @@ -119,31 +94,12 @@ class TestSendNotification(testtools.TestCase): else: status_ex = exceptions.HttpException(http_status=409) - mock_conn.ha.create_notification.side_effect = status_ex + mock_connection.ha.create_notification.side_effect = status_ex notifier = masakari.SendNotification() notifier.send_notification( self.api_retry_max, self.api_retry_interval, self.event) - mock_prof._add_service.assert_called_once_with( - ha_service.HAService(version='v1')) - mock_prof.set_name.assert_called_once_with( - PROFILE_TYPE, PROFILE_NAME) - mock_prof.set_region.assert_called_once_with( - PROFILE_TYPE, 'RegionOne') - mock_prof.set_version.assert_called_once_with( - PROFILE_TYPE, 'v1') - mock_prof.set_interface.assert_called_once_with( - PROFILE_TYPE, 'public') - - mock_Connection.assert_called_once_with( - auth_url=None, - project_name=None, - username=None, - password=None, - project_domain_id=None, - user_domain_id=None, - profile=mock_prof) - mock_conn.ha.create_notification.assert_called_once_with( + mock_connection.ha.create_notification.assert_called_once_with( type=self.event['notification']['type'], hostname=self.event['notification']['hostname'], generated_time=self.event['notification']['generated_time'], @@ -151,16 +107,14 @@ class TestSendNotification(testtools.TestCase): @mock.patch.object(eventlet.greenthread, 'sleep') @mock.patch.object(connection, 'Connection') - @mock.patch.object(profile, 'Profile') def test_send_notification_500_error(self, - mock_Profile, - mock_Connection, + mock_connection, mock_sleep): - mock_prof = mock.Mock() - mock_Profile.return_value = mock_prof - mock_conn = mock.Mock() - mock_Connection.return_value = mock_conn + mock_session = mock.Mock(spec=session.Session) + mock_session.auth = mock.Mock() + mock_session.auth.auth_url = 'https://auth.example.com' + mock_connection = connection.Connection(session=mock_session) # TODO(samP): Remove attribute check and else case if # openstacksdk is bumped up from '>=0.9.19' to '>=0.10.0' @@ -171,36 +125,17 @@ class TestSendNotification(testtools.TestCase): else: status_ex = exceptions.HttpException(http_status=500) - mock_conn.ha.create_notification.side_effect = status_ex + mock_connection.ha.create_notification.side_effect = status_ex mock_sleep.return_value = None notifier = masakari.SendNotification() notifier.send_notification( self.api_retry_max, self.api_retry_interval, self.event) - mock_prof._add_service.assert_called_once_with( - ha_service.HAService(version='v1')) - mock_prof.set_name.assert_called_once_with( - PROFILE_TYPE, PROFILE_NAME) - mock_prof.set_region.assert_called_once_with( - PROFILE_TYPE, 'RegionOne') - mock_prof.set_version.assert_called_once_with( - PROFILE_TYPE, 'v1') - mock_prof.set_interface.assert_called_once_with( - PROFILE_TYPE, 'public') - - mock_Connection.assert_called_once_with( - auth_url=None, - project_name=None, - username=None, - password=None, - project_domain_id=None, - user_domain_id=None, - profile=mock_prof) - mock_conn.ha.create_notification.assert_called_with( + mock_connection.ha.create_notification.assert_called_with( type=self.event['notification']['type'], hostname=self.event['notification']['hostname'], generated_time=self.event['notification']['generated_time'], payload=self.event['notification']['payload']) self.assertEqual(self.api_retry_max + 1, - mock_conn.ha.create_notification.call_count) + mock_connection.ha.create_notification.call_count) diff --git a/masakarimonitors/utils.py b/masakarimonitors/utils.py index c1dd725..dd6551b 100644 --- a/masakarimonitors/utils.py +++ b/masakarimonitors/utils.py @@ -16,15 +16,14 @@ import contextlib import inspect -import pyclbr -import shutil -import sys -import tempfile - from oslo_concurrency import processutils from oslo_log import log as logging from oslo_utils import importutils +import pyclbr +import shutil import six +import sys +import tempfile import masakarimonitors.conf from masakarimonitors.i18n import _ @@ -36,6 +35,20 @@ CONF = masakarimonitors.conf.CONF LOG = logging.getLogger(__name__) +def monkey_patch_for_openstacksdk(module_and_decorator_name): + module, decorator_name = module_and_decorator_name.split(':') + # import decorator function + decorator = importutils.import_class(decorator_name) + __import__(module) + # Retrieve module information using pyclbr + module_data = pyclbr.readmodule_ex(module) + for key in module_data.keys(): + # set the decorator for the function + if isinstance(module_data[key], pyclbr.Function): + if key == "_find_service_filter_class": + setattr(sys.modules[module], key, decorator) + + def monkey_patch(): """monkey_patch function. diff --git a/requirements.txt b/requirements.txt index 5e40cea..25f31cd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,7 @@ # process, which may cause wedges in the gate later. libvirt-python>=1.2.5 # LGPLv2+ +openstacksdk>=0.11.0 # Apache-2.0 oslo.concurrency>=3.8.0 # Apache-2.0 oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0 oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0