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)); }
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; }
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); }
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; }
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); }
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; }