zabbix_export: version: '6.0' date: '2024-08-20T09:49:02Z' groups: - uuid: c2c162144c2d4c5491c8801193af4945 name: Templates/Cloud templates: - uuid: a14ab6b4e80643fe8daa9d7288658f79 template: 'AWS S3 bucket by HTTP' name: 'AWS S3 bucket by HTTP' description: | The template gets AWS S3 bucket 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: 7ca108eafb0d4b65a304815ee637174e name: 'AWS S3: Get alarms check' type: DEPENDENT key: aws.s3.alarms.check delay: '0' history: 7d trends: '0' value_type: CHAR description: 'Data collection check.' preprocessing: - type: JSONPATH parameters: - $.error error_handler: CUSTOM_VALUE - type: DISCARD_UNCHANGED_HEARTBEAT parameters: - 3h master_item: key: aws.s3.get_alarms tags: - tag: component value: status triggers: - uuid: a8f8a7518aad4e32b23a8611afc8f48c expression: 'length(last(/AWS S3 bucket by HTTP/aws.s3.alarms.check))>0' name: 'AWS S3: Failed to get alarms data' opdata: '{ITEM.LASTVALUE1}' priority: WARNING description: 'Failed to get CloudWatch alarms for S3 bucket.' tags: - tag: scope value: availability - uuid: fceb9927715443059269fa4589f90f67 name: 'AWS S3: Bucket Size' type: DEPENDENT key: aws.s3.bucket_size_bytes delay: '0' history: 7d value_type: FLOAT units: B description: | This is a daily metric for the bucket. The amount of data in bytes stored in a bucket in the STANDARD storage class, INTELLIGENT_TIERING storage class, Standard-Infrequent Access (STANDARD_IA) storage class, OneZone-Infrequent Access (ONEZONE_IA), Reduced Redundancy Storage (RRS) class, S3 Glacier Instant Retrieval storage class, Deep Archive Storage (S3 Glacier Deep Archive) class, or S3 Glacier Flexible Retrieval (GLACIER) storage class. This value is calculated by summing the size of all objects and metadata in the bucket (both current and noncurrent objects), including the size of all parts for all incomplete multipart uploads to the bucket. preprocessing: - type: JSONPATH parameters: - '$.metrics[?(@.Label == "StandardStorage BucketSizeBytes")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: aws.s3.get_metrics tags: - tag: component value: storage - uuid: 6da0ea7130e64a7fb8ae32ee02290cbf name: 'AWS S3: Get alarms data' type: SCRIPT key: aws.s3.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) { 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('alarms', '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]; }); } ['bucket_name', 'request_region'].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 (get, 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/, ''); if (get === 'alarms') { host = service + '.' + region + '.amazonaws.com'; } else { host = AWS.params.bucket_name + '.' + service + '.' + region + '.amazonaws.com'; } if (AWS.params.auth_type === 'role_base' || (AWS.params.auth_type === 'assume_role' & !params.includes('AssumeRole'))) { token = AWS.params.auth_type === 'role_base' ? AWS.params.Token : AWS.params.SessionToken; var canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n' + 'x-amz-security-token:' + token + '\n', signed_headers = 'content-encoding;host;x-amz-date;x-amz-security-token'; } else { var canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n', signed_headers = 'content-encoding;host;x-amz-date'; } if (get === 'location') { canonical_uri = '/' + AWS.params.bucket_name; } else { canonical_uri = '/'; } var 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('x-amz-content-sha256:' + sha256(data)); 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: ' + token); } Zabbix.log(4, '[ AWS S3 ] Sending request: ' + url); response = request.get(url); Zabbix.log(4, '[ AWS S3 ] 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; }, getBucketLocation: function () { var payload = {}; payload['location'] = ''; result = AWS.request('location', 'GET', AWS.params.request_region, 's3', AWS.prepareParams(payload)); if (typeof result !== 'object' || result.hasOwnProperty('LocationConstraint') === false ) { throw 'Cannot get buckets region location data from AWS S3 API. Check debug log for more information.'; } return result.LocationConstraint !== null ? result.LocationConstraint : 'us-east-1'; }, getAlarms: function (region) { var payload = { 'Action': 'DescribeAlarms', 'Version': '2010-08-01', 'MaxRecords': 100 }, result = []; while (payload.NextToken !== '') { var alarms = AWS.getField(AWS.request('alarms', 'GET', 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 === 'BucketName' && dimensions[i].Value === AWS.params.bucket_name) { result.push(alarm); break; } } }); } return result; } }; try { AWS.setParams(JSON.parse(value)); var region = AWS.getBucketLocation(); return JSON.stringify(AWS.getAlarms(region)); } catch (error) { error += (String(error).endsWith('.')) ? '' : '.'; Zabbix.log(3, '[ AWS S3 ] ERROR: ' + error); return JSON.stringify({ 'error': error }); } description: | Get alarms data. 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: bucket_name value: '{$AWS.S3.BUCKET.NAME}' - name: proxy value: '{$AWS.PROXY}' - name: request_region value: '{$AWS.REQUEST.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: 598e9dc563334ad6b1d72245a6f8679f name: 'AWS S3: Get metrics data' type: SCRIPT key: aws.s3.get_metrics delay: 0s;h/8 history: '0' trends: '0' value_type: TEXT params: | var AWS = { params: {}, request_period: 2 * 86400, 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 are 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('credentials', '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]; }); } ['bucket_name', 'request_region'].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; }, renderMetricQuery: function (period, bucket_name) { var metrics_list = [ 'BucketSizeBytes:Bytes:Average:StandardStorage', 'NumberOfObjects:Count:Average:AllStorageTypes', ]; var metric_payload = []; metrics_list.forEach(function (metric, index) { var parts = metric.split(':', 4); metric_payload.push({ 'Id': 'm' + index, 'MetricStat': { 'Metric': { 'MetricName': parts[0], 'Namespace': 'AWS/S3', 'Dimensions': [ { 'Name': 'BucketName', 'Value': bucket_name }, { 'Name': 'StorageType', 'Value': parts[3] } ] }, 'Period': period, 'Stat': parts[2], '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 (get, method, region, service, params, data) { if (typeof data === 'undefined' || data === null) { data = ''; } else { data = JSON.stringify(data) } var amzdate = (new Date()).toISOString().replace(/\.\d+Z/, 'Z').replace(/[-:]/g, ''), date = amzdate.replace(/T\d+Z/, ''); if (get === 'metrics' || get === 'credentials') { host = service + '.' + region + '.amazonaws.com'; } else { host = AWS.params.bucket_name + '.' + service + '.' + region + '.amazonaws.com'; } if (AWS.params.auth_type === 'role_base' || (AWS.params.auth_type === 'assume_role' & !params.includes('AssumeRole'))) { token = AWS.params.auth_type === 'role_base' ? AWS.params.Token : AWS.params.SessionToken; var canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n' + 'x-amz-security-token:' + token + '\n', signed_headers = 'content-encoding;host;x-amz-date;x-amz-security-token'; } else { var canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n', signed_headers = 'content-encoding;host;x-amz-date'; } var canonical_uri = '/'; switch (get) { case 'location': canonical_uri = '/' + AWS.params.bucket_name; canonical_request = method + '\n' + canonical_uri + '\n' + params + '\n' + canonical_headers + '\n' + signed_headers + '\n' + sha256(data); break; case 'metrics': canonical_request = method + '\n' + canonical_uri + '\n' + '\n' + canonical_headers + '\n' + signed_headers + '\n' + sha256(data); break; case 'filter_id': case 'credentials': canonical_request = method + '\n' + canonical_uri + '\n' + params + '\n' + canonical_headers + '\n' + signed_headers + '\n' + sha256(data); break; default: throw 'Error: Invalid option "get" for request function'; } var 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(); if (typeof AWS.params.proxy !== 'undefined' && AWS.params.proxy !== '') { request.setProxy(AWS.params.proxy); } request.addHeader('x-amz-date: ' + amzdate); request.addHeader('x-amz-content-sha256:' + sha256(data)); 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: ' + token); } switch (get) { case 'location': case 'filter_id': case 'credentials': url = 'https://' + host + canonical_uri + '?' + params; Zabbix.log(4, '[ AWS S3 ] Sending request: ' + url); response = request.get(url); Zabbix.log(4, '[ AWS S3 ] Received response with status code ' + request.getStatus() + ': ' + response); if (request.getStatus() !== 200) { throw 'Request failed with status code ' + request.getStatus() + ': ' + response; } break; case 'metrics': url = 'https://' + host + '/'; Zabbix.log(4, '[ AWS S3 ] Sending request: ' + url); request.addHeader('X-Amz-Target: GraniteServiceVersion20100801.GetMetricData'); response = request.post(url, data); Zabbix.log(4, '[ AWS S3 ] Received response with status code ' + request.getStatus() + ': ' + response); if (request.getStatus() !== 200) { throw 'Request failed with status code ' + request.getStatus() + ': ' + response; } break; default: throw 'Error: Invalid option "get" for request function'; } 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; }, getBucketLocation: function (bucket_name) { var payload = {}; payload['location'] = ''; result = AWS.request('location', 'GET', AWS.params.request_region, 's3', AWS.prepareParams(payload), '', bucket_name); if (typeof result !== 'object' || result.hasOwnProperty('LocationConstraint') === false ) { throw 'Cannot get buckets region location data from AWS S3 API. Check debug log for more information.'; } return result.LocationConstraint !== null ? result.LocationConstraint : 'us-east-1'; }, getBucketFilterId: function (region) { var payload = {}; payload['metrics'] = ''; data = AWS.getField(AWS.request('filter_id', 'GET', region, 's3', AWS.prepareParams(payload), ''), 'ListMetricsConfigurationsResult'); if (typeof data === 'object' && data.hasOwnProperty('MetricsConfiguration') === true) { if (!Array.isArray(data.MetricsConfiguration)) data.MetricsConfiguration = [data.MetricsConfiguration] data.MetricsConfiguration.forEach(function (item) { item.region = region; }); } else { data.MetricsConfiguration = ['To view request metrics, create a filter'] } return data.MetricsConfiguration; }, getMetricsData: function (region) { var payload = {}, end_time = Math.floor((new Date().getTime()) / 1000), start_time = end_time - AWS.request_period; payload['StartTime'] = start_time; payload['EndTime'] = end_time; payload['ScanBy'] = 'TimestampDescending'; payload['MetricDataQueries'] = AWS.renderMetricQuery(43200, AWS.params.bucket_name); return AWS.getField(AWS.request('metrics', 'POST', region, 'monitoring', '', payload), 'MetricDataResults'); } }; try { AWS.setParams(JSON.parse(value)); var region = AWS.getBucketLocation(AWS.params.bucket_name), metrics = AWS.getMetricsData(region), filter_id = AWS.getBucketFilterId(region); return JSON.stringify({ metrics, filter_id }); } catch (error) { error += (String(error).endsWith('.')) ? '' : '.'; Zabbix.log(3, '[ AWS S3 ] ERROR: ' + error); return JSON.stringify({ 'error': error }); } description: | Get bucket metrics. Full metrics list related to S3: https://docs.aws.amazon.com/AmazonS3/latest/userguide/metrics-dimensions.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: bucket_name value: '{$AWS.S3.BUCKET.NAME}' - name: proxy value: '{$AWS.PROXY}' - name: request_region value: '{$AWS.REQUEST.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: 0e22c196ae834d2899068f25316ffed2 name: 'AWS S3: Get metrics check' type: DEPENDENT key: aws.s3.metrics.check delay: '0' history: 7d trends: '0' value_type: CHAR description: 'Data collection check.' preprocessing: - type: JSONPATH parameters: - $.error error_handler: CUSTOM_VALUE - type: DISCARD_UNCHANGED_HEARTBEAT parameters: - 3h master_item: key: aws.s3.get_metrics tags: - tag: component value: status triggers: - uuid: a8a0b4187f5f4e22b868dd038f53a2ba expression: 'length(last(/AWS S3 bucket by HTTP/aws.s3.metrics.check))>0' name: 'AWS S3: Failed to get metrics data' opdata: '{ITEM.LASTVALUE1}' priority: WARNING description: 'Failed to get CloudWatch metrics for S3 bucket.' tags: - tag: scope value: availability - uuid: 75b467e2079c41c5b3e8f79df8c5a9ba name: 'AWS S3: Number of objects' type: DEPENDENT key: aws.s3.number_of_objects delay: '0' history: 7d value_type: FLOAT description: | This is a daily metric for the bucket. The total number of objects stored in a bucket for all storage classes. This value is calculated by counting all objects in the bucket (both current and noncurrent objects) and the total number of parts for all incomplete multipart uploads to the bucket. preprocessing: - type: JSONPATH parameters: - '$.metrics.[?(@.Label == "AllStorageTypes NumberOfObjects")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: aws.s3.get_metrics tags: - tag: component value: storage discovery_rules: - uuid: 26c424a60a7a4975996ccc44601c4ee3 name: 'Bucket Alarms discovery' type: DEPENDENT key: aws.s3.alarms.discovery delay: '0' filter: evaltype: AND conditions: - macro: '{#ALARM_NAME}' value: '{$AWS.S3.LLD.FILTER.ALARM_NAME.MATCHES}' formulaid: A - macro: '{#ALARM_NAME}' value: '{$AWS.S3.LLD.FILTER.ALARM_NAME.NOT_MATCHES}' operator: NOT_MATCHES_REGEX formulaid: B description: 'Discovery of bucket alarms.' item_prototypes: - uuid: b38bd6e4566445acb52e8ecce4014f0f name: 'AWS S3 Alarms: [{#ALARM_NAME}]: State' type: DEPENDENT key: 'aws.s3.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: - '$.[?(@.AlarmName == "{#ALARM_NAME}")].StateValue.first()' 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.s3.get_alarms tags: - tag: component value: alarms trigger_prototypes: - uuid: 7f0ba96047784510b734c0064d434edc expression: 'last(/AWS S3 bucket by HTTP/aws.s3.alarm.state["{#ALARM_NAME}"])=1' name: 'AWS S3 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: 7e536a43faf742058d303ffe21cd9a8c name: 'AWS S3 Alarms: [{#ALARM_NAME}]: State reason' type: DEPENDENT key: 'aws.s3.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: - '$.[?(@.AlarmName == "{#ALARM_NAME}")].StateReason.first()' error_handler: DISCARD_VALUE - type: DISCARD_UNCHANGED_HEARTBEAT parameters: - 3h master_item: key: aws.s3.get_alarms tags: - tag: component value: alarms trigger_prototypes: - uuid: c1b94199b7ac4cc9889ff0e724f7057d expression: 'last(/AWS S3 bucket by HTTP/aws.s3.alarm.state["{#ALARM_NAME}"])=2 and length(last(/AWS S3 bucket by HTTP/aws.s3.alarm.state_reason["{#ALARM_NAME}"]))>0' name: 'AWS S3 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.s3.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 }); }); return JSON.stringify(result); - type: DISCARD_UNCHANGED_HEARTBEAT parameters: - 3h - uuid: 9ff609d143ae4552b395668718c43191 name: 'Request Metrics discovery' type: DEPENDENT key: aws.s3.configuration.discovery delay: '0' filter: evaltype: AND conditions: - macro: '{#AWS.S3.FILTER.ID.NAME}' value: '{$AWS.S3.LLD.FILTER.ID.NAME.MATCHES}' formulaid: A - macro: '{#AWS.S3.FILTER.ID.NAME}' value: '{$AWS.S3.LLD.FILTER.ID.NAME.NOT_MATCHES}' operator: NOT_MATCHES_REGEX formulaid: B description: 'Discovery of request metrics.' item_prototypes: - uuid: 7c746594159f4f1c94e8790ed1bdf2af name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Requests: Errors, 4xx' type: DEPENDENT key: 'aws.s3.4xx_errors["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT description: | The number of HTTP 4xx client error status code requests made to an Amazon S3 bucket with a value of either 0 or 1. The average statistic shows the error rate, and the sum statistic shows the count of that type of error, during each period. Statistic: Average (reports per request). preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "4xxErrors")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: errors - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: 806de74ed57b4797b294ebe8fa509429 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Requests: Errors, 5xx' type: DEPENDENT key: 'aws.s3.5xx_errors["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT description: | The number of HTTP 5xx server error status code requests made to an Amazon S3 bucket with a value of either 0 or 1. The average statistic shows the error rate, and the sum statistic shows the count of that type of error, during each period. Statistic: Average (reports per request). preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "5xxErrors")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: errors - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: 7530d7ebe61942f4abc29a8ccb3b5516 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Requests: All' type: DEPENDENT key: 'aws.s3.all_requests["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT description: | The total number of HTTP requests made to an Amazon S3 bucket, regardless of type. If you're using a metrics configuration with a filter, then this metric only returns the HTTP requests that meet the filter's requirements. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "AllRequests")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: requests - uuid: 8758c16faef9477d8e3ff41426c2761b name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Requests: Bytes downloaded' type: DEPENDENT key: 'aws.s3.bytes_downloaded["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT units: B description: | The number of bytes downloaded for requests made to an Amazon S3 bucket, where the response includes a body. Statistic: Average (bytes per request). preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "BytesDownloaded")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: 3f5141a7448b43d288a37dfe41a52288 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Replication: Bytes pending' type: DEPENDENT key: 'aws.s3.bytes_pending_replication["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT units: B description: 'The total number of bytes of objects pending replication for a given replication rule.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "BytesPendingReplication")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: replication - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: 99eefab6b9be405ead0e6ea57394a7e3 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Requests: Bytes uploaded' type: DEPENDENT key: 'aws.s3.bytes_uploaded["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT units: B description: | The number of bytes uploaded that contain a request body, made to an Amazon S3 bucket. Statistic: Average (bytes per request). preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "BytesUploaded")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: d9deb58254be4add996d3dec97344132 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Requests: Delete' type: DEPENDENT key: 'aws.s3.delete_requests["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT description: | The number of HTTP DELETE requests made for objects in an Amazon S3 bucket. This also includes Delete Multiple Objects requests. This metric shows the number of requests, not the number of objects deleted. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "DeleteRequests")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: d8c8e91f383747e5b6e73f922f5b3278 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: First byte latency, avg' type: DEPENDENT key: 'aws.s3.first_byte_latency.avg["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT units: ms description: | The per-request time from the complete request being received by an Amazon S3 bucket to when the response starts to be returned. Statistic: Average. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "FirstByteLatency")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: latency - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: 55cb2316171e43a0aa94e0d203832577 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: First byte latency, p90' type: DEPENDENT key: 'aws.s3.first_byte_latency.p90["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT units: ms description: | The per-request time from the complete request being received by an Amazon S3 bucket to when the response starts to be returned. Statistic: 90th percentile. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "FirstByteLatency")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: latency - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: eabbd51547cb4a0484182d42601728c3 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Get request metrics' type: SCRIPT key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' delay: '{$AWS.S3.UPDATE.INTERVAL}' 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) { 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; }, isFloat: function (n) { n = parseFloat(n); return Number(n) === n && n % 1 !== 0; }, checkNumber: function checkNumber(string) { if (typeof string !== "string" || isNaN(string) || AWS.isFloat(string)) { throw 'Incorrect "timespan" parameter given: ' + string + ' Must be an unsigned number'; } return string; }, setParams: function (params) { switch (AWS.getField(params, 'auth_type')) { case 'role_base': AWS.params['auth_type'] = 'role_base'; var request = new HttpRequest(), 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 are 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('POST', 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', 'bucket_name', 'filter_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]; }); updateInterval = AWS.checkNumber('{$AWS.S3.UPDATE.INTERVAL}'); if (updateInterval > 86400 || updateInterval < 1) { throw 'Incorrect "update interval" parameter given: ' + updateInterval + ' Must be between 1 and 86400 seconds.'; } }, 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; }, renderMetricQuery: function (period, bucket_name, filter_id) { var metrics_list = [ 'AllRequests:Count:Sum', 'GetRequests:Count:Sum', 'PutRequests:Count:Sum', 'DeleteRequests:Count:Sum', 'HeadRequests:Count:Sum', 'PostRequests:Count:Sum', 'SelectRequests:Count:Sum', 'SelectBytesScanned:Bytes:Average', 'SelectBytesReturned:Bytes:Average', 'ListRequests:Count:Sum', 'BytesDownloaded:Bytes:Average', 'BytesUploaded:Bytes:Average', '4xxErrors:Count:Average', '5xxErrors:Count:Average', 'TotalRequestLatency:Milliseconds:p90', 'FirstByteLatency:Milliseconds:p90', 'ReplicationLatency:Seconds:Average', 'BytesPendingReplication:Bytes:Average', 'OperationsPendingReplication:Count:Average', ]; var metric_payload = []; metrics_list.forEach(function (metric, index) { var parts = metric.split(':', 3); metric_payload.push({ 'Id': 'm' + index, 'MetricStat': { 'Metric': { 'MetricName': parts[0], 'Namespace': 'AWS/S3', 'Dimensions': [ { 'Name': 'BucketName', 'Value': bucket_name }, { 'Name': 'FilterId', 'Value': filter_id } ] }, 'Period': period, 'Stat': parts[2], '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 = ''; } else { data = JSON.stringify(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 = '/'; if (AWS.params.auth_type === 'role_base' || (AWS.params.auth_type === 'assume_role' & !params.includes('AssumeRole'))) { token = AWS.params.auth_type === 'role_base' ? AWS.params.Token : AWS.params.SessionToken; var canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n' + 'x-amz-security-token:' + token + '\n', signed_headers = 'content-encoding;host;x-amz-date;x-amz-security-token'; } else { var canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n', signed_headers = 'content-encoding;host;x-amz-date'; } var 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('X-Amz-Target: GraniteServiceVersion20100801.GetMetricData') 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: ' + token); } Zabbix.log(4, '[ AWS S3 ] Sending request: ' + url); response = request.post(url, data); Zabbix.log(4, '[ AWS S3 ] 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 payload = {}, end_time = Math.floor((new Date().getTime()) / 1000), start_time = end_time - updateInterval; payload['StartTime'] = start_time; payload['EndTime'] = end_time; payload['ScanBy'] = 'TimestampDescending'; payload['MetricDataQueries'] = AWS.renderMetricQuery(60, AWS.params.bucket_name, AWS.params.filter_id); result = AWS.request('POST', AWS.params.region, 'monitoring', '', payload); if (typeof result !== 'object' || typeof result.MetricDataResults !== 'object') { throw 'Cannot get metrics data from AWS CloudWatch API. Check debug log for more information.'; } return result.MetricDataResults; } }; try { AWS.setParams(JSON.parse(value)); return JSON.stringify(AWS.getMetricsData()); } catch (error) { error += (String(error).endsWith('.')) ? '' : '.'; Zabbix.log(3, '[ AWS S3 ] ERROR: ' + error); return JSON.stringify({ 'error': error }); } description: | Get bucket request metrics filter: '{#AWS.S3.FILTER.ID.NAME}'. Full metrics list related to S3: https://docs.aws.amazon.com/AmazonS3/latest/userguide/metrics-dimensions.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: bucket_name value: '{$AWS.S3.BUCKET.NAME}' - name: filter_id value: '{#AWS.S3.FILTER.ID.NAME}' - name: proxy value: '{$AWS.PROXY}' - name: region value: '{#AWS.S3.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 - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: f2cff8aa3c3c4a308296550561b02829 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Requests: Get' type: DEPENDENT key: 'aws.s3.get_requests["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT description: | The number of HTTP GET requests made for objects in an Amazon S3 bucket. This doesn't include list operations. Paginated list-oriented requests, like List Multipart Uploads, List Parts, Get Bucket Object versions, and others, are not included in this metric. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "GetRequests")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: 0d9f59f099cb47c8991cc2e353154dc7 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Requests: Head' type: DEPENDENT key: 'aws.s3.head_requests["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT description: 'The number of HTTP HEAD requests made to an Amazon S3 bucket.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "HeadRequests")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: f9b09dbbf0a44ea9b34a86853a6ebfd0 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Requests: List' type: DEPENDENT key: 'aws.s3.list_requests["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT description: 'The number of HTTP requests that list the contents of a bucket.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "ListRequests")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: ad753554ca7e45629e7eb144a3595228 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Replication: Operations pending' type: DEPENDENT key: 'aws.s3.operations_pending_replication["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT description: 'The number of operations pending replication for a given replication rule.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "OperationsPendingReplication")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: replication - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: 9bb4416c7c454e5486a7ce4e4b4b90f0 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Requests: Post' type: DEPENDENT key: 'aws.s3.post_requests["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT description: | The number of HTTP POST requests made to an Amazon S3 bucket. Delete Multiple Objects and SELECT Object Content requests are not included in this metric. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "PostRequests")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: 88a67025c835410eb54d74be96cf5b4c name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Requests: Put' type: DEPENDENT key: 'aws.s3.put_requests["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT description: 'The number of HTTP PUT requests made for objects in an Amazon S3 bucket.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "PutRequests")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: ac0f6d6f6f2247379d99fa2f4f0ecc11 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Replication: Latency' type: DEPENDENT key: 'aws.s3.replication_latency["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT units: s description: 'The maximum number of seconds by which the replication destination region is behind the source Region for a given replication rule.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "ReplicationLatency")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: replication - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: 23c13e717a2845399068e7c2e627df4f name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Requests: Select, bytes returned' type: DEPENDENT key: 'aws.s3.select_bytes_returned["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT units: B description: | The number of bytes of data returned with Amazon S3 SELECT Object Content requests in an Amazon S3 bucket. Statistic: Average (bytes per request). preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "SelectBytesReturned")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: 042e84dc68c54390a3d0427b87d89e47 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Requests: Select, bytes scanned' type: DEPENDENT key: 'aws.s3.select_bytes_scanned["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT units: B description: | The number of bytes of data scanned with Amazon S3 SELECT Object Content requests in an Amazon S3 bucket. Statistic: Average (bytes per request). preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "SelectBytesScanned")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: 616ec102597447cdbe2f21186937dcfe name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Requests: Select' type: DEPENDENT key: 'aws.s3.select_requests["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT description: 'The number of Amazon S3 SELECT Object Content requests made for objects in an Amazon S3 bucket.' preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "SelectRequests")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: effa8475024843249ad213d726323e72 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Total request latency, avg' type: DEPENDENT key: 'aws.s3.total_request_latency.avg["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT units: ms description: | The elapsed per-request time from the first byte received to the last byte sent to an Amazon S3 bucket. This includes the time taken to receive the request body and send the response body, which is not included in FirstByteLatency. Statistic: Average. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "TotalRequestLatency")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: latency - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' - uuid: 886b748066834f01aa2f6f9327fceba0 name: 'AWS S3: Filter [{#AWS.S3.FILTER.ID.NAME}]: Total request latency, p90' type: DEPENDENT key: 'aws.s3.total_request_latency.p90["{#AWS.S3.FILTER.ID.NAME}"]' delay: '0' history: 7d value_type: FLOAT units: ms description: | The elapsed per-request time from the first byte received to the last byte sent to an Amazon S3 bucket. This includes the time taken to receive the request body and send the response body, which is not included in FirstByteLatency. Statistic: 90th percentile. preprocessing: - type: JSONPATH parameters: - '$.[?(@.Label == "TotalRequestLatency")].Values.first().first()' error_handler: DISCARD_VALUE master_item: key: 'aws.s3.get_metrics["{#AWS.S3.FILTER.ID.NAME}"]' tags: - tag: component value: latency - tag: component value: requests - tag: filter-id value: '{#AWS.S3.FILTER.ID.NAME}' master_item: key: aws.s3.get_metrics lld_macro_paths: - lld_macro: '{#AWS.S3.FILTER.ID.NAME}' path: $.Id - lld_macro: '{#AWS.S3.REGION}' path: $.region preprocessing: - type: JSONPATH parameters: - $.filter_id - type: DISCARD_UNCHANGED_HEARTBEAT parameters: - 3h tags: - tag: class value: software - tag: target value: aws - tag: target value: s3 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.PROXY}' description: 'Sets HTTP proxy value. If this macro is empty then no proxy is used.' - macro: '{$AWS.REQUEST.REGION}' value: us-east-1 description: 'Region used in GET request `ListBuckets`.' - macro: '{$AWS.S3.BUCKET.NAME}' description: 'S3 bucket name.' - macro: '{$AWS.S3.LLD.FILTER.ALARM_NAME.MATCHES}' value: '.*' description: 'Filter of discoverable alarms by name.' - macro: '{$AWS.S3.LLD.FILTER.ALARM_NAME.NOT_MATCHES}' value: CHANGE_IF_NEEDED description: 'Filter to exclude discovered alarms by name.' - macro: '{$AWS.S3.LLD.FILTER.ID.NAME.MATCHES}' value: '.*' description: 'Filter of discoverable request metrics by filter ID name.' - macro: '{$AWS.S3.LLD.FILTER.ID.NAME.NOT_MATCHES}' value: CHANGE_IF_NEEDED description: 'Filter to exclude discovered request metrics by filter ID name.' - macro: '{$AWS.S3.UPDATE.INTERVAL}' value: '1800' description: 'Interval in seconds for getting request metrics. Used in the metric configuration and in the JavaScript API query. Must be between 1 and 86400 seconds.' - macro: '{$AWS.SECRET.ACCESS.KEY}' type: SECRET_TEXT description: 'Secret access key.' - macro: '{$AWS.STS.REGION}' value: us-east-1 description: 'Region used in assume role request.' valuemaps: - uuid: 5f232f40f02246ab843c9aacdcf8d5c5 name: 'Alarm state' mappings: - value: '0' newvalue: OK - value: '1' newvalue: 'Insufficient data' - value: '2' newvalue: Alarm - value: '255' newvalue: Unknown