Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
jsumners-nr committed Sep 12, 2024
1 parent 5febab4 commit 7187bde
Show file tree
Hide file tree
Showing 6 changed files with 320 additions and 303 deletions.
7 changes: 4 additions & 3 deletions lib/metrics/names.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,12 @@ const HAPI = {

const UTILIZATION = {
AWS_ERROR: SUPPORTABILITY.UTILIZATION + '/aws/error',
PCF_ERROR: SUPPORTABILITY.UTILIZATION + '/pcf/error',
AZURE_ERROR: SUPPORTABILITY.UTILIZATION + '/azure/error',
GCP_ERROR: SUPPORTABILITY.UTILIZATION + '/gcp/error',
BOOT_ID_ERROR: SUPPORTABILITY.UTILIZATION + '/boot_id/error',
DOCKER_ERROR: SUPPORTABILITY.UTILIZATION + '/docker/error',
BOOT_ID_ERROR: SUPPORTABILITY.UTILIZATION + '/boot_id/error'
ECS_CONTAINER_ERROR: SUPPORTABILITY.UTILIZATION + '/ecs/container_id/error',
GCP_ERROR: SUPPORTABILITY.UTILIZATION + '/gcp/error',
PCF_ERROR: SUPPORTABILITY.UTILIZATION + '/pcf/error'
}

const CUSTOM_EVENTS = {
Expand Down
70 changes: 0 additions & 70 deletions lib/utilization/docker-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
'use strict'

const fs = require('node:fs')
const http = require('node:http')
const log = require('../logger').child({ component: 'docker-info' })
const common = require('./common')
const NAMES = require('../metrics/names')
Expand All @@ -20,7 +19,6 @@ const BOOT_ID_PROC_FILE = '/proc/sys/kernel/random/boot_id'
module.exports = {
clearVendorCache: clearDockerVendorCache,
getBootId,
getEcsContainerId,
getVendorInfo: fetchDockerVendorInfo
}

Expand All @@ -43,76 +41,8 @@ function getBootId(agent, callback, logger = log) {
}

logger.debug('Container boot id is not available in cgroups info')

if (hasAwsContainerApi() === false) {
// We don't seem to have a recognized location for getting the container
// identifier.
logger.debug('Container is not in a recognized ECS container, omitting boot info')
recordBootIdError(agent)
return callback(null, null)
}

getEcsContainerId({ agent, callback, logger })
})
}

/**
* Queries the AWS ECS metadata API to get the boot id.
*
* @param {object} params Function parameters.
* @param {object} params.agent Newrelic agent instance.
* @param {Function} params.callback Typical error first callback. The second
* parameter is the boot id as a string.
* @param {object} [params.logger] Internal logger instance.
*/
function getEcsContainerId({ agent, callback, logger }) {
const ecsApiUrl =
process.env.ECS_CONTAINER_METADATA_URI_V4 || process.env.ECS_CONTAINER_METADATA_URI
const req = http.request(ecsApiUrl, (res) => {
let body = Buffer.alloc(0)
res.on('data', (chunk) => {
body = Buffer.concat([body, chunk])
})
res.on('end', () => {
try {
const json = body.toString('utf8')
const data = JSON.parse(json)
if (data.DockerId == null) {
logger.debug('Failed to find DockerId in response, omitting boot info')
recordBootIdError(agent)
return callback(null, null)
}
callback(null, data.DockerId)
} catch (error) {
logger.debug('Failed to process ECS API response, omitting boot info: ' + error.message)
recordBootIdError(agent)
callback(null, null)
}
})
})

req.on('error', () => {
logger.debug('Failed to query ECS endpoint, omitting boot info')
recordBootIdError(agent)
callback(null, null)
})

req.end()
}

/**
* Inspects the running environment to determine if the AWS ECS metadata API
* is available.
*
* @see https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ec2-metadata.html
*
* @returns {boolean}
*/
function hasAwsContainerApi() {
if (process.env.ECS_CONTAINER_METADATA_URI_V4 != null) {
return true
}
return process.env.ECS_CONTAINER_METADATA_URI != null
}

/**
Expand Down
78 changes: 77 additions & 1 deletion lib/utilization/ecs-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@

'use strict'

const http = require('node:http')
const NAMES = require('../metrics/names')

module.exports = function fetchEcsInfo(
agent,
callback,
{
logger = require('../logger').child({ component: 'ecs-info' }),
getEcsContainerId = require('./docker-info').getEcsContainerId
getEcsContainerId = _getEcsContainerId,
hasAwsContainerApi = _hasAwsContainerApi,
recordIdError = _recordIdError
} = {}
) {
// Per spec, we do not have a `detect_ecs` key. Since ECS is a service of AWS,
Expand All @@ -19,9 +24,16 @@ module.exports = function fetchEcsInfo(
return setImmediate(callback, null)
}

if (hasAwsContainerApi() === false) {
logger.debug('ECS API not available, omitting ECS container id info')
recordIdError(agent)
return callback(null, null)
}

getEcsContainerId({
agent,
logger,
recordIdError,
callback: (error, dockerId) => {
if (error) {
return callback(error, null)
Expand All @@ -34,3 +46,67 @@ module.exports = function fetchEcsInfo(
}
})
}

/**
* Queries the AWS ECS metadata API to get the boot id.
*
* @param {object} params Function parameters.
* @param {object} params.agent Newrelic agent instance.
* @param {Function} params.callback Typical error first callback. The second
* parameter is the boot id as a string.
* @param {object} params.logger Internal logger instance.
* @param {function} params.recordIdError Function to record error metric.
*/
function _getEcsContainerId({ agent, callback, logger, recordIdError }) {
const ecsApiUrl =
process.env.ECS_CONTAINER_METADATA_URI_V4 || process.env.ECS_CONTAINER_METADATA_URI
const req = http.request(ecsApiUrl, (res) => {
let body = Buffer.alloc(0)
res.on('data', (chunk) => {
body = Buffer.concat([body, chunk])
})
res.on('end', () => {
try {
const json = body.toString('utf8')
const data = JSON.parse(json)
if (data.DockerId == null) {
logger.debug('Failed to find DockerId in response, omitting boot info')
recordIdError(agent)
return callback(null, null)
}
callback(null, data.DockerId)
} catch (error) {
logger.debug('Failed to process ECS API response, omitting boot info: ' + error.message)
recordIdError(agent)
callback(null, null)
}
})
})

req.on('error', () => {
logger.debug('Failed to query ECS endpoint, omitting boot info')
recordIdError(agent)
callback(null, null)
})

req.end()
}

/**
* Inspects the running environment to determine if the AWS ECS metadata API
* is available.
*
* @see https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ec2-metadata.html
*
* @returns {boolean}
*/
function _hasAwsContainerApi() {
if (process.env.ECS_CONTAINER_METADATA_URI_V4 != null) {
return true
}
return process.env.ECS_CONTAINER_METADATA_URI != null
}

function _recordIdError(agent) {
agent.metrics.getOrCreateMetric(NAMES.UTILIZATION.ECS_CONTAINER_ERROR).incrementCallCount()
}
1 change: 1 addition & 0 deletions test/integration/utilization/system-info.tap.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ test('pricing system-info aws', function (t) {
instanceId: 'test.id',
availabilityZone: 'us-west-2b'
})
t.same(systemInfo.vendors.ecs, { ecsDockerId: 'ecs-container-1' })

// This will throw an error if the sys info isn't being cached properly
t.ok(awsRedirect.isDone(), 'should exhaust nock endpoints')
Expand Down
Loading

0 comments on commit 7187bde

Please sign in to comment.