Skip to content

Commit

Permalink
Fixing config services and configuration type handling
Browse files Browse the repository at this point in the history
Co-authored-by: Walter Domenico Vergara <walterwootz@users.noreply.github.com>
  • Loading branch information
manfredipist and walterwootz committed Mar 26, 2024
1 parent da85d37 commit 648bcdf
Show file tree
Hide file tree
Showing 13 changed files with 1,367 additions and 39 deletions.
12 changes: 8 additions & 4 deletions conf/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,6 @@ config.opcua = {
};

config.mappingTool = {
/**
* Boolean property to assess whether enabling MappingTool or not
*/
enabled: false,
/**
* Boolean property to assess whether enabling polling in MappingTool or not
*/
Expand All @@ -271,6 +267,14 @@ config.mappingTool = {
storeOutput: true
};

/**
* flag indicating which configuration type to perform. Possible choices are:
* - auto : mappingTool will be run and runtime device mappings will be loaded
* - dynamic : device mappings from config.js will be ignored, REST API Provisioning is mandatory
* - static : device mappings from config.js will be loaded
*/

config.configurationType = 'auto';
/**
* map {name: function} of extra transformations avaliable at JEXL plugin
* see https://github.com/telefonicaid/iotagent-node-lib/tree/master/doc/expressionLanguage.md#available-functions
Expand Down
9 changes: 6 additions & 3 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ services:
- "4041:4041"
- "9229:9229"
environment:
- "CONFIGURATION_TYPE=auto"
- "CONFIG_RETRIEVAL=false"
- "DEFAULT_KEY=iot"
- "DEFAULT_TRANSPORT=OPCUA"
- "IOTA_LOGLEVEL=DEBUG"
- "IOTA_TIMESTAMP=true"
- "IOTA_CB_HOST=orion"
Expand Down Expand Up @@ -72,7 +76,6 @@ services:
- "IOTA_OPCUA_SUBSCRIPTION_REQ_MAX_KEEP_ALIVE_COUNT=10"
- "IOTA_OPCUA_SUBSCRIPTION_REQ_PUBLISHING_INTERVAL=1000"
- "IOTA_OPCUA_SUBSCRIPTION_PRIORITY=128"
- "IOTA_OPCUA_MT_ENABLED=false"
- "IOTA_OPCUA_MT_POLLING=false"
- "IOTA_OPCUA_MT_AGENT_ID=age01_"
- "IOTA_OPCUA_MT_ENTITY_ID=age01_Car"
Expand All @@ -95,7 +98,7 @@ services:

orion:
image: fiware/orion:3.10.1
#image: fiware/orion-ld:1.4.0
#image: fiware/orion-ld:1.5.1
hostname: orion
depends_on:
- mongodb
Expand All @@ -108,7 +111,7 @@ services:

iotcarsrv:
hostname: iotcarsrv
image: iotagent4fiware/opcuacarsrv:1.3.9
image: iotagent4fiware/opcuacarsrv:1.4.3
networks:
- hostnet
ports:
Expand Down
1 change: 0 additions & 1 deletion docs/opc_ua_agent_tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,6 @@ services:
- "IOTA_OPCUA_SUBSCRIPTION_REQ_MAX_KEEP_ALIVE_COUNT=10"
- "IOTA_OPCUA_SUBSCRIPTION_REQ_PUBLISHING_INTERVAL=1000"
- "IOTA_OPCUA_SUBSCRIPTION_PRIORITY=128"
- "IOTA_OPCUA_MT_ENABLED=false"
- "IOTA_OPCUA_MT_POLLING=false"
- "IOTA_OPCUA_MT_AGENT_ID=age01_"
- "IOTA_OPCUA_MT_ENTITY_ID=age01_Car"
Expand Down
2 changes: 1 addition & 1 deletion lib/bindings/OPCUABinding.js
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,7 @@ async function start() {
*/
async function initProvisioning() {
try {
if (config.getConfig().mappingTool.enabled || Object.keys(config.getConfig().iota.types).length > 0) {
if (config.getConfig().configurationType === 'auto' || config.getConfig().configurationType === 'static') {
await metaBindings.performProvisioning();
}
} catch (err) {
Expand Down
52 changes: 25 additions & 27 deletions lib/configService.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ function anyIsSet(variableSet) {
}

function processEnvironmentVariables() {
const commonVariables = ['CONFIGURATION_TYPE', 'CONFIG_RETRIEVAL', 'DEFAULT_KEY', 'DEFAULT_TRANSPORT'];

const iotaVariables = [
'IOTA_LOGLEVEL',
'IOTA_TIMESTAMP',
Expand All @@ -61,6 +63,7 @@ function processEnvironmentVariables() {
'IOTA_EXTENDED_FORBIDDEN_CHARACTERS',
'IOTA_AUTOPROVISION'
];

const opcUAVariables = [
'IOTA_OPCUA_ENDPOINT',
'IOTA_OPCUA_SECURITY_MODE',
Expand All @@ -75,22 +78,29 @@ function processEnvironmentVariables() {
'IOTA_OPCUA_SUBSCRIPTION_REQ_PUBLISHING_INTERVAL',
'IOTA_OPCUA_SUBSCRIPTION_PRIORITY'
];
const mappingToolVariables = ['IOTA_OPCUA_MT_ENABLED', 'IOTA_OPCUA_MT_POLLING', 'IOTA_OPCUA_MT_AGENT_ID', 'IOTA_OPCUA_MT_ENTITY_ID', 'IOTA_OPCUA_MT_ENTITY_TYPE', 'IOTA_OPCUA_MT_NAMESPACE_IGNORE', 'IOTA_OPCUA_MT_STORE_OUTPUT'];

const protectedVariables = ['IOTA_OPCUA_SECURITY_USERNAME', 'IOTA_OPCUA_SECURITY_PASSWORD'];
// Substitute Docker Secret Variables where set.
protectedVariables.forEach((key) => {
iotAgentLib.configModule.getSecretData(key);

const mappingToolVariables = ['IOTA_OPCUA_MT_POLLING', 'IOTA_OPCUA_MT_AGENT_ID', 'IOTA_OPCUA_MT_ENTITY_ID', 'IOTA_OPCUA_MT_ENTITY_TYPE', 'IOTA_OPCUA_MT_NAMESPACE_IGNORE', 'IOTA_OPCUA_MT_STORE_OUTPUT'];

commonVariables.forEach((key) => {
let value = process.env[key];
if (value) {
logger.info('Setting OPC UA IoTAgent environment variable %s to environment value: %s', key, value);
}
});

if (process.env.IOTA_CONFIG_RETRIEVAL) {
config.configRetrieval = process.env.IOTA_CONFIG_RETRIEVAL;
if (process.env.CONFIGURATION_TYPE) {
config.configurationType = process.env.CONFIGURATION_TYPE;
}
if (process.env.CONFIG_RETRIEVAL) {
config.configRetrieval = process.env.CONFIG_RETRIEVAL;
}
if (process.env.IOTA_DEFAULT_KEY) {
config.defaultKey = process.env.IOTA_DEFAULT_KEY;
if (process.env.DEFAULT_KEY) {
config.defaultKey = process.env.DEFAULT_KEY;
}
if (process.env.IOTA_DEFAULT_TRANSPORT) {
config.defaultTransport = process.env.IOTA_DEFAULT_TRANSPORT;
if (process.env.DEFAULT_TRANSPORT) {
config.defaultTransport = process.env.DEFAULT_TRANSPORT;
}

iotaVariables.forEach((key) => {
Expand Down Expand Up @@ -188,23 +198,20 @@ function processEnvironmentVariables() {
config.iota.autoprovision = process.env.IOTA_AUTOPROVISION === 'true' ? true : false;
}

if (anyIsSet(opcUAVariables)) {
config.opcua = {
subscription: {}
};
logger.info('Config.opcua erased', config.opcua);
}

opcUAVariables.forEach((key) => {
let value = process.env[key];
if (value) {
if (key.endsWith('USERNAME') || key.endsWith('PASSWORD') || key.endsWith('KEY')) {
value = '********';
}
logger.info('Setting opcUA environment variable %s to environment value: %s', key, value);
logger.info('Setting OPC UA environment variable %s to environment value: %s', key, value);
}
});

protectedVariables.forEach((key) => {
iotAgentLib.configModule.getSecretData(key);
});

if (process.env.IOTA_OPCUA_ENDPOINT) {
config.opcua.endpoint = process.env.IOTA_OPCUA_ENDPOINT;
}
Expand Down Expand Up @@ -253,22 +260,13 @@ function processEnvironmentVariables() {
config.opcua.subscription.priority = process.env.IOTA_OPCUA_SUBSCRIPTION_PRIORITY;
}

if (anyIsSet(mappingToolVariables)) {
config.mappingTool = {};
logger.info('Config.mappingTool erased', config.mappingTool);
}

mappingToolVariables.forEach((key) => {
let value = process.env[key];
if (value) {
logger.info('Setting mappingTool environment variable %s to environment value: %s', key, value);
}
});

if (process.env.IOTA_OPCUA_MT_ENABLED) {
config.mappingTool.enabled = process.env.IOTA_OPCUA_MT_ENABLED === 'true' ? true : false;
}

if (process.env.IOTA_OPCUA_MT_POLLING) {
config.mappingTool.polling = process.env.IOTA_OPCUA_MT_POLLING === 'true' ? true : false;
}
Expand Down
4 changes: 2 additions & 2 deletions lib/iotagent-opcua.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ function deviceProvisioningHandler(device, callback) {
if (error) {
callback(error);
} else {
if (!config.getConfig().mappingTool.enabled && Object.keys(config.getConfig().iota.types).length === 0) {
if (config.getConfig().configurationType === 'dynamic') {
let conf = config.getConfig();
conf.iota.contexts = devices[0].internalAttributes.contexts;
conf.iota.contextSubscriptions = devices[0].internalAttributes.contextSubscriptions;
Expand Down Expand Up @@ -113,7 +113,7 @@ async function start(newConfig, callback) {
config.setLogger(iotAgentLib.logModule);
config.setConfig(newConfig);

if (config.getConfig().mappingTool.enabled && Object.keys(config.getConfig().iota.types).length === 0) {
if (config.getConfig().configurationType === 'auto') {
config.getLogger().info('---------------- MAPPING TOOL ----------------');
const configJS = await mappingTool.mappingTool(config.getConfig());
//console.log("configJS "+ JSON.stringify(configJS))
Expand Down
98 changes: 98 additions & 0 deletions test/functional/configurationTypeAuto.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const { expect, assert } = require('chai');
const util = require('util');
const exec = util.promisify(require('child_process').exec);
const child = require('child_process');
const path = require('path');
const axios = require('axios');

/**
* Contains the current child process of the agent
* @type {null}
*/
let agentProcess = null;

/**
* If true, start and stop an agent instance for each test block
* @type {boolean}
*/
const MOCK_AGENT_PROCESS = true;

/**
* If true, start and stop an environment (opcua car server, orion, mongodb) for each test block using docker
* @type {boolean}
*/
const MOCK_ENVIRONMENT = true;

/**
* Start the agent in a child process using configuration file passed as argument
* @param testConfigFile
* @returns {ChildProcessWithoutNullStreams}
*/
function startAgent(testConfigFile) {
console.log('>>>>> STARTING AGENT <<<<<');
agentProcess = child.spawn('node', ['./bin/iotagent-opcua', `./test/functional/mock/${testConfigFile}`]);
agentProcess.stdout.setEncoding('utf8');
agentProcess.stdout.on('data', function (data) {
console.log('AGENT_LOG: ' + data);
});
agentProcess.stderr.setEncoding('utf8');
agentProcess.stderr.on('data', function (data) {
console.error('AGENT_ERR: ' + data);
});
return agentProcess;
}

/**
* Stop the child process of the agent
* @param process
*/
function stopAgent(process) {
console.log('>>>>> STOPPING AGENT <<<<<');
process.kill('SIGINT');
}

async function wait(seconds) {
await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
}

describe('IoT Agent OPCUA Auto Configuration', () => {
describe('When configurationType is equal to "auto"', () => {
before(async () => {
if (MOCK_ENVIRONMENT) {
await exec(path.resolve(__dirname, '../start-env.sh'));
}
if (MOCK_AGENT_PROCESS) {
startAgent('config-v2-auto-configuration.test.js');
}
});
after(async () => {
if (MOCK_ENVIRONMENT) {
await exec(path.resolve(__dirname, '../stop-env.sh'));
}
if (MOCK_AGENT_PROCESS) {
stopAgent(agentProcess);
}
});
it('Should run the mapping tool and perform provisioning of device', async () => {
await wait(5);

const mockConfig = require('./mock/config-v2-auto-configuration.test');
const url = `http://localhost:${mockConfig.iota.server.port}/iot/devices`;
try {
const res = await axios.get(url, {
headers: {
'fiware-service': mockConfig.iota.service,
'fiware-servicepath': mockConfig.iota.subservice
}
});
expect(res.status).to.greaterThanOrEqual(200).and.lessThanOrEqual(300);
expect(res.data.count).is.greaterThanOrEqual(1);
expect(res.data.devices.length).is.greaterThanOrEqual(1);
expect(res.data.devices[0].entity_name).to.equal(mockConfig.mappingTool.entityId);
expect(res.data.devices[0].entity_type).to.equal(mockConfig.mappingTool.entityType);
} catch (err) {
assert.fail('Request failed', 'Request success', `GET /iot/devices failed ${err}`);
}
});
});
});
Loading

0 comments on commit 648bcdf

Please sign in to comment.