Пример #1
0
GError *
meta1_backend_services_all(struct meta1_backend_s *m1,
                           struct oio_url_s *url, gchar ***result)
{
    struct sqlx_sqlite3_s *sq3 = NULL;
    GError *err = _open_and_lock(m1, url, M1V2_OPENBASE_MASTERSLAVE, &sq3);
    if (err) return err;

    struct sqlx_repctx_s *repctx = NULL;
    if (!(err = sqlx_transaction_begin(sq3, &repctx))) {
        struct meta1_service_url_s **used = NULL;
        if (NULL != (err = __get_all_services(sq3, &used)))
            g_prefix_error(&err, "Query error: ");
        else {
            struct meta1_service_url_s **expanded = expand_urlv(used);
            *result = pack_urlv(expanded);
            meta1_service_url_cleanv(expanded);
            meta1_service_url_cleanv(used);
        }
        err = sqlx_transaction_end(repctx, err);
    }

    sqlx_repository_unlock_and_close_noerror(sq3);
    return err;
}
Пример #2
0
static GError *
__notify_services(struct meta1_backend_s *m1, struct sqlx_sqlite3_s *sq3,
                  struct oio_url_s *url)
{
    if (!m1->notifier)
        return NULL;

    struct meta1_service_url_s **services = NULL;
    GError *err = __get_container_all_services(sq3, url, NULL, &services);
    if (!err) {
        struct meta1_service_url_s **services2 = expand_urlv(services);
        GString *notif = g_string_sized_new(128);
        g_string_append (notif, "{\"event\":\""NAME_SRVTYPE_META1".account.services\"");
        g_string_append_printf (notif, ",\"when\":%"G_GINT64_FORMAT, oio_ext_real_time());
        g_string_append (notif, ",\"data\":{");
        g_string_append_printf (notif, "\"url\":\"%s\"", oio_url_get(url, OIOURL_WHOLE));
        g_string_append (notif, ",\"services\":[");
        if (services2) {
            for (struct meta1_service_url_s **svc = services2; *svc ; svc++) {
                if (svc != services2) // not at the beginning
                    g_string_append(notif, ",");
                meta1_service_url_encode_json(notif, *svc);
            }
        }
        g_string_append(notif, "]}}");

        oio_events_queue__send (m1->notifier, g_string_free(notif, FALSE));

        meta1_service_url_cleanv(services2);
        meta1_service_url_cleanv(services);
    }
    return err;
}
Пример #3
0
GError *
meta1_backend_services_list(struct meta1_backend_s *m1,
                            struct oio_url_s *url, const char *srvtype, gchar ***result)
{
    struct sqlx_sqlite3_s *sq3 = NULL;
    GError *err = _open_and_lock(m1, url, M1V2_OPENBASE_MASTERSLAVE, &sq3);
    if (err) return err;

    struct sqlx_repctx_s *repctx = NULL;
    if (!(err = sqlx_transaction_begin(sq3, &repctx))) {
        if (!(err = __info_user(sq3, url, FALSE, NULL))) {
            struct meta1_service_url_s **uv = NULL;
            err = __get_container_all_services(sq3, url, srvtype, &uv);
            if (NULL != err)
                g_prefix_error(&err, "Query error: ");
            else {
                struct meta1_service_url_s **expanded;
                expanded = expand_urlv(uv);
                *result = pack_urlv(expanded);
                meta1_service_url_cleanv(expanded);
                meta1_service_url_cleanv(uv);
            }
        }
        err = sqlx_transaction_end(repctx, err);
    }

    sqlx_repository_unlock_and_close_noerror(sq3);
    return err;
}
Пример #4
0
static GError *
__notify_services(struct meta1_backend_s *m1, struct sqlx_sqlite3_s *sq3,
		struct oio_url_s *url)
{
	if (!m1->notifier)
		return NULL;

	struct meta1_service_url_s **services = NULL;
	GError *err = __get_container_all_services(sq3, url, NULL, &services);
	if (!err) {
		struct meta1_service_url_s **services2 = expand_urlv(services);
		GString *notif = oio_event__create ("account.services", url);
		g_string_append (notif, ",\"data\":[");
		if (services2) {
			for (struct meta1_service_url_s **svc = services2; *svc ; svc++) {
				if (svc != services2) // not at the beginning
					g_string_append(notif, ",");
				meta1_service_url_encode_json(notif, *svc);
			}
		}
		g_string_append(notif, "]}");

		oio_events_queue__send (m1->notifier, g_string_free(notif, FALSE));

		meta1_service_url_cleanv(services2);
		meta1_service_url_cleanv(services);
	}
	return err;
}
Пример #5
0
static GError *
__del_container_services(struct sqlx_sqlite3_s *sq3, struct oio_url_s *url,
                         const char *srvtype, gchar **urlv)
{
    gint64 seq;
    GError *err = NULL;
    guint line = 1;

    if (!urlv || !*urlv)
        err = __del_container_all_services(sq3, url, srvtype);
    else {
        for (; !err && *urlv ; urlv++,line++) {
            gchar *end = NULL;

            errno = 0;
            seq = g_ascii_strtoll(*urlv, &end, 10);
            if ((end == *urlv) || (!seq && errno==EINVAL))
                err = NEWERROR(CODE_BAD_REQUEST, "line %u : Invalid number", line);
            else
                err = __del_container_one_service(sq3, url, srvtype, seq);
        }
    }

    // delete properties / services
    if (!err) {
        struct meta1_service_url_s **used = NULL;
        // list all services type of cid
        err = __get_container_all_services(sq3, url, srvtype, &used);
        if (err) {
            g_prefix_error(&err, "Preliminary lookup error : ");
        } else {
            if ((!used || !*used)) {
                // service type not used for this container_id...
                // delete all properties about cid/srvtype
                __del_container_srvtype_properties(sq3, url, srvtype);
            }
        }
        meta1_service_url_cleanv (used);
    }

    return err;
}
Пример #6
0
// TODO(srvid): do not suppose url is an IP address
static oio_location_t *
__locations_from_m1srvurl(struct meta1_service_url_s **urls)
{
    GArray *out = g_array_new(TRUE, TRUE, sizeof(oio_location_t));
    struct meta1_service_url_s **cursor = NULL;
    for (cursor = urls; cursor && *cursor; cursor++) {
        struct meta1_service_url_s **extracted;
        extracted = expand_url(*cursor);
        addr_info_t ai = {{0}};
        if (!grid_string_to_addrinfo((*extracted)->host, &ai))
            GRID_WARN("Could not parse [%s] to addrinfo", (*cursor)->host);
        else {
            oio_location_t loc = location_from_addr_info(&ai);
            g_array_append_val(out, loc);
        }
        meta1_service_url_cleanv(extracted);
        extracted = NULL;
    }
    return (oio_location_t*)g_array_free(out, FALSE);
}
Пример #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;
}
Пример #8
0
static GError *
__get_container_service2(struct sqlx_sqlite3_s *sq3,
                         struct oio_url_s *url, struct compound_type_s *ct,
                         struct meta1_backend_s *m1, enum m1v2_getsrv_e mode,
                         gchar ***result, gboolean *renewed)
{
    GError *err = NULL;
    struct meta1_service_url_s **used = NULL;
    enum service_update_policy_e policy;
    guint replicas;

    struct service_update_policies_s *pol;
    if (!(pol = meta1_backend_get_svcupdate(m1)))
        return NEWERROR(CODE_POLICY_NOT_SATISFIABLE, "Bad NS/Policy pair");
    policy = service_howto_update(pol, ct->baretype);
    replicas = service_howmany_replicas(pol, ct->baretype);
    replicas = (replicas > 0 ? replicas : 1);
    // Patches the constraint on the service type (if not set in the request)
    // by the constraint set in the NS-wide storage policy.
    compound_type_update_arg(ct, pol, FALSE);

    /* This special "tag" is used for services types that are to be linked
     * to containers belonging to other services (e.g. there is a container
     * for each rawx in the special "_RDIR" account). It tells the load
     * balancer to compare the location of linked service against the
     * location of the container owner. */
    if (ct->req.k && !strcmp(ct->req.k, NAME_TAGNAME_USER_IS_SERVICE)
            && (!ct->req.v || !ct->req.v[0])) {
        oio_str_replace(&(ct->req.v), oio_url_get(url, OIOURL_USER));
    }

    err = __get_container_all_services(sq3, url, ct->type, &used);
    if (NULL != err) {
        g_prefix_error(&err, "Preliminary lookup error : ");
        return err;
    }
    if (used && !*used) {
        g_free(used);
        used = NULL;
    }

    if (used && (mode != M1V2_GETSRV_RENEW)) {
        /* Only keep the services UP, if not forced to renew */
        struct meta1_service_url_s **up = __get_services_up(m1, used);
        if (up && *up) {
            *result = pack_urlv(up);
            meta1_service_url_cleanv(up);
            meta1_service_url_cleanv(used);
            return NULL;
        }
        meta1_service_url_cleanv(up);
    }

    if (used && (mode == M1V2_GETSRV_REUSE || policy == SVCUPD_KEEP)) {
        /* Services used but unavailable, but we are told to reuse */
        *result = pack_urlv(used);
        meta1_service_url_cleanv(used);
        return err;
    }

    /* No service available, poll a new one */
    struct meta1_service_url_s *m1_url = NULL;
    gint seq = urlv_get_max_seq(used);
    seq = (seq<0 ? 1 : seq+1);

    if (NULL != (m1_url = __poll_services(m1, replicas, ct, seq, used, &err))) {
        if (mode != M1V2_GETSRV_DRYRUN) {
            if (NULL == err) {
                if (policy == SVCUPD_REPLACE)
                    err = __delete_service(sq3, url, ct->type);
                if (NULL == err)
                    err = __save_service(sq3, url, m1_url, TRUE);
            }
        }

        if (!err && result) {
            struct meta1_service_url_s **unpacked = expand_url(m1_url);
            *result = pack_urlv(unpacked);
            meta1_service_url_cleanv(unpacked);
            if (renewed) *renewed = TRUE;
        }
        g_free(m1_url);
    }

    meta1_service_url_cleanv(used);
    return err;
}
Пример #9
0
GError*
meta1_backend_services_relink(struct meta1_backend_s *m1,
                              struct oio_url_s *url, const char *kept, const char *replaced,
                              gboolean dryrun, gchar ***out)
{
    GError *err = NULL;
    struct meta1_service_url_s **ukept = NULL, **urepl = NULL;
    /* fields to be prefetched */
    struct grid_lb_iterator_s *iterator = NULL;
    struct compound_type_s ct;

    memset (&ct, 0, sizeof(ct));
    ukept = __parse_and_expand (kept);
    urepl = __parse_and_expand (replaced);

    /* Sanity checks: we must receive at least one service */
    if ((!ukept || !*ukept) && (!urepl || !*urepl)) {
        err = NEWERROR (CODE_BAD_REQUEST, "Missing URL set");
        goto out;
    }
    /* Sanity check : all the services must have the same <seq,type> */
    struct meta1_service_url_s *ref = ukept && *ukept ? *ukept : *urepl;
    for (struct meta1_service_url_s **p = ukept; p && *p ; ++p) {
        if (0 != _sorter(p, &ref)) {
            err = NEWERROR(CODE_BAD_REQUEST, "Mismatch in URL set (%s)", "kept");
            goto out;
        }
    }
    for (struct meta1_service_url_s **p = urepl; p && *p ; ++p) {
        if (0 != _sorter(p, &ref)) {
            err = NEWERROR(CODE_BAD_REQUEST, "Mismatch in URL set (%s)", "kept");
            goto out;
        }
    }

    /* prefetch some fields from the backend: the compound type (so it is
     * parsed only once), the iterator (so we can already poll services, out
     * of the sqlite3 transaction) */
    if (NULL != (err = compound_type_parse(&ct, ref->srvtype))) {
        err = NEWERROR(CODE_BAD_REQUEST, "Invalid service type");
        goto out;
    }
    if (NULL != (err = _get_iterator (m1, &ct, &iterator))) {
        err = NEWERROR(CODE_BAD_REQUEST, "Service type not managed");
        goto out;
    }

    /* Call the backend logic now */
    struct sqlx_sqlite3_s *sq3 = NULL;
    struct sqlx_repctx_s *repctx = NULL;
    if (!(err = _open_and_lock(m1, url, M1V2_OPENBASE_MASTERONLY, &sq3))) {
        if (!(err = sqlx_transaction_begin(sq3, &repctx))) {
            if (!(err = __info_user(sq3, url, FALSE, NULL))) {
                struct m1v2_relink_input_s in = {
                    .m1 = m1, .sq3 = sq3, .url = url,
                    .iterator = iterator, .ct = &ct,
                    .kept = ukept, .replaced = urepl,
                    .dryrun = dryrun
                };
                err = __relink_container_services(&in, out);
            }
            if (!(err = sqlx_transaction_end(repctx, err))) {
                if (!dryrun)
                    __notify_services_by_cid(m1, sq3, url);
            }
        }
        sqlx_repository_unlock_and_close_noerror(sq3);
    }

out:
    meta1_service_url_cleanv (ukept);
    meta1_service_url_cleanv (urepl);
    grid_lb_iterator_clean (iterator);
    compound_type_clean (&ct);
    return err;
}
Пример #10
0
static GError *
__get_container_service2(struct sqlx_sqlite3_s *sq3,
		struct oio_url_s *url, struct compound_type_s *ct,
		struct meta1_backend_s *m1, enum m1v2_getsrv_e mode,
		gchar ***result, gboolean *renewed)
{
	GError *err = NULL;
	struct meta1_service_url_s **used = NULL;
	enum service_update_policy_e policy;
	guint replicas;

	struct service_update_policies_s *pol;
	if (!(pol = meta1_backend_get_svcupdate(m1)))
		return NEWERROR(CODE_POLICY_NOT_SATISFIABLE, "Bad NS/Policy pair");
	policy = service_howto_update(pol, ct->baretype);
	replicas = service_howmany_replicas(pol, ct->baretype);
	replicas = (replicas > 0 ? replicas : 1);
	// Patches the constraint on the service type (if not set in the request)
	// by the constraint set in the NS-wide storage policy.
	compound_type_update_arg(ct, pol, FALSE);

	err = __get_container_all_services(sq3, url, ct->type, &used);
	if (NULL != err) {
		g_prefix_error(&err, "Preliminary lookup error : ");
		return err;
	}
	if (used && !*used) {
		g_free(used);
		used = NULL;
	}

	if (used && (mode != M1V2_GETSRV_RENEW)) {
		/* Only keep the services UP, if not forced to renew */
		struct meta1_service_url_s **up = __get_services_up(m1, used);
		if (up && *up) {
			*result = pack_urlv(up);
			meta1_service_url_cleanv(up);
			meta1_service_url_cleanv(used);
			return NULL;
		}
		meta1_service_url_cleanv(up);
	}

	if (used && (mode == M1V2_GETSRV_REUSE || policy == SVCUPD_KEEP)) {
		/* Services used but unavailable, but we are told to reuse */
		*result = pack_urlv(used);
		meta1_service_url_cleanv(used);
		return err;
	}

	/* No service available, poll a new one */
	struct meta1_service_url_s *m1_url = NULL;
	gint seq = urlv_get_max_seq(used);
	seq = (seq<0 ? 1 : seq+1);

	if (NULL != (m1_url = __poll_services(m1, replicas, ct, seq, used, &err))) {
		if (mode != M1V2_GETSRV_DRYRUN) {
			if (NULL == err) {
				if (policy == SVCUPD_REPLACE)
					err = __delete_service(sq3, url, ct->type);
				if (NULL == err)
					err = __save_service(sq3, url, m1_url, TRUE);
			}
		}

		if (!err && result) {
			struct meta1_service_url_s **unpacked = expand_url(m1_url);
			*result = pack_urlv(unpacked);
			meta1_service_url_cleanv(unpacked);
			if (renewed) *renewed = TRUE;
		}
		g_free(m1_url);
	}

	meta1_service_url_cleanv(used);
	return err;
}