mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-07-09 04:05:56 +00:00
cloud-setup: configure secondary ip in Aliyun cloud
This is a tool for automatically configuring networking in Aliyun cloud environment. This add a provider implementation for Aliyun that when detected fetches the private ip addressess and the subnet prefix of IPv4 CIDR block. Once this information is fetched from the metadata server, it instructs NetworkManager to add private ip addressess and subnet prefix for each interface detected. It is inspired by SuSE's cloud-netconfig ([1], [2]) and Aliyun Instance Metadata [3]. [1] https://www.suse.com/c/multi-nic-cloud-netconfig-ec2-azure/ [2] https://github.com/SUSE-Enceladus/cloud-netconfig [3] https://www.alibabacloud.com/help/doc-detail/49122.htm It is also intended to work without configuration. The main point is that you boot an image with NetworkManager and nm-cloud-setup enabled, and it just works. https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/885 Signed-off-by: Wen Liang <liangwen12year@gmail.com>
This commit is contained in:
parent
09daf5dd92
commit
f3404435a9
|
@ -5137,6 +5137,8 @@ src_nm_cloud_setup_libnm_cloud_setup_core_a_SOURCES = \
|
|||
src/nm-cloud-setup/nmcs-provider-gcp.h \
|
||||
src/nm-cloud-setup/nmcs-provider-azure.c \
|
||||
src/nm-cloud-setup/nmcs-provider-azure.h \
|
||||
src/nm-cloud-setup/nmcs-provider-aliyun.c \
|
||||
src/nm-cloud-setup/nmcs-provider-aliyun.h \
|
||||
$(NULL)
|
||||
|
||||
src_nm_cloud_setup_libnm_cloud_setup_core_a_CPPFLAGS = \
|
||||
|
|
|
@ -187,6 +187,10 @@
|
|||
<para><literal>NM_CLOUD_SETUP_GCP</literal>: boolean, whether Google GCP support is enabled. Defaults
|
||||
to <literal>no</literal>.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>NM_CLOUD_SETUP_ALIYUN</literal>: boolean, whether Alibaba Cloud (Aliyun) support is enabled. Defaults
|
||||
to <literal>no</literal>.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
</refsect1>
|
||||
|
@ -368,6 +372,62 @@ ln -s /etc/systemd/system/timers.target.wants/nm-cloud-setup.timer /usr/lib/syst
|
|||
</itemizedlist>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Alibaba Cloud (Aliyun)</title>
|
||||
|
||||
<para>For Aliyun, the tools tries to fetch configuration from <literal>http://100.100.100.200/</literal>. Currently, it only
|
||||
configures IPv4 and does nothing about IPv6. It will do the following.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>First fetch <literal>http://100.100.100.200/2016-01-01/meta-data/</literal> to determine whether the
|
||||
expected API is present. This determines whether Aliyun environment is detected and whether to proceed
|
||||
to configure the host using Aliyun meta data.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Fetch <literal>http://100.100.100.200/2016-01-01/meta-data/network/interfaces/macs/</literal> to get the list
|
||||
of available interface. Interfaces are identified by their MAC address.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Then for each interface fetch <literal>http://100.100.100.200/2016-01-01/meta-data/network/interfaces/macs/$MAC/vpc-cidr-block</literal>
|
||||
, <literal>http://100.100.100.200/2016-01-01/meta-data/network/interfaces/macs/$MAC/private-ipv4s</literal> and
|
||||
<literal>http://100.100.100.200/2016-01-01/meta-data/network/interfaces/macs/$MAC/netmask</literal>.
|
||||
Thereby we get a list of private IPv4 addresses, one CIDR subnet block and private IPv4 addresses prefix.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Then nm-cloud-setup iterates over all interfaces for which it could fetch IP configuration.
|
||||
If no ethernet device for the respective MAC address is found, it is skipped.
|
||||
Also, if the device is currently not activated in NetworkManager or if the currently
|
||||
activated profile has a user-data <literal>org.freedesktop.nm-cloud-setup.skip=yes</literal>,
|
||||
it is skipped.</para>
|
||||
<para>Then, the tool will change the runtime configuration of the device.
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Add static IPv4 addresses for all the configured addresses from <literal>private-ipv4s</literal> with
|
||||
prefix length according to <literal>netmask</literal>. For example,
|
||||
we might have here 2 IP addresses like <literal>"10.0.0.150/24,10.0.0.152/24"</literal>.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Choose a route table 30400 + the index of the interface and
|
||||
add a default route <literal>0.0.0.0/0</literal>. The gateway
|
||||
is the first IP address in the CIDR subnet block. For
|
||||
example, we might get a route <literal>"0.0.0.0/0 10.0.0.1 10 table=30400"</literal>.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Finally, add a policy routing rule for each address. For example
|
||||
<literal>"priority 30400 from 10.0.0.150/32 table 30400, priority 30400 from 10.0.0.152/32 table 30400"</literal>.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
With above example, this roughly corresponds for interface <literal>eth0</literal> to
|
||||
<command>nmcli device modify "eth0" ipv4.addresses "10.0.0.150/24,10.0.0.150/24" ipv4.routes "0.0.0.0/0 10.0.0.1 10 table=30400" ipv4.routing-rules "priority 30400 from 10.0.0.150/32 table 30400, priority 30400 from 10.0.0.152/32 table 30400"</command>.
|
||||
Note that this replaces the previous addresses, routes and rules with the new information.
|
||||
But also note that this only changes the run time configuration of the device. The
|
||||
connection profile on disk is not affected.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</refsect2>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "nmcs-provider-ec2.h"
|
||||
#include "nmcs-provider-gcp.h"
|
||||
#include "nmcs-provider-azure.h"
|
||||
#include "nmcs-provider-aliyun.h"
|
||||
#include "libnm-core-aux-intern/nm-libnm-core-utils.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -85,6 +86,7 @@ _provider_detect(GCancellable *sigterm_cancellable)
|
|||
NMCS_TYPE_PROVIDER_EC2,
|
||||
NMCS_TYPE_PROVIDER_GCP,
|
||||
NMCS_TYPE_PROVIDER_AZURE,
|
||||
NMCS_TYPE_PROVIDER_ALIYUN,
|
||||
};
|
||||
int i;
|
||||
gulong cancellable_signal_id;
|
||||
|
|
|
@ -29,6 +29,7 @@ libnm_cloud_setup_core = static_library(
|
|||
'nmcs-provider-ec2.c',
|
||||
'nmcs-provider-gcp.c',
|
||||
'nmcs-provider-azure.c',
|
||||
'nmcs-provider-aliyun.c',
|
||||
'nmcs-provider.c',
|
||||
),
|
||||
dependencies: [
|
||||
|
|
|
@ -18,6 +18,7 @@ ExecStart=@libexecdir@/nm-cloud-setup
|
|||
#Environment=NM_CLOUD_SETUP_EC2=yes
|
||||
#Environment=NM_CLOUD_SETUP_GCP=yes
|
||||
#Environment=NM_CLOUD_SETUP_AZURE=yes
|
||||
#Environment=NM_CLOUD_SETUP_ALIYUN=yes
|
||||
|
||||
CapabilityBoundingSet=
|
||||
LockPersonality=yes
|
||||
|
|
471
src/nm-cloud-setup/nmcs-provider-aliyun.c
Normal file
471
src/nm-cloud-setup/nmcs-provider-aliyun.c
Normal file
|
@ -0,0 +1,471 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "libnm-client-aux-extern/nm-default-client.h"
|
||||
|
||||
#include "nmcs-provider-aliyun.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "nm-cloud-setup-utils.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define HTTP_TIMEOUT_MS 3000
|
||||
|
||||
#define NM_ALIYUN_HOST "100.100.100.200"
|
||||
#define NM_ALIYUN_BASE "http://" NM_ALIYUN_HOST
|
||||
#define NM_ALIYUN_API_VERSION "2016-01-01"
|
||||
#define NM_ALIYUN_METADATA_URL_BASE /* $NM_ALIYUN_BASE/$NM_ALIYUN_API_VERSION */ \
|
||||
"/meta-data/network/interfaces/macs/"
|
||||
|
||||
static const char *
|
||||
_aliyun_base(void)
|
||||
{
|
||||
static const char *base_cached = NULL;
|
||||
const char * base;
|
||||
|
||||
again:
|
||||
base = g_atomic_pointer_get(&base_cached);
|
||||
if (G_UNLIKELY(!base)) {
|
||||
/* The base URI can be set via environment variable.
|
||||
* This is mainly for testing, it's not usually supposed to be configured.
|
||||
* Consider this private API! */
|
||||
base = g_getenv(NMCS_ENV_VARIABLE("NM_CLOUD_SETUP_ALIYUN_HOST"));
|
||||
|
||||
if (!g_atomic_pointer_compare_and_exchange(&base_cached, NULL, base))
|
||||
goto again;
|
||||
}
|
||||
base = nmcs_utils_uri_complete_interned(base) ?: ("" NM_ALIYUN_BASE);
|
||||
return base;
|
||||
}
|
||||
|
||||
#define _aliyun_uri_concat(...) nmcs_utils_uri_build_concat(_aliyun_base(), __VA_ARGS__)
|
||||
#define _aliyun_uri_interfaces(...) \
|
||||
_aliyun_uri_concat(NM_ALIYUN_API_VERSION, NM_ALIYUN_METADATA_URL_BASE, ##__VA_ARGS__)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct _NMCSProviderAliyun {
|
||||
NMCSProvider parent;
|
||||
};
|
||||
|
||||
struct _NMCSProviderAliyunClass {
|
||||
NMCSProviderClass parent;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(NMCSProviderAliyun, nmcs_provider_aliyun, NMCS_TYPE_PROVIDER);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
filter_chars(char *str, const char *chars)
|
||||
{
|
||||
gsize i;
|
||||
gsize j;
|
||||
|
||||
for (i = 0, j = 0; str[i]; i++) {
|
||||
if (!strchr(chars, str[i]))
|
||||
str[j++] = str[i];
|
||||
}
|
||||
str[j] = '\0';
|
||||
}
|
||||
|
||||
static void
|
||||
_detect_get_meta_data_done_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
gs_unref_object GTask *task = user_data;
|
||||
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);
|
||||
|
||||
if (nm_utils_error_is_cancelled(get_error)) {
|
||||
g_task_return_error(task, g_steal_pointer(&get_error));
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_error) {
|
||||
nm_utils_error_set(&error,
|
||||
NM_UTILS_ERROR_UNKNOWN,
|
||||
"failure to get ALIYUN metadata: %s",
|
||||
get_error->message);
|
||||
g_task_return_error(task, g_steal_pointer(&error));
|
||||
return;
|
||||
}
|
||||
|
||||
g_task_return_boolean(task, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
detect(NMCSProvider *provider, GTask *task)
|
||||
{
|
||||
NMHttpClient *http_client;
|
||||
gs_free char *uri = NULL;
|
||||
|
||||
http_client = nmcs_provider_get_http_client(provider);
|
||||
|
||||
nm_http_client_poll_get(http_client,
|
||||
(uri = _aliyun_uri_concat(NM_ALIYUN_API_VERSION "/meta-data/")),
|
||||
HTTP_TIMEOUT_MS,
|
||||
256 * 1024,
|
||||
7000,
|
||||
1000,
|
||||
NULL,
|
||||
g_task_get_cancellable(task),
|
||||
NULL,
|
||||
NULL,
|
||||
_detect_get_meta_data_done_cb,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
GET_CONFIG_FETCH_DONE_TYPE_SUBNET_VPC_CIDR_BLOCK,
|
||||
GET_CONFIG_FETCH_DONE_TYPE_PRIVATE_IPV4S,
|
||||
GET_CONFIG_FETCH_DONE_TYPE_NETMASK
|
||||
} GetConfigFetchDoneType;
|
||||
|
||||
static void
|
||||
_get_config_fetch_done_cb(NMHttpClient * http_client,
|
||||
GAsyncResult * result,
|
||||
gpointer user_data,
|
||||
GetConfigFetchDoneType fetch_type)
|
||||
{
|
||||
NMCSProviderGetConfigTaskData *get_config_data;
|
||||
const char * hwaddr = NULL;
|
||||
gs_unref_bytes GBytes *response = NULL;
|
||||
gs_free_error GError * error = NULL;
|
||||
NMCSProviderGetConfigIfaceData *config_iface_data;
|
||||
in_addr_t tmp_addr;
|
||||
int tmp_prefix;
|
||||
in_addr_t netmask_bin;
|
||||
gs_free const char ** s_addrs = NULL;
|
||||
gsize i;
|
||||
gsize len;
|
||||
|
||||
nm_utils_user_data_unpack(user_data, &get_config_data, &hwaddr);
|
||||
|
||||
nm_http_client_poll_get_finish(http_client, result, NULL, &response, &error);
|
||||
|
||||
if (nm_utils_error_is_cancelled(error))
|
||||
return;
|
||||
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
config_iface_data = g_hash_table_lookup(get_config_data->result_dict, hwaddr);
|
||||
|
||||
switch (fetch_type) {
|
||||
case GET_CONFIG_FETCH_DONE_TYPE_PRIVATE_IPV4S:
|
||||
|
||||
s_addrs = nm_utils_strsplit_set_full(g_bytes_get_data(response, NULL),
|
||||
",",
|
||||
NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP);
|
||||
len = NM_PTRARRAY_LEN(s_addrs);
|
||||
nm_assert(!config_iface_data->has_ipv4s);
|
||||
nm_assert(!config_iface_data->ipv4s_arr);
|
||||
config_iface_data->has_ipv4s = TRUE;
|
||||
config_iface_data->ipv4s_len = 0;
|
||||
if (len > 0) {
|
||||
config_iface_data->ipv4s_arr = g_new(in_addr_t, len);
|
||||
for (i = 0; i < len; i++) {
|
||||
filter_chars((char *) s_addrs[i], "[]\"");
|
||||
if (nm_utils_parse_inaddr_bin(AF_INET, s_addrs[i], NULL, &tmp_addr)) {
|
||||
config_iface_data->ipv4s_arr[config_iface_data->ipv4s_len++] = tmp_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GET_CONFIG_FETCH_DONE_TYPE_SUBNET_VPC_CIDR_BLOCK:
|
||||
|
||||
if (nm_utils_parse_inaddr_prefix_bin(AF_INET,
|
||||
g_bytes_get_data(response, NULL),
|
||||
NULL,
|
||||
&tmp_addr,
|
||||
&tmp_prefix)) {
|
||||
nm_assert(!config_iface_data->has_cidr);
|
||||
config_iface_data->has_cidr = TRUE;
|
||||
config_iface_data->cidr_addr = tmp_addr;
|
||||
}
|
||||
break;
|
||||
|
||||
case GET_CONFIG_FETCH_DONE_TYPE_NETMASK:
|
||||
|
||||
if (nm_utils_parse_inaddr_bin(AF_INET,
|
||||
g_bytes_get_data(response, NULL),
|
||||
NULL,
|
||||
&netmask_bin)) {
|
||||
config_iface_data->cidr_prefix = nm_utils_ip4_netmask_to_prefix(netmask_bin);
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
get_config_data->n_pending--;
|
||||
_nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error));
|
||||
}
|
||||
|
||||
static void
|
||||
_get_config_fetch_done_cb_vpc_cidr_block(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
_get_config_fetch_done_cb(NM_HTTP_CLIENT(source),
|
||||
result,
|
||||
user_data,
|
||||
GET_CONFIG_FETCH_DONE_TYPE_SUBNET_VPC_CIDR_BLOCK);
|
||||
}
|
||||
|
||||
static void
|
||||
_get_config_fetch_done_cb_private_ipv4s(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
_get_config_fetch_done_cb(NM_HTTP_CLIENT(source),
|
||||
result,
|
||||
user_data,
|
||||
GET_CONFIG_FETCH_DONE_TYPE_PRIVATE_IPV4S);
|
||||
}
|
||||
|
||||
static void
|
||||
_get_config_fetch_done_cb_netmask(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
_get_config_fetch_done_cb(NM_HTTP_CLIENT(source),
|
||||
result,
|
||||
user_data,
|
||||
GET_CONFIG_FETCH_DONE_TYPE_NETMASK);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
gssize iface_idx;
|
||||
char path[0];
|
||||
} GetConfigMetadataMac;
|
||||
|
||||
static void
|
||||
_get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
NMCSProviderGetConfigTaskData *get_config_data;
|
||||
gs_unref_hashtable GHashTable *response_parsed = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
GetConfigMetadataMac *v_mac_data;
|
||||
const char * v_hwaddr;
|
||||
GHashTableIter h_iter;
|
||||
NMHttpClient * http_client;
|
||||
|
||||
nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &error);
|
||||
|
||||
if (nm_utils_error_is_cancelled(error))
|
||||
return;
|
||||
|
||||
get_config_data = user_data;
|
||||
|
||||
response_parsed = g_steal_pointer(&get_config_data->extra_data);
|
||||
get_config_data->extra_data_destroy = NULL;
|
||||
|
||||
/* We ignore errors. Only if we got no response at all, it's a problem.
|
||||
* Otherwise, we proceed with whatever we could fetch. */
|
||||
if (!response_parsed) {
|
||||
_nmcs_provider_get_config_task_maybe_return(
|
||||
get_config_data,
|
||||
nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "meta data for interfaces not found"));
|
||||
return;
|
||||
}
|
||||
|
||||
http_client = nmcs_provider_get_http_client(g_task_get_source_object(get_config_data->task));
|
||||
|
||||
g_hash_table_iter_init(&h_iter, response_parsed);
|
||||
while (g_hash_table_iter_next(&h_iter, (gpointer *) &v_hwaddr, (gpointer *) &v_mac_data)) {
|
||||
NMCSProviderGetConfigIfaceData *config_iface_data;
|
||||
gs_free char * uri1 = NULL;
|
||||
gs_free char * uri2 = NULL;
|
||||
gs_free char * uri3 = NULL;
|
||||
const char * hwaddr;
|
||||
|
||||
if (!g_hash_table_lookup_extended(get_config_data->result_dict,
|
||||
v_hwaddr,
|
||||
(gpointer *) &hwaddr,
|
||||
(gpointer *) &config_iface_data)) {
|
||||
if (!get_config_data->any) {
|
||||
_LOGD("get-config: skip fetching meta data for %s (%s)",
|
||||
v_hwaddr,
|
||||
v_mac_data->path);
|
||||
continue;
|
||||
}
|
||||
config_iface_data = nmcs_provider_get_config_iface_data_new(FALSE);
|
||||
g_hash_table_insert(get_config_data->result_dict,
|
||||
(char *) (hwaddr = g_strdup(v_hwaddr)),
|
||||
config_iface_data);
|
||||
}
|
||||
|
||||
nm_assert(config_iface_data->iface_idx == -1);
|
||||
|
||||
config_iface_data->iface_idx = v_mac_data->iface_idx;
|
||||
|
||||
_LOGD("get-config: start fetching meta data for #%" G_GSSIZE_FORMAT ", %s (%s)",
|
||||
config_iface_data->iface_idx,
|
||||
hwaddr,
|
||||
v_mac_data->path);
|
||||
|
||||
get_config_data->n_pending++;
|
||||
nm_http_client_poll_get(
|
||||
http_client,
|
||||
(uri1 = _aliyun_uri_interfaces(v_mac_data->path,
|
||||
NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/",
|
||||
"vpc-cidr-block")),
|
||||
HTTP_TIMEOUT_MS,
|
||||
512 * 1024,
|
||||
10000,
|
||||
1000,
|
||||
NULL,
|
||||
get_config_data->intern_cancellable,
|
||||
NULL,
|
||||
NULL,
|
||||
_get_config_fetch_done_cb_vpc_cidr_block,
|
||||
nm_utils_user_data_pack(get_config_data, hwaddr));
|
||||
|
||||
get_config_data->n_pending++;
|
||||
nm_http_client_poll_get(
|
||||
http_client,
|
||||
(uri2 = _aliyun_uri_interfaces(v_mac_data->path,
|
||||
NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/",
|
||||
"private-ipv4s")),
|
||||
HTTP_TIMEOUT_MS,
|
||||
512 * 1024,
|
||||
10000,
|
||||
1000,
|
||||
NULL,
|
||||
get_config_data->intern_cancellable,
|
||||
NULL,
|
||||
NULL,
|
||||
_get_config_fetch_done_cb_private_ipv4s,
|
||||
nm_utils_user_data_pack(get_config_data, hwaddr));
|
||||
|
||||
get_config_data->n_pending++;
|
||||
nm_http_client_poll_get(
|
||||
http_client,
|
||||
(uri3 = _aliyun_uri_interfaces(v_mac_data->path,
|
||||
NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/",
|
||||
"netmask")),
|
||||
HTTP_TIMEOUT_MS,
|
||||
512 * 1024,
|
||||
10000,
|
||||
1000,
|
||||
NULL,
|
||||
get_config_data->intern_cancellable,
|
||||
NULL,
|
||||
NULL,
|
||||
_get_config_fetch_done_cb_netmask,
|
||||
nm_utils_user_data_pack(get_config_data, hwaddr));
|
||||
}
|
||||
|
||||
_nmcs_provider_get_config_task_maybe_return(get_config_data, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_get_config_metadata_ready_check(long response_code,
|
||||
GBytes * response,
|
||||
gpointer check_user_data,
|
||||
GError **error)
|
||||
{
|
||||
NMCSProviderGetConfigTaskData *get_config_data = check_user_data;
|
||||
gs_unref_hashtable GHashTable *response_parsed = NULL;
|
||||
const guint8 * r_data;
|
||||
const char * cur_line;
|
||||
gsize r_len;
|
||||
gsize cur_line_len;
|
||||
GHashTableIter h_iter;
|
||||
gboolean has_all;
|
||||
const char * c_hwaddr;
|
||||
gssize iface_idx_counter = 0;
|
||||
|
||||
if (response_code != 200 || !response) {
|
||||
/* we wait longer. */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
r_data = g_bytes_get_data(response, &r_len);
|
||||
/* NMHttpClient guarantees that there is a trailing NUL after the data. */
|
||||
nm_assert(r_data[r_len] == 0);
|
||||
|
||||
while (nm_utils_parse_next_line((const char **) &r_data, &r_len, &cur_line, &cur_line_len)) {
|
||||
GetConfigMetadataMac *mac_data;
|
||||
char * hwaddr;
|
||||
|
||||
if (cur_line_len == 0)
|
||||
continue;
|
||||
|
||||
/* Truncate the string. It's safe to do, because we own @response an it has an
|
||||
* extra NUL character after the buffer. */
|
||||
((char *) cur_line)[cur_line_len] = '\0';
|
||||
|
||||
hwaddr = nmcs_utils_hwaddr_normalize(
|
||||
cur_line,
|
||||
cur_line[cur_line_len - 1u] == '/' ? (gssize) (cur_line_len - 1u) : -1);
|
||||
if (!hwaddr)
|
||||
continue;
|
||||
|
||||
if (!response_parsed)
|
||||
response_parsed = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free);
|
||||
|
||||
mac_data = g_malloc(sizeof(GetConfigMetadataMac) + 1u + cur_line_len);
|
||||
mac_data->iface_idx = iface_idx_counter++;
|
||||
memcpy(mac_data->path, cur_line, cur_line_len + 1u);
|
||||
|
||||
/* here we will ignore duplicate responses. */
|
||||
g_hash_table_insert(response_parsed, hwaddr, mac_data);
|
||||
}
|
||||
|
||||
has_all = TRUE;
|
||||
g_hash_table_iter_init(&h_iter, get_config_data->result_dict);
|
||||
while (g_hash_table_iter_next(&h_iter, (gpointer *) &c_hwaddr, NULL)) {
|
||||
if (!response_parsed || !g_hash_table_contains(response_parsed, c_hwaddr)) {
|
||||
has_all = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nm_clear_pointer(&get_config_data->extra_data, g_hash_table_unref);
|
||||
if (response_parsed) {
|
||||
get_config_data->extra_data = g_steal_pointer(&response_parsed);
|
||||
get_config_data->extra_data_destroy = (GDestroyNotify) g_hash_table_unref;
|
||||
}
|
||||
return has_all;
|
||||
}
|
||||
|
||||
static void
|
||||
get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_data)
|
||||
{
|
||||
gs_free char *uri = NULL;
|
||||
|
||||
/* 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),
|
||||
(uri = _aliyun_uri_interfaces()),
|
||||
HTTP_TIMEOUT_MS,
|
||||
256 * 1024,
|
||||
15000,
|
||||
1000,
|
||||
NULL,
|
||||
get_config_data->intern_cancellable,
|
||||
_get_config_metadata_ready_check,
|
||||
get_config_data,
|
||||
_get_config_metadata_ready_cb,
|
||||
get_config_data);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
nmcs_provider_aliyun_init(NMCSProviderAliyun *self)
|
||||
{}
|
||||
|
||||
static void
|
||||
nmcs_provider_aliyun_class_init(NMCSProviderAliyunClass *klass)
|
||||
{
|
||||
NMCSProviderClass *provider_class = NMCS_PROVIDER_CLASS(klass);
|
||||
|
||||
provider_class->_name = "aliyun";
|
||||
provider_class->_env_provider_enabled = NMCS_ENV_VARIABLE("NM_CLOUD_SETUP_ALIYUN");
|
||||
provider_class->detect = detect;
|
||||
provider_class->get_config = get_config;
|
||||
}
|
28
src/nm-cloud-setup/nmcs-provider-aliyun.h
Normal file
28
src/nm-cloud-setup/nmcs-provider-aliyun.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#ifndef __NMCS_PROVIDER_ALIYUN_H__
|
||||
#define __NMCS_PROVIDER_ALIYUN_H__
|
||||
|
||||
#include "nmcs-provider.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct _NMCSProviderAliyun NMCSProviderAliyun;
|
||||
typedef struct _NMCSProviderAliyunClass NMCSProviderAliyunClass;
|
||||
|
||||
#define NMCS_TYPE_PROVIDER_ALIYUN (nmcs_provider_aliyun_get_type())
|
||||
#define NMCS_PROVIDER_ALIYUN(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj), NMCS_TYPE_PROVIDER_ALIYUN, NMCSProviderAliyun))
|
||||
#define NMCS_PROVIDER_ALIYUN_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass), NMCS_TYPE_PROVIDER_ALIYUN, NMCSProviderAliyunClass))
|
||||
#define NMCS_IS_PROVIDER_ALIYUN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMCS_TYPE_PROVIDER_ALIYUN))
|
||||
#define NMCS_IS_PROVIDER_ALIYUN_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass), NMCS_TYPE_PROVIDER_ALIYUN))
|
||||
#define NMCS_PROVIDER_ALIYUN_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS((obj), NMCS_TYPE_PROVIDER_ALIYUN, NMCSProviderAliyunClass))
|
||||
|
||||
GType nmcs_provider_aliyun_get_type(void);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif /* __NMCS_PROVIDER_ALIYUN_H__ */
|
Loading…
Reference in New Issue
Block a user