merge: branch 'ih/nmcs-oci'
cloud-setup: Add OCI (Oracle Cloud) provider https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2056
This commit is contained in:
1
NEWS
1
NEWS
@@ -22,6 +22,7 @@ USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE!
|
||||
* Support automatically adding routes to DNS servers via the
|
||||
ipv4.routed-dns and ipv6.routed-dns properties; when enabled, each
|
||||
name server is reached only via the device that specifies it.
|
||||
* Support OCI in nm-cloud-setup
|
||||
|
||||
=============================================
|
||||
NetworkManager-1.50
|
||||
|
@@ -184,6 +184,10 @@
|
||||
<para><literal>NM_CLOUD_SETUP_ALIYUN</literal>: boolean, whether Alibaba Cloud (Aliyun) support is enabled. Defaults
|
||||
to <literal>no</literal>.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>NM_CLOUD_SETUP_OCI</literal>: boolean, whether Oracle Cloud (OCI) support is enabled. Defaults
|
||||
to <literal>no</literal>.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
</refsect1>
|
||||
@@ -417,6 +421,34 @@ ln -s /etc/systemd/system/timers.target.wants/nm-cloud-setup.timer /usr/lib/syst
|
||||
</itemizedlist>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Oracle Cloud (OCI)</title>
|
||||
|
||||
<para>For OCI, the tools tries to fetch configuration from <literal>http://169.254.169.254/</literal>. Currently, it only
|
||||
configures IPv4 and does nothing about IPv6. It will do the following.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>First fetch <literal>http://169.254.169.254/opc/v2/instance</literal> to determine whether the
|
||||
expected API is present. This determines whether OCI environment is detected and whether to proceed
|
||||
to configure the host using OCI meta data.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Fetch <literal>http://169.254.169.254/opc/v2/vnics</literal> to get the configuration
|
||||
for all the VNICs, getting their MAC address, private IP address, gateway and subnet block.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Then nm-cloud-setup iterates over all interfaces for which it could fetch a 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. Also, there is only one interface and one IP address, the tool does nothing.</para>
|
||||
<para>Then the tool configures the system like doing for AWS environment. That is, using source based policy routing
|
||||
with the tables/rules 30200/30400.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</refsect2>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@@ -800,6 +800,7 @@ endif
|
||||
enable_nm_cloud_setup = get_option('nm_cloud_setup')
|
||||
if enable_nm_cloud_setup
|
||||
assert(libcurl_dep.found(), 'nm-cloud-setup requires libcurl library. Use -Dnm_cloud_setup=false to disable it')
|
||||
assert(jansson_dep.found(), 'nm-cloud-setup requires jansson library. Use -Dnm_cloud_setup=false to disable it')
|
||||
endif
|
||||
|
||||
enable_docs = get_option('docs')
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include "nmcs-provider-gcp.h"
|
||||
#include "nmcs-provider-azure.h"
|
||||
#include "nmcs-provider-aliyun.h"
|
||||
#include "nmcs-provider-oci.h"
|
||||
#include "libnm-core-aux-intern/nm-libnm-core-utils.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -104,6 +105,7 @@ _provider_detect(SigTermData *sigterm_data)
|
||||
NMCS_TYPE_PROVIDER_GCP,
|
||||
NMCS_TYPE_PROVIDER_AZURE,
|
||||
NMCS_TYPE_PROVIDER_ALIYUN,
|
||||
NMCS_TYPE_PROVIDER_OCI,
|
||||
};
|
||||
int i;
|
||||
gulong cancellable_signal_id;
|
||||
|
@@ -36,12 +36,14 @@ libnm_cloud_setup_core = static_library(
|
||||
'nmcs-provider-gcp.c',
|
||||
'nmcs-provider-azure.c',
|
||||
'nmcs-provider-aliyun.c',
|
||||
'nmcs-provider-oci.c',
|
||||
'nmcs-provider.c',
|
||||
),
|
||||
dependencies: [
|
||||
libnm_dep,
|
||||
glib_dep,
|
||||
libcurl_dep,
|
||||
jansson_dep,
|
||||
],
|
||||
)
|
||||
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#define NMCS_ENV_NM_CLOUD_SETUP_AZURE "NM_CLOUD_SETUP_AZURE"
|
||||
#define NMCS_ENV_NM_CLOUD_SETUP_EC2 "NM_CLOUD_SETUP_EC2"
|
||||
#define NMCS_ENV_NM_CLOUD_SETUP_GCP "NM_CLOUD_SETUP_GCP"
|
||||
#define NMCS_ENV_NM_CLOUD_SETUP_OCI "NM_CLOUD_SETUP_OCI"
|
||||
#define NMCS_ENV_NM_CLOUD_SETUP_LOG "NM_CLOUD_SETUP_LOG"
|
||||
|
||||
/* Undocumented/internal environment variables for configuring nm-cloud-setup.
|
||||
@@ -20,6 +21,7 @@
|
||||
#define NMCS_ENV_NM_CLOUD_SETUP_AZURE_HOST "NM_CLOUD_SETUP_AZURE_HOST"
|
||||
#define NMCS_ENV_NM_CLOUD_SETUP_EC2_HOST "NM_CLOUD_SETUP_EC2_HOST"
|
||||
#define NMCS_ENV_NM_CLOUD_SETUP_GCP_HOST "NM_CLOUD_SETUP_GCP_HOST"
|
||||
#define NMCS_ENV_NM_CLOUD_SETUP_OCI_HOST "NM_CLOUD_SETUP_OCI_HOST"
|
||||
#define NMCS_ENV_NM_CLOUD_SETUP_MAP_INTERFACES "NM_CLOUD_SETUP_MAP_INTERFACES"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@@ -31,6 +31,7 @@ ExecStart=@libexecdir@/nm-cloud-setup
|
||||
#Environment=NM_CLOUD_SETUP_GCP=yes
|
||||
#Environment=NM_CLOUD_SETUP_AZURE=yes
|
||||
#Environment=NM_CLOUD_SETUP_ALIYUN=yes
|
||||
#Environment=NM_CLOUD_SETUP_OCI=yes
|
||||
|
||||
CapabilityBoundingSet=
|
||||
KeyringMode=private
|
||||
|
221
src/nm-cloud-setup/nmcs-provider-oci.c
Normal file
221
src/nm-cloud-setup/nmcs-provider-oci.c
Normal file
@@ -0,0 +1,221 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "libnm-client-aux-extern/nm-default-client.h"
|
||||
#include "nmcs-provider-oci.h"
|
||||
#include "nm-cloud-setup-utils.h"
|
||||
#include "libnm-glib-aux/nm-jansson.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define HTTP_TIMEOUT_MS 3000
|
||||
|
||||
#define NM_OCI_HEADER "Authorization:Bearer Oracle"
|
||||
#define NM_OCI_HOST "169.254.169.254"
|
||||
#define NM_OCI_BASE "http://" NM_OCI_HOST
|
||||
|
||||
NMCS_DEFINE_HOST_BASE(_oci_base, NMCS_ENV_NM_CLOUD_SETUP_OCI_HOST, NM_OCI_BASE);
|
||||
|
||||
#define _oci_uri_concat(...) nmcs_utils_uri_build_concat(_oci_base(), "opc/v2/", __VA_ARGS__)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct _NMCSProviderOCI {
|
||||
NMCSProvider parent;
|
||||
};
|
||||
|
||||
struct _NMCSProviderOCIClass {
|
||||
NMCSProviderClass parent;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(NMCSProviderOCI, nmcs_provider_oci, NMCS_TYPE_PROVIDER);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
_detect_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_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));
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_error) {
|
||||
nm_utils_error_set(&error,
|
||||
NM_UTILS_ERROR_UNKNOWN,
|
||||
"failure to get OCI instance data: %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_req(http_client,
|
||||
(uri = _oci_uri_concat("instance")),
|
||||
HTTP_TIMEOUT_MS,
|
||||
256 * 1024,
|
||||
7000,
|
||||
1000,
|
||||
NM_MAKE_STRV(NM_OCI_HEADER),
|
||||
NULL,
|
||||
g_task_get_cancellable(task),
|
||||
NULL,
|
||||
NULL,
|
||||
_detect_done_cb,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
_get_config_done_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
NMCSProviderGetConfigTaskData *get_config_data;
|
||||
NMCSProviderGetConfigIfaceData *config_iface_data;
|
||||
gs_unref_bytes GBytes *response = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
nm_auto_decref_json json_t *vnics = NULL;
|
||||
size_t i;
|
||||
|
||||
nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error);
|
||||
|
||||
if (nm_utils_error_is_cancelled(error))
|
||||
return;
|
||||
|
||||
get_config_data = user_data;
|
||||
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
vnics = json_loads(g_bytes_get_data(response, NULL), JSON_REJECT_DUPLICATES, NULL);
|
||||
if (!vnics || !json_is_array(vnics)) {
|
||||
nm_utils_error_set(&error,
|
||||
NM_UTILS_ERROR_UNKNOWN,
|
||||
"get-config: JSON parse failure, can't configure VNICs");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < json_array_size(vnics); i++) {
|
||||
json_t *vnic, *field;
|
||||
const char *vnic_id, *val;
|
||||
gs_free char *mac = NULL;
|
||||
in_addr_t addr;
|
||||
int prefix;
|
||||
|
||||
vnic = json_array_get(vnics, i);
|
||||
if (!json_is_object(vnic)) {
|
||||
_LOGW("get-config: JSON parse failure for VNIC at index %zu, ignoring VNIC", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
field = json_object_get(vnic, "vnicId");
|
||||
vnic_id = field && json_is_string(field) ? json_string_value(field) : "";
|
||||
|
||||
field = json_object_get(vnic, "macAddr");
|
||||
val = field && json_is_string(field) ? json_string_value(field) : NULL;
|
||||
if (!val) {
|
||||
_LOGW("get-config: missing or invalid 'macAddr' (VNIC %s idx=%zu), ignoring VNIC",
|
||||
vnic_id,
|
||||
i);
|
||||
continue;
|
||||
}
|
||||
|
||||
mac = nmcs_utils_hwaddr_normalize(val, json_string_length(field));
|
||||
config_iface_data = nmcs_provider_get_config_iface_data_create(get_config_data, FALSE, mac);
|
||||
config_iface_data->iface_idx = i;
|
||||
|
||||
field = json_object_get(vnic, "privateIp");
|
||||
val = field && json_is_string(field) ? json_string_value(field) : NULL;
|
||||
if (val && nm_inet_parse_bin(AF_INET, val, NULL, &addr)) {
|
||||
config_iface_data->has_ipv4s = TRUE;
|
||||
config_iface_data->ipv4s_len = 1;
|
||||
config_iface_data->ipv4s_arr = g_new(in_addr_t, 1);
|
||||
config_iface_data->ipv4s_arr[0] = addr;
|
||||
} else {
|
||||
_LOGW("get-config: missing or invalid 'privateIp' (VNIC %s idx=%zu)", vnic_id, i);
|
||||
}
|
||||
|
||||
field = json_object_get(vnic, "virtualRouterIp");
|
||||
val = field && json_is_string(field) ? json_string_value(field) : NULL;
|
||||
if (val && nm_inet_parse_bin(AF_INET, val, NULL, &addr)) {
|
||||
config_iface_data->has_gateway = TRUE;
|
||||
config_iface_data->gateway = addr;
|
||||
} else {
|
||||
_LOGW("get-config: missing or invalid 'virtualRouterIp' (VNIC %s idx=%zu)", vnic_id, i);
|
||||
}
|
||||
|
||||
field = json_object_get(vnic, "subnetCidrBlock");
|
||||
val = field && json_is_string(field) ? json_string_value(field) : NULL;
|
||||
if (val && nm_inet_parse_with_prefix_bin(AF_INET, val, NULL, &addr, &prefix)) {
|
||||
config_iface_data->has_cidr = TRUE;
|
||||
config_iface_data->cidr_addr = addr;
|
||||
config_iface_data->cidr_prefix = prefix;
|
||||
} else {
|
||||
_LOGW("get-config: missing or invalid 'subnetCidrBlock' (VNIC %s idx=%zu)", vnic_id, i);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
_nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error));
|
||||
}
|
||||
|
||||
static void
|
||||
get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_data)
|
||||
{
|
||||
gs_free const char *uri = NULL;
|
||||
|
||||
nm_http_client_poll_req(nmcs_provider_get_http_client(provider),
|
||||
(uri = _oci_uri_concat("vnics")),
|
||||
HTTP_TIMEOUT_MS,
|
||||
256 * 1024,
|
||||
15000,
|
||||
1000,
|
||||
NM_MAKE_STRV(NM_OCI_HEADER),
|
||||
NULL,
|
||||
get_config_data->intern_cancellable,
|
||||
NULL,
|
||||
NULL,
|
||||
_get_config_done_cb,
|
||||
get_config_data);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
nmcs_provider_oci_init(NMCSProviderOCI *self)
|
||||
{}
|
||||
|
||||
static void
|
||||
dispose(GObject *object)
|
||||
{
|
||||
G_OBJECT_CLASS(nmcs_provider_oci_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void
|
||||
nmcs_provider_oci_class_init(NMCSProviderOCIClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
NMCSProviderClass *provider_class = NMCS_PROVIDER_CLASS(klass);
|
||||
|
||||
object_class->dispose = dispose;
|
||||
|
||||
provider_class->_name = "oci";
|
||||
provider_class->_env_provider_enabled = NMCS_ENV_NM_CLOUD_SETUP_OCI;
|
||||
provider_class->detect = detect;
|
||||
provider_class->get_config = get_config;
|
||||
}
|
27
src/nm-cloud-setup/nmcs-provider-oci.h
Normal file
27
src/nm-cloud-setup/nmcs-provider-oci.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#ifndef __NMCS_PROVIDER_OCI_H__
|
||||
#define __NMCS_PROVIDER_OCI_H__
|
||||
|
||||
#include "nmcs-provider.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct _NMCSProviderOCI NMCSProviderOCI;
|
||||
typedef struct _NMCSProviderOCIClass NMCSProviderOCIClass;
|
||||
|
||||
#define NMCS_TYPE_PROVIDER_OCI (nmcs_provider_oci_get_type())
|
||||
#define NMCS_PROVIDER_OCI(obj) \
|
||||
(_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NMCS_TYPE_PROVIDER_OCI, NMCSProviderOCI))
|
||||
#define NMCS_PROVIDER_OCI_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass), NMCS_TYPE_PROVIDER_OCI, NMCSProviderOCIClass))
|
||||
#define NMCS_IS_PROVIDER_OCI(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMCS_TYPE_PROVIDER_OCI))
|
||||
#define NMCS_IS_PROVIDER_OCI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NMCS_TYPE_PROVIDER_OCI))
|
||||
#define NMCS_PROVIDER_OCI_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS((obj), NMCS_TYPE_PROVIDER_OCI, NMCSProviderOCIClass))
|
||||
|
||||
GType nmcs_provider_oci_get_type(void);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif /* __NMCS_PROVIDER_OCI_H__ */
|
Reference in New Issue
Block a user