zabbix_export: version: '6.0' date: '2024-08-20T09:48:41Z' groups: - uuid: c2c162144c2d4c5491c8801193af4945 name: Templates/Cloud templates: - uuid: 7af6d68b223a43d4bf8526cc5dc3fe2e template: 'AWS EC2 by HTTP' name: 'AWS EC2 by HTTP' description: | Get AWS EC2 and attached AWS EBS volumes metrics and uses the script item to make HTTP requests to the CloudWatch API. Don't forget to read the README.md for the correct setup of the template. You can discuss this template or leave feedback on our forum https://www.zabbix.com/forum/zabbix-suggestions-and-feedback Generated by official Zabbix template tool "Templator" groups: - name: Templates/Cloud items: - uuid: 22b61bf7ebba43e8aef544385448d18c name: 'AWS EC2: Get alarms check' type: DEPENDENT key: aws.ec2.alarms.check delay: '0' history: 7d trends: '0' value_type: CHAR description: 'Check result of the alarm data has been got correctly.' preprocessing: - type: JSONPATH parameters: - $.error error_handler: CUSTOM_VALUE - type: DISCARD_UNCHANGED_HEARTBEAT parameters: - 3h master_item: key: aws.ec2.get_alarms tags: - tag: component value: status triggers: - uuid: 1d017a1213fb4bc9896add10a2b97dd6 expression: 'length(last(/AWS EC2 by HTTP/aws.ec2.alarms.check))>0' name: 'AWS EC2: Failed to get alarms data' priority: WARNING description: 'Failed to get CloudWatch alarms for EC2.' tags: - tag: scope value: availability - uuid: 0384bacca1e14994a5c38dc55b73e8bb name: 'AWS EC2: Credit CPU: Balance' type: DEPENDENT key: aws.ec2.cpu.credit_balance delay: '0' history: 7d value_type: FLOAT description: | The number of earned CPU credits that an instance has accrued since it was launched or started. For T2 Standard, the CPUCreditBalance also includes the number of launch credits that have been accrued. Credits are accrued in the credit balance after they are earned, and removed from the credit balance when they are spent. The credit balance has a maximum limit, determined by the instance size. After the limit is reached, any new credits that are earned are discarded. For T2 Standard, launch credits do not count towards the limit. The credits in the CPUCreditBalance are available for the instance to spend to burst beyond its baseline CPU utilization. When an instance is running, credits in the CPUCreditBalance do not expire. When a T3 or T3a instance stops, the CPUCreditBalance value persists for seven days. Thereafter, all accrued credits are lost. When a T2 instance stops, the CPUCreditBalance value does not persist, and all accrued credits are lost. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "CPUCreditBalance")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: aws.ec2.get_metrics tags: - tag: component value: cpu - tag: component value: credit triggers: - uuid: 4e67cac1f58a478fb0e47c52b402fd92 expression: 'max(/AWS EC2 by HTTP/aws.ec2.cpu.credit_balance,5m)<{$AWS.EC2.CPU.CREDIT.BALANCE.MIN.WARN}' name: 'AWS EC2: Instance CPU Credit balance is too low' event_name: 'AWS EC2: Instance CPU Credit balance is too low (less {$AWS.EC2.CPU.CREDIT.BALANCE.MIN.WARN} for 5m)' opdata: 'Current value: {ITEM.LASTVALUE1}' priority: WARNING description: 'The number of earned CPU credits has been less than {$AWS.EC2.CPU.CREDIT.BALANCE.MIN.WARN} in the last 5 minutes.' tags: - tag: scope value: capacity - uuid: b445a56de3194f6f9b4bf9dd85fcbe52 name: 'AWS EC2: Credit CPU: Usage' type: DEPENDENT key: aws.ec2.cpu.credit_usage delay: '0' history: 7d value_type: FLOAT description: | The number of CPU credits spent by the instance for CPU utilization. One CPU credit equals one vCPU running at 100% utilization for one minute or an equivalent combination of vCPUs, utilization, and time (for example, one vCPU running at 50% utilization for two minutes or two vCPUs running at 25% utilization for two minutes). preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "CPUCreditUsage")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: aws.ec2.get_metrics tags: - tag: component value: cpu - tag: component value: credit - uuid: 285ec6451412450c963e3a24d2aa74e1 name: 'AWS EC2: Credit CPU: Surplus balance' type: DEPENDENT key: aws.ec2.cpu.surplus_credit_balance delay: '0' history: 7d value_type: FLOAT description: | The number of surplus credits that have been spent by an unlimited instance when its CPUCreditBalance value is zero. The CPUSurplusCreditBalance value is paid down by earned CPU credits. If the number of surplus credits exceeds the maximum number of credits that the instance can earn in a 24-hour period, the spent surplus credits above the maximum incur an additional charge. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "CPUSurplusCreditBalance")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: aws.ec2.get_metrics tags: - tag: component value: cpu - tag: component value: credit - uuid: 77a32118a77e4836a945c7b0954ef64a name: 'AWS EC2: Credit CPU: Surplus charged' type: DEPENDENT key: aws.ec2.cpu.surplus_credit_charged delay: '0' history: 7d value_type: FLOAT description: | The number of spent surplus credits that are not paid down by earned CPU credits, and which thus incur an additional charge. Spent surplus credits are charged when any of the following occurs: - The spent surplus credits exceed the maximum number of credits that the instance can earn in a 24-hour period. Spent surplus credits above the maximum are charged at the end of the hour; - The instance is stopped or terminated; - The instance is switched from unlimited to standard. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "CPUSurplusCreditsCharged")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: aws.ec2.get_metrics tags: - tag: component value: cpu - tag: component value: credit triggers: - uuid: 644ace5510164f329d9af65bd0ed4f34 expression: 'last(/AWS EC2 by HTTP/aws.ec2.cpu.surplus_credit_charged)>{$AWS.EC2.CPU.CREDIT.SURPLUS.BALANCE.MAX.WARN}' name: 'AWS EC2: Instance has spent too many CPU surplus credits' event_name: 'AWS EC2: Instance has spent too many CPU surplus credits (over {$AWS.EC2.CPU.CREDIT.SURPLUS.BALANCE.MAX.WARN} for 15m)''' opdata: 'Current value: {ITEM.LASTVALUE1}' priority: WARNING description: 'The number of spent surplus credits that are not paid down and which thus incur an additional charge is over {$AWS.EC2.CPU.CREDIT.SURPLUS.BALANCE.MAX.WARN}.' tags: - tag: scope value: capacity - uuid: 7fd871e7eed54845ad069c3e7d3cad56 name: 'AWS EC2: CPU: Utilization' type: DEPENDENT key: aws.ec2.cpu_utilization delay: '0' history: 7d value_type: FLOAT units: '%' description: | The percentage of allocated EC2 compute units that are currently in use on the instance. This metric identifies the processing power required to run an application on a selected instance. Depending on the instance type, tools in your operating system can show a lower percentage than CloudWatch when the instance is not allocated a full processor core. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "CPUUtilization")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: aws.ec2.get_metrics tags: - tag: component value: cpu triggers: - uuid: ea74d00067874b609e4846847033058f expression: 'min(/AWS EC2 by HTTP/aws.ec2.cpu_utilization,15m)>{$AWS.EC2.CPU.UTIL.WARN.MAX}' name: 'AWS EC2: High CPU utilization' event_name: 'AWS EC2: High CPU utilization (over {$AWS.EC2.CPU.UTIL.WARN.MAX}% for 15m)' opdata: 'Current utilization: {ITEM.LASTVALUE1}' priority: WARNING description: 'The CPU utilization is too high. The system might be slow to respond.' tags: - tag: scope value: capacity - tag: scope value: performance - uuid: 49aecab5c7df407b9cbfe80ad8790492 name: 'AWS EC2: Disk: Read bytes, rate' type: DEPENDENT key: aws.ec2.disk.read_bytes.rate delay: '0' history: 7d value_type: FLOAT units: Bps description: | Bytes read from all instance store volumes available to the instance. This metric is used to determine the volume of the data the application reads from the hard disk of the instance. This can be used to determine the speed of the application. If there are no instance store volumes, either the value is 0 or the metric is not reported. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "DiskReadBytes")].Values.first().first()' error_handler: DISCARD_VALUE - type: JAVASCRIPT parameters: - 'return value / 300;' master_item: key: aws.ec2.get_metrics tags: - tag: component value: disk - uuid: d6bb726f9f1b4d5b889ede0ae2c73613 name: 'AWS EC2: Disk: Read, rate' type: DEPENDENT key: aws.ec2.disk.read_ops.rate delay: '0' history: 7d value_type: FLOAT units: Ops description: | Completed read operations from all instance store volumes available to the instance in a specified period of time. If there are no instance store volumes, either the value is 0 or the metric is not reported. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "DiskReadOps")].Values.first().first()' error_handler: DISCARD_VALUE - type: JAVASCRIPT parameters: - 'return value / 300;' master_item: key: aws.ec2.get_metrics tags: - tag: component value: disk - uuid: 95bcfd522147498688555e2cab5c00e2 name: 'AWS EC2: Disk: Write bytes, rate' type: DEPENDENT key: aws.ec2.disk_write_bytes.rate delay: '0' history: 7d value_type: FLOAT units: Bps description: | Bytes written to all instance store volumes available to the instance. This metric is used to determine the volume of the data the application writes onto the hard disk of the instance. This can be used to determine the speed of the application. If there are no instance store volumes, either the value is 0 or the metric is not reported. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "DiskWriteBytes")].Values.first().first()' error_handler: DISCARD_VALUE - type: JAVASCRIPT parameters: - 'return value / 300;' master_item: key: aws.ec2.get_metrics tags: - tag: component value: disk - uuid: 28496d5aa03742feb85ae000deb616d1 name: 'AWS EC2: Disk: Write ops, rate' type: DEPENDENT key: aws.ec2.disk_write_ops.rate delay: '0' history: 7d value_type: FLOAT units: Ops description: | Completed write operations to all instance store volumes available to the instance in a specified period of time. If there are no instance store volumes, either the value is 0 or the metric is not reported. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "DiskWriteOps")].Values.first().first()' error_handler: DISCARD_VALUE - type: JAVASCRIPT parameters: - 'return value / 300;' master_item: key: aws.ec2.get_metrics tags: - tag: component value: disk - uuid: 64180ec5dae84f588006bb1dd0ce6980 name: 'AWS EC2: EBS: Byte balance' type: DEPENDENT key: aws.ec2.ebs.byte_balance delay: '0' history: 7d value_type: FLOAT units: '%' description: 'Percentage of throughput credits remaining in the burst bucket for Nitro-based instances.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "EBSByteBalance%")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: aws.ec2.get_metrics tags: - tag: component value: ebs triggers: - uuid: 27f3b00e295d4aeb9a2d0519e95da4e0 expression: 'max(/AWS EC2 by HTTP/aws.ec2.ebs.byte_balance,5m)<{$AWS.EBS.BYTE.CREDIT.BALANCE.MIN.WARN}' name: 'AWS EC2: Byte Credit balance is too low' event_name: 'AWS EC2: Byte Credit balance is too low (less {$AWS.EBS.BYTE.CREDIT.BALANCE.MIN.WARN}% for 5m)' opdata: 'Current value: {ITEM.LASTVALUE1}' priority: WARNING tags: - tag: scope value: capacity - uuid: 7b8a2b6941d04cde8edc511752755c8f name: 'AWS EC2: EBS: IO balance' type: DEPENDENT key: aws.ec2.ebs.io_balance delay: '0' history: 7d value_type: FLOAT units: '%' description: 'Percentage of I/O credits remaining in the burst bucket for Nitro-based instances.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "EBSIOBalance%")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: aws.ec2.get_metrics tags: - tag: component value: ebs triggers: - uuid: f4b9c2238b5443eab31255422bc22d7d expression: 'max(/AWS EC2 by HTTP/aws.ec2.ebs.io_balance,5m)<{$AWS.EBS.IO.CREDIT.BALANCE.MIN.WARN}' name: 'AWS EC2: I/O Credit balance is too low' event_name: 'AWS EC2: I/O Credit balance is too low (less {$AWS.EBS.IO.CREDIT.BALANCE.MIN.WARN}% for 5m)' opdata: 'Current value: {ITEM.LASTVALUE1}' priority: WARNING tags: - tag: scope value: capacity - uuid: 251c9a3b0afd4930b822f7310f3fda43 name: 'AWS EC2: EBS: Read bytes, rate' type: DEPENDENT key: aws.ec2.ebs.read_bytes.rate delay: '0' history: 7d value_type: FLOAT units: Bps description: 'Bytes read from all EBS volumes attached to the instance for Nitro-based instances.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "EBSReadBytes")].Values.first().first()' error_handler: DISCARD_VALUE - type: JAVASCRIPT parameters: - 'return value / 300;' master_item: key: aws.ec2.get_metrics tags: - tag: component value: ebs - uuid: 29eff02b7c464605bc6d69a963d232b5 name: 'AWS EC2: EBS: Read, rate' type: DEPENDENT key: aws.ec2.ebs.read_ops.rate delay: '0' history: 7d value_type: FLOAT units: Ops description: 'Completed read operations from all Amazon EBS volumes attached to the instance for Nitro-based instances.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "EBSReadOps")].Values.first().first()' error_handler: DISCARD_VALUE - type: JAVASCRIPT parameters: - 'return value / 300;' master_item: key: aws.ec2.get_metrics tags: - tag: component value: ebs - uuid: 9dafe0bcfb214d46975f570e2836e9cd name: 'AWS EC2: EBS: Write bytes, rate' type: DEPENDENT key: aws.ec2.ebs.write_bytes.rate delay: '0' history: 7d value_type: FLOAT units: Bps description: 'Bytes written to all EBS volumes attached to the instance for Nitro-based instances.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "EBSWriteBytes")].Values.first().first()' error_handler: DISCARD_VALUE - type: JAVASCRIPT parameters: - 'return value / 300;' master_item: key: aws.ec2.get_metrics tags: - tag: component value: ebs - uuid: 2da28e61261746d6b94b244b8f0cf2a8 name: 'AWS EC2: EBS: Write, rate' type: DEPENDENT key: aws.ec2.ebs.write_ops.rate delay: '0' history: 7d value_type: FLOAT description: 'Completed write operations to all EBS volumes attached to the instance in a specified period of time.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "EBSWriteOps")].Values.first().first()' error_handler: DISCARD_VALUE - type: JAVASCRIPT parameters: - 'return value / 300;' master_item: key: aws.ec2.get_metrics tags: - tag: component value: ebs - uuid: 4e0b2ed29500487092148b14245839d4 name: 'AWS CloudWatch: Get instance alarms data' type: SCRIPT key: aws.ec2.get_alarms delay: 0s;m/1 history: '0' trends: '0' value_type: TEXT params: | var AWS = { params: {}, metadata: 'http://169.254.169.254/latest/meta-data/iam/security-credentials', getField: function (data, path, val) { var steps = path.split('.'); for (var i = 0; i < steps.length; i++) { var step = steps[i]; if (typeof data !== 'object' || data === null || typeof data[step] === 'undefined') { if (typeof val === 'undefined') { throw 'Required field was not found: ' + path; } return val } data = data[step]; } return data; }, setParams: function (params) { AWS.params['proxy'] = params.proxy; switch (AWS.getField(params, 'auth_type')) { case 'role_base': AWS.params['auth_type'] = 'role_base'; var request = new HttpRequest(); if (typeof AWS.params.proxy !== 'undefined' && AWS.params.proxy !== '') { request.setProxy(AWS.params.proxy); } var IamRoleName = request.get(AWS.metadata); if (request.getStatus() !== 200 || IamRoleName === null || IamRoleName === '') { throw 'Error getting security credentials from instance metadata. Role not found.'; } credentials = request.get(AWS.metadata + '/' + encodeURI(IamRoleName)); if (request.getStatus() !== 200 || credentials === null || credentials === '') { throw 'Error getting security credentials from instance metadata.'; } try { credentials = JSON.parse(credentials); } catch (error) { throw 'Failed to parse response received from instance metadata. Check debug log for more information.'; } ['AccessKeyId', 'SecretAccessKey', 'Token'].forEach(function (field) { if (typeof credentials !== 'object' || typeof credentials[field] === 'undefined' || credentials[field] === '') { throw 'Required credentials is not set: "' + field + '".'; }; AWS.params[field] = credentials[field]; }); break; case 'assume_role': AWS.params['auth_type'] = 'assume_role'; ['AccessKeyId', 'SecretAccessKey', 'sts_region', 'role_arn'].forEach(function (field) { if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') { throw 'Required param is not set: "' + field + '".'; } AWS.params[field] = params[field]; }); role_arn_regex = /role\/(.+)$/; var payload = { 'Action': 'AssumeRole', 'Version': '2011-06-15', 'RoleArn': AWS.params.role_arn, 'RoleSessionName': AWS.params.role_arn.match(role_arn_regex)[1] + 'Session', }; credentials = AWS.getField(AWS.request('GET', AWS.params.sts_region, 'sts', AWS.prepareParams(payload), ''), 'AssumeRoleResponse.AssumeRoleResult.Credentials'); ['AccessKeyId', 'SecretAccessKey', 'SessionToken'].forEach(function (field) { if (typeof credentials !== 'object' || typeof credentials[field] === 'undefined' || credentials[field] === '') { throw 'Required credentials is not set: "' + field + '".'; }; AWS.params[field] = credentials[field]; }); break; default: AWS.params['auth_type'] = 'access_key'; ['AccessKeyId', 'SecretAccessKey'].forEach(function (field) { if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') { throw 'Required param is not set: "' + field + '".'; } AWS.params[field] = params[field]; }); } ['region', 'instance_id'].forEach(function (field) { if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') { throw 'Required param is not set: "' + field + '".'; } AWS.params[field] = params[field]; }); }, sign: function (key, message) { var hex = hmac('sha256', key, message); if ((hex.length % 2) === 1) { throw 'Invalid length of a hex string!'; } var result = new Int8Array(hex.length / 2); for (var i = 0, b = 0; i < hex.length; i += 2, b++) { result[b] = parseInt(hex.substring(i, i + 2), 16); } return result; }, prepareParams: function (params) { var result = []; Object.keys(params).sort().forEach(function (key) { if (typeof params[key] !== 'object') { result.push(key + '=' + encodeURIComponent(params[key])); } else { result.push(prepareObject(key, params[key])); } }); return result.join('&'); }, request: function (method, region, service, params, data) { if (typeof data === 'undefined' || data === null) { data = ''; } var amzdate = (new Date()).toISOString().replace(/\.\d+Z/, 'Z').replace(/[-:]/g, ''), date = amzdate.replace(/T\d+Z/, ''), host = service + '.' + region + '.amazonaws.com', canonical_uri = '/', canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n', signed_headers = 'content-encoding;host;x-amz-date', canonical_request = method + '\n' + canonical_uri + '\n' + params + '\n' + canonical_headers + '\n' + signed_headers + '\n' + sha256(data), credential_scope = date + '/' + region + '/' + service + '/' + 'aws4_request', request_string = 'AWS4-HMAC-SHA256' + '\n' + amzdate + '\n' + credential_scope + '\n' + sha256(canonical_request), key = AWS.sign('AWS4' + AWS.params.SecretAccessKey, date), key = AWS.sign(key, region), key = AWS.sign(key, service), key = AWS.sign(key, 'aws4_request'), request = new HttpRequest(), url = 'https://' + host + canonical_uri + '?' + params; if (typeof AWS.params.proxy !== 'undefined' && AWS.params.proxy !== '') { request.setProxy(AWS.params.proxy); } request.addHeader('x-amz-date: ' + amzdate); request.addHeader('Accept: application/json'); request.addHeader('Content-Type: application/json'); request.addHeader('Content-Encoding: amz-1.0'); request.addHeader('Authorization: ' + 'AWS4-HMAC-SHA256 Credential=' + AWS.params.AccessKeyId + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + hmac('sha256', key, request_string)); if (AWS.params.auth_type === 'role_base' || (AWS.params.auth_type === 'assume_role' & !params.includes('AssumeRole'))) { request.addHeader('X-Amz-Security-Token: ' + (AWS.params.auth_type === 'role_base' ? AWS.params.Token : AWS.params.SessionToken)); } Zabbix.log(4, '[ AWS EC2 ] Sending request: ' + url); response = request.get(url); Zabbix.log(4, '[ AWS EC2 ] Received response with status code ' + request.getStatus() + ': ' + response); if (request.getStatus() !== 200) { throw 'Request failed with status code ' + request.getStatus() + ': ' + response; } try { response = JSON.parse(response); } catch (error) { try { response = JSON.parse(XML.toJson(response)); } catch (error) { throw 'Failed to parse response received from AWS CloudWatch API. Check debug log for more information.'; } } return response; }, getVolumes: function () { var payload = { 'Action': 'DescribeVolumes', 'Version': '2016-11-15', 'MaxResults': 100, 'Filter.1.Name': 'attachment.instance-id', 'Filter.1.Value': AWS.params.instance_id }, value = [], volumes = [], volumes_list = []; while (payload.NextToken !== '') { var result = AWS.getField(AWS.request('GET', AWS.params.region, 'ec2', AWS.prepareParams(payload)), 'DescribeVolumesResponse'); payload.NextToken = result.nextToken || ''; volumes = AWS.getField(result, 'volumeSet.item', value); volumes_list.push(Array.isArray(volumes) ? volumes : [volumes]) } var flattenedData = volumes_list.reduce(function (acc, val) { return acc.concat(val); }, []); return flattenedData; }, getAlarms: function () { var payload = { 'Action': 'DescribeAlarms', 'Version': '2010-08-01', 'MaxRecords': 100 }, result = [], volumes = AWS.getVolumes() while (payload.NextToken !== '') { var alarms = AWS.getField(AWS.request('GET', AWS.params.region, 'monitoring', AWS.prepareParams(payload)), 'DescribeAlarmsResponse.DescribeAlarmsResult'); payload.NextToken = alarms.NextToken || ''; alarms_list = AWS.getField(alarms, 'MetricAlarms'); if (!Array.isArray(alarms_list)) alarms_list = [alarms_list]; alarms_list.forEach(function (alarm) { var dimensions = alarm.Dimensions; if (Array.isArray(alarm.Metrics)) { alarm.Metrics.forEach(function (metric) { if (typeof metric.MetricStat === 'object' && metric.MetricStat !== null && typeof metric.MetricStat.Metric === 'object' && metric.MetricStat.Metric !== null && Array.isArray(metric.MetricStat.Metric.Dimensions)) { dimensions = dimensions.concat(metric.MetricStat.Metric.Dimensions); } }); } for (var i in dimensions) { if (dimensions[i].Name === 'InstanceId' && dimensions[i].Value === AWS.params.instance_id) { result.push(alarm); break; } if (dimensions[i].Name === 'VolumeId' && volumes.indexOf(dimensions[i].Value)) { result.push(alarm); break; } } }); } return result; } } try { AWS.setParams(JSON.parse(value)); return JSON.stringify(AWS.getAlarms()); } catch (error) { error += (String(error).endsWith('.')) ? '' : '.'; Zabbix.log(3, '[ AWS EC2 ] ERROR: ' + error); return JSON.stringify({ 'error': error }); } description: 'DescribeAlarms API method: https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_DescribeAlarms.html' preprocessing: - type: CHECK_NOT_SUPPORTED parameters: - '' timeout: 15s parameters: - name: AccessKeyId value: '{$AWS.ACCESS.KEY.ID}' - name: auth_type value: '{$AWS.AUTH_TYPE}' - name: instance_id value: '{$AWS.EC2.INSTANCE.ID}' - name: proxy value: '{$AWS.PROXY}' - name: region value: '{$AWS.REGION}' - name: role_arn value: '{$AWS.ASSUME.ROLE.ARN}' - name: SecretAccessKey value: '{$AWS.SECRET.ACCESS.KEY}' - name: sts_region value: '{$AWS.STS.REGION}' tags: - tag: component value: raw - uuid: 63ab011505f24885b843a9ac48b36a84 name: 'AWS EC2: Get metrics data' type: SCRIPT key: aws.ec2.get_metrics delay: 0s;m/5 history: '0' trends: '0' value_type: TEXT params: | var AWS = { params: {}, request_period: 600, metadata: 'http://169.254.169.254/latest/meta-data/iam/security-credentials', getField: function (data, path) { var steps = path.split('.'); for (var i = 0; i < steps.length; i++) { var step = steps[i]; if (typeof data !== 'object' || typeof data[step] === 'undefined') { throw 'Required field was not found: ' + path; } data = data[step]; } return data; }, setParams: function (params) { AWS.params['proxy'] = params.proxy; switch (AWS.getField(params, 'auth_type')) { case 'role_base': AWS.params['auth_type'] = 'role_base'; var request = new HttpRequest(); if (typeof AWS.params.proxy !== 'undefined' && AWS.params.proxy !== '') { request.setProxy(AWS.params.proxy); } var IamRoleName = request.get(AWS.metadata); if (request.getStatus() !== 200 || IamRoleName === null || IamRoleName === '') { throw 'Error getting security credentials from instance metadata. Role not found.'; } credentials = request.get(AWS.metadata + '/' + encodeURI(IamRoleName)); if (request.getStatus() !== 200 || credentials === null || credentials === '') { throw 'Error getting security credentials from instance metadata.'; } try { credentials = JSON.parse(credentials); } catch (error) { throw 'Failed to parse response received from instance metadata. Check debug log for more information.'; } ['AccessKeyId', 'SecretAccessKey', 'Token'].forEach(function (field) { if (typeof credentials !== 'object' || typeof credentials[field] === 'undefined' || credentials[field] === '') { throw 'Required credentials is not set: "' + field + '".'; }; AWS.params[field] = credentials[field]; }); break; case 'assume_role': AWS.params['auth_type'] = 'assume_role'; ['AccessKeyId', 'SecretAccessKey', 'sts_region', 'role_arn'].forEach(function (field) { if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') { throw 'Required param is not set: "' + field + '".'; } AWS.params[field] = params[field]; }); role_arn_regex = /role\/(.+)$/; var payload = { 'Action': 'AssumeRole', 'Version': '2011-06-15', 'RoleArn': AWS.params.role_arn, 'RoleSessionName': AWS.params.role_arn.match(role_arn_regex)[1] + 'Session', }; credentials = AWS.getField(AWS.request('GET', AWS.params.sts_region, 'sts', AWS.prepareParams(payload), ''), 'AssumeRoleResponse.AssumeRoleResult.Credentials'); ['AccessKeyId', 'SecretAccessKey', 'SessionToken'].forEach(function (field) { if (typeof credentials !== 'object' || typeof credentials[field] === 'undefined' || credentials[field] === '') { throw 'Required credentials is not set: "' + field + '".'; }; AWS.params[field] = credentials[field]; }); break; default: AWS.params['auth_type'] = 'access_key'; ['AccessKeyId', 'SecretAccessKey'].forEach(function (field) { if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') { throw 'Required param is not set: "' + field + '".'; } AWS.params[field] = params[field]; }); } ['region', 'instance_id'].forEach(function (field) { if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') { throw 'Required param is not set: "' + field + '".'; } AWS.params[field] = params[field]; }); }, sign: function (key, message) { var hex = hmac('sha256', key, message); if ((hex.length % 2) === 1) { throw 'Invalid length of a hex string!'; } var result = new Int8Array(hex.length / 2); for (var i = 0, b = 0; i < hex.length; i += 2, b++) { result[b] = parseInt(hex.substring(i, i + 2), 16); } return result; }, prepareRecursive: function (prefix, param) { var result = {}; if (typeof param === 'object') { if (Array.isArray(param)) { param.forEach(function (value, index) { var nested = AWS.prepareRecursive(prefix + '.member.' + (index + 1), value); Object.keys(nested).forEach(function (key) { result[key] = nested[key]; }); }); } else { Object.keys(param).forEach(function (k) { var nested = AWS.prepareRecursive(prefix + '.' + k, param[k]); Object.keys(nested).forEach(function (key) { result[key] = nested[key]; }); }); } } else { result[prefix] = param; } return result; }, renderPayload: function (period, instance_id) { var metrics_list = [ 'StatusCheckFailed:Count', 'StatusCheckFailed_Instance:Count', 'StatusCheckFailed_System:Count', 'CPUUtilization:Percent', 'NetworkIn:Bytes', 'NetworkOut:Bytes', 'NetworkPacketsIn:Count', 'NetworkPacketsOut:Count', 'DiskReadOps:Count', 'DiskWriteOps:Count', 'DiskReadBytes:Bytes', 'DiskWriteBytes:Bytes', 'MetadataNoToken:Count', 'CPUCreditUsage:Count', 'CPUCreditBalance:Count', 'CPUSurplusCreditBalance:Count', 'CPUSurplusCreditsCharged:Count', 'EBSReadOps:Count', 'EBSWriteOps:Count', 'EBSReadBytes:Bytes', 'EBSWriteBytes:Bytes', 'EBSIOBalance %:Percent', 'EBSByteBalance %:Percent' ]; var metric_payload = []; metrics_list.forEach(function (metric) { var parts = metric.split(':', 2); var name = parts[0].replace(/[^a-zA-Z0-9]/g, ''); metric_payload.push({ 'Id': name.charAt(0).toLowerCase() + name.slice(1), 'MetricStat': { 'Metric': { 'MetricName': parts[0], 'Namespace': 'AWS/EC2', 'Dimensions': [ { 'Name': 'InstanceId', 'Value': instance_id } ] }, 'Period': period, 'Stat': 'Average', 'Unit': parts[1] } }); }); return metric_payload; }, prepareParams: function (params) { var result = []; Object.keys(params).sort().forEach(function (key) { if (typeof params[key] !== 'object') { result.push(key + '=' + encodeURIComponent(params[key])); } else { result.push(prepareObject(key, params[key])); } }); return result.join('&'); }, request: function (method, region, service, params, data) { if (typeof data === 'undefined' || data === null) { data = ''; } var amzdate = (new Date()).toISOString().replace(/\.\d+Z/, 'Z').replace(/[-:]/g, ''), date = amzdate.replace(/T\d+Z/, ''), host = service + '.' + region + '.amazonaws.com', canonical_uri = '/', canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n', signed_headers = 'content-encoding;host;x-amz-date', canonical_request = method + '\n' + canonical_uri + '\n' + params + '\n' + canonical_headers + '\n' + signed_headers + '\n' + sha256(data), credential_scope = date + '/' + region + '/' + service + '/' + 'aws4_request', request_string = 'AWS4-HMAC-SHA256' + '\n' + amzdate + '\n' + credential_scope + '\n' + sha256(canonical_request), key = AWS.sign('AWS4' + AWS.params.SecretAccessKey, date), key = AWS.sign(key, region), key = AWS.sign(key, service), key = AWS.sign(key, 'aws4_request'), request = new HttpRequest(), url = 'https://' + host + canonical_uri + '?' + params; if (typeof AWS.params.proxy !== 'undefined' && AWS.params.proxy !== '') { request.setProxy(AWS.params.proxy); } request.addHeader('x-amz-date: ' + amzdate); request.addHeader('Accept: application/json'); request.addHeader('Content-Type: application/json'); request.addHeader('Content-Encoding: amz-1.0'); request.addHeader('Authorization: ' + 'AWS4-HMAC-SHA256 Credential=' + AWS.params.AccessKeyId + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + hmac('sha256', key, request_string)); if (AWS.params.auth_type === 'role_base' || (AWS.params.auth_type === 'assume_role' & !params.includes('AssumeRole'))) { request.addHeader('X-Amz-Security-Token: ' + (AWS.params.auth_type === 'role_base' ? AWS.params.Token : AWS.params.SessionToken)); } Zabbix.log(4, '[ AWS EC2 ] Sending request: ' + url); response = request.get(url); Zabbix.log(4, '[ AWS EC2 ] Received response with status code ' + request.getStatus() + ': ' + response); if (request.getStatus() !== 200) { throw 'Request failed with status code ' + request.getStatus() + ': ' + response; } try { response = JSON.parse(response); } catch (error) { try { response = JSON.parse(XML.toJson(response)); } catch (error) { throw 'Failed to parse response received from AWS CloudWatch API. Check debug log for more information.'; } } return response; }, getMetricsData: function () { var timestamp = new Date().getTime(), end_time = new Date(timestamp).toISOString().replace(/\.\d+Z/, 'Z'), start_time = new Date(timestamp - AWS.request_period * 1000).toISOString().replace(/\.\d+Z/, 'Z'), payload = AWS.prepareRecursive('MetricDataQueries', AWS.renderPayload(AWS.request_period, AWS.params.instance_id)); payload['Action'] = 'GetMetricData'; payload['Version'] = '2010-08-01'; payload['StartTime'] = start_time; payload['EndTime'] = end_time; payload['ScanBy'] = 'TimestampDescending'; result = AWS.request('GET', AWS.params.region, 'monitoring', AWS.prepareParams(payload)); if (typeof result !== 'object' || typeof result.GetMetricDataResponse !== 'object' || typeof result.GetMetricDataResponse.GetMetricDataResult !== 'object' || typeof result.GetMetricDataResponse.GetMetricDataResult.MetricDataResults !== 'object') { throw 'Cannot get metrics data from AWS CloudWatch API. Check debug log for more information.'; } return result.GetMetricDataResponse.GetMetricDataResult.MetricDataResults; } }; try { AWS.setParams(JSON.parse(value)); return JSON.stringify(AWS.getMetricsData()); } catch (error) { error += (String(error).endsWith('.')) ? '' : '.'; Zabbix.log(3, '[ AWS EC2 ] ERROR: ' + error); return JSON.stringify({ 'error': error }); } description: | Get instance metrics. Full metrics list related to EC2: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/viewing_metrics_with_cloudwatch.html preprocessing: - type: CHECK_NOT_SUPPORTED parameters: - '' timeout: 15s parameters: - name: AccessKeyId value: '{$AWS.ACCESS.KEY.ID}' - name: auth_type value: '{$AWS.AUTH_TYPE}' - name: instance_id value: '{$AWS.EC2.INSTANCE.ID}' - name: proxy value: '{$AWS.PROXY}' - name: region value: '{$AWS.REGION}' - name: role_arn value: '{$AWS.ASSUME.ROLE.ARN}' - name: SecretAccessKey value: '{$AWS.SECRET.ACCESS.KEY}' - name: sts_region value: '{$AWS.STS.REGION}' tags: - tag: component value: raw - uuid: 9ec4650b564c41bca9893eca279a8cc7 name: 'AWS EBS: Get volumes data' type: SCRIPT key: aws.ec2.get_volumes delay: 5m history: '0' trends: '0' value_type: TEXT params: | var AWS = { params: {}, request_period: 600, metadata: 'http://169.254.169.254/latest/meta-data/iam/security-credentials', getField: function (data, path, val) { var steps = path.split('.'); for (var i = 0; i < steps.length; i++) { var step = steps[i]; if (typeof data !== 'object' || data === null || typeof data[step] === 'undefined') { if (typeof val === 'undefined') { throw 'Required field was not found: ' + path; } return val } data = data[step]; } return data; }, setParams: function (params) { AWS.params['proxy'] = params.proxy; switch (AWS.getField(params, 'auth_type')) { case 'role_base': AWS.params['auth_type'] = 'role_base'; var request = new HttpRequest(); if (typeof AWS.params.proxy !== 'undefined' && AWS.params.proxy !== '') { request.setProxy(AWS.params.proxy); } var IamRoleName = request.get(AWS.metadata); if (request.getStatus() !== 200 || IamRoleName === null || IamRoleName === '') { throw 'Error getting security credentials from instance metadata. Role not found.'; } credentials = request.get(AWS.metadata + '/' + encodeURI(IamRoleName)); if (request.getStatus() !== 200 || credentials === null || credentials === '') { throw 'Error getting security credentials from instance metadata.'; } try { credentials = JSON.parse(credentials); } catch (error) { throw 'Failed to parse response received from instance metadata. Check debug log for more information.'; } ['AccessKeyId', 'SecretAccessKey', 'Token'].forEach(function (field) { if (typeof credentials !== 'object' || typeof credentials[field] === 'undefined' || credentials[field] === '') { throw 'Required credentials is not set: "' + field + '".'; }; AWS.params[field] = credentials[field]; }); break; case 'assume_role': AWS.params['auth_type'] = 'assume_role'; ['AccessKeyId', 'SecretAccessKey', 'sts_region', 'role_arn'].forEach(function (field) { if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') { throw 'Required param is not set: "' + field + '".'; } AWS.params[field] = params[field]; }); role_arn_regex = /role\/(.+)$/; var payload = { 'Action': 'AssumeRole', 'Version': '2011-06-15', 'RoleArn': AWS.params.role_arn, 'RoleSessionName': AWS.params.role_arn.match(role_arn_regex)[1] + 'Session', }; credentials = AWS.getField(AWS.request('GET', AWS.params.sts_region, 'sts', AWS.prepareParams(payload), ''), 'AssumeRoleResponse.AssumeRoleResult.Credentials'); ['AccessKeyId', 'SecretAccessKey', 'SessionToken'].forEach(function (field) { if (typeof credentials !== 'object' || typeof credentials[field] === 'undefined' || credentials[field] === '') { throw 'Required credentials is not set: "' + field + '".'; }; AWS.params[field] = credentials[field]; }); break; default: AWS.params['auth_type'] = 'access_key'; ['AccessKeyId', 'SecretAccessKey'].forEach(function (field) { if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') { throw 'Required param is not set: "' + field + '".'; } AWS.params[field] = params[field]; }); } ['region', 'instance_id'].forEach(function (field) { if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') { throw 'Required param is not set: "' + field + '".'; } AWS.params[field] = params[field]; }); }, sign: function (key, message) { var hex = hmac('sha256', key, message); if ((hex.length % 2) === 1) { throw 'Invalid length of a hex string!'; } var result = new Int8Array(hex.length / 2); for (var i = 0, b = 0; i < hex.length; i += 2, b++) { result[b] = parseInt(hex.substring(i, i + 2), 16); } return result; }, prepareParams: function (params) { var result = []; Object.keys(params).sort().forEach(function (key) { if (typeof params[key] !== 'object') { result.push(key + '=' + encodeURIComponent(params[key])); } else { result.push(prepareObject(key, params[key])); } }); return result.join('&'); }, request: function (method, region, service, params, data) { if (typeof data === 'undefined' || data === null) { data = ''; } var amzdate = (new Date()).toISOString().replace(/\.\d+Z/, 'Z').replace(/[-:]/g, ''), date = amzdate.replace(/T\d+Z/, ''), host = service + '.' + region + '.amazonaws.com', canonical_uri = '/', canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n', signed_headers = 'content-encoding;host;x-amz-date', canonical_request = method + '\n' + canonical_uri + '\n' + params + '\n' + canonical_headers + '\n' + signed_headers + '\n' + sha256(data), credential_scope = date + '/' + region + '/' + service + '/' + 'aws4_request', request_string = 'AWS4-HMAC-SHA256' + '\n' + amzdate + '\n' + credential_scope + '\n' + sha256(canonical_request), key = AWS.sign('AWS4' + AWS.params.SecretAccessKey, date), key = AWS.sign(key, region), key = AWS.sign(key, service), key = AWS.sign(key, 'aws4_request'), request = new HttpRequest(), url = 'https://' + host + canonical_uri + '?' + params; if (typeof AWS.params.proxy !== 'undefined' && AWS.params.proxy !== '') { request.setProxy(AWS.params.proxy); } request.addHeader('x-amz-date: ' + amzdate); request.addHeader('Accept: application/json'); request.addHeader('Content-Type: application/json'); request.addHeader('Content-Encoding: amz-1.0'); request.addHeader('Authorization: ' + 'AWS4-HMAC-SHA256 Credential=' + AWS.params.AccessKeyId + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + hmac('sha256', key, request_string)); if (AWS.params.auth_type === 'role_base' || (AWS.params.auth_type === 'assume_role' & !params.includes('AssumeRole'))) { request.addHeader('X-Amz-Security-Token: ' + (AWS.params.auth_type === 'role_base' ? AWS.params.Token : AWS.params.SessionToken)); } Zabbix.log(4, '[ AWS EBS ] Sending request: ' + url); response = request.get(url); Zabbix.log(4, '[ AWS EBS ] Received response with status code ' + request.getStatus() + ': ' + response); if (request.getStatus() !== 200) { throw 'Request failed with status code ' + request.getStatus() + ': ' + response; } try { response = JSON.parse(response); } catch (error) { try { response = JSON.parse(XML.toJson(response)); } catch (error) { throw 'Failed to parse response received from AWS CloudWatch API. Check debug log for more information.'; } } return response; }, getVolumesData: function () { var payload = { 'Action': 'DescribeVolumes', 'Version': '2016-11-15', 'Filter.1.Name': 'attachment.instance-id', 'Filter.1.Value': AWS.params.instance_id, 'MaxResults': 100 }, value = [], volumes_list = []; while (payload.NextToken !== '') { var result = AWS.getField(AWS.request('GET', AWS.params.region, 'ec2', AWS.prepareParams(payload)), 'DescribeVolumesResponse'), volumes_set = AWS.getField(result, 'volumeSet'), volumes = AWS.getField(volumes_set, 'item', value); volumes_list.push(Array.isArray(volumes) ? volumes : [volumes]); payload.NextToken = result.nextToken || ''; } var flattenedData = volumes_list.reduce(function (acc, val) { return acc.concat(val); }, []); return flattenedData; } }; try { AWS.setParams(JSON.parse(value)); return JSON.stringify(AWS.getVolumesData()); } catch (error) { error += (String(error).endsWith('.')) ? '' : '.'; Zabbix.log(3, '[ AWS EBS ] ERROR: ' + error); return JSON.stringify({ 'error': error }); } description: | Get volumes attached to instance. DescribeVolumes API method: https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVolumes.html preprocessing: - type: CHECK_NOT_SUPPORTED parameters: - '' timeout: 15s parameters: - name: AccessKeyId value: '{$AWS.ACCESS.KEY.ID}' - name: auth_type value: '{$AWS.AUTH_TYPE}' - name: instance_id value: '{$AWS.EC2.INSTANCE.ID}' - name: proxy value: '{$AWS.PROXY}' - name: region value: '{$AWS.REGION}' - name: role_arn value: '{$AWS.ASSUME.ROLE.ARN}' - name: SecretAccessKey value: '{$AWS.SECRET.ACCESS.KEY}' - name: sts_region value: '{$AWS.STS.REGION}' tags: - tag: component value: raw - uuid: adbe9cd98ffa41dda981c7f4e27a0d3b name: 'AWS EC2: Metadata: No token' type: DEPENDENT key: aws.ec2.metadata.no_token delay: '0' history: 7d value_type: FLOAT description: | The number of times the instance metadata service was successfully accessed using a method that does not use a token. This metric is used to determine if there are any processes accessing instance metadata that are using Instance Metadata Service Version 1, which does not use a token. If all requests use token-backed sessions, i.e., Instance Metadata Service Version 2, the value is 0. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "MetadataNoToken")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: aws.ec2.get_metrics tags: - tag: component value: metadata - uuid: 7c264d8d5d934f898f7c745acd429d25 name: 'AWS EC2: Get metrics check' type: DEPENDENT key: aws.ec2.metrics.check delay: '0' history: 7d trends: '0' value_type: CHAR description: 'Check result of the instance metric data has been got correctly.' preprocessing: - type: JSONPATH parameters: - $.error error_handler: CUSTOM_VALUE - type: DISCARD_UNCHANGED_HEARTBEAT parameters: - 3h master_item: key: aws.ec2.get_metrics tags: - tag: component value: status triggers: - uuid: c2cf3f875aa14416a108dd05df7b053a expression: 'length(last(/AWS EC2 by HTTP/aws.ec2.metrics.check))>0' name: 'AWS EC2: Failed to get metrics data' priority: WARNING description: 'Failed to get CloudWatch metrics for EC2.' tags: - tag: scope value: availability - uuid: 2b16d3c6457842d892d06249a5fcd670 name: 'AWS EC2: Network: Bytes in, rate' type: DEPENDENT key: aws.ec2.network_in.rate delay: '0' history: 7d value_type: FLOAT units: Bps description: | The number of bytes received on all network interfaces by the instance. This metric identifies the volume of incoming network traffic to a single instance. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "NetworkIn")].Values.first().first()' error_handler: DISCARD_VALUE - type: JAVASCRIPT parameters: - 'return value / 300;' master_item: key: aws.ec2.get_metrics tags: - tag: component value: network - uuid: 87fb8b61f115487696f02e50d98996ac name: 'AWS EC2: Network: Bytes out, rate' type: DEPENDENT key: aws.ec2.network_out.rate delay: '0' history: 7d value_type: FLOAT units: Bps description: | The number of bytes sent out on all network interfaces by the instance. This metric identifies the volume of outgoing network traffic from a single instance. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "NetworkOut")].Values.first().first()' - type: JAVASCRIPT parameters: - 'return value / 300;' master_item: key: aws.ec2.get_metrics tags: - tag: component value: network - uuid: a6b74493528b486782c4b73e080019e1 name: 'AWS EC2: Network: Packets in, rate' type: DEPENDENT key: aws.ec2.packets_in.rate delay: '0' history: 7d value_type: FLOAT description: | The number of packets received on all network interfaces by the instance. This metric identifies the volume of incoming traffic in terms of the number of packets on a single instance. This metric is available for basic monitoring only. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "NetworkPacketsIn")].Values.first().first()' error_handler: DISCARD_VALUE - type: JAVASCRIPT parameters: - 'return value / 300;' master_item: key: aws.ec2.get_metrics tags: - tag: component value: network - uuid: 5d998e1680af4410b34fa9071bb7db78 name: 'AWS EC2: Network: Packets out, rate' type: DEPENDENT key: aws.ec2.packets_out.rate delay: '0' history: 7d value_type: FLOAT description: | The number of packets sent out on all network interfaces by the instance. This metric identifies the volume of outgoing traffic in terms of the number of packets on a single instance. This metric is available for basic monitoring only. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "NetworkPacketsOut")].Values.first().first()' error_handler: DISCARD_VALUE - type: JAVASCRIPT parameters: - 'return value / 300;' master_item: key: aws.ec2.get_metrics tags: - tag: component value: network - uuid: 30156f76599147eaa5bcd4ca39816bbb name: 'AWS EC2: Status: Check failed' type: DEPENDENT key: aws.ec2.status_check_failed delay: '0' history: 7d description: | Reports whether the instance has passed both the instance status check and the system status check in the last minute. This metric can be either 0 (passed) or 1 (failed). valuemap: name: 'Status check' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "StatusCheckFailed")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: aws.ec2.get_metrics tags: - tag: component value: instance - uuid: b373f0994e784caf8f5f39da20d2f5c8 name: 'AWS EC2: Status: Check failed, instance' type: DEPENDENT key: aws.ec2.status_check_failed_instance delay: '0' history: 7d description: | Reports whether the instance has passed the instance status check in the last minute. This metric can be either 0 (passed) or 1 (failed). valuemap: name: 'Status check' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "StatusCheckFailed_Instance")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: aws.ec2.get_metrics tags: - tag: component value: instance triggers: - uuid: 0fdd6b02eea948d3a6c958af7f195dc3 expression: 'last(/AWS EC2 by HTTP/aws.ec2.status_check_failed_instance)=1' name: 'AWS EC2: Instance status check failed' priority: AVERAGE description: | These checks detect problems that require your involvement to repair. The following are examples of problems that can cause instance status checks to fail: Failed system status checks Incorrect networking or startup configuration Exhausted memory Corrupted file system Incompatible kernel tags: - tag: scope value: availability - uuid: c7063824e3a74e6fa55ba21ecba35ca1 name: 'AWS EC2: Status: Check failed, system' type: DEPENDENT key: aws.ec2.status_check_failed_system delay: '0' history: 7d description: | Reports whether the instance has passed the system status check in the last minute. This metric can be either 0 (passed) or 1 (failed). valuemap: name: 'Status check' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "StatusCheckFailed_System")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: aws.ec2.get_metrics tags: - tag: component value: instance triggers: - uuid: 723a254ffd72404ea0cc2366ff186c1c expression: 'last(/AWS EC2 by HTTP/aws.ec2.status_check_failed_system)=1' name: 'AWS EC2: System status check failed' priority: AVERAGE description: | These checks detect underlying problems with your instance that require AWS involvement to repair. The following are examples of problems that can cause system status checks to fail: Loss of network connectivity Loss of system power Software issues on the physical host Hardware issues on the physical host that impact network reachability tags: - tag: scope value: availability - uuid: 3c819ed899c044ae8455266292f65632 name: 'AWS EC2: Get volumes info check' type: DEPENDENT key: aws.ec2.volumes.check delay: '0' history: 7d trends: '0' value_type: CHAR description: 'Check result of the volume information has been got correctly.' preprocessing: - type: JSONPATH parameters: - $.error error_handler: CUSTOM_VALUE - type: DISCARD_UNCHANGED_HEARTBEAT parameters: - 3h master_item: key: aws.ec2.get_volumes tags: - tag: component value: status triggers: - uuid: 844fb22685804fe7894af7c64b420824 expression: 'length(last(/AWS EC2 by HTTP/aws.ec2.volumes.check))>0' name: 'AWS EC2: Failed to get volumes info' priority: WARNING description: 'Failed to get CloudWatch volumes for EC2.' tags: - tag: scope value: availability discovery_rules: - uuid: 318c50196d2b442e9b702f63e70c0820 name: 'Instance Alarms discovery' type: DEPENDENT key: aws.ec2.alarms.discovery delay: '0' filter: evaltype: AND conditions: - macro: '{#ALARM_NAME}' value: '{$AWS.EC2.LLD.FILTER.ALARM_NAME.MATCHES}' formulaid: A - macro: '{#ALARM_NAME}' value: '{$AWS.EC2.LLD.FILTER.ALARM_NAME.NOT_MATCHES}' operator: NOT_MATCHES_REGEX formulaid: B - macro: '{#ALARM_SERVICE_NAMESPACE}' value: '{$AWS.EC2.LLD.FILTER.ALARM_SERVICE_NAMESPACE.MATCHES}' formulaid: C - macro: '{#ALARM_SERVICE_NAMESPACE}' value: '{$AWS.EC2.LLD.FILTER.ALARM_SERVICE_NAMESPACE.NOT_MATCHES}' operator: NOT_MATCHES_REGEX formulaid: D description: 'Discovery instance and attached EBS volumes alarms.' item_prototypes: - uuid: 6294e05dc170431bb3af2caf1ccf6d40 name: 'AWS EC2 Alarms: [{#ALARM_NAME}]: Get metrics' type: DEPENDENT key: 'aws.ec2.alarm.get_metrics["{#ALARM_NAME}"]' delay: '0' history: '0' trends: '0' value_type: TEXT description: 'Get alarm metrics about the state and its reason.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.AlarmName == "{#ALARM_NAME}")].first()' error_handler: DISCARD_VALUE master_item: key: aws.ec2.get_alarms tags: - tag: component value: raw - uuid: 87a163166aed40b786785b64122ab365 name: 'AWS EC2 Alarms: [{#ALARM_NAME}]: State' type: DEPENDENT key: 'aws.ec2.alarm.state["{#ALARM_NAME}"]' delay: '0' history: 7d description: | The state value for the alarm. Possible values: 0 (OK), 1 (INSUFFICIENT_DATA), 2 (ALARM). Alarm description: {#ALARM_DESCRIPTION} valuemap: name: 'Alarm state' preprocessing: - type: JSONPATH parameters: - $.StateValue error_handler: CUSTOM_VALUE error_handler_params: '3' - type: JAVASCRIPT parameters: - | var state = ['OK', 'INSUFFICIENT_DATA', 'ALARM']; return state.indexOf(value.trim()) === -1 ? 255 : state.indexOf(value.trim()); master_item: key: 'aws.ec2.alarm.get_metrics["{#ALARM_NAME}"]' tags: - tag: component value: alarms trigger_prototypes: - uuid: be1301d97b5a47cc81dd6c2b76349f5d expression: 'last(/AWS EC2 by HTTP/aws.ec2.alarm.state["{#ALARM_NAME}"])=1' name: 'AWS EC2 Alarms: [{#ALARM_NAME}] has ''Insufficient data'' state' priority: INFO description: 'Either the alarm has just started, the metric is not available, or not enough data is available for the metric to determine the alarm state.' tags: - tag: scope value: notice - uuid: 92a33b49f010464db7e6c7ef586240e9 name: 'AWS EC2 Alarms: [{#ALARM_NAME}]: State reason' type: DEPENDENT key: 'aws.ec2.alarm.state_reason["{#ALARM_NAME}"]' delay: '0' history: 7d trends: '0' value_type: TEXT description: | An explanation for the alarm state, in text format. Alarm description: {#ALARM_DESCRIPTION} preprocessing: - type: JSONPATH parameters: - $.StateReason error_handler: DISCARD_VALUE - type: DISCARD_UNCHANGED_HEARTBEAT parameters: - 3h master_item: key: 'aws.ec2.alarm.get_metrics["{#ALARM_NAME}"]' tags: - tag: component value: alarms trigger_prototypes: - uuid: 93813bd6aaf14fcb84068cb2c2e5d47e expression: 'last(/AWS EC2 by HTTP/aws.ec2.alarm.state["{#ALARM_NAME}"])=2 and length(last(/AWS EC2 by HTTP/aws.ec2.alarm.state_reason["{#ALARM_NAME}"]))>0' name: 'AWS EC2 Alarms: [{#ALARM_NAME}] has ''Alarm'' state' priority: AVERAGE description: | Alarm "{#ALARM_NAME}" has 'Alarm' state. Reason: {ITEM.LASTVALUE2} tags: - tag: scope value: availability master_item: key: aws.ec2.get_alarms preprocessing: - type: JAVASCRIPT parameters: - | var result = []; var alarms = JSON.parse(value); alarms.forEach(function(alarm) { result.push({ '{#ALARM_DESCRIPTION}': alarm.AlarmDescription !== null ? alarm.AlarmDescription : 'None' , '{#ALARM_NAME}': alarm.AlarmName, '{#ALARM_PERIOD}': alarm.Period, '{#METRIC_NAME}': alarm.MetricName, '{#ALARM_SERVICE_NAMESPACE}': alarm.Namespace !== null ? alarm.Namespace : 'None' }); }); return JSON.stringify(result); - type: DISCARD_UNCHANGED_HEARTBEAT parameters: - 3h - uuid: 6cf7fc98fea44b0789a5aaa837042699 name: 'Instance Volumes discovery' type: DEPENDENT key: aws.ec2.volumes.discovery delay: '0' filter: evaltype: AND conditions: - macro: '{#VOLUME_TYPE}' value: '{$AWS.EC2.LLD.FILTER.VOLUME_TYPE.MATCHES}' formulaid: A - macro: '{#VOLUME_TYPE}' value: '{$AWS.EC2.LLD.FILTER.VOLUME_TYPE.NOT_MATCHES}' operator: NOT_MATCHES_REGEX formulaid: B description: 'Discovery attached EBS volumes.' item_prototypes: - uuid: cc0ece769d954bb590fb1a1a3d20e559 name: 'AWS EBS: [{#VOLUME_ID}]: Attachment state' type: DEPENDENT key: 'aws.ec2.ebs.attachment_status["{#VOLUME_ID}"]' delay: '0' history: 7d description: 'The attachment state of the volume. Possible values: 0 (attaching), 1 (attached), 2 (detaching).' valuemap: name: 'Volume attachment state' preprocessing: - type: JSONPATH parameters: - '$.attachmentSet..[?(@.instanceId == "{$AWS.EC2.INSTANCE.ID}")].status.first()' error_handler: DISCARD_VALUE - type: JAVASCRIPT parameters: - | var state = ['attaching', 'attached', 'detaching']; return state.indexOf(value.trim()) === -1 ? 255 : state.indexOf(value.trim()); - type: DISCARD_UNCHANGED_HEARTBEAT parameters: - 3h master_item: key: 'aws.ec2.ebs.get_volume["{#VOLUME_ID}"]' tags: - tag: component value: volumes - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' - uuid: 639e7ddcac6345239fa27549ad35e799 name: 'AWS EBS: [{#VOLUME_ID}]: Attachment time' type: DEPENDENT key: 'aws.ec2.ebs.attachment_time["{#VOLUME_ID}"]' delay: '0' history: 7d trends: '0' value_type: CHAR description: 'The time stamp when the attachment initiated.' valuemap: name: 'Volume attachment state' preprocessing: - type: JSONPATH parameters: - '$.attachmentSet..[?(@.instanceId == "{$AWS.EC2.INSTANCE.ID}")].attachTime.first()' error_handler: DISCARD_VALUE - type: DISCARD_UNCHANGED_HEARTBEAT parameters: - 3h master_item: key: 'aws.ec2.ebs.get_volume["{#VOLUME_ID}"]' tags: - tag: component value: volumes - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' - uuid: 2df96e6c726e40c6a257c00ae26e8902 name: 'AWS EBS: [{#VOLUME_ID}]: Create time' type: DEPENDENT key: 'aws.ec2.ebs.create_time["{#VOLUME_ID}"]' delay: '0' history: 7d trends: '0' value_type: CHAR description: 'The time stamp when volume creation was initiated.' preprocessing: - type: JSONPATH parameters: - $.createTime error_handler: DISCARD_VALUE - type: DISCARD_UNCHANGED_HEARTBEAT parameters: - 3h master_item: key: 'aws.ec2.ebs.get_volume["{#VOLUME_ID}"]' tags: - tag: component value: volumes - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' - uuid: 141205eac3e4437d824794f8e6c76e90 name: 'AWS EBS: [{#VOLUME_ID}]: Device' type: DEPENDENT key: 'aws.ec2.ebs.device["{#VOLUME_ID}"]' delay: '0' history: 7d trends: '0' value_type: CHAR description: 'The device name specified in the block device mapping (for example, /dev/sda1).' preprocessing: - type: JSONPATH parameters: - '$.attachmentSet..[?(@.instanceId == "{$AWS.EC2.INSTANCE.ID}")].device.first()' error_handler: DISCARD_VALUE - type: DISCARD_UNCHANGED_HEARTBEAT parameters: - 3h master_item: key: 'aws.ec2.ebs.get_volume["{#VOLUME_ID}"]' tags: - tag: component value: volumes - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' - uuid: 6145bf692ea0469eb5583485b6622a59 name: 'AWS EBS: [{#VOLUME_ID}]: Get volume data' type: DEPENDENT key: 'aws.ec2.ebs.get_volume["{#VOLUME_ID}"]' delay: '0' history: '0' trends: '0' value_type: TEXT description: 'Get data of the "{#VOLUME_ID}" volume.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.volumeId == "{#VOLUME_ID}")].first()' error_handler: DISCARD_VALUE master_item: key: aws.ec2.get_volumes tags: - tag: component value: raw - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' - uuid: 95add92252e24ab8b596c539d8090f3d name: 'AWS EBS: [{#VOLUME_ID}]: Status' type: DEPENDENT key: 'aws.ec2.ebs.status["{#VOLUME_ID}"]' delay: '0' history: 7d description: | The state of the volume. Possible values: 0 (creating), 1 (available), 2 (in-use), 3 (deleting), 4 (deleted), 5 (error). valuemap: name: 'Volume status' preprocessing: - type: JSONPATH parameters: - $.status error_handler: DISCARD_VALUE - type: JAVASCRIPT parameters: - | var state = ['creating', 'available', 'in-use', 'deleting', 'deleted', 'error']; return state.indexOf(value.trim()) === -1 ? 255 : state.indexOf(value.trim()); - type: DISCARD_UNCHANGED_HEARTBEAT parameters: - 3h master_item: key: 'aws.ec2.ebs.get_volume["{#VOLUME_ID}"]' tags: - tag: component value: volumes - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' trigger_prototypes: - uuid: 2d4de438bdaa49b2930496ce6ddbe52d expression: 'last(/AWS EC2 by HTTP/aws.ec2.ebs.status["{#VOLUME_ID}"])=5' name: 'AWS EBS: Volume [{#VOLUME_ID}] has ''error'' state' priority: WARNING tags: - tag: scope value: availability - uuid: fd10966f674e430a9dd70b148dcfa002 name: 'AWS EBS: [{#VOLUME_ID}]: Burst balance' type: DEPENDENT key: 'aws.ec2.ebs.volume.burst_balance["{#VOLUME_ID}"]' delay: '0' history: 7d value_type: FLOAT units: '%' description: | Used with General Purpose SSD (gp2), Throughput Optimized HDD (st1), and Cold HDD (sc1) volumes only. Provides information about the percentage of I/O credits (for gp2) or throughput credits (for st1 and sc1) remaining in the burst bucket. Data is reported to CloudWatch only when the volume is active. If the volume is not attached, no data is reported. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "BurstBalance")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.ec2.get_ebs_metrics["{#VOLUME_ID}"]' tags: - tag: component value: volumes - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' trigger_prototypes: - uuid: 9b2f5687020c4a5987c1b1b35a57d8b9 expression: 'max(/AWS EC2 by HTTP/aws.ec2.ebs.volume.burst_balance["{#VOLUME_ID}"],5m)<{$AWS.EBS.BURST.CREDIT.BALANCE.MIN.WARN}' name: 'AWS EBS: Burst balance is too low' event_name: 'AWS EBS: Burst balance is too low (less {$AWS.EBS.BURST.CREDIT.BALANCE.MIN.WARN}% for 5m)' opdata: 'Current value: {ITEM.LASTVALUE1}' priority: WARNING tags: - tag: scope value: capacity - uuid: 8b936cef38294799a6826764eae68850 name: 'AWS EBS: [{#VOLUME_ID}]: Consumed Read/Write, ops' type: DEPENDENT key: 'aws.ec2.ebs.volume.consumed_read_write_ops["{#VOLUME_ID}"]' delay: '0' history: 7d value_type: FLOAT description: | Used with Provisioned IOPS SSD volumes only. The total amount of read and write operations (normalized to 256K capacity units) consumed in a specified period of time. I/O operations that are smaller than 256K each count as 1 consumed IOPS. I/O operations that are larger than 256K are counted in 256K capacity units. For example, a 1024K I/O would count as 4 consumed IOPS. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "VolumeConsumedReadWriteOps")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.ec2.get_ebs_metrics["{#VOLUME_ID}"]' tags: - tag: component value: volumes - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' - uuid: 5476d32c036d49588238cb2d2a4d652f name: 'AWS EBS: [{#VOLUME_ID}]: Idle time' type: DEPENDENT key: 'aws.ec2.ebs.volume.idle_time["{#VOLUME_ID}"]' delay: '0' history: 7d value_type: FLOAT units: s description: | This metric is not supported with Multi-Attach enabled volumes. The total number of seconds in a specified period of time when no read or write operations were submitted. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "VolumeIdleTime")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.ec2.get_ebs_metrics["{#VOLUME_ID}"]' tags: - tag: component value: volumes - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' - uuid: 4dbb00e53cd84b9f88c44c765e73bd85 name: 'AWS EBS: [{#VOLUME_ID}]: Queue length' type: DEPENDENT key: 'aws.ec2.ebs.volume.queue_length["{#VOLUME_ID}"]' delay: '0' history: 7d value_type: FLOAT description: 'The number of read and write operation requests waiting to be completed in a specified period of time.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "VolumeQueueLength")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.ec2.get_ebs_metrics["{#VOLUME_ID}"]' tags: - tag: component value: volumes - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' - uuid: 7313a503be27469ea82733ed965b57e4 name: 'AWS EBS: [{#VOLUME_ID}]: Read, bytes' type: DEPENDENT key: 'aws.ec2.ebs.volume.read_bytes["{#VOLUME_ID}"]' delay: '0' history: 7d value_type: FLOAT units: Bps description: | Provides information on the read operations in a specified period of time. The average size of each read operation during the period, except on volumes attached to a Nitro-based instance, where the average represents the average over the specified period. For Xen instances, data is reported only when there is read activity on the volume. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "VolumeReadBytes")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.ec2.get_ebs_metrics["{#VOLUME_ID}"]' tags: - tag: component value: volumes - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' - uuid: 13d3dce70956402c945421c87e8eb784 name: 'AWS EBS: [{#VOLUME_ID}]: Read, ops' type: DEPENDENT key: 'aws.ec2.ebs.volume.read_ops["{#VOLUME_ID}"]' delay: '0' history: 7d value_type: FLOAT units: Ops description: 'The total number of read operations in a specified period of time. Note: read operations are counted on completion.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "VolumeReadOps")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.ec2.get_ebs_metrics["{#VOLUME_ID}"]' tags: - tag: component value: volumes - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' - uuid: 8d0b610ac0e3479a921720ef623ef896 name: 'AWS EBS: [{#VOLUME_ID}]: Throughput, pct' type: DEPENDENT key: 'aws.ec2.ebs.volume.throughput_percentage["{#VOLUME_ID}"]' delay: '0' history: 7d value_type: FLOAT units: '%' description: | This metric is not supported with Multi-Attach enabled volumes. Used with Provisioned IOPS SSD volumes only. The percentage of I/O operations per second (IOPS) delivered of the total IOPS provisioned for an Amazon EBS volume. Provisioned IOPS SSD volumes deliver their provisioned performance 99.9 percent of the time. During a write, if there are no other pending I/O requests in a minute, the metric value will be 100 percent. Also, a volume's I/O performance may become degraded temporarily due to an action you have taken (for example, creating a snapshot of a volume during peak usage, running the volume on a non-EBS-optimized instance, or accessing data on the volume for the first time). preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "VolumeThroughputPercentage")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.ec2.get_ebs_metrics["{#VOLUME_ID}"]' tags: - tag: component value: volumes - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' - uuid: 58163c98e1b943ceae5fcb52ff85dcfd name: 'AWS EBS: [{#VOLUME_ID}]: Read time, total' type: DEPENDENT key: 'aws.ec2.ebs.volume.total_read_time["{#VOLUME_ID}"]' delay: '0' history: 7d value_type: FLOAT units: s description: | This metric is not supported with Multi-Attach enabled volumes. The total number of seconds spent by all read operations that completed in a specified period of time. If multiple requests are submitted at the same time, this total could be greater than the length of the period. For example, for a period of 1 minutes (60 seconds): if 150 operations completed during that period, and each operation took 1 second, the value would be 150 seconds. For Xen instances, data is reported only when there is read activity on the volume. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "VolumeTotalReadTime")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.ec2.get_ebs_metrics["{#VOLUME_ID}"]' tags: - tag: component value: volumes - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' - uuid: 264a8f7df9e64d219082d5239b90cdf3 name: 'AWS EBS: [{#VOLUME_ID}]: Write time, total' type: DEPENDENT key: 'aws.ec2.ebs.volume.total_write_time["{#VOLUME_ID}"]' delay: '0' history: 7d value_type: FLOAT units: s description: | This metric is not supported with Multi-Attach enabled volumes. The total number of seconds spent by all write operations that completed in a specified period of time. If multiple requests are submitted at the same time, this total could be greater than the length of the period. For example, for a period of 1 minute (60 seconds): if 150 operations completed during that period, and each operation took 1 second, the value would be 150 seconds. For Xen instances, data is reported only when there is write activity on the volume. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "VolumeTotalWriteTime")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.ec2.get_ebs_metrics["{#VOLUME_ID}"]' tags: - tag: component value: volumes - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' - uuid: 459900740e784ca9ba7a8baf5b95734e name: 'AWS EBS: [{#VOLUME_ID}]: Write, bytes' type: DEPENDENT key: 'aws.ec2.ebs.volume.write_bytes["{#VOLUME_ID}"]' delay: '0' history: 7d value_type: FLOAT units: Bps description: | Provides information on the write operations in a specified period of time. The average size of each write operation during the period, except on volumes attached to a Nitro-based instance, where the average represents the average over the specified period. For Xen instances, data is reported only when there is write activity on the volume. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "VolumeWriteBytes")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.ec2.get_ebs_metrics["{#VOLUME_ID}"]' tags: - tag: component value: volumes - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' - uuid: 7216494987dc45f59fc3a4b9100e4159 name: 'AWS EBS: [{#VOLUME_ID}]: Write, ops' type: DEPENDENT key: 'aws.ec2.ebs.volume.write_ops["{#VOLUME_ID}"]' delay: '0' history: 7d value_type: FLOAT units: Ops description: 'The total number of write operations in a specified period of time. Note: write operations are counted on completion.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "VolumeWriteOps")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.ec2.get_ebs_metrics["{#VOLUME_ID}"]' tags: - tag: component value: volumes - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' - uuid: 8b3b008f7f65408fbd49e46186b01cfb name: 'AWS EBS: [{#VOLUME_ID}]: Get metrics' type: SCRIPT key: 'aws.ec2.get_ebs_metrics["{#VOLUME_ID}"]' delay: 0s;m/5 history: '0' trends: '0' value_type: TEXT params: | var AWS = { params: {}, request_period: 600, metadata: 'http://169.254.169.254/latest/meta-data/iam/security-credentials', getField: function (data, path) { var steps = path.split('.'); for (var i = 0; i < steps.length; i++) { var step = steps[i]; if (typeof data !== 'object' || typeof data[step] === 'undefined') { throw 'Required field was not found: ' + path; } data = data[step]; } return data; }, setParams: function (params) { AWS.params['proxy'] = params.proxy; switch (AWS.getField(params, 'auth_type')) { case 'role_base': AWS.params['auth_type'] = 'role_base'; var request = new HttpRequest(); if (typeof AWS.params.proxy !== 'undefined' && AWS.params.proxy !== '') { request.setProxy(AWS.params.proxy); } var IamRoleName = request.get(AWS.metadata); if (request.getStatus() !== 200 || IamRoleName === null || IamRoleName === '') { throw 'Error getting security credentials from instance metadata. Role not found.'; } credentials = request.get(AWS.metadata + '/' + encodeURI(IamRoleName)); if (request.getStatus() !== 200 || credentials === null || credentials === '') { throw 'Error getting security credentials from instance metadata.'; } try { credentials = JSON.parse(credentials); } catch (error) { throw 'Failed to parse response received from instance metadata. Check debug log for more information.'; } ['AccessKeyId', 'SecretAccessKey', 'Token'].forEach(function (field) { if (typeof credentials !== 'object' || typeof credentials[field] === 'undefined' || credentials[field] === '') { throw 'Required credentials is not set: "' + field + '".'; }; AWS.params[field] = credentials[field]; }); break; case 'assume_role': AWS.params['auth_type'] = 'assume_role'; ['AccessKeyId', 'SecretAccessKey', 'sts_region', 'role_arn'].forEach(function (field) { if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') { throw 'Required param is not set: "' + field + '".'; } AWS.params[field] = params[field]; }); role_arn_regex = /role\/(.+)$/; var payload = { 'Action': 'AssumeRole', 'Version': '2011-06-15', 'RoleArn': AWS.params.role_arn, 'RoleSessionName': AWS.params.role_arn.match(role_arn_regex)[1] + 'Session', }; credentials = AWS.getField(AWS.request('GET', AWS.params.sts_region, 'sts', AWS.prepareParams(payload), ''), 'AssumeRoleResponse.AssumeRoleResult.Credentials'); ['AccessKeyId', 'SecretAccessKey', 'SessionToken'].forEach(function (field) { if (typeof credentials !== 'object' || typeof credentials[field] === 'undefined' || credentials[field] === '') { throw 'Required credentials is not set: "' + field + '".'; }; AWS.params[field] = credentials[field]; }); break; default: AWS.params['auth_type'] = 'access_key'; ['AccessKeyId', 'SecretAccessKey'].forEach(function (field) { if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') { throw 'Required param is not set: "' + field + '".'; } AWS.params[field] = params[field]; }); } ['region', 'volume_id'].forEach(function (field) { if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') { throw 'Required param is not set: "' + field + '".'; } AWS.params[field] = params[field]; }); }, sign: function (key, message) { var hex = hmac('sha256', key, message); if ((hex.length % 2) === 1) { throw 'Invalid length of a hex string!'; } var result = new Int8Array(hex.length / 2); for (var i = 0, b = 0; i < hex.length; i += 2, b++) { result[b] = parseInt(hex.substring(i, i + 2), 16); } return result; }, prepareRecursive: function (prefix, param) { var result = {}; if (typeof param === 'object') { if (Array.isArray(param)) { param.forEach(function (value, index) { var nested = AWS.prepareRecursive(prefix + '.member.' + (index + 1), value); Object.keys(nested).forEach(function (key) { result[key] = nested[key]; }); }); } else { Object.keys(param).forEach(function (k) { var nested = AWS.prepareRecursive(prefix + '.' + k, param[k]); Object.keys(nested).forEach(function (key) { result[key] = nested[key]; }); }); } } else { result[prefix] = param; } return result; }, renderPayload: function (period, volume_id) { var metrics_list = [ 'VolumeReadBytes:Bytes', 'VolumeWriteBytes:Bytes', 'VolumeReadOps:Count', 'VolumeWriteOps:Count', 'VolumeTotalReadTime:Seconds', 'VolumeTotalWriteTime:Seconds', 'VolumeIdleTime:Seconds', 'VolumeQueueLength:Count', 'VolumeThroughputPercentage:Percent', 'VolumeConsumedReadWriteOps:Count', 'BurstBalance:Percent' ]; var metric_payload = []; metrics_list.forEach(function (metric) { var parts = metric.split(':', 2); var name = parts[0].replace(/[^a-zA-Z0-9]/g, ''); metric_payload.push({ 'Id': name.charAt(0).toLowerCase() + name.slice(1), 'MetricStat': { 'Metric': { 'MetricName': parts[0], 'Namespace': 'AWS/EBS', 'Dimensions': [ { 'Name': 'VolumeId', 'Value': volume_id } ] }, 'Period': period, 'Stat': 'Average', 'Unit': parts[1] } }); }); return metric_payload; }, prepareParams: function (params) { var result = []; Object.keys(params).sort().forEach(function (key) { if (typeof params[key] !== 'object') { result.push(key + '=' + encodeURIComponent(params[key])); } else { result.push(prepareObject(key, params[key])); } }); return result.join('&'); }, request: function (method, region, service, params, data) { if (typeof data === 'undefined' || data === null) { data = ''; } var amzdate = (new Date()).toISOString().replace(/\.\d+Z/, 'Z').replace(/[-:]/g, ''), date = amzdate.replace(/T\d+Z/, ''), host = service + '.' + region + '.amazonaws.com', canonical_uri = '/', canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n', signed_headers = 'content-encoding;host;x-amz-date', canonical_request = method + '\n' + canonical_uri + '\n' + params + '\n' + canonical_headers + '\n' + signed_headers + '\n' + sha256(data), credential_scope = date + '/' + region + '/' + service + '/' + 'aws4_request', request_string = 'AWS4-HMAC-SHA256' + '\n' + amzdate + '\n' + credential_scope + '\n' + sha256(canonical_request), key = AWS.sign('AWS4' + AWS.params.SecretAccessKey, date), key = AWS.sign(key, region), key = AWS.sign(key, service), key = AWS.sign(key, 'aws4_request'), request = new HttpRequest(), url = 'https://' + host + canonical_uri + '?' + params; if (typeof AWS.params.proxy !== 'undefined' && AWS.params.proxy !== '') { request.setProxy(AWS.params.proxy); } request.addHeader('x-amz-date: ' + amzdate); request.addHeader('Accept: application/json'); request.addHeader('Content-Type: application/json'); request.addHeader('Content-Encoding: amz-1.0'); request.addHeader('Authorization: ' + 'AWS4-HMAC-SHA256 Credential=' + AWS.params.AccessKeyId + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + hmac('sha256', key, request_string)); if (AWS.params.auth_type === 'role_base' || (AWS.params.auth_type === 'assume_role' & !params.includes('AssumeRole'))) { request.addHeader('X-Amz-Security-Token: ' + (AWS.params.auth_type === 'role_base' ? AWS.params.Token : AWS.params.SessionToken)); } Zabbix.log(4, '[ AWS EBS ] Sending request: ' + url); response = request.get(url); Zabbix.log(4, '[ AWS EBS ] Received response with status code ' + request.getStatus() + ': ' + response); if (request.getStatus() !== 200) { throw 'Request failed with status code ' + request.getStatus() + ': ' + response; } if (response !== null) { try { response = JSON.parse(response); } catch (error) { throw 'Failed to parse response received from AWS CloudWatch API. Check debug log for more information.'; } } return response; }, getMetricsData: function () { var timestamp = new Date().getTime(), end_time = new Date(timestamp).toISOString().replace(/\.\d+Z/, 'Z'), start_time = new Date(timestamp - AWS.request_period * 1000).toISOString().replace(/\.\d+Z/, 'Z'), payload = AWS.prepareRecursive('MetricDataQueries', AWS.renderPayload(AWS.request_period, AWS.params.volume_id)); payload['Action'] = 'GetMetricData'; payload['Version'] = '2010-08-01'; payload['StartTime'] = start_time; payload['EndTime'] = end_time; payload['ScanBy'] = 'TimestampDescending'; result = AWS.request('GET', AWS.params.region, 'monitoring', AWS.prepareParams(payload)); if (typeof result !== 'object' || typeof result.GetMetricDataResponse !== 'object' || typeof result.GetMetricDataResponse.GetMetricDataResult !== 'object' || typeof result.GetMetricDataResponse.GetMetricDataResult.MetricDataResults !== 'object') { throw 'Cannot get metrics data from AWS CloudWatch API. Check debug log for more information.'; } return result.GetMetricDataResponse.GetMetricDataResult.MetricDataResults; } }; try { AWS.setParams(JSON.parse(value)); return JSON.stringify(AWS.getMetricsData()); } catch (error) { error += (String(error).endsWith('.')) ? '' : '.'; Zabbix.log(3, '[ AWS EBS ] ERROR: ' + error); return JSON.stringify({'error': error}); } description: | Get metrics of EBS volume. Full metrics list related to EBS: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using_cloudwatch_ebs.html preprocessing: - type: CHECK_NOT_SUPPORTED parameters: - '' timeout: 15s parameters: - name: AccessKeyId value: '{$AWS.ACCESS.KEY.ID}' - name: auth_type value: '{$AWS.AUTH_TYPE}' - name: proxy value: '{$AWS.PROXY}' - name: region value: '{$AWS.REGION}' - name: role_arn value: '{$AWS.ASSUME.ROLE.ARN}' - name: SecretAccessKey value: '{$AWS.SECRET.ACCESS.KEY}' - name: sts_region value: '{$AWS.STS.REGION}' - name: volume_id value: '{#VOLUME_ID}' tags: - tag: component value: raw - tag: type value: '{#VOLUME_TYPE}' - tag: volume value: '{#VOLUME_ID}' graph_prototypes: - uuid: dbf87c66b9034e1ab40f3a2d4adb1a5a name: 'AWS EBS: [{#VOLUME_ID}]: Volume read/write bytes' graph_items: - color: 199C0D item: host: 'AWS EC2 by HTTP' key: 'aws.ec2.ebs.volume.write_bytes["{#VOLUME_ID}"]' - sortorder: '1' color: F63100 item: host: 'AWS EC2 by HTTP' key: 'aws.ec2.ebs.volume.read_bytes["{#VOLUME_ID}"]' - uuid: 97faf8177efd46f2b90a7078e532f623 name: 'AWS EBS: [{#VOLUME_ID}]: Volume read/write ops' graph_items: - color: 199C0D item: host: 'AWS EC2 by HTTP' key: 'aws.ec2.ebs.volume.write_ops["{#VOLUME_ID}"]' - sortorder: '1' color: F63100 item: host: 'AWS EC2 by HTTP' key: 'aws.ec2.ebs.volume.read_ops["{#VOLUME_ID}"]' - uuid: c27e794ff80a4335874ae9b58c8ce6b8 name: 'AWS EBS: [{#VOLUME_ID}]: Volume read/write time' graph_items: - color: 199C0D item: host: 'AWS EC2 by HTTP' key: 'aws.ec2.ebs.volume.total_write_time["{#VOLUME_ID}"]' - sortorder: '1' color: F63100 item: host: 'AWS EC2 by HTTP' key: 'aws.ec2.ebs.volume.total_read_time["{#VOLUME_ID}"]' master_item: key: aws.ec2.get_volumes preprocessing: - type: JAVASCRIPT parameters: - | var result = []; var volumes = JSON.parse(value); volumes.forEach(function(volume) { result.push({ '{#VOLUME_ID}': volume.volumeId, '{#VOLUME_TYPE}': volume.volumeType, }); }); return JSON.stringify(result); - type: DISCARD_UNCHANGED_HEARTBEAT parameters: - 3h tags: - tag: class value: software - tag: target value: aws - tag: target value: ec2 macros: - macro: '{$AWS.ACCESS.KEY.ID}' description: 'Access key ID.' - macro: '{$AWS.ASSUME.ROLE.ARN}' description: 'ARN assume role; add when using the `assume_role` authorization method.' - macro: '{$AWS.AUTH_TYPE}' value: access_key description: 'Authorization method. Possible values: `access_key`, `assume_role`, `role_base`.' - macro: '{$AWS.EBS.BURST.CREDIT.BALANCE.MIN.WARN}' value: '20' description: 'Minimum percentage of Byte credits remaining for trigger expression.' - macro: '{$AWS.EBS.BYTE.CREDIT.BALANCE.MIN.WARN}' value: '20' description: 'Minimum percentage of Byte credits remaining for trigger expression.' - macro: '{$AWS.EBS.IO.CREDIT.BALANCE.MIN.WARN}' value: '20' description: 'Minimum percentage of I/O credits remaining for trigger expression.' - macro: '{$AWS.EC2.CPU.CREDIT.BALANCE.MIN.WARN}' value: '50' description: 'Minimum number of free earned CPU credits for trigger expression.' - macro: '{$AWS.EC2.CPU.CREDIT.SURPLUS.BALANCE.MAX.WARN}' value: '100' description: 'Maximum number of spent CPU Surplus credits for trigger expression.' - macro: '{$AWS.EC2.CPU.UTIL.WARN.MAX}' value: '85' description: 'The warning threshold of the CPU utilization expressed in %.' - macro: '{$AWS.EC2.INSTANCE.ID}' description: 'EC2 instance ID.' - macro: '{$AWS.EC2.LLD.FILTER.ALARM_NAME.MATCHES}' value: '.*' description: 'Filter of discoverable alarms by name.' - macro: '{$AWS.EC2.LLD.FILTER.ALARM_NAME.NOT_MATCHES}' value: CHANGE_IF_NEEDED description: 'Filter to exclude discovered alarms by name.' - macro: '{$AWS.EC2.LLD.FILTER.ALARM_SERVICE_NAMESPACE.MATCHES}' value: '.*' description: 'Filter of discoverable alarms by namespace.' - macro: '{$AWS.EC2.LLD.FILTER.ALARM_SERVICE_NAMESPACE.NOT_MATCHES}' value: CHANGE_IF_NEEDED description: 'Filter to exclude discovered alarms by namespace.' - macro: '{$AWS.EC2.LLD.FILTER.VOLUME_TYPE.MATCHES}' value: '.*' description: 'Filter of discoverable volumes by type.' - macro: '{$AWS.EC2.LLD.FILTER.VOLUME_TYPE.NOT_MATCHES}' value: CHANGE_IF_NEEDED description: 'Filter to exclude discovered volumes by type.' - macro: '{$AWS.PROXY}' description: 'Sets HTTP proxy value. If this macro is empty then no proxy is used.' - macro: '{$AWS.REGION}' value: us-west-1 description: 'Amazon EC2 Region code.' - macro: '{$AWS.SECRET.ACCESS.KEY}' description: 'Secret access key.' - macro: '{$AWS.STS.REGION}' value: us-east-1 description: 'Region used in assume role request.' valuemaps: - uuid: 50b7fdfdf6de41f4b4b210a07c10cd77 name: 'Alarm state' mappings: - value: '0' newvalue: OK - value: '1' newvalue: 'Insufficient data' - value: '2' newvalue: Alarm - value: '255' newvalue: Unknown - uuid: d59e4f0c6aaa40bcb5f504f6743d9201 name: 'Status check' mappings: - value: '0' newvalue: Passed - value: '1' newvalue: Failed - uuid: cf0267337f284182a43db45d823824b7 name: 'Volume attachment state' mappings: - value: '0' newvalue: Attaching - value: '1' newvalue: Attached - value: '2' newvalue: Detaching - value: '255' newvalue: Unknown - uuid: 4f31d29791b94e37b065f790609c50b5 name: 'Volume status' mappings: - value: '0' newvalue: Creating - value: '1' newvalue: Available - value: '2' newvalue: In-use - value: '3' newvalue: Deleting - value: '4' newvalue: Deleted - value: '5' newvalue: Error - value: '255' newvalue: Unknown graphs: - uuid: 397c46285f674ac389c59f1c828ae179 name: 'AWS EC2: Disk read/write bytes' graph_items: - color: 199C0D item: host: 'AWS EC2 by HTTP' key: aws.ec2.disk.read_bytes.rate - sortorder: '1' color: F63100 item: host: 'AWS EC2 by HTTP' key: aws.ec2.disk_write_bytes.rate - uuid: 21b7ec1e5e1445e287855e3d1a12c2bc name: 'AWS EC2: Disk read/write rates' graph_items: - color: 199C0D item: host: 'AWS EC2 by HTTP' key: aws.ec2.disk.read_ops.rate - sortorder: '1' color: F63100 item: host: 'AWS EC2 by HTTP' key: aws.ec2.disk_write_ops.rate - uuid: a1244a6a4b6641388546988257e905dc name: 'AWS EC2: Network packets' graph_items: - color: 199C0D item: host: 'AWS EC2 by HTTP' key: aws.ec2.packets_in.rate - sortorder: '1' color: F63100 item: host: 'AWS EC2 by HTTP' key: aws.ec2.packets_out.rate - uuid: 45e96dbc8dff48eeadd18c69b085863f name: 'AWS EC2: Network traffic' graph_items: - color: 199C0D item: host: 'AWS EC2 by HTTP' key: aws.ec2.network_in.rate - sortorder: '1' color: F63100 item: host: 'AWS EC2 by HTTP' key: aws.ec2.network_out.rate