LineRate Node.js REST API module

Linerate

function
Linerate()

Code
function Linerate() {

  this.rest_url = '/lrs/api/v1.0';

  this.defaults = {
    rest_url: '/lrs/api/v1.0',
    headers: {
      'content-type': 'application/json'
    }
  };

  // wrap request with defaults
  this.request = request.defaults({
    rejectUnauthorized: false
  });

}

Linerate.prototype.STATUS_CODES = {
    'DELETE': { 
      'ok': [ 204 ] 
    },
    'GET': {
      'ok': [ 200 ]
    },
    'PUT': {
      'ok': [ 200 ]
    },
    'POST': {
      'ok': [ 200 ]
    }
};

connect

Creates a session with a LineRate host

method
Linerate.prototype.connect()

Option name Type Description
opts Object

The connection options object. Supported object properties:

opts.host string

Hostname or IP address

opts.port integer

Port number

opts.username string

Username

opts.password string

Password

callback function
Example 1
connect({
   host: '127.0.0.1',
   port: 8443,
   username: 'admin',
   password: 'changeme'
 }, function(error, message) {
   // code here
 });
Code
Linerate.prototype.connect = function(opts, callback) {

  var self = this;

  this.base_url = 'https://' + opts.host + ':' + opts.port;

  this.jar = request.jar();
  
  var options = {
    url: this.base_url + '/login',
    headers: {
      'content-type': 'application/x-www-form-urlencoded'
    },
    body: 'username=' + opts.username + '&password=' + opts.password,
    jar: self.jar
  };

  this.request.post(options, function(error, response) {
    if (error) {
      //throw new Error('connection error: ' + error);
      callback(error);
    }

    // successful login always returns a 302
    if (response.statusCode !== 302) {
      //throw new Error('Login failure: ' + response.statusCode);
      callback(error);
    }

    // and, conveniently, a failed login attempt returns a 302.
    // check for 302 and redirect back to login page for failed login
    if (response.statusCode === 302 && 
        url.parse(response.headers.location).pathname === '/login') {
      callback('Login failed');
    }


    //console.log(self.jar.getCookies(options.url));
    callback(null, 'connected');
  });

};

get

Initiates a GET request

method
Linerate.prototype.get()

Option name Type Description
node string

The REST API node

opts Object

GET options

opts.query Object

An object containing a list of key, value pairs to be used as the query string

callback function
Example 1
get('/config/ntp/server', {
  query: {
    level: 'recurse'
  }
 }, function(error, message) {
   // code here
 });
Code
Linerate.prototype.get = function(node, opts, callback) {

  // arguments fixup
  if (typeof opts === 'function') {
    callback = opts;
    opts = null;
  }

  if (!check_node(node)) {
    return callback('\'node\' must be a string');
  }

  var path = this.rest_url + node;

  if (opts) {
    if (opts.query) {
      path += '?' + qs.stringify(opts.query);
    }
  }

  this.request({
      url: this.base_url + path,
      jar: this.jar,
      headers: this.defaults.headers,
      json: true
    },
    function(error, response) {
      if (error) { 
        // TODO: don't throw from module
        throw new Error('err');
      }
      // pass callback in case of error, we can return
      // directly from check_response
      check_response(response, callback);
      return callback(null, format_response(response.body));
    });
};

put

Initiates a PUT request

method
Linerate.prototype.put()

Option name Type Description
node string

The REST API node

opts Object,string

PUT options. opts is always required for PUT

opts.data Object

The data for the node's PUT operation as defined by the LineRate REST API documentation. If passed as a string,
value is converted to proper object syntax

opts.default boolean

Set default key. Default: false

opts.query Object

An object containing a list of key, value pairs to be used as the query string. Some API nodes accept a query string

callback function
Example 1
put('/exec/system/util/delete', 
 '/tmp/a',
 function(error, message) {
   // code here
 });
Code
Linerate.prototype.put = function(node, opts, callback) {

  if (!check_node(node)) {
    return callback('\'node\' must be a string');
  }

  var path = this.rest_url + node;

  if (opts) {

    // if opts is a string, assuming all defaults except 'data'
    if (typeof opts === 'string') {
      opts = {
        data: opts,
        type: 'string',
        default: false
      };
    }
    else if (typeof opts === 'object') {
      if (!opts.data) {
        callback('missing data');
      }
      if (opts.query) {
        path += '?' + qs.stringify(opts.query);
      }

      opts.type = opts.type || 'string';
      opts.default = opts.default || false;

    }
    else {
      callback('unrecognized opts argument');
      return;
    }
  }

  if (!validate_data(opts.data, opts.type)) {
    console.log('uh-oh');
    callback('input data failed validation');
    return;
  }


  // note that json: true does 3 things:
  // formats body data as json
  // sets content-type header to application/json
  // parses response body as JSON
  this.request.put(
      {
        url: this.base_url + path,
        jar: this.jar,
        headers: this.defaults.headers,
        json: true,
        body: opts
      },
      function(error, response) {
        if (error) { 
          throw new Error('err');
        }
        // pass callback in case of error, we can return
        // directly from check_response
        if (!check_response(response, callback)) {
          // we should have already called back from check_response(),
          // so just return here
          return;
        }
        callback(null, format_response(response.body));
      });
};

delete

Initiates a DELETE request

method
Linerate.prototype.delete()

Option name Type Description
node string

The REST API node

callback function
Example 1
delete('/config/app/proxy/virtualIP/vip01',
 function(error, message) {
   // code here
 });
Code
Linerate.prototype.delete = function(node, callback) {

  if (!check_node(node)) {
    return callback('\'node\' must be a string');
  }

  var path = this.rest_url + node;

  this.request.del({
      url: this.base_url + path,
      jar: this.jar,
      json: true,
    },
    function(error, response) {
      if (error) { 
        // TODO: don't throw from module
        throw new Error(error);
      }
      // pass callback in case of error, we can return
      // directly from check_response
      if (!check_response(response, callback)) {
        // we should have already called back from check_response(),
        // so just return here
        return;
      }

      // a successful DELETE request results in a 204 with no 
      // response body, so handle format_response differently
      // for DELETE
      return callback(null, format_response(
            { message: 'node deleted',
              node: node
            }
          ));

    });
};

util_delete

Convenience method - util_delete

method
Linerate.prototype.util_delete()

Code
Linerate.prototype.util_delete = function(file, callback) {
  var node = '/exec/system/util/delete';
  this.put(node, file, callback);
};

get_hostname

Convenience method - get_hostname

method
Linerate.prototype.get_hostname()

Code
Linerate.prototype.get_hostname = function(callback) {
  var node = '/config/system/hostname';
  this.get(node, callback);
};

set_hostname

Convenience method - set_hostname

method
Linerate.prototype.set_hostname()

Code
Linerate.prototype.set_hostname = function(name, callback) {
  var node = '/config/system/hostname';
  this.put(node, name, callback);
};

backup_list

Convenience method - backup_list

method
Linerate.prototype.backup_list()

Code
Linerate.prototype.backup_list = function(callback) {
  var node = '/status/system/util/backup/list';
  this.get(node, callback);
};

backup_home

Convenience method - backup_home

method
Linerate.prototype.backup_home()

Code
Linerate.prototype.backup_home = function(destination, callback) {
  var node = '/exec/system/util/backup/home';
  this.put(node, destination, callback);
};

write_mem

Convenience method - write_mem

method
Linerate.prototype.write_mem()

Code
Linerate.prototype.write_mem = function(callback) {
  var node = '/exec/system/util/copy';
  this.put(node, 'running-config|startup-config', callback);
};

get_regkey

Convenience method - get_regkey

method
Linerate.prototype.get_regkey()

Code
Linerate.prototype.get_regkey = function(callback) {
  var node = '/status/licensing/regKey';
  this.get(node, callback);
};

set_regkey

Convenience method - set_regkey

method
Linerate.prototype.set_regkey()

Code
Linerate.prototype.set_regkey = function(regkey, callback) {
  var node = '/config/licensing/regKey';
  this.put(node, regkey, callback);
};

get_activation_mode

Convenience method - get_activation_mode

method
Linerate.prototype.get_activation_mode()

Code
Linerate.prototype.get_activation_mode = function(callback) {
  var node = '/status/licensing/activationMode';
  this.get(node, callback);
};

set_activation_mode

Convenience method - set_activation_mode

method
Linerate.prototype.set_activation_mode()

Code
Linerate.prototype.set_activation_mode = function(mode, callback) {
  var node = '/config/licensing/activationMode';
  //if (whitelist_verify(node, mode)) {
    this.put(node, mode, callback);
  //} else {
  //  callback('data failed verification');
 //}
};

install_license

Convenience method - install_license

Assumes feature base (the only currently supported
license type)

license param can be a string with the license or a
filepath to the license file

method
Linerate.prototype.install_license()

Code
Linerate.prototype.install_license = function(license, callback) {
  var node = '/config/licensing/feature/base';
  var license_string = get_file_or_data(license);
  console.log(license_string);
  this.put(node, license_string, callback);
};

function get_file_or_data(path) {
  var data = path;

  if (fs.existsSync(path)) {
    try {
      data = fs.readFileSync(path, { encoding: 'utf-8' } );
    } catch (e) {
      throw new Error(e);
    }
  }

  return data;
}

module.exports = Linerate;