| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 1 | ## |
| 2 | # Copyright 2017 xFlow Research Pvt. Ltd |
| 3 | # This file is part of MON module |
| 4 | # All Rights Reserved. |
| 5 | # |
| 6 | # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 7 | # not use this file except in compliance with the License. You may obtain |
| 8 | # a copy of the License at |
| 9 | # |
| 10 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | # |
| 12 | # Unless required by applicable law or agreed to in writing, software |
| 13 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 14 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 15 | # License for the specific language governing permissions and limitations |
| 16 | # under the License. |
| 17 | # |
| 18 | # For those usages not covered by the Apache License, Version 2.0 please |
| 19 | # contact with: wajeeha.hamid@xflowresearch.com |
| 20 | ## |
| 21 | |
| 22 | ''' |
| 23 | AWS-Plugin implements all the methods of MON to interact with AWS using the BOTO client |
| 24 | ''' |
| 25 | |
| 26 | __author__ = "Wajeeha Hamid" |
| 27 | __date__ = "18-Sept-2017" |
| 28 | |
| 29 | import sys |
| 30 | import datetime |
| 31 | import json |
| 32 | import logging as log |
| 33 | |
| 34 | try: |
| 35 | import boto |
| 36 | import boto.ec2 |
| 37 | import boto.vpc |
| 38 | import boto.ec2.cloudwatch |
| 39 | import boto.ec2.connection |
| 40 | except: |
| 41 | exit("Boto not avialable. Try activating your virtualenv OR `pip install boto`") |
| 42 | |
| 43 | |
| 44 | |
| 45 | class Metrics(): |
| 46 | |
| 47 | def createMetrics(self,cloudwatch_conn,metric_info): |
| 48 | try: |
| 49 | |
| 50 | '''createMetrics will be returning the metric_uuid=0 and |
| 51 | status=True when the metric is supported by AWS''' |
| 52 | |
| 53 | supported=self.check_metric(metric_info['metric_name']) |
| 54 | metric_resp = dict() |
| hamid | bfbc3dd | 2017-09-30 16:23:30 +0500 | [diff] [blame^] | 55 | metric_resp['resource_uuid'] = metric_info['resource_uuid'] |
| 56 | |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 57 | if supported['status'] == True: |
| 58 | metric_resp['status'] = True |
| 59 | metric_resp['metric_uuid'] = 0 |
| hamid | bfbc3dd | 2017-09-30 16:23:30 +0500 | [diff] [blame^] | 60 | log.debug("Metrics Configured Succesfully : %s" , metric_resp) |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 61 | else: |
| 62 | metric_resp['status'] = False |
| 63 | metric_resp['metric_uuid'] = None |
| hamid | bfbc3dd | 2017-09-30 16:23:30 +0500 | [diff] [blame^] | 64 | log.error("Metric name is not supported") |
| 65 | |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 66 | return metric_resp |
| 67 | |
| 68 | except Exception as e: |
| 69 | log.error("Metric Configuration Failed: " + str(e)) |
| 70 | #----------------------------------------------------------------------------------------------------------------------------- |
| 71 | |
| 72 | def metricsData(self,cloudwatch_conn,data_info): |
| 73 | |
| 74 | """Getting Metrics Stats for an Hour.The datapoints are |
| 75 | received after every one minute. |
| 76 | Time interval can be modified using Timedelta value""" |
| 77 | |
| 78 | try: |
| 79 | metric_info = dict() |
| 80 | metric_info_dict = dict() |
| 81 | timestamp_arr = {} |
| 82 | value_arr = {} |
| 83 | |
| 84 | supported=self.check_metric(data_info['metric_name']) |
| 85 | |
| hamid | 9f6a271 | 2017-09-27 16:53:56 +0500 | [diff] [blame] | 86 | if supported['status'] == True: |
| 87 | if int(data_info['collection_period']) % 60 == 0: |
| 88 | metric_stats=cloudwatch_conn.get_metric_statistics(60, datetime.datetime.utcnow() - datetime.timedelta(seconds=int(data_info['collection_period'])), |
| 89 | datetime.datetime.utcnow(),supported['metric_name'],'AWS/EC2', 'Maximum', |
| 90 | dimensions={'InstanceId':data_info['resource_uuid']}, unit='Percent') |
| 91 | index = 0 |
| 92 | for itr in range (len(metric_stats)): |
| 93 | timestamp_arr[index] = str(metric_stats[itr]['Timestamp']) |
| 94 | value_arr[index] = metric_stats[itr]['Maximum'] |
| 95 | index +=1 |
| 96 | metric_info_dict['time_series'] = timestamp_arr |
| 97 | metric_info_dict['metrics_series'] = value_arr |
| 98 | log.debug("Metrics Data : %s", metric_info_dict) |
| 99 | return metric_info_dict |
| 100 | else: |
| 101 | log.error("Collection Period should be a multiple of 60") |
| 102 | return False |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 103 | |
| hamid | 9f6a271 | 2017-09-27 16:53:56 +0500 | [diff] [blame] | 104 | else: |
| hamid | bfbc3dd | 2017-09-30 16:23:30 +0500 | [diff] [blame^] | 105 | log.error("Metric name is not supported") |
| hamid | 9f6a271 | 2017-09-27 16:53:56 +0500 | [diff] [blame] | 106 | return False |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 107 | |
| 108 | except Exception as e: |
| 109 | log.error("Error returning Metrics Data" + str(e)) |
| 110 | |
| 111 | #----------------------------------------------------------------------------------------------------------------------------- |
| 112 | def updateMetrics(self,cloudwatch_conn,metric_info): |
| 113 | |
| 114 | '''updateMetrics will be returning the metric_uuid=0 and |
| 115 | status=True when the metric is supported by AWS''' |
| 116 | try: |
| 117 | supported=self.check_metric(metric_info['metric_name']) |
| 118 | update_resp = dict() |
| hamid | bfbc3dd | 2017-09-30 16:23:30 +0500 | [diff] [blame^] | 119 | update_resp['resource_uuid'] = metric_info['resource_uuid'] |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 120 | if supported['status'] == True: |
| 121 | update_resp['status'] = True |
| 122 | update_resp['metric_uuid'] = 0 |
| hamid | bfbc3dd | 2017-09-30 16:23:30 +0500 | [diff] [blame^] | 123 | log.debug("Metric Updated : %s", update_resp) |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 124 | else: |
| 125 | update_resp['status'] = False |
| 126 | update_resp['metric_uuid'] = None |
| hamid | bfbc3dd | 2017-09-30 16:23:30 +0500 | [diff] [blame^] | 127 | log.error("Metric name is not supported") |
| 128 | |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 129 | return update_resp |
| 130 | |
| 131 | except Exception as e: |
| 132 | log.error("Error in Update Metrics" + str(e)) |
| 133 | #----------------------------------------------------------------------------------------------------------------------------- |
| 134 | def deleteMetrics(self,cloudwatch_conn,del_info): |
| 135 | |
| 136 | ''' " Not supported in AWS" |
| 137 | Returning the required parameters with status = False''' |
| 138 | try: |
| hamid | 9f6a271 | 2017-09-27 16:53:56 +0500 | [diff] [blame] | 139 | supported=self.check_metric(del_info['metric_name']) |
| 140 | metric_resp = dict() |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 141 | del_resp = dict() |
| hamid | 9f6a271 | 2017-09-27 16:53:56 +0500 | [diff] [blame] | 142 | if supported['status'] == True: |
| 143 | del_resp['schema_version'] = del_info['schema_version'] |
| 144 | del_resp['schema_type'] = "delete_metric_response" |
| 145 | del_resp['metric_name'] = del_info['metric_name'] |
| 146 | del_resp['metric_uuid'] = del_info['metric_uuid'] |
| 147 | del_resp['resource_uuid'] = del_info['resource_uuid'] |
| 148 | # TODO : yet to finalize |
| 149 | del_resp['tenant_uuid'] = del_info['tenant_uuid'] |
| 150 | del_resp['correlation_id'] = del_info['correlation_uuid'] |
| 151 | del_resp['status'] = False |
| 152 | log.info("Metric Deletion Not supported in AWS : %s",del_resp) |
| 153 | return del_resp |
| 154 | else: |
| hamid | bfbc3dd | 2017-09-30 16:23:30 +0500 | [diff] [blame^] | 155 | log.error("Metric name is not supported") |
| hamid | 9f6a271 | 2017-09-27 16:53:56 +0500 | [diff] [blame] | 156 | return False |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 157 | |
| 158 | except Exception as e: |
| 159 | log.error(" Metric Deletion Not supported in AWS : " + str(e)) |
| 160 | #------------------------------------------------------------------------------------------------------------------------------------ |
| 161 | |
| 162 | def listMetrics(self,cloudwatch_conn ,list_info): |
| 163 | |
| 164 | '''Returns the list of available AWS/EC2 metrics on which |
| 165 | alarms have been configured and the metrics are being monitored''' |
| 166 | try: |
| 167 | supported = self.check_metric(list_info['metric_name']) |
| hamid | 9f6a271 | 2017-09-27 16:53:56 +0500 | [diff] [blame] | 168 | if supported['status'] == True: |
| 169 | metrics_list = [] |
| 170 | metrics_data = dict() |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 171 | |
| hamid | 9f6a271 | 2017-09-27 16:53:56 +0500 | [diff] [blame] | 172 | #To get the list of associated metrics with the alarms |
| 173 | alarms = cloudwatch_conn.describe_alarms() |
| 174 | itr = 0 |
| 175 | if list_info['metric_name'] == "": |
| 176 | for alarm in alarms: |
| 177 | metrics_info = dict() |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 178 | instance_id = str(alarm.dimensions['InstanceId']).split("'")[1] |
| hamid | 9f6a271 | 2017-09-27 16:53:56 +0500 | [diff] [blame] | 179 | metrics_info['metric_name'] = str(alarm.metric) |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 180 | metrics_info['metric_uuid'] = 0 |
| 181 | metrics_info['metric_unit'] = str(alarm.unit) |
| hamid | 9f6a271 | 2017-09-27 16:53:56 +0500 | [diff] [blame] | 182 | metrics_info['resource_uuid'] = instance_id |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 183 | metrics_list.insert(itr,metrics_info) |
| 184 | itr += 1 |
| hamid | 9f6a271 | 2017-09-27 16:53:56 +0500 | [diff] [blame] | 185 | print metrics_list |
| 186 | return metrics_list |
| 187 | else: |
| 188 | for alarm in alarms: |
| 189 | metrics_info = dict() |
| 190 | if alarm.metric == supported['metric_name']: |
| 191 | instance_id = str(alarm.dimensions['InstanceId']).split("'")[1] |
| 192 | metrics_info['metric_name'] = str(alarm.metric) |
| 193 | metrics_info['metric_uuid'] = 0 |
| 194 | metrics_info['metric_unit'] = str(alarm.unit) |
| 195 | metrics_info['resource_uuid'] = instance_id |
| 196 | metrics_list.insert(itr,metrics_info) |
| 197 | itr += 1 |
| 198 | return metrics_list |
| 199 | log.debug("Metrics List : %s",metrics_list) |
| 200 | else: |
| hamid | bfbc3dd | 2017-09-30 16:23:30 +0500 | [diff] [blame^] | 201 | log.error("Metric name is not supported") |
| hamid | 9f6a271 | 2017-09-27 16:53:56 +0500 | [diff] [blame] | 202 | return False |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 203 | |
| 204 | except Exception as e: |
| 205 | log.error("Error in Getting Metric List " + str(e)) |
| 206 | |
| 207 | #------------------------------------------------------------------------------------------------------------------------------------ |
| 208 | |
| 209 | def check_metric(self,metric_name): |
| 210 | |
| 211 | ''' Checking whether the metric is supported by AWS ''' |
| 212 | try: |
| 213 | check_resp = dict() |
| hamid | 9f6a271 | 2017-09-27 16:53:56 +0500 | [diff] [blame] | 214 | # metric_name |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 215 | if metric_name == 'CPU_UTILIZATION': |
| 216 | metric_name = 'CPUUtilization' |
| 217 | metric_status = True |
| 218 | elif metric_name == 'DISK_READ_OPS': |
| 219 | metric_name = 'DiskReadOps' |
| 220 | metric_status = True |
| 221 | elif metric_name == 'DISK_WRITE_OPS': |
| 222 | metric_name = 'DiskWriteOps' |
| 223 | metric_status = True |
| 224 | elif metric_name == 'DISK_READ_BYTES': |
| 225 | metric_name = 'DiskReadBytes' |
| 226 | metric_status = True |
| 227 | elif metric_name == 'DISK_WRITE_BYTES': |
| 228 | metric_name = 'DiskWriteBytes' |
| 229 | metric_status = True |
| 230 | elif metric_name == 'PACKETS_RECEIVED': |
| 231 | metric_name = 'NetworkPacketsIn' |
| 232 | metric_status = True |
| 233 | elif metric_name == 'PACKETS_SENT': |
| 234 | metric_name = 'NetworkPacketsOut' |
| 235 | metric_status = True |
| hamid | 9f6a271 | 2017-09-27 16:53:56 +0500 | [diff] [blame] | 236 | elif metric_name == "": |
| 237 | metric_name = None |
| 238 | metric_status = True |
| 239 | log.info("Metric Not Supported by AWS plugin ") |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 240 | else: |
| 241 | metric_name = None |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 242 | metric_status = False |
| hamid | 9f6a271 | 2017-09-27 16:53:56 +0500 | [diff] [blame] | 243 | log.info("Metric Not Supported by AWS plugin ") |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 244 | check_resp['metric_name'] = metric_name |
| 245 | #status |
| 246 | if metric_status == True: |
| 247 | check_resp['status'] = True |
| hamid | 9f6a271 | 2017-09-27 16:53:56 +0500 | [diff] [blame] | 248 | else: |
| 249 | check_resp['status'] = False |
| 250 | |
| 251 | return check_resp |
| 252 | |
| hamid | 681877c | 2017-09-18 16:56:59 +0500 | [diff] [blame] | 253 | except Exception as e: |
| 254 | log.error("Error in Plugin Inputs %s",str(e)) |
| 255 | #-------------------------------------------------------------------------------------------------------------------------------------- |
| 256 | |
| 257 | |
| 258 | |
| 259 | |
| 260 | |
| 261 | |
| 262 | |
| 263 | |