mirror of
https://github.com/netdata/netdata.git
synced 2025-04-28 14:42:31 +00:00
bearer authorization API (#15321)
* bearer authorization API - untested
* add machine guid to bearer token response
* removed REGISTRY_URL and replaced it with STRING
* eliminate url pointer from registry_machine_url
* remove registry_url counters from registry
* Revert "eliminate url pointer from registry_machine_url"
This reverts commit 79eff56f77
.
* registry machine urls are now a double linked list
* registry machine urls are now using aral
* all registry objects now use aral
* strings now have 64 partitions and use R/W spinlock
* string to 128 partitions
* fix macro without internal checks
* registry now uses the bearer token when the cookie is not there
* api/v1/registry sends back all nodes on each host
* registry option to use mmap; optimization of registry structures
* do not index the terminator byte in strings; use 256 string partitions
* registry loading optimization
* convert person urls to double linked list to save memory
* re-organize items loading and make sure person urls are always available as machine urls too
* disable registry mmap by default
* keep track of all machine guids and their URLs, even if the cookie cannot be set
* fix bearer parsing
This commit is contained in:
parent
afb8095ec0
commit
5943203a66
23 changed files with 866 additions and 595 deletions
|
@ -700,8 +700,6 @@ set(REGISTRY_PLUGIN_FILES
|
|||
registry/registry_machine.h
|
||||
registry/registry_person.c
|
||||
registry/registry_person.h
|
||||
registry/registry_url.c
|
||||
registry/registry_url.h
|
||||
)
|
||||
|
||||
set(STATSD_PLUGIN_FILES
|
||||
|
|
|
@ -661,8 +661,6 @@ REGISTRY_PLUGIN_FILES = \
|
|||
registry/registry_machine.h \
|
||||
registry/registry_person.c \
|
||||
registry/registry_person.h \
|
||||
registry/registry_url.c \
|
||||
registry/registry_url.h \
|
||||
$(NULL)
|
||||
|
||||
STATSD_PLUGIN_FILES = \
|
||||
|
|
|
@ -24,6 +24,11 @@ typedef struct avl_element {
|
|||
signed char avl_balance; /* Balance factor. */
|
||||
} avl_t;
|
||||
|
||||
typedef struct __attribute__((packed)) avl_element_packed {
|
||||
struct avl_element *avl_link[2]; /* Subtrees. */
|
||||
signed char avl_balance; /* Balance factor. */
|
||||
} avl_t_packed;
|
||||
|
||||
/* An AVL tree */
|
||||
typedef struct avl_tree_type {
|
||||
avl_t *root;
|
||||
|
|
|
@ -369,10 +369,6 @@ size_t dictionary_referenced_items(DICTIONARY *dict) {
|
|||
return referenced_items;
|
||||
}
|
||||
|
||||
long int dictionary_stats_for_registry(DICTIONARY *dict) {
|
||||
if(unlikely(!dict)) return 0;
|
||||
return (dict->stats->memory.index + dict->stats->memory.dict);
|
||||
}
|
||||
void dictionary_version_increment(DICTIONARY *dict) {
|
||||
__atomic_fetch_add(&dict->version, 1, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
|
|
@ -310,7 +310,6 @@ void dictionary_foreach_unlock(DICTFE *dfe);
|
|||
size_t dictionary_version(DICTIONARY *dict);
|
||||
size_t dictionary_entries(DICTIONARY *dict);
|
||||
size_t dictionary_referenced_items(DICTIONARY *dict);
|
||||
long int dictionary_stats_for_registry(DICTIONARY *dict);
|
||||
|
||||
// for all cases that the caller does not provide a stats structure, this is where they are accumulated.
|
||||
extern struct dictionary_stats dictionary_stats_category_other;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
typedef enum web_client_acl {
|
||||
WEB_CLIENT_ACL_NONE = (0),
|
||||
WEB_CLIENT_ACL_NOCHECK = (0),
|
||||
WEB_CLIENT_ACL_NOCHECK = (0), // Don't check anything - this should work on all channels
|
||||
WEB_CLIENT_ACL_DASHBOARD = (1 << 0),
|
||||
WEB_CLIENT_ACL_REGISTRY = (1 << 1),
|
||||
WEB_CLIENT_ACL_BADGE = (1 << 2),
|
||||
|
@ -23,9 +23,17 @@ typedef enum web_client_acl {
|
|||
WEB_CLIENT_ACL_SSL_DEFAULT = (1 << 8),
|
||||
WEB_CLIENT_ACL_ACLK = (1 << 9),
|
||||
WEB_CLIENT_ACL_WEBRTC = (1 << 10),
|
||||
WEB_CLIENT_ACL_BEARER_OPTIONAL = (1 << 11), // allow unprotected access if bearer is not enabled in netdata
|
||||
WEB_CLIENT_ACL_BEARER_REQUIRED = (1 << 12), // allow access only if a valid bearer is used
|
||||
} WEB_CLIENT_ACL;
|
||||
|
||||
#define WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC (WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK | WEB_CLIENT_ACL_WEBRTC)
|
||||
#define WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC (WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK | WEB_CLIENT_ACL_WEBRTC | WEB_CLIENT_ACL_BEARER_OPTIONAL)
|
||||
|
||||
#ifdef NETDATA_DEV_MODE
|
||||
#define ACL_DEV_OPEN_ACCESS WEB_CLIENT_ACL_DASHBOARD
|
||||
#else
|
||||
#define ACL_DEV_OPEN_ACCESS 0
|
||||
#endif
|
||||
|
||||
#define WEB_CLIENT_ACL_ALL 0xFFFF
|
||||
|
||||
|
|
|
@ -8,6 +8,11 @@ typedef int32_t REFCOUNT;
|
|||
// ----------------------------------------------------------------------------
|
||||
// STRING implementation - dedup all STRING
|
||||
|
||||
#define STRING_PARTITION_SHIFTS (0)
|
||||
#define STRING_PARTITIONS (256 >> STRING_PARTITION_SHIFTS)
|
||||
#define string_partition_str(str) ((uint8_t)((str)[0]) >> STRING_PARTITION_SHIFTS)
|
||||
#define string_partition(string) (string_partition_str((string)->str))
|
||||
|
||||
struct netdata_string {
|
||||
uint32_t length; // the string length including the terminating '\0'
|
||||
|
||||
|
@ -18,20 +23,22 @@ struct netdata_string {
|
|||
const char str[]; // the string itself, is appended to this structure
|
||||
};
|
||||
|
||||
static struct string_hashtable {
|
||||
static struct string_partition {
|
||||
RW_SPINLOCK spinlock; // the R/W spinlock to protect the Judy array
|
||||
|
||||
Pvoid_t JudyHSArray; // the Judy array - hashtable
|
||||
netdata_rwlock_t rwlock; // the R/W lock to protect the Judy array
|
||||
|
||||
size_t searches; // the number of successful searches in the index
|
||||
size_t duplications; // when a string is referenced
|
||||
size_t releases; // when a string is unreferenced
|
||||
|
||||
size_t inserts; // the number of successful inserts to the index
|
||||
size_t deletes; // the number of successful deleted from the index
|
||||
|
||||
long int entries; // the number of entries in the index
|
||||
long int active_references; // the number of active references alive
|
||||
long int memory; // the memory used, without the JudyHS index
|
||||
|
||||
size_t inserts; // the number of successful inserts to the index
|
||||
size_t deletes; // the number of successful deleted from the index
|
||||
size_t searches; // the number of successful searches in the index
|
||||
size_t duplications; // when a string is referenced
|
||||
size_t releases; // when a string is unreferenced
|
||||
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
// internal statistics
|
||||
size_t found_deleted_on_search;
|
||||
|
@ -41,50 +48,45 @@ static struct string_hashtable {
|
|||
size_t spins;
|
||||
#endif
|
||||
|
||||
} string_base = {
|
||||
.JudyHSArray = NULL,
|
||||
.rwlock = NETDATA_RWLOCK_INITIALIZER,
|
||||
};
|
||||
} string_base[STRING_PARTITIONS] = { 0 };
|
||||
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
#define string_internal_stats_add(var, val) __atomic_add_fetch(&string_base.var, val, __ATOMIC_RELAXED)
|
||||
#define string_internal_stats_add(partition, var, val) __atomic_add_fetch(&string_base[partition].var, val, __ATOMIC_RELAXED)
|
||||
#else
|
||||
#define string_internal_stats_add(var, val) do {;} while(0)
|
||||
#define string_internal_stats_add(partition, var, val) do {;} while(0)
|
||||
#endif
|
||||
|
||||
#define string_stats_atomic_increment(var) __atomic_add_fetch(&string_base.var, 1, __ATOMIC_RELAXED)
|
||||
#define string_stats_atomic_decrement(var) __atomic_sub_fetch(&string_base.var, 1, __ATOMIC_RELAXED)
|
||||
#define string_stats_atomic_increment(partition, var) __atomic_add_fetch(&string_base[partition].var, 1, __ATOMIC_RELAXED)
|
||||
#define string_stats_atomic_decrement(partition, var) __atomic_sub_fetch(&string_base[partition].var, 1, __ATOMIC_RELAXED)
|
||||
|
||||
void string_statistics(size_t *inserts, size_t *deletes, size_t *searches, size_t *entries, size_t *references, size_t *memory, size_t *duplications, size_t *releases) {
|
||||
if(inserts)
|
||||
*inserts = string_base.inserts;
|
||||
if (inserts) *inserts = 0;
|
||||
if (deletes) *deletes = 0;
|
||||
if (searches) *searches = 0;
|
||||
if (entries) *entries = 0;
|
||||
if (references) *references = 0;
|
||||
if (memory) *memory = 0;
|
||||
if (duplications) *duplications = 0;
|
||||
if (releases) *releases = 0;
|
||||
|
||||
if(deletes)
|
||||
*deletes = string_base.deletes;
|
||||
|
||||
if(searches)
|
||||
*searches = string_base.searches;
|
||||
|
||||
if(entries)
|
||||
*entries = (size_t)string_base.entries;
|
||||
|
||||
if(references)
|
||||
*references = (size_t)string_base.active_references;
|
||||
|
||||
if(memory)
|
||||
*memory = (size_t)string_base.memory;
|
||||
|
||||
if(duplications)
|
||||
*duplications = string_base.duplications;
|
||||
|
||||
if(releases)
|
||||
*releases = string_base.releases;
|
||||
for(size_t i = 0; i < STRING_PARTITIONS ;i++) {
|
||||
if (inserts) *inserts += string_base[i].inserts;
|
||||
if (deletes) *deletes += string_base[i].deletes;
|
||||
if (searches) *searches += string_base[i].searches;
|
||||
if (entries) *entries += (size_t) string_base[i].entries;
|
||||
if (references) *references += (size_t) string_base[i].active_references;
|
||||
if (memory) *memory += (size_t) string_base[i].memory;
|
||||
if (duplications) *duplications += string_base[i].duplications;
|
||||
if (releases) *releases += string_base[i].releases;
|
||||
}
|
||||
}
|
||||
|
||||
#define string_entry_acquire(se) __atomic_add_fetch(&((se)->refcount), 1, __ATOMIC_SEQ_CST);
|
||||
#define string_entry_release(se) __atomic_sub_fetch(&((se)->refcount), 1, __ATOMIC_SEQ_CST);
|
||||
|
||||
static inline bool string_entry_check_and_acquire(STRING *se) {
|
||||
uint8_t partition = string_partition(se);
|
||||
|
||||
REFCOUNT expected, desired, count = 0;
|
||||
|
||||
expected = __atomic_load_n(&se->refcount, __ATOMIC_SEQ_CST);
|
||||
|
@ -96,7 +98,7 @@ static inline bool string_entry_check_and_acquire(STRING *se) {
|
|||
// We cannot use this.
|
||||
// The reference counter reached value zero,
|
||||
// so another thread is deleting this.
|
||||
string_internal_stats_add(spins, count - 1);
|
||||
string_internal_stats_add(partition, spins, count - 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -104,11 +106,11 @@ static inline bool string_entry_check_and_acquire(STRING *se) {
|
|||
|
||||
} while(!__atomic_compare_exchange_n(&se->refcount, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST));
|
||||
|
||||
string_internal_stats_add(spins, count - 1);
|
||||
string_internal_stats_add(partition, spins, count - 1);
|
||||
|
||||
// statistics
|
||||
// string_base.active_references is altered at the in string_strdupz() and string_freez()
|
||||
string_stats_atomic_increment(duplications);
|
||||
string_stats_atomic_increment(partition, duplications);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -123,9 +125,11 @@ STRING *string_dup(STRING *string) {
|
|||
|
||||
string_entry_acquire(string);
|
||||
|
||||
uint8_t partition = string_partition(string);
|
||||
|
||||
// statistics
|
||||
string_stats_atomic_increment(active_references);
|
||||
string_stats_atomic_increment(duplications);
|
||||
string_stats_atomic_increment(partition, active_references);
|
||||
string_stats_atomic_increment(partition, duplications);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
@ -134,26 +138,28 @@ STRING *string_dup(STRING *string) {
|
|||
static inline STRING *string_index_search(const char *str, size_t length) {
|
||||
STRING *string;
|
||||
|
||||
uint8_t partition = string_partition_str(str);
|
||||
|
||||
// Find the string in the index
|
||||
// With a read-lock so that multiple readers can use the index concurrently.
|
||||
|
||||
netdata_rwlock_rdlock(&string_base.rwlock);
|
||||
rw_spinlock_read_lock(&string_base[partition].spinlock);
|
||||
|
||||
Pvoid_t *Rc;
|
||||
Rc = JudyHSGet(string_base.JudyHSArray, (void *)str, length);
|
||||
Rc = JudyHSGet(string_base[partition].JudyHSArray, (void *)str, length - 1);
|
||||
if(likely(Rc)) {
|
||||
// found in the hash table
|
||||
string = *Rc;
|
||||
|
||||
if(string_entry_check_and_acquire(string)) {
|
||||
// we can use this entry
|
||||
string_internal_stats_add(found_available_on_search, 1);
|
||||
string_internal_stats_add(partition, found_available_on_search, 1);
|
||||
}
|
||||
else {
|
||||
// this entry is about to be deleted by another thread
|
||||
// do not touch it, let it go...
|
||||
string = NULL;
|
||||
string_internal_stats_add(found_deleted_on_search, 1);
|
||||
string_internal_stats_add(partition, found_deleted_on_search, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -161,8 +167,8 @@ static inline STRING *string_index_search(const char *str, size_t length) {
|
|||
string = NULL;
|
||||
}
|
||||
|
||||
string_stats_atomic_increment(searches);
|
||||
netdata_rwlock_unlock(&string_base.rwlock);
|
||||
string_stats_atomic_increment(partition, searches);
|
||||
rw_spinlock_read_unlock(&string_base[partition].spinlock);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
@ -175,12 +181,14 @@ static inline STRING *string_index_search(const char *str, size_t length) {
|
|||
static inline STRING *string_index_insert(const char *str, size_t length) {
|
||||
STRING *string;
|
||||
|
||||
netdata_rwlock_wrlock(&string_base.rwlock);
|
||||
uint8_t partition = string_partition_str(str);
|
||||
|
||||
rw_spinlock_write_lock(&string_base[partition].spinlock);
|
||||
|
||||
STRING **ptr;
|
||||
{
|
||||
JError_t J_Error;
|
||||
Pvoid_t *Rc = JudyHSIns(&string_base.JudyHSArray, (void *)str, length, &J_Error);
|
||||
Pvoid_t *Rc = JudyHSIns(&string_base[partition].JudyHSArray, (void *)str, length - 1, &J_Error);
|
||||
if (unlikely(Rc == PJERR)) {
|
||||
fatal(
|
||||
"STRING: Cannot insert entry with name '%s' to JudyHS, JU_ERRNO_* == %u, ID == %d",
|
||||
|
@ -199,9 +207,9 @@ static inline STRING *string_index_insert(const char *str, size_t length) {
|
|||
string->length = length;
|
||||
string->refcount = 1;
|
||||
*ptr = string;
|
||||
string_base.inserts++;
|
||||
string_base.entries++;
|
||||
string_base.memory += (long)(mem_size + JUDYHS_INDEX_SIZE_ESTIMATE(length));
|
||||
string_base[partition].inserts++;
|
||||
string_base[partition].entries++;
|
||||
string_base[partition].memory += (long)(mem_size + JUDYHS_INDEX_SIZE_ESTIMATE(length));
|
||||
}
|
||||
else {
|
||||
// the item is already in the index
|
||||
|
@ -209,25 +217,27 @@ static inline STRING *string_index_insert(const char *str, size_t length) {
|
|||
|
||||
if(string_entry_check_and_acquire(string)) {
|
||||
// we can use this entry
|
||||
string_internal_stats_add(found_available_on_insert, 1);
|
||||
string_internal_stats_add(partition, found_available_on_insert, 1);
|
||||
}
|
||||
else {
|
||||
// this entry is about to be deleted by another thread
|
||||
// do not touch it, let it go...
|
||||
string = NULL;
|
||||
string_internal_stats_add(found_deleted_on_insert, 1);
|
||||
string_internal_stats_add(partition, found_deleted_on_insert, 1);
|
||||
}
|
||||
|
||||
string_stats_atomic_increment(searches);
|
||||
string_stats_atomic_increment(partition, searches);
|
||||
}
|
||||
|
||||
netdata_rwlock_unlock(&string_base.rwlock);
|
||||
rw_spinlock_write_unlock(&string_base[partition].spinlock);
|
||||
return string;
|
||||
}
|
||||
|
||||
// delete an entry from the index
|
||||
static inline void string_index_delete(STRING *string) {
|
||||
netdata_rwlock_wrlock(&string_base.rwlock);
|
||||
uint8_t partition = string_partition(string);
|
||||
|
||||
rw_spinlock_write_lock(&string_base[partition].spinlock);
|
||||
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
if(unlikely(__atomic_load_n(&string->refcount, __ATOMIC_SEQ_CST) != 0))
|
||||
|
@ -236,9 +246,9 @@ static inline void string_index_delete(STRING *string) {
|
|||
|
||||
bool deleted = false;
|
||||
|
||||
if (likely(string_base.JudyHSArray)) {
|
||||
if (likely(string_base[partition].JudyHSArray)) {
|
||||
JError_t J_Error;
|
||||
int ret = JudyHSDel(&string_base.JudyHSArray, (void *)string->str, string->length, &J_Error);
|
||||
int ret = JudyHSDel(&string_base[partition].JudyHSArray, (void *)string->str, string->length - 1, &J_Error);
|
||||
if (unlikely(ret == JERR)) {
|
||||
netdata_log_error(
|
||||
"STRING: Cannot delete entry with name '%s' from JudyHS, JU_ERRNO_* == %u, ID == %d",
|
||||
|
@ -253,18 +263,20 @@ static inline void string_index_delete(STRING *string) {
|
|||
netdata_log_error("STRING: tried to delete '%s' that is not in the index. Ignoring it.", string->str);
|
||||
else {
|
||||
size_t mem_size = sizeof(STRING) + string->length;
|
||||
string_base.deletes++;
|
||||
string_base.entries--;
|
||||
string_base.memory -= (long)(mem_size + JUDYHS_INDEX_SIZE_ESTIMATE(string->length));
|
||||
string_base[partition].deletes++;
|
||||
string_base[partition].entries--;
|
||||
string_base[partition].memory -= (long)(mem_size + JUDYHS_INDEX_SIZE_ESTIMATE(string->length));
|
||||
freez(string);
|
||||
}
|
||||
|
||||
netdata_rwlock_unlock(&string_base.rwlock);
|
||||
rw_spinlock_write_unlock(&string_base[partition].spinlock);
|
||||
}
|
||||
|
||||
STRING *string_strdupz(const char *str) {
|
||||
if(unlikely(!str || !*str)) return NULL;
|
||||
|
||||
uint8_t partition = string_partition_str(str);
|
||||
|
||||
size_t length = strlen(str) + 1;
|
||||
STRING *string = string_index_search(str, length);
|
||||
|
||||
|
@ -277,7 +289,7 @@ STRING *string_strdupz(const char *str) {
|
|||
}
|
||||
|
||||
// statistics
|
||||
string_stats_atomic_increment(active_references);
|
||||
string_stats_atomic_increment(partition, active_references);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
@ -285,6 +297,7 @@ STRING *string_strdupz(const char *str) {
|
|||
void string_freez(STRING *string) {
|
||||
if(unlikely(!string)) return;
|
||||
|
||||
uint8_t partition = string_partition(string);
|
||||
REFCOUNT refcount = string_entry_release(string);
|
||||
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
|
@ -296,8 +309,8 @@ void string_freez(STRING *string) {
|
|||
string_index_delete(string);
|
||||
|
||||
// statistics
|
||||
string_stats_atomic_decrement(active_references);
|
||||
string_stats_atomic_increment(releases);
|
||||
string_stats_atomic_decrement(partition, active_references);
|
||||
string_stats_atomic_increment(partition, releases);
|
||||
}
|
||||
|
||||
inline size_t string_strlen(STRING *string) {
|
||||
|
@ -405,6 +418,54 @@ static void string_unittest_free_char_pp(char **pp, size_t entries) {
|
|||
freez(pp);
|
||||
}
|
||||
|
||||
static long unittest_string_entries(void) {
|
||||
long entries = 0;
|
||||
for(size_t p = 0; p < STRING_PARTITIONS ;p++)
|
||||
entries += string_base[p].entries;
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
|
||||
static size_t unittest_string_found_deleted_on_search(void) {
|
||||
size_t entries = 0;
|
||||
for(size_t p = 0; p < STRING_PARTITIONS ;p++)
|
||||
entries += string_base[p].found_deleted_on_search;
|
||||
|
||||
return entries;
|
||||
}
|
||||
static size_t unittest_string_found_available_on_search(void) {
|
||||
size_t entries = 0;
|
||||
for(size_t p = 0; p < STRING_PARTITIONS ;p++)
|
||||
entries += string_base[p].found_available_on_search;
|
||||
|
||||
return entries;
|
||||
}
|
||||
static size_t unittest_string_found_deleted_on_insert(void) {
|
||||
size_t entries = 0;
|
||||
for(size_t p = 0; p < STRING_PARTITIONS ;p++)
|
||||
entries += string_base[p].found_deleted_on_insert;
|
||||
|
||||
return entries;
|
||||
}
|
||||
static size_t unittest_string_found_available_on_insert(void) {
|
||||
size_t entries = 0;
|
||||
for(size_t p = 0; p < STRING_PARTITIONS ;p++)
|
||||
entries += string_base[p].found_available_on_insert;
|
||||
|
||||
return entries;
|
||||
}
|
||||
static size_t unittest_string_spins(void) {
|
||||
size_t entries = 0;
|
||||
for(size_t p = 0; p < STRING_PARTITIONS ;p++)
|
||||
entries += string_base[p].spins;
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
#endif // NETDATA_INTERNAL_CHECKS
|
||||
|
||||
int string_unittest(size_t entries) {
|
||||
size_t errors = 0;
|
||||
|
||||
|
@ -413,7 +474,7 @@ int string_unittest(size_t entries) {
|
|||
|
||||
// check string
|
||||
{
|
||||
long int string_entries_starting = string_base.entries;
|
||||
long entries_starting = unittest_string_entries();
|
||||
|
||||
fprintf(stderr, "\nChecking strings...\n");
|
||||
|
||||
|
@ -496,9 +557,10 @@ int string_unittest(size_t entries) {
|
|||
|
||||
freez(strings);
|
||||
|
||||
if(string_base.entries != string_entries_starting + 2) {
|
||||
if(unittest_string_entries() != entries_starting + 2) {
|
||||
errors++;
|
||||
fprintf(stderr, "ERROR: strings dictionary should have %ld items but it has %ld\n", string_entries_starting + 2, string_base.entries);
|
||||
fprintf(stderr, "ERROR: strings dictionary should have %ld items but it has %ld\n",
|
||||
entries_starting + 2, unittest_string_entries());
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "OK: strings dictionary has 2 items\n");
|
||||
|
@ -551,11 +613,11 @@ int string_unittest(size_t entries) {
|
|||
};
|
||||
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
size_t ofound_deleted_on_search = string_base.found_deleted_on_search,
|
||||
ofound_available_on_search = string_base.found_available_on_search,
|
||||
ofound_deleted_on_insert = string_base.found_deleted_on_insert,
|
||||
ofound_available_on_insert = string_base.found_available_on_insert,
|
||||
ospins = string_base.spins;
|
||||
size_t ofound_deleted_on_search = unittest_string_found_deleted_on_search(),
|
||||
ofound_available_on_search = unittest_string_found_available_on_search(),
|
||||
ofound_deleted_on_insert = unittest_string_found_deleted_on_insert(),
|
||||
ofound_available_on_insert = unittest_string_found_available_on_insert(),
|
||||
ospins = unittest_string_spins();
|
||||
#endif
|
||||
|
||||
size_t oinserts, odeletes, osearches, oentries, oreferences, omemory, oduplications, oreleases;
|
||||
|
@ -592,11 +654,11 @@ int string_unittest(size_t entries) {
|
|||
inserts - oinserts, deletes - odeletes, searches - osearches, sentries - oentries, references - oreferences, memory - omemory, duplications - oduplications, releases - oreleases);
|
||||
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
size_t found_deleted_on_search = string_base.found_deleted_on_search,
|
||||
found_available_on_search = string_base.found_available_on_search,
|
||||
found_deleted_on_insert = string_base.found_deleted_on_insert,
|
||||
found_available_on_insert = string_base.found_available_on_insert,
|
||||
spins = string_base.spins;
|
||||
size_t found_deleted_on_search = unittest_string_found_deleted_on_search(),
|
||||
found_available_on_search = unittest_string_found_available_on_search(),
|
||||
found_deleted_on_insert = unittest_string_found_deleted_on_insert(),
|
||||
found_available_on_insert = unittest_string_found_available_on_insert(),
|
||||
spins = unittest_string_spins();
|
||||
|
||||
fprintf(stderr, "on insert: %zu ok + %zu deleted\non search: %zu ok + %zu deleted\nspins: %zu\n",
|
||||
found_available_on_insert - ofound_available_on_insert,
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
#define REGISTRY_STATUS_FAILED "failed"
|
||||
#define REGISTRY_STATUS_DISABLED "disabled"
|
||||
|
||||
bool registry_is_valid_url(const char *url) {
|
||||
return url && (*url == 'h' || *url == '*');
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// REGISTRY concurrency locking
|
||||
|
||||
|
@ -23,19 +27,19 @@ static inline void registry_unlock(void) {
|
|||
// COOKIES
|
||||
|
||||
static void registry_set_cookie(struct web_client *w, const char *guid) {
|
||||
char edate[100];
|
||||
char e_date[100];
|
||||
time_t et = now_realtime_sec() + registry.persons_expiration;
|
||||
struct tm etmbuf, *etm = gmtime_r(&et, &etmbuf);
|
||||
strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", etm);
|
||||
struct tm e_tm_buf, *etm = gmtime_r(&et, &e_tm_buf);
|
||||
strftime(e_date, sizeof(e_date), "%a, %d %b %Y %H:%M:%S %Z", etm);
|
||||
|
||||
buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s\r\n", guid, edate);
|
||||
buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s\r\n", guid, e_date);
|
||||
if(registry.enable_cookies_samesite_secure)
|
||||
buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s; SameSite=None; Secure\r\n", guid, edate);
|
||||
buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s; SameSite=None; Secure\r\n", guid, e_date);
|
||||
|
||||
if(registry.registry_domain && *registry.registry_domain) {
|
||||
buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s; Domain=%s\r\n", guid, edate, registry.registry_domain);
|
||||
buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s; Domain=%s\r\n", guid, e_date, registry.registry_domain);
|
||||
if(registry.enable_cookies_samesite_secure)
|
||||
buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s; Domain=%s; SameSite=None; Secure\r\n", guid, edate, registry.registry_domain);
|
||||
buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s; Domain=%s; SameSite=None; Secure\r\n", guid, e_date, registry.registry_domain);
|
||||
}
|
||||
|
||||
w->response.has_cookies = true;
|
||||
|
@ -84,37 +88,41 @@ struct registry_json_walk_person_urls_callback {
|
|||
int count;
|
||||
};
|
||||
|
||||
static STRING *asterisks = NULL;
|
||||
|
||||
// callback for rendering PERSON_URLs
|
||||
static int registry_json_person_url_callback(void *entry, void *data) {
|
||||
REGISTRY_PERSON_URL *pu = (REGISTRY_PERSON_URL *)entry;
|
||||
struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data;
|
||||
static int registry_json_person_url_callback(REGISTRY_PERSON_URL *pu, struct registry_json_walk_person_urls_callback *c) {
|
||||
if(unlikely(!asterisks))
|
||||
asterisks = string_strdupz("***");
|
||||
|
||||
struct web_client *w = c->w;
|
||||
|
||||
if (!strcmp(pu->url->url,"***")) return 0;
|
||||
if (pu->url == asterisks) return 0;
|
||||
|
||||
buffer_json_add_array_item_array(w->response.data);
|
||||
buffer_json_add_array_item_string(w->response.data, pu->machine->guid);
|
||||
buffer_json_add_array_item_string(w->response.data, pu->url->url);
|
||||
buffer_json_add_array_item_string(w->response.data, string2str(pu->url));
|
||||
buffer_json_add_array_item_uint64(w->response.data, pu->last_t * (uint64_t) 1000);
|
||||
buffer_json_add_array_item_uint64(w->response.data, pu->usages);
|
||||
buffer_json_add_array_item_string(w->response.data, pu->machine_name);
|
||||
buffer_json_add_array_item_string(w->response.data, string2str(pu->machine_name));
|
||||
buffer_json_array_close(w->response.data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// callback for rendering MACHINE_URLs
|
||||
static int registry_json_machine_url_callback(const DICTIONARY_ITEM *item __maybe_unused, void *entry, void *data) {
|
||||
REGISTRY_MACHINE_URL *mu = (REGISTRY_MACHINE_URL *)entry;
|
||||
struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data;
|
||||
static int registry_json_machine_url_callback(REGISTRY_MACHINE_URL *mu, struct registry_json_walk_person_urls_callback *c) {
|
||||
if(unlikely(!asterisks))
|
||||
asterisks = string_strdupz("***");
|
||||
|
||||
struct web_client *w = c->w;
|
||||
REGISTRY_MACHINE *m = c->m;
|
||||
|
||||
if (!strcmp(mu->url->url,"***")) return 0;
|
||||
if (mu->url == asterisks) return 0;
|
||||
|
||||
buffer_json_add_array_item_array(w->response.data);
|
||||
buffer_json_add_array_item_string(w->response.data, m->guid);
|
||||
buffer_json_add_array_item_string(w->response.data, mu->url->url);
|
||||
buffer_json_add_array_item_string(w->response.data, string2str(mu->url));
|
||||
buffer_json_add_array_item_uint64(w->response.data, mu->last_t * (uint64_t) 1000);
|
||||
buffer_json_add_array_item_uint64(w->response.data, mu->usages);
|
||||
buffer_json_array_close(w->response.data);
|
||||
|
@ -130,9 +138,7 @@ struct registry_person_url_callback_verify_machine_exists_data {
|
|||
int count;
|
||||
};
|
||||
|
||||
static inline int registry_person_url_callback_verify_machine_exists(void *entry, void *data) {
|
||||
struct registry_person_url_callback_verify_machine_exists_data *d = (struct registry_person_url_callback_verify_machine_exists_data *)data;
|
||||
REGISTRY_PERSON_URL *pu = (REGISTRY_PERSON_URL *)entry;
|
||||
static inline int registry_person_url_callback_verify_machine_exists(REGISTRY_PERSON_URL *pu, struct registry_person_url_callback_verify_machine_exists_data *d) {
|
||||
REGISTRY_MACHINE *m = d->m;
|
||||
|
||||
if(pu->machine == m)
|
||||
|
@ -161,34 +167,54 @@ int registry_request_hello_json(RRDHOST *host, struct web_client *w) {
|
|||
buffer_json_member_add_string(w->response.data, "cloud_base_url", registry.cloud_base_url);
|
||||
buffer_json_member_add_boolean(w->response.data, "anonymous_statistics", netdata_anonymous_statistics_enabled);
|
||||
|
||||
buffer_json_member_add_array(w->response.data, "nodes");
|
||||
RRDHOST *h;
|
||||
dfe_start_read(rrdhost_root_index, h) {
|
||||
buffer_json_add_array_item_object(w->response.data);
|
||||
buffer_json_member_add_string(w->response.data, "machine_guid", h->machine_guid);
|
||||
buffer_json_member_add_string(w->response.data, "hostname", rrdhost_registry_hostname(h));
|
||||
buffer_json_object_close(w->response.data);
|
||||
}
|
||||
dfe_done(h);
|
||||
buffer_json_array_close(w->response.data);
|
||||
|
||||
registry_json_footer(w);
|
||||
return HTTP_RESP_OK;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//public ACCESS request
|
||||
|
||||
#define REGISTRY_VERIFY_COOKIES_GUID "give-me-back-this-cookie-now--please"
|
||||
// public ACCESS request
|
||||
|
||||
// the main method for registering an access
|
||||
int registry_request_access_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when) {
|
||||
if(unlikely(!registry.enabled))
|
||||
return registry_json_disabled(host, w, "access");
|
||||
|
||||
if(!registry_is_valid_url(url)) {
|
||||
buffer_flush(w->response.data);
|
||||
buffer_strcat(w->response.data, "Invalid URL given in the request");
|
||||
return HTTP_RESP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// verify the browser supports cookies
|
||||
// verify the browser supports cookies or the bearer
|
||||
|
||||
if(registry.verify_cookies_redirects > 0 && !person_guid[0]) {
|
||||
registry_request_access(REGISTRY_VERIFY_COOKIES_GUID, machine_guid, url, name, when);
|
||||
|
||||
buffer_flush(w->response.data);
|
||||
registry_set_cookie(w, REGISTRY_VERIFY_COOKIES_GUID);
|
||||
w->response.data->content_type = CT_APPLICATION_JSON;
|
||||
registry_json_header(host, w, "access", REGISTRY_STATUS_REDIRECT);
|
||||
buffer_json_member_add_string(w->response.data, "person_guid", REGISTRY_VERIFY_COOKIES_GUID);
|
||||
buffer_json_member_add_string(w->response.data, "registry", registry.registry_to_announce);
|
||||
registry_json_footer(w);
|
||||
return HTTP_RESP_OK;
|
||||
}
|
||||
|
||||
if(unlikely(person_guid[0] && !strcmp(person_guid, REGISTRY_VERIFY_COOKIES_GUID)))
|
||||
if(unlikely(person_guid[0] && is_dummy_person(person_guid)))
|
||||
// it passed the check - they gave us a different person_guid
|
||||
// empty the dummy one, so that we will generate a new person_guid
|
||||
person_guid[0] = '\0';
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -212,7 +238,8 @@ int registry_request_access_json(RRDHOST *host, struct web_client *w, char *pers
|
|||
buffer_json_member_add_array(w->response.data, "urls");
|
||||
|
||||
struct registry_json_walk_person_urls_callback c = { p, NULL, w, 0 };
|
||||
avl_traverse(&p->person_urls, registry_json_person_url_callback, &c);
|
||||
for(REGISTRY_PERSON_URL *pu = p->person_urls; pu ;pu = pu->next)
|
||||
registry_json_person_url_callback(pu, &c);
|
||||
buffer_json_array_close(w->response.data); // urls
|
||||
|
||||
registry_json_footer(w);
|
||||
|
@ -228,6 +255,12 @@ int registry_request_delete_json(RRDHOST *host, struct web_client *w, char *pers
|
|||
if(!registry.enabled)
|
||||
return registry_json_disabled(host, w, "delete");
|
||||
|
||||
if(!registry_is_valid_url(url)) {
|
||||
buffer_flush(w->response.data);
|
||||
buffer_strcat(w->response.data, "Invalid URL given in the request");
|
||||
return HTTP_RESP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
registry_lock();
|
||||
|
||||
REGISTRY_PERSON *p = registry_request_delete(person_guid, machine_guid, url, delete_url, when);
|
||||
|
@ -253,6 +286,12 @@ int registry_request_search_json(RRDHOST *host, struct web_client *w, char *pers
|
|||
if(!registry.enabled)
|
||||
return registry_json_disabled(host, w, "search");
|
||||
|
||||
if(!registry_is_valid_url(url)) {
|
||||
buffer_flush(w->response.data);
|
||||
buffer_strcat(w->response.data, "Invalid URL given in the request");
|
||||
return HTTP_RESP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
registry_lock();
|
||||
|
||||
REGISTRY_MACHINE *m = registry_request_machine(person_guid, machine_guid, url, request_machine, when);
|
||||
|
@ -267,7 +306,10 @@ int registry_request_search_json(RRDHOST *host, struct web_client *w, char *pers
|
|||
|
||||
buffer_json_member_add_array(w->response.data, "urls");
|
||||
struct registry_json_walk_person_urls_callback c = { NULL, m, w, 0 };
|
||||
dictionary_walkthrough_read(m->machine_urls, registry_json_machine_url_callback, &c);
|
||||
|
||||
for(REGISTRY_MACHINE_URL *mu = m->machine_urls; mu ; mu = mu->next)
|
||||
registry_json_machine_url_callback(mu, &c);
|
||||
|
||||
buffer_json_array_close(w->response.data);
|
||||
|
||||
registry_json_footer(w);
|
||||
|
@ -279,12 +321,15 @@ int registry_request_search_json(RRDHOST *host, struct web_client *w, char *pers
|
|||
// SWITCH REQUEST
|
||||
|
||||
// the main method for switching user identity
|
||||
int registry_request_switch_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *new_person_guid, time_t when) {
|
||||
int registry_request_switch_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url __maybe_unused, char *new_person_guid, time_t when __maybe_unused) {
|
||||
if(!registry.enabled)
|
||||
return registry_json_disabled(host, w, "switch");
|
||||
|
||||
(void)url;
|
||||
(void)when;
|
||||
if(!registry_is_valid_url(url)) {
|
||||
buffer_flush(w->response.data);
|
||||
buffer_strcat(w->response.data, "Invalid URL given in the request");
|
||||
return HTTP_RESP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
registry_lock();
|
||||
|
||||
|
@ -315,7 +360,9 @@ int registry_request_switch_json(RRDHOST *host, struct web_client *w, char *pers
|
|||
struct registry_person_url_callback_verify_machine_exists_data data = { m, 0 };
|
||||
|
||||
// verify the old person has access to this machine
|
||||
avl_traverse(&op->person_urls, registry_person_url_callback_verify_machine_exists, &data);
|
||||
for(REGISTRY_PERSON_URL *pu = op->person_urls; pu ;pu = pu->next)
|
||||
registry_person_url_callback_verify_machine_exists(pu, &data);
|
||||
|
||||
if(!data.count) {
|
||||
registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED);
|
||||
registry_json_footer(w);
|
||||
|
@ -325,7 +372,9 @@ int registry_request_switch_json(RRDHOST *host, struct web_client *w, char *pers
|
|||
|
||||
// verify the new person has access to this machine
|
||||
data.count = 0;
|
||||
avl_traverse(&np->person_urls, registry_person_url_callback_verify_machine_exists, &data);
|
||||
for(REGISTRY_PERSON_URL *pu = np->person_urls; pu ;pu = pu->next)
|
||||
registry_person_url_callback_verify_machine_exists(pu, &data);
|
||||
|
||||
if(!data.count) {
|
||||
registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED);
|
||||
registry_json_footer(w);
|
||||
|
@ -396,14 +445,12 @@ void registry_statistics(void) {
|
|||
|
||||
rrddim_add(stc, "persons", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
|
||||
rrddim_add(stc, "machines", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
|
||||
rrddim_add(stc, "urls", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
|
||||
rrddim_add(stc, "persons_urls", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
|
||||
rrddim_add(stc, "machines_urls", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
|
||||
}
|
||||
|
||||
rrddim_set(stc, "persons", (collected_number)registry.persons_count);
|
||||
rrddim_set(stc, "machines", (collected_number)registry.machines_count);
|
||||
rrddim_set(stc, "urls", (collected_number)registry.urls_count);
|
||||
rrddim_set(stc, "persons_urls", (collected_number)registry.persons_urls_count);
|
||||
rrddim_set(stc, "machines_urls", (collected_number)registry.machines_urls_count);
|
||||
rrdset_done(stc);
|
||||
|
@ -428,15 +475,21 @@ void registry_statistics(void) {
|
|||
|
||||
rrddim_add(stm, "persons", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
|
||||
rrddim_add(stm, "machines", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
|
||||
rrddim_add(stm, "urls", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
|
||||
rrddim_add(stm, "persons_urls", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
|
||||
rrddim_add(stm, "machines_urls", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
|
||||
}
|
||||
|
||||
rrddim_set(stm, "persons", (collected_number)registry.persons_memory + dictionary_stats_for_registry(registry.persons));
|
||||
rrddim_set(stm, "machines", (collected_number)registry.machines_memory + dictionary_stats_for_registry(registry.machines));
|
||||
rrddim_set(stm, "urls", (collected_number)registry.urls_memory);
|
||||
rrddim_set(stm, "persons_urls", (collected_number)registry.persons_urls_memory);
|
||||
rrddim_set(stm, "machines_urls", (collected_number)registry.machines_urls_memory);
|
||||
struct aral_statistics *p_aral_stats = aral_statistics(registry.persons_aral);
|
||||
rrddim_set(stm, "persons", (collected_number)p_aral_stats->structures.allocated_bytes + (collected_number)p_aral_stats->malloc.allocated_bytes);
|
||||
|
||||
struct aral_statistics *m_aral_stats = aral_statistics(registry.machines_aral);
|
||||
rrddim_set(stm, "machines", (collected_number)m_aral_stats->structures.allocated_bytes + (collected_number)m_aral_stats->malloc.allocated_bytes);
|
||||
|
||||
struct aral_statistics *pu_aral_stats = aral_statistics(registry.person_urls_aral);
|
||||
rrddim_set(stm, "persons_urls", (collected_number)pu_aral_stats->structures.allocated_bytes + (collected_number)pu_aral_stats->malloc.allocated_bytes);
|
||||
|
||||
struct aral_statistics *mu_aral_stats = aral_statistics(registry.machine_urls_aral);
|
||||
rrddim_set(stm, "machines_urls", (collected_number)mu_aral_stats->structures.allocated_bytes + (collected_number)mu_aral_stats->malloc.allocated_bytes);
|
||||
|
||||
rrdset_done(stm);
|
||||
}
|
||||
|
|
|
@ -11,18 +11,15 @@ int registry_db_should_be_saved(void) {
|
|||
// ----------------------------------------------------------------------------
|
||||
// INTERNAL FUNCTIONS FOR SAVING REGISTRY OBJECTS
|
||||
|
||||
static int registry_machine_save_url(const DICTIONARY_ITEM *item __maybe_unused, void *entry, void *file) {
|
||||
REGISTRY_MACHINE_URL *mu = entry;
|
||||
FILE *fp = file;
|
||||
|
||||
debug(D_REGISTRY, "Registry: registry_machine_save_url('%s')", mu->url->url);
|
||||
static int registry_machine_save_url(REGISTRY_MACHINE_URL *mu, FILE *fp) {
|
||||
debug(D_REGISTRY, "REGISTRY: registry_machine_save_url('%s')", string2str(mu->url));
|
||||
|
||||
int ret = fprintf(fp, "V\t%08x\t%08x\t%08x\t%02x\t%s\n",
|
||||
mu->first_t,
|
||||
mu->last_t,
|
||||
mu->usages,
|
||||
mu->flags,
|
||||
mu->url->url
|
||||
string2str(mu->url)
|
||||
);
|
||||
|
||||
// error handling is done at registry_db_save()
|
||||
|
@ -35,7 +32,7 @@ static int registry_machine_save(const DICTIONARY_ITEM *item __maybe_unused, voi
|
|||
REGISTRY_MACHINE *m = entry;
|
||||
FILE *fp = file;
|
||||
|
||||
debug(D_REGISTRY, "Registry: registry_machine_save('%s')", m->guid);
|
||||
debug(D_REGISTRY, "REGISTRY: registry_machine_save('%s')", m->guid);
|
||||
|
||||
int ret = fprintf(fp, "M\t%08x\t%08x\t%08x\t%s\n",
|
||||
m->first_t,
|
||||
|
@ -45,9 +42,13 @@ static int registry_machine_save(const DICTIONARY_ITEM *item __maybe_unused, voi
|
|||
);
|
||||
|
||||
if(ret >= 0) {
|
||||
int ret2 = dictionary_walkthrough_read(m->machine_urls, registry_machine_save_url, fp);
|
||||
if(ret2 < 0) return ret2;
|
||||
ret += ret2;
|
||||
for(REGISTRY_MACHINE_URL *mu = m->machine_urls; mu ; mu = mu->next) {
|
||||
int rc = registry_machine_save_url(mu, fp);
|
||||
if(rc < 0)
|
||||
return rc;
|
||||
|
||||
ret += rc;
|
||||
}
|
||||
}
|
||||
|
||||
// error handling is done at registry_db_save()
|
||||
|
@ -55,11 +56,8 @@ static int registry_machine_save(const DICTIONARY_ITEM *item __maybe_unused, voi
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline int registry_person_save_url(void *entry, void *file) {
|
||||
REGISTRY_PERSON_URL *pu = entry;
|
||||
FILE *fp = file;
|
||||
|
||||
debug(D_REGISTRY, "Registry: registry_person_save_url('%s')", pu->url->url);
|
||||
static inline int registry_person_save_url(REGISTRY_PERSON_URL *pu, FILE *fp) {
|
||||
debug(D_REGISTRY, "REGISTRY: registry_person_save_url('%s')", string2str(pu->url));
|
||||
|
||||
int ret = fprintf(fp, "U\t%08x\t%08x\t%08x\t%02x\t%s\t%s\t%s\n",
|
||||
pu->first_t,
|
||||
|
@ -67,8 +65,8 @@ static inline int registry_person_save_url(void *entry, void *file) {
|
|||
pu->usages,
|
||||
pu->flags,
|
||||
pu->machine->guid,
|
||||
pu->machine_name,
|
||||
pu->url->url
|
||||
string2str(pu->machine_name),
|
||||
string2str(pu->url)
|
||||
);
|
||||
|
||||
// error handling is done at registry_db_save()
|
||||
|
@ -80,7 +78,7 @@ static inline int registry_person_save(const DICTIONARY_ITEM *item __maybe_unuse
|
|||
REGISTRY_PERSON *p = entry;
|
||||
FILE *fp = file;
|
||||
|
||||
debug(D_REGISTRY, "Registry: registry_person_save('%s')", p->guid);
|
||||
debug(D_REGISTRY, "REGISTRY: registry_person_save('%s')", p->guid);
|
||||
|
||||
int ret = fprintf(fp, "P\t%08x\t%08x\t%08x\t%s\n",
|
||||
p->first_t,
|
||||
|
@ -90,10 +88,13 @@ static inline int registry_person_save(const DICTIONARY_ITEM *item __maybe_unuse
|
|||
);
|
||||
|
||||
if(ret >= 0) {
|
||||
//int ret2 = dictionary_walkthrough_read(p->person_urls, registry_person_save_url, fp);
|
||||
int ret2 = avl_traverse(&p->person_urls, registry_person_save_url, fp);
|
||||
if (ret2 < 0) return ret2;
|
||||
ret += ret2;
|
||||
for(REGISTRY_PERSON_URL *pu = p->person_urls; pu ;pu = pu->next) {
|
||||
int rc = registry_person_save_url(pu, fp);
|
||||
if(rc < 0)
|
||||
return rc;
|
||||
else
|
||||
ret += rc;
|
||||
}
|
||||
}
|
||||
|
||||
// error handling is done at registry_db_save()
|
||||
|
@ -119,42 +120,42 @@ int registry_db_save(void) {
|
|||
snprintfz(old_filename, FILENAME_MAX, "%s.old", registry.db_filename);
|
||||
snprintfz(tmp_filename, FILENAME_MAX, "%s.tmp", registry.db_filename);
|
||||
|
||||
debug(D_REGISTRY, "Registry: Creating file '%s'", tmp_filename);
|
||||
debug(D_REGISTRY, "REGISTRY: Creating file '%s'", tmp_filename);
|
||||
FILE *fp = fopen(tmp_filename, "w");
|
||||
if(!fp) {
|
||||
netdata_log_error("Registry: Cannot create file: %s", tmp_filename);
|
||||
netdata_log_error("REGISTRY: Cannot create file: %s", tmp_filename);
|
||||
error_log_limit_reset();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// dictionary_walkthrough_read() has its own locking, so this is safe to do
|
||||
|
||||
debug(D_REGISTRY, "Saving all machines");
|
||||
debug(D_REGISTRY, "REGISTRY: saving all machines");
|
||||
int bytes1 = dictionary_walkthrough_read(registry.machines, registry_machine_save, fp);
|
||||
if(bytes1 < 0) {
|
||||
netdata_log_error("Registry: Cannot save registry machines - return value %d", bytes1);
|
||||
netdata_log_error("REGISTRY: Cannot save registry machines - return value %d", bytes1);
|
||||
fclose(fp);
|
||||
error_log_limit_reset();
|
||||
return bytes1;
|
||||
}
|
||||
debug(D_REGISTRY, "Registry: saving machines took %d bytes", bytes1);
|
||||
debug(D_REGISTRY, "REGISTRY: saving machines took %d bytes", bytes1);
|
||||
|
||||
debug(D_REGISTRY, "Saving all persons");
|
||||
int bytes2 = dictionary_walkthrough_read(registry.persons, registry_person_save, fp);
|
||||
if(bytes2 < 0) {
|
||||
netdata_log_error("Registry: Cannot save registry persons - return value %d", bytes2);
|
||||
netdata_log_error("REGISTRY: Cannot save registry persons - return value %d", bytes2);
|
||||
fclose(fp);
|
||||
error_log_limit_reset();
|
||||
return bytes2;
|
||||
}
|
||||
debug(D_REGISTRY, "Registry: saving persons took %d bytes", bytes2);
|
||||
debug(D_REGISTRY, "REGISTRY: saving persons took %d bytes", bytes2);
|
||||
|
||||
// save the totals
|
||||
fprintf(fp, "T\t%016llx\t%016llx\t%016llx\t%016llx\t%016llx\t%016llx\n",
|
||||
registry.persons_count,
|
||||
registry.machines_count,
|
||||
registry.usages_count + 1, // this is required - it is lost on db rotation
|
||||
registry.urls_count,
|
||||
0LLU, //registry.urls_count,
|
||||
registry.persons_urls_count,
|
||||
registry.machines_urls_count
|
||||
);
|
||||
|
@ -164,36 +165,36 @@ int registry_db_save(void) {
|
|||
errno = 0;
|
||||
|
||||
// remove the .old db
|
||||
debug(D_REGISTRY, "Registry: Removing old db '%s'", old_filename);
|
||||
debug(D_REGISTRY, "REGISTRY: Removing old db '%s'", old_filename);
|
||||
if(unlink(old_filename) == -1 && errno != ENOENT)
|
||||
netdata_log_error("Registry: cannot remove old registry file '%s'", old_filename);
|
||||
netdata_log_error("REGISTRY: cannot remove old registry file '%s'", old_filename);
|
||||
|
||||
// rename the db to .old
|
||||
debug(D_REGISTRY, "Registry: Link current db '%s' to .old: '%s'", registry.db_filename, old_filename);
|
||||
debug(D_REGISTRY, "REGISTRY: Link current db '%s' to .old: '%s'", registry.db_filename, old_filename);
|
||||
if(link(registry.db_filename, old_filename) == -1 && errno != ENOENT)
|
||||
netdata_log_error("Registry: cannot move file '%s' to '%s'. Saving registry DB failed!", registry.db_filename, old_filename);
|
||||
netdata_log_error("REGISTRY: cannot move file '%s' to '%s'. Saving registry DB failed!", registry.db_filename, old_filename);
|
||||
|
||||
else {
|
||||
// remove the database (it is saved in .old)
|
||||
debug(D_REGISTRY, "Registry: removing db '%s'", registry.db_filename);
|
||||
debug(D_REGISTRY, "REGISTRY: removing db '%s'", registry.db_filename);
|
||||
if (unlink(registry.db_filename) == -1 && errno != ENOENT)
|
||||
netdata_log_error("Registry: cannot remove old registry file '%s'", registry.db_filename);
|
||||
netdata_log_error("REGISTRY: cannot remove old registry file '%s'", registry.db_filename);
|
||||
|
||||
// move the .tmp to make it active
|
||||
debug(D_REGISTRY, "Registry: linking tmp db '%s' to active db '%s'", tmp_filename, registry.db_filename);
|
||||
debug(D_REGISTRY, "REGISTRY: linking tmp db '%s' to active db '%s'", tmp_filename, registry.db_filename);
|
||||
if (link(tmp_filename, registry.db_filename) == -1) {
|
||||
netdata_log_error("Registry: cannot move file '%s' to '%s'. Saving registry DB failed!", tmp_filename,
|
||||
netdata_log_error("REGISTRY: cannot move file '%s' to '%s'. Saving registry DB failed!", tmp_filename,
|
||||
registry.db_filename);
|
||||
|
||||
// move the .old back
|
||||
debug(D_REGISTRY, "Registry: linking old db '%s' to active db '%s'", old_filename, registry.db_filename);
|
||||
debug(D_REGISTRY, "REGISTRY: linking old db '%s' to active db '%s'", old_filename, registry.db_filename);
|
||||
if(link(old_filename, registry.db_filename) == -1)
|
||||
netdata_log_error("Registry: cannot move file '%s' to '%s'. Recovering the old registry DB failed!", old_filename, registry.db_filename);
|
||||
netdata_log_error("REGISTRY: cannot move file '%s' to '%s'. Recovering the old registry DB failed!", old_filename, registry.db_filename);
|
||||
}
|
||||
else {
|
||||
debug(D_REGISTRY, "Registry: removing tmp db '%s'", tmp_filename);
|
||||
debug(D_REGISTRY, "REGISTRY: removing tmp db '%s'", tmp_filename);
|
||||
if(unlink(tmp_filename) == -1)
|
||||
netdata_log_error("Registry: cannot remove tmp registry file '%s'", tmp_filename);
|
||||
netdata_log_error("REGISTRY: cannot remove tmp registry file '%s'", tmp_filename);
|
||||
|
||||
// it has been moved successfully
|
||||
// discard the current registry log
|
||||
|
@ -215,75 +216,33 @@ size_t registry_db_load(void) {
|
|||
char *s, buf[4096 + 1];
|
||||
REGISTRY_PERSON *p = NULL;
|
||||
REGISTRY_MACHINE *m = NULL;
|
||||
REGISTRY_URL *u = NULL;
|
||||
STRING *u = NULL;
|
||||
size_t line = 0;
|
||||
|
||||
debug(D_REGISTRY, "Registry: loading active db from: '%s'", registry.db_filename);
|
||||
debug(D_REGISTRY, "REGISTRY: loading active db from: '%s'", registry.db_filename);
|
||||
FILE *fp = fopen(registry.db_filename, "r");
|
||||
if(!fp) {
|
||||
netdata_log_error("Registry: cannot open registry file: '%s'", registry.db_filename);
|
||||
netdata_log_error("REGISTRY: cannot open registry file: '%s'", registry.db_filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
REGISTRY_MACHINE_URL *mu;
|
||||
size_t len = 0;
|
||||
buf[4096] = '\0';
|
||||
while((s = fgets_trim_len(buf, 4096, fp, &len))) {
|
||||
line++;
|
||||
|
||||
debug(D_REGISTRY, "Registry: read line %zu to length %zu: %s", line, len, s);
|
||||
debug(D_REGISTRY, "REGISTRY: read line %zu to length %zu: %s", line, len, s);
|
||||
switch(*s) {
|
||||
case 'T': // totals
|
||||
if(unlikely(len != 103 || s[1] != '\t' || s[18] != '\t' || s[35] != '\t' || s[52] != '\t' || s[69] != '\t' || s[86] != '\t' || s[103] != '\0')) {
|
||||
netdata_log_error("Registry totals line %zu is wrong (len = %zu).", line, len);
|
||||
continue;
|
||||
}
|
||||
registry.persons_count = strtoull(&s[2], NULL, 16);
|
||||
registry.machines_count = strtoull(&s[19], NULL, 16);
|
||||
registry.usages_count = strtoull(&s[36], NULL, 16);
|
||||
registry.urls_count = strtoull(&s[53], NULL, 16);
|
||||
registry.persons_urls_count = strtoull(&s[70], NULL, 16);
|
||||
registry.machines_urls_count = strtoull(&s[87], NULL, 16);
|
||||
break;
|
||||
|
||||
case 'P': // person
|
||||
m = NULL;
|
||||
// verify it is valid
|
||||
if(unlikely(len != 65 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[65] != '\0')) {
|
||||
netdata_log_error("Registry person line %zu is wrong (len = %zu).", line, len);
|
||||
continue;
|
||||
}
|
||||
|
||||
s[1] = s[10] = s[19] = s[28] = '\0';
|
||||
p = registry_person_allocate(&s[29], strtoul(&s[2], NULL, 16));
|
||||
p->last_t = (uint32_t)strtoul(&s[11], NULL, 16);
|
||||
p->usages = (uint32_t)strtoul(&s[20], NULL, 16);
|
||||
debug(D_REGISTRY, "Registry loaded person '%s', first: %u, last: %u, usages: %u", p->guid, p->first_t, p->last_t, p->usages);
|
||||
break;
|
||||
|
||||
case 'M': // machine
|
||||
p = NULL;
|
||||
// verify it is valid
|
||||
if(unlikely(len != 65 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[65] != '\0')) {
|
||||
netdata_log_error("Registry person line %zu is wrong (len = %zu).", line, len);
|
||||
continue;
|
||||
}
|
||||
|
||||
s[1] = s[10] = s[19] = s[28] = '\0';
|
||||
m = registry_machine_allocate(&s[29], strtoul(&s[2], NULL, 16));
|
||||
m->last_t = (uint32_t)strtoul(&s[11], NULL, 16);
|
||||
m->usages = (uint32_t)strtoul(&s[20], NULL, 16);
|
||||
debug(D_REGISTRY, "Registry loaded machine '%s', first: %u, last: %u, usages: %u", m->guid, m->first_t, m->last_t, m->usages);
|
||||
break;
|
||||
|
||||
case 'U': // person URL
|
||||
if(unlikely(!p)) {
|
||||
netdata_log_error("Registry: ignoring line %zu, no person loaded: %s", line, s);
|
||||
netdata_log_error("REGISTRY: ignoring line %zu, no person loaded: %s", line, s);
|
||||
continue;
|
||||
}
|
||||
|
||||
// verify it is valid
|
||||
if(len < 69 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[31] != '\t' || s[68] != '\t') {
|
||||
netdata_log_error("Registry person URL line %zu is wrong (len = %zu).", line, len);
|
||||
netdata_log_error("REGISTRY: person URL line %zu is wrong (len = %zu).", line, len);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -293,51 +252,125 @@ size_t registry_db_load(void) {
|
|||
char *url = &s[69];
|
||||
while(*url && *url != '\t') url++;
|
||||
if(!*url) {
|
||||
netdata_log_error("Registry person URL line %zu does not have a url.", line);
|
||||
netdata_log_error("REGISTRY: person URL line %zu does not have a url.", line);
|
||||
continue;
|
||||
}
|
||||
*url++ = '\0';
|
||||
|
||||
// u = registry_url_allocate_nolock(url, strlen(url));
|
||||
u = registry_url_get(url, strlen(url));
|
||||
if(*url != 'h' && *url != '*') {
|
||||
netdata_log_error("REGISTRY: person URL line %zu does not have a valid url: %s", line, url);
|
||||
continue;
|
||||
}
|
||||
|
||||
time_t first_t = strtoul(&s[2], NULL, 16);
|
||||
u = string_strdupz(url);
|
||||
|
||||
time_t first_t = (time_t)strtoul(&s[2], NULL, 16);
|
||||
|
||||
m = registry_machine_find(&s[32]);
|
||||
if(!m) m = registry_machine_allocate(&s[32], first_t);
|
||||
|
||||
REGISTRY_PERSON_URL *pu = registry_person_url_allocate(p, m, u, &s[69], strlen(&s[69]), first_t);
|
||||
mu = registry_machine_url_find(m, u);
|
||||
if(!mu) {
|
||||
netdata_log_error("REGISTRY: person URL line %zu was not linked to the machine it refers to", line);
|
||||
mu = registry_machine_url_allocate(m, u, first_t);
|
||||
}
|
||||
|
||||
REGISTRY_PERSON_URL *pu = registry_person_url_index_find(p, u);
|
||||
if(!pu)
|
||||
pu = registry_person_url_allocate(p, m, u, &s[69], strlen(&s[69]), first_t);
|
||||
else
|
||||
netdata_log_error("REGISTRY: person URL line %zu is duplicate, reusing the old one.", line);
|
||||
|
||||
pu->last_t = (uint32_t)strtoul(&s[11], NULL, 16);
|
||||
pu->usages = (uint32_t)strtoul(&s[20], NULL, 16);
|
||||
pu->flags = (uint8_t)strtoul(&s[29], NULL, 16);
|
||||
debug(D_REGISTRY, "Registry loaded person URL '%s' with name '%s' of machine '%s', first: %u, last: %u, usages: %u, flags: %02x", u->url, pu->machine_name, m->guid, pu->first_t, pu->last_t, pu->usages, pu->flags);
|
||||
debug(D_REGISTRY, "REGISTRY: loaded person URL '%s' with name '%s' of machine '%s', first: %u, last: %u, usages: %u, flags: %02x",
|
||||
string2str(u), string2str(pu->machine_name), m->guid, pu->first_t, pu->last_t, pu->usages, pu->flags);
|
||||
|
||||
string_freez(u);
|
||||
break;
|
||||
|
||||
case 'P': // person
|
||||
m = NULL;
|
||||
// verify it is valid
|
||||
if(unlikely(len != 65 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[65] != '\0')) {
|
||||
netdata_log_error("REGISTRY: person line %zu is wrong (len = %zu).", line, len);
|
||||
continue;
|
||||
}
|
||||
|
||||
s[1] = s[10] = s[19] = s[28] = '\0';
|
||||
p = registry_person_allocate(&s[29], (time_t)strtoul(&s[2], NULL, 16));
|
||||
p->last_t = (uint32_t)strtoul(&s[11], NULL, 16);
|
||||
p->usages = (uint32_t)strtoul(&s[20], NULL, 16);
|
||||
debug(D_REGISTRY, "REGISTRY: loaded person '%s', first: %u, last: %u, usages: %u", p->guid, p->first_t, p->last_t, p->usages);
|
||||
break;
|
||||
|
||||
case 'V': // machine URL
|
||||
if(unlikely(!m)) {
|
||||
netdata_log_error("Registry: ignoring line %zu, no machine loaded: %s", line, s);
|
||||
netdata_log_error("REGISTRY: ignoring line %zu, no machine loaded: %s", line, s);
|
||||
continue;
|
||||
}
|
||||
|
||||
// verify it is valid
|
||||
if(len < 32 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[31] != '\t') {
|
||||
netdata_log_error("Registry person URL line %zu is wrong (len = %zu).", line, len);
|
||||
netdata_log_error("REGISTRY: person URL line %zu is wrong (len = %zu).", line, len);
|
||||
continue;
|
||||
}
|
||||
|
||||
s[1] = s[10] = s[19] = s[28] = s[31] = '\0';
|
||||
// u = registry_url_allocate_nolock(&s[32], strlen(&s[32]));
|
||||
u = registry_url_get(&s[32], strlen(&s[32]));
|
||||
|
||||
REGISTRY_MACHINE_URL *mu = registry_machine_url_allocate(m, u, strtoul(&s[2], NULL, 16));
|
||||
url = &s[32];
|
||||
if(*url != 'h' && *url != '*') {
|
||||
netdata_log_error("REGISTRY: machine URL line %zu does not have a valid url: %s", line, url);
|
||||
continue;
|
||||
}
|
||||
|
||||
u = string_strdupz(url);
|
||||
|
||||
mu = registry_machine_url_find(m, u);
|
||||
if(!mu)
|
||||
mu = registry_machine_url_allocate(m, u, (time_t)strtoul(&s[2], NULL, 16));
|
||||
else
|
||||
netdata_log_error("REGISTRY: machine URL line %zu is duplicate, reusing the old one.", line);
|
||||
|
||||
mu->last_t = (uint32_t)strtoul(&s[11], NULL, 16);
|
||||
mu->usages = (uint32_t)strtoul(&s[20], NULL, 16);
|
||||
mu->flags = (uint8_t)strtoul(&s[29], NULL, 16);
|
||||
debug(D_REGISTRY, "Registry loaded machine URL '%s', machine '%s', first: %u, last: %u, usages: %u, flags: %02x", u->url, m->guid, mu->first_t, mu->last_t, mu->usages, mu->flags);
|
||||
debug(D_REGISTRY, "Registry loaded machine URL '%s', machine '%s', first: %u, last: %u, usages: %u, flags: %02x",
|
||||
string2str(u), m->guid, mu->first_t, mu->last_t, mu->usages, mu->flags);
|
||||
|
||||
string_freez(u);
|
||||
break;
|
||||
|
||||
case 'M': // machine
|
||||
p = NULL;
|
||||
// verify it is valid
|
||||
if(unlikely(len != 65 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[65] != '\0')) {
|
||||
netdata_log_error("REGISTRY: person line %zu is wrong (len = %zu).", line, len);
|
||||
continue;
|
||||
}
|
||||
|
||||
s[1] = s[10] = s[19] = s[28] = '\0';
|
||||
m = registry_machine_allocate(&s[29], (time_t)strtoul(&s[2], NULL, 16));
|
||||
m->last_t = (uint32_t)strtoul(&s[11], NULL, 16);
|
||||
m->usages = (uint32_t)strtoul(&s[20], NULL, 16);
|
||||
debug(D_REGISTRY, "REGISTRY: loaded machine '%s', first: %u, last: %u, usages: %u", m->guid, m->first_t, m->last_t, m->usages);
|
||||
break;
|
||||
|
||||
case 'T': // totals
|
||||
if(unlikely(len != 103 || s[1] != '\t' || s[18] != '\t' || s[35] != '\t' || s[52] != '\t' || s[69] != '\t' || s[86] != '\t' || s[103] != '\0')) {
|
||||
netdata_log_error("REGISTRY: totals line %zu is wrong (len = %zu).", line, len);
|
||||
continue;
|
||||
}
|
||||
registry.persons_count = strtoull(&s[2], NULL, 16);
|
||||
registry.machines_count = strtoull(&s[19], NULL, 16);
|
||||
registry.usages_count = strtoull(&s[36], NULL, 16);
|
||||
registry.persons_urls_count = strtoull(&s[70], NULL, 16);
|
||||
registry.machines_urls_count = strtoull(&s[87], NULL, 16);
|
||||
break;
|
||||
|
||||
default:
|
||||
netdata_log_error("Registry: ignoring line %zu of filename '%s': %s.", line, registry.db_filename, s);
|
||||
netdata_log_error("REGISTRY: ignoring line %zu of filename '%s': %s.", line, registry.db_filename, s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,63 @@
|
|||
#include "daemon/common.h"
|
||||
#include "registry_internals.h"
|
||||
|
||||
void registry_db_stats(void) {
|
||||
size_t persons = 0;
|
||||
size_t persons_urls = 0;
|
||||
size_t max_urls_per_person = 0;
|
||||
|
||||
REGISTRY_PERSON *p;
|
||||
dfe_start_read(registry.persons, p) {
|
||||
persons++;
|
||||
size_t urls = 0;
|
||||
for(REGISTRY_PERSON_URL *pu = p->person_urls ; pu ;pu = pu->next)
|
||||
urls++;
|
||||
|
||||
if(urls > max_urls_per_person)
|
||||
max_urls_per_person = urls;
|
||||
|
||||
persons_urls += urls;
|
||||
}
|
||||
dfe_done(p);
|
||||
|
||||
size_t machines = 0;
|
||||
size_t machines_urls = 0;
|
||||
size_t max_urls_per_machine = 0;
|
||||
|
||||
REGISTRY_MACHINE *m;
|
||||
dfe_start_read(registry.machines, m) {
|
||||
machines++;
|
||||
size_t urls = 0;
|
||||
for(REGISTRY_MACHINE_URL *mu = m->machine_urls ; mu ;mu = mu->next)
|
||||
urls++;
|
||||
|
||||
if(urls > max_urls_per_machine)
|
||||
max_urls_per_machine = urls;
|
||||
|
||||
machines_urls += urls;
|
||||
}
|
||||
dfe_done(m);
|
||||
|
||||
netdata_log_info("REGISTRY: persons %zu, person_urls %zu, max_urls_per_person %zu, "
|
||||
"machines %zu, machine_urls %zu, max_urls_per_machine %zu",
|
||||
persons, persons_urls, max_urls_per_person,
|
||||
machines, machines_urls, max_urls_per_machine);
|
||||
}
|
||||
|
||||
void registry_generate_curl_urls(void) {
|
||||
FILE *fp = fopen("/tmp/registry.curl", "w+");
|
||||
|
||||
REGISTRY_PERSON *p;
|
||||
dfe_start_read(registry.persons, p) {
|
||||
for(REGISTRY_PERSON_URL *pu = p->person_urls ; pu ;pu = pu->next) {
|
||||
fprintf(fp, "do_curl '%s' '%s' '%s'\n", p->guid, pu->machine->guid, string2str(pu->url));
|
||||
}
|
||||
}
|
||||
dfe_done(p);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
int registry_init(void) {
|
||||
char filename[FILENAME_MAX + 1];
|
||||
|
||||
|
@ -16,7 +73,7 @@ int registry_init(void) {
|
|||
registry.enabled = 0;
|
||||
}
|
||||
|
||||
// pathnames
|
||||
// path names
|
||||
snprintfz(filename, FILENAME_MAX, "%s/registry", netdata_configured_varlib_dir);
|
||||
registry.pathname = config_get(CONFIG_SECTION_DIRECTORIES, "registry", filename);
|
||||
if(mkdir(registry.pathname, 0770) == -1 && errno != EEXIST)
|
||||
|
@ -57,73 +114,104 @@ int registry_init(void) {
|
|||
config_set_number(CONFIG_SECTION_REGISTRY, "max URL name length", (long long)registry.max_name_length);
|
||||
}
|
||||
|
||||
bool use_mmap = config_get_boolean(CONFIG_SECTION_REGISTRY, "use mmap", false);
|
||||
|
||||
// initialize entries counters
|
||||
registry.persons_count = 0;
|
||||
registry.machines_count = 0;
|
||||
registry.usages_count = 0;
|
||||
registry.urls_count = 0;
|
||||
registry.persons_urls_count = 0;
|
||||
registry.machines_urls_count = 0;
|
||||
|
||||
// initialize memory counters
|
||||
registry.persons_memory = 0;
|
||||
registry.machines_memory = 0;
|
||||
registry.urls_memory = 0;
|
||||
registry.persons_urls_memory = 0;
|
||||
registry.machines_urls_memory = 0;
|
||||
|
||||
// initialize locks
|
||||
netdata_mutex_init(®istry.lock);
|
||||
|
||||
// create dictionaries
|
||||
registry.persons = dictionary_create(REGISTRY_DICTIONARY_OPTIONS);
|
||||
registry.machines = dictionary_create(REGISTRY_DICTIONARY_OPTIONS);
|
||||
avl_init(®istry.registry_urls_root_index, registry_url_compare);
|
||||
|
||||
// load the registry database
|
||||
if(registry.enabled) {
|
||||
// create dictionaries
|
||||
registry.persons = dictionary_create(REGISTRY_DICTIONARY_OPTIONS);
|
||||
registry.machines = dictionary_create(REGISTRY_DICTIONARY_OPTIONS);
|
||||
|
||||
// initialize the allocators
|
||||
|
||||
size_t min_page_size = 4 * 1024;
|
||||
size_t max_page_size = 1024 * 1024;
|
||||
|
||||
if(use_mmap) {
|
||||
min_page_size = 100 * 1024 * 1024;
|
||||
max_page_size = 512 * 1024 * 1024;
|
||||
}
|
||||
|
||||
registry.persons_aral = aral_create("registry_persons", sizeof(REGISTRY_PERSON),
|
||||
min_page_size / sizeof(REGISTRY_PERSON), max_page_size,
|
||||
®istry.aral_stats,
|
||||
"registry_persons",
|
||||
&netdata_configured_cache_dir,
|
||||
use_mmap, true);
|
||||
|
||||
registry.machines_aral = aral_create("registry_machines", sizeof(REGISTRY_MACHINE),
|
||||
min_page_size / sizeof(REGISTRY_MACHINE), max_page_size,
|
||||
®istry.aral_stats,
|
||||
"registry_machines",
|
||||
&netdata_configured_cache_dir,
|
||||
use_mmap, true);
|
||||
|
||||
registry.person_urls_aral = aral_create("registry_person_urls", sizeof(REGISTRY_PERSON_URL),
|
||||
min_page_size / sizeof(REGISTRY_PERSON_URL), max_page_size,
|
||||
®istry.aral_stats,
|
||||
"registry_person_urls",
|
||||
&netdata_configured_cache_dir,
|
||||
use_mmap, true);
|
||||
|
||||
registry.machine_urls_aral = aral_create("registry_machine_urls", sizeof(REGISTRY_MACHINE_URL),
|
||||
min_page_size / sizeof(REGISTRY_MACHINE_URL), max_page_size,
|
||||
®istry.aral_stats,
|
||||
"registry_machine_urls",
|
||||
&netdata_configured_cache_dir,
|
||||
use_mmap, true);
|
||||
|
||||
// disable cancelability to avoid enable/disable per item in the dictionary locks
|
||||
netdata_thread_disable_cancelability();
|
||||
|
||||
registry_log_open();
|
||||
registry_db_load();
|
||||
registry_log_load();
|
||||
|
||||
if(unlikely(registry_db_should_be_saved()))
|
||||
registry_db_save();
|
||||
|
||||
// registry_db_stats();
|
||||
// registry_generate_curl_urls();
|
||||
// exit(0);
|
||||
|
||||
netdata_thread_enable_cancelability();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int machine_urls_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, void *entry, void *data) {
|
||||
REGISTRY_MACHINE *m = (REGISTRY_MACHINE *)data;
|
||||
(void)m;
|
||||
|
||||
REGISTRY_MACHINE_URL *mu = (REGISTRY_MACHINE_URL *)entry;
|
||||
|
||||
debug(D_REGISTRY, "Registry: unlinking url '%s' from machine", mu->url->url);
|
||||
registry_url_unlink(mu->url);
|
||||
|
||||
debug(D_REGISTRY, "Registry: freeing machine url");
|
||||
freez(mu);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int machine_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, void *entry, void *data __maybe_unused) {
|
||||
REGISTRY_MACHINE *m = (REGISTRY_MACHINE *)entry;
|
||||
int ret = dictionary_walkthrough_read(m->machine_urls, machine_urls_delete_callback, m);
|
||||
|
||||
dictionary_destroy(m->machine_urls);
|
||||
int count = 0;
|
||||
|
||||
while(m->machine_urls) {
|
||||
registry_machine_url_unlink_from_machine_and_free(m, m->machine_urls);
|
||||
count++;
|
||||
}
|
||||
|
||||
freez(m);
|
||||
|
||||
return ret + 1;
|
||||
return count + 1;
|
||||
}
|
||||
|
||||
static int registry_person_del_callback(const DICTIONARY_ITEM *item __maybe_unused, void *entry, void *d __maybe_unused) {
|
||||
REGISTRY_PERSON *p = (REGISTRY_PERSON *)entry;
|
||||
|
||||
debug(D_REGISTRY, "Registry: registry_person_del('%s'): deleting person", p->guid);
|
||||
|
||||
while(p->person_urls.root)
|
||||
registry_person_unlink_from_url(p, (REGISTRY_PERSON_URL *)p->person_urls.root);
|
||||
while(p->person_urls)
|
||||
registry_person_unlink_from_url(p, (REGISTRY_PERSON_URL *)p->person_urls);
|
||||
|
||||
//debug(D_REGISTRY, "Registry: deleting person '%s' from persons registry", p->guid);
|
||||
//dictionary_del(registry.persons, p->guid);
|
||||
|
@ -140,8 +228,19 @@ void registry_free(void) {
|
|||
debug(D_REGISTRY, "Registry: destroying persons dictionary");
|
||||
dictionary_walkthrough_read(registry.persons, registry_person_del_callback, NULL);
|
||||
dictionary_destroy(registry.persons);
|
||||
registry.persons = NULL;
|
||||
|
||||
debug(D_REGISTRY, "Registry: destroying machines dictionary");
|
||||
dictionary_walkthrough_read(registry.machines, machine_delete_callback, NULL);
|
||||
dictionary_destroy(registry.machines);
|
||||
registry.machines = NULL;
|
||||
|
||||
aral_destroy(registry.persons_aral);
|
||||
aral_destroy(registry.machines_aral);
|
||||
aral_destroy(registry.person_urls_aral);
|
||||
aral_destroy(registry.machine_urls_aral);
|
||||
registry.persons_aral = NULL;
|
||||
registry.machines_aral = NULL;
|
||||
registry.person_urls_aral = NULL;
|
||||
registry.machine_urls_aral = NULL;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ static inline char *registry_fix_url(char *url, size_t *len) {
|
|||
// HELPERS
|
||||
|
||||
// verify the person, the machine and the URL exist in our DB
|
||||
REGISTRY_PERSON_URL *registry_verify_request(char *person_guid, char *machine_guid, char *url, REGISTRY_PERSON **pp, REGISTRY_MACHINE **mm) {
|
||||
REGISTRY_PERSON_URL *registry_verify_request(const char *person_guid, char *machine_guid, char *url, REGISTRY_PERSON **pp, REGISTRY_MACHINE **mm) {
|
||||
char pbuf[GUID_LEN + 1], mbuf[GUID_LEN + 1];
|
||||
|
||||
if(!person_guid || !*person_guid || !machine_guid || !*machine_guid || !url || !*url) {
|
||||
|
@ -121,7 +121,10 @@ REGISTRY_PERSON_URL *registry_verify_request(char *person_guid, char *machine_gu
|
|||
}
|
||||
if(pp) *pp = p;
|
||||
|
||||
REGISTRY_PERSON_URL *pu = registry_person_url_index_find(p, url);
|
||||
STRING *u = string_strdupz(url);
|
||||
REGISTRY_PERSON_URL *pu = registry_person_url_index_find(p, u);
|
||||
string_freez(u);
|
||||
|
||||
if(!pu) {
|
||||
netdata_log_info("Registry Request Verification: URL not found for person, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
|
||||
return NULL;
|
||||
|
@ -138,23 +141,28 @@ REGISTRY_PERSON_URL *registry_verify_request(char *person_guid, char *machine_gu
|
|||
// ----------------------------------------------------------------------------
|
||||
// REGISTRY REQUESTS
|
||||
|
||||
REGISTRY_PERSON *registry_request_access(char *person_guid, char *machine_guid, char *url, char *name, time_t when) {
|
||||
REGISTRY_PERSON *registry_request_access(const char *person_guid, char *machine_guid, char *url, char *name, time_t when) {
|
||||
debug(D_REGISTRY, "registry_request_access('%s', '%s', '%s'): NEW REQUEST", (person_guid)?person_guid:"", machine_guid, url);
|
||||
|
||||
REGISTRY_MACHINE *m = registry_machine_get(machine_guid, when);
|
||||
bool is_dummy = is_dummy_person(person_guid);
|
||||
|
||||
REGISTRY_MACHINE *m = registry_machine_find_or_create(machine_guid, when, is_dummy);
|
||||
if(!m) return NULL;
|
||||
|
||||
REGISTRY_PERSON *p = registry_person_find_or_create(person_guid, when, is_dummy);
|
||||
|
||||
// make sure the name is valid
|
||||
size_t namelen;
|
||||
name = registry_fix_machine_name(name, &namelen);
|
||||
size_t name_len;
|
||||
name = registry_fix_machine_name(name, &name_len);
|
||||
|
||||
size_t urllen;
|
||||
url = registry_fix_url(url, &urllen);
|
||||
size_t url_len;
|
||||
url = registry_fix_url(url, &url_len);
|
||||
|
||||
REGISTRY_PERSON *p = registry_person_get(person_guid, when);
|
||||
STRING *u = string_strdupz(url);
|
||||
|
||||
if(!is_dummy)
|
||||
registry_person_link_to_url(p, m, u, name, name_len, when);
|
||||
|
||||
REGISTRY_URL *u = registry_url_get(url, urllen);
|
||||
registry_person_link_to_url(p, m, u, name, namelen, when);
|
||||
registry_machine_link_to_url(m, u, when);
|
||||
|
||||
registry_log('A', p, m, u, name);
|
||||
|
@ -164,7 +172,7 @@ REGISTRY_PERSON *registry_request_access(char *person_guid, char *machine_guid,
|
|||
return p;
|
||||
}
|
||||
|
||||
REGISTRY_PERSON *registry_request_delete(char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when) {
|
||||
REGISTRY_PERSON *registry_request_delete(const char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when) {
|
||||
(void) when;
|
||||
|
||||
REGISTRY_PERSON *p = NULL;
|
||||
|
@ -184,14 +192,17 @@ REGISTRY_PERSON *registry_request_delete(char *person_guid, char *machine_guid,
|
|||
}
|
||||
*/
|
||||
|
||||
REGISTRY_PERSON_URL *dpu = registry_person_url_index_find(p, delete_url);
|
||||
STRING *d_url = string_strdupz(delete_url);
|
||||
REGISTRY_PERSON_URL *dpu = registry_person_url_index_find(p, d_url);
|
||||
string_freez(d_url);
|
||||
|
||||
if(!dpu) {
|
||||
netdata_log_info("Registry Delete Request: URL not found for person: '%s', machine '%s', url '%s', delete url '%s'", p->guid
|
||||
, m->guid, pu->url->url, delete_url);
|
||||
, m->guid, string2str(pu->url), delete_url);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
registry_log('D', p, m, pu->url, dpu->url->url);
|
||||
registry_log('D', p, m, pu->url, string2str(dpu->url));
|
||||
registry_person_unlink_from_url(p, dpu);
|
||||
|
||||
return p;
|
||||
|
@ -218,7 +229,7 @@ static int machine_request_callback(void *entry, void *data) {
|
|||
return 0; // continue
|
||||
}
|
||||
|
||||
REGISTRY_MACHINE *registry_request_machine(char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when) {
|
||||
REGISTRY_MACHINE *registry_request_machine(const char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when) {
|
||||
(void)when;
|
||||
|
||||
char mbuf[GUID_LEN + 1];
|
||||
|
@ -230,7 +241,7 @@ REGISTRY_MACHINE *registry_request_machine(char *person_guid, char *machine_guid
|
|||
|
||||
// make sure the machine GUID is valid
|
||||
if(regenerate_guid(request_machine, mbuf) == -1) {
|
||||
netdata_log_info("Registry Machine URLs request: invalid machine GUID, person: '%s', machine '%s', url '%s', request machine '%s'", p->guid, m->guid, pu->url->url, request_machine);
|
||||
netdata_log_info("Registry Machine URLs request: invalid machine GUID, person: '%s', machine '%s', url '%s', request machine '%s'", p->guid, m->guid, string2str(pu->url), request_machine);
|
||||
return NULL;
|
||||
}
|
||||
request_machine = mbuf;
|
||||
|
@ -238,7 +249,7 @@ REGISTRY_MACHINE *registry_request_machine(char *person_guid, char *machine_guid
|
|||
// make sure the machine exists
|
||||
m = registry_machine_find(request_machine);
|
||||
if(!m) {
|
||||
netdata_log_info("Registry Machine URLs request: machine not found, person: '%s', machine '%s', url '%s', request machine '%s'", p->guid, machine_guid, pu->url->url, request_machine);
|
||||
netdata_log_info("Registry Machine URLs request: machine not found, person: '%s', machine '%s', url '%s', request machine '%s'", p->guid, machine_guid, string2str(pu->url), request_machine);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -250,7 +261,8 @@ REGISTRY_MACHINE *registry_request_machine(char *person_guid, char *machine_guid
|
|||
struct machine_request_callback_data rdata = { m, NULL };
|
||||
|
||||
// request a walk through on the dictionary
|
||||
avl_traverse(&p->person_urls, machine_request_callback, &rdata);
|
||||
for(pu = p->person_urls; pu ;pu = pu->next)
|
||||
machine_request_callback(pu, &rdata);
|
||||
|
||||
if(rdata.result)
|
||||
return m;
|
||||
|
|
|
@ -10,28 +10,24 @@
|
|||
|
||||
#define REGISTRY_DICTIONARY_OPTIONS (DICT_OPTION_VALUE_LINK_DONT_CLONE | DICT_OPTION_NAME_LINK_DONT_CLONE | DICT_OPTION_SINGLE_THREADED)
|
||||
|
||||
#define REGISTRY_VERIFY_COOKIES_GUID "11111111-2222-3333-4444-555555555555"
|
||||
#define is_dummy_person(person_guid) (strcmp(person_guid, REGISTRY_VERIFY_COOKIES_GUID) == 0)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// COMMON structures
|
||||
|
||||
struct registry {
|
||||
int enabled;
|
||||
netdata_mutex_t lock;
|
||||
|
||||
// entries counters / statistics
|
||||
unsigned long long persons_count;
|
||||
unsigned long long machines_count;
|
||||
unsigned long long usages_count;
|
||||
unsigned long long urls_count;
|
||||
unsigned long long persons_urls_count;
|
||||
unsigned long long machines_urls_count;
|
||||
unsigned long long log_count;
|
||||
|
||||
// memory counters / statistics
|
||||
unsigned long long persons_memory;
|
||||
unsigned long long machines_memory;
|
||||
unsigned long long urls_memory;
|
||||
unsigned long long persons_urls_memory;
|
||||
unsigned long long machines_urls_memory;
|
||||
|
||||
// configuration
|
||||
unsigned long long save_registry_every_entries;
|
||||
char *registry_domain;
|
||||
|
@ -50,7 +46,6 @@ struct registry {
|
|||
char *db_filename;
|
||||
char *log_filename;
|
||||
char *machine_guid_filename;
|
||||
char *session_key_filename;
|
||||
|
||||
// open files
|
||||
FILE *log_fp;
|
||||
|
@ -59,12 +54,15 @@ struct registry {
|
|||
DICTIONARY *persons; // dictionary of REGISTRY_PERSON *, with key the REGISTRY_PERSON.guid
|
||||
DICTIONARY *machines; // dictionary of REGISTRY_MACHINE *, with key the REGISTRY_MACHINE.guid
|
||||
|
||||
avl_tree_type registry_urls_root_index;
|
||||
ARAL *persons_aral;
|
||||
ARAL *machines_aral;
|
||||
|
||||
netdata_mutex_t lock;
|
||||
ARAL *person_urls_aral;
|
||||
ARAL *machine_urls_aral;
|
||||
|
||||
struct aral_statistics aral_stats;
|
||||
};
|
||||
|
||||
#include "registry_url.h"
|
||||
#include "registry_machine.h"
|
||||
#include "registry_person.h"
|
||||
#include "registry.h"
|
||||
|
@ -72,12 +70,12 @@ struct registry {
|
|||
extern struct registry registry;
|
||||
|
||||
// REGISTRY LOW-LEVEL REQUESTS (in registry-internals.c)
|
||||
REGISTRY_PERSON *registry_request_access(char *person_guid, char *machine_guid, char *url, char *name, time_t when);
|
||||
REGISTRY_PERSON *registry_request_delete(char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when);
|
||||
REGISTRY_MACHINE *registry_request_machine(char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when);
|
||||
REGISTRY_PERSON *registry_request_access(const char *person_guid, char *machine_guid, char *url, char *name, time_t when);
|
||||
REGISTRY_PERSON *registry_request_delete(const char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when);
|
||||
REGISTRY_MACHINE *registry_request_machine(const char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when);
|
||||
|
||||
// REGISTRY LOG (in registry_log.c)
|
||||
void registry_log(char action, REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name);
|
||||
void registry_log(char action, REGISTRY_PERSON *p, REGISTRY_MACHINE *m, STRING *u, const char *name);
|
||||
int registry_log_open(void);
|
||||
void registry_log_close(void);
|
||||
void registry_log_recreate(void);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "daemon/common.h"
|
||||
#include "registry_internals.h"
|
||||
|
||||
void registry_log(char action, REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name) {
|
||||
void registry_log(char action, REGISTRY_PERSON *p, REGISTRY_MACHINE *m, STRING *u, const char *name) {
|
||||
if(likely(registry.log_fp)) {
|
||||
if(unlikely(fprintf(registry.log_fp, "%c\t%08x\t%s\t%s\t%s\t%s\n",
|
||||
action,
|
||||
|
@ -11,7 +11,7 @@ void registry_log(char action, REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY
|
|||
p->guid,
|
||||
m->guid,
|
||||
name,
|
||||
u->url) < 0))
|
||||
string2str(u)) < 0))
|
||||
netdata_log_error("Registry: failed to save log. Registry data may be lost in case of abnormal restart.");
|
||||
|
||||
// we increase the counter even on failures
|
||||
|
@ -94,7 +94,7 @@ ssize_t registry_log_load(void) {
|
|||
s[1] = s[10] = s[47] = s[84] = '\0';
|
||||
|
||||
// get the variables
|
||||
time_t when = strtoul(&s[2], NULL, 16);
|
||||
time_t when = (time_t)strtoul(&s[2], NULL, 16);
|
||||
char *person_guid = &s[11];
|
||||
char *machine_guid = &s[48];
|
||||
char *name = &s[85];
|
||||
|
|
|
@ -7,52 +7,58 @@
|
|||
// MACHINE
|
||||
|
||||
REGISTRY_MACHINE *registry_machine_find(const char *machine_guid) {
|
||||
debug(D_REGISTRY, "Registry: registry_machine_find('%s')", machine_guid);
|
||||
debug(D_REGISTRY, "REGISTRY: registry_machine_find('%s')", machine_guid);
|
||||
return dictionary_get(registry.machines, machine_guid);
|
||||
}
|
||||
|
||||
REGISTRY_MACHINE_URL *registry_machine_url_allocate(REGISTRY_MACHINE *m, REGISTRY_URL *u, time_t when) {
|
||||
debug(D_REGISTRY, "registry_machine_url_allocate('%s', '%s'): allocating %zu bytes", m->guid, u->url, sizeof(REGISTRY_MACHINE_URL));
|
||||
REGISTRY_MACHINE_URL *registry_machine_url_find(REGISTRY_MACHINE *m, STRING *url) {
|
||||
REGISTRY_MACHINE_URL *mu;
|
||||
|
||||
REGISTRY_MACHINE_URL *mu = mallocz(sizeof(REGISTRY_MACHINE_URL));
|
||||
for(mu = m->machine_urls; mu ;mu = mu->next)
|
||||
if(mu->url == url)
|
||||
break;
|
||||
|
||||
return mu;
|
||||
}
|
||||
|
||||
void registry_machine_url_unlink_from_machine_and_free(REGISTRY_MACHINE *m, REGISTRY_MACHINE_URL *mu) {
|
||||
DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(m->machine_urls, mu, prev, next);
|
||||
string_freez(mu->url);
|
||||
aral_freez(registry.machine_urls_aral, mu);
|
||||
}
|
||||
|
||||
REGISTRY_MACHINE_URL *registry_machine_url_allocate(REGISTRY_MACHINE *m, STRING *u, time_t when) {
|
||||
debug(D_REGISTRY, "REGISTRY: registry_machine_url_allocate('%s', '%s'): allocating %zu bytes", m->guid, string2str(u), sizeof(REGISTRY_MACHINE_URL));
|
||||
|
||||
REGISTRY_MACHINE_URL *mu = aral_mallocz(registry.machine_urls_aral);
|
||||
|
||||
mu->first_t = mu->last_t = (uint32_t)when;
|
||||
mu->usages = 1;
|
||||
mu->url = u;
|
||||
mu->url = string_dup(u);
|
||||
mu->flags = REGISTRY_URL_FLAGS_DEFAULT;
|
||||
|
||||
registry.machines_urls_memory += sizeof(REGISTRY_MACHINE_URL);
|
||||
debug(D_REGISTRY, "REGISTRY: registry_machine_url_allocate('%s', '%s'): indexing URL in machine", m->guid, string2str(u));
|
||||
|
||||
debug(D_REGISTRY, "registry_machine_url_allocate('%s', '%s'): indexing URL in machine", m->guid, u->url);
|
||||
|
||||
registry.machines_urls_memory -= dictionary_stats_for_registry(m->machine_urls);
|
||||
dictionary_set(m->machine_urls, u->url, mu, sizeof(REGISTRY_MACHINE_URL));
|
||||
registry.machines_urls_memory += dictionary_stats_for_registry(m->machine_urls);
|
||||
|
||||
registry_url_link(u);
|
||||
DOUBLE_LINKED_LIST_PREPEND_ITEM_UNSAFE(m->machine_urls, mu, prev, next);
|
||||
|
||||
return mu;
|
||||
}
|
||||
|
||||
REGISTRY_MACHINE *registry_machine_allocate(const char *machine_guid, time_t when) {
|
||||
debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating new machine, sizeof(MACHINE)=%zu", machine_guid, sizeof(REGISTRY_MACHINE));
|
||||
debug(D_REGISTRY, "REGISTRY: registry_machine_allocate('%s'): creating new machine, sizeof(MACHINE)=%zu", machine_guid, sizeof(REGISTRY_MACHINE));
|
||||
|
||||
REGISTRY_MACHINE *m = mallocz(sizeof(REGISTRY_MACHINE));
|
||||
REGISTRY_MACHINE *m = aral_mallocz(registry.machines_aral);
|
||||
|
||||
strncpyz(m->guid, machine_guid, GUID_LEN);
|
||||
|
||||
debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating dictionary of urls", machine_guid);
|
||||
m->machine_urls = dictionary_create(REGISTRY_DICTIONARY_OPTIONS);
|
||||
m->machine_urls = NULL;
|
||||
|
||||
m->first_t = m->last_t = (uint32_t)when;
|
||||
m->usages = 0;
|
||||
|
||||
registry.machines_memory += sizeof(REGISTRY_MACHINE);
|
||||
registry.machines_count++;
|
||||
|
||||
registry.machines_urls_memory -= dictionary_stats_for_registry(m->machine_urls);
|
||||
dictionary_set(registry.machines, m->guid, m, sizeof(REGISTRY_MACHINE));
|
||||
registry.machines_urls_memory += dictionary_stats_for_registry(m->machine_urls);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
@ -60,14 +66,14 @@ REGISTRY_MACHINE *registry_machine_allocate(const char *machine_guid, time_t whe
|
|||
// 1. validate machine GUID
|
||||
// 2. if it is valid, find it or create it and return it
|
||||
// 3. if it is not valid, return NULL
|
||||
REGISTRY_MACHINE *registry_machine_get(const char *machine_guid, time_t when) {
|
||||
REGISTRY_MACHINE *registry_machine_find_or_create(const char *machine_guid, time_t when, bool is_dummy __maybe_unused) {
|
||||
REGISTRY_MACHINE *m = NULL;
|
||||
|
||||
if(likely(machine_guid && *machine_guid)) {
|
||||
// validate it is a GUID
|
||||
char buf[GUID_LEN + 1];
|
||||
if(unlikely(regenerate_guid(machine_guid, buf) == -1))
|
||||
netdata_log_info("Registry: machine guid '%s' is not a valid guid. Ignoring it.", machine_guid);
|
||||
netdata_log_info("REGISTRY: machine guid '%s' is not a valid guid. Ignoring it.", machine_guid);
|
||||
else {
|
||||
machine_guid = buf;
|
||||
m = registry_machine_find(machine_guid);
|
||||
|
@ -82,17 +88,17 @@ REGISTRY_MACHINE *registry_machine_get(const char *machine_guid, time_t when) {
|
|||
// ----------------------------------------------------------------------------
|
||||
// LINKING OF OBJECTS
|
||||
|
||||
REGISTRY_MACHINE_URL *registry_machine_link_to_url(REGISTRY_MACHINE *m, REGISTRY_URL *u, time_t when) {
|
||||
debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): searching for URL in machine", m->guid, u->url);
|
||||
REGISTRY_MACHINE_URL *registry_machine_link_to_url(REGISTRY_MACHINE *m, STRING *url, time_t when) {
|
||||
debug(D_REGISTRY, "REGISTRY: registry_machine_link_to_url('%s', '%s'): searching for URL in machine", m->guid, string2str(url));
|
||||
|
||||
REGISTRY_MACHINE_URL *mu = dictionary_get(m->machine_urls, u->url);
|
||||
REGISTRY_MACHINE_URL *mu = registry_machine_url_find(m, url);
|
||||
if(!mu) {
|
||||
debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): not found", m->guid, u->url);
|
||||
mu = registry_machine_url_allocate(m, u, when);
|
||||
debug(D_REGISTRY, "REGISTRY: registry_machine_link_to_url('%s', '%s'): not found", m->guid, string2str(url));
|
||||
mu = registry_machine_url_allocate(m, url, when);
|
||||
registry.machines_urls_count++;
|
||||
}
|
||||
else {
|
||||
debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): found", m->guid, u->url);
|
||||
debug(D_REGISTRY, "REGISTRY: registry_machine_link_to_url('%s', '%s'): found", m->guid, string2str(url));
|
||||
mu->usages++;
|
||||
if(likely(mu->last_t < (uint32_t)when)) mu->last_t = (uint32_t)when;
|
||||
}
|
||||
|
@ -101,7 +107,7 @@ REGISTRY_MACHINE_URL *registry_machine_link_to_url(REGISTRY_MACHINE *m, REGISTRY
|
|||
if(likely(m->last_t < (uint32_t)when)) m->last_t = (uint32_t)when;
|
||||
|
||||
if(mu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
|
||||
debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): accessing an expired URL.", m->guid, u->url);
|
||||
debug(D_REGISTRY, "REGISTRY: registry_machine_link_to_url('%s', '%s'): accessing an expired URL.", m->guid, string2str(url));
|
||||
mu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,13 +10,15 @@
|
|||
|
||||
// For each MACHINE-URL pair we keep this
|
||||
struct registry_machine_url {
|
||||
REGISTRY_URL *url; // de-duplicated URL
|
||||
STRING *url; // de-duplicated URL
|
||||
|
||||
uint8_t flags;
|
||||
|
||||
uint32_t first_t; // the first time we saw this
|
||||
uint32_t last_t; // the last time we saw this
|
||||
uint32_t usages; // how many times this has been accessed
|
||||
|
||||
struct registry_machine_url *prev, *next;
|
||||
};
|
||||
typedef struct registry_machine_url REGISTRY_MACHINE_URL;
|
||||
|
||||
|
@ -26,7 +28,7 @@ struct registry_machine {
|
|||
|
||||
uint32_t links; // the number of REGISTRY_PERSON_URL linked to this machine
|
||||
|
||||
DICTIONARY *machine_urls; // MACHINE_URL *
|
||||
REGISTRY_MACHINE_URL *machine_urls; // MACHINE_URL *
|
||||
|
||||
uint32_t first_t; // the first time we saw this
|
||||
uint32_t last_t; // the last time we saw this
|
||||
|
@ -35,9 +37,12 @@ struct registry_machine {
|
|||
typedef struct registry_machine REGISTRY_MACHINE;
|
||||
|
||||
REGISTRY_MACHINE *registry_machine_find(const char *machine_guid);
|
||||
REGISTRY_MACHINE_URL *registry_machine_url_allocate(REGISTRY_MACHINE *m, REGISTRY_URL *u, time_t when);
|
||||
REGISTRY_MACHINE_URL *registry_machine_url_allocate(REGISTRY_MACHINE *m, STRING *u, time_t when);
|
||||
REGISTRY_MACHINE *registry_machine_allocate(const char *machine_guid, time_t when);
|
||||
REGISTRY_MACHINE *registry_machine_get(const char *machine_guid, time_t when);
|
||||
REGISTRY_MACHINE_URL *registry_machine_link_to_url(REGISTRY_MACHINE *m, REGISTRY_URL *u, time_t when);
|
||||
REGISTRY_MACHINE *registry_machine_find_or_create(const char *machine_guid, time_t when, bool is_dummy);
|
||||
REGISTRY_MACHINE_URL *registry_machine_link_to_url(REGISTRY_MACHINE *m, STRING *url, time_t when);
|
||||
|
||||
REGISTRY_MACHINE_URL *registry_machine_url_find(REGISTRY_MACHINE *m, STRING *url);
|
||||
void registry_machine_url_unlink_from_machine_and_free(REGISTRY_MACHINE *m, REGISTRY_MACHINE_URL *mu);
|
||||
|
||||
#endif //NETDATA_REGISTRY_MACHINE_H
|
||||
|
|
|
@ -6,103 +6,78 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
// PERSON_URL INDEX
|
||||
|
||||
int person_url_compare(void *a, void *b) {
|
||||
register uint32_t hash1 = ((REGISTRY_PERSON_URL *)a)->url->hash;
|
||||
register uint32_t hash2 = ((REGISTRY_PERSON_URL *)b)->url->hash;
|
||||
inline REGISTRY_PERSON_URL *registry_person_url_index_find(REGISTRY_PERSON *p, STRING *url) {
|
||||
debug(D_REGISTRY, "Registry: registry_person_url_index_find('%s', '%s')", p->guid, string2str(url));
|
||||
|
||||
if(hash1 < hash2) return -1;
|
||||
else if(hash1 > hash2) return 1;
|
||||
else return strcmp(((REGISTRY_PERSON_URL *)a)->url->url, ((REGISTRY_PERSON_URL *)b)->url->url);
|
||||
}
|
||||
REGISTRY_PERSON_URL *pu;
|
||||
for(pu = p->person_urls ; pu ;pu = pu->next)
|
||||
if(pu->url == url)
|
||||
break;
|
||||
|
||||
inline REGISTRY_PERSON_URL *registry_person_url_index_find(REGISTRY_PERSON *p, const char *url) {
|
||||
debug(D_REGISTRY, "Registry: registry_person_url_index_find('%s', '%s')", p->guid, url);
|
||||
|
||||
char buf[sizeof(REGISTRY_URL) + strlen(url)];
|
||||
|
||||
REGISTRY_URL *u = (REGISTRY_URL *)&buf;
|
||||
strcpy(u->url, url);
|
||||
u->hash = simple_hash(u->url);
|
||||
|
||||
REGISTRY_PERSON_URL tpu = { .url = u };
|
||||
|
||||
REGISTRY_PERSON_URL *pu = (REGISTRY_PERSON_URL *)avl_search(&p->person_urls, (void *)&tpu);
|
||||
return pu;
|
||||
}
|
||||
|
||||
inline REGISTRY_PERSON_URL *registry_person_url_index_add(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) {
|
||||
debug(D_REGISTRY, "Registry: registry_person_url_index_add('%s', '%s')", p->guid, pu->url->url);
|
||||
REGISTRY_PERSON_URL *tpu = (REGISTRY_PERSON_URL *)avl_insert(&(p->person_urls), (avl_t *)(pu));
|
||||
if(tpu != pu)
|
||||
netdata_log_error("Registry: registry_person_url_index_add('%s', '%s') already exists as '%s'", p->guid, pu->url->url, tpu->url->url);
|
||||
|
||||
return tpu;
|
||||
DOUBLE_LINKED_LIST_PREPEND_ITEM_UNSAFE(p->person_urls, pu, prev, next);
|
||||
return pu;
|
||||
}
|
||||
|
||||
inline REGISTRY_PERSON_URL *registry_person_url_index_del(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) {
|
||||
debug(D_REGISTRY, "Registry: registry_person_url_index_del('%s', '%s')", p->guid, pu->url->url);
|
||||
REGISTRY_PERSON_URL *tpu = (REGISTRY_PERSON_URL *)avl_remove(&(p->person_urls), (avl_t *)(pu));
|
||||
if(!tpu)
|
||||
netdata_log_error("Registry: registry_person_url_index_del('%s', '%s') deleted nothing", p->guid, pu->url->url);
|
||||
else if(tpu != pu)
|
||||
netdata_log_error("Registry: registry_person_url_index_del('%s', '%s') deleted wrong URL '%s'", p->guid, pu->url->url, tpu->url->url);
|
||||
|
||||
return tpu;
|
||||
DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(p->person_urls, pu, prev, next);
|
||||
return pu;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// PERSON_URL
|
||||
|
||||
REGISTRY_PERSON_URL *registry_person_url_allocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when) {
|
||||
debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url, sizeof(REGISTRY_PERSON_URL) + namelen);
|
||||
REGISTRY_PERSON_URL *registry_person_url_allocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, STRING *url, char *machine_name, size_t machine_name_len, time_t when) {
|
||||
debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, string2str(url), sizeof(REGISTRY_PERSON_URL) + machine_name_len);
|
||||
|
||||
// protection from too big names
|
||||
if(namelen > registry.max_name_length)
|
||||
namelen = registry.max_name_length;
|
||||
if(machine_name_len > registry.max_name_length)
|
||||
machine_name_len = registry.max_name_length;
|
||||
|
||||
REGISTRY_PERSON_URL *pu = mallocz(sizeof(REGISTRY_PERSON_URL) + namelen);
|
||||
REGISTRY_PERSON_URL *pu = aral_mallocz(registry.person_urls_aral);
|
||||
|
||||
// a simple strcpy() should do the job
|
||||
// but I prefer to be safe, since the caller specified urllen
|
||||
strncpyz(pu->machine_name, name, namelen);
|
||||
// a simple strcpy() should do the job,
|
||||
// but I prefer to be safe, since the caller specified name_len
|
||||
pu->machine_name = string_strdupz(machine_name);
|
||||
|
||||
pu->machine = m;
|
||||
pu->first_t = pu->last_t = (uint32_t)when;
|
||||
pu->usages = 1;
|
||||
pu->url = u;
|
||||
pu->url = string_dup(url);
|
||||
pu->flags = REGISTRY_URL_FLAGS_DEFAULT;
|
||||
m->links++;
|
||||
|
||||
registry.persons_urls_memory += sizeof(REGISTRY_PERSON_URL) + namelen;
|
||||
|
||||
debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): indexing URL in person", p->guid, m->guid, u->url);
|
||||
debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): indexing URL in person", p->guid, m->guid, string2str(url));
|
||||
REGISTRY_PERSON_URL *tpu = registry_person_url_index_add(p, pu);
|
||||
if(tpu != pu) {
|
||||
netdata_log_error("Registry: Attempted to add duplicate person url '%s' with name '%s' to person '%s'", u->url, name, p->guid);
|
||||
freez(pu);
|
||||
netdata_log_error("Registry: Attempted to add duplicate person url '%s' with name '%s' to person '%s'", string2str(url), machine_name, p->guid);
|
||||
string_freez(pu->machine_name);
|
||||
string_freez(pu->url);
|
||||
aral_freez(registry.person_urls_aral, pu);
|
||||
pu = tpu;
|
||||
}
|
||||
else
|
||||
registry_url_link(u);
|
||||
|
||||
return pu;
|
||||
}
|
||||
|
||||
void registry_person_url_free(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) {
|
||||
debug(D_REGISTRY, "registry_person_url_free('%s', '%s')", p->guid, pu->url->url);
|
||||
void registry_person_url_deindex_and_free(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) {
|
||||
debug(D_REGISTRY, "registry_person_url_deindex_and_free('%s', '%s')", p->guid, string2str(pu->url));
|
||||
|
||||
REGISTRY_PERSON_URL *tpu = registry_person_url_index_del(p, pu);
|
||||
if(tpu) {
|
||||
registry_url_unlink(tpu->url);
|
||||
string_freez(tpu->machine_name);
|
||||
string_freez(tpu->url);
|
||||
tpu->machine->links--;
|
||||
registry.persons_urls_memory -= sizeof(REGISTRY_PERSON_URL) + strlen(tpu->machine_name);
|
||||
freez(tpu);
|
||||
aral_freez(registry.person_urls_aral, tpu);
|
||||
}
|
||||
}
|
||||
|
||||
// this function is needed to change the name of a PERSON_URL
|
||||
REGISTRY_PERSON_URL *registry_person_url_reallocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when, REGISTRY_PERSON_URL *pu) {
|
||||
debug(D_REGISTRY, "registry_person_url_reallocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url, sizeof(REGISTRY_PERSON_URL) + namelen);
|
||||
REGISTRY_PERSON_URL *registry_person_url_reallocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, STRING *url, char *machine_name, size_t machine_name_len, time_t when, REGISTRY_PERSON_URL *pu) {
|
||||
debug(D_REGISTRY, "registry_person_url_reallocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, string2str(url), sizeof(REGISTRY_PERSON_URL) + machine_name_len);
|
||||
|
||||
// keep a backup
|
||||
REGISTRY_PERSON_URL pu2 = {
|
||||
|
@ -111,15 +86,15 @@ REGISTRY_PERSON_URL *registry_person_url_reallocate(REGISTRY_PERSON *p, REGISTRY
|
|||
.usages = pu->usages,
|
||||
.flags = pu->flags,
|
||||
.machine = pu->machine,
|
||||
.machine_name = ""
|
||||
.machine_name = NULL
|
||||
};
|
||||
|
||||
// remove the existing one from the index
|
||||
registry_person_url_free(p, pu);
|
||||
registry_person_url_deindex_and_free(p, pu);
|
||||
pu = &pu2;
|
||||
|
||||
// allocate a new one
|
||||
REGISTRY_PERSON_URL *tpu = registry_person_url_allocate(p, m, u, name, namelen, when);
|
||||
REGISTRY_PERSON_URL *tpu = registry_person_url_allocate(p, m, url, machine_name, machine_name_len, when);
|
||||
tpu->first_t = pu->first_t;
|
||||
tpu->last_t = pu->last_t;
|
||||
tpu->usages = pu->usages;
|
||||
|
@ -140,7 +115,7 @@ REGISTRY_PERSON *registry_person_find(const char *person_guid) {
|
|||
REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t when) {
|
||||
debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): allocating new person, sizeof(PERSON)=%zu", (person_guid)?person_guid:"", sizeof(REGISTRY_PERSON));
|
||||
|
||||
REGISTRY_PERSON *p = mallocz(sizeof(REGISTRY_PERSON));
|
||||
REGISTRY_PERSON *p = aral_mallocz(registry.persons_aral);
|
||||
if(!person_guid) {
|
||||
for(;;) {
|
||||
uuid_t uuid;
|
||||
|
@ -159,14 +134,11 @@ REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t when)
|
|||
else
|
||||
strncpyz(p->guid, person_guid, GUID_LEN);
|
||||
|
||||
debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): creating dictionary of urls", p->guid);
|
||||
avl_init(&p->person_urls, person_url_compare);
|
||||
p->person_urls = NULL;
|
||||
|
||||
p->first_t = p->last_t = (uint32_t)when;
|
||||
p->usages = 0;
|
||||
|
||||
registry.persons_memory += sizeof(REGISTRY_PERSON);
|
||||
|
||||
registry.persons_count++;
|
||||
dictionary_set(registry.persons, p->guid, p, sizeof(REGISTRY_PERSON));
|
||||
|
||||
|
@ -178,23 +150,29 @@ REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t when)
|
|||
// 2. if it is valid, find it
|
||||
// 3. if it is not valid, create a new one
|
||||
// 4. return it
|
||||
REGISTRY_PERSON *registry_person_get(const char *person_guid, time_t when) {
|
||||
debug(D_REGISTRY, "Registry: registry_person_get('%s'): creating dictionary of urls", person_guid);
|
||||
REGISTRY_PERSON *registry_person_find_or_create(const char *person_guid, time_t when, bool is_dummy) {
|
||||
debug(D_REGISTRY, "Registry: registry_person_find_or_create('%s'): creating dictionary of urls", person_guid);
|
||||
|
||||
char buf[GUID_LEN + 1];
|
||||
REGISTRY_PERSON *p = NULL;
|
||||
|
||||
if(person_guid && *person_guid) {
|
||||
char buf[GUID_LEN + 1];
|
||||
// validate it is a GUID
|
||||
if(unlikely(regenerate_guid(person_guid, buf) == -1))
|
||||
if(unlikely(regenerate_guid(person_guid, buf) == -1)) {
|
||||
netdata_log_info("Registry: person guid '%s' is not a valid guid. Ignoring it.", person_guid);
|
||||
person_guid = NULL;
|
||||
}
|
||||
else {
|
||||
person_guid = buf;
|
||||
p = registry_person_find(person_guid);
|
||||
if(!p && !is_dummy)
|
||||
person_guid = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
person_guid = NULL;
|
||||
|
||||
if(!p) p = registry_person_allocate(NULL, when);
|
||||
if(!p) p = registry_person_allocate(person_guid, when);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
@ -202,39 +180,39 @@ REGISTRY_PERSON *registry_person_get(const char *person_guid, time_t when) {
|
|||
// ----------------------------------------------------------------------------
|
||||
// LINKING OF OBJECTS
|
||||
|
||||
REGISTRY_PERSON_URL *registry_person_link_to_url(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when) {
|
||||
debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): searching for URL in person", p->guid, m->guid, u->url);
|
||||
REGISTRY_PERSON_URL *registry_person_link_to_url(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, STRING *url, char *machine_name, size_t machine_name_len, time_t when) {
|
||||
debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): searching for URL in person", p->guid, m->guid, string2str(url));
|
||||
|
||||
REGISTRY_PERSON_URL *pu = registry_person_url_index_find(p, u->url);
|
||||
REGISTRY_PERSON_URL *pu = registry_person_url_index_find(p, url);
|
||||
if(!pu) {
|
||||
debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, u->url);
|
||||
pu = registry_person_url_allocate(p, m, u, name, namelen, when);
|
||||
debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, string2str(url));
|
||||
pu = registry_person_url_allocate(p, m, url, machine_name, machine_name_len, when);
|
||||
registry.persons_urls_count++;
|
||||
}
|
||||
else {
|
||||
debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): found", p->guid, m->guid, u->url);
|
||||
debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): found", p->guid, m->guid, string2str(url));
|
||||
pu->usages++;
|
||||
if(likely(pu->last_t < (uint32_t)when)) pu->last_t = (uint32_t)when;
|
||||
|
||||
if(pu->machine != m) {
|
||||
REGISTRY_MACHINE_URL *mu = dictionary_get(pu->machine->machine_urls, u->url);
|
||||
REGISTRY_MACHINE_URL *mu = registry_machine_url_find(pu->machine, url);
|
||||
if(mu) {
|
||||
debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - expiring it from previous machine.",
|
||||
p->guid, m->guid, u->url, pu->machine->guid);
|
||||
p->guid, m->guid, string2str(url), pu->machine->guid);
|
||||
mu->flags |= REGISTRY_URL_FLAGS_EXPIRED;
|
||||
}
|
||||
else {
|
||||
debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - but the URL is not linked to the old machine.",
|
||||
p->guid, m->guid, u->url, pu->machine->guid);
|
||||
p->guid, m->guid, string2str(url), pu->machine->guid);
|
||||
}
|
||||
|
||||
pu->machine->links--;
|
||||
pu->machine = m;
|
||||
}
|
||||
|
||||
if(strcmp(pu->machine_name, name) != 0) {
|
||||
if(strcmp(string2str(pu->machine_name), machine_name) != 0) {
|
||||
// the name of the PERSON_URL has changed !
|
||||
pu = registry_person_url_reallocate(p, m, u, name, namelen, when, pu);
|
||||
pu = registry_person_url_reallocate(p, m, url, machine_name, machine_name_len, when, pu);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,7 +220,7 @@ REGISTRY_PERSON_URL *registry_person_link_to_url(REGISTRY_PERSON *p, REGISTRY_MA
|
|||
if(likely(p->last_t < (uint32_t)when)) p->last_t = (uint32_t)when;
|
||||
|
||||
if(pu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
|
||||
debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): accessing an expired URL. Re-enabling URL.", p->guid, m->guid, u->url);
|
||||
debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): accessing an expired URL. Re-enabling URL.", p->guid, m->guid, string2str(url));
|
||||
pu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
|
||||
}
|
||||
|
||||
|
@ -250,5 +228,5 @@ REGISTRY_PERSON_URL *registry_person_link_to_url(REGISTRY_PERSON *p, REGISTRY_MA
|
|||
}
|
||||
|
||||
void registry_person_unlink_from_url(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) {
|
||||
registry_person_url_free(p, pu);
|
||||
registry_person_url_deindex_and_free(p, pu);
|
||||
}
|
||||
|
|
|
@ -10,19 +10,18 @@
|
|||
|
||||
// for each PERSON-URL pair we keep this
|
||||
struct registry_person_url {
|
||||
avl_t avl; // binary tree node
|
||||
|
||||
REGISTRY_URL *url; // de-duplicated URL
|
||||
REGISTRY_MACHINE *machine; // link the MACHINE of this URL
|
||||
|
||||
uint8_t flags;
|
||||
|
||||
uint32_t usages; // how many times this has been accessed
|
||||
|
||||
uint32_t first_t; // the first time we saw this
|
||||
uint32_t last_t; // the last time we saw this
|
||||
uint32_t usages; // how many times this has been accessed
|
||||
|
||||
char machine_name[1]; // the name of the machine, as known by the user
|
||||
// dynamically allocated to fit properly
|
||||
REGISTRY_MACHINE *machine; // link the MACHINE of this URL
|
||||
STRING *machine_name; // the hostname of the machine
|
||||
STRING *url; // de-duplicated URL
|
||||
|
||||
struct registry_person_url *prev, *next;
|
||||
};
|
||||
typedef struct registry_person_url REGISTRY_PERSON_URL;
|
||||
|
||||
|
@ -30,32 +29,29 @@ typedef struct registry_person_url REGISTRY_PERSON_URL;
|
|||
struct registry_person {
|
||||
char guid[GUID_LEN + 1]; // the person GUID
|
||||
|
||||
avl_tree_type person_urls; // dictionary of PERSON_URLs
|
||||
REGISTRY_PERSON_URL *person_urls; // dictionary of PERSON_URLs
|
||||
|
||||
uint32_t first_t; // the first time we saw this
|
||||
uint32_t last_t; // the last time we saw this
|
||||
uint32_t usages; // how many times this has been accessed
|
||||
|
||||
//uint32_t flags;
|
||||
//char *email;
|
||||
};
|
||||
typedef struct registry_person REGISTRY_PERSON;
|
||||
|
||||
// PERSON_URL
|
||||
REGISTRY_PERSON_URL *registry_person_url_index_find(REGISTRY_PERSON *p, const char *url);
|
||||
REGISTRY_PERSON_URL *registry_person_url_index_find(REGISTRY_PERSON *p, STRING *url);
|
||||
REGISTRY_PERSON_URL *registry_person_url_index_add(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) NEVERNULL WARNUNUSED;
|
||||
REGISTRY_PERSON_URL *registry_person_url_index_del(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) WARNUNUSED;
|
||||
|
||||
REGISTRY_PERSON_URL *registry_person_url_allocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when);
|
||||
REGISTRY_PERSON_URL *registry_person_url_reallocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when, REGISTRY_PERSON_URL *pu);
|
||||
REGISTRY_PERSON_URL *registry_person_url_allocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, STRING *url, char *machine_name, size_t machine_name_len, time_t when);
|
||||
REGISTRY_PERSON_URL *registry_person_url_reallocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, STRING *url, char *machine_name, size_t machine_name_len, time_t when, REGISTRY_PERSON_URL *pu);
|
||||
|
||||
// PERSON
|
||||
REGISTRY_PERSON *registry_person_find(const char *person_guid);
|
||||
REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t when);
|
||||
REGISTRY_PERSON *registry_person_get(const char *person_guid, time_t when);
|
||||
REGISTRY_PERSON *registry_person_find_or_create(const char *person_guid, time_t when, bool is_dummy);
|
||||
|
||||
// LINKING PERSON -> PERSON_URL
|
||||
REGISTRY_PERSON_URL *registry_person_link_to_url(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when);
|
||||
REGISTRY_PERSON_URL *registry_person_link_to_url(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, STRING *url, char *machine_name, size_t machine_name_len, time_t when);
|
||||
void registry_person_unlink_from_url(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu);
|
||||
|
||||
#endif //NETDATA_REGISTRY_PERSON_H
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "daemon/common.h"
|
||||
#include "registry_internals.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// REGISTRY_URL
|
||||
|
||||
int registry_url_compare(void *a, void *b) {
|
||||
if(((REGISTRY_URL *)a)->hash < ((REGISTRY_URL *)b)->hash) return -1;
|
||||
else if(((REGISTRY_URL *)a)->hash > ((REGISTRY_URL *)b)->hash) return 1;
|
||||
else return strcmp(((REGISTRY_URL *)a)->url, ((REGISTRY_URL *)b)->url);
|
||||
}
|
||||
|
||||
inline REGISTRY_URL *registry_url_index_add(REGISTRY_URL *u) {
|
||||
return (REGISTRY_URL *)avl_insert(&(registry.registry_urls_root_index), (avl_t *)(u));
|
||||
}
|
||||
|
||||
inline REGISTRY_URL *registry_url_index_del(REGISTRY_URL *u) {
|
||||
return (REGISTRY_URL *)avl_remove(&(registry.registry_urls_root_index), (avl_t *)(u));
|
||||
}
|
||||
|
||||
REGISTRY_URL *registry_url_get(const char *url, size_t urllen) {
|
||||
// protection from too big URLs
|
||||
if(urllen > registry.max_url_length)
|
||||
urllen = registry.max_url_length;
|
||||
|
||||
debug(D_REGISTRY, "Registry: registry_url_get('%s', %zu)", url, urllen);
|
||||
|
||||
char buf[sizeof(REGISTRY_URL) + urllen]; // no need for +1, 1 is already in REGISTRY_URL
|
||||
REGISTRY_URL *n = (REGISTRY_URL *)&buf[0];
|
||||
n->len = (uint16_t)urllen;
|
||||
strncpyz(n->url, url, n->len);
|
||||
n->hash = simple_hash(n->url);
|
||||
|
||||
REGISTRY_URL *u = (REGISTRY_URL *)avl_search(&(registry.registry_urls_root_index), (avl_t *)n);
|
||||
if(!u) {
|
||||
debug(D_REGISTRY, "Registry: registry_url_get('%s', %zu): allocating %zu bytes", url, urllen, sizeof(REGISTRY_URL) + urllen);
|
||||
u = callocz(1, sizeof(REGISTRY_URL) + urllen); // no need for +1, 1 is already in REGISTRY_URL
|
||||
|
||||
// a simple strcpy() should do the job
|
||||
// but I prefer to be safe, since the caller specified urllen
|
||||
u->len = (uint16_t)urllen;
|
||||
strncpyz(u->url, url, u->len);
|
||||
u->links = 0;
|
||||
u->hash = simple_hash(u->url);
|
||||
|
||||
registry.urls_memory += sizeof(REGISTRY_URL) + urllen; // no need for +1, 1 is already in REGISTRY_URL
|
||||
|
||||
debug(D_REGISTRY, "Registry: registry_url_get('%s'): indexing it", url);
|
||||
n = registry_url_index_add(u);
|
||||
if(n != u) {
|
||||
netdata_log_error("INTERNAL ERROR: registry_url_get(): url '%s' already exists in the registry as '%s'", u->url, n->url);
|
||||
freez(u);
|
||||
u = n;
|
||||
}
|
||||
else
|
||||
registry.urls_count++;
|
||||
}
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
void registry_url_link(REGISTRY_URL *u) {
|
||||
u->links++;
|
||||
debug(D_REGISTRY, "Registry: registry_url_link('%s'): URL has now %u links", u->url, u->links);
|
||||
}
|
||||
|
||||
void registry_url_unlink(REGISTRY_URL *u) {
|
||||
u->links--;
|
||||
if(!u->links) {
|
||||
debug(D_REGISTRY, "Registry: registry_url_unlink('%s'): No more links for this URL", u->url);
|
||||
REGISTRY_URL *n = registry_url_index_del(u);
|
||||
if(!n) {
|
||||
netdata_log_error("INTERNAL ERROR: registry_url_unlink('%s'): cannot find url in index", u->url);
|
||||
}
|
||||
else {
|
||||
if(n != u) {
|
||||
netdata_log_error("INTERNAL ERROR: registry_url_unlink('%s'): deleted different url '%s'", u->url, n->url);
|
||||
}
|
||||
|
||||
registry.urls_memory -= sizeof(REGISTRY_URL) + n->len; // no need for +1, 1 is already in REGISTRY_URL
|
||||
freez(n);
|
||||
}
|
||||
}
|
||||
else
|
||||
debug(D_REGISTRY, "Registry: registry_url_unlink('%s'): URL has %u links left", u->url, u->links);
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef NETDATA_REGISTRY_URL_H
|
||||
#define NETDATA_REGISTRY_URL_H 1
|
||||
|
||||
#include "registry_internals.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// URL structures
|
||||
// Save memory by de-duplicating URLs
|
||||
// so instead of storing URLs all over the place
|
||||
// we store them here and we keep pointers elsewhere
|
||||
|
||||
struct registry_url {
|
||||
avl_t avl;
|
||||
uint32_t hash; // the index hash
|
||||
|
||||
uint32_t links; // the number of links to this URL - when none is left, we free it
|
||||
|
||||
uint16_t len; // the length of the URL in bytes
|
||||
char url[1]; // the URL - dynamically allocated to more size
|
||||
};
|
||||
typedef struct registry_url REGISTRY_URL;
|
||||
|
||||
// REGISTRY_URL INDEX
|
||||
int registry_url_compare(void *a, void *b);
|
||||
REGISTRY_URL *registry_url_index_del(REGISTRY_URL *u) WARNUNUSED;
|
||||
REGISTRY_URL *registry_url_index_add(REGISTRY_URL *u) NEVERNULL WARNUNUSED;
|
||||
|
||||
// REGISTRY_URL MANAGEMENT
|
||||
REGISTRY_URL *registry_url_get(const char *url, size_t urllen) NEVERNULL;
|
||||
void registry_url_link(REGISTRY_URL *u);
|
||||
void registry_url_unlink(REGISTRY_URL *u);
|
||||
|
||||
#endif //NETDATA_REGISTRY_URL_H
|
|
@ -2,6 +2,35 @@
|
|||
|
||||
#include "web_api.h"
|
||||
|
||||
bool netdata_is_protected_by_bearer = false; // this is controlled by cloud, at the point the agent logs in - this should also be saved to /var/lib/netdata
|
||||
DICTIONARY *netdata_authorized_bearers = NULL;
|
||||
|
||||
static bool web_client_check_acl_and_bearer(struct web_client *w, WEB_CLIENT_ACL endpoint_acl) {
|
||||
if(endpoint_acl == WEB_CLIENT_ACL_NOCHECK)
|
||||
// the endpoint is totally public
|
||||
return true;
|
||||
|
||||
bool acl_allows = w->acl & endpoint_acl;
|
||||
if(!acl_allows)
|
||||
// the channel we received the request from (w->acl) is not compatible with the endpoint
|
||||
return false;
|
||||
|
||||
if(!netdata_is_protected_by_bearer && !(endpoint_acl & WEB_CLIENT_ACL_BEARER_REQUIRED))
|
||||
// bearer protection is not enabled and is not required by the endpoint
|
||||
return true;
|
||||
|
||||
if(!(endpoint_acl & (WEB_CLIENT_ACL_BEARER_REQUIRED|WEB_CLIENT_ACL_BEARER_OPTIONAL)))
|
||||
// endpoint does not require a bearer
|
||||
return true;
|
||||
|
||||
if((w->acl & (WEB_CLIENT_ACL_ACLK|WEB_CLIENT_ACL_WEBRTC)) || api_check_bearer_token(w))
|
||||
// the request is coming from ACLK or WEBRTC (authorized already),
|
||||
// or we have a valid bearer on the request
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int web_client_api_request_vX(RRDHOST *host, struct web_client *w, char *url_path_endpoint, struct web_api_command *api_commands) {
|
||||
if(unlikely(!url_path_endpoint || !*url_path_endpoint)) {
|
||||
buffer_flush(w->response.data);
|
||||
|
@ -13,7 +42,7 @@ int web_client_api_request_vX(RRDHOST *host, struct web_client *w, char *url_pat
|
|||
|
||||
for(int i = 0; api_commands[i].command ; i++) {
|
||||
if(unlikely(hash == api_commands[i].hash && !strcmp(url_path_endpoint, api_commands[i].command))) {
|
||||
if(unlikely(api_commands[i].acl != WEB_CLIENT_ACL_NOCHECK) && !(w->acl & api_commands[i].acl))
|
||||
if(unlikely(!web_client_check_acl_and_bearer(w, api_commands[i].acl)))
|
||||
return web_client_permission_denied(w);
|
||||
|
||||
char *query_string = (char *)buffer_tostring(w->url_query_string_decoded);
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
#include "web/api/health/health_cmdapi.h"
|
||||
#include "web/api/queries/weights.h"
|
||||
|
||||
extern bool netdata_is_protected_by_bearer;
|
||||
extern DICTIONARY *netdata_authorized_bearers;
|
||||
bool api_check_bearer_token(struct web_client *w);
|
||||
bool extract_bearer_token_from_request(struct web_client *w, char *dst, size_t dst_len);
|
||||
|
||||
struct web_api_command {
|
||||
const char *command;
|
||||
uint32_t hash;
|
||||
|
|
|
@ -927,16 +927,17 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *
|
|||
*/
|
||||
}
|
||||
|
||||
char person_guid[GUID_LEN + 1] = "";
|
||||
|
||||
debug(D_WEB_CLIENT, "%llu: API v1 registry with URL '%s'", w->id, url);
|
||||
|
||||
// TODO
|
||||
// The browser may send multiple cookies with our id
|
||||
|
||||
char person_guid[UUID_STR_LEN] = "";
|
||||
char *cookie = strstr(w->response.data->buffer, NETDATA_REGISTRY_COOKIE_NAME "=");
|
||||
if(cookie)
|
||||
strncpyz(person_guid, &cookie[sizeof(NETDATA_REGISTRY_COOKIE_NAME)], 36);
|
||||
strncpyz(person_guid, &cookie[sizeof(NETDATA_REGISTRY_COOKIE_NAME)], UUID_STR_LEN - 1);
|
||||
else if(!extract_bearer_token_from_request(w, person_guid, sizeof(person_guid)))
|
||||
person_guid[0] = '\0';
|
||||
|
||||
char action = '\0';
|
||||
char *machine_guid = NULL,
|
||||
|
@ -1516,12 +1517,6 @@ int web_client_api_request_v1_dbengine_stats(RRDHOST *host __maybe_unused, struc
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef NETDATA_DEV_MODE
|
||||
#define ACL_DEV_OPEN_ACCESS WEB_CLIENT_ACL_DASHBOARD
|
||||
#else
|
||||
#define ACL_DEV_OPEN_ACCESS 0
|
||||
#endif
|
||||
|
||||
static struct web_api_command api_commands_v1[] = {
|
||||
{ "info", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_info },
|
||||
{ "data", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_data },
|
||||
|
@ -1531,7 +1526,7 @@ static struct web_api_command api_commands_v1[] = {
|
|||
{ "contexts", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_contexts },
|
||||
|
||||
// registry checks the ACL by itself, so we allow everything
|
||||
{ "registry", 0, WEB_CLIENT_ACL_NOCHECK, web_client_api_request_v1_registry },
|
||||
{ "registry", 0, WEB_CLIENT_ACL_NOCHECK, web_client_api_request_v1_registry },
|
||||
|
||||
// badges can be fetched with both dashboard and badge permissions
|
||||
{ "badge.svg", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC | WEB_CLIENT_ACL_BADGE, web_client_api_request_v1_badge },
|
||||
|
@ -1545,16 +1540,16 @@ static struct web_api_command api_commands_v1[] = {
|
|||
|
||||
#if defined(ENABLE_ML)
|
||||
{ "ml_info", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_ml_info },
|
||||
{ "ml_models", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_ml_models },
|
||||
// { "ml_models", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_ml_models },
|
||||
#endif
|
||||
|
||||
{ "manage/health", 0, WEB_CLIENT_ACL_MGMT | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_mgmt_health },
|
||||
{"manage/health", 0, WEB_CLIENT_ACL_MGMT | WEB_CLIENT_ACL_ACLK | WEB_CLIENT_ACL_BEARER_REQUIRED, web_client_api_request_v1_mgmt_health },
|
||||
{ "aclk", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_aclk_state },
|
||||
{ "metric_correlations", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_metric_correlations },
|
||||
{ "weights", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_weights },
|
||||
|
||||
{ "function", 0, WEB_CLIENT_ACL_ACLK | ACL_DEV_OPEN_ACCESS, web_client_api_request_v1_function },
|
||||
{ "functions", 0, WEB_CLIENT_ACL_ACLK | ACL_DEV_OPEN_ACCESS, web_client_api_request_v1_functions },
|
||||
{"function", 0, WEB_CLIENT_ACL_ACLK | WEB_CLIENT_ACL_BEARER_REQUIRED | ACL_DEV_OPEN_ACCESS, web_client_api_request_v1_function },
|
||||
{"functions", 0, WEB_CLIENT_ACL_ACLK | WEB_CLIENT_ACL_BEARER_REQUIRED | ACL_DEV_OPEN_ACCESS, web_client_api_request_v1_functions },
|
||||
|
||||
{ "dbengine_stats", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_dbengine_stats },
|
||||
|
||||
|
|
|
@ -3,6 +3,119 @@
|
|||
#include "web_api_v2.h"
|
||||
#include "../rtc/webrtc.h"
|
||||
|
||||
struct bearer_token {
|
||||
time_t created_s;
|
||||
time_t expires_s;
|
||||
};
|
||||
|
||||
static void bearer_get_token(uuid_t *uuid) {
|
||||
static SPINLOCK spinlock = NETDATA_SPINLOCK_INITIALIZER;
|
||||
static bool initialized = false;
|
||||
|
||||
if(!initialized) {
|
||||
spinlock_lock(&spinlock);
|
||||
if (!netdata_authorized_bearers) {
|
||||
netdata_authorized_bearers = dictionary_create_advanced(
|
||||
DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
|
||||
NULL, sizeof(struct bearer_token));
|
||||
}
|
||||
spinlock_unlock(&spinlock);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
char uuid_str[UUID_STR_LEN];
|
||||
|
||||
uuid_generate_random(*uuid);
|
||||
uuid_unparse_lower(*uuid, uuid_str);
|
||||
|
||||
struct bearer_token t = { 0 }, *z;
|
||||
z = dictionary_set(netdata_authorized_bearers, uuid_str, &t, sizeof(t));
|
||||
if(!z->created_s) {
|
||||
z->created_s = now_monotonic_sec();
|
||||
z->expires_s = z->created_s + 86400;
|
||||
}
|
||||
}
|
||||
|
||||
#define HTTP_REQUEST_AUTHORIZATION_BEARER "\r\nAuthorization: Bearer "
|
||||
|
||||
bool extract_bearer_token_from_request(struct web_client *w, char *dst, size_t dst_len) {
|
||||
const char *req = buffer_tostring(w->response.data);
|
||||
size_t req_len = buffer_strlen(w->response.data);
|
||||
const char *bearer = strcasestr(req, HTTP_REQUEST_AUTHORIZATION_BEARER);
|
||||
|
||||
if(!bearer)
|
||||
return false;
|
||||
|
||||
const char *token_start = bearer + sizeof(HTTP_REQUEST_AUTHORIZATION_BEARER) - 1;
|
||||
|
||||
while(isspace(*token_start))
|
||||
token_start++;
|
||||
|
||||
const char *token_end = token_start + UUID_STR_LEN - 1 + 2;
|
||||
if (token_end > req + req_len)
|
||||
return false;
|
||||
|
||||
strncpyz(dst, token_start, dst_len - 1);
|
||||
uuid_t uuid;
|
||||
if (uuid_parse(dst, uuid) != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool api_check_bearer_token(struct web_client *w) {
|
||||
if(!netdata_authorized_bearers)
|
||||
return false;
|
||||
|
||||
char token[UUID_STR_LEN];
|
||||
if(!extract_bearer_token_from_request(w, token, sizeof(token)))
|
||||
return false;
|
||||
|
||||
struct bearer_token *z = dictionary_get(netdata_authorized_bearers, token);
|
||||
return z && z->expires_s > now_monotonic_sec();
|
||||
}
|
||||
|
||||
int api_v2_bearer_protection(RRDHOST *host __maybe_unused, struct web_client *w __maybe_unused, char *url) {
|
||||
while (url) {
|
||||
char *value = strsep_skip_consecutive_separators(&url, "&");
|
||||
if (!value || !*value) continue;
|
||||
|
||||
char *name = strsep_skip_consecutive_separators(&value, "=");
|
||||
if (!name || !*name) continue;
|
||||
if (!value || !*value) continue;
|
||||
|
||||
if(!strcmp(name, "bearer_protection")) {
|
||||
if(!strcmp(value, "on") || !strcmp(value, "true") || !strcmp(value, "yes"))
|
||||
netdata_is_protected_by_bearer = true;
|
||||
else
|
||||
netdata_is_protected_by_bearer = false;
|
||||
}
|
||||
}
|
||||
|
||||
BUFFER *wb = w->response.data;
|
||||
buffer_flush(wb);
|
||||
buffer_json_initialize(wb, "\"", "\"", 0, true, false);
|
||||
buffer_json_member_add_boolean(wb, "bearer_protection", netdata_is_protected_by_bearer);
|
||||
buffer_json_finalize(wb);
|
||||
|
||||
return HTTP_RESP_OK;
|
||||
}
|
||||
|
||||
int api_v2_bearer_token(RRDHOST *host __maybe_unused, struct web_client *w __maybe_unused, char *url __maybe_unused) {
|
||||
uuid_t uuid;
|
||||
bearer_get_token(&uuid);
|
||||
|
||||
BUFFER *wb = w->response.data;
|
||||
buffer_flush(wb);
|
||||
buffer_json_initialize(wb, "\"", "\"", 0, true, false);
|
||||
buffer_json_member_add_string(wb, "mg", localhost->machine_guid);
|
||||
buffer_json_member_add_boolean(wb, "bearer_protection", netdata_is_protected_by_bearer);
|
||||
buffer_json_member_add_uuid(wb, "token", &uuid);
|
||||
buffer_json_finalize(wb);
|
||||
|
||||
return HTTP_RESP_OK;
|
||||
}
|
||||
|
||||
static int web_client_api_request_v2_contexts_internal(RRDHOST *host __maybe_unused, struct web_client *w, char *url, CONTEXTS_V2_MODE mode) {
|
||||
struct api_v2_contexts_request req = { 0 };
|
||||
|
||||
|
@ -441,24 +554,30 @@ static int web_client_api_request_v2_webrtc(RRDHOST *host __maybe_unused, struct
|
|||
}
|
||||
|
||||
static struct web_api_command api_commands_v2[] = {
|
||||
{"data", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_data},
|
||||
{"info", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_info},
|
||||
{"nodes", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_nodes},
|
||||
{"node_instances", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_node_instances},
|
||||
{"contexts", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_contexts},
|
||||
{"weights", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_weights},
|
||||
{"versions", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_versions},
|
||||
{"functions", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_functions},
|
||||
{"alerts", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_alerts},
|
||||
{"alert_transitions", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_alert_transitions},
|
||||
{"alert_config", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_alert_config},
|
||||
{"claim", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_claim},
|
||||
{"q", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_q},
|
||||
{"info", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_info},
|
||||
|
||||
{"rtc_offer", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v2_webrtc},
|
||||
{"data", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_data},
|
||||
{"weights", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_weights},
|
||||
|
||||
{"contexts", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_contexts},
|
||||
{"nodes", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_nodes},
|
||||
{"node_instances", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_node_instances},
|
||||
{"versions", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_versions},
|
||||
{"functions", 0, WEB_CLIENT_ACL_ACLK | WEB_CLIENT_ACL_BEARER_REQUIRED | ACL_DEV_OPEN_ACCESS, web_client_api_request_v2_functions},
|
||||
{"q", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_q},
|
||||
{"alerts", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_alerts},
|
||||
|
||||
{"alert_transitions", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_alert_transitions},
|
||||
{"alert_config", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_alert_config},
|
||||
|
||||
{"claim", 0, WEB_CLIENT_ACL_NOCHECK, web_client_api_request_v2_claim},
|
||||
|
||||
{"rtc_offer", 0, WEB_CLIENT_ACL_ACLK | ACL_DEV_OPEN_ACCESS, web_client_api_request_v2_webrtc},
|
||||
{"bearer_protection", 0, WEB_CLIENT_ACL_ACLK | ACL_DEV_OPEN_ACCESS, api_v2_bearer_protection},
|
||||
{"bearer_get_token", 0, WEB_CLIENT_ACL_ACLK | ACL_DEV_OPEN_ACCESS, api_v2_bearer_token},
|
||||
|
||||
// terminator
|
||||
{NULL, 0, WEB_CLIENT_ACL_NONE, NULL},
|
||||
{NULL, 0, WEB_CLIENT_ACL_NONE, NULL},
|
||||
};
|
||||
|
||||
inline int web_client_api_request_v2(RRDHOST *host, struct web_client *w, char *url_path_endpoint) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue