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