Esempio n. 1
0
static GError *
_m1_action (struct req_args_s *args, gchar ** m1v,
	GError * (*hook) (const gchar * m1))
{
	for (gchar ** pm1 = m1v; *pm1; ++pm1) {
		struct meta1_service_url_s *m1 = meta1_unpack_url (*pm1);
		if (!m1)
			continue;
		if (0 != g_ascii_strcasecmp(m1->srvtype, "meta1")) {
			meta1_service_url_clean (m1);
			continue;
		}

		struct addr_info_s m1a;
		if (!grid_string_to_addrinfo (m1->host, NULL, &m1a)) {
			GRID_INFO ("Invalid META1 [%s] for [%s]",
				m1->host, hc_url_get (args->url, HCURL_WHOLE));
			meta1_service_url_clean (m1);
			continue;
		}

		GError *err = hook (m1->host);
		meta1_service_url_clean (m1);
		if (!err)
			return NULL;
		else if (err->code == CODE_REDIRECT)
			g_clear_error (&err);
		else {
			g_prefix_error (&err, "META1 error: ");
			return err;
		}
	}
	return NEWERROR (CODE_UNAVAILABLE, "No meta1 answered");
}
static struct meta1_service_url_s *
__poll_services(struct meta1_backend_s *m1, guint replicas,
                struct compound_type_s *ct, guint seq,
                struct meta1_service_url_s **used, GError **err)
{
    GRID_DEBUG("Polling %u [%s]", replicas, ct->fulltype);

    // ----------------------------------------------------------------------
    GPtrArray *ids = g_ptr_array_new_with_free_func(g_free);
    oio_location_t *avoid = __locations_from_m1srvurl(used);
    oio_location_t *known = NULL;
    if (ct->req.k && !strcmp(ct->req.k, NAME_TAGNAME_USER_IS_SERVICE)) {
        gchar srvurl[64] = {0};
        g_snprintf(srvurl, sizeof(srvurl), "1||%s|", ct->req.v);
        struct meta1_service_url_s *inplace[2] = {
            meta1_unpack_url(srvurl), NULL
        };
        /* If ct->req.v is not an addr, known will contain NULL */
        // FIXME: this should be in `avoid` instead of `known`
        // but avoids are compared without the location mask
        known = __locations_from_m1srvurl(inplace);
        meta1_service_url_clean(inplace[0]);
    }
    void _on_id(oio_location_t loc, const char *id)
    {
        (void)loc;
        g_ptr_array_add(ids, g_strdup(id));
    }
Esempio n. 3
0
static struct meta1_service_url_s *
__poll_services(struct meta1_backend_s *m1, guint replicas,
                struct compound_type_s *ct, guint seq,
                struct meta1_service_url_s **used, GError **err)
{
    struct grid_lb_iterator_s *iter = NULL;
    struct service_info_s **siv = NULL;

    GRID_DEBUG("Polling %u [%s]", replicas, ct->fulltype);

    if (!(*err = _get_iterator(m1, ct, &iter))) {
        struct lb_next_opt_ext_s opt;
        memset(&opt, 0, sizeof(opt));
        opt.req.distance = MACRO_COND(replicas>1,1,0);
        opt.req.max = replicas;
        opt.req.duplicates = FALSE;
        opt.req.stgclass = NULL;
        opt.req.strict_stgclass = TRUE;
        opt.srv_forbidden = __srvinfo_from_m1srvurl(m1->lb, ct->baretype, used);

        if (ct->req.k && !strcmp(ct->req.k, NAME_TAGNAME_USER_IS_SERVICE)) {
            gchar *srvurl = g_strdup_printf("1||%s|", ct->req.v);
            struct meta1_service_url_s *inplace[2] = {
                meta1_unpack_url(srvurl), NULL
            };
            /* If ct->req.v is not an addr, srv_inplace will contain NULL */
            opt.srv_inplace = __srvinfo_from_m1srvurl(m1->lb, NULL, inplace);
            opt.req.distance = 1;
            meta1_service_url_clean(inplace[0]);
            g_free(srvurl);
        } else {
            opt.filter.hook = _filter_tag;
            opt.filter.data = ct;
        }

        if (!grid_lb_iterator_next_set2(iter, &siv, &opt)) {
            EXTRA_ASSERT(siv == NULL);
            *err = NEWERROR(CODE_POLICY_NOT_SATISFIABLE, "No service available");
        }

        grid_lb_iterator_clean(iter);
        iter = NULL;
        g_slist_free_full(opt.srv_forbidden, (GDestroyNotify)service_info_clean);
        g_slist_free_full(opt.srv_inplace, (GDestroyNotify)service_info_clean);
    }

    if(NULL != *err)
        return NULL;

    struct meta1_service_url_s *m1u = _siv_to_url (siv);
    service_info_cleanv(siv, FALSE);
    siv = NULL;
    g_strlcpy(m1u->srvtype, ct->type, sizeof(m1u->srvtype));
    m1u->seq = seq;
    return m1u;
}
Esempio n. 4
0
void
meta1_service_url_cleanv(struct meta1_service_url_s **uv)
{
	struct meta1_service_url_s **p;

	if (!uv)
		return;
	for (p=uv; *p ;p++)
		meta1_service_url_clean(*p);
	g_free(uv);
}
Esempio n. 5
0
static GString *
_pack_m1url_list (GString *gstr, gchar ** urlv)
{
	if (!gstr)
		gstr = g_string_new ("");
	g_string_append_c (gstr, '[');
	for (gchar ** v = urlv; v && *v; v++) {
		struct meta1_service_url_s *m1 = meta1_unpack_url (*v);
		meta1_service_url_encode_json (gstr, m1);
		meta1_service_url_clean (m1);
		if (*(v + 1))
			g_string_append_c (gstr, ',');
	}
	g_string_append_c (gstr, ']');
	return gstr;
}
Esempio n. 6
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);
}
Esempio n. 7
0
static GError *
__relink_container_services(struct m1v2_relink_input_s *in, gchar ***out)
{
    GError *err = NULL;
    struct service_info_s **polled = NULL;
    struct meta1_service_url_s *packed = NULL;

    struct meta1_service_url_s *ref = (in->kept && in->kept[0])
                                      ? in->kept[0] : in->replaced[0];

    /* check the services provided are those in place */
    struct meta1_service_url_s **inplace = NULL;
    err = __get_container_all_services (in->sq3, in->url, ref->srvtype, &inplace);
    if (!err && !__match_urlv(inplace, in->kept, in->replaced))
        err = NEWERROR(CODE_USER_INUSE, "services changed");
    meta1_service_url_cleanv (inplace);
    inplace = NULL;

    /* it is time to poll */
    if (!err) {
        struct service_update_policies_s *pol = meta1_backend_get_svcupdate(in->m1);
        EXTRA_ASSERT (pol != NULL);

        struct lb_next_opt_ext_s opt;
        memset (&opt, 0, sizeof (opt));
        opt.req.max = service_howmany_replicas (pol, in->ct->baretype);
        opt.req.distance = opt.req.max > 1 ? 1 : 0;
        opt.req.duplicates = FALSE;
        opt.req.stgclass = NULL;
        opt.req.strict_stgclass = TRUE;
        opt.filter.hook = NULL;
        opt.filter.data = NULL;
        if (in->kept)
            opt.srv_inplace = __srvinfo_from_m1srvurl (in->m1->lb,
                              in->ct->baretype, in->kept);
        if (in->replaced)
            opt.srv_forbidden = __srvinfo_from_m1srvurl (in->m1->lb,
                                in->ct->baretype, in->replaced);

        if (g_slist_length(opt.srv_inplace) >= opt.req.max)
            err = NEWERROR(CODE_POLICY_NOT_SATISFIABLE, "Too many services kept");

        if (!err) {
            if (!grid_lb_iterator_next_set2 (in->iterator, &polled, &opt)) {
                EXTRA_ASSERT(polled == NULL);
                err = NEWERROR (CODE_POLICY_NOT_SATISFIABLE, "No service available");
            } else {
                EXTRA_ASSERT(polled != NULL);
            }
        }

        g_slist_free_full (opt.srv_forbidden, (GDestroyNotify)service_info_clean);
        g_slist_free_full (opt.srv_inplace, (GDestroyNotify)service_info_clean);
    }

    /* Services have been polled, them save them.
     * We MUST use the same SEQ number. Since the service are packed in one
     * entry, we can save them with a single SQL statement. */
    if (!err && !in->dryrun) {
        packed = _siv_to_url (polled);
        packed->seq = ref->seq;
        strcpy (packed->srvtype, ref->srvtype);
        err = __save_service (in->sq3, in->url, packed, TRUE);
    }

    /* if the checks, polling and storage succeeded, prepare the output for
     * the caller */
    if (!err) {
        struct meta1_service_url_s **newset = expand_url (packed);
        *out = pack_urlv (newset);
        meta1_service_url_cleanv (newset);
    }

    service_info_cleanv (polled, FALSE);
    meta1_service_url_clean (packed);
    return err;
}