-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
125 lines (97 loc) · 3.25 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
'use strict'
const EventEmitter = require('events').EventEmitter
const request = require('request')
module.exports = function plugin (options) {
return new Processor(options)
}
class Processor extends EventEmitter {
constructor (options) {
if (!options) options = {}
super()
let endpoint = options.endpoint || process.env.ECS_CONTAINER_METADATA_URI || ''
if (endpoint.endsWith('/')) endpoint = endpoint.slice(0, -1)
if (options.version === 2) {
endpoint = endpoint || 'http://169.254.170.2/v2'
this._fetch = this._fetchV2.bind(this)
} else if (options.version === 3) {
if (!endpoint) {
throw new Error('The "endpoint" option or ECS_CONTAINER_METADATA_URI is required')
}
this._fetch = this._fetchV3.bind(this)
} else {
throw new Error('The "version" option must be one of 2, 3')
}
this._endpoint = endpoint
this._tags = null
}
start (callback) {
this._fetch((err, tags) => {
if (err) return callback(err)
this._tags = tags
callback()
})
}
stop (callback) {
this._tags = null
process.nextTick(callback)
}
process (metric) {
for (const k in this._tags) {
metric.tags[k] = this._tags[k]
}
this.emit('metric', metric)
}
_fetchV2 (callback) {
// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v2.html
// Fetch Task Metadata
request(`${this._endpoint}/metadata`, { json: true }, (err, res, body) => {
if (err) return callback(err)
if (res.statusCode < 200 || res.statusCode > 299) {
return callback(new Error(`HTTP ${res.statusCode}`))
}
const tags = {
cluster: body.Cluster,
region: extractRegionFromArn(body.TaskARN)
}
// TODO (!!): where can we get 'name' and 'image' from?
callback(null, tags)
})
}
_fetchV3 (callback) {
// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v3.html#task-metadata-endpoint-v3-response
// Fetch Task Metadata
request(`${this._endpoint}/task`, { json: true }, (err, res, body) => {
if (err) return callback(err)
if (res.statusCode < 200 || res.statusCode > 299) {
return callback(new Error(`HTTP ${res.statusCode}`))
}
const tags = {
cluster: body.Cluster,
region: extractRegionFromArn(body.TaskARN)
}
// Fetch metadata JSON for the container
request(`${this._endpoint}`, { json: true }, (err, res, body) => {
if (err) return callback(err)
if (res.statusCode < 200 || res.statusCode > 299) {
return callback(new Error(`HTTP ${res.statusCode}`))
}
// TODO (!): remove once tested in ECS
console.error('processor-ecs-tags: metadata JSON for the container')
console.error(require('util').inspect(body, { depth: null }))
tags.name = body.Name
tags.image = body.Image
callback(null, tags)
})
})
}
}
function extractRegionFromArn (arn) {
if (typeof arn !== 'string') {
throw new TypeError('The "arn" argument must be a string')
}
const region = arn.split(':')[3]
if (!arn.startsWith('arn:aws:ecs:') || !region) {
throw new Error('Unexpected ARN format: ' + arn)
}
return region
}