Fix masakari-monitor connection issue
From openstacksdk version 0.11.1 onwards, there is no way you can add service to the connection. Hence we need to monkey _find_service_filter_class method from sdk to allow to point to thee correct service filter class from masakariclient. Solution provided here is not going to work in sdk 0.9.19 and 0.10.0 versions. Because service descriptor is not supported in 0.9.19 and 0.10.0 sdk versions and profile parameter doesn't work correctly during connection initialization. Also solution provided here is not going to work in sdk 0.13.0 and above, it will still fails with below error "'Connection' object has no attribute 'ha'" this is because 'Connection' object expecting instance_ha not ha Co-Author: tpatil <tushar.vitthal.patil@gmail.com> Change-Id: Ic10d1b380abc8b3b6cc38015c9c3bf4ab7705a0c Depends-On: I24ec493f3333a5b3f6bfed9395c921fb28500065 Closes-Bug: #1779752
This commit is contained in:
parent
da40a2f881
commit
3ffd576b79
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue