static celix_status_t etcdWatcher_addAlreadyExistingNodes(node_discovery_pt node_discovery, int* highestModified) { celix_status_t status = CELIX_SUCCESS; char** endpointArray = calloc(MAX_NODES, sizeof(*endpointArray)); char rootPath[MAX_ROOTNODE_LENGTH]; int i, size; *highestModified = -1; if (!endpointArray) { status = CELIX_ENOMEM; } else { for (i = 0; i < MAX_NODES; i++) { endpointArray[i] = calloc(MAX_KEY_LENGTH, sizeof(*endpointArray[i])); } // we need to go though all nodes and get the highest modifiedIndex if (((status = etcdWatcher_getRootPath(node_discovery->context, &rootPath[0])) == CELIX_SUCCESS) && (etcd_getEndpoints(rootPath, endpointArray, &size) == true)) { for (i = 0; i < size; i++) { node_description_pt nodeDescription = NULL; char* key = endpointArray[i]; int modIndex = 0; // check for key .. char action[MAX_ACTION_LENGTH]; char etcdValue[MAX_VALUE_LENGTH]; if (etcd_get(key, &etcdValue[0], &action[0], &modIndex) != true) { printf("NODE_DISCOVERY: Could not retrieve value for %s\n", key); status = CELIX_ILLEGAL_STATE; } else { status = etcdWatcher_getWiringEndpointFromKey(node_discovery, key, &etcdValue[0], &nodeDescription); node_discovery_addNode(node_discovery, nodeDescription); } if (modIndex > *highestModified) { *highestModified = modIndex; } } } for (i = 0; i < MAX_NODES; i++) { free(endpointArray[i]); } } free(endpointArray); return status; }
static celix_status_t etcdWatcher_getLocalNodePath(bundle_context_pt context, node_description_pt ownNodeDescription, char* localNodePath) { celix_status_t status = CELIX_SUCCESS; char rootPath[MAX_ROOTNODE_LENGTH]; if ((etcdWatcher_getRootPath(context, &rootPath[0]) != CELIX_SUCCESS)) { status = CELIX_ILLEGAL_STATE; } else if (rootPath[strlen(&rootPath[0]) - 1] == '/') { snprintf(localNodePath, MAX_LOCALNODE_LENGTH, "%s%s/%s", &rootPath[0], ownNodeDescription->zoneId, ownNodeDescription->nodeId); } else { snprintf(localNodePath, MAX_LOCALNODE_LENGTH, "%s/%s/%s", &rootPath[0], ownNodeDescription->zoneId, ownNodeDescription->nodeId); } return status; }
// gets everything from provided key celix_status_t etcdWatcher_getWiringEndpointFromKey(node_discovery_pt node_discovery, char* etcdKey, char* etcdValue, node_description_pt* nodeDescription) { celix_status_t status = CELIX_SUCCESS; char rootPath[MAX_ROOTNODE_LENGTH]; char expr[MAX_LOCALNODE_LENGTH]; char zoneId[MAX_LOCALNODE_LENGTH]; char nodeId[MAX_LOCALNODE_LENGTH]; char wireId[MAX_LOCALNODE_LENGTH]; etcdWatcher_getRootPath(node_discovery->context, &rootPath[0]); snprintf(expr, MAX_LOCALNODE_LENGTH, "/%s/%%[^/]/%%[^/]/%%[^/].*", rootPath); int foundItems = sscanf(etcdKey, expr, &zoneId[0], &nodeId[0], &wireId[0]); if (foundItems != 3) { printf("NODE_DISCOVERY: Could not find zone/node/wire (key: %s) \n", etcdKey); status = CELIX_ILLEGAL_STATE; } else { properties_pt nodeDescProperties = properties_create(); status = nodeDescription_create(nodeId, zoneId, nodeDescProperties, nodeDescription); if (status == CELIX_SUCCESS) { wiring_endpoint_description_pt wiringEndpointDescription = NULL; properties_pt wiringDescProperties = properties_create(); if (etcdValue != NULL) { if (wiringEndpoint_properties_load(etcdValue, wiringDescProperties) != CELIX_SUCCESS) { printf("NODE_DISCOVERY: Error while loading wiring properties"); } } status = wiringEndpointDescription_create(wireId, wiringDescProperties, &wiringEndpointDescription); if (status == CELIX_SUCCESS) { celixThreadMutex_lock(&(*nodeDescription)->wiring_ep_desc_list_lock); arrayList_add((*nodeDescription)->wiring_ep_descriptions_list, wiringEndpointDescription); celixThreadMutex_unlock(&(*nodeDescription)->wiring_ep_desc_list_lock); } } else { printf("NODE_DISCOVERY: Could not create Node description\n"); } } return status; }
/* * performs (blocking) etcd_watch calls to check for * changing discovery endpoint information within etcd. */ static void* etcdWatcher_run(void* data) { etcd_watcher_pt watcher = (etcd_watcher_pt) data; time_t timeBeforeWatch = time(NULL); static char rootPath[MAX_ROOTNODE_LENGTH]; int highestModified = 0; bundle_context_pt context = watcher->discovery->context; etcdWatcher_addAlreadyExistingWatchpoints(watcher->discovery, &highestModified); etcdWatcher_getRootPath(context, &rootPath[0]); while (watcher->running) { char rkey[MAX_KEY_LENGTH]; char value[MAX_VALUE_LENGTH]; char preValue[MAX_VALUE_LENGTH]; char action[MAX_ACTION_LENGTH]; int modIndex; if (etcd_watch(rootPath, highestModified + 1, &action[0], &preValue[0], &value[0], &rkey[0], &modIndex) == true) { if (strcmp(action, "set") == 0) { etcdWatcher_addEntry(watcher, &rkey[0], &value[0]); } else if (strcmp(action, "delete") == 0) { etcdWatcher_removeEntry(watcher, &rkey[0], &value[0]); } else if (strcmp(action, "expire") == 0) { etcdWatcher_removeEntry(watcher, &rkey[0], &value[0]); } else if (strcmp(action, "update") == 0) { etcdWatcher_addEntry(watcher, &rkey[0], &value[0]); } else { logHelper_log(*watcher->loghelper, OSGI_LOGSERVICE_INFO, "Unexpected action: %s", action); } highestModified = modIndex; } // update own framework uuid if (time(NULL) - timeBeforeWatch > (DEFAULT_ETCD_TTL/2)) { etcdWatcher_addOwnFramework(watcher); timeBeforeWatch = time(NULL); } } return NULL; }
static celix_status_t etcdWatcher_getLocalNodePath(bundle_context_pt context, char* localNodePath) { celix_status_t status = CELIX_SUCCESS; char rootPath[MAX_ROOTNODE_LENGTH]; char* uuid = NULL; if ((etcdWatcher_getRootPath(context, &rootPath[0]) != CELIX_SUCCESS)) { status = CELIX_ILLEGAL_STATE; } else if (((bundleContext_getProperty(context, OSGI_FRAMEWORK_FRAMEWORK_UUID, &uuid)) != CELIX_SUCCESS) || (!uuid)) { status = CELIX_ILLEGAL_STATE; } else if (rootPath[strlen(&rootPath[0]) - 1] == '/') { snprintf(localNodePath, MAX_LOCALNODE_LENGTH, "%s%s", &rootPath[0], uuid); } else { snprintf(localNodePath, MAX_LOCALNODE_LENGTH, "%s/%s", &rootPath[0], uuid); } return status; }
/* * retrieves all already existing discovery endpoints * from etcd and adds them to the poller. * * returns the modifiedIndex of the last modified * discovery endpoint (see etcd documentation). */ static celix_status_t etcdWatcher_addAlreadyExistingWatchpoints(discovery_pt discovery, int* highestModified) { celix_status_t status = CELIX_SUCCESS; char** nodeArr = calloc(MAX_NODES, sizeof(*nodeArr)); char rootPath[MAX_ROOTNODE_LENGTH]; int i, size; *highestModified = -1; for (i = 0; i < MAX_NODES; i++) { nodeArr[i] = calloc(MAX_KEY_LENGTH, sizeof(*nodeArr[i])); } // we need to go though all nodes and get the highest modifiedIndex if (((status = etcdWatcher_getRootPath(discovery->context, &rootPath[0])) == CELIX_SUCCESS) && (etcd_getNodes(rootPath, nodeArr, &size) == true)) { for (i = 0; i < size; i++) { char* key = nodeArr[i]; char value[MAX_VALUE_LENGTH]; char action[MAX_VALUE_LENGTH]; int modIndex; if (etcd_get(key, &value[0], &action[0], &modIndex) == true) { // TODO: check that this is not equals to the local endpoint endpointDiscoveryPoller_addDiscoveryEndpoint(discovery->poller, &value[0]); if (modIndex > *highestModified) { *highestModified = modIndex; } } } } for (i = 0; i < MAX_NODES; i++) { free(nodeArr[i]); } free(nodeArr); return status; }
/* * performs (blocking) etcd_watch calls to check for * changing discovery endpoint information within etcd. */ static void* etcdWatcher_run(void* data) { etcd_watcher_pt watcher = (etcd_watcher_pt) data; time_t timeBeforeWatch = time(NULL); char rootPath[MAX_ROOTNODE_LENGTH]; int highestModified = 0; node_discovery_pt node_discovery = watcher->node_discovery; bundle_context_pt context = node_discovery->context; memset(rootPath, 0, MAX_ROOTNODE_LENGTH); etcdWatcher_addAlreadyExistingNodes(node_discovery, &highestModified); etcdWatcher_getRootPath(context, rootPath); while ((celixThreadMutex_lock(&watcher->watcherLock) == CELIX_SUCCESS) && watcher->running) { char rkey[MAX_KEY_LENGTH]; char value[MAX_VALUE_LENGTH]; char preValue[MAX_VALUE_LENGTH]; char action[MAX_ACTION_LENGTH]; int modIndex; celixThreadMutex_unlock(&watcher->watcherLock); if (etcd_watch(rootPath, highestModified + 1, &action[0], &preValue[0], &value[0], &rkey[0], &modIndex) == true) { if ((strcmp(action, "set") == 0) || (strcmp(action, "create") == 0)) { node_description_pt nodeDescription = NULL; celix_status_t status = etcdWatcher_getWiringEndpointFromKey(node_discovery, &rkey[0], &value[0], &nodeDescription); if (status == CELIX_SUCCESS) { node_discovery_addNode(node_discovery, nodeDescription); } } else if (strcmp(action, "delete") == 0) { node_description_pt nodeDescription = NULL; celix_status_t status = etcdWatcher_getWiringEndpointFromKey(node_discovery, &rkey[0], NULL, &nodeDescription); if (status == CELIX_SUCCESS) { node_discovery_removeNode(node_discovery, nodeDescription); } } else if (strcmp(action, "expire") == 0) { node_description_pt nodeDescription = NULL; celix_status_t status = etcdWatcher_getWiringEndpointFromKey(node_discovery, &rkey[0], NULL, &nodeDescription); if (status == CELIX_SUCCESS) { node_discovery_removeNode(node_discovery, nodeDescription); } } else if (strcmp(action, "update") == 0) { node_description_pt nodeDescription = NULL; celix_status_t status = etcdWatcher_getWiringEndpointFromKey(node_discovery, &rkey[0], &value[0], &nodeDescription); if (status == CELIX_SUCCESS) { node_discovery_addNode(node_discovery, nodeDescription); } } else { fw_log(logger, OSGI_FRAMEWORK_LOG_INFO, "Unexpected action: %s", action); } highestModified = modIndex; } /* prevent busy waiting, in case etcd_watch returns false */ else if (time(NULL) - timeBeforeWatch <= (DEFAULT_ETCD_TTL / 4)) { sleep(DEFAULT_ETCD_TTL / 4); } // update own framework uuid if (time(NULL) - timeBeforeWatch > (DEFAULT_ETCD_TTL / 4)) { etcdWatcher_addOwnNode(watcher); // perform additional full-sync etcdWatcher_addAlreadyExistingNodes(node_discovery, &highestModified); timeBeforeWatch = time(NULL); } } if (watcher->running == false) { celixThreadMutex_unlock(&watcher->watcherLock); } return NULL; }