Merge "Included OpenStack integration tests."
[osm/MON.git] / osm_mon / 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 getfqdn
37 from datetime import datetime
38 from xml.etree import ElementTree as ET
39 import logging
40 import os
41 import json
42 import sys
43 import requests
44 sys.path.append("../../../core/message_bus")
45 from producer import KafkaProducer
46 #from core.message_bus.producer import KafkaProducer
47
48 try:
49     from cheroot.wsgi import Server as WSGIServer
50     from cheroot.ssl.pyopenssl import pyOpenSSLAdapter
51 except ImportError:
52     from cherrypy.wsgiserver import CherryPyWSGIServer as WSGIServer
53     from cherrypy.wsgiserver.ssl_pyopenssl import pyOpenSSLAdapter
54
55 #Set Constants
56 BASE_DIR = os.path.dirname(os.path.dirname(__file__))
57 CERT_DIR = os.path.join(BASE_DIR, "SSL_certificate")
58 certificate_name = getfqdn() + ".cert"
59 key_name = getfqdn() + ".key"
60 CERTIFICATE = os.path.join(CERT_DIR, certificate_name)
61 KEY = os.path.join(CERT_DIR, key_name)
62 #CERTIFICATE = os.path.join(CERT_DIR, "www.vrops_webservice.com.cert")
63 #KEY = os.path.join(CERT_DIR, "www.vrops_webservice.com.key")
64 CONFIG_FILE = os.path.join(BASE_DIR, '../vrops_config.xml')
65 #Severity Mapping from vROPs to OSM
66 VROPS_SEVERITY_TO_OSM_MAPPING = {
67                 "ALERT_CRITICALITY_LEVEL_CRITICAL":"CRITICAL",
68                 "ALERT_CRITICALITY_LEVEL_WARNING":"WARNING",
69                 "ALERT_CRITICALITY_LEVEL_IMMEDIATE":"MAJOR",
70                 "ALERT_CRITICALITY_LEVEL_INFO":"INDETERMINATE",
71                 "ALERT_CRITICALITY_LEVEL_AUTO":"INDETERMINATE",
72                 "ALERT_CRITICALITY_LEVEL_UNKNOWN":"INDETERMINATE",
73                 "ALERT_CRITICALITY_LEVEL_NONE":"INDETERMINATE"
74             }
75
76 #Set logger
77 logger = logging.getLogger('vROPs_Webservice')
78 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
79 hdlr = logging.FileHandler(os.path.join(BASE_DIR,"vrops_webservice.log"))
80 hdlr.setFormatter(formatter)
81 logger.addHandler(hdlr)
82 logger.setLevel(logging.DEBUG)
83
84
85 def format_datetime(str_date):
86     """
87         Method to format datetime
88         Args:
89             str_date - datetime string
90         Returns:
91            formated datetime
92     """
93     date_fromat = "%Y-%m-%dT%H:%M:%S"
94     formated_datetime = None
95     try:
96         datetime_obj = datetime.fromtimestamp(float(str_date)/1000.)
97         formated_datetime = datetime_obj.strftime(date_fromat)
98     except Exception as exp:
99         logger.error('Exception: {} occured while converting date {} into format {}'.format(
100                            exp,str_date, date_fromat))
101
102     return formated_datetime
103
104 def get_alarm_config():
105     """
106         Method to get configuration parameters
107         Args:
108             None
109         Returns:
110             dictionary of config parameters
111     """
112     alarm_config = {}
113     try:
114         xml_content = ET.parse(CONFIG_FILE)
115         alarms = xml_content.getroot()
116         for alarm in alarms:
117             if alarm.tag == 'Access_Config':
118                 for param in alarm:
119                     alarm_config[param.tag] = param.text
120     except Exception as exp:
121         logger.error('Exception: {} occured while parsing config file.'.format(exp))
122
123     return alarm_config
124
125 def get_alarm_definationID(alarm_uuid):
126     """
127          Method to get alarm/alert defination ID
128             Args:
129                 alarm_uuid : UUID of alarm
130             Returns:
131                 alarm defination ID
132     """
133     alarm_definationID = None
134     if alarm_uuid :
135         try:
136             access_config = get_alarm_config()
137             headers = {'Accept': 'application/json'}
138             api_url = '{}/suite-api/api/alerts/{}'.format(access_config.get('vrops_site'), alarm_uuid)
139             api_response = requests.get(
140                             api_url,
141                             auth=(access_config.get('vrops_user'), access_config.get('vrops_password')),
142                             verify = False, headers = headers
143                             )
144
145             if  api_response.status_code == 200:
146                 data = api_response.json()
147                 if data.get("alertDefinitionId") is not None:
148                     alarm_definationID = '-'.join(data.get("alertDefinitionId").split('-')[1:])
149             else:
150                 logger.error("Failed to get alert definition ID for alarm {}".format(alarm_uuid))
151         except Exception as exp:
152             logger.error( "Exception occured while getting alert definition ID for alarm : {}".format(exp, alarm_uuid))
153
154     return alarm_definationID
155
156
157 @route('/notify/<alarmID>', method='POST')
158 def notify_alarm(alarmID):
159     """
160         Method notify alarm details by publishing message at Kafka message bus
161         Args:
162             alarmID - Name of alarm
163         Returns:
164            response code
165     """
166     logger.info("Request:{} from:{} {} {} ".format(request, request.remote_addr, request.method, request.url))
167     response.headers['Content-Type'] = 'application/json'
168     try:
169         postdata = json.loads(request.body.read())
170         notify_details = {}
171         alaram_config = get_alarm_config()
172         #Parse noditfy data
173         notify_details['alarm_uuid'] = get_alarm_definationID(postdata.get('alertId'))
174         notify_details['description'] = postdata.get('info')
175         notify_details['alarm_instance_uuid'] = alarmID
176         notify_details['resource_uuid'] = '-'.join(postdata.get('alertName').split('-')[1:])
177         notify_details['tenant_uuid'] =  alaram_config.get('tenant_id')
178         notify_details['vim_type'] = "VMware"
179         notify_details['severity'] = VROPS_SEVERITY_TO_OSM_MAPPING.get(postdata.get('criticality'), 'INDETERMINATE')
180         notify_details['status'] = postdata.get('status')
181         if postdata.get('startDate'):
182             notify_details['start_date_time'] = format_datetime(postdata.get('startDate'))
183         if postdata.get('updateDate'):
184             notify_details['update_date_time'] = format_datetime(postdata.get('updateDate'))
185         if postdata.get('cancelDate'):
186             notify_details['cancel_date_time'] = format_datetime(postdata.get('cancelDate'))
187
188         alarm_details = {'schema_version': 1.0,
189                          'schema_type': "notify_alarm",
190                          'notify_details': notify_details
191                         }
192         alarm_data = json.dumps(alarm_details)
193         logger.info("Alarm details: {}".format(alarm_data))
194
195         #Publish Alarm details
196         kafkaMsgProducer = KafkaProducer("alarm_response")
197         kafkaMsgProducer.publish(topic='alarm_response', key='notify_alarm', value=alarm_data)
198
199         #return 201 on Success
200         response.status = 201
201
202     except Exception as exp:
203         logger.error('Exception: {} occured while notifying alarm {}.'.format(exp, alarmID))
204         #return 500 on Error
205         response.status = 500
206
207     return response
208
209
210 class SSLWebServer(ServerAdapter):
211     """
212     CherryPy web server with SSL support.
213     """
214
215     def run(self, handler):
216         """
217         Runs a CherryPy Server using the SSL certificate.
218         """
219         server = WSGIServer((self.host, self.port), handler)
220         server.ssl_adapter = pyOpenSSLAdapter(
221             certificate=CERTIFICATE,
222             private_key=KEY,
223            # certificate_chain="intermediate_cert.crt"
224         )
225
226         try:
227             server.start()
228             logger.info("Started vROPs Web Service")
229         except Exception as exp:
230             server.stop()
231             logger.error("Exception: {} Stopped vROPs Web Service".format(exp))
232
233
234 if __name__ == "__main__":
235     #Start SSL Web Service
236     logger.info("Start vROPs Web Service")
237     app = default_app()
238     server_names['sslwebserver'] = SSLWebServer
239     run(app=app,host=getfqdn(), port=8080, server='sslwebserver')
240
241
242