/**
* @module google/metadata_server
*/
var http = require('http');
/**
* Google Cloud Metadata Server API convenience object. Metadata server stores
* metadata configured for each instance, this object allows you to easily communicate
* with Cliques instance metadata servers to easily retrieve metadata for an instance.
*
* For more information on Metadata servers, see
* [the Google Cloud Metadata Server Docs](https://cloud.google.com/compute/docs/storing-retrieving-metadata).
*
* @class
* @param {Object} [options] options object
* @param {String} [options.apiVersion='v1'] Google Metadata Server API version
* @param {String} [options.hostname='metadata.google.internal'] API hostname
* @param {String} [options.basepath='computeMetadata'] Basepath from API hostname
* @param {Object} [options.defaultHeaders={"Metadata-Flavor":"Google"}]
* @type {exports.MetadataServerAPI}
*/
var MetadataServerAPI = exports.MetadataServerAPI = function(options){
options = options || {};
this.apiVersion = options.apiVersion || 'v1';
this.hostname = 'metadata.google.internal';
this.basePath = 'computeMetadata';
this.defaultHeaders = {
"Metadata-Flavor": "Google"
};
};
/**
* Helper function to take boilerplate code out of request options generation.
*
* Takes a simplified options object and transforms to full options object
* to pass to http.request
*
* @param {Array} path_array base API path
* @param {Object} options simplified options object specific to this instance
* @param {String} [options.method='GET'] http method, defaults to 'GET'
* @param {Object} [options.query] query object, e.g. {k: 'v', k2: 'v2'}
* @param {Object} [options.headers] any additional headers to pass into request
* @returns {Object} Augmented options object to pass to http.request
* @private
*/
MetadataServerAPI.prototype._getOptions = function(path_array, options){
options = options || {};
var method = options.method || 'GET';
var query = options.query;
var headers = options.headers;
var root_path_arr = ['',this.basePath, this.apiVersion];
var full_path_arr = root_path_arr.concat(path_array);
var path = full_path_arr.join('/');
if (query){
path = [path, querystring.stringify(query)].join('?');
}
var new_options = {
path: path,
hostname: this.hostname,
method: method,
headers: this.defaultHeaders
};
if (headers){
Object.keys(headers).forEach(function(key){
if (headers.hasOwnProperty(key)){
new_options.headers[key] = headers[key]
}
})
}
return new_options;
};
/**
* Wrapper function to be used to send any API requests
*
* @param {Array} path_array path of API resource, provided as array
* @param {Object} [options] optional additional options object.
* Passed to _getOptions, see docstring there for details
* @param {Object} [data] optional POST or PUT JSON data. If provided,
* options.method arg must be set
* @param callback
* @private
*/
MetadataServerAPI.prototype._sendAPIRequest = function(path_array, options, data, callback){
// tedious handling of optional arguments
if (arguments.length == 2) {
callback = options;
data = false;
options = {}
} else if (arguments.length == 3){
callback = data;
data = false;
} else {
// Set default JSON data headers, if data is provided
data = JSON.stringify(data);
if (!options.hasOwnProperty("headers")) {
options.headers = {};
}
options.headers["Content-Type"] = "application/json";
options.headers["Content-Length"] = data.length;
}
var new_options = this._getOptions(path_array, options);
//options string just for returning to callback error handler
var options_str = 'path: '+new_options.path+', hostname: '+new_options.hostname+
', port: '+new_options.port+', method: '+new_options.method;
// now send request
var req = http.request(new_options, function(res){
if (res.statusCode == "400"){
return callback('HTTP ERROR: 400 REST API Request Error at ' + options_str)
}
// handle response body data, pass to callback as JSON
var body = '';
res.on('data', function(chunk){
body += chunk;
});
res.on('end', function(){
return callback(null, body);
});
});
// add error handler
req.on("error", function(e){
callback(e + ", Request options: " + options_str);
});
// write stringified JSON data, if any
if (data){
req.write(data);
}
req.end();
};
MetadataServerAPI.prototype.getInstanceMetadataVal = function(key, callback){
var path = ['instance', 'attributes', key];
this._sendAPIRequest(path, callback);
};