Ext timeout despite high setting

We’re having some trouble with external script timout. We’ve set GENIEACS_EXT_TIMEOUT=15000
in genieacs.env, but we’re still getting timouts quite often. Are we missing something?

Post your provision script and your ext script pls.

This is the external script. I did not write it, thus I can’t explain all bits and pieces of it. It returns data which is then picked up in a provisioning script. These are off course scripts to control cpe’s in “real time”.

// InHome configuration script

const url = require('url');
const https = require('http');
//const logger = require('../../lib/logger');

const INHOME_API_HOST = process.env.INHOME_API_HOST || 'ztinhomeapi.netnordic.net';
const INHOME_API_PORT = process.env.INHOME_API_PORT || 443;
const INHOME_INTG_HOST = process.env.INHOME_INTG_HOST || 'ztinhomeintg.netnordic.net';
const INHOME_INTG_PORT = process.env.INHOME_INTG_PORT || 443;

function addDevice(args, callback) {
  let postData = args[0];
  let options = {
    hostname: INHOME_INTG_HOST,
    port: INHOME_INTG_PORT,
    path: '/api/device',
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
      'Content-Length': postData.length
    },
    timeout: 15000
  };

  let req = https.request(options, (res) => {
    if (res.statusCode !== 200) {
      return callback(new Error('addDevice failed (status code: ' + res.statusCode + ')'));
    }

    let data = '';

    res.on('data', (chunk) => data += chunk);

    res.on('end', function() {
      let json = JSON.parse(data);
      if (!json) {
        return callback(new Error('addDevice failed (no data)'));
      } else if (json.success) {
        return callback(null, json.data);
      } else {
        return callback(new Error('addDevice failed (message: ' + json.message + ')'));
      }
    });
  });

  req.on('error', (err) => {
    return callback(err);
  });

  req.write(postData);

  req.end();
}

function getConfig(args, callback) {
  let params = JSON.parse(args[0]);
  let options = {
    hostname: INHOME_API_HOST,
    port: INHOME_API_PORT,
    path: '/api/device/' + encodeURIComponent(params.serialNumber) + '/config',
    method: 'GET',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    timeout: 15000
  };

  let req = https.request(options, function(res) {
    if (res.statusCode !== 200) {
      return callback(new Error('getConfig failed (status code: ' + res.statusCode + ')'));
    }

    let data = '';

    res.on('data', (chunk) => data += chunk);

    res.on('end', function() {
      let json = JSON.parse(data);
      if (!json) {
        return callback(new Error('getConfig failed (no data)'));
      } else if (json.success) {
        return callback(null, json.data);
      } else {
        return callback(new Error('getConfig failed (message: ' + json.message + ')'));
      }
    });
  });

  req.on('error', (err) => {
    return callback(err);
  });

  req.end();
}

function getService(args, callback) {
  let params = JSON.parse(args[0]);
  let options = {
    hostname: INHOME_INTG_HOST,
    port: INHOME_INTG_PORT,
    path: '/api/service?ipAddress=' + params.ipAddress,
    method: 'GET',
    headers: {
      'Accept': 'application/json'
    },
    timeout: 15000
  };

  let req = https.request(options, (res) => {
    if (res.statusCode !== 200) {
      return callback(new Error('getService failed (status code: ' + res.statusCode + ')'));
    }

    let data = '';

    res.on('data', (chunk) => data += chunk);

    res.on('end', function() {
      let json = JSON.parse(data);
      if (!json) {
        return callback(new Error('getService failed (no data)'));
      } else if (json.success) {
        return callback(null, json.data);
      } else {
        return callback(new Error('getService failed (message: ' + json.message + ')'));
      }
    });
  });

  req.on('error', (err) => {
    return callback(err);
  });

  req.end();
}

exports.addDevice = addDevice;
exports.getConfig = getConfig;
exports.getService = getService;

Provisioning script:
log(“inHome-config-drgos”);

let ts = Date.now();

let serialNumber = declare("DeviceID.SerialNumber", { value: 1 }).value[0];

let args = {
  serialNumber: serialNumber
};

let config = ext("inhome", "getConfig", JSON.stringify(args));

declare("Tags.inHome-config", null, {
  value: false
});

if (!config) {
  log("No config returned from API", args);
} else {
  if (config.router) {
    log("Configuring router", config.router);

    let productClass = declare("DeviceID.ProductClass", { value: 1 }).value[0];

    // WiFi
    if (config.router.wiFi == true) {
      if (config.wiFi) {
        log("Configuring Wi-Fi", config.wiFi);
        for (let i in config.wiFi.radios) {
          let radio = config.wiFi.radios[i];

          if (radio.frequency == "2.4GHz") {
            log("Configuring 2.4 GHz radio", radio);

            if (radio.enabled === true) {
              log("Configuring 2.4 GHz radio", radio);

              for (var j = 0; j < 4; j++) {
                if (j < radio.interfaces.length) {
                  let intf = radio.interfaces[j];
                  if (intf) {
                    configureWLAN("InternetGatewayDevice.LANDevice.1.WLANConfiguration." + (j + 1),
                      radio.broadcastSsid, radio.channel, true, intf.presharedKey, intf.ssid, radio.transmitPower)
                  }
                }
              }
            } else if (radio.enabled === false) {
              log("Disabling 2.4 GHz radio", radio);

              for (var j = 0; j < 4; j++) {
                configureWLAN("InternetGatewayDevice.LANDevice.1.WLANConfiguration." + (j + 1),
                  null, null, false, null, null, null)
              }
            }
          } else if (radio.frequency == "5GHz" && productClass == "HRG1000") {
            log("Configuring 5 GHZ radio", radio);

            if (radio.enabled === true) {
              for (var j = 0; j < 4; j++) {
                if (j < radio.interfaces.length) {
                  let intf = radio.interfaces[j];
                  if (intf) {
                    configureWLAN("InternetGatewayDevice.LANDevice.1.WLANConfiguration." + (j + 1 + 4),
                      radio.broadcastSsid, radio.channel, true, intf.presharedKey, intf.ssid, radio.transmitPower)
                  }
                }
              }
            } else if (radio.enabled === false) {
              log("Disabling 5 GHZ radio", radio);

              for (var j = 0; j < 4; j++) {
                configureWLAN("InternetGatewayDevice.LANDevice.1.WLANConfiguration." + (j + 1 + 4),
                  null, null, false, null, null, null)
              }
            }
          } else {
            log("Unsupported radio", radio);
          }
        }
      }
    } else {
      declare("InternetGatewayDevice.LANDevice.1.WLANConfiguration.*.Enable", { value: ts }, { value: false });
      declare("InternetGatewayDevice.LANDevice.1.WLANConfiguration.*.RadioEnabled", { value: ts }, { value: false });
    }

    // Bridge
    let natIf = declare("InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.[Name:vlan1]", { value: ts });
    if (natIf && natIf.path) {
      if (config.router.bridge == true) {
        //declare(natIf.path + ".Enable", null, { value: false });
        setLayer2(1, true);
        setLayer2(2, true);
        setLayer2(3, true);
        setLayer2(4, true);
      } else {
        //declare(natIf.path + ".Enable", null, { value: true });
        setLayer2(1, config.router.layer2Lan1);
        setLayer2(2, config.router.layer2Lan2);
        setLayer2(3, config.router.layer2Lan3);
        setLayer2(4, config.router.layer2Lan4);
      }
    } else {
      log("No NAT interface found");
      setLayer2(1, config.router.layer2Lan1);
      setLayer2(2, config.router.layer2Lan2);
      setLayer2(3, config.router.layer2Lan3);
      setLayer2(4, config.router.layer2Lan4);
    }
  }
}

function configureWLAN(path, broadcastSsid, channel, enable, presharedKey, ssid, transmitPower) {
  if (broadcastSsid === true || broadcastSsid === false) {
    declare(path + ".SSIDAdvertisementEnabled", { value: ts }, { value: broadcastSsid });
  }

  //if (channel >= 0) {
  //  declare(path + ".AutoChannelEnable", { value: ts }, { value: channel === 0 });
  //  if (channel > 0) {
  //    // TODO: Check channel in Device.WiFi.Radio.1.PossibleChannels
  //    declare(path + ".Channel", { value: ts }, { value: channel });
  //  }
  //}

  if (enable === true || enable === false) {
    declare(path + ".Enable", { value: ts }, { value: enable });
    declare(path + ".RadioEnabled", { value: ts }, { value: enable });
  }

  if (presharedKey && presharedKey.length > 0) {
    declare(path + ".PreSharedKey.1.KeyPassphrase", { value: ts }, { value: presharedKey });
  }

  if (ssid && ssid.length > 0) {
    declare(path + ".SSID", { value: ts }, { value: ssid });
  }

  //if (transmitPower > 0) {
  //  declare(path + ".TransmitPower", { value: ts }, { value: transmitPower });
  //}
}

function setLayer2(lan, enable) {
  const lanInterface = "InternetGatewayDevice.LANDevice.1.LANEthernetInterfaceConfig." + lan;

  // disable interface before change
  declare(lanInterface + ".Enable", null, { value: false });

  let filter = declare("InternetGatewayDevice.Layer2Bridging.Filter.[FilterEnable:true,FilterBridgeReference:1,FilterInterface:1000" + lan + "]",
    { path: ts }, { path: (enable ? 1 : 0) });
  
  let marking = declare("InternetGatewayDevice.Layer2Bridging.Marking.[MarkingBridgeReference:1,MarkingInterface:1000" + lan + ",VLANIDUntag:true]",
    { path: ts }, { path: (enable ? 1 : 0) });
  if (enable && marking) {
    declare(marking.path + ".MarkingEnable", null, { value: true });
  }
  
  // enable interface before change
  declare(lanInterface + ".Enable", null, { value: true });
}

log("DONE inHome-config-drgos");

On the surface your ext script looks good. I’d put logging in your ext script to know more about whats happening.