Source: segments/plugins/ec2_plugin.js

var Plugin = require('./plugin');
var logger = require('../../logger');
var http = require('http');

var EC2Plugin = {
  /**
   * A function to get the instance data from the EC2 metadata service.
   * @param {function} callback - The callback for the plugin loader.
   */
  getData: function(callback) {
    const METADATA_PATH = '/latest/dynamic/instance-identity/document';

    function populateMetadata(token) {
      const options = getOptions(
        METADATA_PATH,
        'GET',
        token ? { 'X-aws-ec2-metadata-token': token } : {}
      );

      Plugin.getPluginMetadata(options, function(err, data) {
        if (err || !data) {
          logger.getLogger().error('Error loading EC2 plugin metadata: ', err ? err.toString() : 'Could not retrieve data from IMDS.');
          callback();
          return;
        }

        const metadata = {
          ec2: {
            instance_id: data.instanceId,
            availability_zone: data.availabilityZone,
            instance_size: data.instanceType,
            ami_id: data.imageId
          }
        };
        callback(metadata);
      });
    }

    /**
     * This kicks off a requet to get a token used for requests to IMDSv2. If the request for the token
     * fails, we fall back to IMDSv1. Otherwise, the token will be used for an IMDSv2 request.
     */
    getToken(function(token) {
      if (token === null) {
        logger.getLogger().debug('EC2Plugin failed to get token from IMDSv2. Falling back to IMDSv1.');
      }

      populateMetadata(token);
    });
  },
  originName: 'AWS::EC2::Instance'
};

/**
 * Asynchronously retrieves a token used in requests to EC2 instance metadata service.
 * @param {function} callback - callback to plugin
 */
function getToken(callback) {
  const httpReq = http.__request ? http.__request : http.request;
  const TTL = 60; //seconds
  const TOKEN_PATH = '/latest/api/token';
  const options = getOptions(TOKEN_PATH, 'PUT', {
    'X-aws-ec2-metadata-token-ttl-seconds': TTL
  });

  let req = httpReq(options, function(res) {
    let body = '';

    res.on('data', function(chunk) {
      body += chunk;
    });

    res.on('end', function() {
      if (this.statusCode === 200 || this.statusCode === 300) {
        callback(body);
      } else {
        callback(null);
      }
    });
  });

  req.on('error', function() {
    callback(null);
  });

  req.on('timeout', function() {
    req.abort();
    callback(null);
  });

  req.setTimeout(Plugin.METADATA_TIMEOUT);
  req.end();
}

function getOptions(path, method, headers) {
  if (!method) {
    method = 'GET';
  }

  if (!headers) {
    headers = {};
  }

  return {
    host: '169.254.169.254',
    path: path,
    method: method,
    headers: headers
  };
}

module.exports = EC2Plugin;