Example #1
0
// TODO: factorize the two following functions
enum http_rc_e
action_admin_meta0_list(struct req_args_s *args)
{
	GError *err = NULL;
	GSList *m0_lst = NULL;
	GSList *m1_lst = NULL;
	GString *json = NULL;

	err = conscience_get_services(NS(), NAME_SRVTYPE_META0, FALSE, &m0_lst);
	if (!err) {
		for (GSList *l = m0_lst; l; l = l->next) {
			g_clear_error(&err);
			service_info_t *m0 = l->data;
			gchar m0_url[STRLEN_ADDRINFO] = {0};
			grid_addrinfo_to_string(&(m0->addr), m0_url, sizeof(m0_url));

			err = meta0_remote_get_meta1_all(m0_url, &m1_lst);

			if (!err || !CODE_IS_NETWORK_ERROR(err->code))
				break;
		}
		g_slist_free_full(m0_lst, (GDestroyNotify)service_info_clean);
	}

	if (m1_lst) {
		json = _m0_mapping_from_m1_list(m1_lst);
		meta0_utils_list_clean(m1_lst);
		return _reply_json(args, HTTP_CODE_OK, "OK", json);
	}
	return _reply_common_error(args, err);
}
Example #2
0
enum http_rc_e
action_admin_meta0_force(struct req_args_s *args)
{
	GError *err = NULL;
	GSList *m0_lst = NULL;

	err = conscience_get_services(NS(), NAME_SRVTYPE_META0, FALSE, &m0_lst);
	if (!err) {
		for (GSList *l = m0_lst; l; l = l->next) {
			g_clear_error(&err);
			service_info_t *m0 = l->data;
			gchar m0_url[STRLEN_ADDRINFO] = {0};
			grid_addrinfo_to_string(&(m0->addr), m0_url, sizeof(m0_url));

			err = meta0_remote_force(m0_url, (gchar*) args->rq->body->data);

			if (!err) {
				err = meta0_remote_cache_refresh(m0_url);
				break;
			} else if (!CODE_IS_NETWORK_ERROR(err->code)) {
				break;
			}
		}
		g_slist_free_full(m0_lst, (GDestroyNotify)service_info_clean);
	}
	if (err)
		return _reply_common_error(args, err);
	return _reply_nocontent(args);
}
Example #3
0
enum http_rc_e
action_dir_srv_renew (struct req_args_s *args, struct json_object *jargs)
{
	(void) jargs;
	const gchar *type = TYPE();
	if (!type)
		return _reply_format_error (args, NEWERROR(CODE_BAD_REQUEST, "No service type provided"));
	gboolean autocreate = _request_has_flag (args, PROXYD_HEADER_MODE, "autocreate");
	gboolean dryrun = _request_has_flag (args, PROXYD_HEADER_MODE, "dryrun");

	gchar **urlv = NULL;
	GError *hook (const gchar * m1) {
		struct addr_info_s m1a;
		if (!grid_string_to_addrinfo (m1, NULL, &m1a))
			return NEWERROR (CODE_NETWORK_ERROR, "Invalid M1 address");
		GError *err = NULL;
		urlv = meta1v2_remote_poll_reference_service (&m1a, &err, args->url, type, dryrun, autocreate);
		return err;
	}

	GError *err = _m1_locate_and_action (args, hook);

	if (!err || CODE_IS_NETWORK_ERROR(err->code)) {
		/* Also decache on timeout, a majority of request succeed,
         * and it will probably silently succeed  */
		hc_decache_reference_service (resolver, args->url, type);
	}

	if (err)
		return _reply_common_error (args, err);
	EXTRA_ASSERT (urlv != NULL);
	return _reply_success_json (args, _pack_and_freev_m1url_list (NULL, urlv));
}
Example #4
0
enum http_rc_e
action_forward_stats (struct req_args_s *args)
{
	const char *id = OPT("id");
	if (!id)
		return _reply_format_error (args, BADREQ("Missing SRVID"));

	args->rp->no_access();
	MESSAGE req = metautils_message_create_named("REQ_STATS");
	GByteArray *encoded = message_marshall_gba_and_clean (req);
	gchar *packed = NULL;
	GError *err = gridd_client_exec_and_concat_string (id, 1.0, encoded, &packed);
	if (err) {
		g_free0 (packed);
		if (CODE_IS_NETWORK_ERROR(err->code)) {
			if (err->code == ERRCODE_CONN_TIMEOUT || err->code == ERRCODE_READ_TIMEOUT)
				return _reply_gateway_timeout (args, err);
			return _reply_srv_unavailable (args, err);
		}
		return _reply_common_error (args, err);
	}

	for (gchar *s=packed; *s ;++s) { if (*s == '=') *s = ' '; }

	/* TODO(jfs): quite duplicated from _reply_json() but the original
	   was not suitable. */
	args->rp->set_status (200, "OK");
	args->rp->set_body_bytes (g_bytes_new_take((guint8*)packed, strlen(packed)));
	args->rp->finalize ();
	return HTTPRC_DONE;
}
Example #5
0
enum http_rc_e
action_dir_srv_unlink (struct req_args_s *args)
{
	const gchar *type = TYPE();
	if (!type)
		return _reply_format_error (args, NEWERROR( CODE_BAD_REQUEST, "No service type provided"));

	GError *hook (const gchar * m1) {
		struct addr_info_s m1a;
		if (!grid_string_to_addrinfo (m1, NULL, &m1a))
			return NEWERROR (CODE_NETWORK_ERROR, "Invalid M1 address");
		GError *err = NULL;
		meta1v2_remote_unlink_service (&m1a, &err, args->url, type);
		return err;
	}

	GError *err = _m1_locate_and_action (args, hook);

	if (!err || CODE_IS_NETWORK_ERROR(err->code)) {
		/* Also decache on timeout, a majority of request succeed,
         * and it will probably silently succeed  */
		hc_decache_reference_service (resolver, args->url, type);
	}

	if (!err)
		return _reply_success_json (args, NULL);
	return _reply_common_error (args, err);
}
Example #6
0
static enum http_rc_e
_reply_m2_error (struct req_args_s *args, GError * err)
{
	if (!err)
		return _reply_success_json (args, NULL);
	g_prefix_error (&err, "M2 error: ");
	if (err->code == CODE_CONTAINER_NOTEMPTY)
		return _reply_conflict_error (args, err);
	return _reply_common_error (args, err);
}
Example #7
0
enum http_rc_e
action_dir_srv_force (struct req_args_s *args, struct json_object *jargs)
{
	struct meta1_service_url_s *m1u = NULL;
	const gchar *type = TYPE();
	if (!type)
		return _reply_format_error (args, NEWERROR(CODE_BAD_REQUEST, "No service type provided"));

	gboolean force = _request_has_flag (args, PROXYD_HEADER_MODE, "replace");
	gboolean autocreate = _request_has_flag (args, PROXYD_HEADER_MODE, "autocreate");

	GError *hook (const gchar * m1) {
		struct addr_info_s m1a;
		if (!grid_string_to_addrinfo (m1, NULL, &m1a))
			return NEWERROR (CODE_NETWORK_ERROR, "Invalid M1 address");
		GError *e = NULL;
		gchar *packed = meta1_pack_url (m1u);
		meta1v2_remote_force_reference_service (&m1a, &e, args->url, packed, autocreate, force);
		g_free (packed);
		return e;
	}

	GError *err = meta1_service_url_load_json_object (jargs, &m1u);

	if (!err)
		err = _m1_locate_and_action (args, hook);
	if (m1u) {
		meta1_service_url_clean (m1u);
		m1u = NULL;
	}

	if (!err || CODE_IS_NETWORK_ERROR(err->code)) {
		/* Also decache on timeout, a majority of request succeed,
         * and it will probably silently succeed  */
		hc_decache_reference_service (resolver, args->url, type);
	}

	if (err)
		return _reply_common_error (args, err);
	return _reply_success_json (args, NULL);
}
Example #8
0
enum http_rc_e
action_dir_srv_list (struct req_args_s *args)
{
	const gchar *type = TYPE();
	if (!type)
		return _reply_format_error (args, NEWERROR( CODE_BAD_REQUEST, "No service type provided"));

	gchar **urlv = NULL;
	GError *err = hc_resolve_reference_service (resolver, args->url, type, &urlv);
	EXTRA_ASSERT ((err != NULL) ^ (urlv != NULL));

	if (!err) {

		if ((args->flags & FLAG_NOEMPTY) && !*urlv) {
			g_strfreev (urlv);
			urlv = NULL;
			return _reply_notfound_error (args, NEWERROR (CODE_NOT_FOUND, "No service linked"));
		}
		return _reply_success_json (args, _pack_and_freev_m1url_list (NULL, urlv));
	}

	return _reply_common_error (args, err);
}
Example #9
0
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, NEWERROR(CODE_INTERNAL_ERROR,
        "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) {
        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_clean (si);
        return _reply_format_error (args, BADREQ("Service type not specified"));
    }

    if (!si->ns_name[0]) {
        g_strlcpy (si->ns_name, nsname, sizeof(si->ns_name));
    } else if (!validate_namespace (si->ns_name)) {
        service_info_clean (si);
        return _reply_format_error (args, NEWERROR (CODE_NAMESPACE_NOTMANAGED,
        "Unexpected NS"));
    }

    si->score.timestamp = oio_ext_real_time () / G_TIME_SPAN_SECOND;

    if (op == REGOP_PUSH)
        si->score.value = SCORE_UNSET;
    else if (op == REGOP_UNLOCK)
        si->score.value = SCORE_UNLOCK;
    else /* if (op == REGOP_LOCK) */
        si->score.value = CLAMP(si->score.value, SCORE_DOWN, SCORE_MAX);

    // TODO follow the DRY principle and factorize this!
    if (flag_cache_enabled) {
        GString *gstr = g_string_new ("");
        service_info_encode_json (gstr, si, TRUE);
        PUSH_DO(lru_tree_insert(push_queue, service_info_key(si), si));
        return _reply_success_json (args, gstr);
    } else {
        CSURL(cs);
        GSList l = {.data = si, .next = NULL};
        if (NULL != (err = conscience_remote_push_services (cs, &l))) {
            service_info_clean (si);
            return _reply_common_error (args, err);
        } else {
            GString *gstr = g_string_new ("");
            service_info_encode_json (gstr, si, TRUE);
            service_info_clean (si);
            return _reply_success_json (args, gstr);
        }
    }
}
Example #10
0
enum http_rc_e
action_forward (struct req_args_s *args)
{
	const char *id = OPT("id");
	const char *action = TOK("ACTION");

	if (!id)
		return _reply_format_error (args, BADREQ("Missing SRVID"));
	if (!action)
		return _reply_format_error (args, BADREQ("Missing action"));

	GError *err = NULL;
	if (!g_ascii_strcasecmp (action, "flush")) {
		err = sqlx_remote_execute_FLUSH (id);
		if (!err)
			return _reply_success_json (args, NULL);
		return _reply_common_error (args, err);
	}
	if (!g_ascii_strcasecmp (action, "reload")) {
		err = sqlx_remote_execute_RELOAD (id);
		if (!err)
			return _reply_success_json (args, NULL);
		return _reply_common_error (args, err);
	}
	if (!g_ascii_strcasecmp (action, "kill")) {
		GByteArray *encoded = message_marshall_gba_and_clean (
				metautils_message_create_named("REQ_KILL"));
		err = gridd_client_exec (id, 1.0, encoded);
		if (err)
			return _reply_common_error (args, err);
		return _reply_success_json (args, NULL);
	}
	if (!g_ascii_strcasecmp (action, "ping")) {
		args->rp->no_access();
		GByteArray *encoded = message_marshall_gba_and_clean (
				metautils_message_create_named("REQ_PING"));
		err = gridd_client_exec (id, 1.0, encoded);
		if (err)
			return _reply_common_error (args, err);
		return _reply_success_json (args, NULL);
	}
	if (!g_ascii_strcasecmp (action, "lean-glib")) {
		MESSAGE req = metautils_message_create_named("REQ_LEAN");
		metautils_message_add_field_str(req, "LIBC", "1");
		metautils_message_add_field_str(req, "THREADS", "1");
		GByteArray *encoded = message_marshall_gba_and_clean (req);
		err = gridd_client_exec (id, 1.0, encoded);
		if (err)
			return _reply_common_error (args, err);
		return _reply_success_json (args, NULL);
	}

	if (!g_ascii_strcasecmp (action, "lean-sqlx")) {
		GByteArray *encoded = message_marshall_gba_and_clean (
				metautils_message_create_named(NAME_MSGNAME_SQLX_LEANIFY));
		err = gridd_client_exec (id, 1.0, encoded);
		if (err)
			return _reply_common_error (args, err);
		return _reply_success_json (args, NULL);
	}

	if (!g_ascii_strcasecmp (action, "version")) {
		args->rp->no_access();
		MESSAGE req = metautils_message_create_named("REQ_VERSION");
		GByteArray *encoded = message_marshall_gba_and_clean (req);
		gchar *packed = NULL;
		err = gridd_client_exec_and_concat_string (id, 1.0, encoded, &packed);
		if (err) {
			g_free0 (packed);
			return _reply_common_error (args, err);
		}

		/* TODO(jfs): quite duplicated from _reply_json() but the original
		   was not suitable. */
		args->rp->set_status (200, "OK");
		args->rp->set_body_bytes (g_bytes_new_take((guint8*)packed, strlen(packed)));
		args->rp->finalize ();
		return HTTPRC_DONE;
	}

	if (!g_ascii_strcasecmp (action, "handlers")) {
		args->rp->no_access();
		MESSAGE req = metautils_message_create_named("REQ_HANDLERS");
		GByteArray *encoded = message_marshall_gba_and_clean (req);
		gchar *packed = NULL;
		err = gridd_client_exec_and_concat_string (id, 1.0, encoded, &packed);
		if (err) {
			g_free0 (packed);
			return _reply_common_error (args, err);
		}

		/* TODO(jfs): quite duplicated from _reply_json() but the original
		   was not suitable. */
		args->rp->set_status (200, "OK");
		args->rp->set_body_bytes (g_bytes_new_take((guint8*)packed, strlen(packed)));
		args->rp->finalize ();
		return HTTPRC_DONE;
	}

	return _reply_common_error (args, BADREQ("unexpected action"));
}
Example #11
0
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_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, nsname, 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 (cs_expire_local_services > 0) {
		struct service_info_s *v = service_info_dup (si);
		v->score.timestamp = oio_ext_monotonic_seconds ();
		PUSH_DO(
			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);
		);
	}