Skip to content

Commit

Permalink
np2 sr setup NEW library for setup.sh
Browse files Browse the repository at this point in the history
... installing all the required SR
modules. Useful for cross-compilation.
  • Loading branch information
michalvasko committed Apr 30, 2024
1 parent c1a8e0e commit 39bf57d
Show file tree
Hide file tree
Showing 5 changed files with 370 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,9 @@ if(BUILD_CLI)
add_subdirectory(cli)
endif()

# np2 sysrepo setup lib
add_subdirectory(lib)

# source files to be covered by the 'format' target and a test with 'format-check' target
source_format(${FORMAT_SRC})

Expand Down
28 changes: 28 additions & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
if(NOT NP2SRV_VERSION)
message(FATAL_ERROR "Please use the root CMakeLists file instead.")
endif()

project(np2_sr_setup C)

# source files
set(LIB_SRC
np2_sr_setup.c)

# generate YANG header files
add_custom_command(OUTPUT np2_sr_yang.h
COMMAND ${CMAKE_COMMAND} -E env
NP2_MODULE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/../modules
LN2_MODULE_DIR=${LN2_YANG_MODULE_DIR}
NP2_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/generate.sh
COMMENT "Generating YANG header files (generate.sh)..."
)

include_directories(${CMAKE_CURRENT_BINARY_DIR})

# lib target
add_library(np2_sr_setup ${LIB_SRC} np2_sr_yang.h)

# reuse server variables
target_link_libraries(np2_sr_setup ${LIBYANG_LIBRARIES})
target_link_libraries(np2_sr_setup ${SYSREPO_LIBRARIES})
112 changes: 112 additions & 0 deletions lib/generate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/usr/bin/env bash

if [ -z "$NP2_MODULE_DIR" -o -z "$LN2_MODULE_DIR" -o -z "$NP2_BINARY_DIR" ]; then
echo "Required environment variables not defined!"
exit 1
fi


# start the YANG array
MAIN_YANG_ARRAY="
struct {
const char *file;
const char *data;
int len;
} yang_files[] = {
"

# generate headers from all the YANG modules
NP2_MODDIR=${DESTDIR}${NP2_MODULE_DIR}
LN2_MODDIR=${DESTDIR}${LN2_MODULE_DIR}
BINDIR=${DESTDIR}${NP2_BINARY_DIR}
for YANG_PATH in ${NP2_MODDIR}/*.yang ${LN2_MODDIR}/*.yang; do
# get module name
YANG_FILE="$(basename "${YANG_PATH}")"

if [[ "$MAIN_YANG_ARRAY" =~ "\"$YANG_FILE\"" ]]; then
# duplicate module
continue
fi

# generate HEX
HEX=$(echo "$(cat "${YANG_PATH}")" | xxd -i -c1)
LENGTH=$((${#HEX}/8))

# generate array name
ARRAY_NAME="$(echo "${YANG_FILE}" | tr -- "-@." "_")"

# generate header file name without the revision
HEADER_FILE="${ARRAY_NAME}.h"

# print into a C header file
echo -e "const char ${ARRAY_NAME}[] = {\n$HEX\n};\nconst int ${ARRAY_NAME}_l = ${LENGTH};" > "${BINDIR}/${HEADER_FILE}"

# build all the include lines in the main header
MAIN_INCLUDE_LINES="${MAIN_INCLUDE_LINES}#include \"${HEADER_FILE}\"\n"

# build the array of modules
MAIN_YANG_ARRAY="${MAIN_YANG_ARRAY} {.file = \"${YANG_FILE}\", .data = ${ARRAY_NAME}, .len = ${ARRAY_NAME}_l},\n"
done

# end the YANG array
MAIN_YANG_ARRAY="${MAIN_YANG_ARRAY} {.file = NULL, .data = NULL}\n};\n\n"


# import module arrays
cur_dir=$(dirname "$0")
source "${cur_dir}/../scripts/common.sh"

# start install and feature arrays
MAIN_FEATURE_ARRAY="const char **yang_features[] = {\n"
MAIN_INSTALL_ARRAY="const char *yang_install[] = {\n"
COUNT=0

# generate install and features arrays
for LINE in "${NP2_MODULES[@]}" "${LN2_MODULES[@]}"; do
((COUNT+=1))

# get file and array name
FILE="$(echo "$LINE" | sed 's/\([^ ]*\).*/\1/')"
ARRAY_NAME="$(echo "${FILE}" | tr -- "-@." "_")_f"

# generate feature array
HAS_FEATURES=$(echo "$LINE" | grep " -e ")
if [ -z "$HAS_FEATURES" ]; then
FEATURES="NULL"
else
FEATURES="${ARRAY_NAME}"
MOD_FEATURES="const char *${ARRAY_NAME}[] = {"
LINE=$(echo "$LINE" | sed 's/[^ ]* \(.*\)/\1/')
while [ "${LINE:0:3}" = "-e " ]; do
# skip "-e "
LINE=${LINE:3}
# parse feature
FEATURE=$(echo "$LINE" | sed 's/\([^ ]*\).*/\1/')

MOD_FEATURES="$MOD_FEATURES\"$FEATURE\", "

# next iteration, skip this feature
LINE=$(echo "$LINE" | sed 's/[^ ]* \(.*\)/\1/')
done
MOD_FEATURES="${MOD_FEATURES}NULL}"

MAIN_FEATURE_MODS="${MAIN_FEATURE_MODS}${MOD_FEATURES};\n"
fi

MAIN_FEATURE_ARRAY="${MAIN_FEATURE_ARRAY} ${FEATURES},\n"
MAIN_INSTALL_ARRAY="${MAIN_INSTALL_ARRAY} \"${FILE}\",\n"
done

# end install and feature array
MAIN_FEATURE_ARRAY="${MAIN_FEATURE_ARRAY}};\n\n"
MAIN_INSTALL_ARRAY="${MAIN_INSTALL_ARRAY}};\n"

MAIN_INSTALL_COUNT="int yang_install_count = ${COUNT};"

# generate the main header
echo -e "#include <stdlib.h>\n\n${MAIN_INCLUDE_LINES}\
${MAIN_YANG_ARRAY}\
${MAIN_FEATURE_MODS}\
${MAIN_FEATURE_ARRAY}\
${MAIN_INSTALL_ARRAY}\
${MAIN_INSTALL_COUNT}" > "${BINDIR}/np2_sr_yang.h"
192 changes: 192 additions & 0 deletions lib/np2_sr_setup.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/**
* @file np2_sr_setup.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief netopeer2-server sysrepo YANG module setup library
*
* @copyright
* Copyright (c) 2024 Deutsche Telekom AG.
* Copyright (c) 2024 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

#include <libyang/libyang.h>
#include <sysrepo.h>

#include "np2_sr_yang.h"

#define ERR(msg, ...) fprintf(stderr, msg "\n", __VA_ARGS__)
#define ERRMSG(msg) fprintf(stderr, msg "\n")

/**
* @brief Check a module in the specific revision and all the features is not already installed.
*
* @param[in] file YANG module file name.
* @param[in] features Array of enabled features.
* @param[in] conn Sysrepo connection to use.
* @param[out] processed Whether the module needs tobe installed or was processed.
* @return 0 on success.
* @return non-zero on error.
*/
static int
np2_sr_setup_mod_check(const char *file, const char **features, sr_conn_ctx_t *conn, int *processed)
{
int rc = 0, i, r;
const struct ly_ctx *ctx = sr_acquire_context(conn);
const struct lys_module *mod;
const char *ptr;
char *name = NULL, *revision = NULL;
LY_ERR lyrc;

*processed = 0;

/* parse name and revision */
ptr = strchr(file, '@');
name = strndup(file, ptr - file);
++ptr;
revision = strndup(ptr, strlen(ptr) - 5);
if (!name || !revision) {
ERRMSG("Failed to allocate memory.");
rc = 1;
goto cleanup;
}

/* check the file is installed */
mod = ly_ctx_get_module_implemented(ctx, name);
if (!mod) {
goto cleanup;
}
if (!revision || strcmp(mod->revision, revision)) {
/* different revision, will fail during installation */
goto cleanup;
}

/* we will adjust enabled features */
*processed = 1;

if (!features) {
goto cleanup;
}

/* check/enable all the features */
for (i = 0; features[i]; ++i) {
lyrc = lys_feature_value(mod, features[i]);
if (lyrc == LY_ENOTFOUND) {
ERR("Failed to find feature \"%s\" in \"%s\".", features[i], name);
rc = 1;
goto cleanup;
}

if (lyrc == LY_ENOT) {
/* enable feature, context will be changed */
sr_release_context(conn);
r = sr_enable_module_feature(conn, name, features[i]);
ctx = sr_acquire_context(conn);

if (r) {
ERR("Failed to enable feature \"%s\" in \"%s\".", features[i], name);
rc = 1;
goto cleanup;
}

mod = ly_ctx_get_module_implemented(ctx, name);
}
}

cleanup:
sr_release_context(conn);
free(name);
free(revision);
return rc;
}

int
np2_sr_setup(const char *owner, const char *group, mode_t perm)
{
int rc = 0, fd, r, i, mod_count;
sr_conn_ctx_t *conn = NULL;
sr_install_mod_t *mods = NULL;

/* log */
sr_log_stderr(SR_LL_WRN);

/* connect */
if (sr_connect(0, &conn)) {
ERRMSG("Failed to connect to sysrepo.");
rc = 1;
goto cleanup;
}

/* print all the modules into files */
for (i = 0; yang_files[i].file; ++i) {
fd = open(yang_files[i].file, O_WRONLY | O_CREAT | O_TRUNC, 00600);
if (fd < 0) {
ERR("Failed to create \"%s\".", yang_files[i].file);
rc = 1;
goto cleanup;
}

r = write(fd, yang_files[i].data, yang_files[i].len);
close(fd);

if (r != yang_files[i].len) {
ERR("Failed to write \"%s\".", yang_files[i].file);
rc = 1;
goto cleanup;
}
}

/* prepare modules to install */
mods = calloc(yang_install_count, sizeof *mods);
if (!mods) {
ERRMSG("Failed to allocate memory.");
rc = 1;
goto cleanup;
}
mod_count = 0;
for (i = 0; i < yang_install_count; ++i) {
/* first check that the module is not installed already and all its features enabled */
if (np2_sr_setup_mod_check(yang_install[i], yang_features[i], conn, &r)) {
rc = 1;
goto cleanup;
}
if (r) {
continue;
}

mods[mod_count].schema_path = yang_install[i];
mods[mod_count].features = yang_features[i];
mods[mod_count].owner = owner;
mods[mod_count].group = group;
mods[mod_count].perm = perm;

++mod_count;
}

/* install modules */
if (sr_install_modules2(conn, mods, mod_count, ".", NULL, NULL, 0)) {
ERRMSG("Failed to install modules.");
rc = 1;
goto cleanup;
}

cleanup:
free(mods);
sr_disconnect(conn);
for (i = 0; yang_files[i].file; ++i) {
unlink(yang_files[i].file);
}
return rc;
}
35 changes: 35 additions & 0 deletions lib/np2_sr_setup.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @file np2_sr_setup.h
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief netopeer2-server sysrepo YANG module setup library header
*
* @copyright
* Copyright (c) 2024 Deutsche Telekom AG.
* Copyright (c) 2024 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/

#ifndef NP2_SR_SETUP_H_
#define NP2_SR_SETUP_H_

#include <sys/stat.h>

/**
* @brief Install all YANG modules required by netopeer2-server into sysrepo.
*
* Logs to stderr.
*
* @param[in] owner Optional owner of the installed modules, process user by default.
* @param[in] group Optional group of the installed modules, process group or configured sysrepo group by default.
* @param[in] perm Optional specific permissions of the installed modules.
* @return 0 on success.
* @return non-zero on error.
*/
int np2_sr_setup(const char *owner, const char *group, mode_t perm);

#endif /* NP2_SR_SETUP_H_ */

0 comments on commit 39bf57d

Please sign in to comment.