Skip to content
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
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_error(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
75 changes: 74 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,55 @@ 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;

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