Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Merge-Patch Support Handling #1283

Merged
merged 19 commits into from
Mar 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES_NEXT_RELEASE
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
- Add NGSI-LD Merge-Patch Support Handling #1283
- Update to offer NGSI-LD 1.6.1. Registrations #1302
- Document removal of support for NGSI-LD 1.3.1 Interface
7 changes: 6 additions & 1 deletion config.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ var config = {
},
server: {
port: 4041,
host: '0.0.0.0'
host: '0.0.0.0',
ldSupport : {
null: true,
datasetId: true,
merge: false
}
},
authentication: {
enabled: true,
Expand Down
8 changes: 8 additions & 0 deletions doc/howto.md
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,14 @@ iotAgentLib.setDataUpdateHandler(updateContextHandler);
iotAgentLib.setDataQueryHandler(queryContextHandler);
```

Where necessary, additional handlers to deal with command actuations and merge-patch operations may also be added when
necessary.

```javascript
iotAgentLib.setCommandHandler(commandHandler);
iotAgentLib.setMergePatchHandler(mergePatchHandler);
```

#### IOTA Testing

In order to test it, we need to create an HTTP server simulating the device. The quickest way to do that may be using
Expand Down
18 changes: 18 additions & 0 deletions doc/installationguide.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,22 @@ overriding the group setting.
}
```

When connected to an **NGSI-LD** context broker, an IoT Agent is able to indicate whether it is willing to accept `null`
values and also whether it is able to process the **NGSI-LD** `datasetId` metadata element. Setting these
values to `false` will cause the IoT Agent to return a 400 **Bad Request** HTTP status code explaining that the IoT
Agent does not support nulls or multi-attribute requests if they are encountered.

```javascript
{
baseRoot: '/',
port: 4041,
ldSupport : {
null: true,
datasetId: true
}
}
```

- **stats**: configure the periodic collection of statistics. Use `interval` in milliseconds to set the time between
stats writings.

Expand Down Expand Up @@ -301,6 +317,8 @@ overrides.
| IOTA_CB_NGSI_VERSION | `contextBroker.ngsiVersion` |
| IOTA_NORTH_HOST | `server.host` |
| IOTA_NORTH_PORT | `server.port` |
| IOTA_LD_SUPPORT_NULL | `server.ldSupport.null` |
| IOTA_LD_SUPPORT_DATASET_ID | `server.ldSupport.datasetId` |
Comment on lines +320 to +321
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those parameters need to be documented

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed af14fde

| IOTA_PROVIDER_URL | `providerUrl` |
| IOTA_AUTH_ENABLED | `authentication.enabled` |
| IOTA_AUTH_TYPE | `authentication.type` |
Expand Down
77 changes: 77 additions & 0 deletions doc/usermanual.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,83 @@ values.
The handler is expected to call its callback once with no parameters (failing to do so may cause unexpected behaviors in
the IoT Agent).

##### iotagentLib.setCommandHandler()

###### Signature

```javascript
function setCommandHandler(newHandler)
```

###### Description

Sets the new user handler for registered entity commands. This handler will be called whenever a command request arrives, with
the following parameters: (`id`, `type`, `service`, `subservice`, `attributes`, `callback`). The handler must retrieve
all the corresponding information from the devices and return a NGSI entity with the requested values.

The callback must be invoked with the updated Context Element, using the information retrieved from the devices. E.g.:

```javascript
callback(null, {
type: "TheType",
isPattern: false,
id: "EntityID",
attributes: [
{
name: "lumniscence",
type: "Lumens",
value: "432"
}
]
});
```

In the case of NGSI requests affecting multiple entities, this handler will be called multiple times, one for each
entity, and all the results will be combined into a single response. Only IoT Agents which deal with actuator devices will include a handler for commands.

###### Params

- newHandler: User handler for command requests.

##### iotagentLib.setMergePatchHandler()

###### Signature

```javascript
function setMergePatchHandler(newHandler)
```

###### Description

Sets the new user handler for NGSI-LD Entity [merge-patch](https://datatracker.ietf.org/doc/html/rfc7386) requests. This handler will be called whenever a merge-patch request arrives, with
the following parameters: (`id`, `type`, `service`, `subservice`, `attributes`, `callback`). The handler must retrieve
all the corresponding information from the devices and return a NGSI entity with the requested values.

The callback must be invoked with the updated Context Element, using the information retrieved from the devices. E.g.:

```javascript
callback(null, {
type: "TheType",
isPattern: false,
id: "EntityID",
attributes: [
{
name: "lumniscence",
type: "Lumens",
value: "432"
}
]
});
```

In the case of NGSI-LD requests affecting multiple entities, this handler will be
called multiple times. Since merge-patch is an advanced function, not all IoT Agents
will include a handler for merge-patch.

###### Params

- newHandler: User handler for merge-patch requests.

##### iotagentLib.setProvisioningHandler()

###### Signature
Expand Down
16 changes: 15 additions & 1 deletion lib/commonConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,9 @@ function processEnvironmentVariables() {
'IOTA_DEFAULT_ENTITY_NAME_CONJUNCTION',
'IOTA_JSON_LD_CONTEXT',
'IOTA_FALLBACK_TENANT',
'IOTA_FALLBACK_PATH'
'IOTA_FALLBACK_PATH',
'IOTA_LD_SUPPORT_NULL',
'IOTA_LD_SUPPORT_DATASET_ID'
];
const iotamVariables = [
'IOTA_IOTAM_URL',
Expand Down Expand Up @@ -263,6 +265,18 @@ function processEnvironmentVariables() {
config.server.port = process.env.IOTA_NORTH_PORT;
}

config.server.ldSupport = config.server.ldSupport || {null: true, datasetId: true, merge: false};

if (process.env.IOTA_LD_SUPPORT_NULL) {
config.server.ldSupport.null = process.env.IOTA_LD_SUPPORT_NULL === 'true';
}
if (process.env.IOTA_LD_SUPPORT_DATASET_ID) {
config.server.ldSupport.datasetId = process.env.IOTA_LD_SUPPORT_DATASET_ID === 'true';
}
if (process.env.IOTA_LD_SUPPORT_MERGE) {
config.server.ldSupport.datasetId = process.env.IOTA_LD_SUPPORT_MERGE === 'true';
}

if (process.env.IOTA_PROVIDER_URL) {
config.providerUrl = process.env.IOTA_PROVIDER_URL;
}
Expand Down
1 change: 1 addition & 0 deletions lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ module.exports = {
SUBSERVICE_HEADER: 'fiware-servicepath',
NGSI_LD_TENANT_HEADER: 'NGSILD-Tenant',
NGSI_LD_PATH_HEADER: 'NGSILD-Path',
NGSI_LD_NULL: 'urn:ngsi-ld:null',
//FIXME: check Keystone support this in lowercase, then change
AUTH_HEADER: 'X-Auth-Token',
X_FORWARDED_FOR_HEADER: 'x-forwarded-for',
Expand Down
1 change: 1 addition & 0 deletions lib/fiware-iotagent-lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ exports.getConfigurationSilently = groupConfig.getSilently;
exports.findConfiguration = groupConfig.find;
exports.setDataUpdateHandler = contextServer.setUpdateHandler;
exports.setCommandHandler = contextServer.setCommandHandler;
exports.setMergePatchHandler = contextServer.setMergePatchHandler;
exports.setDataQueryHandler = contextServer.setQueryHandler;
exports.setConfigurationHandler = contextServer.setConfigurationHandler;
exports.setRemoveConfigurationHandler = contextServer.setRemoveConfigurationHandler;
Expand Down
1 change: 1 addition & 0 deletions lib/services/devices/deviceService.js
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ function registerDevice(deviceObj, callback) {
deviceObj.type = deviceData.type;
deviceObj.staticAttributes = deviceData.staticAttributes;
deviceObj.commands = deviceData.commands;
deviceObj.lazy = deviceData.lazy;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain why you included this line and how it is related with functionalities implemented in this PR (merge patch)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is necessary to ensure that a lazy attribute may be merged-patched (see use on line lib/services/northBound/contextServer-NGSI-LD.js - 455)

if ('timestamp' in deviceData && deviceData.timestamp !== undefined) {
deviceObj.timestamp = deviceData.timestamp;
}
Expand Down
4 changes: 4 additions & 0 deletions lib/services/devices/registrationUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ function sendRegistrationsNgsiLD(unregister, deviceData, callback) {
const properties = [];
const lazy = deviceData.lazy || [];
const commands = deviceData.commands || [];
const supportMerge = config.getConfig().server.ldSupport.merge;

lazy.forEach((element) => {
properties.push(element.name);
Expand All @@ -328,6 +329,9 @@ function sendRegistrationsNgsiLD(unregister, deviceData, callback) {
if (commands.length > 0){
operations.push('updateOps');
}
if (supportMerge){
operations.push('mergeEntity');
}

if (properties.length === 0) {
logger.debug(context, 'Registration with Context Provider is not needed. Device without lazy atts or commands');
Expand Down
Loading