#!/usr/bin/env python # -*- coding: utf-8 -*- ## # Copyright 2016-2017 VMware Inc. # This file is part of ETSI OSM # 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. # # For those usages not covered by the Apache License, Version 2.0 please # contact: osslegalrouting@vmware.com ## """ Webservice for vRealize Operations (vROPs) to post/notify alarms details. """ from osm_mon.core.settings import Config __author__ = "Arpita Kate" __date__ = "$15-Sept-2017 16:09:29$" __version__ = '0.1' import json import logging import os import sys from datetime import datetime from socket import getfqdn import requests from bottle import (ServerAdapter, route, run, server_names, default_app, request, response) sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', '..', '..')) from osm_mon.core.message_bus.producer import Producer # from core.message_bus.producer import KafkaProducer sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', '..')) from osm_mon.core.database import DatabaseManager try: from cheroot.wsgi import Server as WSGIServer from cheroot.ssl.pyopenssl import pyOpenSSLAdapter except ImportError: from cherrypy.wsgiserver import CherryPyWSGIServer as WSGIServer from cherrypy.wsgiserver.ssl_pyopenssl import pyOpenSSLAdapter # Set Constants BASE_DIR = os.path.dirname(os.path.dirname(__file__)) CERT_DIR = os.path.join(BASE_DIR, "SSL_certificate") certificate_name = getfqdn() + ".cert" key_name = getfqdn() + ".key" CERTIFICATE = os.path.join(CERT_DIR, certificate_name) KEY = os.path.join(CERT_DIR, key_name) # CERTIFICATE = os.path.join(CERT_DIR, "www.vrops_webservice.com.cert") # KEY = os.path.join(CERT_DIR, "www.vrops_webservice.com.key") CONFIG_FILE = os.path.join(BASE_DIR, '../vrops_config.xml') # Severity Mapping from vROPs to OSM VROPS_SEVERITY_TO_OSM_MAPPING = { "ALERT_CRITICALITY_LEVEL_CRITICAL": "CRITICAL", "ALERT_CRITICALITY_LEVEL_WARNING": "WARNING", "ALERT_CRITICALITY_LEVEL_IMMEDIATE": "MAJOR", "ALERT_CRITICALITY_LEVEL_INFO": "INDETERMINATE", "ALERT_CRITICALITY_LEVEL_AUTO": "INDETERMINATE", "ALERT_CRITICALITY_LEVEL_UNKNOWN": "INDETERMINATE", "ALERT_CRITICALITY_LEVEL_NONE": "INDETERMINATE" } # Set logger cfg = Config.instance() logging.basicConfig(stream=sys.stdout, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p', level=logging.getLevelName(cfg.OSMMON_LOG_LEVEL)) logger = logging.getLogger(__name__) def format_datetime(str_date): """ Method to format datetime Args: str_date - datetime string Returns: formated datetime """ date_fromat = "%Y-%m-%dT%H:%M:%S" formated_datetime = None try: datetime_obj = datetime.fromtimestamp(float(str_date) / 1000.) formated_datetime = datetime_obj.strftime(date_fromat) except Exception as exp: logger.error('Exception: {} occured while converting date {} into format {}'.format( exp, str_date, date_fromat)) return formated_datetime def get_alarm_config(alarm_name): """ Method to get configuration parameters Args: None Returns: dictionary of config parameters """ vim_account = {} database_manager = DatabaseManager() alarm = database_manager.get_alarm(alarm_name, 'VMware') vim_account_details = alarm.credentials try: if vim_account_details is not None: vim_account['name'] = vim_account_details.name vim_account['vim_tenant_name'] = vim_account_details.tenant_name vim_account['vim_type'] = vim_account_details.type vim_account['vim_uuid'] = vim_account_details.uuid vim_account['vim_url'] = vim_account_details.url vim_account['org_user'] = vim_account_details.user vim_account['org_password'] = vim_account_details.password vim_config = json.loads(vim_account_details.config) vim_account['tenant_id'] = vim_config['tenant_id'] vim_account['admin_username'] = vim_config['admin_username'] vim_account['admin_password'] = vim_config['admin_password'] vim_account['vrops_site'] = vim_config['vrops_site'] vim_account['vrops_user'] = vim_config['vrops_user'] vim_account['vrops_password'] = vim_config['vrops_password'] vim_account['vcenter_ip'] = vim_config['vcenter_ip'] vim_account['vcenter_port'] = vim_config['vcenter_port'] vim_account['vcenter_user'] = vim_config['vcenter_user'] vim_account['vcenter_password'] = vim_config['vcenter_password'] if vim_config['nsx_manager'] is not None: vim_account['nsx_manager'] = vim_config['nsx_manager'] if vim_config['nsx_user'] is not None: vim_account['nsx_user'] = vim_config['nsx_user'] if vim_config['nsx_password'] is not None: vim_account['nsx_password'] = vim_config['nsx_password'] if vim_config['orgname'] is not None: vim_account['orgname'] = vim_config['orgname'] except Exception as exp: logger.error("VIM account details not sufficient: {}".format(exp)) return vim_account def get_alarm_definationID(alarm_instance_uuid, access_config): """ Method to get alarm/alert defination ID Args: alarm_instance_uuid : UUID of alarm Returns: alarm defination ID """ alarm_definationID = None if alarm_instance_uuid: try: # access_config = get_alarm_config() headers = {'Accept': 'application/json'} api_url = '{}/suite-api/api/alerts/{}' \ .format(access_config.get('vrops_site'), alarm_instance_uuid) api_response = requests.get(api_url, auth=(access_config.get('vrops_user'), access_config.get('vrops_password')), verify=False, headers=headers ) if api_response.status_code == 200: data = api_response.json() if data.get("alertDefinitionId") is not None: alarm_definationID = '-'.join(data.get("alertDefinitionId").split('-')[1:]) else: logger.error("Failed to get alert definition ID for alarm {}" .format(alarm_instance_uuid)) except Exception as exp: logger.error("Exception occured while getting alert definition ID for alarm : {}" .format(exp, alarm_instance_uuid)) return alarm_definationID @route('/notify/', method='POST') def notify_alarm(alarmID): """ Method notify alarm details by publishing message at Kafka message bus Args: alarmID - Name of alarm Returns: response code """ logger.info("Request:{} from:{} {} {} " \ .format(request, request.remote_addr, request.method, request.url)) response.headers['Content-Type'] = 'application/json' try: postdata = json.loads(request.body.read()) notify_details = {} vim_access_config = get_alarm_config(postdata.get('alertName')) # Parse notify data notify_details['vim_uuid'] = vim_access_config.get('vim_uuid') notify_details['alarm_uuid'] = get_alarm_definationID(postdata.get('alertId'), vim_access_config) notify_details['description'] = postdata.get('info') notify_details['alarm_instance_uuid'] = alarmID notify_details['resource_uuid'] = '-'.join(postdata.get('alertName').split('-')[1:]) notify_details['tenant_uuid'] = vim_access_config.get('tenant_id') notify_details['vim_type'] = "VMware" notify_details['severity'] = VROPS_SEVERITY_TO_OSM_MAPPING.get(postdata.get('criticality'), 'INDETERMINATE') notify_details['status'] = postdata.get('status') if postdata.get('startDate'): notify_details['start_date_time'] = format_datetime(postdata.get('startDate')) if postdata.get('updateDate'): notify_details['update_date_time'] = format_datetime(postdata.get('updateDate')) if postdata.get('cancelDate'): notify_details['cancel_date_time'] = format_datetime(postdata.get('cancelDate')) alarm_details = {'schema_version': 1.0, 'schema_type': "notify_alarm", 'notify_details': notify_details } alarm_data = json.dumps(alarm_details) logger.info("Alarm details: {}".format(alarm_data)) # Publish Alarm details producer = Producer() producer.send(topic='alarm_response', key=notify_alarm, value=alarm_data) producer.flush() # return 201 on Success response.status = 201 except Exception as exp: logger.error('Exception: {} occured while notifying alarm {}.'.format(exp, alarmID)) # return 500 on Error response.status = 500 return response class SSLWebServer(ServerAdapter): """ CherryPy web server with SSL support. """ def run(self, handler): """ Runs a CherryPy Server using the SSL certificate. """ server = WSGIServer((self.host, self.port), handler) server.ssl_adapter = pyOpenSSLAdapter( certificate=CERTIFICATE, private_key=KEY, # certificate_chain="intermediate_cert.crt" ) try: server.start() logger.info("Started vROPs Web Service") except Exception as exp: server.stop() logger.error("Exception: {} Stopped vROPs Web Service".format(exp)) if __name__ == "__main__": # Start SSL Web Service logger.info("Start vROPs Web Service") app = default_app() server_names['sslwebserver'] = SSLWebServer run(app=app, host=getfqdn(), port=8080, server='sslwebserver')