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