static service_info_t * _find_matching_rawx(GSList *rawx, GSList *used_loc, gint64 distance, const gchar *stg_class, GSList **rawx_garbage) { GRID_DEBUG("Searching rawx distant of %"G_GINT64_FORMAT " with storage class '%s'", distance, stg_class); GSList *l = NULL; gchar loc[1024]; struct service_tag_s * loc_tag = NULL; GRID_DEBUG("Checking for an available rawx in a list of %d elements", g_slist_length(rawx)); for (l = rawx; l && l->data; l = l->next) { GRID_DEBUG("Checking one rawx..."); /* ensure service score */ if(((service_info_t*)l->data)->score.value <= 0) { GRID_DEBUG("Rawx score <= 0"); continue; } /* ensure not spotted as unreachable */ if(_is_rawx_in_garbage((service_info_t*)l->data, *rawx_garbage)) { GRID_DEBUG("Rawx already in unreachable list"); continue; } /* check rawx reachable */ if(!is_rawx_reachable((service_info_t*)l->data)) { GRID_DEBUG("Rawx unreachable"); *rawx_garbage = g_slist_prepend(*rawx_garbage, l->data); continue; } /* check rawx has appropriate storage class (strictly) */ if (!service_info_check_storage_class(l->data, stg_class)) { GRID_DEBUG(MSG_DONT_MATCH_CRITERIA, "storage class"); continue; } /* ensure distance match with our policy */ bzero(loc, sizeof(loc)); loc_tag = service_info_get_tag(((service_info_t*)l->data)->tags, NAME_TAGNAME_RAWX_LOC); GRID_DEBUG("service tag extracted"); if(!loc_tag) { if(distance > 1) { continue; } return ((service_info_t*)l->data); } service_tag_get_value_string(loc_tag, loc, sizeof(loc), NULL); if(__test_location(loc, used_loc, distance)) { return ((service_info_t*)l->data); } else { GRID_DEBUG(MSG_DONT_MATCH_CRITERIA, "distance"); } } return NULL; }
const gchar * service_info_get_tag_value(const struct service_info_s *si, const gchar *name, const gchar *def) { struct service_tag_s *tag; if (!si || !si->tags) return def; if (!(tag = service_info_get_tag(si->tags, name))) return def; if (tag->type == STVT_STR) return tag->value.s; if (tag->type == STVT_BUF) return tag->value.buf; return def; }
struct service_tag_s * service_info_ensure_tag(GPtrArray * a, const gchar * name) { struct service_tag_s *srvtag; if (!a || !name) return NULL; srvtag = service_info_get_tag(a, name); if (!srvtag) { srvtag = g_malloc0(sizeof(struct service_tag_s)); g_strlcpy(srvtag->name, name, sizeof(srvtag->name)); g_ptr_array_add(a, srvtag); srvtag->type = STVT_BOOL; srvtag->value.b = FALSE; } return srvtag; }
/** * @return TRUE if "agent_check" tag is missing or is true, * false otherwise */ static gboolean _agent_check_enabled(struct service_info_s *si) { if (!si) return FALSE; gboolean srv_check_enabled = TRUE; service_tag_t *tag = service_info_get_tag(si->tags, NAME_TAGNAME_AGENT_CHECK); if (tag) { GError *err = NULL; if (tag->type == STVT_BOOL) { service_tag_get_value_boolean(tag, &srv_check_enabled, &err); } else { gchar buf[64] = {0}; service_tag_get_value_string(tag, buf, sizeof(buf), &err); srv_check_enabled = metautils_cfg_get_bool(buf, TRUE); } g_clear_error(&err); } return srv_check_enabled; }
gboolean fill_scanning_info_for_chunk_checker(struct volume_scanning_info_s *scanning_info, service_info_t * service_info, struct integrity_loop_config_s *config, GError ** error) { gchar volume_path[LIMIT_LENGTH_VOLUMENAME]; struct chunk_checker_data_s cc_data; struct service_tag_s *tag = NULL; CHECK_ARG_POINTER(scanning_info, error); CHECK_ARG_POINTER(service_info, error); CHECK_ARG_POINTER(config, error); bzero(volume_path, sizeof(volume_path)); bzero(scanning_info, sizeof(*scanning_info)); bzero(&cc_data, sizeof(cc_data)); tag = service_info_get_tag(service_info->tags, NAME_TAGNAME_RAWX_VOL); if (tag == NULL) { GSETERROR(error, "Failed to retrieve tag [%s]", NAME_TAGNAME_RAWX_VOL); return FALSE; } /* Fill volume_path */ if (!service_tag_get_value_string(tag, volume_path, sizeof(volume_path), error)) { GSETERROR(error, "Failed to extract string value from tag [%s]", NAME_TAGNAME_RAWX_VOL); return FALSE; } /* Fill callback and callback data */ scanning_info->volume_path = g_strdup(volume_path); scanning_info->file_action = check_chunk_and_sleep; scanning_info->dir_exit = sleep_after_directory; cc_data.volume_path = g_strdup(volume_path); cc_data.sleep_time = config->chunk_checker_sleep_time; cc_data.si = service_info_dup(service_info); scanning_info->callback_data = g_memdup(&cc_data, sizeof(cc_data)); return TRUE; }
static gboolean _filter_tag(struct service_info_s *si, gpointer u) { struct compound_type_s *ct = u; EXTRA_ASSERT(ct != NULL); if (!ct->req.k) return TRUE; struct service_tag_s *tag = service_info_get_tag(si->tags, ct->req.k); if (NULL == tag) return FALSE; switch (tag->type) { case STVT_BUF: return !fnmatch(ct->req.v, tag->value.buf, 0); case STVT_STR: return !fnmatch(ct->req.v, tag->value.s, 0); default: return FALSE; } }
static void _extract_location(gpointer data, gpointer udata) { GRID_DEBUG("extracting services locations"); struct service_tag_s * loc_tag = NULL; gchar loc[1024]; GSList **used_loc = (GSList **) udata; bzero(loc, sizeof(loc)); if(data) loc_tag = service_info_get_tag(((service_info_t*)data)->tags, NAME_TAGNAME_RAWX_LOC); GRID_DEBUG("service tag extracted"); if(!loc_tag) return; service_tag_get_value_string(loc_tag, loc, sizeof(loc), NULL); if(strlen(loc) > 0) *used_loc = g_slist_prepend(*used_loc, g_strdup(loc)); }
static void allservice_check_start_HT(struct namespace_data_s *ns_data, GHashTable *ht) { gsize offset; struct taskdata_checksrv_s td_scheme; GHashTableIter iter_serv; gpointer k, v; g_hash_table_iter_init(&iter_serv, ht); while (g_hash_table_iter_next(&iter_serv, &k, &v)) { struct service_info_s *si = v; gboolean srv_check_enabled = TRUE; /* Services can disable TCP checks (enabled by default) */ service_tag_t *tag = service_info_get_tag(si->tags, NAME_TAGNAME_AGENT_CHECK); if (tag) { GError *err = NULL; if (tag->type == STVT_BOOL) { service_tag_get_value_boolean(tag, &srv_check_enabled, &err); } else { gchar buf[64] = {0}; service_tag_get_value_string(tag, buf, sizeof(buf), &err); srv_check_enabled = metautils_cfg_get_bool(buf, TRUE); } g_clear_error(&err); } memset(&td_scheme, 0x00, sizeof(td_scheme)); offset = g_snprintf(td_scheme.task_name, sizeof(td_scheme.task_name), "%s.", TASK_ID); addr_info_to_string(&(si->addr), td_scheme.task_name+offset, sizeof(td_scheme.task_name)-offset); g_strlcpy(td_scheme.ns_name, ns_data->name, sizeof(td_scheme.ns_name)-1); if (!srv_check_enabled) { GRID_DEBUG("Task [%s] disabled by " NAME_TAGNAME_AGENT_CHECK, td_scheme.task_name); } else if (!is_task_scheduled(td_scheme.task_name)) { GError *error_local = NULL; task_t *task = NULL; struct taskdata_checksrv_s *task_data; agent_get_service_key(si, td_scheme.srv_key, sizeof(td_scheme.srv_key)); g_strlcpy(td_scheme.srv_key, (gchar*)k, sizeof(td_scheme.srv_key)-1); /* prepare the task structure */ task_data = g_memdup(&td_scheme, sizeof(td_scheme)); if (!task_data) { ERROR("Memory allocation failure"); continue; } task = create_task(period_check_services, td_scheme.task_name); task = set_task_callbacks(task, _check_tcp_service_task, g_free, task_data); if (!task) { ERROR("Memory allocation failure"); continue; } /* now start the task! */ if (add_task_to_schedule(task, &error_local)) INFO("Task started: %s", td_scheme.task_name); else { ERROR("Failed to add task to scheduler [%s] : %s", td_scheme.task_name, gerror_get_message(error_local)); g_free(task); } if (error_local) g_clear_error(&error_local); } } }
struct conscience_srv_s * conscience_srvtype_refresh(struct conscience_srvtype_s *srvtype, struct service_info_s *si) { g_assert_nonnull (srvtype); g_assert_nonnull (si); struct conscience_srvid_s srvid; memcpy(&(srvid.addr), &(si->addr), sizeof(addr_info_t)); struct service_tag_s *tag_first = service_info_get_tag(si->tags, NAME_TAGNAME_RAWX_FIRST); gboolean really_first = FALSE; /*register the service if necessary */ struct conscience_srv_s *p_srv = conscience_srvtype_get_srv(srvtype, &srvid); if (!p_srv) { p_srv = conscience_srvtype_register_srv(srvtype, NULL, &srvid); g_assert_nonnull (p_srv); really_first = tag_first && tag_first->type == STVT_BOOL && tag_first->value.b; } /* refresh the tags: create missing, replace existing * (but the tags are not flushed before) */ if (si->tags) { TRACE("Refreshing tags for srv [%.*s]", (int)(LIMIT_LENGTH_SRVDESCR), p_srv->description); const guint max = si->tags->len; for (guint i = 0; i < max; i++) { struct service_tag_s *tag = g_ptr_array_index(si->tags, i); if (tag == tag_first) continue; struct service_tag_s *orig = conscience_srv_ensure_tag(p_srv, tag->name); service_tag_copy(orig, tag); } } p_srv->score.timestamp = oio_ext_monotonic_seconds (); if (si->score.value == SCORE_UNSET || si->score.value == SCORE_UNLOCK) { if (really_first) { GRID_TRACE2("SRV first [%s]", p_srv->description); p_srv->score.value = 0; p_srv->locked = TRUE; } else { if (si->score.value == SCORE_UNLOCK) { if (p_srv->locked) { GRID_TRACE2("SRV unlocked [%s]", p_srv->description); p_srv->locked = FALSE; p_srv->score.value = CLAMP (p_srv->score.value, SCORE_DOWN, SCORE_MAX); } else { GRID_TRACE2("SRV already unlocked [%s]", p_srv->description); } } else { /* UNSET, a.k.a. regular computation */ if (p_srv->locked) { GRID_TRACE2("SRV untouched [%s]", p_srv->description); } else { GError *err = NULL; if (!conscience_srv_compute_score(p_srv, &err)) { GRID_TRACE2("SRV error [%s]: (%d) %s", p_srv->description, err->code, err->message); g_clear_error (&err); } else { GRID_TRACE2("SRV refreshed [%s]", p_srv->description); } } } } } else { /* LOCK */ p_srv->score.value = CLAMP(si->score.value, SCORE_DOWN, SCORE_MAX); if (p_srv->locked) { GRID_TRACE2("SRV already locked [%s]", p_srv->description); } else { p_srv->locked = TRUE; GRID_TRACE2("SRV locked [%s]", p_srv->description); } } return p_srv; }
struct service_tag_s * conscience_srv_get_tag(struct conscience_srv_s *service, const gchar * name) { return service ? service_info_get_tag(service->tags,name) : NULL; }
static gboolean manage_service(struct service_info_s *si) { GError *error_local; struct service_info_s *old_si = NULL; struct service_tag_s *tag_first = NULL; struct namespace_data_s *ns_data; gsize key_size; gchar key[LIMIT_LENGTH_SRVTYPE + STRLEN_ADDRINFO], str_addr[STRLEN_ADDRINFO]; if (!si) { ERROR("Invalid parameter"); return FALSE; } key_size = agent_get_service_key(si, key, sizeof(key)); grid_addrinfo_to_string(&(si->addr), str_addr, sizeof(str_addr)); /*this service must refer to known namespace and service type*/ error_local = NULL; if (!(ns_data = get_namespace(si->ns_name, &error_local))) { ERROR("Namespace unavailable for service [ns=%s type=%s addr=%s] : %s", si->ns_name, si->type, str_addr, gerror_get_message(error_local)); if (error_local) g_error_free(error_local); return FALSE; } /*Info trace when a service of a new type is used */ if (error_local) g_error_free(error_local); if (!conscience_get_srvtype(ns_data->conscience, &error_local, si->type, MODE_STRICT)) { /*to avoid traces flooding, if the service already exists, no trace is sent */ if (!g_hash_table_lookup(ns_data->local_services, key) && !g_hash_table_lookup(ns_data->down_services, key)) { INFO("New service type discovered [ns=%s type=%s addr=%s]", ns_data->name, si->type, str_addr); } } /*replace MACRO tags by their true values */ if (error_local) g_clear_error(&error_local); metautils_srvinfo_ensure_tags (si); si->score.value = SCORE_UNSET; si->score.timestamp = oio_ext_real_time() / G_TIME_SPAN_SECOND; /*then keep the score */ g_hash_table_remove(ns_data->down_services, key); /* save first lauched tag if still in old si */ old_si = g_hash_table_lookup(ns_data->local_services, key); if (old_si != NULL) { tag_first = service_info_get_tag(old_si->tags, NAME_TAGNAME_RAWX_FIRST); if (tag_first != NULL) service_tag_set_value_boolean(service_info_ensure_tag(si->tags, NAME_TAGNAME_RAWX_FIRST), tag_first->value.b); } service_tag_set_value_boolean(service_info_ensure_tag(si->tags, "tag.up"), TRUE); g_hash_table_insert(ns_data->local_services, g_strndup(key, key_size), si); DEBUG("Service registration [ns=%s type=%s addr=%s]", ns_data->name, si->type, str_addr); if (error_local) g_error_free(error_local); return TRUE; }
static enum http_rc_e _registration (struct req_args_s *args, enum reg_op_e op, struct json_object *jsrv) { GError *err; if (!jsrv || !json_object_is_type (jsrv, json_type_object)) return _reply_common_error (args, BADREQ("Expected: json object")); if (!push_queue) return _reply_bad_gateway(args, SYSERR("Service upstream disabled")); if (NULL != (err = _cs_check_tokens(args))) return _reply_notfound_error (args, err); struct service_info_s *si = NULL; err = service_info_load_json_object (jsrv, &si, TRUE); if (err) { g_prefix_error (&err, "JSON error: "); if (err->code == CODE_BAD_REQUEST) return _reply_format_error (args, err); else return _reply_system_error (args, err); } if (!si->type[0] && !service_info_get_tag(si->tags, "tag.id")) { service_info_clean (si); return _reply_format_error (args, BADREQ("Service type not specified")); } if (!si->ns_name[0]) { GRID_TRACE2("%s NS forced to %s", __FUNCTION__, si->ns_name); g_strlcpy (si->ns_name, ns_name, sizeof(si->ns_name)); } else if (!validate_namespace (si->ns_name)) { service_info_clean (si); return _reply_format_error (args, BADNS()); } gchar *k = service_info_key (si); STRING_STACKIFY(k); GRID_TRACE2("%s op=%s score=%d key=[%s]", __FUNCTION__, _regop_2str(op), si->score.value, k); switch (op) { case REGOP_PUSH: si->score.value = SCORE_UNSET; if (!service_is_known (k)) { service_learn (k); service_tag_set_value_boolean (service_info_ensure_tag ( si->tags, NAME_TAGNAME_RAWX_FIRST), TRUE); } break; case REGOP_LOCK: si->score.value = CLAMP(si->score.value, SCORE_DOWN, SCORE_MAX); break; case REGOP_UNLOCK: si->score.value = SCORE_UNLOCK; break; default: g_assert_not_reached(); } if (ttl_expire_local_services > 0 && op != REGOP_UNLOCK) { struct service_info_s *v = service_info_dup (si); v->score.timestamp = oio_ext_monotonic_seconds (); REG_WRITE( const struct service_info_s *si0 = lru_tree_get(srv_registered, k); if (si0) v->score.value = si0->score.value; lru_tree_insert (srv_registered, g_strdup(k), v); ); }