Blame SOURCES/rsyslog-8.24.0-rhbz1622767-mmkubernetes-stop-on-pod-delete.patch

ee3a35
From 3987cd929d859f900318b393133c3bdde8dfffd5 Mon Sep 17 00:00:00 2001
ee3a35
From: Rich Megginson <rmeggins@redhat.com>
ee3a35
Date: Tue, 28 Aug 2018 12:44:23 -0600
ee3a35
Subject: [PATCH] mmkubertnetes: action fails preparation cycle if kubernetes
ee3a35
 API destroys resource during bootup sequence
ee3a35
ee3a35
The plugin was not handling 404 Not Found correctly when looking
ee3a35
up pods and namespaces.  In this case, we assume the pod/namespace
ee3a35
was deleted, annotate the record with whatever metadata we have,
ee3a35
and cache the fact that the pod/namespace is missing so we don't
ee3a35
attempt to look it up again.
ee3a35
In addition, the plugin was not handling error 429 Busy correctly.
ee3a35
In this case, it should also annotate the record with whatever
ee3a35
metadata it has, and _not_ cache anything.  By default the plugin
ee3a35
will retry every 5 seconds to connect to Kubernetes.  This
ee3a35
behavior is controlled by the new config param `busyretryinterval`.
ee3a35
This commit also adds impstats counters so that admins can
ee3a35
view the state of the plugin to see if the lookups are working
ee3a35
or are returning errors.  The stats are reported per-instance
ee3a35
or per-action to facilitate using multiple different actions
ee3a35
for different Kubernetes servers.
ee3a35
This commit also adds support for client cert auth to
ee3a35
Kubernetes via the two new config params `tls.mycert` and
ee3a35
`tls.myprivkey`.
ee3a35
---
ee3a35
 contrib/mmkubernetes/mmkubernetes.c | 296 ++++++++++++++++++++++++----
ee3a35
 1 files changed, 272 insertions(+), 24 deletions(-)
ee3a35
ee3a35
diff --git a/contrib/mmkubernetes/mmkubernetes.c b/contrib/mmkubernetes/mmkubernetes.c
ee3a35
index 422cb2577..5bf5b049d 100644
ee3a35
--- a/contrib/mmkubernetes/mmkubernetes.c
ee3a35
+++ b/contrib/mmkubernetes/mmkubernetes.c
ee3a35
@@ -52,9 +52,12 @@
ee3a35
 #include "syslogd-types.h"
ee3a35
 #include "module-template.h"
ee3a35
 #include "errmsg.h"
ee3a35
+#include "statsobj.h"
ee3a35
 #include "regexp.h"
ee3a35
 #include "hashtable.h"
ee3a35
 #include "srUtils.h"
ee3a35
+#include "unicode-helper.h"
ee3a35
+#include "datetime.h"
ee3a35
 
ee3a35
 /* static data */
ee3a35
 MODULE_TYPE_OUTPUT /* this is technically an output plugin */
ee3a35
@@ -62,6 +65,8 @@ MODULE_TYPE_KEEP /* releasing the module would cause a leak through libcurl */
ee3a35
 DEF_OMOD_STATIC_DATA
ee3a35
 DEFobjCurrIf(errmsg)
ee3a35
 DEFobjCurrIf(regexp)
ee3a35
+DEFobjCurrIf(statsobj)
ee3a35
+DEFobjCurrIf(datetime)
ee3a35
 
ee3a35
 #define HAVE_LOADSAMPLESFROMSTRING 1
ee3a35
 #if defined(NO_LOADSAMPLESFROMSTRING)
ee3a35
@@ -95,12 +100,14 @@ DEFobjCurrIf(regexp)
ee3a35
 #define DFLT_CONTAINER_NAME "$!CONTAINER_NAME" /* name of variable holding CONTAINER_NAME value */
ee3a35
 #define DFLT_CONTAINER_ID_FULL "$!CONTAINER_ID_FULL" /* name of variable holding CONTAINER_ID_FULL value */
ee3a35
 #define DFLT_KUBERNETES_URL "https://kubernetes.default.svc.cluster.local:443"
ee3a35
+#define DFLT_BUSY_RETRY_INTERVAL 5 /* retry every 5 seconds */
ee3a35
 
ee3a35
 static struct cache_s {
ee3a35
 	const uchar *kbUrl;
ee3a35
 	struct hashtable *mdHt;
ee3a35
 	struct hashtable *nsHt;
ee3a35
 	pthread_mutex_t *cacheMtx;
ee3a35
+	int lastBusyTime;
ee3a35
 } **caches;
ee3a35
 
ee3a35
 typedef struct {
ee3a35
@@ -116,6 +123,8 @@ struct modConfData_s {
ee3a35
 	uchar *srcMetadataPath;	/* where to get data for kubernetes queries */
ee3a35
 	uchar *dstMetadataPath;	/* where to put metadata obtained from kubernetes */
ee3a35
 	uchar *caCertFile; /* File holding the CA cert (+optional chain) of CA that issued the Kubernetes server cert */
ee3a35
+	uchar *myCertFile; /* File holding cert corresponding to private key used for client cert auth */
ee3a35
+	uchar *myPrivKeyFile; /* File holding private key corresponding to cert used for client cert auth */
ee3a35
 	sbool allowUnsignedCerts; /* For testing/debugging - do not check for CA certs (CURLOPT_SSL_VERIFYPEER FALSE) */
ee3a35
 	uchar *token; /* The token value to use to authenticate to Kubernetes - takes precedence over tokenFile */
ee3a35
 	uchar *tokenFile; /* The file whose contents is the token value to use to authenticate to Kubernetes */
ee3a35
@@ -127,6 +136,7 @@ struct modConfData_s {
ee3a35
 	uchar *fnRulebase; /* lognorm rulebase filename for container log filename match */
ee3a35
 	char *contRules; /* lognorm rules for CONTAINER_NAME value match */
ee3a35
 	uchar *contRulebase; /* lognorm rulebase filename for CONTAINER_NAME value match */
ee3a35
+	int busyRetryInterval; /* how to handle 429 response - 0 means error, non-zero means retry every N seconds */
ee3a35
 };
ee3a35
 
ee3a35
 /* action (instance) configuration data */
ee3a35
@@ -135,6 +145,8 @@ typedef struct _instanceData {
ee3a35
 	msgPropDescr_t *srcMetadataDescr;	/* where to get data for kubernetes queries */
ee3a35
 	uchar *dstMetadataPath;	/* where to put metadata obtained from kubernetes */
ee3a35
 	uchar *caCertFile; /* File holding the CA cert (+optional chain) of CA that issued the Kubernetes server cert */
ee3a35
+	uchar *myCertFile; /* File holding cert corresponding to private key used for client cert auth */
ee3a35
+	uchar *myPrivKeyFile; /* File holding private key corresponding to cert used for client cert auth */
ee3a35
 	sbool allowUnsignedCerts; /* For testing/debugging - do not check for CA certs (CURLOPT_SSL_VERIFYPEER FALSE) */
ee3a35
 	uchar *token; /* The token value to use to authenticate to Kubernetes - takes precedence over tokenFile */
ee3a35
 	uchar *tokenFile; /* The file whose contents is the token value to use to authenticate to Kubernetes */
ee3a35
@@ -151,6 +163,7 @@ typedef struct _instanceData {
ee3a35
 	msgPropDescr_t *contNameDescr; /* CONTAINER_NAME field */
ee3a35
 	msgPropDescr_t *contIdFullDescr; /* CONTAINER_ID_FULL field */
ee3a35
 	struct cache_s *cache;
ee3a35
+	int busyRetryInterval; /* how to handle 429 response - 0 means error, non-zero means retry every N seconds */
ee3a35
 } instanceData;
ee3a35
 
ee3a35
 typedef struct wrkrInstanceData {
ee3a35
@@ -159,6 +172,16 @@ typedef struct wrkrInstanceData {
ee3a35
 	struct curl_slist *curlHdr;
ee3a35
 	char *curlRply;
ee3a35
 	size_t curlRplyLen;
ee3a35
+	statsobj_t *stats; /* stats for this instance */
ee3a35
+	STATSCOUNTER_DEF(k8sRecordSeen, mutK8sRecordSeen)
ee3a35
+	STATSCOUNTER_DEF(namespaceMetadataSuccess, mutNamespaceMetadataSuccess)
ee3a35
+	STATSCOUNTER_DEF(namespaceMetadataNotFound, mutNamespaceMetadataNotFound)
ee3a35
+	STATSCOUNTER_DEF(namespaceMetadataBusy, mutNamespaceMetadataBusy)
ee3a35
+	STATSCOUNTER_DEF(namespaceMetadataError, mutNamespaceMetadataError)
ee3a35
+	STATSCOUNTER_DEF(podMetadataSuccess, mutPodMetadataSuccess)
ee3a35
+	STATSCOUNTER_DEF(podMetadataNotFound, mutPodMetadataNotFound)
ee3a35
+	STATSCOUNTER_DEF(podMetadataBusy, mutPodMetadataBusy)
ee3a35
+	STATSCOUNTER_DEF(podMetadataError, mutPodMetadataError)
ee3a35
 } wrkrInstanceData_t;
ee3a35
 
ee3a35
 /* module parameters (v6 config format) */
ee3a35
@@ -167,6 +190,8 @@ static struct cnfparamdescr modpdescr[] = {
ee3a35
 	{ "srcmetadatapath", eCmdHdlrString, 0 },
ee3a35
 	{ "dstmetadatapath", eCmdHdlrString, 0 },
ee3a35
 	{ "tls.cacert", eCmdHdlrString, 0 },
ee3a35
+	{ "tls.mycert", eCmdHdlrString, 0 },
ee3a35
+	{ "tls.myprivkey", eCmdHdlrString, 0 },
ee3a35
 	{ "allowunsignedcerts", eCmdHdlrBinary, 0 },
ee3a35
 	{ "token", eCmdHdlrString, 0 },
ee3a35
 	{ "tokenfile", eCmdHdlrString, 0 },
ee3a35
@@ -174,7 +199,8 @@ static struct cnfparamdescr modpdescr[] = {
ee3a35
 	{ "de_dot", eCmdHdlrBinary, 0 },
ee3a35
 	{ "de_dot_separator", eCmdHdlrString, 0 },
ee3a35
 	{ "filenamerulebase", eCmdHdlrString, 0 },
ee3a35
-	{ "containerrulebase", eCmdHdlrString, 0 }
ee3a35
+	{ "containerrulebase", eCmdHdlrString, 0 },
ee3a35
+	{ "busyretryinterval", eCmdHdlrInt, 0 }
ee3a35
 #if HAVE_LOADSAMPLESFROMSTRING == 1
ee3a35
 	,
ee3a35
 	{ "filenamerules", eCmdHdlrArray, 0 },
ee3a35
@@ -193,6 +219,8 @@ static struct cnfparamdescr actpdescr[] = {
ee3a35
 	{ "srcmetadatapath", eCmdHdlrString, 0 },
ee3a35
 	{ "dstmetadatapath", eCmdHdlrString, 0 },
ee3a35
 	{ "tls.cacert", eCmdHdlrString, 0 },
ee3a35
+	{ "tls.mycert", eCmdHdlrString, 0 },
ee3a35
+	{ "tls.myprivkey", eCmdHdlrString, 0 },
ee3a35
 	{ "allowunsignedcerts", eCmdHdlrBinary, 0 },
ee3a35
 	{ "token", eCmdHdlrString, 0 },
ee3a35
 	{ "tokenfile", eCmdHdlrString, 0 },
ee3a35
@@ -200,7 +228,8 @@ static struct cnfparamdescr actpdescr[] = {
ee3a35
 	{ "de_dot", eCmdHdlrBinary, 0 },
ee3a35
 	{ "de_dot_separator", eCmdHdlrString, 0 },
ee3a35
 	{ "filenamerulebase", eCmdHdlrString, 0 },
ee3a35
-	{ "containerrulebase", eCmdHdlrString, 0 }
ee3a35
+	{ "containerrulebase", eCmdHdlrString, 0 },
ee3a35
+	{ "busyretryinterval", eCmdHdlrInt, 0 }
ee3a35
 #if HAVE_LOADSAMPLESFROMSTRING == 1
ee3a35
 	,
ee3a35
 	{ "filenamerules", eCmdHdlrArray, 0 },
ee3a35
@@ -493,8 +522,9 @@ ENDbeginCnfLoad
ee3a35
 BEGINsetModCnf
ee3a35
 	struct cnfparamvals *pvals = NULL;
ee3a35
 	int i;
ee3a35
-	FILE *fp;
ee3a35
+	FILE *fp = NULL;
ee3a35
 	int ret;
ee3a35
+	char errStr[1024];
ee3a35
 CODESTARTsetModCnf
ee3a35
 	pvals = nvlstGetParams(lst, &modpblk, NULL);
ee3a35
 	if(pvals == NULL) {
ee3a35
@@ -509,6 +539,7 @@ CODESTARTsetModCnf
ee3a35
 	}
ee3a35
 
ee3a35
 	loadModConf->de_dot = DFLT_DE_DOT;
ee3a35
+	loadModConf->busyRetryInterval = DFLT_BUSY_RETRY_INTERVAL;
ee3a35
 	for(i = 0 ; i < modpblk.nParams ; ++i) {
ee3a35
 		if(!pvals[i].bUsed) {
ee3a35
 			continue;
ee3a35
@@ -528,11 +559,39 @@ CODESTARTsetModCnf
ee3a35
 				rs_strerror_r(errno, errStr, sizeof(errStr));
ee3a35
 				iRet = RS_RET_NO_FILE_ACCESS;
ee3a35
 				errmsg.LogError(0, iRet,
ee3a35
-						"error: certificate file %s couldn't be accessed: %s\n",
ee3a35
+						"error: 'tls.cacert' file %s couldn't be accessed: %s\n",
ee3a35
 						loadModConf->caCertFile, errStr);
ee3a35
 				ABORT_FINALIZE(iRet);
ee3a35
 			} else {
ee3a35
 				fclose(fp);
ee3a35
+				fp = NULL;
ee3a35
+			}
ee3a35
+		} else if(!strcmp(modpblk.descr[i].name, "tls.mycert")) {
ee3a35
+			free(loadModConf->myCertFile);
ee3a35
+			loadModConf->myCertFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
ee3a35
+			fp = fopen((const char*)loadModConf->myCertFile, "r");
ee3a35
+			if(fp == NULL) {
ee3a35
+				rs_strerror_r(errno, errStr, sizeof(errStr));
ee3a35
+				iRet = RS_RET_NO_FILE_ACCESS;
ee3a35
+				LogError(0, iRet,
ee3a35
+						"error: 'tls.mycert' file %s couldn't be accessed: %s\n",
ee3a35
+						loadModConf->myCertFile, errStr);
ee3a35
+			} else {
ee3a35
+				fclose(fp);
ee3a35
+				fp = NULL;
ee3a35
+			}
ee3a35
+		} else if(!strcmp(modpblk.descr[i].name, "tls.myprivkey")) {
ee3a35
+			loadModConf->myPrivKeyFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
ee3a35
+			fp = fopen((const char*)loadModConf->myPrivKeyFile, "r");
ee3a35
+			if(fp == NULL) {
ee3a35
+				rs_strerror_r(errno, errStr, sizeof(errStr));
ee3a35
+				iRet = RS_RET_NO_FILE_ACCESS;
ee3a35
+				LogError(0, iRet,
ee3a35
+						"error: 'tls.myprivkey' file %s couldn't be accessed: %s\n",
ee3a35
+						loadModConf->myPrivKeyFile, errStr);
ee3a35
+			} else {
ee3a35
+				fclose(fp);
ee3a35
+				fp = NULL;
ee3a35
 			}
ee3a35
 		} else if(!strcmp(modpblk.descr[i].name, "allowunsignedcerts")) {
ee3a35
 			loadModConf->allowUnsignedCerts = pvals[i].val.d.n;
ee3a35
@@ -557,6 +614,7 @@ CODESTARTsetModCnf
ee3a35
 				ABORT_FINALIZE(iRet);
ee3a35
 			} else {
ee3a35
 				fclose(fp);
ee3a35
+				fp = NULL;
ee3a35
 			}
ee3a35
 		} else if(!strcmp(modpblk.descr[i].name, "annotation_match")) {
ee3a35
 			free_annotationmatch(&loadModConf->annotation_match);
ee3a35
@@ -586,6 +643,7 @@ CODESTARTsetModCnf
ee3a35
 				ABORT_FINALIZE(iRet);
ee3a35
 			} else {
ee3a35
 				fclose(fp);
ee3a35
+				fp = NULL;
ee3a35
 			}
ee3a35
 #if HAVE_LOADSAMPLESFROMSTRING == 1
ee3a35
 		} else if(!strcmp(modpblk.descr[i].name, "containerrules")) {
ee3a35
@@ -606,7 +663,10 @@ CODESTARTsetModCnf
ee3a35
 				ABORT_FINALIZE(iRet);
ee3a35
 			} else {
ee3a35
 				fclose(fp);
ee3a35
+				fp = NULL;
ee3a35
 			}
ee3a35
+		} else if(!strcmp(modpblk.descr[i].name, "busyretryinterval")) {
ee3a35
+			loadModConf->busyRetryInterval = pvals[i].val.d.n;
ee3a35
 		} else {
ee3a35
 			dbgprintf("mmkubernetes: program error, non-handled "
ee3a35
 				"param '%s' in module() block\n", modpblk.descr[i].name);
ee3a35
@@ -650,6 +710,8 @@ CODESTARTsetModCnf
ee3a35
 	caches = calloc(1, sizeof(struct cache_s *));
ee3a35
 
ee3a35
 finalize_it:
ee3a35
+	if (fp)
ee3a35
+		fclose(fp);
ee3a35
 	if(pvals != NULL)
ee3a35
 		cnfparamvalsDestruct(pvals, &modpblk);
ee3a35
 ENDsetModCnf
ee3a35
@@ -667,6 +729,8 @@ CODESTARTfreeInstance
ee3a35
 	free(pData->srcMetadataDescr);
ee3a35
 	free(pData->dstMetadataPath);
ee3a35
 	free(pData->caCertFile);
ee3a35
+	free(pData->myCertFile);
ee3a35
+	free(pData->myPrivKeyFile);
ee3a35
 	free(pData->token);
ee3a35
 	free(pData->tokenFile);
ee3a35
 	free(pData->fnRules);
ee3a35
@@ -710,6 +774,45 @@ CODESTARTcreateWrkrInstance
ee3a35
 	char *tokenHdr = NULL;
ee3a35
 	FILE *fp = NULL;
ee3a35
 	char *token = NULL;
ee3a35
+	char *statsName = NULL;
ee3a35
+
ee3a35
+	CHKiRet(statsobj.Construct(&(pWrkrData->stats)));
ee3a35
+	if ((-1 == asprintf(&statsName, "mmkubernetes(%s)", pWrkrData->pData->kubernetesUrl)) ||
ee3a35
+		(!statsName)) {
ee3a35
+		ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
ee3a35
+	}
ee3a35
+	CHKiRet(statsobj.SetName(pWrkrData->stats, (uchar *)statsName));
ee3a35
+	free(statsName);
ee3a35
+	statsName = NULL;
ee3a35
+	CHKiRet(statsobj.SetOrigin(pWrkrData->stats, UCHAR_CONSTANT("mmkubernetes")));
ee3a35
+	STATSCOUNTER_INIT(pWrkrData->k8sRecordSeen, pWrkrData->mutK8sRecordSeen);
ee3a35
+	CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("recordseen"),
ee3a35
+		ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->k8sRecordSeen)));
ee3a35
+	STATSCOUNTER_INIT(pWrkrData->namespaceMetadataSuccess, pWrkrData->mutNamespaceMetadataSuccess);
ee3a35
+	CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("namespacemetadatasuccess"),
ee3a35
+		ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->namespaceMetadataSuccess)));
ee3a35
+	STATSCOUNTER_INIT(pWrkrData->namespaceMetadataNotFound, pWrkrData->mutNamespaceMetadataNotFound);
ee3a35
+	CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("namespacemetadatanotfound"),
ee3a35
+		ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->namespaceMetadataNotFound)));
ee3a35
+	STATSCOUNTER_INIT(pWrkrData->namespaceMetadataBusy, pWrkrData->mutNamespaceMetadataBusy);
ee3a35
+	CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("namespacemetadatabusy"),
ee3a35
+		ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->namespaceMetadataBusy)));
ee3a35
+	STATSCOUNTER_INIT(pWrkrData->namespaceMetadataError, pWrkrData->mutNamespaceMetadataError);
ee3a35
+	CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("namespacemetadataerror"),
ee3a35
+		ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->namespaceMetadataError)));
ee3a35
+	STATSCOUNTER_INIT(pWrkrData->podMetadataSuccess, pWrkrData->mutPodMetadataSuccess);
ee3a35
+	CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("podmetadatasuccess"),
ee3a35
+		ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->podMetadataSuccess)));
ee3a35
+	STATSCOUNTER_INIT(pWrkrData->podMetadataNotFound, pWrkrData->mutPodMetadataNotFound);
ee3a35
+	CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("podmetadatanotfound"),
ee3a35
+		ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->podMetadataNotFound)));
ee3a35
+	STATSCOUNTER_INIT(pWrkrData->podMetadataBusy, pWrkrData->mutPodMetadataBusy);
ee3a35
+	CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("podmetadatabusy"),
ee3a35
+		ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->podMetadataBusy)));
ee3a35
+	STATSCOUNTER_INIT(pWrkrData->podMetadataError, pWrkrData->mutPodMetadataError);
ee3a35
+	CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("podmetadataerror"),
ee3a35
+		ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->podMetadataError)));
ee3a35
+	CHKiRet(statsobj.ConstructFinalize(pWrkrData->stats));
ee3a35
 
ee3a35
 	hdr = curl_slist_append(hdr, "Content-Type: text/json; charset=utf-8");
ee3a35
 	if (pWrkrData->pData->token) {
ee3a35
@@ -749,12 +852,20 @@ CODESTARTcreateWrkrInstance
ee3a35
 	curl_easy_setopt(ctx, CURLOPT_WRITEDATA, pWrkrData);
ee3a35
 	if(pWrkrData->pData->caCertFile)
ee3a35
 		curl_easy_setopt(ctx, CURLOPT_CAINFO, pWrkrData->pData->caCertFile);
ee3a35
+	if(pWrkrData->pData->myCertFile)
ee3a35
+		curl_easy_setopt(ctx, CURLOPT_SSLCERT, pWrkrData->pData->myCertFile);
ee3a35
+	if(pWrkrData->pData->myPrivKeyFile)
ee3a35
+		curl_easy_setopt(ctx, CURLOPT_SSLKEY, pWrkrData->pData->myPrivKeyFile);
ee3a35
 	if(pWrkrData->pData->allowUnsignedCerts)
ee3a35
 		curl_easy_setopt(ctx, CURLOPT_SSL_VERIFYPEER, 0);
ee3a35
 
ee3a35
 	pWrkrData->curlCtx = ctx;
ee3a35
 finalize_it:
ee3a35
 	free(token);
ee3a35
+	free(statsName);
ee3a35
+	if ((iRet != RS_RET_OK) && pWrkrData->stats) {
ee3a35
+		statsobj.Destruct(&(pWrkrData->stats));
ee3a35
+	}
ee3a35
 	if (fp) {
ee3a35
 		fclose(fp);
ee3a35
 	}
ee3a35
@@ -765,6 +876,7 @@ BEGINfreeWrkrInstance
ee3a35
 CODESTARTfreeWrkrInstance
ee3a35
 	curl_easy_cleanup(pWrkrData->curlCtx);
ee3a35
 	curl_slist_free_all(pWrkrData->curlHdr);
ee3a35
+	statsobj.Destruct(&(pWrkrData->stats));
ee3a35
 ENDfreeWrkrInstance
ee3a35
 
ee3a35
 
ee3a35
@@ -790,6 +902,8 @@ cacheNew(const uchar *const url)
ee3a35
 		key_equals_string, (void (*)(void *)) json_object_put);
ee3a35
 	cache->nsHt = create_hashtable(100, hash_from_string,
ee3a35
 		key_equals_string, (void (*)(void *)) json_object_put);
ee3a35
+	dbgprintf("mmkubernetes: created cache mdht [%p] nsht [%p]\n",
ee3a35
+			cache->mdHt, cache->nsHt);
ee3a35
 	cache->cacheMtx = malloc(sizeof(pthread_mutex_t));
ee3a35
 	if (!cache->mdHt || !cache->nsHt || !cache->cacheMtx) {
ee3a35
 		free (cache);
ee3a35
@@ -797,6 +911,7 @@ cacheNew(const uchar *const url)
ee3a35
 		FINALIZE;
ee3a35
 	}
ee3a35
 	pthread_mutex_init(cache->cacheMtx, NULL);
ee3a35
+	cache->lastBusyTime = 0;
ee3a35
 
ee3a35
 finalize_it:
ee3a35
 	return cache;
ee3a35
@@ -816,9 +931,10 @@ static void cacheFree(struct cache_s *cache)
ee3a35
 BEGINnewActInst
ee3a35
 	struct cnfparamvals *pvals = NULL;
ee3a35
 	int i;
ee3a35
-	FILE *fp;
ee3a35
+	FILE *fp = NULL;
ee3a35
 	char *rxstr = NULL;
ee3a35
 	char *srcMetadataPath = NULL;
ee3a35
+	char errStr[1024];
ee3a35
 CODESTARTnewActInst
ee3a35
 	DBGPRINTF("newActInst (mmkubernetes)\n");
ee3a35
 
ee3a35
@@ -840,6 +956,7 @@ CODESTARTnewActInst
ee3a35
 
ee3a35
 	pData->de_dot = loadModConf->de_dot;
ee3a35
 	pData->allowUnsignedCerts = loadModConf->allowUnsignedCerts;
ee3a35
+	pData->busyRetryInterval = loadModConf->busyRetryInterval;
ee3a35
 	for(i = 0 ; i < actpblk.nParams ; ++i) {
ee3a35
 		if(!pvals[i].bUsed) {
ee3a35
 			continue;
ee3a35
@@ -872,6 +988,33 @@ CODESTARTnewActInst
ee3a35
 				ABORT_FINALIZE(iRet);
ee3a35
 			} else {
ee3a35
 				fclose(fp);
ee3a35
+				fp = NULL;
ee3a35
+			}
ee3a35
+		} else if(!strcmp(actpblk.descr[i].name, "tls.mycert")) {
ee3a35
+			pData->myCertFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
ee3a35
+			fp = fopen((const char*)pData->myCertFile, "r");
ee3a35
+			if(fp == NULL) {
ee3a35
+				rs_strerror_r(errno, errStr, sizeof(errStr));
ee3a35
+				iRet = RS_RET_NO_FILE_ACCESS;
ee3a35
+				LogError(0, iRet,
ee3a35
+						"error: 'tls.mycert' file %s couldn't be accessed: %s\n",
ee3a35
+						pData->myCertFile, errStr);
ee3a35
+			} else {
ee3a35
+				fclose(fp);
ee3a35
+				fp = NULL;
ee3a35
+			}
ee3a35
+		} else if(!strcmp(actpblk.descr[i].name, "tls.myprivkey")) {
ee3a35
+			pData->myPrivKeyFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
ee3a35
+			fp = fopen((const char*)pData->myPrivKeyFile, "r");
ee3a35
+			if(fp == NULL) {
ee3a35
+				rs_strerror_r(errno, errStr, sizeof(errStr));
ee3a35
+				iRet = RS_RET_NO_FILE_ACCESS;
ee3a35
+				LogError(0, iRet,
ee3a35
+						"error: 'tls.myprivkey' file %s couldn't be accessed: %s\n",
ee3a35
+						pData->myPrivKeyFile, errStr);
ee3a35
+			} else {
ee3a35
+				fclose(fp);
ee3a35
+				fp = NULL;
ee3a35
 			}
ee3a35
 		} else if(!strcmp(actpblk.descr[i].name, "allowunsignedcerts")) {
ee3a35
 			pData->allowUnsignedCerts = pvals[i].val.d.n;
ee3a35
@@ -892,6 +1034,7 @@ CODESTARTnewActInst
ee3a35
 				ABORT_FINALIZE(iRet);
ee3a35
 			} else {
ee3a35
 				fclose(fp);
ee3a35
+				fp = NULL;
ee3a35
 			}
ee3a35
 		} else if(!strcmp(actpblk.descr[i].name, "annotation_match")) {
ee3a35
 			free_annotationmatch(&pData->annotation_match);
ee3a35
@@ -921,6 +1063,7 @@ CODESTARTnewActInst
ee3a35
 				ABORT_FINALIZE(iRet);
ee3a35
 			} else {
ee3a35
 				fclose(fp);
ee3a35
+				fp = NULL;
ee3a35
 			}
ee3a35
 #if HAVE_LOADSAMPLESFROMSTRING == 1
ee3a35
 		} else if(!strcmp(modpblk.descr[i].name, "containerrules")) {
ee3a35
@@ -941,7 +1083,10 @@ CODESTARTnewActInst
ee3a35
 				ABORT_FINALIZE(iRet);
ee3a35
 			} else {
ee3a35
 				fclose(fp);
ee3a35
+				fp = NULL;
ee3a35
 			}
ee3a35
+		} else if(!strcmp(actpblk.descr[i].name, "busyretryinterval")) {
ee3a35
+			pData->busyRetryInterval = pvals[i].val.d.n;
ee3a35
 		} else {
ee3a35
 			dbgprintf("mmkubernetes: program error, non-handled "
ee3a35
 				"param '%s' in action() block\n", actpblk.descr[i].name);
ee3a35
@@ -982,6 +1127,10 @@ CODESTARTnewActInst
ee3a35
 		pData->dstMetadataPath = (uchar *) strdup((char *) loadModConf->dstMetadataPath);
ee3a35
 	if(pData->caCertFile == NULL && loadModConf->caCertFile)
ee3a35
 		pData->caCertFile = (uchar *) strdup((char *) loadModConf->caCertFile);
ee3a35
+	if(pData->myCertFile == NULL && loadModConf->myCertFile)
ee3a35
+		pData->myCertFile = (uchar *) strdup((char *) loadModConf->myCertFile);
ee3a35
+	if(pData->myPrivKeyFile == NULL && loadModConf->myPrivKeyFile)
ee3a35
+		pData->myPrivKeyFile = (uchar *) strdup((char *) loadModConf->myPrivKeyFile);
ee3a35
 	if(pData->token == NULL && loadModConf->token)
ee3a35
 		pData->token = (uchar *) strdup((char *) loadModConf->token);
ee3a35
 	if(pData->tokenFile == NULL && loadModConf->tokenFile)
ee3a35
@@ -1018,6 +1167,8 @@ CODESTARTnewActInst
ee3a35
 CODE_STD_FINALIZERnewActInst
ee3a35
 	if(pvals != NULL)
ee3a35
 		cnfparamvalsDestruct(pvals, &actpblk);
ee3a35
+	if(fp)
ee3a35
+		fclose(fp);
ee3a35
 	free(rxstr);
ee3a35
 	free(srcMetadataPath);
ee3a35
 ENDnewActInst
ee3a35
@@ -1061,6 +1212,8 @@ CODESTARTfreeCnf
ee3a35
 	free(pModConf->srcMetadataPath);
ee3a35
 	free(pModConf->dstMetadataPath);
ee3a35
 	free(pModConf->caCertFile);
ee3a35
+	free(pModConf->myCertFile);
ee3a35
+	free(pModConf->myPrivKeyFile);
ee3a35
 	free(pModConf->token);
ee3a35
 	free(pModConf->tokenFile);
ee3a35
 	free(pModConf->de_dot_separator);
ee3a35
@@ -1069,8 +1222,11 @@ CODESTARTfreeCnf
ee3a35
 	free(pModConf->contRules);
ee3a35
 	free(pModConf->contRulebase);
ee3a35
 	free_annotationmatch(&pModConf->annotation_match);
ee3a35
-	for(i = 0; caches[i] != NULL; i++)
ee3a35
+	for(i = 0; caches[i] != NULL; i++) {
ee3a35
+		dbgprintf("mmkubernetes: freeing cache [%d] mdht [%p] nsht [%p]\n",
ee3a35
+				i, caches[i]->mdHt, caches[i]->nsHt);
ee3a35
 		cacheFree(caches[i]);
ee3a35
+	}
ee3a35
 	free(caches);
ee3a35
 ENDfreeCnf
ee3a35
 
ee3a35
@@ -1082,6 +1238,8 @@ CODESTARTdbgPrintInstInfo
ee3a35
 	dbgprintf("\tsrcMetadataPath='%s'\n", pData->srcMetadataDescr->name);
ee3a35
 	dbgprintf("\tdstMetadataPath='%s'\n", pData->dstMetadataPath);
ee3a35
 	dbgprintf("\ttls.cacert='%s'\n", pData->caCertFile);
ee3a35
+	dbgprintf("\ttls.mycert='%s'\n", pData->myCertFile);
ee3a35
+	dbgprintf("\ttls.myprivkey='%s'\n", pData->myPrivKeyFile);
ee3a35
 	dbgprintf("\tallowUnsignedCerts='%d'\n", pData->allowUnsignedCerts);
ee3a35
 	dbgprintf("\ttoken='%s'\n", pData->token);
ee3a35
 	dbgprintf("\ttokenFile='%s'\n", pData->tokenFile);
ee3a35
@@ -1093,6 +1251,7 @@ CODESTARTdbgPrintInstInfo
ee3a35
 	dbgprintf("\tfilenamerules='%s'\n", pData->fnRules);
ee3a35
 	dbgprintf("\tcontainerrules='%s'\n", pData->contRules);
ee3a35
 #endif
ee3a35
+	dbgprintf("\tbusyretryinterval='%d'\n", pData->busyRetryInterval);
ee3a35
 ENDdbgPrintInstInfo
ee3a35
 
ee3a35
 
ee3a35
@@ -1206,6 +1365,24 @@ queryKB(wrkrInstanceData_t *pWrkrData, char *url, struct json_object **rply)
ee3a35
 	struct json_object *jo;
ee3a35
 	long resp_code = 400;
ee3a35
 
ee3a35
+	if (pWrkrData->pData->cache->lastBusyTime) {
ee3a35
+		time_t now;
ee3a35
+		datetime.GetTime(&now;;
ee3a35
+		now -= pWrkrData->pData->cache->lastBusyTime;
ee3a35
+		if (now < pWrkrData->pData->busyRetryInterval) {
ee3a35
+			LogMsg(0, RS_RET_RETRY, LOG_DEBUG,
ee3a35
+				"mmkubernetes: Waited [%ld] of [%d] seconds for the requested url [%s]\n",
ee3a35
+				now, pWrkrData->pData->busyRetryInterval, url);
ee3a35
+			ABORT_FINALIZE(RS_RET_RETRY);
ee3a35
+		} else {
ee3a35
+			LogMsg(0, RS_RET_OK, LOG_DEBUG,
ee3a35
+				"mmkubernetes: Cleared busy status after [%d] seconds - "
ee3a35
+				"will retry the requested url [%s]\n",
ee3a35
+				pWrkrData->pData->busyRetryInterval, url);
ee3a35
+			pWrkrData->pData->cache->lastBusyTime = 0;
ee3a35
+		}
ee3a35
+	}
ee3a35
+
ee3a35
 	/* query kubernetes for pod info */
ee3a35
 	ccode = curl_easy_setopt(pWrkrData->curlCtx, CURLOPT_URL, url);
ee3a35
 	if(ccode != CURLE_OK)
ee3a35
@@ -1411,17 +1411,23 @@ queryKB(wrkrInstanceData_t *pWrkrData, char *url, struct json_object **rply)
ee3a35
 		ABORT_FINALIZE(RS_RET_ERR);
ee3a35
 	}
ee3a35
 	if(resp_code == 404) {
ee3a35
-		errmsg.LogMsg(0, RS_RET_ERR, LOG_ERR,
ee3a35
+		errmsg.LogMsg(0, RS_RET_NOT_FOUND, LOG_INFO,
ee3a35
 			      "mmkubernetes: Not Found: the resource does not exist at url [%s]\n",
ee3a35
 			      url);
ee3a35
-		ABORT_FINALIZE(RS_RET_ERR);
ee3a35
+		ABORT_FINALIZE(RS_RET_NOT_FOUND);
ee3a35
 	}
ee3a35
 	if(resp_code == 429) {
ee3a35
-		errmsg.LogMsg(0, RS_RET_ERR, LOG_ERR,
ee3a35
+		if (pWrkrData->pData->busyRetryInterval) {
ee3a35
+			time_t now;
ee3a35
+			datetime.GetTime(&now;;
ee3a35
+			pWrkrData->pData->cache->lastBusyTime = now;
ee3a35
+		}
ee3a35
+
ee3a35
+		errmsg.LogMsg(0, RS_RET_RETRY, LOG_INFO,
ee3a35
 			      "mmkubernetes: Too Many Requests: the server is too heavily loaded "
ee3a35
 			      "to provide the data for the requested url [%s]\n",
ee3a35
 			      url);
ee3a35
-		ABORT_FINALIZE(RS_RET_ERR);
ee3a35
+		ABORT_FINALIZE(RS_RET_RETRY);
ee3a35
 	}
ee3a35
 	if(resp_code != 200) {
ee3a35
 		errmsg.LogMsg(0, RS_RET_ERR, LOG_ERR,
ee3a35
@@ -1299,12 +1482,14 @@ BEGINdoAction
ee3a35
 	char *mdKey = NULL;
ee3a35
 	struct json_object *jMetadata = NULL, *jMetadataCopy = NULL, *jMsgMeta = NULL,
ee3a35
 			*jo = NULL;
ee3a35
-	int add_ns_metadata = 0;
ee3a35
+	int add_pod_metadata = 1;
ee3a35
 CODESTARTdoAction
ee3a35
 	CHKiRet_Hdlr(extractMsgMetadata(pMsg, pWrkrData->pData, &jMsgMeta)) {
ee3a35
 		ABORT_FINALIZE((iRet == RS_RET_NOT_FOUND) ? RS_RET_OK : iRet);
ee3a35
 	}
ee3a35
 
ee3a35
+	STATSCOUNTER_INC(pWrkrData->k8sRecordSeen, pWrkrData->mutK8sRecordSeen);
ee3a35
+
ee3a35
 	if (fjson_object_object_get_ex(jMsgMeta, "pod_name", &jo))
ee3a35
 		podName = json_object_get_string(jo);
ee3a35
 	if (fjson_object_object_get_ex(jMsgMeta, "namespace_name", &jo))
ee3a35
@@ -1347,28 +1532,49 @@ CODESTARTdoAction
ee3a35
 			}
ee3a35
 			iRet = queryKB(pWrkrData, url, &jReply);
ee3a35
 			free(url);
ee3a35
-			/* todo: implement support for the .orphaned namespace */
ee3a35
-			if (iRet != RS_RET_OK) {
ee3a35
+			if (iRet == RS_RET_NOT_FOUND) {
ee3a35
+				/* negative cache namespace - make a dummy empty namespace metadata object */
ee3a35
+				jNsMeta = json_object_new_object();
ee3a35
+				STATSCOUNTER_INC(pWrkrData->namespaceMetadataNotFound,
ee3a35
+						 pWrkrData->mutNamespaceMetadataNotFound);
ee3a35
+			} else if (iRet == RS_RET_RETRY) {
ee3a35
+				/* server is busy - retry or error */
ee3a35
+				STATSCOUNTER_INC(pWrkrData->namespaceMetadataBusy,
ee3a35
+						 pWrkrData->mutNamespaceMetadataBusy);
ee3a35
+				if (0 == pWrkrData->pData->busyRetryInterval) {
ee3a35
+					pthread_mutex_unlock(pWrkrData->pData->cache->cacheMtx);
ee3a35
+					ABORT_FINALIZE(RS_RET_ERR);
ee3a35
+				}
ee3a35
+				add_pod_metadata = 0; /* don't cache pod metadata either - retry both */
ee3a35
+			} else if (iRet != RS_RET_OK) {
ee3a35
+				/* hard error - something the admin needs to fix e.g. network, config, auth */
ee3a35
 				json_object_put(jReply);
ee3a35
 				jReply = NULL;
ee3a35
+				STATSCOUNTER_INC(pWrkrData->namespaceMetadataError,
ee3a35
+						 pWrkrData->mutNamespaceMetadataError);
ee3a35
 				pthread_mutex_unlock(pWrkrData->pData->cache->cacheMtx);
ee3a35
 				FINALIZE;
ee3a35
-			}
ee3a35
-
ee3a35
-			if(fjson_object_object_get_ex(jReply, "metadata", &jNsMeta)) {
ee3a35
+			} else if (fjson_object_object_get_ex(jReply, "metadata", &jNsMeta)) {
ee3a35
 				jNsMeta = json_object_get(jNsMeta);
ee3a35
 				parse_labels_annotations(jNsMeta, &pWrkrData->pData->annotation_match,
ee3a35
 					pWrkrData->pData->de_dot,
ee3a35
 					(const char *)pWrkrData->pData->de_dot_separator,
ee3a35
 					pWrkrData->pData->de_dot_separator_len);
ee3a35
-				add_ns_metadata = 1;
ee3a35
+				STATSCOUNTER_INC(pWrkrData->namespaceMetadataSuccess,
ee3a35
+						 pWrkrData->mutNamespaceMetadataSuccess);
ee3a35
 			} else {
ee3a35
 				/* namespace with no metadata??? */
ee3a35
 				errmsg.LogMsg(0, RS_RET_ERR, LOG_INFO,
ee3a35
 					      "mmkubernetes: namespace [%s] has no metadata!\n", ns);
ee3a35
-				jNsMeta = NULL;
ee3a35
+				/* negative cache namespace - make a dummy empty namespace metadata object */
ee3a35
+				jNsMeta = json_object_new_object();
ee3a35
+				STATSCOUNTER_INC(pWrkrData->namespaceMetadataSuccess,
ee3a35
+						 pWrkrData->mutNamespaceMetadataSuccess);
ee3a35
 			}
ee3a35
 
ee3a35
+			if(jNsMeta) {
ee3a35
+				hashtable_insert(pWrkrData->pData->cache->nsHt, strdup(ns), jNsMeta);
ee3a35
+			}
ee3a35
 			json_object_put(jReply);
ee3a35
 			jReply = NULL;
ee3a35
 		}
ee3a35
@@ -1381,14 +1587,28 @@ CODESTARTdoAction
ee3a35
 		}
ee3a35
 		iRet = queryKB(pWrkrData, url, &jReply);
ee3a35
 		free(url);
ee3a35
-		if(iRet != RS_RET_OK) {
ee3a35
-			if(jNsMeta && add_ns_metadata) {
ee3a35
-				hashtable_insert(pWrkrData->pData->cache->nsHt, strdup(ns), jNsMeta);
ee3a35
+		if (iRet == RS_RET_NOT_FOUND) {
ee3a35
+			/* negative cache pod - make a dummy empty pod metadata object */
ee3a35
+			iRet = RS_RET_OK;
ee3a35
+			STATSCOUNTER_INC(pWrkrData->podMetadataNotFound, pWrkrData->mutPodMetadataNotFound);
ee3a35
+		} else if (iRet == RS_RET_RETRY) {
ee3a35
+			/* server is busy - retry or error */
ee3a35
+			STATSCOUNTER_INC(pWrkrData->podMetadataBusy, pWrkrData->mutPodMetadataBusy);
ee3a35
+			if (0 == pWrkrData->pData->busyRetryInterval) {
ee3a35
+				pthread_mutex_unlock(pWrkrData->pData->cache->cacheMtx);
ee3a35
+				ABORT_FINALIZE(RS_RET_ERR);
ee3a35
 			}
ee3a35
+			add_pod_metadata = 0; /* do not cache so that we can retry */
ee3a35
+			iRet = RS_RET_OK;
ee3a35
+		} else if(iRet != RS_RET_OK) {
ee3a35
+			/* hard error - something the admin needs to fix e.g. network, config, auth */
ee3a35
 			json_object_put(jReply);
ee3a35
 			jReply = NULL;
ee3a35
+			STATSCOUNTER_INC(pWrkrData->podMetadataError, pWrkrData->mutPodMetadataError);
ee3a35
 			pthread_mutex_unlock(pWrkrData->pData->cache->cacheMtx);
ee3a35
 			FINALIZE;
ee3a35
+		} else {
ee3a35
+			STATSCOUNTER_INC(pWrkrData->podMetadataSuccess, pWrkrData->mutPodMetadataSuccess);
ee3a35
 		}
ee3a35
 
ee3a35
 		jo = json_object_new_object();
ee3a35
@@ -1435,11 +1655,9 @@ CODESTARTdoAction
ee3a35
 			json_object_object_add(jo, "container_id", json_object_get(jo2));
ee3a35
 		json_object_object_add(jMetadata, "docker", jo);
ee3a35
 
ee3a35
-		hashtable_insert(pWrkrData->pData->cache->mdHt, mdKey, jMetadata);
ee3a35
-		mdKey = NULL;
ee3a35
-		if(jNsMeta && add_ns_metadata) {
ee3a35
-			hashtable_insert(pWrkrData->pData->cache->nsHt, strdup(ns), jNsMeta);
ee3a35
-			ns = NULL;
ee3a35
+		if (add_pod_metadata) {
ee3a35
+			hashtable_insert(pWrkrData->pData->cache->mdHt, mdKey, jMetadata);
ee3a35
+			mdKey = NULL;
ee3a35
 		}
ee3a35
 	}
ee3a35
 
ee3a35
@@ -1450,6 +1668,11 @@ CODESTARTdoAction
ee3a35
 	 * outside of the cache lock
ee3a35
 	 */
ee3a35
 	jMetadataCopy = json_tokener_parse(json_object_get_string(jMetadata));
ee3a35
+	if (!add_pod_metadata) {
ee3a35
+		/* jMetadata object was created from scratch and not cached */
ee3a35
+		json_object_put(jMetadata);
ee3a35
+		jMetadata = NULL;
ee3a35
+	}
ee3a35
 	pthread_mutex_unlock(pWrkrData->pData->cache->cacheMtx);
ee3a35
 	/* the +1 is there to skip the leading '$' */
ee3a35
 	msgAddJSON(pMsg, (uchar *) pWrkrData->pData->dstMetadataPath + 1, jMetadataCopy, 0, 0);
ee3a35
@@ -1691,6 +1693,8 @@ BEGINmodExit
ee3a35
 
ee3a35
 	objRelease(regexp, LM_REGEXP_FILENAME);
ee3a35
 	objRelease(errmsg, CORE_COMPONENT);
ee3a35
+	objRelease(datetime, CORE_COMPONENT);
ee3a35
+	objRelease(statsobj, CORE_COMPONENT);
ee3a35
 ENDmodExit
ee3a35
 
ee3a35
 
ee3a35
@@ -1705,6 +1711,8 @@ CODEmodInit_QueryRegCFSLineHdlr
ee3a35
 	DBGPRINTF("mmkubernetes: module compiled with rsyslog version %s.\n", VERSION);
ee3a35
 	CHKiRet(objUse(errmsg, CORE_COMPONENT));
ee3a35
 	CHKiRet(objUse(regexp, LM_REGEXP_FILENAME));
ee3a35
+	CHKiRet(objUse(datetime, CORE_COMPONENT));
ee3a35
+	CHKiRet(objUse(statsobj, CORE_COMPONENT));
ee3a35
 
ee3a35
 	/* CURL_GLOBAL_ALL initializes more than is needed but the
ee3a35
 	 * libcurl documentation discourages use of other values
ee3a35
--- a/contrib/mmkubernetes/mmkubernetes.c
ee3a35
+++ b/contrib/mmkubernetes/mmkubernetes.c
ee3a35
@@ -560,7 +560,6 @@
ee3a35
 			loadModConf->caCertFile = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL);
ee3a35
 			fp = fopen((const char*)loadModConf->caCertFile, "r");
ee3a35
 			if(fp == NULL) {
ee3a35
-				char errStr[1024];
ee3a35
 				rs_strerror_r(errno, errStr, sizeof(errStr));
ee3a35
 				iRet = RS_RET_NO_FILE_ACCESS;
ee3a35
 				errmsg.LogError(0, iRet,
ee3a35
@@ -608,7 +607,6 @@
ee3a35
 			loadModConf->tokenFile = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL);
ee3a35
 			fp = fopen((const char*)loadModConf->tokenFile, "r");
ee3a35
 			if(fp == NULL) {
ee3a35
-				char errStr[1024];
ee3a35
 				rs_strerror_r(errno, errStr, sizeof(errStr));
ee3a35
 				iRet = RS_RET_NO_FILE_ACCESS;
ee3a35
 				errmsg.LogError(0, iRet,
ee3a35
@@ -638,7 +636,6 @@
ee3a35
 			loadModConf->fnRulebase = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL);
ee3a35
 			fp = fopen((const char*)loadModConf->fnRulebase, "r");
ee3a35
 			if(fp == NULL) {
ee3a35
-				char errStr[1024];
ee3a35
 				rs_strerror_r(errno, errStr, sizeof(errStr));
ee3a35
 				iRet = RS_RET_NO_FILE_ACCESS;
ee3a35
 				errmsg.LogError(0, iRet,
ee3a35
@@ -659,7 +656,6 @@
ee3a35
 			loadModConf->contRulebase = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL);
ee3a35
 			fp = fopen((const char*)loadModConf->contRulebase, "r");
ee3a35
 			if(fp == NULL) {
ee3a35
-				char errStr[1024];
ee3a35
 				rs_strerror_r(errno, errStr, sizeof(errStr));
ee3a35
 				iRet = RS_RET_NO_FILE_ACCESS;
ee3a35
 				errmsg.LogError(0, iRet,
ee3a35
@@ -975,7 +971,6 @@
ee3a35
 			pData->caCertFile = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL);
ee3a35
 			fp = fopen((const char*)pData->caCertFile, "r");
ee3a35
 			if(fp == NULL) {
ee3a35
-				char errStr[1024];
ee3a35
 				rs_strerror_r(errno, errStr, sizeof(errStr));
ee3a35
 				iRet = RS_RET_NO_FILE_ACCESS;
ee3a35
 				errmsg.LogError(0, iRet,
ee3a35
@@ -1022,7 +1017,6 @@
ee3a35
 			pData->tokenFile = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL);
ee3a35
 			fp = fopen((const char*)pData->tokenFile, "r");
ee3a35
 			if(fp == NULL) {
ee3a35
-				char errStr[1024];
ee3a35
 				rs_strerror_r(errno, errStr, sizeof(errStr));
ee3a35
 				iRet = RS_RET_NO_FILE_ACCESS;
ee3a35
 				errmsg.LogError(0, iRet,
ee3a35
@@ -1052,7 +1046,6 @@
ee3a35
 			pData->fnRulebase = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL);
ee3a35
 			fp = fopen((const char*)pData->fnRulebase, "r");
ee3a35
 			if(fp == NULL) {
ee3a35
-				char errStr[1024];
ee3a35
 				rs_strerror_r(errno, errStr, sizeof(errStr));
ee3a35
 				iRet = RS_RET_NO_FILE_ACCESS;
ee3a35
 				errmsg.LogError(0, iRet,
ee3a35
@@ -1073,7 +1066,6 @@
ee3a35
 			pData->contRulebase = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL);
ee3a35
 			fp = fopen((const char*)pData->contRulebase, "r");
ee3a35
 			if(fp == NULL) {
ee3a35
-				char errStr[1024];
ee3a35
 				rs_strerror_r(errno, errStr, sizeof(errStr));
ee3a35
 				iRet = RS_RET_NO_FILE_ACCESS;
ee3a35
 				errmsg.LogError(0, iRet,