#!/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. """ __author__ = "Arpita Kate" __date__ = "$15-Sept-2017 16:09:29$" __version__ = '0.1' from bottle import (ServerAdapter, route, run, server_names, redirect, default_app, request, response, template, debug, TEMPLATE_PATH , static_file) from socket import getfqdn from datetime import datetime from xml.etree import ElementTree as ET import logging import os import json import sys import requests sys.path.append("../../../core/message_bus") from producer import KafkaProducer #from core.message_bus.producer import KafkaProducer 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 logger = logging.getLogger('vROPs_Webservice') formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') hdlr = logging.FileHandler(os.path.join(BASE_DIR,"vrops_webservice.log")) hdlr.setFormatter(formatter) logger.addHandler(hdlr) logger.setLevel(logging.DEBUG) 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(): """ Method to get configuration parameters Args: None Returns: dictionary of config parameters """ alarm_config = {} try: xml_content = ET.parse(CONFIG_FILE) alarms = xml_content.getroot() for alarm in alarms: if alarm.tag == 'Access_Config': for param in alarm: alarm_config[param.tag] = param.text except Exception as exp: logger.error('Exception: {} occured while parsing config file.'.format(exp)) return alarm_config def get_alarm_definationID(alarm_uuid): """ Method to get alarm/alert defination ID Args: alarm_uuid : UUID of alarm Returns: alarm defination ID """ alarm_definationID = None if alarm_uuid : try: access_config = get_alarm_config() headers = {'Accept': 'application/json'} api_url = '{}/suite-api/api/alerts/{}'.format(access_config.get('vrops_site'), alarm_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_uuid)) except Exception as exp: logger.error( "Exception occured while getting alert definition ID for alarm : {}".format(exp, alarm_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 = {} alaram_config = get_alarm_config() #Parse noditfy data notify_details['alarm_uuid'] = get_alarm_definationID(postdata.get('alertId')) 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'] = alaram_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 kafkaMsgProducer = KafkaProducer() kafkaMsgProducer.publish(topic='alarm_response', key='notify_alarm', value=alarm_data) #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')