Merge pull request #6679 from rgerhards/codex/config-translate-mode

[codex] runtime: add config translation mode
This commit is contained in:
Rainer Gerhards 2026-04-03 10:31:18 +02:00 committed by GitHub
commit 20f521a1c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 1839 additions and 34 deletions

View File

@ -18,7 +18,7 @@ EXTRA_DIST = \
contrib/gnutls/cert.pem \
contrib/gnutls/key.pem
SUBDIRS = doc compat runtime grammar . plugins/immark plugins/imuxsock plugins/imtcp plugins/imudp plugins/omtesting
SUBDIRS = doc compat grammar runtime . plugins/immark plugins/imuxsock plugins/imtcp plugins/imudp plugins/omtesting
# external plugin driver is always enabled (core component)
SUBDIRS += plugins/mmexternal

View File

@ -89,6 +89,7 @@
#include "ruleset.h"
#include "parserif.h"
#include "statsobj.h"
#include "runtime/translate.h"
/* AIXPORT : cs renamed to legacy_cs as clashes with libpthreads variable in complete file*/
#ifdef _AIX
@ -302,6 +303,8 @@ rsRetVal actionDestruct(action_t *const pThis) {
if (!strcmp((char *)modGetName(pThis->pMod), "builtin:omdiscard")) {
/* discard actions will be optimized out */
nvlstDestruct(pThis->pSyntaxLst);
pThis->pSyntaxLst = NULL;
FINALIZE;
}
@ -321,6 +324,7 @@ rsRetVal actionDestruct(action_t *const pThis) {
free((void *)pThis->pszErrFile);
free((void *)pThis->pszExternalStateFile);
free(pThis->pszName);
nvlstDestruct(pThis->pSyntaxLst);
free(pThis->ppTpl);
free(pThis->peParamPassing);
freeWrkrDataTable(pThis);
@ -2217,6 +2221,9 @@ rsRetVal addAction(action_t **ppAction,
CHKiRet(actionConstruct(&pAction)); /* create action object first */
pAction->pMod = pMod;
pAction->pModData = pModData;
if (rsconfTranslateEnabled() && lst != NULL && pAction->pSyntaxLst == NULL) {
pAction->pSyntaxLst = rsconfTranslateCloneNvlst(lst);
}
if (actParams == NULL) { /* use legacy systemn */
pAction->pszName = cs.pszActionName;
pAction->iResumeInterval = cs.glbliActionResumeInterval;

View File

@ -82,6 +82,7 @@ struct action_s {
time_t tLastOccur; /* time last occurrence was seen (for timing them out) */
struct modInfo_s *pMod; /* pointer to output module handling this selector */
void *pModData; /* pointer to module data - content is module-specific */
struct nvlst *pSyntaxLst; /* cloned config syntax for translation/export */
sbool bRepMsgHasMsg; /* "message repeated..." has msg fragment in it (0-no, 1-yes) */
rsRetVal (*submitToActQ)(action_t *, wti_t *, smsg_t *); /* function submit message to action queue */
rsRetVal (*qConstruct)(struct queue_s *pThis);

View File

@ -4904,7 +4904,11 @@ struct cnfstmt *cnfstmtNewUnset(char *var) {
}
struct cnfstmt *cnfstmtNewContinue(void) {
return cnfstmtNew(S_NOP);
struct cnfstmt *cnfstmt = cnfstmtNew(S_NOP);
if (cnfstmt != NULL) {
cnfstmt->printable = (uchar *)strdup("continue");
}
return cnfstmt;
}
struct cnfstmt *cnfstmtNewPRIFILT(char *prifilt, struct cnfstmt *t_then) {

View File

@ -81,6 +81,8 @@ librsyslog_la_SOURCES = \
prop.h \
ratelimit.c \
ratelimit.h \
translate.c \
translate.h \
yamlconf.c \
yamlconf.h \
lookup.c \
@ -118,7 +120,7 @@ librsyslog_la_SOURCES = \
if WITH_MODDIRS
librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\"
else
librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I\$(top_srcdir) -I\$(top_srcdir)/grammar
librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I\$(top_srcdir) -I\$(top_srcdir)/grammar -I\$(top_builddir)/grammar
endif
#librsyslog_la_LDFLAGS = -module -avoid-version
librsyslog_la_CPPFLAGS += $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) $(LIBUUID_CFLAGS) $(LIBFASTJSON_CFLAGS) ${LIBESTR_CFLAGS} $(LIBYAML_CFLAGS)

View File

@ -70,6 +70,7 @@
#include "template.h"
#include "timezones.h"
#include "ratelimit.h"
#include "translate.h"
#ifdef HAVE_LIBYAML
#include "yamlconf.h"
#endif
@ -596,7 +597,6 @@ void ATTR_NONNULL() cnfDoObj(struct cnfobj *const o) {
int bDestructObj = 1;
int bChkUnuse = 1;
assert(o != NULL);
dbgprintf("cnf:global:obj: ");
cnfobjPrint(o);
@ -609,6 +609,10 @@ void ATTR_NONNULL() cnfDoObj(struct cnfobj *const o) {
return;
}
if (rsconfTranslateEnabled()) {
rsconfTranslateCaptureObj(o, cnfcurrfn, yylineno);
}
switch (o->objType) {
case CNFOBJ_GLOBAL:
glblProcessCnf(o);
@ -664,11 +668,18 @@ void ATTR_NONNULL() cnfDoObj(struct cnfobj *const o) {
}
void cnfDoScript(struct cnfstmt *script) {
if (rsconfTranslateEnabled()) {
rsconfTranslateCaptureScript(script, cnfcurrfn, yylineno);
}
dbgprintf("cnf:global:script\n");
ruleset.AddScript(ruleset.GetCurrent(loadConf), script);
}
void cnfDoCfsysline(char *ln) {
if (rsconfTranslateEnabled()) {
rsconfTranslateAddUnsupported(cnfcurrfn, yylineno, "legacy $-directive '%s' is not supported by the translator",
ln);
}
DBGPRINTF("cnf:global:cfsysline: %s\n", ln);
/* the legacy system needs the "$" stripped */
conf.cfsysline((uchar *)ln + 1);
@ -676,6 +687,10 @@ void cnfDoCfsysline(char *ln) {
}
void cnfDoBSDTag(char *ln) {
if (rsconfTranslateEnabled()) {
rsconfTranslateAddUnsupported(cnfcurrfn, yylineno,
"BSD-style tag block '%s' is not supported by the translator", ln);
}
DBGPRINTF("cnf:global:BSD tag: %s\n", ln);
LogError(0, RS_RET_BSD_BLOCKS_UNSUPPORTED,
"BSD-style blocks are no longer supported in rsyslog, "
@ -686,6 +701,10 @@ void cnfDoBSDTag(char *ln) {
}
void cnfDoBSDHost(char *ln) {
if (rsconfTranslateEnabled()) {
rsconfTranslateAddUnsupported(cnfcurrfn, yylineno,
"BSD-style host block '%s' is not supported by the translator", ln);
}
DBGPRINTF("cnf:global:BSD host: %s\n", ln);
LogError(0, RS_RET_BSD_BLOCKS_UNSUPPORTED,
"BSD-style blocks are no longer supported in rsyslog, "
@ -1557,7 +1576,7 @@ static rsRetVal load(rsconf_t **cnf, uchar *confFile) {
* If not, terminate. -- rgerhards, 2008-07-25
* TODO: iConfigVerify -- should it be pulled from the config, or leave as is (option)?
*/
if (iConfigVerify) {
if (iConfigVerify && !rsconfTranslateEnabled()) {
if (iRet == RS_RET_OK) iRet = RS_RET_VALIDATION_RUN;
FINALIZE;
}

1325
runtime/translate.c Normal file

File diff suppressed because it is too large Load Diff

102
runtime/translate.h Normal file
View File

@ -0,0 +1,102 @@
/** @file translate.h
* @brief Interfaces for canonical config translation.
*
* Copyright 2026 Rainer Gerhards and Adiscon GmbH.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* -or-
* see COPYING.ASL20 in the source distribution
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef RUNTIME_TRANSLATE_H_INCLUDED
#define RUNTIME_TRANSLATE_H_INCLUDED
#include "rsyslog.h"
#include "grammar/rainerscript.h"
/** @brief Supported translation output formats. */
enum rsconfTranslateFormat { RSCONF_TRANSLATE_NONE = 0, RSCONF_TRANSLATE_RAINERSCRIPT, RSCONF_TRANSLATE_YAML };
/**
* @brief Configure translation mode for the current validation run.
*
* Resets any previously retained translation state before enabling the
* selected output format.
*
* @param fmt Translation output format, or @c RSCONF_TRANSLATE_NONE to disable.
*/
void rsconfTranslateConfigure(enum rsconfTranslateFormat fmt);
/**
* @brief Release all retained translation state.
*/
void rsconfTranslateCleanup(void);
/**
* @brief Check whether translation capture is enabled.
*
* @return Non-zero when config translation is active.
*/
int rsconfTranslateEnabled(void);
/**
* @brief Check whether translation capture hit a fatal error.
*
* @return Non-zero when translation should fail instead of writing output.
*/
int rsconfTranslateHasFatal(void);
/**
* @brief Clone a name-value list for later translation output.
*
* @param lst List head to clone.
* @return Cloned list, or NULL on allocation failure.
*/
struct nvlst *rsconfTranslateCloneNvlst(const struct nvlst *lst);
/**
* @brief Capture a config object before normal processing consumes it.
*
* @param o Parsed config object.
* @param source Source file name, if known.
* @param line Source line number.
*/
void rsconfTranslateCaptureObj(const struct cnfobj *o, const char *source, int line);
/**
* @brief Capture executable script statements for later emission.
*
* @param script Statement tree to serialize.
* @param source Source file name, if known.
* @param line Source line number.
*/
void rsconfTranslateCaptureScript(const struct cnfstmt *script, const char *source, int line);
/**
* @brief Record a fatal unsupported construct for translation.
*
* @param source Source file name, if known.
* @param line Source line number.
* @param fmt Printf-style explanation of the unsupported construct.
*/
void rsconfTranslateAddUnsupported(const char *source, int line, const char *fmt, ...)
__attribute__((format(printf, 3, 4)));
/**
* @brief Write the translated configuration document.
*
* @param path Output path, or "-" for stdout.
* @return rsyslog status code for the write operation.
*/
rsRetVal rsconfTranslateWriteFile(const char *path);
#endif

View File

@ -1935,6 +1935,9 @@ rsRetVal yamlconf_load(const char *fname) {
char *seen_keys[YAMLCONF_MAX_TOPKEYS];
int seen_count = 0;
DEFiRet;
char *prev_cnfcurrfn = cnfcurrfn;
cnfcurrfn = (char *)fname;
fh = fopen(fname, "r");
if (fh == NULL) {
@ -2049,6 +2052,7 @@ finalize_it:
for (int ki = 0; ki < seen_count; ++ki) free(seen_keys[ki]);
if (parserInit) yaml_parser_delete(&parser);
if (fh) fclose(fh);
cnfcurrfn = prev_cnfcurrfn;
RETiRet;
}

View File

@ -557,6 +557,8 @@ TESTS_DEFAULT_VALGRIND = \
TESTS_LIBGCRYPT_VALGRIND = \
queue-encryption-disk_keyfile-vg.sh
TESTS_LIBYAML = \
config-translate-rs-to-yaml.sh \
config-translate-yaml-to-rs.sh \
ratelimit_hup.sh \
yaml-basic.sh \
yaml-basic-yamlonly.sh \
@ -1209,6 +1211,13 @@ TESTS_PMNULL = \
TESTS_OMSTDOUT = \
omstdout-basic.sh
TESTS_LIBYAML_IMTCP = \
config-translate-rs-roundtrip.sh \
config-translate-yaml-roundtrip.sh
TESTS_LIBYAML_OMSTDOUT = \
config-translate-legacy-warning.sh
TESTS_PMNORMALIZE = \
pmnormalize-basic.sh \
pmnormalize-invld-rulebase.sh \
@ -1721,6 +1730,8 @@ EXTRA_DIST += $(TESTS_OSSL_WRONG_OPT)
EXTRA_DIST += $(TESTS_DEFAULT_VALGRIND)
EXTRA_DIST += $(TESTS_LIBGCRYPT_VALGRIND)
EXTRA_DIST += $(TESTS_LIBYAML)
EXTRA_DIST += $(TESTS_LIBYAML_IMTCP)
EXTRA_DIST += $(TESTS_LIBYAML_OMSTDOUT)
EXTRA_DIST += $(TESTS_IMTCP)
EXTRA_DIST += $(TESTS_IMTCP_YAML)
EXTRA_DIST += $(TESTS_IMTCP_VALGRIND)
@ -2082,6 +2093,12 @@ endif # ENABLE_LIBGCRYPT
endif # HAVE_VALGRIND
if HAVE_LIBYAML
TESTS += $(TESTS_LIBYAML)
if ENABLE_IMTCP_TESTS
TESTS += $(TESTS_LIBYAML_IMTCP)
endif # ENABLE_IMTCP_TESTS
if ENABLE_OMSTDOUT
TESTS += $(TESTS_LIBYAML_OMSTDOUT)
endif # ENABLE_OMSTDOUT
endif # HAVE_LIBYAML
endif # ENABLE_DEFAULT_TESTS

View File

@ -0,0 +1,25 @@
#!/bin/bash
# check translation warnings for legacy selector syntax.
#
# Part of the testbench for rsyslog.
#
# This file is part of rsyslog.
# Released under ASL 2.0
. ${srcdir:=.}/diag.sh init
export ASAN_OPTIONS="${ASAN_OPTIONS:-detect_leaks=0}"
modpath="../runtime/.libs:../plugins/omstdout/.libs:../.libs"
cat > "${RSYSLOG_DYNNAME}.conf" <<'RS_EOF'
module(load="omstdout")
*.* :omstdout:
RS_EOF
../tools/rsyslogd -N1 -f "${RSYSLOG_DYNNAME}.conf" -F yaml -o "${RSYSLOG_DYNNAME}.yaml" -M"$modpath"
content_check '# TRANSLATION WARNING: top-level statements normalized into explicit RSYSLOG_DefaultRuleset' "${RSYSLOG_DYNNAME}.yaml"
content_check '# TRANSLATION WARNING: legacy action syntax preserved as script text' "${RSYSLOG_DYNNAME}.yaml"
content_check 'name: "RSYSLOG_DefaultRuleset"' "${RSYSLOG_DYNNAME}.yaml"
content_check '*.* :omstdout:' "${RSYSLOG_DYNNAME}.yaml"
echo SUCCESS: legacy translation warning coverage
exit_test

View File

@ -0,0 +1,85 @@
#!/bin/bash
# check canonical RainerScript -> YAML -> RainerScript round-trip.
#
# Part of the testbench for rsyslog.
#
# This file is part of rsyslog.
# Released under ASL 2.0
. ${srcdir:=.}/diag.sh init
require_plugin imtcp
export ASAN_OPTIONS="${ASAN_OPTIONS:-detect_leaks=0}"
modpath="../runtime/.libs:../plugins/imtcp/.libs:../.libs"
outlog="/tmp/${RSYSLOG_DYNNAME}.roundtrip.log"
portfile="${RSYSLOG_DYNNAME}.tcpflood_port"
cat > "${RSYSLOG_DYNNAME}.conf" <<RS_EOF
global(defaultNetstreamDriverCAFile="${srcdir}/tls-certs/ca.pem"
defaultNetstreamDriverCertFile="${srcdir}/tls-certs/cert.pem"
defaultNetstreamDriverKeyFile="${srcdir}/tls-certs/key.pem")
module(load="../plugins/imtcp/.libs/imtcp"
StreamDriver.Name="gtls"
StreamDriver.Mode="1"
StreamDriver.AuthMode="x509/name"
PermittedPeer=["rsyslog-client"])
input(type="imtcp" listenPortFileName="${portfile}" port="0")
template(name="outfmt" type="string" string="%msg:F,58:2%\n")
ruleset(name="main") {
action(type="omfile" file="${outlog}" template="outfmt")
}
RS_EOF
../tools/rsyslogd -N1 -f "${RSYSLOG_DYNNAME}.conf" -F yaml -o "${RSYSLOG_DYNNAME}.roundtrip.yaml" -M"$modpath" || error_exit $?
../tools/rsyslogd -N1 -f "${RSYSLOG_DYNNAME}.roundtrip.yaml" -F rainerscript -o "${RSYSLOG_DYNNAME}.roundtrip.conf" -M"$modpath" || error_exit $?
cat > "${RSYSLOG_DYNNAME}.expected.yaml" <<YAML_EOF
version: 2
global:
defaultNetstreamDriverCAFile: "${srcdir}/tls-certs/ca.pem"
defaultNetstreamDriverCertFile: "${srcdir}/tls-certs/cert.pem"
defaultNetstreamDriverKeyFile: "${srcdir}/tls-certs/key.pem"
modules:
- load: "../plugins/imtcp/.libs/imtcp"
PermittedPeer: ["rsyslog-client"]
StreamDriver.AuthMode: "x509/name"
StreamDriver.Mode: "1"
StreamDriver.Name: "gtls"
inputs:
- type: "imtcp"
listenPortFileName: "${portfile}"
port: "0"
templates:
- name: "outfmt"
type: "string"
string: "%msg:F,58:2%\n"
rulesets:
- name: "main"
script: |
action(type="omfile" file="${outlog}" template="outfmt")
YAML_EOF
cmp_exact_file "${RSYSLOG_DYNNAME}.expected.yaml" "${RSYSLOG_DYNNAME}.roundtrip.yaml"
cat > "${RSYSLOG_DYNNAME}.expected.conf" <<RS_EOF
global(defaultNetstreamDriverCAFile="${srcdir}/tls-certs/ca.pem" defaultNetstreamDriverCertFile="${srcdir}/tls-certs/cert.pem" defaultNetstreamDriverKeyFile="${srcdir}/tls-certs/key.pem")
module(load="../plugins/imtcp/.libs/imtcp" PermittedPeer=["rsyslog-client"] StreamDriver.AuthMode="x509/name" StreamDriver.Mode="1" StreamDriver.Name="gtls")
input(type="imtcp" listenPortFileName="${portfile}" port="0")
template(name="outfmt" type="string" string="%msg:F,58:2%\n")
ruleset(name="main") {
action(type="omfile" file="${outlog}" template="outfmt")
}
RS_EOF
cmp_exact_file "${RSYSLOG_DYNNAME}.expected.conf" "${RSYSLOG_DYNNAME}.roundtrip.conf"
../tools/rsyslogd -N1 -f "${RSYSLOG_DYNNAME}.roundtrip.conf" -M"$modpath" || error_exit $?
echo SUCCESS: RainerScript round-trip translation
exit_test

View File

@ -0,0 +1,40 @@
#!/bin/bash
# check canonical translation from RainerScript to YAML.
#
# Part of the testbench for rsyslog.
#
# This file is part of rsyslog.
# Released under ASL 2.0
. ${srcdir:=.}/diag.sh init
export ASAN_OPTIONS="${ASAN_OPTIONS:-detect_leaks=0}"
modpath="../runtime/.libs:../plugins/omstdout/.libs:../.libs"
cat > "${RSYSLOG_DYNNAME}.conf" <<'RS_EOF'
module(load="omstdout")
main_queue(queue.type="Direct")
ruleset(name="main") {
action(type="omstdout")
}
RS_EOF
../tools/rsyslogd -N1 -f "${RSYSLOG_DYNNAME}.conf" -F yaml -o "${RSYSLOG_DYNNAME}.yaml" -M"$modpath"
cat > "${RSYSLOG_DYNNAME}.expected.yaml" <<'YAML_EOF'
version: 2
mainqueue:
queue.type: "Direct"
modules:
- load: "omstdout"
rulesets:
- name: "main"
script: |
action(type="omstdout")
YAML_EOF
cmp_exact_file "${RSYSLOG_DYNNAME}.expected.yaml" "${RSYSLOG_DYNNAME}.yaml"
../tools/rsyslogd -N1 -f "${RSYSLOG_DYNNAME}.yaml" -M"$modpath"
echo SUCCESS: RainerScript to YAML translation
exit_test

View File

@ -0,0 +1,77 @@
#!/bin/bash
# check canonical YAML -> RainerScript -> YAML round-trip.
#
# Part of the testbench for rsyslog.
#
# This file is part of rsyslog.
# Released under ASL 2.0
. ${srcdir:=.}/diag.sh init
export ASAN_OPTIONS="${ASAN_OPTIONS:-detect_leaks=0}"
modpath="../runtime/.libs:../plugins/imtcp/.libs:../.libs"
outlog="/tmp/${RSYSLOG_DYNNAME}.roundtrip.log"
portfile="${RSYSLOG_DYNNAME}.tcpflood_port"
cat > "${RSYSLOG_DYNNAME}.yaml" <<YAML_EOF
version: 2
global:
defaultNetstreamDriverCAFile: "${srcdir}/tls-certs/ca.pem"
defaultNetstreamDriverCertFile: "${srcdir}/tls-certs/cert.pem"
defaultNetstreamDriverKeyFile: "${srcdir}/tls-certs/key.pem"
modules:
- load: "../plugins/imtcp/.libs/imtcp"
PermittedPeer: ["rsyslog-client"]
StreamDriver.AuthMode: "x509/name"
StreamDriver.Mode: "1"
StreamDriver.Name: "gtls"
inputs:
- type: "imtcp"
listenPortFileName: "${portfile}"
port: "0"
templates:
- name: "outfmt"
type: "string"
string: "%msg:F,58:2%\\n"
rulesets:
- name: "main"
script: |
action(type="omfile" file="${outlog}" template="outfmt")
YAML_EOF
../tools/rsyslogd -N1 -f "${RSYSLOG_DYNNAME}.yaml" -F rainerscript -o "${RSYSLOG_DYNNAME}.roundtrip.conf" -M"$modpath" || error_exit $?
../tools/rsyslogd -N1 -f "${RSYSLOG_DYNNAME}.roundtrip.conf" -F yaml -o "${RSYSLOG_DYNNAME}.roundtrip.yaml" -M"$modpath" || error_exit $?
cat > "${RSYSLOG_DYNNAME}.expected.yaml" <<YAML_EOF
version: 2
global:
defaultNetstreamDriverCAFile: "${srcdir}/tls-certs/ca.pem"
defaultNetstreamDriverCertFile: "${srcdir}/tls-certs/cert.pem"
defaultNetstreamDriverKeyFile: "${srcdir}/tls-certs/key.pem"
modules:
- load: "../plugins/imtcp/.libs/imtcp"
PermittedPeer: ["rsyslog-client"]
StreamDriver.AuthMode: "x509/name"
StreamDriver.Mode: "1"
StreamDriver.Name: "gtls"
inputs:
- type: "imtcp"
listenPortFileName: "${portfile}"
port: "0"
templates:
- name: "outfmt"
type: "string"
string: "%msg:F,58:2%\\n"
rulesets:
- name: "main"
script: |
action(type="omfile" file="${outlog}" template="outfmt")
YAML_EOF
cmp_exact_file "${RSYSLOG_DYNNAME}.expected.yaml" "${RSYSLOG_DYNNAME}.roundtrip.yaml"
../tools/rsyslogd -N1 -f "${RSYSLOG_DYNNAME}.roundtrip.yaml" -M"$modpath" || error_exit $?
echo SUCCESS: YAML round-trip translation
exit_test

View File

@ -0,0 +1,41 @@
#!/bin/bash
# check canonical translation from YAML to RainerScript.
#
# Part of the testbench for rsyslog.
#
# This file is part of rsyslog.
# Released under ASL 2.0
. ${srcdir:=.}/diag.sh init
export ASAN_OPTIONS="${ASAN_OPTIONS:-detect_leaks=0}"
modpath="../runtime/.libs:../plugins/omstdout/.libs:../.libs"
cat > "${RSYSLOG_DYNNAME}.yaml" <<'YAML_EOF'
version: 2
modules:
- load: "omstdout"
mainqueue:
queue.type: "Direct"
rulesets:
- name: "main"
script: |
action(type="omstdout")
YAML_EOF
../tools/rsyslogd -N1 -f "${RSYSLOG_DYNNAME}.yaml" -F rainerscript -o "${RSYSLOG_DYNNAME}.out.conf" -M"$modpath"
cat > "${RSYSLOG_DYNNAME}.expected.conf" <<'RS_EOF'
main_queue(queue.type="Direct")
module(load="omstdout")
ruleset(name="main") {
action(type="omstdout")
}
RS_EOF
cmp_exact_file "${RSYSLOG_DYNNAME}.expected.conf" "${RSYSLOG_DYNNAME}.out.conf"
../tools/rsyslogd -N1 -f "${RSYSLOG_DYNNAME}.out.conf" -M"$modpath"
echo SUCCESS: YAML to RainerScript translation
exit_test

View File

@ -451,6 +451,28 @@ cmp_exact() {
fi;
}
# compare two files for exact content
# $1 is the expected file, $2 is the actual file
cmp_exact_file() {
expected_file="$1"
actual_file="$2"
if [ "$expected_file" == "" ] || [ "$actual_file" == "" ]; then
printf 'Testbench ERROR, cmp_exact_file() needs expected and actual filenames!\n'
error_exit 100
fi
cmp "$expected_file" "$actual_file" > /dev/null
if [ $? -ne 0 ]; then
printf 'invalid response generated\n'
printf '################# %s is:\n' "$actual_file"
cat -n "$actual_file"
printf '################# %s is expected:\n' "$expected_file"
cat -n "$expected_file"
printf '\n#################### diff is:\n'
diff -u "$expected_file" "$actual_file"
error_exit 1
fi
}
# code common to all startup...() functions
startup_common() {
instance=

View File

@ -66,6 +66,7 @@
#include "srUtils.h"
#include "rainerscript.h"
#include "rsconf.h"
#include "translate.h"
#include "cfsysline.h"
#include "datetime.h"
#include "operatingstate.h"
@ -1431,6 +1432,8 @@ static void initAll(int argc, char **argv) {
int iHelperUOpt;
int bChDirRoot = 1; /* change the current working directory to "/"? */
char *arg; /* for command line option processing */
char *configOutputPath = NULL;
enum rsconfTranslateFormat iTranslateFmt = RSCONF_TRANSLATE_NONE;
char cwdbuf[128]; /* buffer to obtain/display current working directory */
int parentPipeFD = 0; /* fd of pipe to parent, if auto-backgrounding */
DEFiRet;
@ -1453,15 +1456,16 @@ static void initAll(int argc, char **argv) {
* before processing complex configurations that might depend on it.
*/
#if defined(_AIX)
while ((ch = getopt(argc, argv, "46ACDdf:hi:M:nN:o:qQS:T:u:vwxR")) != EOF) {
while ((ch = getopt(argc, argv, "46ACDdf:F:hi:M:nN:o:qQS:T:u:vwxR")) != EOF) {
#else
while ((ch = getopt(argc, argv, "46ACDdf:hi:M:nN:o:qQS:T:u:vwx")) != EOF) {
while ((ch = getopt(argc, argv, "46ACDdf:F:hi:M:nN:o:qQS:T:u:vwx")) != EOF) {
#endif
switch ((char)ch) {
case '4':
case '6':
case 'A':
case 'f': /* configuration file */
case 'F': /* translation output format */
case 'i': /* pid file name */
case 'n': /* don't fork */
case 'N': /* enable config verify mode */
@ -1580,36 +1584,27 @@ static void initAll(int argc, char **argv) {
case 'N': /* enable config verify mode */
iConfigVerify = (arg == NULL) ? 0 : atoi(arg);
break;
case 'F':
if (arg == NULL) {
fprintf(stderr, "rsyslogd: -F requires a format argument\n");
exit(1);
}
if (!strcasecmp(arg, "yaml")) {
iTranslateFmt = RSCONF_TRANSLATE_YAML;
} else if (!strcasecmp(arg, "rainerscript")) {
iTranslateFmt = RSCONF_TRANSLATE_RAINERSCRIPT;
} else {
fprintf(stderr, "rsyslogd: unsupported translation format '%s'\n", arg);
exit(1);
}
break;
case 'o':
if (fp_rs_full_conf_output != NULL) {
fprintf(stderr,
"warning: -o option given multiple times. Now "
"using value %s\n",
if (configOutputPath != NULL) {
fprintf(stderr, "warning: -o option given multiple times. Now using value %s\n",
(arg == NULL) ? "-" : arg);
fclose(fp_rs_full_conf_output);
fp_rs_full_conf_output = NULL;
}
if (arg == NULL || !strcmp(arg, "-")) {
fp_rs_full_conf_output = stdout;
} else {
fp_rs_full_conf_output = fopen(arg, "w");
}
if (fp_rs_full_conf_output == NULL) {
perror(arg);
fprintf(stderr,
"rsyslogd: cannot open config output file %s - "
"-o option will be ignored\n",
arg);
} else {
time_t tTime;
struct tm tp;
datetime.GetTime(&tTime);
localtime_r(&tTime, &tp);
fprintf(fp_rs_full_conf_output,
"## full conf created by rsyslog version %s at "
"%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d ##\n",
VERSION, tp.tm_year + 1900, tp.tm_mon + 1, tp.tm_mday, tp.tm_hour, tp.tm_min, tp.tm_sec);
}
configOutputPath = arg;
arg = NULL;
break;
case 'q': /* add hostname if DNS resolving has failed */
fprintf(stderr,
@ -1681,6 +1676,38 @@ static void initAll(int argc, char **argv) {
if (iRet != RS_RET_END_OF_LINKEDLIST) FINALIZE;
if (iTranslateFmt != RSCONF_TRANSLATE_NONE) {
if (!iConfigVerify) {
fprintf(stderr, "rsyslogd: -F requires -N1 config validation mode\n");
ABORT_FINALIZE(RS_RET_ERR);
}
if (configOutputPath == NULL) {
fprintf(stderr, "rsyslogd: -F requires -o <path>\n");
ABORT_FINALIZE(RS_RET_ERR);
}
rsconfTranslateConfigure(iTranslateFmt);
} else if (configOutputPath != NULL) {
if (!strcmp(configOutputPath, "-")) {
fp_rs_full_conf_output = stdout;
} else {
fp_rs_full_conf_output = fopen(configOutputPath, "w");
}
if (fp_rs_full_conf_output == NULL) {
perror(configOutputPath);
fprintf(stderr, "rsyslogd: cannot open config output file %s - -o option will be ignored\n",
configOutputPath);
} else {
time_t tTime;
struct tm tp;
datetime.GetTime(&tTime);
localtime_r(&tTime, &tp);
fprintf(fp_rs_full_conf_output,
"## full conf created by rsyslog version %s at "
"%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d ##\n",
VERSION, tp.tm_year + 1900, tp.tm_mon + 1, tp.tm_mday, tp.tm_hour, tp.tm_min, tp.tm_sec);
}
}
if (iConfigVerify) {
doFork = 0;
fprintf(stderr, "rsyslogd: version %s, config validation run (level %d), master config %s\n", VERSION,
@ -1825,6 +1852,12 @@ static void initAll(int argc, char **argv) {
}
CHKiRet(localRet);
if (iTranslateFmt != RSCONF_TRANSLATE_NONE) {
CHKiRet(rsconfTranslateWriteFile(configOutputPath));
iRet = RS_RET_VALIDATION_RUN;
FINALIZE;
}
CHKiRet(rsyslogd_InitStdRatelimiters());
if (bChDirRoot) {
@ -1888,6 +1921,7 @@ static void initAll(int argc, char **argv) {
}
finalize_it:
rsconfTranslateCleanup();
if (iRet == RS_RET_VALIDATION_RUN) {
fprintf(stderr, "rsyslogd: End of config validation run. Bye.\n");
exit(0);