Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 3 additions & 0 deletions src/c/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ iot_data_t *edgex_common_config_defaults (const char *svcname)
iot_data_string_map_add (result, "Device/Labels", iot_data_alloc_typed_vector (0, IOT_DATA_STRING));
iot_data_string_map_add (result, "Device/ProfilesDir", iot_data_alloc_string ("", IOT_DATA_REF));
iot_data_string_map_add (result, "Device/DevicesDir", iot_data_alloc_string ("", IOT_DATA_REF));
iot_data_string_map_add (result, "Device/ProvisionWatchersDir", iot_data_alloc_string ("", IOT_DATA_REF));
iot_data_string_map_add (result, "Device/EventQLength", iot_data_alloc_ui32 (0));
iot_data_string_map_add (result, "Device/AllowedFails", iot_data_alloc_i32 (0));
iot_data_string_map_add (result, "Device/DeviceDownTimeout", iot_data_alloc_ui64 (0));
Expand Down Expand Up @@ -510,6 +511,7 @@ static void edgex_device_populateCommonConfigFromMap (edgex_device_config *confi
config->device.maxeventsize = iot_data_ui32 (iot_data_string_map_get (map, "MaxEventSize"));
config->device.profilesdir = iot_data_string_map_get_string (map, "Device/ProfilesDir");
config->device.devicesdir = iot_data_string_map_get_string (map, "Device/DevicesDir");
config->device.provisionwatchersdir = iot_data_string_map_get_string (map, "Device/ProvisionWatchersDir");
config->device.allowed_fails = iot_data_ui32 (iot_data_string_map_get (map, "Device/AllowedFails"));
config->device.dev_downtime = iot_data_ui64 (iot_data_string_map_get (map, "Device/DeviceDownTimeout"));

Expand Down Expand Up @@ -736,6 +738,7 @@ static JSON_Value *edgex_device_config_toJson (devsdk_service_t *svc)
json_object_set_uint (dobj, "MaxEventSize", svc->config.device.maxeventsize);
json_object_set_string (dobj, "ProfilesDir", svc->config.device.profilesdir);
json_object_set_string (dobj, "DevicesDir", svc->config.device.devicesdir);
json_object_set_string (dobj, "ProvisionWatchersDir", svc->config.device.provisionwatchersdir);
json_object_set_boolean
(dobj, "UpdateLastConnected", svc->config.device.updatelastconnected);
json_object_set_uint (dobj, "EventQLength", svc->config.device.eventqlen);
Expand Down
1 change: 1 addition & 0 deletions src/c/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ typedef struct edgex_device_deviceinfo
_Atomic(uint32_t) maxeventsize;
const char *profilesdir;
const char *devicesdir;
const char *provisionwatchersdir;
atomic_bool updatelastconnected;
uint32_t eventqlen;
uint32_t allowed_fails;
Expand Down
8 changes: 1 addition & 7 deletions src/c/examples/discovery/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,7 @@ curl -X POST 0:59999/api/v3/discovery
```

Initially, none of the discovered devices will be added to EdgeX, but by
using appropriate Provision Watchers they can be accepted. To upload the
supplied Provision Watchers to core-metadata:

```
curl -X POST [email protected] 0:59881/api/v3/provisionwatcher
curl -X POST [email protected] 0:59881/api/v3/provisionwatcher
```
using appropriate Provision Watchers they can be accepted. The structure of an example provision watcher can be found in res/watchers. The SDK will parse all watcher objects inside of the directory defined by the `Device/ProvisionWatcherDir` configuration value and automatically upload them to core-metadata. If a provision watcher already exists and is registered in core-metadata, it is skipped.

The Provision Watchers each match one of the discovered devices. They work by
specifying acceptance criteria (`identifiers`) that match potentially many
Expand Down
1 change: 1 addition & 0 deletions src/c/examples/discovery/res/configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Service:
Device:
ProfilesDir: ./res/profiles
DevicesDir: ./res/devices
ProvisionWatchersDir: ./res/watchers

MessageBus:
Optional:
Expand Down
25 changes: 25 additions & 0 deletions src/c/examples/discovery/res/watchers/watcher1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"apiVersion": "v3",
"name": "watcher1",
"identifiers": {
"MAC": "00-05-1B-A1-99-[0-9A-Fa-f][0-9A-Fa-f]"
},
"blockingIdentifiers": {
"MAC": [
"00-05-1B-A1-99-99"
]
},
"serviceName": "device-template",
"adminState": "UNLOCKED",
"discoveredDevice": {
"profileName": "TemplateSensor",
"serviceName": "device-template",
"adminState": "UNLOCKED",
"properties": {
"DeviceNameTemplate": {
"valueReplace": true,
"template": "device-name-{{MAC}}"
}
}
}
}
26 changes: 26 additions & 0 deletions src/c/examples/discovery/res/watchers/watcher2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"apiVersion": "v3",
"name": "watcher2",
"identifiers": {
"HTTP": "10\\.0\\.0\\.[0-9]*"
},
"blockingIdentifiers": {
"HTTP": [
"10.0.0.1",
"10.0.0.255"
]
},
"profileName": "TemplateSensor",
"adminstate": "UNLOCKED",
"discoveredDevice": {
"profileName": "TemplateSensor",
"serviceName": "device-template",
"adminState": "UNLOCKED",
"properties": {
"DeviceNameTemplate": {
"valueReplace": true,
"template": "device-name-{{HTTP}}"
}
}
}
}
1 change: 0 additions & 1 deletion src/c/examples/discovery/watcher1.json

This file was deleted.

1 change: 0 additions & 1 deletion src/c/examples/discovery/watcher2.json

This file was deleted.

54 changes: 54 additions & 0 deletions src/c/metadata.c
Original file line number Diff line number Diff line change
Expand Up @@ -747,3 +747,57 @@ edgex_watcher *edgex_metadata_client_get_watchers
*err = EDGEX_OK;
return result;
}

void edgex_metadata_client_add_watcher_jobj(iot_logger_t *lc, edgex_service_endpoints *endpoints, edgex_secret_provider_t *secretprovider, const char *servicename, JSON_Object *jobj, devsdk_error *err)
{

if (!json_object_get_string(jobj, "serviceName")) {
json_object_set_string (jobj, "serviceName", servicename);
}

if (!json_object_get_string(jobj, "adminState")) {
json_object_set_string (jobj, "adminState", "UNLOCKED");
}

if (!json_object_get_string(jobj, "apiVersion")) {
json_object_set_string (jobj, "apiVersion", EDGEX_API_VERSION);
}

JSON_Value *reqval = edgex_wrap_request("ProvisionWatcher", json_object_get_wrapping_value (jobj));
char *json = json_serialize_to_string(reqval);
edgex_ctx ctx;
*err = EDGEX_OK;
char url[URL_BUF_SIZE];

memset (&ctx, 0, sizeof (edgex_ctx));

snprintf
(
url,
URL_BUF_SIZE - 1,
"http://%s:%u/api/" EDGEX_API_VERSION "/provisionwatcher",
endpoints->metadata.host,
endpoints->metadata.port
);

iot_data_t *jwt_data = edgex_secrets_request_jwt (secretprovider);
ctx.jwt_token = iot_data_string (jwt_data);

edgex_http_post (lc, &ctx, url, json, edgex_http_write_cb, err);

iot_data_free(jwt_data);
ctx.jwt_token = NULL;

if (err->code == 0)
{
iot_log_info(lc, "Provision watcher %s created", json_object_get_string(jobj, "name"));
}
else
{
iot_log_info(lc, "edgex_metadata_client_add_watcher_jobj: %s: %s", err->reason, ctx.buff);
}

json_value_free (reqval);
free(ctx.buff);
json_free_serialized_string (json);
}
10 changes: 10 additions & 0 deletions src/c/metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,14 @@ edgex_watcher *edgex_metadata_client_get_watchers
devsdk_error * err
);

void edgex_metadata_client_add_watcher_jobj
(
iot_logger_t *lc,
edgex_service_endpoints *endpoints,
edgex_secret_provider_t *secretprovider,
const char *servicename,
JSON_Object *obj,
devsdk_error *err
);

#endif
11 changes: 11 additions & 0 deletions src/c/service.c
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,17 @@ static void startConfigured (devsdk_service_t *svc, const devsdk_timeout *deadli
edgex_watcher_free (w);
}

/* Load Provision Watchers from files and register in metadata */
if (svc->config.device.provisionwatchersdir && strlen (svc->config.device.provisionwatchersdir))
{
edgex_device_watchers_upload (svc, err);
if (err->code)
{
iot_log_error (svc->logger, "Failed to upload provision watchers from directory");
return;
}
}

/* Start scheduled events */

iot_scheduler_start (svc->scheduler);
Expand Down
80 changes: 79 additions & 1 deletion src/c/watchers.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@

#include "watchers.h"
#include "edgex-rest.h"

#include "service.h"
#include "errorlist.h"
#include "metadata.h"
#include "filesys.h"
#include <regex.h>

typedef struct edgex_watchlist_t
Expand Down Expand Up @@ -179,6 +182,24 @@ static bool matchpw (const edgex_watcher *pw, const iot_data_t *ids)
return true;
}

static bool edgex_watcher_exists (const edgex_watchlist_t *wl, const char *name)
{
bool exists = false;
pthread_rwlock_rdlock ((pthread_rwlock_t *)&wl->lock);

for (const edgex_watcher *w = wl->list; w; w = w->next)
{
if (strcmp (w->name, name) == 0)
{
exists = true;
break;
}
}

pthread_rwlock_unlock ((pthread_rwlock_t *)&wl->lock);
return exists;
}

edgex_watcher *edgex_watchlist_match (const edgex_watchlist_t *wl, const iot_data_t *ids)
{
pthread_rwlock_rdlock ((pthread_rwlock_t *)&wl->lock);
Expand All @@ -199,3 +220,60 @@ edgex_watcher *edgex_watchlist_match (const edgex_watchlist_t *wl, const iot_dat
pthread_rwlock_unlock ((pthread_rwlock_t *)&wl->lock);
return result;
}

static void edgex_add_watcher_json (devsdk_service_t *svc, const char *fname, devsdk_error *err)
{

JSON_Value *jval = json_parse_file (fname);
if (jval)
{
JSON_Object *jobj = json_value_get_object (jval);
const char *name = json_object_get_string (jobj, "name");
if (name)
{
iot_log_debug(svc->logger, "Checking existence of ProvisionWatcher %s", name);
if (edgex_watcher_exists (svc->watchlist, name))
{
iot_log_info(svc->logger, "ProvisionWatcher %s already exists: skipped", name);
}
else
{
JSON_Value *copy = json_value_deep_copy(jval);
JSON_Object *watchobj = json_value_get_object(copy);
edgex_metadata_client_add_watcher_jobj(svc->logger, &svc->config.endpoints, svc->secretstore, svc->name, watchobj, err);
}
}
else
{
iot_log_warn (svc->logger, "Provision watcher upload: Missing provisionwatcher name in %s", fname);
}

json_value_free (jval);
}
else
{
iot_log_error (svc->logger, "File %s does not parse as JSON", fname);
*err = EDGEX_CONF_PARSE_ERROR;
}
}

void edgex_device_watchers_upload (devsdk_service_t *svc, devsdk_error *err)
{
*err = EDGEX_OK;

if (!svc->config.device.provisionwatchersdir || !strlen(svc->config.device.provisionwatchersdir))
{
return; // No directory configured
}

iot_log_info (svc->logger, "Processing Provision Watchers from %s", svc->config.device.provisionwatchersdir);

devsdk_strings *filenames = devsdk_scandir (svc->logger, svc->config.device.provisionwatchersdir, "json");

for (devsdk_strings *f = filenames; f; f = f->next)
{
edgex_add_watcher_json (svc, f->str, err);
}

devsdk_strings_free (filenames);
}
1 change: 1 addition & 0 deletions src/c/watchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ extern bool edgex_watchlist_remove_watcher (edgex_watchlist_t *list, const char
extern void edgex_watchlist_update_watcher (edgex_watchlist_t *list, const edgex_watcher *updated);

extern edgex_watcher *edgex_watchlist_match (const edgex_watchlist_t *list, const iot_data_t *ids);
extern void edgex_device_watchers_upload (devsdk_service_t *svc, devsdk_error *err);

#endif