zabbix_export:
  version: '6.0'
  date: '2023-11-28T11:07:32Z'
  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
              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: {},
            
                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) {
                    switch (AWS.getField(params, 'auth_type')) {
                        case 'role_base':
                            AWS.params['auth_type'] = 'role_base';
                            var request = new HttpRequest(),
                                IamRoleName = request.get('http://169.254.169.254/latest/meta-data/iam/security-credentials');
            
                            if (request.getStatus() !== 200 || IamRoleName === null || IamRoleName === '') {
                                throw 'Error getting security credentials from instance metadata. Role not found.';
                            }
            
                            credentials = request.get('http://169.254.169.254/latest/meta-data/iam/security-credentials/' + 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 'access_key':
                        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'].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, uri) {
                    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') {
                        var canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n' + 'x-amz-security-token:' + AWS.params.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 = '/' + uri;
                    } 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');
            
                    var 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')
                        request.addHeader('X-Amz-Security-Token: ' + AWS.params.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;
                    }
            
                    if (response[0] === '<') {
                        try {
                            response = XML.toJson(response);
                        }
                        catch (error) {
                            throw 'Failed to parse response received from AWS CloudWatch API. Check debug log for more information.';
                        }
                    }
            
                    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;
                },
            
                getBucketLocation: function (bucket_name) {
                    var payload = {};
            
                    payload['location'] = '';
            
                    result = AWS.request('location', 'GET', 'us-east-1', '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';
                },
            
                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));
                region = AWS.getBucketLocation(AWS.params.bucket_name);
                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: region
              value: '{$AWS.REGION}'
            - name: SecretAccessKey
              value: '{$AWS.SECRET.ACCESS.KEY}'
          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,
            
                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) {
                    switch (AWS.getField(params, 'auth_type')) {
                        case 'role_base':
                            AWS.params['auth_type'] = 'role_base';
                            var request = new HttpRequest(),
                                IamRoleName = request.get('http://169.254.169.254/latest/meta-data/iam/security-credentials');
            
                            if (request.getStatus() !== 200 || IamRoleName === null || IamRoleName === '') {
                                throw 'Error getting security credentials from instance metadata. Role not found.';
                            }
            
                            credentials = request.get('http://169.254.169.254/latest/meta-data/iam/security-credentials/' + 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 'access_key':
                        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'].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, uri) {
                    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') {
                        host = service + '.' + region + '.amazonaws.com';
                    } else {
                        host = AWS.params.bucket_name + '.' + service + '.' + region + '.amazonaws.com';
                    }
            
                    if (AWS.params.auth_type === 'role_base') {
                        var canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n' + 'x-amz-security-token:' + AWS.params.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 = '/' + uri;
                        canonical_request = method + '\n' + canonical_uri + '\n' + params + '\n' + canonical_headers + '\n' + signed_headers + '\n' + sha256(data),
                            url = 'https://' + host + canonical_uri + '?' + params;
                    }
                    if (get === 'metrics') {
                        canonical_uri = '/',
                            canonical_request = method + '\n' + canonical_uri + '\n' + '\n' + canonical_headers + '\n' + signed_headers + '\n' + sha256(data),
                            url = 'https://' + host + canonical_uri;
                    }
                    if (get === 'filter_id') {
                        canonical_uri = '/';
                        canonical_request = method + '\n' + canonical_uri + '\n' + params + '\n' + canonical_headers + '\n' + signed_headers + '\n' + sha256(data),
                            url = 'https://' + host + canonical_uri + '?' + params;
                    }
                    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');
                    var 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')
                        request.addHeader('X-Amz-Security-Token: ' + AWS.params.Token);
            
            
                    if (get === 'location' || get === 'filter_id') {
                        url = 'https://' + host + canonical_uri + '?' + params,
                            response = request.get(url);
                        if (response !== null) {
                            try {
                                response = XML.toJson(response);
                            }
                            catch (error) {
                                throw 'Failed to parse response received from AWS CloudWatch API. Check debug log for more information.';
                            }
                        }
                    }
                    if (get === 'metrics') {
                        url = 'https://' + host + '/',
                            request.addHeader('X-Amz-Target: GraniteServiceVersion20100801.GetMetricData'),
                            response = request.post(url, data);
            
                    }
            
                    Zabbix.log(4, '[ AWS S3 ] Sending request: ' + 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;
                    }
            
                    return JSON.parse(response);
                },
            
                getBucketLocation: function (bucket_name) {
                    var payload = {};
            
                    payload['location'] = '';
            
                    result = AWS.request('location', 'GET', 'us-east-1', '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 (bucket_name, region) {
                    var payload = {};
                    payload['metrics'] = '';
            
                    data = AWS.getField(AWS.request('filter_id', 'GET', region, 's3', AWS.prepareParams(payload), '', bucket_name), 'ListMetricsConfigurationsResult');
            
                    if (typeof data === 'object' && data.hasOwnProperty('MetricsConfiguration') === true) {
                        data.MetricsConfiguration.forEach(function (item) {
                            item.region = region;
                        });
                    } else { data = ['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));
                region = AWS.getBucketLocation(AWS.params.bucket_name);
                metrics = AWS.getMetricsData(region);
                filter_id = AWS.getBucketFilterId(AWS.params.bucket_name, 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: SecretAccessKey
              value: '{$AWS.SECRET.ACCESS.KEY}'
          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
              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
                  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: 'Metrics Configuration 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 metrics configuration.'
          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: {},
                
                    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('http://169.254.169.254/latest/meta-data/iam/security-credentials');
                
                                if (request.getStatus() !== 200 || IamRoleName === null || IamRoleName === '') {
                                    throw 'Error getting security credentials from instance metadata. Role not found.';
                                }
                
                                credentials = request.get('http://169.254.169.254/latest/meta-data/iam/security-credentials/' + 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 'access_key':
                            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',
                            'FirstByteLatency:Milliseconds:p90',
                            '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, request_data) {
                        if (typeof request_data === 'undefined' || request_data === null) {
                            request_data = '';
                        }
                        else {
                            request_data = JSON.stringify(request_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') {
                            var canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n' + 'x-amz-security-token:' + AWS.params.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' + '\n' + canonical_headers + '\n' + signed_headers + '\n' + sha256(request_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');
                
                        var request = new HttpRequest(),
                            url = 'https://' + host + canonical_uri;
                
                        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')
                            request.addHeader('X-Amz-Security-Token: ' + AWS.params.Token);
                
                        Zabbix.log(4, '[ AWS S3 ] Sending request: ' + url);
                
                        response = request.post(url, request_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;
                        }
                
                        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 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: SecretAccessKey
                  value: '{$AWS.SECRET.ACCESS.KEY}'
              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.AUTH_TYPE}'
          value: access_key
          description: 'Authorization method. Possible values: role_base, access_key.'
        - macro: '{$AWS.PROXY}'
          description: 'Sets HTTP proxy value. If this macro is empty then no proxy is used.'
        - 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.'
      valuemaps:
        - uuid: 5f232f40f02246ab843c9aacdcf8d5c5
          name: 'Alarm state'
          mappings:
            - value: '0'
              newvalue: OK
            - value: '1'
              newvalue: 'Insufficient data'
            - value: '2'
              newvalue: Alarm
            - value: '255'
              newvalue: Unknown
