Orion Context Broker - subscriptions - fiware

I have a small problem. Im doing a subscription to Orion Context Broker and I have a strange problem with URL of callback:
this code works from tutorial:
{
"entities": [
{
"type": "Room",
"isPattern": "false",
"id": "Room1"
}
],
"attributes": [
"temperature"
],
"reference": "http://localhost:1028/accumulate",
"duration": "P1M",
"notifyConditions": [
{
"type": "ONTIMEINTERVAL",
"condValues": [
"PT10S"
]
}
]
}
But this code doesnt work:
{
"entities": [
{
"type": "Room",
"isPattern": "false",
"id": "Room1"
}
],
"attributes": [
"temperature"
],
"reference": "http://192.168.1.12:1028/accumulate?name=dupex",
"duration": "P1M",
"notifyConditions": [
{
"type": "ONTIMEINTERVAL",
"condValues": [
"PT10S"
]
}
]
}
Only difference is reference field:
"reference": "192.168.1.12:1028/accumulate?name=dupex"
I got:
{
"subscribeError": {
"errorCode": {
"code": "400",
"reasonPhrase": "Bad Request",
"details": "Illegal value for JSON field"
}
}
}
Any Suggestion please :) thank you.

The root cause of the problem is that = is a forbidden character, not allowed in payload request for security reasons (see this section in the user manual about it).
There are two possible workarounds:
Avoid the usage of query strings in the URL for reference in subscribeContext, e.g. using http://192.168.1.12:1028/accumulate/name/dupex.
Encode URL encoding to avoid forbidden characters (in particular, the code for = is %3D) and prepare your code to decode it.
In case 2, you could use the follwoing reference in subscribeContext: http://192.168.1.12:1028/accumulate?name%3Ddupex. Then, an example of code that will take into account the encoding and get the name argument properly would be the following (written in Python using Flask as REST server framework):
from flask import Flask, request
from urllib import unquote
from urlparse import urlparse, parse_qs
app = Flask(__name__)
#app.route("/accumulate")
def test():
s = unquote(request.full_path) # /accumulate?name%3Dduplex -> /accumulate?name=duplex
p = urlparse(s) # extract the query part: '?name=duplex'
d = parse_qs(p.query) # stores the query part in a Python dictionary for easy access
name= d['name'][0] # name <- 'duplex'
# Do whatever you need with the name...
return ""
if __name__ == "__main__":
app.run()
I guess that a similar approach can be used in other languages (Java, Node, etc.).
EDIT: Orion version 1.2 support notification customization in the NGSIv2, which allows this use case. For example, you can define the following subscriptions:
{
..
"notification": {
"httpCustom": {
"url": "http://192.168.1.12:1028/accumulate",
"qs": {
"name": "dupex"
}
}
..
}
..
}
Please have a look to "Subscriptions" and "Custom Notifications" sections at NGSIv2 Specification for details.

Related

FIWARE - Orion Context Broker as Context Provider

I'm having a hard time understanding how context providers work in the Orion Context Broker.
I followed the examples in the step-by-step guide written by Jason Fox. However, I still do not exactly get what happens in the background and how the context broker exactly creates the POST from the registration. Here is what I am trying to do:
I do have a WeatherStation that provides sensor data for a neighborhood.
{
"id": "urn:ngsi-ld:WeatherStation:001",
"type": "Device:WeatherStation",
"temperature": {
"type": "Number",
"value": 20.5,
"metadata": {}
},
"windspeed": {
"type": "Number",
"value": 60.0,
"metadata": {}
}
}
Now I like the WeatherStation to be a context provider for all buildings.
{
"id": "urn:ngsi-ld:building:001",
"type": "Building"
}
Here is the registration that I try to use.
{
"id": null,
"description": "Random Weather Conditions",
"provider": {
"http": {
"url": "http://localhost:1026/v2"
},
"supportedForwardingMode": "all"
},
"dataProvided": {
"entities": [
{
"id": "null",
"idPattern": ".*",
"type": "Building",
"typePattern": null
}
],
"attrs": [
"temperature",
"windspeed"
],
"expression": null
},
"status": "active",
"expires": null,
"forwardingInformation": null
}
The context broker accepts both entities and the registration without any error.
Since I have a multi-tenant setup I use one fiware_service for the complete neighborhood but every building would later have a seperate fiware_servicepath. Hence, the weatherstation has a different servicepath than the building. Although I also tried to put them both on the same path.
For now I used the same headers for all entities.
{
"fiware-service": "filip",
"fiware-servicepath": "/testing"
}
Here is the log of the context broker (version: 3.1.0):
INFO#2021-09-23T19:17:17.944Z logTracing.cpp[212]: Request forwarded (regId: 614cd2b511c25270060d873a): POST http://localhost:1026/v2/op/query, request payload (87 bytes): {"entities":[{"idPattern":".*","type":"Building"}],"attrs":["temperature","windspeed"]}, response payload (2 bytes): [], response code: 200
INFO#2021-09-23T19:17:17.944Z logTracing.cpp[130]: Request received: POST /v2/op/query?options=normalized%2Ccount&limit=1000, request payload (55 bytes): {"entities": [{"idPattern": ".*", "type": "Building"}]}, response code: 200
The log says that it receives the request and forwards it as expected. However, as I understand it this would simply point to the same building entity again. Hence, it is somehow a circular forwarding. I also cannot tell anything about the headers of the request.
I do not understand how the forwarded request from the building can actually query the weather station for information. When I query my building I still only receive the entity with no own properties:
{
"id": "urn:ngsi-ld:building:001",
"type": "Building"
}
I also tried to vary the url of the registration but with no success.
Is this scenario actually possible with the current implementation? It would be very useful
Is there any example for this including also the headers?
I know that I could simply use reference but that would put more work on the user.
Thanks for any help on this.
It is messy, but you could achieve this via a subscription. Hold the weather station as a separate entity in the context broker and poll or push updates into the entity. The subscription would fire whenever the data changes and make two NGSI requests:
Find all entities which have a Relationship servicedBy=WeatherStationX
Run an upsert on all entities to add a Property to each entity:
{
"temperature" : {
"type" : "Property",
"value" : 7,
"unitCode": "CEL",
"observedAt": "XXXXX",
"providedBy": "WeatherStation1"
}
}
Where observedAt comes either from the payload of the weather station or the notification timestamp.
Within the existing IoT Agents, provisioning the link attribute allows a device to propagate measures to a second entity (e.g. this Thermometer entity is measuring temperature for an associated Building entity)
{
"entity_type": "Device",
"resource": "/iot/d",
"protocol": "PDI-IoTA-UltraLight",
..etc
"attributes": [
{"object_id": "l", "name": "temperature", "type":"Float",
"metadata":{
"unitCode":{"type": "Text", "value" :"CEL"}
}
}
],
"static_attributes": [
{
"name": "controlledAsset",
"type": "Relationship",
"value": "urn:ngsi-ld:Building:001",
"link": {
"attributes": ["temperature"],
"name": "providedBy",
"type": "Building"
}
}
]
}
At the moment the logic just links direct one-to-one, but it would be possible to raise a PR to check for an Array and update multiple entities in an upsert - the relevant section of code is here

ambari rest API + set json configuration in ambari

To create a new config group, it is mandatory to provide a config group name, a tag and the cluster name to which it belongs. The tag as seen in this example is a name of the service. Two config groups with the same tag cannot be associated with the same host.
how to run the following json file with curl ?
in order to set this config group in ambari
POST /api/v1/clusters/c1/config_groups
[
{
"ConfigGroup": {
"cluster_name": "c1",
"group_name": "hdfs-nextgenslaves",
"tag": "HDFS",
"description": "HDFS configs for rack added on May 19, 2010",
"hosts": [
{
"host_name": "host1"
}
],
"desired_configs": [
{
"type": "core-site",
"tag": "nextgen1",
"properties": {
"key": "value"
}
}
]
}
}
]
 reference - https://github.com/swagle/test/blob/master/docs/api/v1/config-groups.md
Is your question about how to send multiline json with curl? You can find different methods here.

Invalid OpenAPI JSON file - Expected type object but found type string for security definition

I'm getting a validation error for the following openApi.json file, which I'm trying to configure in order to use JWT authentication to my Endpoints service on Google Cloud. I'm following this guide - https://cloud.google.com/endpoints/docs/openapi/service-account-authentication#configure_auth. The error can be easily reproduced by pasting and validating my sample using the Swagger online parser. The error message is:
Swagger schema validation failed.
Expected type object but found type string at #/paths//my/api/get/responses/200/description/securityDefinitions/mySecurityDefinition/x-google-jwks_uri/x-google-issuer/type/flow/authorizationUrl/security/0
JSON_OBJECT_VALIDATION_FAILED
I'd like to understand why I get the message Expected type object but found type string. The error message looks like it's maybe complaining about the security definition, but I'm not seeing why.
openapi.json
{
"swagger": "2.0",
"info": {
"version": "1.0.0",
"title": "my-app-hostname.appspot.com"
},
"host": "my-app-hostname.appspot.com",
"basePath": "/api",
"schemes": [
"https"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"security" : [
"mySecurityDefinition"
],
"securityDefinitions": {
"mySecurityDefinition": {
"authorizationUrl": "",
"flow": "implicit",
"type": "oauth2",
"x-google-issuer": "myServiceAccountEmailAddress",
"x-google-jwks_uri": "https://www.googleapis.com/robot/v1/metadata/x509/myServiceAccountEmailAddress"
}
},
"paths": {
"/my/api": {
"get": {
"responses": {
"200": {
"description": "A successful response"
}
}
}
}
}
}
What am I doing wrong? If I change the 1st object in the security array to this, then it doesn't validate, but the parser gives no error message:
"security" : [
{
"mySecurityDefinition": [ ]
}
],

How to create new alerts in azure for all webapps at same time

I want to create new alerts(High CPU,RAM) for all AppServicePlans in a given subscription. I could not find Powershell commands to create new alerts. Is there a way we can create these alerts for all appserviceplans with a single script? May be using ARM template?
Sorry for pasting a direct answer, but I cannot yet comment. You get the error because in the documentation for Add-AzMetricAlertruleV2 it states: "$act is the output of New-AzActionGroup cmdlet". Meaning you need to use for example:
$act = New-AzActionGroup -ActionGroupId "testActionGroup"
After that you need to add it in the parameter -ActionGroup $act for it to work.
If you look at Resource Explorer and navigate to a manually created (near-realtime) alert, you should see the "critera" object defined like below. Here is a full example of a resource that seems to be working. Create some variables for each of your values:
{
"type": "Microsoft.Insights/metricAlerts",
"apiVersion": "2018-03-01",
"name": "[variables('alertName')]",
"location": "global",
"dependsOn": [],
"tags": {
"[concat('hidden-link:', variables('applicationInsightsResourceId'))]": "Resource",
"[concat('hidden-link:', variables('webtestResourceId'))]": "Resource"
},
"properties": {
"description": "[concat('Alert for ', parameters('availibilityTestName'))]",
"severity": 4,
"enabled": true,
"scopes": [
"[variables('webtestResourceId')]",
"[variables('applicationInsightsResourceId')]"
],
"evaluationFrequency": "PT5M",
"windowSize": "PT15M",
"criteria": {
"odata.type": "Microsoft.Azure.Monitor.WebtestLocationAvailabilityCriteria",
"webTestId": "[variables('webtestResourceId')]",
"componentId": "[variables('applicationInsightsResourceId')]",
"failedLocationCount": 3
},
"actions": [
{
"actionGroupId": "[resourceId('microsoft.insights/actiongroups', 'webhook')]",
"webHookProperties": {
// Some properties to send to webhook
}
}
]
}
}

Swagger ui url with parameters

How to pass base url in the form http://localhost:3000/resources/api/?key=aslkdajd1323121lklakskdl to swagger ui ?
I was able to access http://localhost:3000/resources/api but when I add auth filter and pass key, it says, Unauthorized.
Using swagger 1.X
Pre-populating the parameter through apiKeyauthorization in index.html did not help, but when I type in the key in UI, it worked. Unable to understand the reason for this. Hope someone can help me make sense out of it.
Try this swagger 2.0 file (use http://studio.restlet.com to downgrade to version 1.2) :
{
"swagger": "2.0",
"info": {
"version": "0.0.1",
"title": "Todo App"
},
"host": "localhost:3000",
"schemes": [
"http"
],
"paths": {
"/resources/api": {
"post": {
"parameters": [
{
"name": "key",
"in": "query",
"description": "key",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "Successful response"
}
}
}
}
}
}
I was able to solve this by adding
window.authorizations.add("key", new ApiKeyAuthorization("key", yourKeyValue, "query"));
in the SwaggerUI constructor function
window.swaggerUi = new SwaggerUi({ . . .
right before the statement
window.swaggerUi.load()
You just need get the parameter from the url with javscript. In the file "index.html", under swagger-ui/dist folder, add something like this to get your key:
var key = window.location.search.match(/key=([^&]+)/);
You can see a simple example in my GIST.