OSM MON Installation and Packaging Updates
[osm/MON.git] / plugins / vRealiseOps / vROPs_Webservice / vrops_webservice
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 ##
5 # Copyright 2016-2017 VMware Inc.
6 # This file is part of ETSI OSM
7 # All Rights Reserved.
8 #
9 # Licensed under the Apache License, Version 2.0 (the "License"); you may
10 # not use this file except in compliance with the License. You may obtain
11 # a copy of the License at
12 #
13 #         http://www.apache.org/licenses/LICENSE-2.0
14 #
15 # Unless required by applicable law or agreed to in writing, software
16 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18 # License for the specific language governing permissions and limitations
19 # under the License.
20 #
21 # For those usages not covered by the Apache License, Version 2.0 please
22 # contact:  osslegalrouting@vmware.com
23 ##
24
25 """
26  Webservice for vRealize Operations (vROPs) to post/notify alarms details.
27
28 """
29 __author__ = "Arpita Kate"
30 __date__ = "$15-Sept-2017 16:09:29$"
31 __version__ = '0.1'
32
33
34 from bottle import (ServerAdapter, route, run, server_names, redirect, default_app,
35                      request, response, template, debug, TEMPLATE_PATH , static_file)
36 from socket import gethostname
37 from datetime import datetime
38 from xml.etree import ElementTree as ET
39 import logging
40 import os
41 import json
42 import requests
43
44 from core.message_bus.producer import KafkaProducer
45
46 try:
47     from cheroot.wsgi import Server as WSGIServer
48     from cheroot.ssl.pyopenssl import pyOpenSSLAdapter
49 except ImportError:
50     from cherrypy.wsgiserver import CherryPyWSGIServer as WSGIServer
51     from cherrypy.wsgiserver.ssl_pyopenssl import pyOpenSSLAdapter
52
53 #Set Constants
54 BASE_DIR = os.path.dirname(os.path.dirname(__file__))
55 CERT_DIR = os.path.join(BASE_DIR, "SSL_certificate")
56 CERTIFICATE = os.path.join(CERT_DIR, "www.vrops_webservice.com.cert")
57 KEY = os.path.join(CERT_DIR, "www.vrops_webservice.com.key")
58 CONFIG_FILE = os.path.join(BASE_DIR, '../vrops_config.xml')
59 #Severity Mapping from vROPs to OSM
60 VROPS_SEVERITY_TO_OSM_MAPPING = {
61                 "ALERT_CRITICALITY_LEVEL_CRITICAL":"CRITICAL",
62                 "ALERT_CRITICALITY_LEVEL_WARNING":"WARNING",
63                 "ALERT_CRITICALITY_LEVEL_IMMEDIATE":"MAJOR",
64                 "ALERT_CRITICALITY_LEVEL_INFO":"INDETERMINATE",
65                 "ALERT_CRITICALITY_LEVEL_AUTO":"INDETERMINATE",
66                 "ALERT_CRITICALITY_LEVEL_UNKNOWN":"INDETERMINATE",
67                 "ALERT_CRITICALITY_LEVEL_NONE":"INDETERMINATE"
68             }
69
70 #Set logger
71 logger = logging.getLogger('vROPs_Webservice')
72 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
73 hdlr = logging.FileHandler(os.path.join(BASE_DIR,"vrops_webservice.log"))
74 hdlr.setFormatter(formatter)
75 logger.addHandler(hdlr)
76 logger.setLevel(logging.DEBUG)
77
78
79 def format_datetime(str_date):
80     """
81         Method to format datetime
82         Args:
83             str_date - datetime string
84         Returns:
85            formated datetime
86     """
87     date_fromat = "%Y-%m-%dT%H:%M:%S"
88     formated_datetime = None
89     try:
90         datetime_obj = datetime.fromtimestamp(float(str_date)/1000.)
91         formated_datetime = datetime_obj.strftime(date_fromat)
92     except Exception as exp:
93         logger.error('Exception: {} occured while converting date {} into format {}'.format(
94                            exp,str_date, date_fromat))
95
96     return formated_datetime
97
98 def get_alarm_config():
99     """
100         Method to get configuration parameters
101         Args:
102             None
103         Returns:
104             dictionary of config parameters
105     """
106     alarm_config = {}
107     try:
108         xml_content = ET.parse(CONFIG_FILE)
109         alarms = xml_content.getroot()
110         for alarm in alarms:
111             if alarm.tag == 'Access_Config':
112                 for param in alarm:
113                     alarm_config[param.tag] = param.text
114     except Exception as exp:
115         logger.error('Exception: {} occured while parsing config file.'.format(exp))
116
117     return alarm_config
118
119 def get_alarm_definationID(alarm_uuid):
120     """
121          Method to get alarm/alert defination ID
122             Args:
123                 alarm_uuid : UUID of alarm
124             Returns:
125                 alarm defination ID
126     """
127     alarm_definationID = None
128     if alarm_uuid :
129         try:
130             access_config = get_alarm_config()
131             headers = {'Accept': 'application/json'}
132             api_url = '{}/suite-api/api/alerts/{}'.format(access_config.get('vrops_site'), alarm_uuid)
133             api_response = requests.get(
134                             api_url,
135                             auth=(access_config.get('vrops_user'), access_config.get('vrops_password')),
136                             verify = False, headers = headers
137                             )
138
139             if  api_response.status_code == 200:
140                 data = api_response.json()
141                 if data.get("alertDefinitionId") is not None:
142                     alarm_definationID = '-'.join(data.get("alertDefinitionId").split('-')[1:])
143             else:
144                 logger.error("Failed to get alert definition ID for alarm {}".format(alarm_uuid))
145         except Exception as exp:
146             logger.error( "Exception occured while getting alert definition ID for alarm : {}".format(exp, alarm_uuid))
147
148     return alarm_definationID
149
150
151 @route('/notify/<alarmID>', method='POST')
152 def notify_alarm(alarmID):
153     """
154         Method notify alarm details by publishing message at Kafka message bus
155         Args:
156             alarmID - Name of alarm
157         Returns:
158            response code
159     """
160     logger.info("Request:{} from:{} {} {} ".format(request, request.remote_addr, request.method, request.url))
161     response.headers['Content-Type'] = 'application/json'
162     try:
163         postdata = json.loads(request.body.read())
164         notify_details = {}
165         alaram_config = get_alarm_config()
166         #Parse noditfy data
167         notify_details['alarm_uuid'] = get_alarm_definationID(postdata.get('alertId'))
168         notify_details['description'] = postdata.get('info')
169         notify_details['alarm_instance_uuid'] = alarmID
170         notify_details['resource_uuid'] = '-'.join(postdata.get('alertName').split('-')[1:])
171         notify_details['tenant_uuid'] =  alaram_config.get('tenant_id')
172         notify_details['vim_type'] = "VMware"
173         notify_details['severity'] = VROPS_SEVERITY_TO_OSM_MAPPING.get(postdata.get('criticality'), 'INDETERMINATE')
174         notify_details['status'] = postdata.get('status')
175         if postdata.get('startDate'):
176             notify_details['start_date_time'] = format_datetime(postdata.get('startDate'))
177         if postdata.get('updateDate'):
178             notify_details['update_date_time'] = format_datetime(postdata.get('updateDate'))
179         if postdata.get('cancelDate'):
180             notify_details['cancel_date_time'] = format_datetime(postdata.get('cancelDate'))
181
182         alarm_details = {'schema_version': 1.0,
183                          'schema_type': "notify_alarm",
184                          'notify_details': notify_details
185                         }
186         alarm_data = json.dumps(alarm_details)
187         logger.info("Alarm details: {}".format(alarm_data))
188
189         #Publish Alarm details
190         kafkaMsgProducer = KafkaProducer()
191         kafkaMsgProducer.publish(topic='alarm_response', key='notify_alarm', value=alarm_data)
192
193         #return 201 on Success
194         response.status = 201
195
196     except Exception as exp:
197         logger.error('Exception: {} occured while notifying alarm {}.'.format(exp, alarmID))
198         #return 500 on Error
199         response.status = 500
200
201     return response
202
203
204 class SSLWebServer(ServerAdapter):
205     """
206     CherryPy web server with SSL support.
207     """
208
209     def run(self, handler):
210         """
211         Runs a CherryPy Server using the SSL certificate.
212         """
213         server = WSGIServer((self.host, self.port), handler)
214         server.ssl_adapter = pyOpenSSLAdapter(
215             certificate=CERTIFICATE,
216             private_key=KEY,
217            # certificate_chain="intermediate_cert.crt"
218         )
219
220         try:
221             server.start()
222             logger.info("Started vROPs Web Serverice")
223         except Exception as exp:
224             server.stop()
225             logger.error("Exception: {} Stopped vROPs Web Serverice".format(exp))
226
227
228 if __name__ == "__main__":
229     #Start SSL Web Service
230     logger.info("Start vROPs Web Serverice")
231     app = default_app()
232     server_names['sslwebserver'] = SSLWebServer
233     run(app=app,host=gethostname(), port=8080, server='sslwebserver')
234