summary refs log tree commit diff
path: root/src/nm-cloud-setup
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-cloud-setup')
-rw-r--r--src/nm-cloud-setup/nm-http-client.c161
-rw-r--r--src/nm-cloud-setup/nm-http-client.h24
-rw-r--r--src/nm-cloud-setup/nmcs-provider-aliyun.c27
-rw-r--r--src/nm-cloud-setup/nmcs-provider-azure.c31
-rw-r--r--src/nm-cloud-setup/nmcs-provider-ec2.c82
-rw-r--r--src/nm-cloud-setup/nmcs-provider-gcp.c25
-rw-r--r--src/nm-cloud-setup/nmcs-provider.h28
7 files changed, 231 insertions, 147 deletions
diff --git a/src/nm-cloud-setup/nm-http-client.c b/src/nm-cloud-setup/nm-http-client.c
index a0964e21..db123f10 100644
--- a/src/nm-cloud-setup/nm-http-client.c
+++ b/src/nm-cloud-setup/nm-http-client.c
@@ -104,12 +104,12 @@ typedef struct {
 } GetResult;
 
 static void
-_get_result_free(gpointer data)
+_req_result_free(gpointer data)
 {
-    GetResult *get_result = data;
+    GetResult *req_result = data;
 
-    g_bytes_unref(get_result->response_data);
-    nm_g_slice_free(get_result);
+    g_bytes_unref(req_result->response_data);
+    nm_g_slice_free(req_result);
 }
 
 typedef struct {
@@ -154,7 +154,7 @@ _ehandle_free(EHandleData *edata)
 static void
 _ehandle_complete(EHandleData *edata, GError *error_take)
 {
-    GetResult    *get_result;
+    GetResult    *req_result;
     gs_free char *str_tmp_1     = NULL;
     long          response_code = -1;
 
@@ -200,15 +200,15 @@ _ehandle_complete(EHandleData *edata, GError *error_take)
 
     _ehandle_free_ehandle(edata);
 
-    get_result  = g_slice_new(GetResult);
-    *get_result = (GetResult){
+    req_result  = g_slice_new(GetResult);
+    *req_result = (GetResult){
         .response_code = response_code,
         /* This ensures that response_data is always NUL terminated. This is an important guarantee
          * that NMHttpClient makes. */
         .response_data = nm_str_buf_finalize_to_gbytes(&edata->recv_data),
     };
 
-    g_task_return_pointer(edata->task, get_result, _get_result_free);
+    g_task_return_pointer(edata->task, req_result, _req_result_free);
 
     _ehandle_free(edata);
 }
@@ -256,12 +256,13 @@ _get_cancelled_cb(GObject *object, gpointer user_data)
     _ehandle_complete(edata, error);
 }
 
-void
-nm_http_client_get(NMHttpClient       *self,
+static void
+nm_http_client_req(NMHttpClient       *self,
                    const char         *url,
                    int                 timeout_msec,
                    gssize              max_data,
                    const char *const  *http_headers,
+                   const char         *http_method,
                    GCancellable       *cancellable,
                    GAsyncReadyCallback callback,
                    gpointer            user_data)
@@ -280,7 +281,7 @@ nm_http_client_get(NMHttpClient       *self,
 
     edata  = g_slice_new(EHandleData);
     *edata = (EHandleData){
-        .task      = nm_g_task_new(self, cancellable, nm_http_client_get, callback, user_data),
+        .task      = nm_g_task_new(self, cancellable, nm_http_client_req, callback, user_data),
         .recv_data = NM_STR_BUF_INIT(0, FALSE),
         .max_data  = max_data,
         .url       = g_strdup(url),
@@ -289,7 +290,7 @@ nm_http_client_get(NMHttpClient       *self,
 
     nmcs_wait_for_objects_register(edata->task);
 
-    _LOG2D(edata, "start get ...");
+    _LOG2D(edata, "start %s ...", http_method ?: "get");
 
     edata->ehandle = curl_easy_init();
     if (!edata->ehandle) {
@@ -328,6 +329,9 @@ nm_http_client_get(NMHttpClient       *self,
         curl_easy_setopt(edata->ehandle, CURLOPT_HTTPHEADER, edata->headers);
     }
 
+    if (http_method)
+        curl_easy_setopt(edata->ehandle, CURLOPT_CUSTOMREQUEST, http_method);
+
     if (timeout_msec > 0) {
         edata->timeout_source = _source_attach(self,
                                                nm_g_timeout_source_new(timeout_msec,
@@ -352,7 +356,7 @@ nm_http_client_get(NMHttpClient       *self,
 }
 
 /**
- * nm_http_client_get_finish:
+ * nm_http_client_req_finish:
  * @self: the #NMHttpClient instance
  * @result: the #GAsyncResult which to complete.
  * @out_response_code: (allow-none) (out): the HTTP response code or -1 on other error.
@@ -366,34 +370,34 @@ nm_http_client_get(NMHttpClient       *self,
  *
  * Returns: %TRUE on success or %FALSE with an error code.
  */
-gboolean
-nm_http_client_get_finish(NMHttpClient *self,
+static gboolean
+nm_http_client_req_finish(NMHttpClient *self,
                           GAsyncResult *result,
                           long         *out_response_code,
                           GBytes      **out_response_data,
                           GError      **error)
 {
-    GetResult *get_result;
+    GetResult *req_result;
 
     g_return_val_if_fail(NM_IS_HTTP_CLIENT(self), FALSE);
-    g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_http_client_get), FALSE);
+    g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_http_client_req), FALSE);
 
-    get_result = g_task_propagate_pointer(G_TASK(result), error);
+    req_result = g_task_propagate_pointer(G_TASK(result), error);
 
-    nm_assert(!error || (!!get_result) == (!*error));
+    nm_assert(!error || (!!req_result) == (!*error));
 
-    if (!get_result) {
+    if (!req_result) {
         NM_SET_OUT(out_response_code, -1);
         NM_SET_OUT(out_response_data, NULL);
         return FALSE;
     }
 
-    NM_SET_OUT(out_response_code, get_result->response_code);
+    NM_SET_OUT(out_response_code, req_result->response_code);
 
     /* response_data is binary, but is also guaranteed to be NUL terminated! */
-    NM_SET_OUT(out_response_data, g_steal_pointer(&get_result->response_data));
+    NM_SET_OUT(out_response_data, g_steal_pointer(&req_result->response_data));
 
-    _get_result_free(get_result);
+    _req_result_free(req_result);
     return TRUE;
 }
 
@@ -403,63 +407,65 @@ typedef struct {
     GTask                      *task;
     char                       *uri;
     const char *const          *http_headers;
-    NMHttpClientPollGetCheckFcn check_fcn;
+    const char                 *http_method;
+    NMHttpClientPollReqCheckFcn check_fcn;
     gpointer                    check_user_data;
     GBytes                     *response_data;
     gsize                       request_max_data;
     long                        response_code;
     int                         request_timeout_ms;
-} PollGetData;
+} PollReqData;
 
 static void
-_poll_get_data_free(gpointer data)
+_poll_req_data_free(gpointer data)
 {
-    PollGetData *poll_get_data = data;
+    PollReqData *poll_req_data = data;
 
-    g_free(poll_get_data->uri);
+    g_free(poll_req_data->uri);
 
-    nm_clear_pointer(&poll_get_data->response_data, g_bytes_unref);
-    g_strfreev((char **) poll_get_data->http_headers);
+    nm_clear_pointer(&poll_req_data->response_data, g_bytes_unref);
+    g_free((gpointer) poll_req_data->http_headers);
 
-    nm_g_slice_free(poll_get_data);
+    nm_g_slice_free(poll_req_data);
 }
 
 static void
-_poll_get_probe_start_fcn(GCancellable       *cancellable,
+_poll_req_probe_start_fcn(GCancellable       *cancellable,
                           gpointer            probe_user_data,
                           GAsyncReadyCallback callback,
                           gpointer            user_data)
 {
-    PollGetData *poll_get_data = probe_user_data;
+    PollReqData *poll_req_data = probe_user_data;
 
-    /* balanced by _poll_get_probe_finish_fcn() */
-    g_object_ref(poll_get_data->task);
+    /* balanced by _poll_req_probe_finish_fcn() */
+    g_object_ref(poll_req_data->task);
 
-    nm_http_client_get(g_task_get_source_object(poll_get_data->task),
-                       poll_get_data->uri,
-                       poll_get_data->request_timeout_ms,
-                       poll_get_data->request_max_data,
-                       poll_get_data->http_headers,
+    nm_http_client_req(g_task_get_source_object(poll_req_data->task),
+                       poll_req_data->uri,
+                       poll_req_data->request_timeout_ms,
+                       poll_req_data->request_max_data,
+                       poll_req_data->http_headers,
+                       poll_req_data->http_method,
                        cancellable,
                        callback,
                        user_data);
 }
 
 static gboolean
-_poll_get_probe_finish_fcn(GObject      *source,
+_poll_req_probe_finish_fcn(GObject      *source,
                            GAsyncResult *result,
                            gpointer      probe_user_data,
                            GError      **error)
 {
-    PollGetData                      *poll_get_data = probe_user_data;
+    PollReqData                      *poll_req_data = probe_user_data;
     _nm_unused gs_unref_object GTask *task =
-        poll_get_data->task; /* balance ref from _poll_get_probe_start_fcn() */
+        poll_req_data->task; /* balance ref from _poll_req_probe_start_fcn() */
     gboolean               success;
     gs_free_error GError  *local_error   = NULL;
     gs_unref_bytes GBytes *response_data = NULL;
     long                   response_code = -1;
 
-    success = nm_http_client_get_finish(g_task_get_source_object(poll_get_data->task),
+    success = nm_http_client_req_finish(g_task_get_source_object(poll_req_data->task),
                                         result,
                                         &response_code,
                                         &response_data,
@@ -476,10 +482,10 @@ _poll_get_probe_finish_fcn(GObject      *source,
         return FALSE;
     }
 
-    if (poll_get_data->check_fcn) {
-        success = poll_get_data->check_fcn(response_code,
+    if (poll_req_data->check_fcn) {
+        success = poll_req_data->check_fcn(response_code,
                                            response_data,
-                                           poll_get_data->check_user_data,
+                                           poll_req_data->check_user_data,
                                            &local_error);
     } else
         success = (response_code == 200);
@@ -494,15 +500,15 @@ _poll_get_probe_finish_fcn(GObject      *source,
         return FALSE;
     }
 
-    poll_get_data->response_code = response_code;
-    poll_get_data->response_data = g_steal_pointer(&response_data);
+    poll_req_data->response_code = response_code;
+    poll_req_data->response_data = g_steal_pointer(&response_data);
     return TRUE;
 }
 
 static void
-_poll_get_done_cb(GObject *source, GAsyncResult *result, gpointer user_data)
+_poll_req_done_cb(GObject *source, GAsyncResult *result, gpointer user_data)
 {
-    PollGetData          *poll_get_data = user_data;
+    PollReqData          *poll_req_data = user_data;
     gs_free_error GError *error         = NULL;
     gboolean              success;
 
@@ -511,29 +517,30 @@ _poll_get_done_cb(GObject *source, GAsyncResult *result, gpointer user_data)
     nm_assert((!!success) == (!error));
 
     if (error)
-        g_task_return_error(poll_get_data->task, g_steal_pointer(&error));
+        g_task_return_error(poll_req_data->task, g_steal_pointer(&error));
     else
-        g_task_return_boolean(poll_get_data->task, TRUE);
+        g_task_return_boolean(poll_req_data->task, TRUE);
 
-    g_object_unref(poll_get_data->task);
+    g_object_unref(poll_req_data->task);
 }
 
 void
-nm_http_client_poll_get(NMHttpClient               *self,
+nm_http_client_poll_req(NMHttpClient               *self,
                         const char                 *uri,
                         int                         request_timeout_ms,
                         gssize                      request_max_data,
                         int                         poll_timeout_ms,
                         int                         ratelimit_timeout_ms,
                         const char *const          *http_headers,
+                        const char                 *http_method,
                         GCancellable               *cancellable,
-                        NMHttpClientPollGetCheckFcn check_fcn,
+                        NMHttpClientPollReqCheckFcn check_fcn,
                         gpointer                    check_user_data,
                         GAsyncReadyCallback         callback,
                         gpointer                    user_data)
 {
     nm_auto_pop_gmaincontext GMainContext *context = NULL;
-    PollGetData                           *poll_get_data;
+    PollReqData                           *poll_req_data;
 
     g_return_if_fail(NM_IS_HTTP_CLIENT(self));
     g_return_if_fail(uri && uri[0]);
@@ -543,21 +550,27 @@ nm_http_client_poll_get(NMHttpClient               *self,
     g_return_if_fail(ratelimit_timeout_ms >= -1);
     g_return_if_fail(!cancellable || G_CANCELLABLE(cancellable));
 
-    poll_get_data  = g_slice_new(PollGetData);
-    *poll_get_data = (PollGetData){
-        .task = nm_g_task_new(self, cancellable, nm_http_client_poll_get, callback, user_data),
+    poll_req_data  = g_slice_new(PollReqData);
+    *poll_req_data = (PollReqData){
+        .task = nm_g_task_new(self, cancellable, nm_http_client_poll_req, callback, user_data),
         .uri  = g_strdup(uri),
         .request_timeout_ms = request_timeout_ms,
         .request_max_data   = request_max_data,
         .check_fcn          = check_fcn,
         .check_user_data    = check_user_data,
         .response_code      = -1,
-        .http_headers       = NM_CAST_STRV_CC(g_strdupv((char **) http_headers)),
+        .http_headers       = NULL,
+        .http_method        = http_method,
     };
 
-    nmcs_wait_for_objects_register(poll_get_data->task);
+    if (http_headers) {
+        poll_req_data->http_headers =
+            nm_strv_dup_packed(http_headers, -1) ?: g_new(const char *, 1);
+    }
+
+    nmcs_wait_for_objects_register(poll_req_data->task);
 
-    g_task_set_task_data(poll_get_data->task, poll_get_data, _poll_get_data_free);
+    g_task_set_task_data(poll_req_data->task, poll_req_data, _poll_req_data_free);
 
     context =
         nm_g_main_context_push_thread_default_if_necessary(nm_http_client_get_main_context(self));
@@ -565,28 +578,28 @@ nm_http_client_poll_get(NMHttpClient               *self,
     nmcs_utils_poll(poll_timeout_ms,
                     ratelimit_timeout_ms,
                     0,
-                    _poll_get_probe_start_fcn,
-                    _poll_get_probe_finish_fcn,
-                    poll_get_data,
+                    _poll_req_probe_start_fcn,
+                    _poll_req_probe_finish_fcn,
+                    poll_req_data,
                     cancellable,
-                    _poll_get_done_cb,
-                    poll_get_data);
+                    _poll_req_done_cb,
+                    poll_req_data);
 }
 
 gboolean
-nm_http_client_poll_get_finish(NMHttpClient *self,
+nm_http_client_poll_req_finish(NMHttpClient *self,
                                GAsyncResult *result,
                                long         *out_response_code,
                                GBytes      **out_response_data,
                                GError      **error)
 {
-    PollGetData          *poll_get_data;
+    PollReqData          *poll_req_data;
     GTask                *task;
     gboolean              success;
     gs_free_error GError *local_error = NULL;
 
     g_return_val_if_fail(NM_HTTP_CLIENT(self), FALSE);
-    g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_http_client_poll_get), FALSE);
+    g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_http_client_poll_req), FALSE);
 
     task = G_TASK(result);
 
@@ -601,10 +614,10 @@ nm_http_client_poll_get_finish(NMHttpClient *self,
         return FALSE;
     }
 
-    poll_get_data = g_task_get_task_data(task);
+    poll_req_data = g_task_get_task_data(task);
 
-    NM_SET_OUT(out_response_code, poll_get_data->response_code);
-    NM_SET_OUT(out_response_data, g_steal_pointer(&poll_get_data->response_data));
+    NM_SET_OUT(out_response_code, poll_req_data->response_code);
+    NM_SET_OUT(out_response_data, g_steal_pointer(&poll_req_data->response_data));
     return TRUE;
 }
 
diff --git a/src/nm-cloud-setup/nm-http-client.h b/src/nm-cloud-setup/nm-http-client.h
index b041e99f..60310340 100644
--- a/src/nm-cloud-setup/nm-http-client.h
+++ b/src/nm-cloud-setup/nm-http-client.h
@@ -28,40 +28,26 @@ GMainContext *nm_http_client_get_main_context(NMHttpClient *self);
 
 /*****************************************************************************/
 
-void nm_http_client_get(NMHttpClient       *self,
-                        const char         *uri,
-                        int                 timeout_msec,
-                        gssize              max_data,
-                        const char *const  *http_headers,
-                        GCancellable       *cancellable,
-                        GAsyncReadyCallback callback,
-                        gpointer            user_data);
-
-gboolean nm_http_client_get_finish(NMHttpClient *self,
-                                   GAsyncResult *result,
-                                   long         *out_response_code,
-                                   GBytes      **out_response_data,
-                                   GError      **error);
-
-typedef gboolean (*NMHttpClientPollGetCheckFcn)(long     response_code,
+typedef gboolean (*NMHttpClientPollReqCheckFcn)(long     response_code,
                                                 GBytes  *response_data,
                                                 gpointer check_user_data,
                                                 GError **error);
 
-void nm_http_client_poll_get(NMHttpClient               *self,
+void nm_http_client_poll_req(NMHttpClient               *self,
                              const char                 *uri,
                              int                         request_timeout_ms,
                              gssize                      request_max_data,
                              int                         poll_timeout_ms,
                              int                         ratelimit_timeout_ms,
                              const char *const          *http_headers,
+                             const char                 *http_method,
                              GCancellable               *cancellable,
-                             NMHttpClientPollGetCheckFcn check_fcn,
+                             NMHttpClientPollReqCheckFcn check_fcn,
                              gpointer                    check_user_data,
                              GAsyncReadyCallback         callback,
                              gpointer                    user_data);
 
-gboolean nm_http_client_poll_get_finish(NMHttpClient *self,
+gboolean nm_http_client_poll_req_finish(NMHttpClient *self,
                                         GAsyncResult *result,
                                         long         *out_response_code,
                                         GBytes      **out_response_data,
diff --git a/src/nm-cloud-setup/nmcs-provider-aliyun.c b/src/nm-cloud-setup/nmcs-provider-aliyun.c
index 4b109609..86ecd76b 100644
--- a/src/nm-cloud-setup/nmcs-provider-aliyun.c
+++ b/src/nm-cloud-setup/nmcs-provider-aliyun.c
@@ -77,7 +77,7 @@ _detect_get_meta_data_done_cb(GObject *source, GAsyncResult *result, gpointer us
     gs_free_error GError  *get_error = NULL;
     gs_free_error GError  *error     = NULL;
 
-    nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error);
+    nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error);
 
     if (nm_utils_error_is_cancelled(get_error)) {
         g_task_return_error(task, g_steal_pointer(&get_error));
@@ -104,13 +104,14 @@ detect(NMCSProvider *provider, GTask *task)
 
     http_client = nmcs_provider_get_http_client(provider);
 
-    nm_http_client_poll_get(http_client,
+    nm_http_client_poll_req(http_client,
                             (uri = _aliyun_uri_concat(NM_ALIYUN_API_VERSION "/meta-data/")),
                             HTTP_TIMEOUT_MS,
                             256 * 1024,
                             7000,
                             1000,
                             NULL,
+                            NULL,
                             g_task_get_cancellable(task),
                             NULL,
                             NULL,
@@ -144,7 +145,7 @@ _get_config_fetch_done_cb(NMHttpClient                   *http_client,
     gsize                  i;
     gsize                  len;
 
-    nm_http_client_poll_get_finish(http_client, result, NULL, &response, &error);
+    nm_http_client_poll_req_finish(http_client, result, NULL, &response, &error);
 
     if (nm_utils_error_is_cancelled(error))
         return;
@@ -302,7 +303,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
     GHashTableIter                 h_iter;
     NMHttpClient                  *http_client;
 
-    nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &error);
+    nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &error);
 
     if (nm_utils_error_is_cancelled(error))
         return;
@@ -356,7 +357,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
               v_mac_data->path);
 
         get_config_data->n_pending++;
-        nm_http_client_poll_get(
+        nm_http_client_poll_req(
             http_client,
             (uri1 = _aliyun_uri_interfaces(v_mac_data->path,
                                            NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/",
@@ -366,6 +367,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             10000,
             1000,
             NULL,
+            NULL,
             get_config_data->intern_cancellable,
             NULL,
             NULL,
@@ -373,7 +375,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             config_iface_data);
 
         get_config_data->n_pending++;
-        nm_http_client_poll_get(
+        nm_http_client_poll_req(
             http_client,
             (uri2 = _aliyun_uri_interfaces(v_mac_data->path,
                                            NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/",
@@ -383,6 +385,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             10000,
             1000,
             NULL,
+            NULL,
             get_config_data->intern_cancellable,
             NULL,
             NULL,
@@ -390,7 +393,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             config_iface_data);
 
         get_config_data->n_pending++;
-        nm_http_client_poll_get(
+        nm_http_client_poll_req(
             http_client,
             (uri3 = _aliyun_uri_interfaces(v_mac_data->path,
                                            NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/",
@@ -400,6 +403,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             10000,
             1000,
             NULL,
+            NULL,
             get_config_data->intern_cancellable,
             NULL,
             NULL,
@@ -407,7 +411,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             config_iface_data);
 
         get_config_data->n_pending++;
-        nm_http_client_poll_get(
+        nm_http_client_poll_req(
             http_client,
             (uri4 = _aliyun_uri_interfaces(v_mac_data->path,
                                            NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/",
@@ -417,6 +421,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             10000,
             1000,
             NULL,
+            NULL,
             get_config_data->intern_cancellable,
             NULL,
             NULL,
@@ -424,7 +429,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             config_iface_data);
 
         get_config_data->n_pending++;
-        nm_http_client_poll_get(
+        nm_http_client_poll_req(
             http_client,
             (uri5 = _aliyun_uri_interfaces(v_mac_data->path,
                                            NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/",
@@ -434,6 +439,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             10000,
             1000,
             NULL,
+            NULL,
             get_config_data->intern_cancellable,
             NULL,
             NULL,
@@ -524,13 +530,14 @@ get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_dat
      * MAC addresses, then we poll until we see them. They might not yet be
      * around from the start...
      */
-    nm_http_client_poll_get(nmcs_provider_get_http_client(provider),
+    nm_http_client_poll_req(nmcs_provider_get_http_client(provider),
                             (uri = _aliyun_uri_interfaces()),
                             HTTP_TIMEOUT_MS,
                             256 * 1024,
                             15000,
                             1000,
                             NULL,
+                            NULL,
                             get_config_data->intern_cancellable,
                             _get_config_metadata_ready_check,
                             get_config_data,
diff --git a/src/nm-cloud-setup/nmcs-provider-azure.c b/src/nm-cloud-setup/nmcs-provider-azure.c
index b59235bf..69946f5c 100644
--- a/src/nm-cloud-setup/nmcs-provider-azure.c
+++ b/src/nm-cloud-setup/nmcs-provider-azure.c
@@ -42,7 +42,7 @@ _detect_get_meta_data_done_cb(GObject *source, GAsyncResult *result, gpointer us
     gs_free_error GError  *get_error = NULL;
     gs_free_error GError  *error     = NULL;
 
-    nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error);
+    nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error);
 
     if (nm_utils_error_is_cancelled(get_error)) {
         g_task_return_error(task, g_steal_pointer(&get_error));
@@ -69,13 +69,14 @@ detect(NMCSProvider *provider, GTask *task)
 
     http_client = nmcs_provider_get_http_client(provider);
 
-    nm_http_client_poll_get(http_client,
+    nm_http_client_poll_req(http_client,
                             (uri = _azure_uri_concat("/metadata/instance")),
                             HTTP_TIMEOUT_MS,
                             256 * 1024,
                             7000,
                             1000,
                             NM_MAKE_STRV(NM_AZURE_METADATA_HEADER),
+                            NULL,
                             g_task_get_cancellable(task),
                             NULL,
                             NULL,
@@ -121,7 +122,7 @@ _get_config_fetch_done_cb(NMHttpClient      *http_client,
     in_addr_t                       tmp_addr;
     int                             tmp_prefix = -1;
 
-    nm_http_client_poll_get_finish(http_client, result, NULL, &response, &error);
+    nm_http_client_poll_req_finish(http_client, result, NULL, &response, &error);
 
     if (nm_utils_error_is_cancelled(error))
         return;
@@ -241,7 +242,7 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u
     gsize                          line_len;
     char                           iface_idx_str[30];
 
-    nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error);
+    nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error);
 
     if (nm_utils_error_is_cancelled(error))
         return;
@@ -283,7 +284,7 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u
 
         iface_data->n_iface_data_pending++;
 
-        nm_http_client_poll_get(
+        nm_http_client_poll_req(
             NM_HTTP_CLIENT(source),
             (uri = _azure_uri_interfaces(iface_idx_str,
                                          "/ipv4/ipAddress/",
@@ -294,6 +295,7 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u
             10000,
             1000,
             NM_MAKE_STRV(NM_AZURE_METADATA_HEADER),
+            NULL,
             get_config_data->intern_cancellable,
             NULL,
             NULL,
@@ -308,7 +310,7 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u
         gs_free char *uri = NULL;
 
         iface_data->n_iface_data_pending++;
-        nm_http_client_poll_get(
+        nm_http_client_poll_req(
             NM_HTTP_CLIENT(source),
             (uri = _azure_uri_interfaces(iface_idx_str, "/ipv4/subnet/0/address/")),
             HTTP_TIMEOUT_MS,
@@ -316,6 +318,7 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u
             10000,
             1000,
             NM_MAKE_STRV(NM_AZURE_METADATA_HEADER),
+            NULL,
             get_config_data->intern_cancellable,
             NULL,
             NULL,
@@ -325,7 +328,7 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u
         nm_clear_g_free(&uri);
 
         iface_data->n_iface_data_pending++;
-        nm_http_client_poll_get(
+        nm_http_client_poll_req(
             NM_HTTP_CLIENT(source),
             (uri = _azure_uri_interfaces(iface_idx_str, "/ipv4/subnet/0/prefix/")),
             HTTP_TIMEOUT_MS,
@@ -333,6 +336,7 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u
             10000,
             1000,
             NM_MAKE_STRV(NM_AZURE_METADATA_HEADER),
+            NULL,
             get_config_data->intern_cancellable,
             NULL,
             NULL,
@@ -357,7 +361,7 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data)
     gs_free const char            *uri        = NULL;
     char                           buf[100];
 
-    nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error);
+    nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error);
 
     if (nm_utils_error_is_cancelled(error))
         return;
@@ -408,13 +412,14 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data)
 
     nm_sprintf_buf(buf, "%" G_GSSIZE_FORMAT "/ipv4/ipAddress/", iface_data->intern_iface_idx);
 
-    nm_http_client_poll_get(NM_HTTP_CLIENT(source),
+    nm_http_client_poll_req(NM_HTTP_CLIENT(source),
                             (uri = _azure_uri_interfaces(buf)),
                             HTTP_TIMEOUT_MS,
                             512 * 1024,
                             10000,
                             1000,
                             NM_MAKE_STRV(NM_AZURE_METADATA_HEADER),
+                            NULL,
                             get_config_data->intern_cancellable,
                             NULL,
                             NULL,
@@ -441,7 +446,7 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat
     guint                          i;
     gssize                         extern_iface_idx_cnt = 0;
 
-    nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error);
+    nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error);
 
     if (nm_utils_error_is_cancelled(error))
         return;
@@ -508,13 +513,14 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat
         nm_sprintf_buf(buf, "%" G_GSSIZE_FORMAT "/macAddress", iface_data->intern_iface_idx);
 
         get_config_data->n_pending++;
-        nm_http_client_poll_get(NM_HTTP_CLIENT(source),
+        nm_http_client_poll_req(NM_HTTP_CLIENT(source),
                                 (uri = _azure_uri_interfaces(buf)),
                                 HTTP_TIMEOUT_MS,
                                 512 * 1024,
                                 10000,
                                 1000,
                                 NM_MAKE_STRV(NM_AZURE_METADATA_HEADER),
+                                NULL,
                                 get_config_data->intern_cancellable,
                                 NULL,
                                 NULL,
@@ -531,13 +537,14 @@ get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_dat
 {
     gs_free const char *uri = NULL;
 
-    nm_http_client_poll_get(nmcs_provider_get_http_client(provider),
+    nm_http_client_poll_req(nmcs_provider_get_http_client(provider),
                             (uri = _azure_uri_interfaces()),
                             HTTP_TIMEOUT_MS,
                             256 * 1024,
                             15000,
                             1000,
                             NM_MAKE_STRV(NM_AZURE_METADATA_HEADER),
+                            NULL,
                             get_config_data->intern_cancellable,
                             NULL,
                             NULL,
diff --git a/src/nm-cloud-setup/nmcs-provider-ec2.c b/src/nm-cloud-setup/nmcs-provider-ec2.c
index 58d691c7..65a8f629 100644
--- a/src/nm-cloud-setup/nmcs-provider-ec2.c
+++ b/src/nm-cloud-setup/nmcs-provider-ec2.c
@@ -16,6 +16,11 @@
 #define NM_EC2_METADATA_URL_BASE /* $NM_EC2_BASE/$NM_EC2_API_VERSION */ \
     "/meta-data/network/interfaces/macs/"
 
+/* Token TTL of 180 seconds is chosen abitrarily, in hope that it is
+ * surely more than enough to read all relevant metadata. */
+#define NM_EC2_TOKEN_TTL_HEADER "X-aws-ec2-metadata-token-ttl-seconds: 180"
+#define NM_EC2_TOKEN_HEADER     "X-aws-ec2-metadata-token: "
+
 static const char *
 _ec2_base(void)
 {
@@ -44,8 +49,15 @@ again:
 
 /*****************************************************************************/
 
+enum {
+    NM_EC2_HTTP_HEADER_TOKEN,
+    NM_EC2_HTTP_HEADER_SENTINEL,
+    _NM_EC2_HTTP_HEADER_NUM,
+};
+
 struct _NMCSProviderEC2 {
     NMCSProvider parent;
+    char        *token;
 };
 
 struct _NMCSProviderEC2Class {
@@ -56,23 +68,18 @@ G_DEFINE_TYPE(NMCSProviderEC2, nmcs_provider_ec2, NMCS_TYPE_PROVIDER);
 
 /*****************************************************************************/
 
-static gboolean
-_detect_get_meta_data_check_cb(long     response_code,
-                               GBytes  *response,
-                               gpointer check_user_data,
-                               GError **error)
-{
-    return response_code == 200 && nmcs_utils_parse_get_full_line(response, "ami-id");
-}
-
 static void
-_detect_get_meta_data_done_cb(GObject *source, GAsyncResult *result, gpointer user_data)
+_detect_get_token_done_cb(GObject *source, GAsyncResult *result, gpointer user_data)
 {
     gs_unref_object GTask *task      = user_data;
+    NMCSProviderEC2       *self      = NMCS_PROVIDER_EC2(g_task_get_source_object(task));
+    gs_unref_bytes GBytes *response  = NULL;
     gs_free_error GError  *get_error = NULL;
     gs_free_error GError  *error     = NULL;
 
-    nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error);
+    nm_clear_g_free(&self->token);
+
+    nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &get_error);
 
     if (nm_utils_error_is_cancelled(get_error)) {
         g_task_return_error(task, g_steal_pointer(&get_error));
@@ -88,6 +95,12 @@ _detect_get_meta_data_done_cb(GObject *source, GAsyncResult *result, gpointer us
         return;
     }
 
+    /* We use the token as-is. Special characters can cause confusion (e.g.
+     * response splitting), but we're not crossing a security boundary.
+     * None of the examples in AWS documentation does any sort of
+     * sanitization either.  */
+    self->token = g_strconcat(NM_EC2_TOKEN_HEADER, g_bytes_get_data(response, NULL), NULL);
+
     g_task_return_boolean(task, TRUE);
 }
 
@@ -99,17 +112,18 @@ detect(NMCSProvider *provider, GTask *task)
 
     http_client = nmcs_provider_get_http_client(provider);
 
-    nm_http_client_poll_get(http_client,
-                            (uri = _ec2_uri_concat("latest/meta-data/")),
+    nm_http_client_poll_req(http_client,
+                            (uri = _ec2_uri_concat("latest/api/token")),
                             HTTP_TIMEOUT_MS,
                             256 * 1024,
                             7000,
                             1000,
-                            NULL,
+                            NM_MAKE_STRV(NM_EC2_TOKEN_TTL_HEADER),
+                            "PUT",
                             g_task_get_cancellable(task),
-                            _detect_get_meta_data_check_cb,
                             NULL,
-                            _detect_get_meta_data_done_cb,
+                            NULL,
+                            _detect_get_token_done_cb,
                             task);
 }
 
@@ -126,7 +140,7 @@ _get_config_fetch_done_cb(NMHttpClient                   *http_client,
     in_addr_t              tmp_addr;
     int                    tmp_prefix;
 
-    nm_http_client_poll_get_finish(http_client, result, NULL, &response, &error);
+    nm_http_client_poll_req_finish(http_client, result, NULL, &response, &error);
 
     if (nm_utils_error_is_cancelled(error))
         return;
@@ -197,6 +211,7 @@ static void
 _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer user_data)
 {
     NMCSProviderGetConfigTaskData *get_config_data;
+    NMCSProviderEC2               *self;
     gs_unref_hashtable GHashTable *response_parsed = NULL;
     gs_free_error GError          *error           = NULL;
     GetConfigMetadataMac          *v_mac_data;
@@ -204,12 +219,13 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
     GHashTableIter                 h_iter;
     NMHttpClient                  *http_client;
 
-    nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &error);
+    nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &error);
 
     if (nm_utils_error_is_cancelled(error))
         return;
 
     get_config_data = user_data;
+    self            = NMCS_PROVIDER_EC2(get_config_data->self);
 
     response_parsed                     = g_steal_pointer(&get_config_data->extra_data);
     get_config_data->extra_data_destroy = NULL;
@@ -254,7 +270,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
               v_mac_data->path);
 
         get_config_data->n_pending++;
-        nm_http_client_poll_get(
+        nm_http_client_poll_req(
             http_client,
             (uri1 = _ec2_uri_interfaces(v_mac_data->path,
                                         NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/",
@@ -263,6 +279,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             512 * 1024,
             10000,
             1000,
+            NM_MAKE_STRV(self->token),
             NULL,
             get_config_data->intern_cancellable,
             NULL,
@@ -271,7 +288,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             config_iface_data);
 
         get_config_data->n_pending++;
-        nm_http_client_poll_get(
+        nm_http_client_poll_req(
             http_client,
             (uri2 = _ec2_uri_interfaces(v_mac_data->path,
                                         NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/",
@@ -280,6 +297,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             512 * 1024,
             10000,
             1000,
+            NM_MAKE_STRV(self->token),
             NULL,
             get_config_data->intern_cancellable,
             NULL,
@@ -365,18 +383,25 @@ _get_config_metadata_ready_check(long     response_code,
 static void
 get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_data)
 {
-    gs_free char *uri = NULL;
+    NMCSProviderEC2 *self = NMCS_PROVIDER_EC2(provider);
+    gs_free char    *uri  = NULL;
+
+    /* This can be called only if detect() succeeded, which implies
+     * there must be a token.
+     */
+    nm_assert(self->token);
 
     /* First we fetch the "macs/". If the caller requested some particular
      * MAC addresses, then we poll until we see them. They might not yet be
      * around from the start...
      */
-    nm_http_client_poll_get(nmcs_provider_get_http_client(provider),
+    nm_http_client_poll_req(nmcs_provider_get_http_client(provider),
                             (uri = _ec2_uri_interfaces()),
                             HTTP_TIMEOUT_MS,
                             256 * 1024,
                             15000,
                             1000,
+                            NM_MAKE_STRV(self->token),
                             NULL,
                             get_config_data->intern_cancellable,
                             _get_config_metadata_ready_check,
@@ -392,10 +417,23 @@ nmcs_provider_ec2_init(NMCSProviderEC2 *self)
 {}
 
 static void
+dispose(GObject *object)
+{
+    NMCSProviderEC2 *self = NMCS_PROVIDER_EC2(object);
+
+    nm_clear_g_free(&self->token);
+
+    G_OBJECT_CLASS(nmcs_provider_ec2_parent_class)->dispose(object);
+}
+
+static void
 nmcs_provider_ec2_class_init(NMCSProviderEC2Class *klass)
 {
+    GObjectClass      *object_class   = G_OBJECT_CLASS(klass);
     NMCSProviderClass *provider_class = NMCS_PROVIDER_CLASS(klass);
 
+    object_class->dispose = dispose;
+
     provider_class->_name                 = "ec2";
     provider_class->_env_provider_enabled = NMCS_ENV_VARIABLE("NM_CLOUD_SETUP_EC2");
     provider_class->detect                = detect;
diff --git a/src/nm-cloud-setup/nmcs-provider-gcp.c b/src/nm-cloud-setup/nmcs-provider-gcp.c
index a325f31a..ca354865 100644
--- a/src/nm-cloud-setup/nmcs-provider-gcp.c
+++ b/src/nm-cloud-setup/nmcs-provider-gcp.c
@@ -45,7 +45,7 @@ _detect_get_meta_data_done_cb(GObject *source, GAsyncResult *result, gpointer us
     gs_free_error GError  *get_error = NULL;
     gs_free_error GError  *error     = NULL;
 
-    nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error);
+    nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error);
 
     if (nm_utils_error_is_cancelled(get_error)) {
         g_task_return_error(task, g_steal_pointer(&get_error));
@@ -72,13 +72,14 @@ detect(NMCSProvider *provider, GTask *task)
 
     http_client = nmcs_provider_get_http_client(provider);
 
-    nm_http_client_poll_get(http_client,
+    nm_http_client_poll_req(http_client,
                             (uri = _gcp_uri_concat("id")),
                             HTTP_TIMEOUT_MS,
                             256 * 1024,
                             7000,
                             1000,
                             NM_MAKE_STRV(NM_GCP_METADATA_HEADER),
+                            NULL,
                             g_task_get_cancellable(task),
                             NULL,
                             NULL,
@@ -114,7 +115,7 @@ _get_config_fip_cb(GObject *source, GAsyncResult *result, gpointer user_data)
     NMIPRoute                     **routes_arr;
     NMIPRoute                      *route_new;
 
-    nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error);
+    nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error);
 
     if (nm_utils_error_is_cancelled(error))
         return;
@@ -171,7 +172,7 @@ _get_config_ips_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat
     gsize                          line_len;
     guint                          i;
 
-    nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error);
+    nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error);
 
     if (nm_utils_error_is_cancelled(error))
         return;
@@ -220,13 +221,14 @@ _get_config_ips_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat
         const char         *str = uri_arr->pdata[i];
         gs_free const char *uri = NULL;
 
-        nm_http_client_poll_get(NM_HTTP_CLIENT(source),
+        nm_http_client_poll_req(NM_HTTP_CLIENT(source),
                                 (uri = _gcp_uri_interfaces(str)),
                                 HTTP_TIMEOUT_MS,
                                 HTTP_REQ_MAX_DATA,
                                 HTTP_POLL_TIMEOUT_MS,
                                 HTTP_RATE_LIMIT_MS,
                                 NM_MAKE_STRV(NM_GCP_METADATA_HEADER),
+                                NULL,
                                 get_config_data->intern_cancellable,
                                 NULL,
                                 NULL,
@@ -252,7 +254,7 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data)
     NMCSProviderGetConfigTaskData *get_config_data;
     gboolean                       is_requested;
 
-    nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error);
+    nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error);
 
     if (nm_utils_error_is_cancelled(error))
         return;
@@ -306,13 +308,14 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data)
 
     nm_sprintf_buf(sbuf, "%" G_GSSIZE_FORMAT "/forwarded-ips/", iface_data->intern_iface_idx);
 
-    nm_http_client_poll_get(NM_HTTP_CLIENT(source),
+    nm_http_client_poll_req(NM_HTTP_CLIENT(source),
                             (uri = _gcp_uri_interfaces(sbuf)),
                             HTTP_TIMEOUT_MS,
                             HTTP_REQ_MAX_DATA,
                             HTTP_POLL_TIMEOUT_MS,
                             HTTP_RATE_LIMIT_MS,
                             NM_MAKE_STRV(NM_GCP_METADATA_HEADER),
+                            NULL,
                             get_config_data->intern_cancellable,
                             NULL,
                             NULL,
@@ -339,7 +342,7 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat
     guint                          i;
     gssize                         extern_iface_idx_cnt = 0;
 
-    nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error);
+    nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error);
 
     if (nm_utils_error_is_cancelled(error))
         return;
@@ -405,13 +408,14 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat
         nm_sprintf_buf(sbuf, "%" G_GSSIZE_FORMAT "/mac", data->intern_iface_idx);
 
         get_config_data->n_pending++;
-        nm_http_client_poll_get(NM_HTTP_CLIENT(source),
+        nm_http_client_poll_req(NM_HTTP_CLIENT(source),
                                 (uri = _gcp_uri_interfaces(sbuf)),
                                 HTTP_TIMEOUT_MS,
                                 HTTP_REQ_MAX_DATA,
                                 HTTP_POLL_TIMEOUT_MS,
                                 HTTP_RATE_LIMIT_MS,
                                 NM_MAKE_STRV(NM_GCP_METADATA_HEADER),
+                                NULL,
                                 get_config_data->intern_cancellable,
                                 NULL,
                                 NULL,
@@ -428,13 +432,14 @@ get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_dat
 {
     gs_free const char *uri = NULL;
 
-    nm_http_client_poll_get(nmcs_provider_get_http_client(provider),
+    nm_http_client_poll_req(nmcs_provider_get_http_client(provider),
                             (uri = _gcp_uri_interfaces()),
                             HTTP_TIMEOUT_MS,
                             HTTP_REQ_MAX_DATA,
                             HTTP_POLL_TIMEOUT_MS,
                             HTTP_RATE_LIMIT_MS,
                             NM_MAKE_STRV(NM_GCP_METADATA_HEADER),
+                            NULL,
                             get_config_data->intern_cancellable,
                             NULL,
                             NULL,
diff --git a/src/nm-cloud-setup/nmcs-provider.h b/src/nm-cloud-setup/nmcs-provider.h
index 994b1e24..09cdb414 100644
--- a/src/nm-cloud-setup/nmcs-provider.h
+++ b/src/nm-cloud-setup/nmcs-provider.h
@@ -152,8 +152,36 @@ typedef struct {
     const char  *_name;
     const char  *_env_provider_enabled;
 
+    /**
+     * detect:
+     * @self: the #NMCSProvider
+     * @task: a #GTask that's completed when the detection finishes.
+     *
+     * Checks whether the metadata of a particular cloud provider is
+     * accessible on the host machine. The check runs asynchronously.
+     *
+     * When the check finishes, @task is completed. If the check was
+     * successful, @task returns a gboolean of %TRUE. Otherwise
+     * a %FALSE value or an error is returned.
+     *
+     * The routine has to be called before the get_config() can be
+     * used.
+     */
     void (*detect)(NMCSProvider *self, GTask *task);
 
+    /**
+     * get_config:
+     * @self: the #NMCSProvider
+     * @get_config_data: encapsulates a #GTask and network configuration data
+     *
+     * Collects the network configuration from metadata service of a
+     * particular cloud provider. The metadata is traversed and checked
+     * asynchronously, completing a task encapsulated in @get_config_data
+     * upon finishing.
+     *
+     * Call to detect() with a successful result is necessary before
+     * using this routine.
+     */
     void (*get_config)(NMCSProvider *self, NMCSProviderGetConfigTaskData *get_config_data);
 
 } NMCSProviderClass;