Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

YAML consolidation prelude: new YAML dump APIs (FR-702) #251

Merged
merged 3 commits into from
Jan 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions include/netplan.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,13 @@ netplan_state_get_netdefs_size(const NetplanState* np_state);
NETPLAN_PUBLIC NetplanNetDefinition*
netplan_state_get_netdef(const NetplanState* np_state, const char* id);

/* Dump the whole yaml configuration into the given file, regardless of the origin
* of each definition.
*/
NETPLAN_PUBLIC gboolean
netplan_state_write_yaml(
netplan_state_dump_yaml(
const NetplanState* np_state,
const char* file_hint,
const char* rootdir,
int output_fd,
GError** error);

NETPLAN_PUBLIC gboolean
Expand Down
18 changes: 18 additions & 0 deletions netplan/libnetplan.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ def _load_abi(cls):
lib.netplan_state_get_netdef.argtypes = [_NetplanStateP, c_char_p]
lib.netplan_state_get_netdef.restype = _NetplanNetDefinitionP

lib.netplan_state_dump_yaml.argtypes = [_NetplanStateP, c_int, _GErrorPP]
lib.netplan_state_dump_yaml.restype = c_int

cls._abi_loaded = True

def __init__(self):
Expand All @@ -139,6 +142,10 @@ def __del__(self):
def import_parser_results(self, parser):
_checked_lib_call(lib.netplan_state_import_parser_results, self._ptr, parser._ptr)

def dump_yaml(self, output_file):
fd = output_file.fileno()
_checked_lib_call(lib.netplan_state_dump_yaml, self._ptr, fd)

def __len__(self):
return lib.netplan_state_get_netdefs_size(self._ptr)

Expand Down Expand Up @@ -242,3 +249,14 @@ def netplan_get_ids_for_devtype(devtype, rootdir):
raise Exception(err.contents.message.decode('utf-8'))
nds = list(_NetdefIterator(__GlobalState(), devtype))
return [nd.id for nd in nds]


lib.netplan_util_dump_yaml_subtree.argtypes = [c_char_p, c_int, c_int, _GErrorPP]
lib.netplan_util_dump_yaml_subtree.restype = c_int


def dump_yaml_subtree(prefix, input_file, output_file):
_checked_lib_call(lib.netplan_util_dump_yaml_subtree,
prefix.encode('utf-8'),
input_file.fileno(),
output_file.fileno())
10 changes: 9 additions & 1 deletion src/abi_compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <glib.h>
#include <glib/gstdio.h>
#include <errno.h>
#include <fcntl.h>

/* These arrays are not useful per-say, but allow us to export the various
* struct offsets of the netplan_state members to the linker, which can use
Expand Down Expand Up @@ -228,8 +229,15 @@ netplan_state_write_yaml(const NetplanState* np_state, const char* file_hint, co
NETPLAN_ABI void
write_netplan_conf_full(const char* file_hint, const char* rootdir)
{
g_autofree gchar *path = NULL;
netplan_finish_parse(NULL);
netplan_state_write_yaml(&global_state, file_hint, rootdir, NULL);
if (!netplan_state_has_nondefault_globals(&global_state) &&
!netplan_state_get_netdefs_size(&global_state))
return;
path = g_build_path(G_DIR_SEPARATOR_S, rootdir ?: G_DIR_SEPARATOR_S, "etc", "netplan", file_hint, NULL);
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640);
netplan_state_dump_yaml(&global_state, fd, NULL);
close(fd);
}

NETPLAN_PUBLIC gboolean
Expand Down
75 changes: 36 additions & 39 deletions src/netplan.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@
*/

#include <glib.h>
#include <glib/gstdio.h>
#include <yaml.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#include "netplan.h"
#include "parse.h"
#include "types.h"
#include "yaml-helpers.h"
#include "util-internal.h"
#include "names.h"

gchar *tmp = NULL;
Expand Down Expand Up @@ -491,21 +497,6 @@ write_routes(yaml_event_t* event, yaml_emitter_t* emitter, const NetplanNetDefin
err_path: return FALSE; // LCOV_EXCL_LINE
}

static gboolean
has_openvswitch(const NetplanOVSSettings* ovs, NetplanBackend backend, GHashTable *ovs_ports) {
return (ovs_ports && g_hash_table_size(ovs_ports) > 0)
|| (ovs->external_ids && g_hash_table_size(ovs->external_ids) > 0)
|| (ovs->other_config && g_hash_table_size(ovs->other_config) > 0)
|| ovs->lacp
|| ovs->fail_mode
|| ovs->mcast_snooping
|| ovs->rstp
|| ovs->protocols
|| (ovs->ssl.ca_certificate || ovs->ssl.client_certificate || ovs->ssl.client_key)
|| (ovs->controller.connection_mode || ovs->controller.addresses)
|| backend == NETPLAN_BACKEND_OVS;
}

static gboolean
write_openvswitch(yaml_event_t* event, yaml_emitter_t* emitter, const NetplanOVSSettings* ovs, NetplanBackend backend, GHashTable *ovs_ports)
{
Expand Down Expand Up @@ -890,38 +881,25 @@ contains_netdef_type(gconstpointer value, gconstpointer user_data)
return nd->type == *type ? 0 : -1;
}

/**
* Generate the Netplan YAML configuration for all netdefs in the state
* @np_state: the state for which to generate the config
* @file_hint: Name hint for the generated output YAML file
* @rootdir: If not %NULL, generate configuration in this root directory
* (useful for testing).
*/
NETPLAN_INTERNAL gboolean
netplan_state_write_yaml(const NetplanState* np_state, const char* file_hint, const char* rootdir, GError** error)
static gboolean
netplan_netdef_list_write_yaml(const NetplanState* np_state, GList* netdefs, int out_fd, GError** error)
{
g_autofree gchar *path = NULL;
GHashTable *ovs_ports = NULL;
GList* netdefs = np_state->netdefs_ordered;

gboolean global_values = (np_state->backend != NETPLAN_BACKEND_NONE
|| has_openvswitch(&np_state->ovs_settings, NETPLAN_BACKEND_NONE, NULL));

if (!global_values && netplan_state_get_netdefs_size(np_state) == 0) {
g_debug("No data/netdefs to serialize into YAML.");
return TRUE;
}

path = g_build_path(G_DIR_SEPARATOR_S, rootdir ?: G_DIR_SEPARATOR_S, "etc", "netplan", file_hint, NULL);
int dup_fd = dup(out_fd);
if (dup_fd < 0)
goto file_error; // LCOV_EXCL_LINE
FILE* out_stream = fdopen(dup_fd, "w");
if (!out_stream)
goto file_error;

/* Start rendering YAML output */
yaml_emitter_t emitter_data;
yaml_event_t event_data;
yaml_emitter_t* emitter = &emitter_data;
yaml_event_t* event = &event_data;
FILE *output = fopen(path, "wb");

YAML_OUT_START(event, emitter, output);
YAML_OUT_START(event, emitter, out_stream);
/* build the netplan boilerplate YAML structure */
YAML_SCALAR_PLAIN(event, emitter, "network");
YAML_MAPPING_OPEN(event, emitter);
Expand Down Expand Up @@ -973,16 +951,35 @@ netplan_state_write_yaml(const NetplanState* np_state, const char* file_hint, co

/* Tear down the YAML emitter */
YAML_OUT_STOP(event, emitter);
fclose(output);
fclose(out_stream);
return TRUE;

// LCOV_EXCL_START
err_path:
g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "Error generating YAML: %s", emitter->problem);
yaml_emitter_delete(emitter);
fclose(output);
fclose(out_stream);
return FALSE;
// LCOV_EXCL_STOP

file_error:
g_set_error(error, G_FILE_ERROR, errno, "%s", strerror(errno));
return FALSE;
}

/**
* Dump the whole state into a single YAML file.
*
* @np_state: the state for which to generate the config
* @out_fd: File descriptor to an opened file into which to dump the content
*/
gboolean
netplan_state_dump_yaml(const NetplanState* np_state, int out_fd, GError** error)
{
if (!np_state->netdefs_ordered && !netplan_state_has_nondefault_globals(np_state))
return TRUE;

return netplan_netdef_list_write_yaml(np_state, np_state->netdefs_ordered, out_fd, error);
}

/* XXX: implement the following functions, once needed:
Expand Down
8 changes: 8 additions & 0 deletions src/types.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <glib.h>
#include "types.h"
#include "util-internal.h"

#define FREE_AND_NULLIFY(ptr) { g_free(ptr); ptr = NULL; }

Expand Down Expand Up @@ -436,3 +437,10 @@ netplan_netdef_get_id(const NetplanNetDefinition* netdef)

NETPLAN_INTERNAL const char*
_netplan_netdef_id(NetplanNetDefinition* netdef) __attribute__((alias("netplan_netdef_get_id")));

gboolean
netplan_state_has_nondefault_globals(const NetplanState* np_state)
{
return (np_state->backend != NETPLAN_BACKEND_NONE)
|| has_openvswitch(&np_state->ovs_settings, NETPLAN_BACKEND_NONE, NULL);
}
3 changes: 3 additions & 0 deletions src/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -511,3 +511,6 @@ ip_rule_clear(NetplanIPRule** rule);

void
route_clear(NetplanIPRoute** route);

gboolean
netplan_state_has_nondefault_globals(const NetplanState* np_state);
3 changes: 3 additions & 0 deletions src/util-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,6 @@ process_input_file(const char* f);

NETPLAN_INTERNAL gboolean
process_yaml_hierarchy(const char* rootdir);

gboolean
has_openvswitch(const NetplanOVSSettings* ovs, NetplanBackend backend, GHashTable *ovs_ports);
Loading