You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
923 lines
42 KiB
923 lines
42 KiB
1 year ago
|
zabbix_export:
|
||
|
version: '7.0'
|
||
|
template_groups:
|
||
|
- uuid: c2c162144c2d4c5491c8801193af4945
|
||
|
name: Templates/Cloud
|
||
|
host_groups:
|
||
|
- uuid: a571c0d144b14fd4a87a9d9b2aa9fcd6
|
||
|
name: Applications
|
||
|
- uuid: 748ad4d098d447d492bb935c907f652f
|
||
|
name: Databases
|
||
|
- uuid: 137f19e6e2dc4219b33553b812627bc2
|
||
|
name: 'Virtual machines'
|
||
|
templates:
|
||
|
- uuid: c60e5929ab474f67bbe67dc6b04e709d
|
||
|
template: 'AWS by HTTP'
|
||
|
name: 'AWS by HTTP'
|
||
|
description: |
|
||
|
Get AWS EC2, RDS and S3 instances, AWS ECS clusters. 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" 2.0.0
|
||
|
vendor:
|
||
|
name: Zabbix
|
||
|
version: 7.0-0
|
||
|
groups:
|
||
|
- name: Templates/Cloud
|
||
|
discovery_rules:
|
||
|
- uuid: c651911bad9244ad9c8d2dad5b0d70e4
|
||
|
name: 'EC2 instances discovery'
|
||
|
type: SCRIPT
|
||
|
key: aws.ec2.discovery
|
||
|
delay: 12h
|
||
|
params: |
|
||
|
var AwsEC2 = {
|
||
|
params: {},
|
||
|
|
||
|
setParams: function (params) {
|
||
|
['access_key', 'region', 'secret_key'].forEach(function (field) {
|
||
|
if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') {
|
||
|
throw 'Required param is not set: "' + field + '".';
|
||
|
}
|
||
|
});
|
||
|
|
||
|
AwsEC2.params = params;
|
||
|
},
|
||
|
|
||
|
sign: function (key, message) {
|
||
|
var hex = hmac('sha256', key, message);
|
||
|
|
||
|
if ((hex.length % 2) === 1) {
|
||
|
throw 'Invalid length of a hex string!';
|
||
|
}
|
||
|
|
||
|
var result = new Int8Array(hex.length / 2);
|
||
|
for (var i = 0, b = 0; i < hex.length; i += 2, b++) {
|
||
|
result[b] = parseInt(hex.substring(i, i + 2), 16);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
},
|
||
|
|
||
|
prepareParams: function (params) {
|
||
|
var result = [];
|
||
|
|
||
|
Object.keys(params).sort().forEach(function (key) {
|
||
|
if (typeof params[key] !== 'object') {
|
||
|
result.push(key + '=' + encodeURIComponent(params[key]));
|
||
|
}
|
||
|
else {
|
||
|
result.push(prepareObject(key, params[key]));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return result.join('&');
|
||
|
},
|
||
|
|
||
|
request: function (method, region, service, host, 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/, ''),
|
||
|
|
||
|
canonical_uri = '/' + uri,
|
||
|
canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n',
|
||
|
signed_headers = 'content-encoding;host;x-amz-date',
|
||
|
canonical_request = method + '\n' + canonical_uri + '\n' + params + '\n' + canonical_headers + '\n' + signed_headers + '\n' + sha256(data),
|
||
|
credential_scope = date + '/' + region + '/' + service + '/' + 'aws4_request',
|
||
|
request_string = 'AWS4-HMAC-SHA256' + '\n' + amzdate + '\n' + credential_scope + '\n' + sha256(canonical_request),
|
||
|
key = AwsEC2.sign('AWS4' + AwsEC2.params.secret_key, date);
|
||
|
|
||
|
key = AwsEC2.sign(key, region);
|
||
|
key = AwsEC2.sign(key, service);
|
||
|
key = AwsEC2.sign(key, 'aws4_request');
|
||
|
|
||
|
var request = new HttpRequest(),
|
||
|
url = 'https://' + host + canonical_uri + '?' + params;
|
||
|
|
||
|
if (typeof AwsEC2.params.proxy !== 'undefined' && AwsEC2.params.proxy !== '') {
|
||
|
request.setProxy(AwsEC2.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=' + AwsEC2.params.access_key + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + hmac('sha256', key, request_string));
|
||
|
|
||
|
Zabbix.log(4, '[ AWS EC2 ] Sending request: ' + url);
|
||
|
|
||
|
response = request.post(url, data);
|
||
|
|
||
|
Zabbix.log(4, '[ AWS EC2 ] Received response with status code ' + request.getStatus() + ': ' + response);
|
||
|
|
||
|
if (request.getStatus() !== 200) {
|
||
|
throw 'Request failed with status code ' + request.getStatus() + ': ' + response;
|
||
|
}
|
||
|
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.';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return JSON.parse(response);
|
||
|
},
|
||
|
|
||
|
tagToNameInstances: function (instance) {
|
||
|
if (!Array.isArray(instance))
|
||
|
instance = [instance];
|
||
|
instance.forEach(function (item, index, instance_array) {
|
||
|
if (typeof item !== 'object'
|
||
|
|| typeof item.instancesSet !== 'object'
|
||
|
|| typeof item.instancesSet.item !== 'object'
|
||
|
|| item.instancesSet.item.hasOwnProperty('instanceId') === false)
|
||
|
throw 'Failed response parse. Check debug log for more information.';
|
||
|
var instanceName = item.instancesSet.item.instanceId
|
||
|
if (typeof item.instancesSet.item.tagSet === 'object'
|
||
|
&& typeof item.instancesSet.item.tagSet.item === 'object') {
|
||
|
if (!Array.isArray(item.instancesSet.item.tagSet.item))
|
||
|
item.instancesSet.item.tagSet.item = [item.instancesSet.item.tagSet.item];
|
||
|
item.instancesSet.item.tagSet.item.forEach(
|
||
|
function (tag) {
|
||
|
if (tag.hasOwnProperty('key') && tag.key === 'Name') {
|
||
|
instanceName = tag.value;
|
||
|
}
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
instance_array[index]['instanceName'] = instanceName;
|
||
|
});
|
||
|
|
||
|
return instance;
|
||
|
},
|
||
|
|
||
|
listInstances: function () {
|
||
|
var payload = {};
|
||
|
|
||
|
payload['Action'] = 'DescribeInstances',
|
||
|
payload['Version'] = '2016-11-15'
|
||
|
|
||
|
result = AwsEC2.request('POST', AwsEC2.params.region, 'ec2', 'ec2.' + AwsEC2.params.region + '.amazonaws.com', AwsEC2.prepareParams(payload), '', '');
|
||
|
|
||
|
if (typeof result !== 'object'
|
||
|
|| typeof result.DescribeInstancesResponse !== 'object'
|
||
|
|| typeof result.DescribeInstancesResponse.reservationSet !== 'object') {
|
||
|
throw 'Cannot get EC2 instance list from AWS API. Check debug log for more information.';
|
||
|
}
|
||
|
|
||
|
if (result.DescribeInstancesResponse.reservationSet === null)
|
||
|
return [];
|
||
|
|
||
|
if (typeof result.DescribeInstancesResponse.reservationSet.item !== 'object')
|
||
|
throw 'Cannot get EC2 instance list from AWS API. Check debug log for more information.';
|
||
|
|
||
|
return AwsEC2.tagToNameInstances(result.DescribeInstancesResponse.reservationSet.item);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
try {
|
||
|
AwsEC2.setParams(JSON.parse(value));
|
||
|
|
||
|
return JSON.stringify(AwsEC2.listInstances());
|
||
|
}
|
||
|
catch (error) {
|
||
|
error += (String(error).endsWith('.')) ? '' : '.';
|
||
|
Zabbix.log(3, '[ AWS EC2 ] ERROR: ' + error);
|
||
|
return JSON.stringify({ 'error': error });
|
||
|
}
|
||
|
filter:
|
||
|
evaltype: AND
|
||
|
conditions:
|
||
|
- macro: '{#AWS.EC2.INSTANCE.NAME}'
|
||
|
value: '{$AWS.EC2.LLD.FILTER.NAME.MATCHES}'
|
||
|
formulaid: A
|
||
|
- macro: '{#AWS.EC2.INSTANCE.NAME}'
|
||
|
value: '{$AWS.EC2.LLD.FILTER.NAME.NOT_MATCHES}'
|
||
|
operator: NOT_MATCHES_REGEX
|
||
|
formulaid: B
|
||
|
description: 'Get EC2 instances.'
|
||
|
host_prototypes:
|
||
|
- uuid: c4c830c727294b07926c39b00cf19046
|
||
|
host: '{#AWS.EC2.INSTANCE.ID}'
|
||
|
name: '{#AWS.EC2.INSTANCE.NAME}'
|
||
|
group_links:
|
||
|
- group:
|
||
|
name: 'Virtual machines'
|
||
|
templates:
|
||
|
- name: 'AWS EC2 by HTTP'
|
||
|
macros:
|
||
|
- macro: '{$AWS.EC2.INSTANCE.ID}'
|
||
|
value: '{#AWS.EC2.INSTANCE.ID}'
|
||
|
description: 'EC2 instance ID.'
|
||
|
custom_interfaces: 'YES'
|
||
|
interfaces:
|
||
|
- ip: '{#AWS.EC2.INSTANCE.ID}'
|
||
|
timeout: 15s
|
||
|
parameters:
|
||
|
- name: access_key
|
||
|
value: '{$AWS.ACCESS.KEY.ID}'
|
||
|
- name: secret_key
|
||
|
value: '{$AWS.SECRET.ACCESS.KEY}'
|
||
|
- name: region
|
||
|
value: '{$AWS.REGION}'
|
||
|
- name: proxy
|
||
|
value: '{$AWS.PROXY}'
|
||
|
lld_macro_paths:
|
||
|
- lld_macro: '{#AWS.EC2.INSTANCE.ID}'
|
||
|
path: $.instancesSet.item.instanceId
|
||
|
- lld_macro: '{#AWS.EC2.INSTANCE.NAME}'
|
||
|
path: $.instanceName
|
||
|
- uuid: 44b68894d68c45ec9a5ea787c975ae16
|
||
|
name: 'ECS clusters discovery'
|
||
|
type: SCRIPT
|
||
|
key: aws.ecs.discovery
|
||
|
delay: 12h
|
||
|
params: |
|
||
|
var AwsECS = {
|
||
|
params: {},
|
||
|
setParams: function (params) {
|
||
|
['access_key', 'region', 'secret_key'].forEach(function (field) {
|
||
|
if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') {
|
||
|
throw 'Required param is not set: "' + field + '".';
|
||
|
}
|
||
|
});
|
||
|
AwsECS.params = 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;
|
||
|
|
||
|
},
|
||
|
|
||
|
sign: function (key, message) {
|
||
|
var hex = hmac('sha256', key, message);
|
||
|
if ((hex.length % 2) === 1) {
|
||
|
throw 'Invalid length of a hex string!';
|
||
|
}
|
||
|
var result = new Int8Array(hex.length / 2);
|
||
|
for (var i = 0, b = 0; i < hex.length; i += 2, b++) {
|
||
|
result[b] = parseInt(hex.substring(i, i + 2), 16);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
|
||
|
},
|
||
|
|
||
|
prepareParams: function (params) {
|
||
|
var result = [];
|
||
|
Object.keys(params).sort().forEach(function (key) {
|
||
|
if (typeof params[key] !== 'object') {
|
||
|
result.push(key + '=' + encodeURIComponent(params[key]));
|
||
|
}
|
||
|
else {
|
||
|
result.push(prepareObject(key, params[key]));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return result.join('&');
|
||
|
|
||
|
},
|
||
|
|
||
|
request: function (method, region, service, host, 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/, ''),
|
||
|
canonical_uri = '/' + uri,
|
||
|
canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n',
|
||
|
signed_headers = 'content-encoding;host;x-amz-date',
|
||
|
canonical_request = method + '\n' + canonical_uri + '\n' + params + '\n' + canonical_headers + '\n' + signed_headers + '\n' + sha256(data),
|
||
|
credential_scope = date + '/' + region + '/' + service + '/' + 'aws4_request',
|
||
|
request_string = 'AWS4-HMAC-SHA256' + '\n' + amzdate + '\n' + credential_scope + '\n' + sha256(canonical_request),
|
||
|
key = AwsECS.sign('AWS4' + AwsECS.params.secret_key, date);
|
||
|
key = AwsECS.sign(key, region);
|
||
|
key = AwsECS.sign(key, service);
|
||
|
key = AwsECS.sign(key, 'aws4_request');
|
||
|
var request = new HttpRequest(),
|
||
|
url = 'https://' + host + canonical_uri + '?' + params;
|
||
|
if (typeof AwsECS.params.proxy !== 'undefined' && AwsECS.params.proxy !== '') {
|
||
|
request.setProxy(AwsECS.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/x-www-form-urlencoded');
|
||
|
request.addHeader('Content-Encoding: amz-1.0');
|
||
|
request.addHeader('Authorization: ' + 'AWS4-HMAC-SHA256 Credential=' + AwsECS.params.access_key + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + hmac('sha256', key, request_string));
|
||
|
|
||
|
Zabbix.log(4, '[ AWS ECS ] Sending request: ' + url);
|
||
|
|
||
|
response = request.post(url, data);
|
||
|
|
||
|
Zabbix.log(4, '[ AWS ECS ] 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) {
|
||
|
throw 'Failed to parse response received from AWS API. Check debug log for more information.';
|
||
|
}
|
||
|
|
||
|
return response;
|
||
|
|
||
|
},
|
||
|
|
||
|
listClusters: function () {
|
||
|
var payload = {},
|
||
|
result,
|
||
|
ECSClusters,
|
||
|
data = [];
|
||
|
payload['Action'] = 'ListClusters';
|
||
|
payload['Version'] = '2014-11-13';
|
||
|
result = AwsECS.request('POST', AwsECS.params.region, 'ecs', 'ecs.' + AwsECS.params.region + '.amazonaws.com', AwsECS.prepareParams(payload), '', '');
|
||
|
ECSClusters = AwsECS.getField(result, 'ListClustersResponse.ListClustersResult.clusterArns')
|
||
|
for (k in ECSClusters) {
|
||
|
clusters = ECSClusters[k];
|
||
|
json = {};
|
||
|
input = clusters.split('/');
|
||
|
for (var i = 1; i < input.length; i += 2) {
|
||
|
json[input[i]] = input[i + 1];
|
||
|
}
|
||
|
data.push({
|
||
|
'clusters_name': input[1],
|
||
|
});
|
||
|
}
|
||
|
if (Array.isArray(data))
|
||
|
return data;
|
||
|
else
|
||
|
return [data];
|
||
|
|
||
|
},
|
||
|
|
||
|
decribeClusters: function (cluster_name) {
|
||
|
var payload = {},
|
||
|
result;
|
||
|
payload['Action'] = 'DescribeClusters';
|
||
|
payload['Version'] = '2014-11-13';
|
||
|
payload['clusters.clusterName'] = cluster_name;
|
||
|
payload['include.statistics'] = 'STATISTICS';
|
||
|
result = AwsECS.request('POST', AwsECS.params.region, 'ecs', 'ecs.' + AwsECS.params.region + '.amazonaws.com', AwsECS.prepareParams(payload), '', '');
|
||
|
|
||
|
return result;
|
||
|
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
try {
|
||
|
AwsECS.setParams(JSON.parse(value));
|
||
|
var clusters = AwsECS.listClusters(),
|
||
|
infrastructure = [],
|
||
|
metrics = ['runningEC2TasksCount', 'pendingEC2TasksCount', 'activeEC2ServiceCount', 'drainingEC2ServiceCount'],
|
||
|
ECSClusters = [],
|
||
|
DescribeClusters = [];
|
||
|
DescribeClusters = clusters.map(function (cluster) {
|
||
|
ECSClusters = AwsECS.getField(AwsECS.decribeClusters(cluster.clusters_name), 'DescribeClustersResponse.DescribeClustersResult.clusters')
|
||
|
for (k in ECSClusters) {
|
||
|
var ECS2 = 0;
|
||
|
statistic = AwsECS.getField(ECSClusters[k], 'statistics');
|
||
|
statistic.forEach(function (id) {
|
||
|
for (i in metrics) {
|
||
|
if (AwsECS.getField(id, 'name') === metrics[i]) {
|
||
|
ECS2 += Number(AwsECS.getField(id, 'value'));
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
infrastructure = (ECS2 > 0) ? 'use_ecs2' : 'serverless';
|
||
|
|
||
|
return {
|
||
|
'clusterName': ECSClusters[k].clusterName,
|
||
|
'status': ECSClusters[k].status,
|
||
|
'infrastructure': infrastructure
|
||
|
}
|
||
|
|
||
|
}
|
||
|
})
|
||
|
return JSON.stringify(DescribeClusters);
|
||
|
}
|
||
|
catch (error) {
|
||
|
error += (String(error).endsWith('.')) ? '' : '.';
|
||
|
Zabbix.log(3, '[ AWS ECS ] ERROR: ' + error);
|
||
|
return JSON.stringify({ 'error': error });
|
||
|
}
|
||
|
filter:
|
||
|
evaltype: AND
|
||
|
conditions:
|
||
|
- macro: '{#AWS.ECS.CLUSTER.NAME}'
|
||
|
value: '{$AWS.ECS.LLD.FILTER.NAME.MATCHES}'
|
||
|
formulaid: A
|
||
|
- macro: '{#AWS.ECS.CLUSTER.NAME}'
|
||
|
value: '{$AWS.ECS.LLD.FILTER.NAME.NOT_MATCHES}'
|
||
|
operator: NOT_MATCHES_REGEX
|
||
|
formulaid: B
|
||
|
- macro: '{#AWS.ECS.CLUSTER.STATUS}'
|
||
|
value: '{$AWS.ECS.LLD.FILTER.STATUS.MATCHES}'
|
||
|
formulaid: C
|
||
|
- macro: '{#AWS.ECS.CLUSTER.STATUS}'
|
||
|
value: '{$AWS.ECS.LLD.FILTER.STATUS.NOT_MATCHES}'
|
||
|
operator: NOT_MATCHES_REGEX
|
||
|
formulaid: D
|
||
|
description: 'Get ECS clusters.'
|
||
|
host_prototypes:
|
||
|
- uuid: 71072e5a149e45b293946866f8220c07
|
||
|
host: '{#AWS.ECS.CLUSTER.NAME}'
|
||
|
name: '{#AWS.ECS.CLUSTER.NAME}'
|
||
|
group_links:
|
||
|
- group:
|
||
|
name: Applications
|
||
|
macros:
|
||
|
- macro: '{$AWS.ECS.CLUSTER.NAME}'
|
||
|
value: '{#AWS.ECS.CLUSTER.NAME}'
|
||
|
description: 'ECS cluster name.'
|
||
|
timeout: 15s
|
||
|
parameters:
|
||
|
- name: access_key
|
||
|
value: '{$AWS.ACCESS.KEY.ID}'
|
||
|
- name: secret_key
|
||
|
value: '{$AWS.SECRET.ACCESS.KEY}'
|
||
|
- name: region
|
||
|
value: '{$AWS.REGION}'
|
||
|
- name: proxy
|
||
|
value: '{$AWS.PROXY}'
|
||
|
lld_macro_paths:
|
||
|
- lld_macro: '{#AWS.ECS.CLUSTER.NAME}'
|
||
|
path: $.clusterName
|
||
|
- lld_macro: '{#AWS.ECS.CLUSTER.STATUS}'
|
||
|
path: $.status
|
||
|
- lld_macro: '{#AWS.ECS.CLUSTER.INFRASTRUCTURE}'
|
||
|
path: $.infrastructure
|
||
|
overrides:
|
||
|
- name: Serverless
|
||
|
step: '1'
|
||
|
filter:
|
||
|
conditions:
|
||
|
- macro: '{#AWS.ECS.CLUSTER.INFRASTRUCTURE}'
|
||
|
value: ^serverless$
|
||
|
formulaid: A
|
||
|
operations:
|
||
|
- operationobject: HOST_PROTOTYPE
|
||
|
operator: REGEXP
|
||
|
templates:
|
||
|
- name: 'AWS ECS Serverless Cluster by HTTP'
|
||
|
- name: 'Use EC2 Infrastructure'
|
||
|
step: '2'
|
||
|
filter:
|
||
|
conditions:
|
||
|
- macro: '{#AWS.ECS.CLUSTER.INFRASTRUCTURE}'
|
||
|
value: ^use_ecs2$
|
||
|
formulaid: A
|
||
|
operations:
|
||
|
- operationobject: HOST_PROTOTYPE
|
||
|
operator: REGEXP
|
||
|
templates:
|
||
|
- name: 'AWS ECS Cluster by HTTP'
|
||
|
- uuid: c1127e674b7548b2802cd8771f3a4768
|
||
|
name: 'RDS instances discovery'
|
||
|
type: SCRIPT
|
||
|
key: aws.rds.discovery
|
||
|
delay: 12h
|
||
|
params: |
|
||
|
var AwsRDS = {
|
||
|
params: {},
|
||
|
|
||
|
setParams: function (params) {
|
||
|
['access_key', 'region', 'secret_key'].forEach(function (field) {
|
||
|
if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') {
|
||
|
throw 'Required param is not set: "' + field + '".';
|
||
|
}
|
||
|
});
|
||
|
|
||
|
AwsRDS.params = params;
|
||
|
},
|
||
|
|
||
|
sign: function (key, message) {
|
||
|
var hex = hmac('sha256', key, message);
|
||
|
|
||
|
if ((hex.length % 2) === 1) {
|
||
|
throw 'Invalid length of a hex string!';
|
||
|
}
|
||
|
|
||
|
var result = new Int8Array(hex.length / 2);
|
||
|
for (var i = 0, b = 0; i < hex.length; i += 2, b++) {
|
||
|
result[b] = parseInt(hex.substring(i, i + 2), 16);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
},
|
||
|
|
||
|
prepareParams: function (params) {
|
||
|
var result = [];
|
||
|
|
||
|
Object.keys(params).sort().forEach(function (key) {
|
||
|
if (typeof params[key] !== 'object') {
|
||
|
result.push(key + '=' + encodeURIComponent(params[key]));
|
||
|
}
|
||
|
else {
|
||
|
result.push(prepareObject(key, params[key]));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return result.join('&');
|
||
|
},
|
||
|
|
||
|
request: function (method, region, service, host, 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/, ''),
|
||
|
|
||
|
canonical_uri = '/' + uri,
|
||
|
canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n',
|
||
|
signed_headers = 'content-encoding;host;x-amz-date',
|
||
|
canonical_request = method + '\n' + canonical_uri + '\n' + params + '\n' + canonical_headers + '\n' + signed_headers + '\n' + sha256(data),
|
||
|
credential_scope = date + '/' + region + '/' + service + '/' + 'aws4_request',
|
||
|
request_string = 'AWS4-HMAC-SHA256' + '\n' + amzdate + '\n' + credential_scope + '\n' + sha256(canonical_request),
|
||
|
key = AwsRDS.sign('AWS4' + AwsRDS.params.secret_key, date);
|
||
|
|
||
|
key = AwsRDS.sign(key, region);
|
||
|
key = AwsRDS.sign(key, service);
|
||
|
key = AwsRDS.sign(key, 'aws4_request');
|
||
|
|
||
|
var request = new HttpRequest(),
|
||
|
url = 'https://' + host + canonical_uri + '?' + params;
|
||
|
|
||
|
if (typeof AwsRDS.params.proxy !== 'undefined' && AwsRDS.params.proxy !== '') {
|
||
|
request.setProxy(AwsRDS.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=' + AwsRDS.params.access_key + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + hmac('sha256', key, request_string));
|
||
|
|
||
|
Zabbix.log(4, '[ AWS RDS ] Sending request: ' + url);
|
||
|
|
||
|
response = request.post(url, data);
|
||
|
|
||
|
Zabbix.log(4, '[ AWS RDS ] 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) {
|
||
|
throw 'Failed to parse response received from AWS API. Check debug log for more information.';
|
||
|
}
|
||
|
|
||
|
return response;
|
||
|
},
|
||
|
|
||
|
listInstances: function () {
|
||
|
var payload = {};
|
||
|
|
||
|
payload['Action'] = 'DescribeDBInstances',
|
||
|
payload['Version'] = '2014-10-31'
|
||
|
|
||
|
result = AwsRDS.request('POST', AwsRDS.params.region, 'rds', 'rds.' + AwsRDS.params.region + '.amazonaws.com', AwsRDS.prepareParams(payload), '', '');
|
||
|
|
||
|
if (typeof result !== 'object'
|
||
|
|| typeof result.DescribeDBInstancesResponse !== 'object'
|
||
|
|| typeof result.DescribeDBInstancesResponse.DescribeDBInstancesResult !== 'object'
|
||
|
|| typeof result.DescribeDBInstancesResponse.DescribeDBInstancesResult.DBInstances !== 'object') {
|
||
|
throw 'Cannot get DB instance list from AWS RDS API. Check debug log for more information.';
|
||
|
}
|
||
|
if (Array.isArray(result.DescribeDBInstancesResponse.DescribeDBInstancesResult.DBInstances))
|
||
|
return result.DescribeDBInstancesResponse.DescribeDBInstancesResult.DBInstances;
|
||
|
else
|
||
|
return [result.DescribeDBInstancesResponse.DescribeDBInstancesResult.DBInstances];
|
||
|
|
||
|
}
|
||
|
};
|
||
|
|
||
|
try {
|
||
|
AwsRDS.setParams(JSON.parse(value));
|
||
|
|
||
|
return JSON.stringify(AwsRDS.listInstances());
|
||
|
}
|
||
|
catch (error) {
|
||
|
error += (String(error).endsWith('.')) ? '' : '.';
|
||
|
Zabbix.log(3, '[ AWS RDS ] ERROR: ' + error);
|
||
|
return JSON.stringify({ 'error': error });
|
||
|
}
|
||
|
filter:
|
||
|
evaltype: AND
|
||
|
conditions:
|
||
|
- macro: '{#AWS.RDS.INSTANCE.ID}'
|
||
|
value: '{$AWS.RDS.LLD.FILTER.NAME.MATCHES}'
|
||
|
formulaid: A
|
||
|
- macro: '{#AWS.RDS.INSTANCE.ID}'
|
||
|
value: '{$AWS.RDS.LLD.FILTER.NAME.NOT_MATCHES}'
|
||
|
operator: NOT_MATCHES_REGEX
|
||
|
formulaid: B
|
||
|
description: 'Get RDS instances.'
|
||
|
host_prototypes:
|
||
|
- uuid: 799663c52a644f78aa3b3c14d4cc7235
|
||
|
host: '{#AWS.RDS.INSTANCE.ID}'
|
||
|
name: '{#AWS.RDS.INSTANCE.ID}'
|
||
|
group_links:
|
||
|
- group:
|
||
|
name: Databases
|
||
|
templates:
|
||
|
- name: 'AWS RDS instance by HTTP'
|
||
|
macros:
|
||
|
- macro: '{$AWS.RDS.INSTANCE.ID}'
|
||
|
value: '{#AWS.RDS.INSTANCE.ID}'
|
||
|
description: 'RDS instance ID.'
|
||
|
custom_interfaces: 'YES'
|
||
|
interfaces:
|
||
|
- ip: '{#AWS.RDS.INSTANCE.ID}'
|
||
|
timeout: 15s
|
||
|
parameters:
|
||
|
- name: access_key
|
||
|
value: '{$AWS.ACCESS.KEY.ID}'
|
||
|
- name: secret_key
|
||
|
value: '{$AWS.SECRET.ACCESS.KEY}'
|
||
|
- name: region
|
||
|
value: '{$AWS.REGION}'
|
||
|
- name: proxy
|
||
|
value: '{$AWS.PROXY}'
|
||
|
lld_macro_paths:
|
||
|
- lld_macro: '{#AWS.RDS.INSTANCE.ID}'
|
||
|
path: $.DBInstanceIdentifier
|
||
|
- uuid: ab6a97a108fb4dbc9fd1e07378721ffe
|
||
|
name: 'S3 buckets discovery'
|
||
|
type: SCRIPT
|
||
|
key: aws.s3.discovery
|
||
|
delay: 12h
|
||
|
params: |
|
||
|
var AwsS3 = {
|
||
|
params: {},
|
||
|
|
||
|
setParams: function (params) {
|
||
|
['access_key', 'secret_key'].forEach(function (field) {
|
||
|
if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') {
|
||
|
throw 'Required param is not set: "' + field + '".';
|
||
|
}
|
||
|
});
|
||
|
|
||
|
AwsS3.params = params;
|
||
|
},
|
||
|
|
||
|
sign: function (key, message) {
|
||
|
var hex = hmac('sha256', key, message);
|
||
|
|
||
|
if ((hex.length % 2) === 1) {
|
||
|
throw 'Invalid length of a hex string!';
|
||
|
}
|
||
|
|
||
|
var result = new Int8Array(hex.length / 2);
|
||
|
for (var i = 0, b = 0; i < hex.length; i += 2, b++) {
|
||
|
result[b] = parseInt(hex.substring(i, i + 2), 16);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
},
|
||
|
|
||
|
prepareParams: function (params) {
|
||
|
var result = [];
|
||
|
|
||
|
Object.keys(params).sort().forEach(function (key) {
|
||
|
if (typeof params[key] !== 'object') {
|
||
|
result.push(key + '=' + encodeURIComponent(params[key]));
|
||
|
}
|
||
|
else {
|
||
|
result.push(prepareObject(key, params[key]));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return result.join('&');
|
||
|
},
|
||
|
|
||
|
request: function (method, region, service, host, 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/, ''),
|
||
|
|
||
|
canonical_uri = '/' + uri,
|
||
|
canonical_headers = 'content-encoding:amz-1.0\n' + 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n',
|
||
|
signed_headers = 'content-encoding;host;x-amz-date',
|
||
|
canonical_request = method + '\n' + canonical_uri + '\n' + params + '\n' + canonical_headers + '\n' + signed_headers + '\n' + sha256(data),
|
||
|
credential_scope = date + '/' + region + '/' + service + '/' + 'aws4_request',
|
||
|
request_string = 'AWS4-HMAC-SHA256' + '\n' + amzdate + '\n' + credential_scope + '\n' + sha256(canonical_request),
|
||
|
key = AwsS3.sign('AWS4' + AwsS3.params.secret_key, date);
|
||
|
|
||
|
key = AwsS3.sign(key, region);
|
||
|
key = AwsS3.sign(key, service);
|
||
|
key = AwsS3.sign(key, 'aws4_request');
|
||
|
|
||
|
var request = new HttpRequest(),
|
||
|
url = 'https://' + host + canonical_uri + '?' + params;
|
||
|
|
||
|
if (typeof AwsS3.params.proxy !== 'undefined' && AwsS3.params.proxy !== '') {
|
||
|
request.setProxy(AwsS3.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=' + AwsS3.params.access_key + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + hmac('sha256', key, request_string));
|
||
|
|
||
|
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 !== null) {
|
||
|
try {
|
||
|
response = XML.toJson(response);
|
||
|
}
|
||
|
catch (error) {
|
||
|
throw 'Failed to parse response received from AWS CloudWatch API. Check debug log for more information.';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return JSON.parse(response);
|
||
|
},
|
||
|
|
||
|
getBucketLocation: function (bucket_name) {
|
||
|
var payload = {};
|
||
|
|
||
|
payload['location'] = '',
|
||
|
|
||
|
result = AwsS3.request('GET', 'us-east-1', 's3', 's3.amazonaws.com', AwsS3.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';
|
||
|
},
|
||
|
|
||
|
listBuckets: function () {
|
||
|
var payload = {};
|
||
|
|
||
|
payload['Action'] = 'ListBuckets',
|
||
|
payload['Version'] = '2006-03-01',
|
||
|
|
||
|
result = AwsS3.request('GET', 'us-east-1', 's3', 's3.us-east-1.amazonaws.com', AwsS3.prepareParams(payload), '', '');
|
||
|
if (typeof result !== 'object'
|
||
|
|| typeof result.ListAllMyBucketsResult !== 'object'
|
||
|
|| typeof result.ListAllMyBucketsResult.Buckets !== 'object') {
|
||
|
throw 'Cannot get buckets list from AWS S3 API. Check debug log for more information.';
|
||
|
}
|
||
|
if (result.ListAllMyBucketsResult.Buckets === null)
|
||
|
return []
|
||
|
if (typeof result.ListAllMyBucketsResult.Buckets.Bucket !== 'object') {
|
||
|
throw 'Cannot get buckets list from AWS S3 API. Check debug log for more information.';
|
||
|
}
|
||
|
|
||
|
var buckets = [];
|
||
|
if (!Array.isArray(result.ListAllMyBucketsResult.Buckets.Bucket))
|
||
|
buckets = [result.ListAllMyBucketsResult.Buckets.Bucket]
|
||
|
else
|
||
|
buckets = result.ListAllMyBucketsResult.Buckets.Bucket
|
||
|
buckets.forEach(
|
||
|
function (bucket, index, buckets_array) {
|
||
|
if (!bucket.hasOwnProperty('Name'))
|
||
|
throw 'Cannot get location for bucket. Check debug log for more information.';
|
||
|
buckets_array[index]['location'] = AwsS3.getBucketLocation(bucket['Name']);
|
||
|
});
|
||
|
|
||
|
return buckets;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
try {
|
||
|
AwsS3.setParams(JSON.parse(value));
|
||
|
|
||
|
return JSON.stringify(AwsS3.listBuckets());
|
||
|
}
|
||
|
catch (error) {
|
||
|
error += (String(error).endsWith('.')) ? '' : '.';
|
||
|
Zabbix.log(3, '[ AWS S3 ] ERROR: ' + error);
|
||
|
return JSON.stringify({ 'error': error });
|
||
|
}
|
||
|
filter:
|
||
|
evaltype: AND
|
||
|
conditions:
|
||
|
- macro: '{#AWS.S3.NAME}'
|
||
|
value: '{$AWS.S3.LLD.FILTER.NAME.MATCHES}'
|
||
|
formulaid: A
|
||
|
- macro: '{#AWS.S3.NAME}'
|
||
|
value: '{$AWS.S3.LLD.FILTER.NAME.NOT_MATCHES}'
|
||
|
operator: NOT_MATCHES_REGEX
|
||
|
formulaid: B
|
||
|
description: 'Get S3 bucket instances.'
|
||
|
host_prototypes:
|
||
|
- uuid: e45bd9810ea14718b17b875aad3fc544
|
||
|
host: '{#AWS.S3.NAME}'
|
||
|
name: '{#AWS.S3.NAME}'
|
||
|
group_links:
|
||
|
- group:
|
||
|
name: Applications
|
||
|
group_prototypes:
|
||
|
- name: '{#AWS.S3.REGION}'
|
||
|
templates:
|
||
|
- name: 'AWS S3 bucket by HTTP'
|
||
|
macros:
|
||
|
- macro: '{$AWS.REGION}'
|
||
|
value: '{#AWS.S3.REGION}'
|
||
|
description: 'Amazon S3 region code.'
|
||
|
- macro: '{$AWS.S3.BUCKET.NAME}'
|
||
|
value: '{#AWS.S3.NAME}'
|
||
|
description: 'S3 bucket name.'
|
||
|
- macro: '{$AWS.S3.FILTER.ID}'
|
||
|
value: '1'
|
||
|
description: 'S3 bucket requests filter identifier.'
|
||
|
custom_interfaces: 'YES'
|
||
|
interfaces:
|
||
|
- ip: '{#AWS.S3.NAME}'
|
||
|
timeout: 15s
|
||
|
parameters:
|
||
|
- name: access_key
|
||
|
value: '{$AWS.ACCESS.KEY.ID}'
|
||
|
- name: secret_key
|
||
|
value: '{$AWS.SECRET.ACCESS.KEY}'
|
||
|
- name: proxy
|
||
|
value: '{$AWS.PROXY}'
|
||
|
lld_macro_paths:
|
||
|
- lld_macro: '{#AWS.S3.NAME}'
|
||
|
path: $.Name
|
||
|
- lld_macro: '{#AWS.S3.REGION}'
|
||
|
path: $.location
|
||
|
tags:
|
||
|
- tag: class
|
||
|
value: software
|
||
|
- tag: target
|
||
|
value: aws
|
||
|
macros:
|
||
|
- macro: '{$AWS.ACCESS.KEY.ID}'
|
||
|
description: 'Access key ID.'
|
||
|
- macro: '{$AWS.EC2.LLD.FILTER.NAME.MATCHES}'
|
||
|
value: '.*'
|
||
|
description: 'Filter of discoverable EC2 instances by namespace.'
|
||
|
- macro: '{$AWS.EC2.LLD.FILTER.NAME.NOT_MATCHES}'
|
||
|
value: CHANGE_IF_NEEDED
|
||
|
description: 'Filter to exclude discovered EC2 instances by namespace.'
|
||
|
- macro: '{$AWS.ECS.LLD.FILTER.NAME.MATCHES}'
|
||
|
value: '.*'
|
||
|
description: 'Filter of discoverable ECS clusters by name.'
|
||
|
- macro: '{$AWS.ECS.LLD.FILTER.NAME.NOT_MATCHES}'
|
||
|
value: CHANGE_IF_NEEDED
|
||
|
description: 'Filter to exclude discovered ECS clusters by name.'
|
||
|
- macro: '{$AWS.ECS.LLD.FILTER.STATUS.MATCHES}'
|
||
|
value: ACTIVE
|
||
|
description: 'Filter of discoverable ECS clusters by status.'
|
||
|
- macro: '{$AWS.ECS.LLD.FILTER.STATUS.NOT_MATCHES}'
|
||
|
value: CHANGE_IF_NEEDED
|
||
|
description: 'Filter to exclude discovered ECS clusters by status.'
|
||
|
- macro: '{$AWS.PROXY}'
|
||
|
description: 'Sets HTTP proxy value. If this macro is empty then no proxy is used.'
|
||
|
- macro: '{$AWS.RDS.LLD.FILTER.NAME.MATCHES}'
|
||
|
value: '.*'
|
||
|
description: 'Filter of discoverable RDS instances by namespace.'
|
||
|
- macro: '{$AWS.RDS.LLD.FILTER.NAME.NOT_MATCHES}'
|
||
|
value: CHANGE_IF_NEEDED
|
||
|
description: 'Filter to exclude discovered RDS instances by namespace.'
|
||
|
- macro: '{$AWS.REGION}'
|
||
|
value: us-west-1
|
||
|
description: 'Amazon EC2 region code.'
|
||
|
- macro: '{$AWS.S3.LLD.FILTER.NAME.MATCHES}'
|
||
|
value: '.*'
|
||
|
description: 'Filter of discoverable S3 buckets by namespace.'
|
||
|
- macro: '{$AWS.S3.LLD.FILTER.NAME.NOT_MATCHES}'
|
||
|
value: CHANGE_IF_NEEDED
|
||
|
description: 'Filter to exclude discovered S3 buckets by namespace.'
|
||
|
- macro: '{$AWS.SECRET.ACCESS.KEY}'
|
||
|
type: SECRET_TEXT
|
||
|
description: 'Secret access key.'
|