diff --git a/puppet-manifests/src/modules/platform/manifests/sysinv.pp b/puppet-manifests/src/modules/platform/manifests/sysinv.pp index 0b2afef96b..9d418331ef 100644 --- a/puppet-manifests/src/modules/platform/manifests/sysinv.pp +++ b/puppet-manifests/src/modules/platform/manifests/sysinv.pp @@ -2,6 +2,7 @@ class platform::sysinv::params ( $api_port = 6385, $region_name = undef, $service_create = false, + $fm_catalog_info = 'faultmanagement:fm:internalURL', ) { } class platform::sysinv @@ -45,6 +46,7 @@ class platform::sysinv rabbit_port => $::platform::amqp::params::port, rabbit_userid => $::platform::amqp::params::auth_user, rabbit_password => $::platform::amqp::params::auth_password, + fm_catalog_info => $fm_catalog_info, } # Note: The log format strings are prefixed with "sysinv" because it is diff --git a/puppet-modules-wrs/puppet-sysinv/src/sysinv/manifests/init.pp b/puppet-modules-wrs/puppet-sysinv/src/sysinv/manifests/init.pp index 4efac5cb7e..4608fb5f0a 100644 --- a/puppet-modules-wrs/puppet-sysinv/src/sysinv/manifests/init.pp +++ b/puppet-modules-wrs/puppet-sysinv/src/sysinv/manifests/init.pp @@ -1,7 +1,7 @@ # # Files in this package are licensed under Apache; see LICENSE file. # -# Copyright (c) 2013-2016 Wind River Systems, Inc. +# Copyright (c) 2013-2018 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -69,7 +69,8 @@ class sysinv ( $neutron_region_name = 'RegionOne', $cinder_region_name = 'RegionOne', $nova_region_name = 'RegionOne', - $magnum_region_name = 'RegionOne' + $magnum_region_name = 'RegionOne', + $fm_catalog_info = undef, ) { include sysinv::params @@ -200,6 +201,11 @@ class sysinv ( 'keystone_authtoken/magnum_region_name': value => $magnum_region_name; } + sysinv_config { + 'fm/catalog_info': value => $fm_catalog_info; + 'fm/os_region_name': value => $region_name; + } + sysinv_api_paste_ini { 'filter:authtoken/region_name': value => $region_name; } diff --git a/sysinv/sysinv/sysinv/sysinv/api/hooks.py b/sysinv/sysinv/sysinv/sysinv/api/hooks.py index d909928621..ae8d5dcc3a 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/hooks.py +++ b/sysinv/sysinv/sysinv/sysinv/api/hooks.py @@ -16,13 +16,15 @@ # License for the specific language governing permissions and limitations # under the License. # -# Copyright (c) 2013-2014 Wind River Systems, Inc. +# Copyright (c) 2013-2018 Wind River Systems, Inc. # import time import urlparse +import webob from oslo_config import cfg +from oslo_serialization import jsonutils from pecan import hooks from sysinv.common import context @@ -33,6 +35,7 @@ from sysinv.openstack.common import policy from webob import exc from sysinv.openstack.common import log +from sysinv.openstack.common.gettextutils import _ import eventlet.semaphore import re @@ -78,6 +81,9 @@ class ContextHook(hooks.PecanHook): The flag is set to True, if X-Roles contains either an administrator or admin substring. Otherwise it is set to False. + X-Service_Catalog: + Used for context.service_catalog. + """ def __init__(self, public_api_routes): self.public_api_routes = public_api_routes @@ -92,6 +98,14 @@ class ContextHook(hooks.PecanHook): domain_name = state.request.headers.get('X-User-Domain-Name') auth_token = state.request.headers.get('X-Auth-Token', None) creds = {'roles': state.request.headers.get('X-Roles', '').split(',')} + catalog_header = state.request.headers.get('X-Service-Catalog') + service_catalog = None + if catalog_header: + try: + service_catalog = jsonutils.loads(catalog_header) + except ValueError: + raise webob.exc.HTTPInternalServerError( + _('Invalid service catalog json.')) is_admin = policy.check('admin', state.request.headers, creds) @@ -105,7 +119,9 @@ class ContextHook(hooks.PecanHook): domain_id=domain_id, domain_name=domain_name, is_admin=is_admin, - is_public_api=is_public_api) + is_public_api=is_public_api, + service_catalog=service_catalog + ) class RPCHook(hooks.PecanHook): diff --git a/sysinv/sysinv/sysinv/sysinv/common/context.py b/sysinv/sysinv/sysinv/sysinv/common/context.py index 880d332dc2..693afc4911 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/context.py +++ b/sysinv/sysinv/sysinv/sysinv/common/context.py @@ -16,18 +16,23 @@ from sysinv.db import api as dbapi from sysinv.openstack.common import context +REQUIRED_SERVICE_TYPES = ('faultmanagement',) + + class RequestContext(context.RequestContext): """Extends security contexts from the OpenStack common library.""" def __init__(self, auth_token=None, domain_id=None, domain_name=None, user=None, tenant=None, is_admin=False, is_public_api=False, - read_only=False, show_deleted=False, request_id=None): + read_only=False, show_deleted=False, request_id=None, + service_catalog=None): """Stores several additional request parameters: :param domain_id: The ID of the domain. :param domain_name: The name of the domain. :param is_public_api: Specifies whether the request should be processed without authentication. + :param service_catalog: Specifies the service_catalog """ self.is_public_api = is_public_api self.domain_id = domain_id @@ -40,6 +45,13 @@ class RequestContext(context.RequestContext): read_only=read_only, show_deleted=show_deleted, request_id=request_id) + if service_catalog: + # Only include required parts of service_catalog + self.service_catalog = [s for s in service_catalog + if s.get('type') in REQUIRED_SERVICE_TYPES] + else: + # if list is empty or none + self.service_catalog = [] @property def session(self): @@ -51,7 +63,8 @@ class RequestContext(context.RequestContext): def to_dict(self): result = {'domain_id': self.domain_id, 'domain_name': self.domain_name, - 'is_public_api': self.is_public_api} + 'is_public_api': self.is_public_api, + 'service_catalog': self.service_catalog} result.update(super(RequestContext, self).to_dict()) diff --git a/sysinv/sysinv/sysinv/sysinv/common/fm.py b/sysinv/sysinv/sysinv/sysinv/common/fm.py index 6361852182..fe59e1a50f 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/fm.py +++ b/sysinv/sysinv/sysinv/sysinv/common/fm.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2016 Wind River Systems, Inc. +# Copyright (c) 2016-2018 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -7,13 +7,36 @@ # FM Fault Management Handling +from keystoneauth1.access import service_catalog as k_service_catalog +from oslo_config import cfg from fm_api import constants as fm_constants from fm_api import fm_api +import fmclient as fm_client from sysinv.openstack.common import log +CONF = cfg.CONF + LOG = log.getLogger(__name__) +fm_group = cfg.OptGroup( + 'fm', + title='FM Options', + help="Configuration options for the fault management service") + +fm_opts = [ + cfg.StrOpt('catalog_info', + default='faultmanagement:fm:internalURL', + help="Service catalog Look up info."), + cfg.StrOpt('os_region_name', + default='RegionOne', + help="Region name of this node. It is used for catalog lookup") +] + +CONF.register_group(fm_group) +CONF.register_opts(fm_opts, group=fm_group) + + class FmCustomerLog(object): """ Fault Management Customer Log @@ -55,3 +78,27 @@ class FmCustomerLog(object): LOG.info("Generated customer log, fm_uuid=%s." % fm_uuid) else: LOG.error("Unknown event id (%s) given." % fm_event_id) + + +def fmclient(context, version=1, endpoint=None): + """Constructs a fm client object for making API requests. + + :param context: The request context for auth. + :param version: API endpoint version. + :param endpoint: Optional If the endpoint is not available, it will be + retrieved from context + """ + auth_token = context.auth_token + if endpoint is None: + sc = k_service_catalog.ServiceCatalogV2(context.service_catalog) + service_type, service_name, interface = \ + CONF.fm.catalog_info.split(':') + service_parameters = {'service_type': service_type, + 'service_name': service_name, + 'interface': interface, + 'region_name': CONF.fm.os_region_name} + endpoint = sc.url_for(**service_parameters) + + return fm_client.Client(version=version, + endpoint=endpoint, + auth_token=auth_token) diff --git a/sysinv/sysinv/sysinv/sysinv/common/health.py b/sysinv/sysinv/sysinv/sysinv/common/health.py index 31777aec85..467bfdfef9 100755 --- a/sysinv/sysinv/sysinv/sysinv/common/health.py +++ b/sysinv/sysinv/sysinv/sysinv/common/health.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2016 Wind River Systems, Inc. +# Copyright (c) 2018 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -13,6 +13,7 @@ from fm_api import fm_api from sysinv.common import ceph from sysinv.common import constants from sysinv.common import utils +from sysinv.common.fm import fmclient from sysinv.common.storage_backend_conf import StorageBackendConfig from sysinv.api.controllers.v1 import patch_api from sysinv.api.controllers.v1 import vim_api @@ -95,9 +96,9 @@ class Health(object): success = not not_patch_current_hosts and not hostnames return success, not_patch_current_hosts, hostnames - def _check_alarms(self, force=False): + def _check_alarms(self, context, force=False): """Checks that no alarms are active""" - db_alarms = self._dbapi.ialarm_get_all(include_suppress=True) + db_alarms = fmclient(context).alarm.list(include_suppress=True) success = True allowed = 0 @@ -210,7 +211,7 @@ class Health(object): return True - def get_system_health(self, force=False): + def get_system_health(self, context, force=False): """Returns the general health of the system""" # Checks the following: # All hosts are provisioned @@ -277,7 +278,7 @@ class Health(object): health_ok = health_ok and success - success, allowed, affecting = self._check_alarms(force) + success, allowed, affecting = self._check_alarms(context, force) output += _('No alarms: [%s]\n') \ % (Health.SUCCESS_MSG if success else Health.FAIL_MSG) if not success: @@ -288,7 +289,7 @@ class Health(object): return health_ok, output - def get_system_health_upgrade(self, force=False): + def get_system_health_upgrade(self, context, force=False): """Ensures the system is in a valid state for an upgrade""" # Does a general health check then does the following: # A load is imported @@ -298,7 +299,7 @@ class Health(object): system_mode = self._dbapi.isystem_get_one().system_mode simplex = (system_mode == constants.SYSTEM_MODE_SIMPLEX) - health_ok, output = self.get_system_health(force) + health_ok, output = self.get_system_health(context, force) loads = self._dbapi.load_get_list() try: imported_load = utils.get_imported_load(loads) diff --git a/sysinv/sysinv/sysinv/sysinv/conductor/manager.py b/sysinv/sysinv/sysinv/sysinv/conductor/manager.py index c6d2e23747..5aacc29eb2 100644 --- a/sysinv/sysinv/sysinv/sysinv/conductor/manager.py +++ b/sysinv/sysinv/sysinv/sysinv/conductor/manager.py @@ -8975,9 +8975,11 @@ class ConductorManager(service.PeriodicService): health_util = health.Health(self.dbapi) if upgrade is True: - return health_util.get_system_health_upgrade(force=force) + return health_util.get_system_health_upgrade(context=context, + force=force) else: - return health_util.get_system_health(force=force) + return health_util.get_system_health(context=context, + force=force) def _get_cinder_address_name(self, network_type): ADDRESS_FORMAT_ARGS = (constants.CONTROLLER_HOSTNAME, diff --git a/sysinv/sysinv/sysinv/tox.ini b/sysinv/sysinv/sysinv/tox.ini index c7fd3cfeee..e870657fc4 100644 --- a/sysinv/sysinv/sysinv/tox.ini +++ b/sysinv/sysinv/sysinv/tox.ini @@ -41,6 +41,7 @@ deps = -r{toxinidir}/requirements.txt -e{[tox]cgcsdir}/stx-update/tsconfig/tsconfig -e{[tox]cgcsdir}/stx-config/configutilities/configutilities -e{[tox]cgcsdir}/stx-fault/fm-api + -e{[tox]cgcsdir}/stx-fault/python-fmclient/fmclient -e{[tox]cgcsdir}/stx-config/controllerconfig/controllerconfig -e{[tox]cgcsdir}/stx-update/cgcs-patch/cgcs-patch -e{[tox]cgcsdir}/stx-integ/utilities/platform-util/platform-util