iotagent-node-lib 4.6.0 → 4.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +0 -1
- package/Changelog +12 -0
- package/config.js +3 -1
- package/doc/admin.md +39 -5
- package/doc/api.md +67 -6
- package/doc/requirements.txt +1 -1
- package/lib/commonConfig.js +21 -2
- package/lib/model/Command.js +2 -2
- package/lib/model/Device.js +7 -3
- package/lib/model/Group.js +5 -3
- package/lib/model/dbConn.js +53 -112
- package/lib/services/commands/commandRegistryMongoDB.js +115 -75
- package/lib/services/common/iotManagerService.js +3 -1
- package/lib/services/devices/deviceRegistryMemory.js +36 -0
- package/lib/services/devices/deviceRegistryMongoDB.js +160 -87
- package/lib/services/devices/deviceService.js +33 -3
- package/lib/services/devices/devices-NGSI-v2.js +6 -1
- package/lib/services/groups/groupRegistryMongoDB.js +120 -83
- package/lib/services/ngsi/entities-NGSI-v2.js +14 -1
- package/lib/services/ngsi/ngsiService.js +32 -1
- package/lib/services/northBound/deviceProvisioningServer.js +12 -3
- package/lib/templates/updateDevice.json +12 -0
- package/lib/templates/updateDeviceLax.json +12 -0
- package/package.json +4 -4
- package/test/functional/config-test.js +3 -2
- package/test/functional/testUtils.js +2 -2
- package/test/unit/examples/groupProvisioningRequests/provisionFullGroup.json +1 -0
- package/test/unit/general/config-multi-core-test.js +1 -2
- package/test/unit/general/contextBrokerKeystoneSecurityAccess-test.js +5 -4
- package/test/unit/general/deviceService-test.js +6 -5
- package/test/unit/memoryRegistry/deviceRegistryMemory_test.js +6 -5
- package/test/unit/mongodb/mongodb-connectionoptions-test.js +7 -39
- package/test/unit/ngsi-ld/expressions/jexlBasedTransformations-test.js +1 -2
- package/test/unit/ngsi-ld/general/config-jsonld-contexts-test.js +1 -2
- package/test/unit/ngsi-mixed/provisioning/ngsi-versioning-test.js +8 -5
- package/test/unit/ngsiv2/expressions/jexlBasedTransformations-test.js +42 -41
- package/test/unit/ngsiv2/general/contextBrokerOAuthSecurityAccess-test.js +11 -10
- package/test/unit/ngsiv2/general/deviceService-test.js +6 -5
- package/test/unit/ngsiv2/general/https-support-test.js +1 -1
- package/test/unit/ngsiv2/lazyAndCommands/active-devices-attribute-update-test.js +4 -3
- package/test/unit/ngsiv2/lazyAndCommands/command-test.js +6 -5
- package/test/unit/ngsiv2/lazyAndCommands/lazy-devices-test.js +17 -16
- package/test/unit/ngsiv2/lazyAndCommands/polling-commands-test.js +10 -18
- package/test/unit/ngsiv2/ngsiService/active-devices-test.js +21 -20
- package/test/unit/ngsiv2/ngsiService/staticAttributes-test.js +8 -7
- package/test/unit/ngsiv2/plugins/alias-plugin_test.js +12 -11
- package/test/unit/ngsiv2/plugins/custom-plugin_test.js +3 -2
- package/test/unit/ngsiv2/plugins/multientity-plugin_test.js +28 -27
- package/test/unit/ngsiv2/provisioning/device-group-api-test.js +6 -4
- package/test/unit/ngsiv2/provisioning/device-provisioning-api_test.js +12 -11
- package/test/unit/ngsiv2/provisioning/device-provisioning-configGroup-api_test.js +11 -10
- package/test/unit/ngsiv2/provisioning/device-registration_test.js +5 -4
- package/test/unit/ngsiv2/provisioning/listProvisionedDevices-test.js +6 -5
- package/test/unit/ngsiv2/provisioning/provisionDeviceMultientity-test.js +1 -1
- package/test/unit/ngsiv2/provisioning/removeProvisionedDevice-test.js +5 -4
- package/test/unit/ngsiv2/provisioning/updateProvisionedDevices-test.js +8 -7
package/.github/workflows/ci.yml
CHANGED
package/Changelog
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
4.7.0 (February 3rd, 2025)
|
|
2
|
+
|
|
3
|
+
- Add: store (and recover) previous jexlctxt and make available in current jexlctxt (#1690)
|
|
4
|
+
- Add: option to force to use CB flow control with new API field useCBflowControl at group and device device level (#1420)
|
|
5
|
+
- Add: useCBflowControl config setting (IOTA_CB_FLOW_CONTROL env var) to set CB flow control behaviour at instance level (#1420)
|
|
6
|
+
- Add: allow remove last measure in device
|
|
7
|
+
- Add: store last measure in device (by id, apikey, service and subservice) and new API field storeLastMeasure at group and device levels (#1669)
|
|
8
|
+
- Add: storeLastMeasure config setting (IOTA_STORE_LAST_MEASURE env var) to set default store last measure behaviour at instance level (#1669)
|
|
9
|
+
- Fix: set polling and transport for autoprovisioned devices
|
|
10
|
+
- Upgrade express dep from 4.19.2 to 4.21.2
|
|
11
|
+
- Upgrade mongodb devdep from 4.17.1 to 4.17.2
|
|
12
|
+
- Upgrade mongoose dep from 5.13.20 to 8.9.5 (solving vulnerabilies CVE-2024-53900 and CVE-2025-23061) (#1674)
|
package/config.js
CHANGED
|
@@ -77,7 +77,9 @@ var config = {
|
|
|
77
77
|
providerUrl: 'http://192.168.56.1:4041',
|
|
78
78
|
deviceRegistrationDuration: 'P1M',
|
|
79
79
|
defaultType: 'Thing',
|
|
80
|
-
expressLimit: '1Mb'
|
|
80
|
+
expressLimit: '1Mb',
|
|
81
|
+
useCBflowControl: false,
|
|
82
|
+
storeLastMeasure: false
|
|
81
83
|
};
|
|
82
84
|
|
|
83
85
|
module.exports = config;
|
package/doc/admin.md
CHANGED
|
@@ -125,9 +125,9 @@ allowing the computer to interpret the rest of the data with more clarity and de
|
|
|
125
125
|
```
|
|
126
126
|
|
|
127
127
|
Under mixed mode, **NGSI v2** payloads are used for context broker communications by default, but this payload may also
|
|
128
|
-
be switched to **NGSI LD** at group or device provisioning time using the `ngsiVersion` field in the
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
be switched to **NGSI LD** at group or device provisioning time using the `ngsiVersion` field in the provisioning API.
|
|
129
|
+
The `ngsiVersion` field switch may be added at either group or device level, with the device level overriding the group
|
|
130
|
+
setting.
|
|
131
131
|
|
|
132
132
|
#### `server`
|
|
133
133
|
|
|
@@ -306,7 +306,8 @@ added `agentPath`:
|
|
|
306
306
|
|
|
307
307
|
#### `types`
|
|
308
308
|
|
|
309
|
-
This parameter includes additional groups configuration as described into the
|
|
309
|
+
This parameter includes additional groups configuration as described into the
|
|
310
|
+
[Config group API](api.md#config-group-api) section.
|
|
310
311
|
|
|
311
312
|
#### `service`
|
|
312
313
|
|
|
@@ -415,7 +416,38 @@ IotAgents, as all Express applications that use the body-parser middleware, have
|
|
|
415
416
|
size that the application will handle. This default limit for ioiotagnets are 1Mb. So, if your IotAgent receives a
|
|
416
417
|
request with a body that exceeds this limit, the application will throw a “Error: Request entity too large”.
|
|
417
418
|
|
|
418
|
-
The 1Mb default can be changed setting the `expressLimit` configuration parameter (or equivalente `IOTA_EXPRESS_LIMIT`
|
|
419
|
+
The 1Mb default can be changed setting the `expressLimit` configuration parameter (or equivalente `IOTA_EXPRESS_LIMIT`
|
|
420
|
+
environment variable).
|
|
421
|
+
|
|
422
|
+
#### `storeLastMeasure`
|
|
423
|
+
|
|
424
|
+
If this flag is activated, last measure arrived to Device IoTAgent without be processed will be stored in Device under
|
|
425
|
+
`lastMeasure` field (composed of sub-fields `timestamp` and `measure` for the measure itself, in multi-measure format).
|
|
426
|
+
This flag is overwritten by `storeLastMeasure` flag in group or device. This flag is disabled by default.
|
|
427
|
+
|
|
428
|
+
For example in a device document stored in MongoDB will be extended with a subdocument named lastMeasure like this:
|
|
429
|
+
|
|
430
|
+
```json
|
|
431
|
+
{
|
|
432
|
+
"lastMeasure": {
|
|
433
|
+
"timestamp": "2025-01-09T10:35:33.079Z",
|
|
434
|
+
"measure": [
|
|
435
|
+
[
|
|
436
|
+
{
|
|
437
|
+
"name": "level",
|
|
438
|
+
"type": "Text",
|
|
439
|
+
"value": 33
|
|
440
|
+
}
|
|
441
|
+
]
|
|
442
|
+
]
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
#### `useCBflowControl`
|
|
448
|
+
|
|
449
|
+
If this flag is activated, when iotAgent invokes Context Broker will use [flowControl option](https://github.com/telefonicaid/fiware-orion/blob/master/doc/manuals/admin/perf_tuning.md#updates-flow-control-mechanism). This flag is overwritten by
|
|
450
|
+
`useCBflowControl` flag in group or device. This flag is disabled by default.
|
|
419
451
|
|
|
420
452
|
### Configuration using environment variables
|
|
421
453
|
|
|
@@ -479,6 +511,8 @@ overrides.
|
|
|
479
511
|
| IOTA_DEFAULT_ENTITY_NAME_CONJUNCTION | `defaultEntityNameConjunction` |
|
|
480
512
|
| IOTA_RELAX_TEMPLATE_VALIDATION | `relaxTemplateValidation` |
|
|
481
513
|
| IOTA_EXPRESS_LIMIT | `expressLimit` |
|
|
514
|
+
| IOTA_STORE_LAST_MEASURE | `storeLastMeasure` |
|
|
515
|
+
| IOTA_CB_FLOW_CONTROL | `useCBflowControl` |
|
|
482
516
|
|
|
483
517
|
Note:
|
|
484
518
|
|
package/doc/api.md
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
- [Special measures and attributes names](#special-measures-and-attributes-names)
|
|
13
13
|
- [Device to NGSI Mapping](#device-to-ngsi-mapping)
|
|
14
14
|
- [Device autoprovision and entity creation](#device-autoprovision-and-entity-creation)
|
|
15
|
+
- [Entity Name expression support](#entity-name-expression-support)
|
|
15
16
|
- [Multientity support](#multientity-support)
|
|
16
17
|
- [Metadata support](#metadata-support)
|
|
17
18
|
- [NGSI LD data and metadata considerations](#ngsi-ld-data-and-metadata-considerations)
|
|
@@ -164,7 +165,7 @@ parameters defined at device level in database, the parameters are inherit from
|
|
|
164
165
|
|
|
165
166
|
### Uniqueness of groups and devices
|
|
166
167
|
|
|
167
|
-
Group uniqueness is defined by the combination of:
|
|
168
|
+
Group uniqueness is defined by the combination of: resource and apikey. This is so because given a measure (identified by an apikey) there is no way to identify group related if apikey is not unique for all services and subservices.
|
|
168
169
|
|
|
169
170
|
Device uniqueness is defined by the combination of: service, subservice, device_id and apikey. Note that several devices
|
|
170
171
|
with the same device_id are allowed in the same service and subservice as long as their apikeys are different.
|
|
@@ -187,9 +188,9 @@ configured for a single device in the device provisioning, or it can be defined
|
|
|
187
188
|
|
|
188
189
|
The entity type should be defined both in the group and in the device, but the entity name (entity ID) is not defined in
|
|
189
190
|
the group. In that case, if there is no a existing device the same device ID, the entity name of the device generated
|
|
190
|
-
will be a concatenation of the entity type and the device ID (I.E: `entityType:device_id`).
|
|
191
|
-
entity name
|
|
192
|
-
|
|
191
|
+
will be a concatenation of the entity type and the device ID (I.E: `entityType:device_id`). If you need to generate the
|
|
192
|
+
entity name differently, it is possible to define an expression to generate it, using the parameter `entityNameExp` in
|
|
193
|
+
the group as described in the [Entity Name expression support](#entity-name-expression-support) section.
|
|
193
194
|
|
|
194
195
|
It is also possible to configure how each of the measures obtained from the device is mapped to different attributes.
|
|
195
196
|
The name and type of the attribute is configured by the user (globally for all the devices in the group or in a per
|
|
@@ -271,6 +272,59 @@ If for any reason you need the entity at CB before the first measure of the corr
|
|
|
271
272
|
IOTAgent, you can create it in advance using the Context Broker
|
|
272
273
|
[NGSI v2 API](https://github.com/telefonicaid/fiware-orion/blob/master/doc/manuals/orion-api.md).
|
|
273
274
|
|
|
275
|
+
## Entity Name expression support
|
|
276
|
+
|
|
277
|
+
By default, the entity name used to persist the device measures in the Context Broker can be defined in the device
|
|
278
|
+
provisioning or, if the device is autoprovisioned, it is generated by the IoT Agent as a concatenation of the entity
|
|
279
|
+
type and the device ID. If you need to generate the entity name differently, it is possible to define an expression to
|
|
280
|
+
generate it, using the [Expression Language](#expression-language-support) through the `entityNameExp` field in the
|
|
281
|
+
group.
|
|
282
|
+
|
|
283
|
+
With this feature, the entity name can be generated dynamically based not only on the device ID and entity type, but
|
|
284
|
+
also on the measures reported by the device or any other context information. The `entityNameExp` field is only
|
|
285
|
+
available at the group level. **Important**: when using `entityNameExp`, the `entity_name` field in the device
|
|
286
|
+
provisioning is ignored. This means that the entity name used to store the device information in the Context Broker is
|
|
287
|
+
always generated by the `entityNameExp` expression. If you need to explicitly define the entity name for a particular
|
|
288
|
+
device, you can include a particular condition in the `entityNameExp` expression to handle that case (e.g.
|
|
289
|
+
`id == 'myDevice' ? 'myEntity' : entityType + ':' + id`).
|
|
290
|
+
|
|
291
|
+
The following example shows how to define an entity name expression:
|
|
292
|
+
|
|
293
|
+
```json
|
|
294
|
+
{
|
|
295
|
+
"services": [
|
|
296
|
+
{
|
|
297
|
+
"resource": "/json",
|
|
298
|
+
"apikey": "801230BJKL23Y9090DSFL123HJK09H324HV8732",
|
|
299
|
+
"entity_type": "TemperatureSensor",
|
|
300
|
+
"entityNameExp": "id + '__' + sn",
|
|
301
|
+
"attributes": [
|
|
302
|
+
{
|
|
303
|
+
"object_id": "t",
|
|
304
|
+
"name": "temperature",
|
|
305
|
+
"type": "Number"
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
"object_id": "sn",
|
|
309
|
+
"name": "serialNumber",
|
|
310
|
+
"type": "Text"
|
|
311
|
+
}
|
|
312
|
+
]
|
|
313
|
+
}
|
|
314
|
+
]
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
As defined above, the `entityNameExp` is `id + '__' + sn` and it will generate the entity name by concatenating the
|
|
319
|
+
device ID and the serial number reported by the device. For example, for a given measure with `id` equal to `dev123` and
|
|
320
|
+
`sn` equal to `ABCDEF`, the resulting entity name will be `dev123__ABCDEF`.
|
|
321
|
+
|
|
322
|
+
Note that, when using `entityNameExp`, the `entity_name` of the device provisioning is set to the result of the
|
|
323
|
+
expression the first time the device is created. If the expression is modified later, the `entity_name` of the device
|
|
324
|
+
provisioning will not be updated, but the value used to persist the device measures in the Context Broker will be the
|
|
325
|
+
result of the new expression. This can lead to a situation where the `entity_name` of the device provisioning and the
|
|
326
|
+
entity name used in the Context Broker are different.
|
|
327
|
+
|
|
274
328
|
## Multientity support
|
|
275
329
|
|
|
276
330
|
The IOTA is able to persists measures coming from a single device to more than one entity, declaring the target entities
|
|
@@ -555,7 +609,8 @@ of expression in the IoT Agent are:
|
|
|
555
609
|
- [Metadata](#expression-support-in-metadata)
|
|
556
610
|
- Commands payload transformation (push and pull).
|
|
557
611
|
- Auto provisioned devices entity name. It is configured at config Group level by setting the `entityNameExp`
|
|
558
|
-
parameter. It defines an expression to generate the Entity Name for autoprovisioned devices.
|
|
612
|
+
parameter. It defines an expression to generate the Entity Name for autoprovisioned devices. More information in the
|
|
613
|
+
[Entity Name expression support](#entity-name-expression-support) section.
|
|
559
614
|
- Dynamic `endpoint` definition. Configured at device level, it defines where the device listen for push http
|
|
560
615
|
commands. It can be either a static value or an expression.
|
|
561
616
|
|
|
@@ -568,6 +623,7 @@ expression. In all cases the following data is available to all expressions:
|
|
|
568
623
|
- `service`: device service (`Fiware-Service`)
|
|
569
624
|
- `subservice`: device subservice (`Fiware-ServicePath`)
|
|
570
625
|
- `staticAttributes`: static attributes defined in the device or config group
|
|
626
|
+
- `oldCtxt`: previous JEXL context (related to last processed measure)
|
|
571
627
|
|
|
572
628
|
Additionally, for attribute expressions (`expression`, `entity_name`), `entityNameExp` and metadata expressions
|
|
573
629
|
(`expression`) the following is available in the **context** used to evalute:
|
|
@@ -1715,13 +1771,15 @@ Config group is represented by a JSON object with the following fields:
|
|
|
1715
1771
|
| `static_attributes` | ✓ | | | this attributes will be added to all the entities of this group 'as is', additional `metadata` is optional. |
|
|
1716
1772
|
| `internal_attributes` | ✓ | | | optional section with free format, to allow specific IoT Agents to store information along with the devices in the Device Registry. |
|
|
1717
1773
|
| `explicitAttrs` | ✓ | string or bool | ✓ | optional field to support selective ignore of measures so that IOTA doesn’t progress. See details in [specific section](#explicitly-defined-attributes-explicitattrs) |
|
|
1718
|
-
| `entityNameExp` | ✓ | string | | optional field to allow use expressions to define entity name, instead default name, based on the device ID and the entity type (i.e. `<device_id>:<entity_type>`)
|
|
1774
|
+
| `entityNameExp` | ✓ | string | | optional field to allow use expressions to define entity name, instead default name, based on the device ID and the entity type (i.e. `<device_id>:<entity_type>`). More information in [specific section](#entity-name-expression-entitynameexp) |
|
|
1719
1775
|
| `ngsiVersion` | ✓ | string | | optional string value used in mixed mode to switch between **NGSI-v2** and **NGSI-LD** payloads. Possible values are: `v2` or `ld`. The default is `v2`. When not running in mixed mode, this field is ignored. |
|
|
1720
1776
|
| `defaultEntityNameConjunction` | ✓ | string | | optional string value to set default conjunction string used to compose a default `entity_name` when is not provided at device provisioning time. |
|
|
1721
1777
|
| `autoprovision` | ✓ | bool | ✓? | optional boolean: If `false`, autoprovisioned devices (i.e. devices that are not created with an explicit provision operation but when the first measure arrives) are not allowed in this group. Default (in the case of omitting the field) is `true`. |
|
|
1722
1778
|
| `payloadType` | ✓ | string | | optional string value used to switch between **IoTAgent**, **NGSI-v2** and **NGSI-LD** measure payloads types. Possible values are: `iotagent`, `ngsiv2` or `ngsild`. The default is `iotagent`. |
|
|
1723
1779
|
| `transport` | ✓ | `string` | | Transport protocol used by the group of devices to send updates, for the IoT Agents with multiple transport protocols. |
|
|
1724
1780
|
| `endpoint` | ✓ | `string` | | Endpoint where the group of device is going to receive commands, if any. |
|
|
1781
|
+
| `storeLastMeasure` | ✓ | `boolean` | | Store in device last measure received. See more info [in this section](admin.md#storelastmeasure). False by default |
|
|
1782
|
+
| `useCBflowControl` | ✓ | `boolean` | | Use Context Broker flow control. See more info [in this section](admin.md#useCBflowControl). False by default |
|
|
1725
1783
|
|
|
1726
1784
|
### Config group operations
|
|
1727
1785
|
|
|
@@ -1942,6 +2000,9 @@ the API resource fields and the same fields in the database model.
|
|
|
1942
2000
|
| `explicitAttrs` | ✓ | `boolean` | ✓ | Field to support selective ignore of measures so that IOTA doesn’t progress. See details in [specific section](#explicitly-defined-attributes-explicitattrs) |
|
|
1943
2001
|
| `ngsiVersion` | ✓ | `string` | | string value used in mixed mode to switch between **NGSI-v2** and **NGSI-LD** payloads. The default is `v2`. When not running in mixed mode, this field is ignored. |
|
|
1944
2002
|
| `payloadType` | ✓ | `string` | | optional string value used to switch between **IoTAgent**, **NGSI-v2** and **NGSI-LD** measure payloads types. Possible values are: `iotagent`, `ngsiv2` or `ngsild`. The default is `iotagent`. |
|
|
2003
|
+
| `storeLastMeasure` | ✓ | `boolean` | | Store in device last measure received. Useful just for debugging purpose. See more info [in this section](admin.md#storelastmeasure). False by default. |
|
|
2004
|
+
| `lastMeasure` | ✓ | `object` | | last measure stored on device when `storeLastMeasure` is enabled. See more info [in this section](admin.md#storelastmeasure). This field can be cleared using `{}` in a device update request. In that case, `lastMeasure` is removed from device (until a next measure is received and `lastMesuare` gets created again). |
|
|
2005
|
+
| `useCBflowControl` | ✓ | `boolean` | | Use Context Broker flow control. See more info [in this section](admin.md#useCBflowControl). False by default. |
|
|
1945
2006
|
|
|
1946
2007
|
### Device operations
|
|
1947
2008
|
|
package/doc/requirements.txt
CHANGED
package/lib/commonConfig.js
CHANGED
|
@@ -157,7 +157,9 @@ function processEnvironmentVariables() {
|
|
|
157
157
|
'IOTA_FALLBACK_PATH',
|
|
158
158
|
'IOTA_LD_SUPPORT_NULL',
|
|
159
159
|
'IOTA_LD_SUPPORT_DATASET_ID',
|
|
160
|
-
'IOTA_EXPRESS_LIMIT'
|
|
160
|
+
'IOTA_EXPRESS_LIMIT',
|
|
161
|
+
'IOTA_USE_CB_FLOW_CONTROL',
|
|
162
|
+
'IOTA_STORE_LAST_MEASURE'
|
|
161
163
|
];
|
|
162
164
|
const iotamVariables = [
|
|
163
165
|
'IOTA_IOTAM_URL',
|
|
@@ -350,6 +352,11 @@ function processEnvironmentVariables() {
|
|
|
350
352
|
config.defaultResource = process.env.IOTA_DEFAULT_RESOURCE;
|
|
351
353
|
}
|
|
352
354
|
|
|
355
|
+
// Default transport
|
|
356
|
+
if (process.env.IOTA_DEFAULT_TRANSPORT !== undefined) {
|
|
357
|
+
config.defaultTransport = process.env.IOTA_DEFAULT_TRANSPORT;
|
|
358
|
+
}
|
|
359
|
+
|
|
353
360
|
// Default explicitAttrs
|
|
354
361
|
if (process.env.IOTA_EXPLICIT_ATTRS !== undefined) {
|
|
355
362
|
config.explicitAttrs = process.env.IOTA_EXPLICIT_ATTRS;
|
|
@@ -474,6 +481,16 @@ function processEnvironmentVariables() {
|
|
|
474
481
|
} else {
|
|
475
482
|
config.expressLimit = config.expressLimit ? config.expressLimit : '1mb';
|
|
476
483
|
}
|
|
484
|
+
if (process.env.IOTA_USE_CB_FLOW_CONTROL) {
|
|
485
|
+
config.useCBflowControl = process.env.IOTA_USE_CB_FLOW_CONTROL === 'true';
|
|
486
|
+
} else {
|
|
487
|
+
config.useCBflowControl = config.useCBflowControl === true;
|
|
488
|
+
}
|
|
489
|
+
if (process.env.IOTA_STORE_LAST_MEASURE) {
|
|
490
|
+
config.storeLastMeasure = process.env.IOTA_STORE_LAST_MEASURE === 'true';
|
|
491
|
+
} else {
|
|
492
|
+
config.storeLastMeasure = config.storeLastMeasure === true;
|
|
493
|
+
}
|
|
477
494
|
}
|
|
478
495
|
|
|
479
496
|
function setConfig(newConfig) {
|
|
@@ -503,7 +520,9 @@ function getConfigForTypeInformation() {
|
|
|
503
520
|
multiCore: config.multiCore,
|
|
504
521
|
relaxTemplateValidation: config.relaxTemplateValidation,
|
|
505
522
|
defaultEntityNameConjunction: config.defaultEntityNameConjunction,
|
|
506
|
-
defaultType: config.defaultType
|
|
523
|
+
defaultType: config.defaultType,
|
|
524
|
+
useCBflowControl: config.useCBflowControl,
|
|
525
|
+
storeLastMeasure: config.storeLastMeasure
|
|
507
526
|
};
|
|
508
527
|
return conf;
|
|
509
528
|
}
|
package/lib/model/Command.js
CHANGED
|
@@ -34,8 +34,8 @@ const Command = new Schema({
|
|
|
34
34
|
creationDate: { type: Date, default: Date.now }
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
function load(
|
|
38
|
-
module.exports.model =
|
|
37
|
+
function load() {
|
|
38
|
+
module.exports.model = mongoose.model('Command', Command);
|
|
39
39
|
module.exports.internalSchema = Command;
|
|
40
40
|
}
|
|
41
41
|
|
package/lib/model/Device.js
CHANGED
|
@@ -53,11 +53,15 @@ const Device = new Schema({
|
|
|
53
53
|
autoprovision: Boolean,
|
|
54
54
|
explicitAttrs: Group.ExplicitAttrsType,
|
|
55
55
|
ngsiVersion: String,
|
|
56
|
-
payloadType: String
|
|
56
|
+
payloadType: String,
|
|
57
|
+
useCBflowControl: Boolean,
|
|
58
|
+
storeLastMeasure: Boolean,
|
|
59
|
+
lastMeasure: Object,
|
|
60
|
+
oldCtxt: Object
|
|
57
61
|
});
|
|
58
62
|
|
|
59
|
-
function load(
|
|
60
|
-
module.exports.model =
|
|
63
|
+
function load() {
|
|
64
|
+
module.exports.model = mongoose.model('Device', Device);
|
|
61
65
|
module.exports.internalSchema = Device;
|
|
62
66
|
}
|
|
63
67
|
|
package/lib/model/Group.js
CHANGED
|
@@ -65,12 +65,14 @@ const Group = new Schema({
|
|
|
65
65
|
defaultEntityNameConjunction: String,
|
|
66
66
|
ngsiVersion: String,
|
|
67
67
|
entityNameExp: String,
|
|
68
|
-
payloadType: String
|
|
68
|
+
payloadType: String,
|
|
69
|
+
useCBflowControl: Boolean,
|
|
70
|
+
storeLastMeasure: Boolean
|
|
69
71
|
});
|
|
70
72
|
|
|
71
|
-
function load(
|
|
73
|
+
function load() {
|
|
72
74
|
Group.index({ apikey: 1, resource: 1 }, { unique: true });
|
|
73
|
-
module.exports.model =
|
|
75
|
+
module.exports.model = mongoose.model('Group', Group);
|
|
74
76
|
module.exports.internalSchema = Group;
|
|
75
77
|
}
|
|
76
78
|
|
package/lib/model/dbConn.js
CHANGED
|
@@ -31,7 +31,6 @@ const config = require('../commonConfig');
|
|
|
31
31
|
const constants = require('../constants');
|
|
32
32
|
const alarms = require('../services/common/alarmManagement');
|
|
33
33
|
const logger = require('logops');
|
|
34
|
-
const async = require('async');
|
|
35
34
|
const errors = require('../errors');
|
|
36
35
|
let defaultDb;
|
|
37
36
|
const DEFAULT_DB_NAME = 'iotagent';
|
|
@@ -40,9 +39,9 @@ const context = {
|
|
|
40
39
|
};
|
|
41
40
|
|
|
42
41
|
function loadModels() {
|
|
43
|
-
require('./Device').load(
|
|
44
|
-
require('./Group').load(
|
|
45
|
-
require('./Command').load(
|
|
42
|
+
require('./Device').load();
|
|
43
|
+
require('./Group').load();
|
|
44
|
+
require('./Command').load();
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
/**
|
|
@@ -50,93 +49,52 @@ function loadModels() {
|
|
|
50
49
|
*
|
|
51
50
|
* @this Reference to the dbConn module itself.
|
|
52
51
|
*/
|
|
52
|
+
|
|
53
53
|
function init(host, db, port, options, callback) {
|
|
54
|
-
/*jshint camelcase:false, validthis:true */
|
|
55
54
|
let url;
|
|
56
55
|
let retries = 0;
|
|
57
56
|
let lastError;
|
|
58
|
-
const maxRetries =
|
|
59
|
-
(config.getConfig().mongodb && config.getConfig().mongodb.retries) || constants.DEFAULT_MONGODB_RETRIES;
|
|
57
|
+
const maxRetries = config.getConfig().mongodb?.retries || constants.DEFAULT_MONGODB_RETRIES;
|
|
60
58
|
|
|
61
59
|
function addPort(item) {
|
|
62
|
-
return item
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function commaConcat(previous, current, currentIndex) {
|
|
66
|
-
if (currentIndex !== 0) {
|
|
67
|
-
previous += ',';
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
previous += current;
|
|
71
|
-
|
|
72
|
-
return previous;
|
|
60
|
+
return `${item}:${port}`;
|
|
73
61
|
}
|
|
74
62
|
|
|
75
63
|
url = 'mongodb://';
|
|
76
64
|
|
|
77
65
|
if (options.auth) {
|
|
78
|
-
url += options.auth.user
|
|
66
|
+
url += `${encodeURIComponent(options.auth.user)}:${encodeURIComponent(options.auth.password)}@`;
|
|
79
67
|
}
|
|
80
68
|
|
|
81
|
-
const hosts = host.split(',').map(addPort).
|
|
82
|
-
|
|
83
|
-
url += hosts + '/' + db;
|
|
69
|
+
const hosts = host.split(',').map(addPort).join(',');
|
|
70
|
+
url += `${hosts}/${db}`;
|
|
84
71
|
|
|
85
72
|
if (options.extraArgs) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
url +=
|
|
89
|
-
.map(function ([k, v]) {
|
|
90
|
-
return encodeURIComponent(k) + '=' + encodeURIComponent(v);
|
|
91
|
-
})
|
|
92
|
-
.join('&');
|
|
73
|
+
const query = new URLSearchParams(options.extraArgs).toString();
|
|
74
|
+
if (query) {
|
|
75
|
+
url += `?${query}`;
|
|
93
76
|
}
|
|
94
77
|
delete options.extraArgs;
|
|
95
78
|
}
|
|
96
79
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (defaultDb) {
|
|
100
|
-
logger.info(context, 'Successfully connected to MongoDB.');
|
|
101
|
-
module.exports.db = defaultDb;
|
|
102
|
-
loadModels();
|
|
103
|
-
} else {
|
|
104
|
-
logger.error(context, 'MONGODB-002: Error found after [%d] attempts: %s', retries, error || lastError);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
callback(error);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function retryCheck() {
|
|
111
|
-
return !defaultDb && retries < maxRetries;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function connectionAttempt(url, options, callback) {
|
|
115
|
-
logger.info(context, 'Attempting to connect to MongoDB instance with url %j. Attempt %d', url, retries);
|
|
116
|
-
// FIXME: useNewUrlParser is no longer used in underlying mongodb driver 4.x
|
|
117
|
-
// (see https://github.com/mongodb/node-mongodb-native/blob/HEAD/etc/notes/CHANGES_4.0.0.md)
|
|
118
|
-
// but not sure if current mongoose version is still using mongodb 3.x internally
|
|
119
|
-
// probably mongodb-connectionoptions-test.js needs to be fixed if useNewUrlParser is removed at the end
|
|
120
|
-
options.useNewUrlParser = true;
|
|
121
|
-
options.useUnifiedTopology = true;
|
|
122
|
-
mongoose.set('useCreateIndex', true);
|
|
123
|
-
/* eslint-disable-next-line no-unused-vars */
|
|
124
|
-
const candidateDb = mongoose.createConnection(url, options, function (error, result) {
|
|
125
|
-
if (error) {
|
|
126
|
-
logger.error(context, 'MONGODB-001: Error trying to connect to MongoDB: %s', error);
|
|
127
|
-
lastError = error;
|
|
128
|
-
} else {
|
|
129
|
-
defaultDb = candidateDb;
|
|
80
|
+
function connectionAttempt(callback) {
|
|
81
|
+
logger.info(context, `Attempting to connect to MongoDB at ${url}. Attempt ${retries + 1}`);
|
|
130
82
|
|
|
83
|
+
mongoose
|
|
84
|
+
.connect(url, options)
|
|
85
|
+
.then(() => {
|
|
86
|
+
defaultDb = mongoose.connection;
|
|
87
|
+
logger.info(context, 'Successfully connected to MongoDB.');
|
|
88
|
+
loadModels();
|
|
131
89
|
defaultDb.on('error', function (error) {
|
|
132
90
|
logger.error(context, 'Mongo Driver error: %j', error);
|
|
91
|
+
lastError = error;
|
|
133
92
|
alarms.raise(constants.MONGO_ALARM, error);
|
|
134
93
|
});
|
|
135
94
|
/* eslint-disable-next-line no-unused-vars */
|
|
136
95
|
defaultDb.on('connecting', function (error) {
|
|
137
96
|
logger.debug(context, 'Mongo Driver connecting');
|
|
138
97
|
});
|
|
139
|
-
|
|
140
98
|
defaultDb.on('connected', function () {
|
|
141
99
|
logger.debug(context, 'Mongo Driver connected');
|
|
142
100
|
});
|
|
@@ -159,69 +117,52 @@ function init(host, db, port, options, callback) {
|
|
|
159
117
|
defaultDb.on('close', function () {
|
|
160
118
|
logger.debug(context, 'Mongo Driver close');
|
|
161
119
|
});
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
120
|
+
callback();
|
|
121
|
+
})
|
|
122
|
+
.catch((err) => {
|
|
123
|
+
logger.error(context, `MONGODB-001: Error trying to connect to MongoDB: ${err}`);
|
|
124
|
+
lastError = err;
|
|
125
|
+
retries++;
|
|
126
|
+
if (retries < maxRetries) {
|
|
127
|
+
const retryTime = config.getConfig().mongodb?.retryTime || constants.DEFAULT_MONGODB_RETRY_TIME;
|
|
128
|
+
logger.info(context, `Retrying in ${retryTime} seconds...`);
|
|
129
|
+
setTimeout(() => connectionAttempt(callback), retryTime * 1000);
|
|
130
|
+
} else {
|
|
131
|
+
logger.error(
|
|
132
|
+
context,
|
|
133
|
+
'MONGODB-002: Error to connect found after %d attempts: %s',
|
|
134
|
+
retries,
|
|
135
|
+
lastError
|
|
136
|
+
);
|
|
137
|
+
callback(err);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
183
140
|
}
|
|
184
141
|
|
|
185
|
-
|
|
186
|
-
async.whilst(retryCheck, tryCreateConnection, createConnectionHandler);
|
|
142
|
+
connectionAttempt(callback);
|
|
187
143
|
}
|
|
188
144
|
|
|
189
145
|
function configureDb(callback) {
|
|
190
|
-
/*jshint camelcase:false, validthis:true */
|
|
191
146
|
const currentConfig = config.getConfig();
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (!currentConfig.mongodb || !currentConfig.mongodb.host) {
|
|
147
|
+
if (currentConfig.deviceRegistry?.type === 'mongodb') {
|
|
148
|
+
if (!currentConfig.mongodb?.host) {
|
|
195
149
|
logger.fatal(context, 'MONGODB-003: No host found for MongoDB driver.');
|
|
196
150
|
callback(new errors.BadConfiguration('No host found for MongoDB driver'));
|
|
197
151
|
} else {
|
|
198
|
-
|
|
152
|
+
const dbName = currentConfig.mongodb.db || DEFAULT_DB_NAME;
|
|
199
153
|
const port = currentConfig.mongodb.port || 27017;
|
|
200
154
|
const options = {};
|
|
201
155
|
|
|
202
|
-
if (
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (currentConfig.mongodb.replicaSet) {
|
|
207
|
-
options.replicaSet = currentConfig.mongodb.replicaSet;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (currentConfig.mongodb.ssl) {
|
|
211
|
-
options.ssl = currentConfig.mongodb.ssl;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (currentConfig.mongodb.extraArgs) {
|
|
215
|
-
options.extraArgs = currentConfig.mongodb.extraArgs;
|
|
216
|
-
}
|
|
156
|
+
if (currentConfig.mongodb.replicaSet) options.replicaSet = currentConfig.mongodb.replicaSet;
|
|
157
|
+
if (currentConfig.mongodb.ssl) options.ssl = currentConfig.mongodb.ssl;
|
|
158
|
+
if (currentConfig.mongodb.extraArgs) options.extraArgs = currentConfig.mongodb.extraArgs;
|
|
217
159
|
|
|
218
160
|
if (currentConfig.mongodb.user && currentConfig.mongodb.password) {
|
|
219
|
-
options.auth = {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
161
|
+
options.auth = {
|
|
162
|
+
user: currentConfig.mongodb.user,
|
|
163
|
+
password: currentConfig.mongodb.password
|
|
164
|
+
};
|
|
223
165
|
if (currentConfig.mongodb.authSource) {
|
|
224
|
-
// Overload extraArgs if it was set
|
|
225
166
|
options.extraArgs = {
|
|
226
167
|
...options.extraArgs,
|
|
227
168
|
authSource: currentConfig.mongodb.authSource
|
|
@@ -229,7 +170,7 @@ function configureDb(callback) {
|
|
|
229
170
|
}
|
|
230
171
|
}
|
|
231
172
|
|
|
232
|
-
init(
|
|
173
|
+
init(currentConfig.mongodb.host, dbName, port, options, callback);
|
|
233
174
|
}
|
|
234
175
|
} else {
|
|
235
176
|
callback();
|