customCommands stored as binary data (BinData)

gbyers at indue.com.au gbyers at indue.com.au
Thu Aug 27 06:54:08 EDT 2015


> -----Original Message-----
> From: Users [mailto:users-bounces at lists.genieacs.com] On Behalf Of
> Florian Eckert
> Sent: Thursday, 27 August 2015 7:49 PM
> To: Community support for GenieACS users
> Subject: Re: customCommands stored as binary data (BinData)
> 
> Can you please show use your customCommand source? In the repo there
> is only commands with ftp requests
> 

Sure. There's nothing groundbreaking here though. I just followed the 2 examples already there that use telnet ;-) I'd be too embarrassed to post the whole thing (I "wrote" 5 lines of JavaScript about 15 years ago), but using the ssh2 module available for Node.JS, the gist of it is shown below. Note that getGroupSerial just mimics the behaviour of getDeviceIp in the example code to get the InternetGatewayDevice.DeviceInfo.ProvisioningCode & InternetGatewayDevice.DeviceInfo.SerialNumber values.


var util = require('util');
var ssh2 = require('ssh2');

...

var remotecmd = function(group, serial, callback) {
  var cmnd = util.format('%s -g "%s" -s "%s"', COMMAND, group, serial);
  var conn = new ssh2.Client.Client();

  conn.on('ready', function() {
    conn.exec(cmnd, callback);
  }).connect({
    host: HOSTNAME,
    port: PORT,
    username: USERNAME,
    privateKey: require('fs').readFileSync(PRIVATE_KEY),
    readyTimeout: TIMEOUT
  });

  return conn;
}

...

exports.get = function(deviceId, args, callback) {
  getGroupSerial(deviceId, function(err, group, serial) {
    if (err) return callback(err);

    if (typeof group === 'undefined') {
      return callback("ProvisioningCode Not Set");
    };

    if (typeof serial === 'undefined') {
      return callback("SerialNumber Unknown");
    };

    var conn = remotecmd(group, serial, function(err, stream) {
      var result = '';

      if (err) return callback(err);

      stream.on('close', function(code, signal) {
        var err;
        conn.end();
        if (code) {
          err = "Runtime error (" + code + ")";
        } else {
          util.log(deviceId + ": Determined OpenVPN Username (" + result + ")");
        }
        return callback(err, result.toString());
      }).on('data', function(data) {
        result = data;
      }).stderr.on('data', function(data) {
        util.log(deviceId + ": ERROR: " + data);
      });

    });

    conn.on('error', function(err) {
      callback(err);
    });
  });
};


So the above uses the sacli tool over SSH via a Python wrapper I hacked together on the OpenVPN AS server. That's pretty clunky, so since getting this to work, I've managed to work out the XML-RPC interface to OpenVPN Access Server & have since started replacing the ssh2 stuff above with simple XML-RPC calls using the xmlrpc module. It should be more light weight & means I can control everything from GenieACS going forward (creating new OpenVPN users, deploying OpenVPN configs, etc). The interesting thing to note is that you can store arbitrary metadata against an OpenVPN user; like a CPE serial number, for example. Given a ProvisioningCode (OpenVPN group) & a CPE serial number, I can know whether an OpenVPN user already exists & if not, create one, pull down an AUTOLOGIN bundle for it, package it (my CPEs use the ipkg format), upload it & tell the CPE to download and install, all via GenieACS custom commands & the NBI API. 

 
> 2015-08-27 1:07 GMT+02:00 gbyers at indue.com.au <gbyers at indue.com.au>:
> >> On Wed, Aug 26, 2015, at 01:59 AM, gbyers at indue.com.au wrote:
> >> > > I've written a custom command that connects to an OpenVPN server
> & determines
> >> > > info about a device based on its ProvisioningCode & SerialNumber.
> The result
> >> > > of that command is always a string, yet it's stored in mongo as
> BinData,
> >> > > represented as some sort of hash. Therefore, if I create an alias
> for this
> >> > > custom command to display in the UI, the output isn't as
> expected. Here's an
> >> > > example ;
> >> > >
> >> > > > db.devices.find({}, {_customCommands: true})
> >> > > { "_id" : "XXXXXXXXXXXXXXX", "_customCommands" : { "openvpn" : {
> "_value" : BinData(0,"XXXXXXXX"),
> >> > > "_timestamp" : ISODate("2015-08-25T01:50:31.721Z") } } }
> >> > >
> >> > > Is there a way to coerce this into mongo as type: 'string', or do
> I need to decode this using a parameter
> >> > > renderer within the UI?
> >> >
> >> >
> >> > Alrighty then. Turns out to be a PEBKAC issue. I was using a ssh2
> module
> >> > for Node.js that was encoding the result in a Buffer object. This
> must
> >> > have been a recent change & it caught me out. Dumping deviceUpdates
> ;
> >> >
> >> >     { customCommands: [ [ 'openvpn', <Buffer 4d 57 30 30 30 36> ] ]
> }
> >> >
> >> > The simple fix was to add a toString() to the result of my custom
> command
> >> > ;
> >> >
> >> >     return callback(err, result.toString());
> >> >
> >> >
> >> > Grant
> >>
> >> Thank you for clarifying the fix.
> >>
> >> Out of curiosity, how are you populating the ProvisioningCode
> parameter?
> >>
> >> Zaid
> >
> > Currently, I'm just setting it through the GenieACS UI. It simply
> defines an OpenVN AS group that this new CPE should be a member of.
> >
> > Grant
> >
> > _______________________________________________
> > Users mailing list
> > Users at lists.genieacs.com
> > http://lists.genieacs.com/mailman/listinfo/users
> > _______________________________________________
> > Users mailing list
> > Users at lists.genieacs.com
> > http://lists.genieacs.com/mailman/listinfo/users
> 
> 
> 
> --
> Mit freundlichen Grüßen
> _______________________________________________
> Users mailing list
> Users at lists.genieacs.com
> http://lists.genieacs.com/mailman/listinfo/users


More information about the Users mailing list