summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml3
-rw-r--r--.github/workflows/daily.yml12
-rw-r--r--TLS.md17
-rw-r--r--deps/Makefile2
-rw-r--r--src/Makefile39
-rw-r--r--src/connection.h13
-rwxr-xr-xsrc/mkreleasehdr.sh2
-rw-r--r--src/module.c8
-rw-r--r--src/redismodule.h44
-rw-r--r--src/release.c7
-rw-r--r--src/sentinel.c16
-rw-r--r--src/server.c152
-rw-r--r--src/server.h25
-rw-r--r--src/tls.c62
-rw-r--r--tests/instances.tcl11
-rw-r--r--tests/modules/defragtest.c4
-rw-r--r--tests/support/server.tcl5
-rw-r--r--tests/support/util.tcl22
-rw-r--r--tests/test_helper.tcl7
-rw-r--r--tests/unit/moduleapi/infra.tcl9
-rw-r--r--tests/unit/moduleapi/moduleconfigs.tcl40
21 files changed, 302 insertions, 198 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2b406f74b..f6a61b0e0 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -24,7 +24,8 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: make
- run: make SANITIZER=address REDIS_CFLAGS='-Werror'
+ # build with TLS module just for compilation coverage
+ run: make SANITIZER=address REDIS_CFLAGS='-Werror' BUILD_TLS=module
- name: testprep
run: sudo apt-get install tcl8.6 tclx -y
- name: test
diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml
index da3c8a21f..e9e0549af 100644
--- a/.github/workflows/daily.yml
+++ b/.github/workflows/daily.yml
@@ -539,7 +539,7 @@ jobs:
run: |
yum -y install centos-release-scl epel-release
yum -y install devtoolset-7 openssl-devel openssl
- scl enable devtoolset-7 "make BUILD_TLS=yes REDIS_CFLAGS='-Werror'"
+ scl enable devtoolset-7 "make BUILD_TLS=module REDIS_CFLAGS='-Werror'"
- name: testprep
run: |
yum -y install tcl tcltls tclx
@@ -547,19 +547,19 @@ jobs:
- name: test
if: true && !contains(github.event.inputs.skiptests, 'redis')
run: |
- ./runtest --accurate --verbose --dump-logs --tls --dump-logs ${{github.event.inputs.test_args}}
+ ./runtest --accurate --verbose --dump-logs --tls-module --dump-logs ${{github.event.inputs.test_args}}
- name: module api test
if: true && !contains(github.event.inputs.skiptests, 'modules')
run: |
- ./runtest-moduleapi --verbose --dump-logs --tls --dump-logs ${{github.event.inputs.test_args}}
+ ./runtest-moduleapi --verbose --dump-logs --tls-module --dump-logs ${{github.event.inputs.test_args}}
- name: sentinel tests
if: true && !contains(github.event.inputs.skiptests, 'sentinel')
run: |
- ./runtest-sentinel --tls ${{github.event.inputs.cluster_test_args}}
+ ./runtest-sentinel ${{github.event.inputs.cluster_test_args}}
- name: cluster tests
if: true && !contains(github.event.inputs.skiptests, 'cluster')
run: |
- ./runtest-cluster --tls ${{github.event.inputs.cluster_test_args}}
+ ./runtest-cluster --tls-module ${{github.event.inputs.cluster_test_args}}
test-centos7-tls-no-tls:
runs-on: ubuntu-latest
@@ -582,7 +582,7 @@ jobs:
run: |
yum -y install centos-release-scl epel-release
yum -y install devtoolset-7 openssl-devel openssl
- scl enable devtoolset-7 "make BUILD_TLS=yes REDIS_CFLAGS='-Werror'"
+ scl enable devtoolset-7 "make BUILD_TLS=module REDIS_CFLAGS='-Werror'"
- name: testprep
run: |
yum -y install tcl tcltls tclx
diff --git a/TLS.md b/TLS.md
index 2d020d0ce..b9bce7edc 100644
--- a/TLS.md
+++ b/TLS.md
@@ -9,8 +9,14 @@ Getting Started
To build with TLS support you'll need OpenSSL development libraries (e.g.
libssl-dev on Debian/Ubuntu).
+To build TLS support as Redis built-in:
Run `make BUILD_TLS=yes`.
+Or to build TLS as Redis module:
+Run `make BUILD_TLS=module`.
+
+Note that sentinel mode does not support TLS module.
+
### Tests
To run Redis test suite with TLS, you'll need TLS support for TCL (i.e.
@@ -22,16 +28,27 @@ To run Redis test suite with TLS, you'll need TLS support for TCL (i.e.
2. Run `./runtest --tls` or `./runtest-cluster --tls` to run Redis and Redis
Cluster tests in TLS mode.
+3. Run `./runtest --tls-module` or `./runtest-cluster --tls-module` to
+ run Redis and Redis cluster tests in TLS mode with Redis module.
+
### Running manually
To manually run a Redis server with TLS mode (assuming `gen-test-certs.sh` was
invoked so sample certificates/keys are available):
+For TLS built-in mode:
./src/redis-server --tls-port 6379 --port 0 \
--tls-cert-file ./tests/tls/redis.crt \
--tls-key-file ./tests/tls/redis.key \
--tls-ca-cert-file ./tests/tls/ca.crt
+For TLS module mode:
+ ./src/redis-server --tls-port 6379 --port 0 \
+ --tls-cert-file ./tests/tls/redis.crt \
+ --tls-key-file ./tests/tls/redis.key \
+ --tls-ca-cert-file ./tests/tls/ca.crt \
+ --loadmodule src/redis-tls.so
+
To connect to this Redis server with `redis-cli`:
./src/redis-cli --tls \
diff --git a/deps/Makefile b/deps/Makefile
index 8592e1766..96dbb8c1d 100644
--- a/deps/Makefile
+++ b/deps/Makefile
@@ -44,7 +44,7 @@ distclean:
.PHONY: distclean
-ifeq ($(BUILD_TLS),yes)
+ifneq (,$(filter $(BUILD_TLS),yes module))
HIREDIS_MAKE_FLAGS = USE_SSL=1
endif
diff --git a/src/Makefile b/src/Makefile
index 814f3c0aa..fdfef2b3c 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -267,24 +267,41 @@ ifeq ($(MALLOC),jemalloc)
FINAL_LIBS := ../deps/jemalloc/lib/libjemalloc.a $(FINAL_LIBS)
endif
-ifeq ($(BUILD_TLS),yes)
- FINAL_CFLAGS+=-DUSE_OPENSSL $(OPENSSL_CFLAGS)
- FINAL_LDFLAGS+=$(OPENSSL_LDFLAGS)
- LIBSSL_PKGCONFIG := $(shell $(PKG_CONFIG) --exists libssl && echo $$?)
+# LIBSSL & LIBCRYPTO
+LIBSSL_LIBS=
+LIBSSL_PKGCONFIG := $(shell $(PKG_CONFIG) --exists libssl && echo $$?)
ifeq ($(LIBSSL_PKGCONFIG),0)
LIBSSL_LIBS=$(shell $(PKG_CONFIG) --libs libssl)
else
LIBSSL_LIBS=-lssl
endif
- LIBCRYPTO_PKGCONFIG := $(shell $(PKG_CONFIG) --exists libcrypto && echo $$?)
+LIBCRYPTO_LIBS=
+LIBCRYPTO_PKGCONFIG := $(shell $(PKG_CONFIG) --exists libcrypto && echo $$?)
ifeq ($(LIBCRYPTO_PKGCONFIG),0)
LIBCRYPTO_LIBS=$(shell $(PKG_CONFIG) --libs libcrypto)
else
LIBCRYPTO_LIBS=-lcrypto
endif
+
+BUILD_NO:=0
+BUILD_YES:=1
+BUILD_MODULE:=2
+ifeq ($(BUILD_TLS),yes)
+ FINAL_CFLAGS+=-DUSE_OPENSSL=$(BUILD_YES) $(OPENSSL_CFLAGS) -DBUILD_TLS_MODULE=$(BUILD_NO)
+ FINAL_LDFLAGS+=$(OPENSSL_LDFLAGS)
FINAL_LIBS += ../deps/hiredis/libhiredis_ssl.a $(LIBSSL_LIBS) $(LIBCRYPTO_LIBS)
endif
+TLS_MODULE=
+TLS_MODULE_NAME:=redis-tls$(PROG_SUFFIX).so
+TLS_MODULE_CFLAGS:=$(FINAL_CFLAGS)
+ifeq ($(BUILD_TLS),module)
+ FINAL_CFLAGS+=-DUSE_OPENSSL=$(BUILD_MODULE) $(OPENSSL_CFLAGS)
+ TLS_CLIENT_LIBS = ../deps/hiredis/libhiredis_ssl.a $(LIBSSL_LIBS) $(LIBCRYPTO_LIBS)
+ TLS_MODULE=$(TLS_MODULE_NAME)
+ TLS_MODULE_CFLAGS+=-DUSE_OPENSSL=$(BUILD_MODULE) $(OPENSSL_CFLAGS) -DBUILD_TLS_MODULE=$(BUILD_MODULE)
+endif
+
ifndef V
define MAKE_INSTALL
@printf ' %b %b\n' $(LINKCOLOR)INSTALL$(ENDCOLOR) $(BINCOLOR)$(1)$(ENDCOLOR) 1>&2
@@ -325,7 +342,7 @@ REDIS_CHECK_RDB_NAME=redis-check-rdb$(PROG_SUFFIX)
REDIS_CHECK_AOF_NAME=redis-check-aof$(PROG_SUFFIX)
ALL_SOURCES=$(sort $(patsubst %.o,%.c,$(REDIS_SERVER_OBJ) $(REDIS_CLI_OBJ) $(REDIS_BENCHMARK_OBJ)))
-all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME)
+all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) $(TLS_MODULE)
@echo ""
@echo "Hint: It's a good idea to run 'make test' ;)"
@echo ""
@@ -385,13 +402,17 @@ $(REDIS_CHECK_RDB_NAME): $(REDIS_SERVER_NAME)
$(REDIS_CHECK_AOF_NAME): $(REDIS_SERVER_NAME)
$(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_CHECK_AOF_NAME)
+# redis-tls.so
+$(TLS_MODULE_NAME): $(REDIS_SERVER_NAME)
+ $(QUIET_CC)$(CC) -o $@ tls.c -shared -fPIC $(TLS_MODULE_CFLAGS) $(TLS_CLIENT_LIBS)
+
# redis-cli
$(REDIS_CLI_NAME): $(REDIS_CLI_OBJ)
- $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o $(FINAL_LIBS)
+ $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o $(FINAL_LIBS) $(TLS_CLIENT_LIBS)
# redis-benchmark
$(REDIS_BENCHMARK_NAME): $(REDIS_BENCHMARK_OBJ)
- $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/hdr_histogram/libhdrhistogram.a $(FINAL_LIBS)
+ $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/hdr_histogram/libhdrhistogram.a $(FINAL_LIBS) $(TLS_CLIENT_LIBS)
DEP = $(REDIS_SERVER_OBJ:%.o=%.d) $(REDIS_CLI_OBJ:%.o=%.d) $(REDIS_BENCHMARK_OBJ:%.o=%.d)
-include $(DEP)
@@ -410,7 +431,7 @@ commands.c: commands/*.json ../utils/generate-command-code.py
endif
clean:
- rm -rf $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) *.o *.gcda *.gcno *.gcov redis.info lcov-html Makefile.dep
+ rm -rf $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) *.o *.gcda *.gcno *.gcov redis.info lcov-html Makefile.dep *.so
rm -f $(DEP)
.PHONY: clean
diff --git a/src/connection.h b/src/connection.h
index 9fe5277e5..61ca205fe 100644
--- a/src/connection.h
+++ b/src/connection.h
@@ -107,8 +107,6 @@ typedef struct ConnectionType {
/* TLS specified methods */
sds (*get_peer_cert)(struct connection *conn);
- void* (*get_ctx)(void);
- void* (*get_client_ctx)(void);
} ConnectionType;
struct connection {
@@ -355,15 +353,6 @@ int connKeepAlive(connection *conn, int interval);
int connSendTimeout(connection *conn, long long ms);
int connRecvTimeout(connection *conn, long long ms);
-/* Helpers for tls special considerations */
-static inline void *connTypeGetCtx(ConnectionType *ct) {
- return ct->get_ctx();
-}
-
-static inline void *connTypeGetClientCtx(ConnectionType *ct) {
- return ct->get_client_ctx();
-}
-
/* Get cert for the secure connection */
static inline sds connGetPeerCert(connection *conn) {
if (conn->type->get_peer_cert) {
@@ -399,7 +388,7 @@ static inline connection *connCreate(ConnectionType *ct) {
return ct->conn_create();
}
-/* Create a accepted connection of specified type.
+/* Create an accepted connection of specified type.
* priv is connection type specified argument */
static inline connection *connCreateAccepted(ConnectionType *ct, int fd, void *priv) {
return ct->conn_create_accepted(fd, priv);
diff --git a/src/mkreleasehdr.sh b/src/mkreleasehdr.sh
index 236c26c2b..117b9e86f 100755
--- a/src/mkreleasehdr.sh
+++ b/src/mkreleasehdr.sh
@@ -11,4 +11,6 @@ test -f release.h || touch release.h
echo "#define REDIS_GIT_SHA1 \"$GIT_SHA1\"" > release.h
echo "#define REDIS_GIT_DIRTY \"$GIT_DIRTY\"" >> release.h
echo "#define REDIS_BUILD_ID \"$BUILD_ID\"" >> release.h
+echo "#include \"version.h\"" >> release.h
+echo "#define REDIS_BUILD_ID_RAW REDIS_VERSION REDIS_BUILD_ID REDIS_GIT_DIRTY REDIS_GIT_SHA1" >> release.h
touch release.c # Force recompile of release.c
diff --git a/src/module.c b/src/module.c
index 7644e2c77..f0f49837b 100644
--- a/src/module.c
+++ b/src/module.c
@@ -69,14 +69,14 @@
* pointers that have an API the module can call with them)
* -------------------------------------------------------------------------- */
-typedef struct RedisModuleInfoCtx {
+struct RedisModuleInfoCtx {
struct RedisModule *module;
dict *requested_sections;
sds info; /* info string we collected so far */
int sections; /* number of sections we collected so far */
int in_section; /* indication if we're in an active section or not */
int in_dict_field; /* indication that we're currently appending to a dict */
-} RedisModuleInfoCtx;
+};
/* This represents a shared API. Shared APIs will be used to populate
* the server.sharedapi dictionary, mapping names of APIs exported by
@@ -12211,13 +12211,13 @@ const char *RM_GetCurrentCommandName(RedisModuleCtx *ctx) {
/* The defrag context, used to manage state during calls to the data type
* defrag callback.
*/
-typedef struct RedisModuleDefragCtx {
+struct RedisModuleDefragCtx {
long defragged;
long long int endtime;
unsigned long *cursor;
struct redisObject *key; /* Optional name of key processed, NULL when unknown. */
int dbid; /* The dbid of the key being processed, -1 when unknown. */
-} RedisModuleDefragCtx;
+};
/* Register a defrag callback for global data, i.e. anything that the module
* may allocate that is not tied to a specific data type.
diff --git a/src/redismodule.h b/src/redismodule.h
index 6397e704e..36e8bf51f 100644
--- a/src/redismodule.h
+++ b/src/redismodule.h
@@ -750,13 +750,41 @@ typedef enum {
REDISMODULE_ACL_LOG_CHANNEL /* Channel authorization failure */
} RedisModuleACLLogEntryReason;
+/* Incomplete structures needed by both the core and modules. */
+typedef struct RedisModuleString RedisModuleString;
+typedef struct RedisModuleIO RedisModuleIO;
+typedef struct RedisModuleDigest RedisModuleDigest;
+typedef struct RedisModuleInfoCtx RedisModuleInfoCtx;
+typedef struct RedisModuleDefragCtx RedisModuleDefragCtx;
+
+/* Function pointers needed by both the core and modules, these needs to be
+ * exposed since you can't cast a function pointer to (void *). */
+typedef void (*RedisModuleInfoFunc)(RedisModuleInfoCtx *ctx, int for_crash_report);
+typedef void (*RedisModuleDefragFunc)(RedisModuleDefragCtx *ctx);
+typedef void (*RedisModuleUserChangedFunc) (uint64_t client_id, void *privdata);
+
/* ------------------------- End of common defines ------------------------ */
-#ifndef REDISMODULE_CORE
+#if defined REDISMODULE_CORE
+/* Things only defined for the modules core (server), not exported to modules
+ * that include this file. */
+
+#define RedisModuleString robj
+
+#endif /* defined REDISMODULE_CORE */
+
+#if !defined REDISMODULE_CORE && !defined REDISMODULE_CORE_MODULE
+/* Things defined for modules, but not for core-modules. */
typedef long long mstime_t;
typedef long long ustime_t;
+#endif /* !defined REDISMODULE_CORE && !defined REDISMODULE_CORE_MODULE */
+
+/* ----------- The rest of the defines are only for modules ----------------- */
+#if !defined REDISMODULE_CORE || defined REDISMODULE_CORE_MODULE
+/* Things defined for modules and core-modules. */
+
/* Macro definitions specific to individual compilers */
#ifndef REDISMODULE_ATTR_UNUSED
# ifdef __GNUC__
@@ -786,21 +814,16 @@ typedef long long ustime_t;
typedef struct RedisModuleCtx RedisModuleCtx;
typedef struct RedisModuleCommand RedisModuleCommand;
typedef struct RedisModuleKey RedisModuleKey;
-typedef struct RedisModuleString RedisModuleString;
typedef struct RedisModuleCallReply RedisModuleCallReply;
-typedef struct RedisModuleIO RedisModuleIO;
typedef struct RedisModuleType RedisModuleType;
-typedef struct RedisModuleDigest RedisModuleDigest;
typedef struct RedisModuleBlockedClient RedisModuleBlockedClient;
typedef struct RedisModuleClusterInfo RedisModuleClusterInfo;
typedef struct RedisModuleDict RedisModuleDict;
typedef struct RedisModuleDictIter RedisModuleDictIter;
typedef struct RedisModuleCommandFilterCtx RedisModuleCommandFilterCtx;
typedef struct RedisModuleCommandFilter RedisModuleCommandFilter;
-typedef struct RedisModuleInfoCtx RedisModuleInfoCtx;
typedef struct RedisModuleServerInfoData RedisModuleServerInfoData;
typedef struct RedisModuleScanCursor RedisModuleScanCursor;
-typedef struct RedisModuleDefragCtx RedisModuleDefragCtx;
typedef struct RedisModuleUser RedisModuleUser;
typedef struct RedisModuleKeyOptCtx RedisModuleKeyOptCtx;
@@ -827,11 +850,8 @@ typedef void (*RedisModuleClusterMessageReceiver)(RedisModuleCtx *ctx, const cha
typedef void (*RedisModuleTimerProc)(RedisModuleCtx *ctx, void *data);
typedef void (*RedisModuleCommandFilterFunc) (RedisModuleCommandFilterCtx *filter);
typedef void (*RedisModuleForkDoneHandler) (int exitcode, int bysignal, void *user_data);
-typedef void (*RedisModuleInfoFunc)(RedisModuleInfoCtx *ctx, int for_crash_report);
typedef void (*RedisModuleScanCB)(RedisModuleCtx *ctx, RedisModuleString *keyname, RedisModuleKey *key, void *privdata);
typedef void (*RedisModuleScanKeyCB)(RedisModuleKey *key, RedisModuleString *field, RedisModuleString *value, void *privdata);
-typedef void (*RedisModuleUserChangedFunc) (uint64_t client_id, void *privdata);
-typedef int (*RedisModuleDefragFunc)(RedisModuleDefragCtx *ctx);
typedef RedisModuleString * (*RedisModuleConfigGetStringFunc)(const char *name, void *privdata);
typedef long long (*RedisModuleConfigGetNumericFunc)(const char *name, void *privdata);
typedef int (*RedisModuleConfigGetBoolFunc)(const char *name, void *privdata);
@@ -1559,11 +1579,5 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
#define RMAPI_FUNC_SUPPORTED(func) (func != NULL)
-#else
-
-/* Things only defined for the modules core, not exported to modules
- * including this file. */
-#define RedisModuleString robj
-
#endif /* REDISMODULE_CORE */
#endif /* REDISMODULE_H */
diff --git a/src/release.c b/src/release.c
index e0bd018fc..adc7e55dd 100644
--- a/src/release.c
+++ b/src/release.c
@@ -35,7 +35,6 @@
#include <stdio.h>
#include "release.h"
-#include "version.h"
#include "crc64.h"
char *redisGitSHA1(void) {
@@ -46,8 +45,12 @@ char *redisGitDirty(void) {
return REDIS_GIT_DIRTY;
}
+const char *redisBuildIdRaw(void) {
+ return REDIS_BUILD_ID_RAW;
+}
+
uint64_t redisBuildId(void) {
- char *buildid = REDIS_VERSION REDIS_BUILD_ID REDIS_GIT_DIRTY REDIS_GIT_SHA1;
+ char *buildid = REDIS_BUILD_ID_RAW;
return crc64(0,(unsigned char*)buildid,strlen(buildid));
}
diff --git a/src/sentinel.c b/src/sentinel.c
index 881f4b909..a75eb3236 100644
--- a/src/sentinel.c
+++ b/src/sentinel.c
@@ -30,7 +30,7 @@
#include "server.h"
#include "hiredis.h"
-#ifdef USE_OPENSSL
+#if USE_OPENSSL == 1 /* BUILD_YES */
#include "openssl/ssl.h"
#include "hiredis_ssl.h"
#endif
@@ -44,6 +44,11 @@
extern char **environ;
+#if USE_OPENSSL == 1 /* BUILD_YES */
+extern SSL_CTX *redis_tls_ctx;
+extern SSL_CTX *redis_tls_client_ctx;
+#endif
+
#define REDIS_SENTINEL_PORT 26379
/* ======================== Sentinel global state =========================== */
@@ -2373,12 +2378,7 @@ void sentinelSetClientName(sentinelRedisInstance *ri, redisAsyncContext *c, char
}
static int instanceLinkNegotiateTLS(redisAsyncContext *context) {
-#ifndef USE_OPENSSL
- (void) context;
-#else
- SSL_CTX *redis_tls_ctx = connTypeGetCtx(connectionTypeTls());
- SSL_CTX *redis_tls_client_ctx = connTypeGetClientCtx(connectionTypeTls());
-
+#if USE_OPENSSL == 1 /* BUILD_YES */
if (!redis_tls_ctx) return C_ERR;
SSL *ssl = SSL_new(redis_tls_client_ctx ? redis_tls_client_ctx : redis_tls_ctx);
if (!ssl) return C_ERR;
@@ -2387,6 +2387,8 @@ static int instanceLinkNegotiateTLS(redisAsyncContext *context) {
SSL_free(ssl);
return C_ERR;
}
+#else
+ UNUSED(context);
#endif
return C_OK;
}
diff --git a/src/server.c b/src/server.c
index f01805840..b6a72ae88 100644
--- a/src/server.c
+++ b/src/server.c
@@ -2446,12 +2446,6 @@ void initServer(void) {
exit(1);
}
- if ((server.tls_port || server.tls_replication || server.tls_cluster)
- && connTypeConfigure(connectionTypeTls(), &server.tls_ctx_config, 1) == C_ERR) {
- serverLog(LL_WARNING, "Failed to configure TLS. Check logs for more info.");
- exit(1);
- }
-
for (j = 0; j < CLIENT_MEM_USAGE_BUCKETS; j++) {
server.client_mem_usage_buckets[j].mem_usage_sum = 0;
server.client_mem_usage_buckets[j].clients = listCreate();
@@ -2470,40 +2464,6 @@ void initServer(void) {
}
server.db = zmalloc(sizeof(redisDb)*server.dbnum);
- /* Setup listeners from server config for TCP/TLS/Unix */
- int conn_index;
- connListener *listener;
- if (server.port != 0) {
- conn_index = connectionIndexByType(CONN_TYPE_SOCKET);
- if (conn_index < 0)
- serverPanic("Failed finding connection listener of %s", CONN_TYPE_SOCKET);
- listener = &server.listeners[conn_index];
- listener->bindaddr = server.bindaddr;
- listener->bindaddr_count = server.bindaddr_count;
- listener->port = server.port;
- listener->ct = connectionByType(CONN_TYPE_SOCKET);
- }
- if (server.tls_port != 0) {
- conn_index = connectionIndexByType(CONN_TYPE_TLS);
- if (conn_index < 0)
- serverPanic("Failed finding connection listener of %s", CONN_TYPE_TLS);
- listener = &server.listeners[conn_index];
- listener->bindaddr = server.bindaddr;
- listener->bindaddr_count = server.bindaddr_count;
- listener->port = server.tls_port;
- listener->ct = connectionByType(CONN_TYPE_TLS);
- }
- if (server.unixsocket != NULL) {
- conn_index = connectionIndexByType(CONN_TYPE_UNIX);
- if (conn_index < 0)
- serverPanic("Failed finding connection listener of %s", CONN_TYPE_UNIX);
- listener = &server.listeners[conn_index];
- listener->bindaddr = &server.unixsocket;
- listener->bindaddr_count = 1;
- listener->ct = connectionByType(CONN_TYPE_UNIX);
- listener->priv = &server.unixsocketperm; /* Unix socket specified */
- }
-
/* Create the Redis databases, and initialize other internal state. */
for (j = 0; j < server.dbnum; j++) {
server.db[j].dict = dictCreate(&dbDictType);
@@ -2584,29 +2544,6 @@ void initServer(void) {
exit(1);
}
- /* create all the configured listener, and add handler to start to accept */
- int listen_fds = 0;
- for (j = 0; j < CONN_TYPE_MAX; j++) {
- listener = &server.listeners[j];
- if (listener->ct == NULL)
- continue;
-
- if (connListen(listener) == C_ERR) {
- serverLog(LL_WARNING, "Failed listening on port %u (%s), aborting.", listener->port, listener->ct->get_type(NULL));
- exit(1);
- }
-
- if (createSocketAcceptHandler(listener, connAcceptHandler(listener->ct)) != C_OK)
- serverPanic("Unrecoverable error creating %s listener accept handler.", listener->ct->get_type(NULL));
-
- listen_fds += listener->count;
- }
-
- if (listen_fds == 0) {
- serverLog(LL_WARNING, "Configured to not listen anywhere, exiting.");
- exit(1);
- }
-
/* Register a readable event for the pipe used to awake the event loop
* from module threads. */
if (aeCreateFileEvent(server.el, server.module_pipe[0], AE_READABLE,
@@ -2630,7 +2567,6 @@ void initServer(void) {
server.maxmemory_policy = MAXMEMORY_NO_EVICTION;
}
- if (server.cluster_enabled) clusterInit();
scriptingInit(1);
functionsInit();
slowlogInit();
@@ -2642,6 +2578,78 @@ void initServer(void) {
applyWatchdogPeriod();
}
+void initListeners() {
+ /* Setup listeners from server config for TCP/TLS/Unix */
+ int conn_index;
+ connListener *listener;
+ if (server.port != 0) {
+ conn_index = connectionIndexByType(CONN_TYPE_SOCKET);
+ if (conn_index < 0)
+ serverPanic("Failed finding connection listener of %s", CONN_TYPE_SOCKET);
+ listener = &server.listeners[conn_index];
+ listener->bindaddr = server.bindaddr;
+ listener->bindaddr_count = server.bindaddr_count;
+ listener->port = server.port;
+ listener->ct = connectionByType(CONN_TYPE_SOCKET);
+ }
+
+ if (server.tls_port || server.tls_replication || server.tls_cluster) {
+ ConnectionType *ct_tls = connectionTypeTls();
+ if (!ct_tls) {
+ serverLog(LL_WARNING, "Failed finding TLS support.");
+ exit(1);
+ }
+ if (connTypeConfigure(ct_tls, &server.tls_ctx_config, 1) == C_ERR) {
+ serverLog(LL_WARNING, "Failed to configure TLS. Check logs for more info.");
+ exit(1);
+ }
+ }
+
+ if (server.tls_port != 0) {
+ conn_index = connectionIndexByType(CONN_TYPE_TLS);
+ if (conn_index < 0)
+ serverPanic("Failed finding connection listener of %s", CONN_TYPE_TLS);
+ listener = &server.listeners[conn_index];
+ listener->bindaddr = server.bindaddr;
+ listener->bindaddr_count = server.bindaddr_count;
+ listener->port = server.tls_port;
+ listener->ct = connectionByType(CONN_TYPE_TLS);
+ }
+ if (server.unixsocket != NULL) {
+ conn_index = connectionIndexByType(CONN_TYPE_UNIX);
+ if (conn_index < 0)
+ serverPanic("Failed finding connection listener of %s", CONN_TYPE_UNIX);
+ listener = &server.listeners[conn_index];
+ listener->bindaddr = &server.unixsocket;
+ listener->bindaddr_count = 1;
+ listener->ct = connectionByType(CONN_TYPE_UNIX);
+ listener->priv = &server.unixsocketperm; /* Unix socket specified */
+ }
+
+ /* create all the configured listener, and add handler to start to accept */
+ int listen_fds = 0;
+ for (int j = 0; j < CONN_TYPE_MAX; j++) {
+ listener = &server.listeners[j];
+ if (listener->ct == NULL)
+ continue;
+
+ if (connListen(listener) == C_ERR) {
+ serverLog(LL_WARNING, "Failed listening on port %u (%s), aborting.", listener->port, listener->ct->get_type(NULL));
+ exit(1);
+ }
+
+ if (createSocketAcceptHandler(listener, connAcceptHandler(listener->ct)) != C_OK)
+ serverPanic("Unrecoverable error creating %s listener accept handler.", listener->ct->get_type(NULL));
+
+ listen_fds += listener->count;
+ }
+
+ if (listen_fds == 0) {
+ serverLog(LL_WARNING, "Configured to not listen anywhere, exiting.");
+ exit(1);
+ }
+}
+
/* Some steps in server initialization need to be done last (after modules
* are loaded).
* Specifically, creation of threads due to a race bug in ld.so, in which
@@ -7086,6 +7094,16 @@ int main(int argc, char **argv) {
if (server.set_proc_title) redisSetProcTitle(NULL);
redisAsciiArt();
checkTcpBacklogSettings();
+ if (!server.sentinel_mode) {
+ moduleInitModulesSystemLast();
+ moduleLoadFromQueue();
+ }
+ ACLLoadUsersAtStartup();
+ initListeners();
+ if (server.cluster_enabled) {
+ clusterInit();
+ }
+ InitServerLast();
if (!server.sentinel_mode) {
/* Things not needed when running in Sentinel mode. */
@@ -7114,10 +7132,6 @@ int main(int argc, char **argv) {
}
#endif /* __arm64__ */
#endif /* __linux__ */
- moduleInitModulesSystemLast();
- moduleLoadFromQueue();
- ACLLoadUsersAtStartup();
- InitServerLast();
aofLoadManifestFromDisk();
loadDataFromDisk();
aofOpenIfNeededOnServerStart();
@@ -7148,8 +7162,6 @@ int main(int argc, char **argv) {
redisCommunicateSystemd("READY=1\n");
}
} else {
- ACLLoadUsersAtStartup();
- InitServerLast();
sentinelIsRunning();
if (server.supervised_mode == SUPERVISED_SYSTEMD) {
redisCommunicateSystemd("STATUS=Ready to accept connections\n");
diff --git a/src/server.h b/src/server.h
index 65faa84af..8a0a2f5f6 100644
--- a/src/server.h
+++ b/src/server.h
@@ -81,6 +81,7 @@ typedef long long ustime_t; /* microsecond time type. */
#include "connection.h" /* Connection abstraction */
#define REDISMODULE_CORE 1
+typedef struct redisObject robj;
#include "redismodule.h" /* Redis modules API defines. */
/* Following includes allow test functions to be called from Redis main() */
@@ -679,9 +680,6 @@ struct RedisModuleIO;
struct RedisModuleDigest;
struct RedisModuleCtx;
struct moduleLoadQueueEntry;
-struct redisObject;
-struct RedisModuleDefragCtx;
-struct RedisModuleInfoCtx;
struct RedisModuleKeyOptCtx;
struct RedisModuleCommand;
@@ -701,20 +699,12 @@ typedef size_t (*moduleTypeFreeEffortFunc)(struct redisObject *key, const void *
typedef void (*moduleTypeUnlinkFunc)(struct redisObject *key, void *value);
typedef void *(*moduleTypeCopyFunc)(struct redisObject *fromkey, struct redisObject *tokey, const void *value);
typedef int (*moduleTypeDefragFunc)(struct RedisModuleDefragCtx *ctx, struct redisObject *key, void **value);
-typedef void (*RedisModuleInfoFunc)(struct RedisModuleInfoCtx *ctx, int for_crash_report);
-typedef void (*RedisModuleDefragFunc)(struct RedisModuleDefragCtx *ctx);
typedef size_t (*moduleTypeMemUsageFunc2)(struct RedisModuleKeyOptCtx *ctx, const void *value, size_t sample_size);
typedef void (*moduleTypeFreeFunc2)(struct RedisModuleKeyOptCtx *ctx, void *value);
typedef size_t (*moduleTypeFreeEffortFunc2)(struct RedisModuleKeyOptCtx *ctx, const void *value);
typedef void (*moduleTypeUnlinkFunc2)(struct RedisModuleKeyOptCtx *ctx, void *value);
typedef void *(*moduleTypeCopyFunc2)(struct RedisModuleKeyOptCtx *ctx, const void *value);
-/* This callback type is called by moduleNotifyUserChanged() every time
- * a user authenticated via the module API is associated with a different
- * user or gets disconnected. This needs to be exposed since you can't cast
- * a function pointer to (void *). */
-typedef void (*RedisModuleUserChangedFunc) (uint64_t client_id, void *privdata);
-
/* The module type, which is referenced in each value of a given type, defines
* the methods and links to the module exporting the type. */
@@ -786,7 +776,7 @@ typedef struct RedisModule RedisModule;
/* This is a wrapper for the 'rio' streams used inside rdb.c in Redis, so that
* the user does not have to take the total count of the written bytes nor
* to care about error conditions. */
-typedef struct RedisModuleIO {
+struct RedisModuleIO {
size_t bytes; /* Bytes read / written so far. */
rio *rio; /* Rio stream. */
moduleType *type; /* Module type doing the operation. */
@@ -794,7 +784,7 @@ typedef struct RedisModuleIO {
struct RedisModuleCtx *ctx; /* Optional context, see RM_GetContextFromIO()*/
struct redisObject *key; /* Optional name of key processed */
int dbid; /* The dbid of the key being processed, -1 when unknown. */
-} RedisModuleIO;
+};
/* Macro to initialize an IO context. Note that the 'ver' field is populated
* inside rdb.c according to the version of the value to load. */
@@ -813,12 +803,12 @@ typedef struct RedisModuleIO {
* a data structure, so that a digest can be created in a way that correctly
* reflects the values. See the DEBUG DIGEST command implementation for more
* background. */
-typedef struct RedisModuleDigest {
+struct RedisModuleDigest {
unsigned char o[20]; /* Ordered elements. */
unsigned char x[20]; /* Xored elements. */
struct redisObject *key; /* Optional name of key processed */
int dbid; /* The dbid of the key being processed */
-} RedisModuleDigest;
+};
/* Just start with a digest composed of all zero bytes. */
#define moduleInitDigestContext(mdvar) do { \
@@ -849,7 +839,7 @@ typedef struct RedisModuleDigest {
#define OBJ_SHARED_REFCOUNT INT_MAX /* Global object never destroyed. */
#define OBJ_STATIC_REFCOUNT (INT_MAX-1) /* Object allocated in the stack. */
#define OBJ_FIRST_SPECIAL_REFCOUNT OBJ_STATIC_REFCOUNT
-typedef struct redisObject {
+struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
@@ -857,7 +847,7 @@ typedef struct redisObject {
* and most significant 16 bits access time). */
int refcount;
void *ptr;
-} robj;
+};
/* The a string name for an object's type as listed above
* Native types are checked against the OBJ_STRING, OBJ_LIST, OBJ_* defines,
@@ -3269,6 +3259,7 @@ void *dictSdsDup(dict *d, const void *key);
char *redisGitSHA1(void);
char *redisGitDirty(void);
uint64_t redisBuildId(void);
+const char *redisBuildIdRaw(void);
char *redisBuildIdString(void);
/* Commands prototypes */
diff --git a/src/tls.c b/src/tls.c
index be6bf4e1b..99cbea5a2 100644
--- a/src/tls.c
+++ b/src/tls.c
@@ -27,12 +27,13 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#define REDISMODULE_CORE_MODULE /* A module that's part of the redis core, uses server.h too. */
#include "server.h"
#include "connhelpers.h"
#include "adlist.h"
-#ifdef USE_OPENSSL
+#if (USE_OPENSSL == 1 /* BUILD_YES */ ) || ((USE_OPENSSL == 2 /* BUILD_MODULE */) && (BUILD_TLS_MODULE == 2))
#include <openssl/conf.h>
#include <openssl/ssl.h>
@@ -56,8 +57,8 @@
#define REDIS_TLS_PROTO_DEFAULT (REDIS_TLS_PROTO_TLSv1_2)
#endif
-static SSL_CTX *redis_tls_ctx = NULL;
-static SSL_CTX *redis_tls_client_ctx = NULL;
+SSL_CTX *redis_tls_ctx = NULL;
+SSL_CTX *redis_tls_client_ctx = NULL;
static int parseProtocolsConfig(const char *str) {
int i, count = 0;
@@ -1087,14 +1088,6 @@ static sds connTLSGetPeerCert(connection *conn_) {
return cert_pem;
}
-static void *tlsGetCtx(void) {
- return redis_tls_ctx;
-}
-
-static void *tlsGetClientCtx(void) {
- return redis_tls_client_ctx;
-}
-
static ConnectionType CT_TLS = {
/* connection type */
.get_type = connTLSGetType,
@@ -1137,20 +1130,55 @@ static ConnectionType CT_TLS = {
/* TLS specified methods */
.get_peer_cert = connTLSGetPeerCert,
- .get_ctx = tlsGetCtx,
- .get_client_ctx = tlsGetClientCtx
};
-int RedisRegisterConnectionTypeTLS()
-{
+int RedisRegisterConnectionTypeTLS() {
return connTypeRegister(&CT_TLS);
}
#else /* USE_OPENSSL */
-int RedisRegisterConnectionTypeTLS()
-{
+int RedisRegisterConnectionTypeTLS() {
+ serverLog(LL_VERBOSE, "Connection type %s not builtin", CONN_TYPE_TLS);
return C_ERR;
}
#endif
+
+#if BUILD_TLS_MODULE == 2 /* BUILD_MODULE */
+
+#include "release.h"
+
+int RedisModule_OnLoad(void *ctx, RedisModuleString **argv, int argc) {
+ UNUSED(argv);
+ UNUSED(argc);
+
+ /* Connection modules must be part of the same build as redis. */
+ if (strcmp(REDIS_BUILD_ID_RAW, redisBuildIdRaw())) {
+ serverLog(LL_NOTICE, "Connection type %s was not built together with the redis-server used.", CONN_TYPE_TLS);
+ return REDISMODULE_ERR;
+ }
+
+ if (RedisModule_Init(ctx,"tls",1,REDISMODULE_APIVER_1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ /* Connection modules is available only bootup. */
+ if ((RedisModule_GetContextFlags(ctx) & REDISMODULE_CTX_FLAGS_SERVER_STARTUP) == 0) {
+ serverLog(LL_NOTICE, "Connection type %s can be loaded only during bootup", CONN_TYPE_TLS);
+ return REDISMODULE_ERR;
+ }
+
+ RedisModule_SetModuleOptions(ctx, REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD);
+
+ if(connTypeRegister(&CT_TLS) != C_OK)
+ return REDISMODULE_ERR;
+
+ return REDISMODULE_OK;
+}
+
+int RedisModule_OnUnload(void *arg) {
+ UNUSED(arg);
+ serverLog(LL_NOTICE, "Connection type %s can not be unloaded", CONN_TYPE_TLS);
+ return REDISMODULE_ERR;
+}
+#endif
diff --git a/tests/instances.tcl b/tests/instances.tcl
index 8faf6fb31..9cbb11a92 100644
--- a/tests/instances.tcl
+++ b/tests/instances.tcl
@@ -19,6 +19,7 @@ source ../support/test.tcl
set ::verbose 0
set ::valgrind 0
set ::tls 0
+set ::tls_module 0
set ::pause_on_error 0
set ::dont_clean 0
set ::simulate_error 0
@@ -85,6 +86,10 @@ proc spawn_instance {type base_port count {conf {}} {base_conf_file ""}} {
}
if {$::tls} {
+ if {$::tls_module} {
+ puts $cfg [format "loadmodule %s/../../../src/redis-tls.so" [pwd]]
+ }
+
puts $cfg "tls-port $port"
puts $cfg "tls-replication yes"
puts $cfg "tls-cluster yes"
@@ -271,13 +276,16 @@ proc parse_options {} {
} elseif {$opt eq {--host}} {
incr j
set ::host ${val}
- } elseif {$opt eq {--tls}} {
+ } elseif {$opt eq {--tls} || $opt eq {--tls-module}} {
package require tls 1.6
::tls::init \
-cafile "$::tlsdir/ca.crt" \
-certfile "$::tlsdir/client.crt" \
-keyfile "$::tlsdir/client.key"
set ::tls 1
+ if {$opt eq {--tls-module}} {
+ set ::tls_module 1
+ }
} elseif {$opt eq {--config}} {
set val2 [lindex $::argv [expr $j+2]]
dict set ::global_config $val $val2
@@ -293,6 +301,7 @@ proc parse_options {} {
puts "--fail Simulate a test failure."
puts "--valgrind Run with valgrind."
puts "--tls Run tests in TLS mode."
+ puts "--tls-module Run tests in TLS mode with Redis module."
puts "--host <host> Use hostname instead of 127.0.0.1."
puts "--config <k> <v> Extra config argument(s)."
puts "--stop Blocks once the first test fails."
diff --git a/tests/modules/defragtest.c b/tests/modules/defragtest.c
index 221280df1..6a02a059f 100644
--- a/tests/modules/defragtest.c
+++ b/tests/modules/defragtest.c
@@ -35,7 +35,7 @@ static void createGlobalStrings(RedisModuleCtx *ctx, int count)
}
}
-static int defragGlobalStrings(RedisModuleDefragCtx *ctx)
+static void defragGlobalStrings(RedisModuleDefragCtx *ctx)
{
for (int i = 0; i < global_strings_len; i++) {
RedisModuleString *new = RedisModule_DefragRedisModuleString(ctx, global_strings[i]);
@@ -45,8 +45,6 @@ static int defragGlobalStrings(RedisModuleDefragCtx *ctx)
global_defragged++;
}
}
-
- return 0;
}
static void FragInfo(RedisModuleInfoCtx *ctx, int for_crash_report) {
diff --git a/tests/support/server.tcl b/tests/support/server.tcl
index b673b70ae..6cc846b97 100644
--- a/tests/support/server.tcl
+++ b/tests/support/server.tcl
@@ -300,7 +300,7 @@ proc wait_server_started {config_file stdout pid} {
set maxiter [expr {120*1000/$checkperiod}] ; # Wait up to 2 minutes.
set port_busy 0
while 1 {
- if {[regexp -- " PID: $pid" [exec cat $stdout]]} {
+ if {[regexp -- " PID: $pid.*Server initialized" [exec cat $stdout]]} {
break
}
after $checkperiod
@@ -464,6 +464,9 @@ proc start_server {options {code undefined}} {
set data [split [exec cat "tests/assets/$baseconfig"] "\n"]
set config {}
if {$::tls} {
+ if {$::tls_module} {
+ lappend config_lines [list "loadmodule" [format "%s/src/redis-tls.so" [pwd]]]
+ }
dict set config "tls-cert-file" [format "%s/tests/tls/server.crt" [pwd]]
dict set config "tls-key-file" [format "%s/tests/tls/server.key" [pwd]]
dict set config "tls-client-cert-file" [format "%s/tests/tls/client.crt" [pwd]]
diff --git a/tests/support/util.tcl b/tests/support/util.tcl
index 8153ad8bb..c7aef0f50 100644
--- a/tests/support/util.tcl
+++ b/tests/support/util.tcl
@@ -1039,3 +1039,25 @@ proc memory_usage {key} {
}
return $usage
}
+
+# forward compatibility, lmap missing in TCL 8.5
+proc lmap args {
+ set body [lindex $args end]
+ set args [lrange $args 0 end-1]
+ set n 0
+ set pairs [list]
+ foreach {varnames listval} $args {
+ set varlist [list]
+ foreach varname $varnames {
+ upvar 1 $varname var$n
+ lappend varlist var$n
+ incr n
+ }
+ lappend pairs $varlist $listval
+ }
+ set temp [list]
+ foreach {*}$pairs {
+ lappend temp [uplevel 1 $body]
+ }
+ set temp
+}
diff --git a/tests/test_helper.tcl b/tests/test_helper.tcl
index 5c951dda6..efa7a0a16 100644
--- a/tests/test_helper.tcl
+++ b/tests/test_helper.tcl
@@ -111,6 +111,7 @@ set ::traceleaks 0
set ::valgrind 0
set ::durable 0
set ::tls 0
+set ::tls_module 0
set ::stack_logging 0
set ::verbose 0
set ::quiet 0
@@ -611,6 +612,7 @@ proc print_help_screen {} {
"--wait-server Wait after server is started (so that you can attach a debugger)."
"--dump-logs Dump server log on test failure."
"--tls Run tests in TLS mode."
+ "--tls-module Run tests in TLS mode with Redis module."
"--host <addr> Run tests against an external host."
"--port <port> TCP port to use against external host."
"--baseport <port> Initial port number for spawned redis servers."
@@ -659,13 +661,16 @@ for {set j 0} {$j < [llength $argv]} {incr j} {
}
} elseif {$opt eq {--quiet}} {
set ::quiet 1
- } elseif {$opt eq {--tls}} {
+ } elseif {$opt eq {--tls} || $opt eq {--tls-module}} {
package require tls 1.6
set ::tls 1
::tls::init \
-cafile "$::tlsdir/ca.crt" \
-certfile "$::tlsdir/client.crt" \
-keyfile "$::tlsdir/client.key"
+ if {$opt eq {--tls-module}} {
+ set ::tls_module 1
+ }
} elseif {$opt eq {--host}} {
set ::external 1
set ::host $arg
diff --git a/tests/unit/moduleapi/infra.tcl b/tests/unit/moduleapi/infra.tcl
index 7bfa7d4b3..1140e5ad5 100644
--- a/tests/unit/moduleapi/infra.tcl
+++ b/tests/unit/moduleapi/infra.tcl
@@ -5,18 +5,21 @@ test {modules config rewrite} {
start_server {tags {"modules"}} {
r module load $testmodule
- assert_equal [lindex [lindex [r module list] 0] 1] infotest
+ set modules [lmap x [r module list] {dict get $x name}]
+ assert_not_equal [lsearch $modules infotest] -1
r config rewrite
restart_server 0 true false
- assert_equal [lindex [lindex [r module list] 0] 1] infotest
+ set modules [lmap x [r module list] {dict get $x name}]
+ assert_not_equal [lsearch $modules infotest] -1
assert_equal {OK} [r module unload infotest]
r config rewrite
restart_server 0 true false
- assert_equal [llength [r module list]] 0
+ set modules [lmap x [r module list] {dict get $x name}]
+ assert_equal [lsearch $modules infotest] -1
}
}
diff --git a/tests/unit/moduleapi/moduleconfigs.tcl b/tests/unit/moduleapi/moduleconfigs.tcl
index 8ebce3514..2b28fc307 100644
--- a/tests/unit/moduleapi/moduleconfigs.tcl
+++ b/tests/unit/moduleapi/moduleconfigs.tcl
@@ -5,7 +5,7 @@ start_server {tags {"modules"}} {
r module load $testmodule
test {Config get commands work} {
# Make sure config get module config works
- assert_equal [lindex [lindex [r module list] 0] 1] moduleconfigs
+ assert_not_equal [lsearch [lmap x [r module list] {dict get $x name}] moduleconfigs] -1
assert_equal [r config get moduleconfigs.mutable_bool] "moduleconfigs.mutable_bool yes"
assert_equal [r config get moduleconfigs.immutable_bool] "moduleconfigs.immutable_bool no"
assert_equal [r config get moduleconfigs.memory_numeric] "moduleconfigs.memory_numeric 1024"
@@ -94,7 +94,7 @@ start_server {tags {"modules"}} {
test {test loadex functionality} {
r module loadex $testmodule CONFIG moduleconfigs.mutable_bool no CONFIG moduleconfigs.immutable_bool yes CONFIG moduleconfigs.memory_numeric 2mb CONFIG moduleconfigs.string tclortickle
- assert_equal [lindex [lindex [r module list] 0] 1] moduleconfigs
+ assert_not_equal [lsearch [lmap x [r module list] {dict get $x name}] moduleconfigs] -1
assert_equal [r config get moduleconfigs.mutable_bool] "moduleconfigs.mutable_bool no"
assert_equal [r config get moduleconfigs.immutable_bool] "moduleconfigs.immutable_bool yes"
assert_equal [r config get moduleconfigs.memory_numeric] "moduleconfigs.memory_numeric 2097152"
@@ -157,7 +157,7 @@ start_server {tags {"modules"}} {
test {test config rewrite with dynamic load} {
#translates to: super \0secret password
r module loadex $testmodule CONFIG moduleconfigs.string \x73\x75\x70\x65\x72\x20\x00\x73\x65\x63\x72\x65\x74\x20\x70\x61\x73\x73\x77\x6f\x72\x64 ARGS
- assert_equal [lindex [lindex [r module list] 0] 1] moduleconfigs
+ assert_not_equal [lsearch [lmap x [r module list] {dict get $x name}] moduleconfigs] -1
assert_equal [r config get moduleconfigs.string] "moduleconfigs.string {super \0secret password}"
r config set moduleconfigs.mutable_bool yes
r config set moduleconfigs.memory_numeric 750
@@ -207,7 +207,7 @@ start_server {tags {"modules"}} {
test {test 1.module load 2.config rewrite 3.module unload 4.config rewrite works} {
# Configs need to be removed from the old config file in this case.
r module loadex $testmodule CONFIG moduleconfigs.memory_numeric 500 ARGS
- assert_equal [lindex [lindex [r module list] 0] 1] moduleconfigs
+ assert_not_equal [lsearch [lmap x [r module list] {dict get $x name}] moduleconfigs] -1
r config rewrite
r module unload moduleconfigs
r config rewrite
@@ -217,34 +217,18 @@ start_server {tags {"modules"}} {
}
test {startup moduleconfigs} {
# No loadmodule directive
- set nomodload [start_server [list overrides [list moduleconfigs.string "hello"]]]
- wait_for_condition 100 50 {
- ! [is_alive $nomodload]
- } else {
- fail "startup should've failed with no load and module configs supplied"
- }
- set stdout [dict get $nomodload stdout]
- assert_equal [count_message_lines $stdout "Module Configuration detected without loadmodule directive or no ApplyConfig call: aborting"] 1
+ catch {exec src/redis-server --moduleconfigs.string "hello"} err
+ assert_match {*Module Configuration detected without loadmodule directive or no ApplyConfig call: aborting*} $err
# Bad config value
- set badconfig [start_server [list overrides [list loadmodule "$testmodule" moduleconfigs.string "rejectisfreed"]]]
- wait_for_condition 100 50 {
- ! [is_alive $badconfig]
- } else {
- fail "startup with bad moduleconfigs should've failed"
- }
- set stdout [dict get $badconfig stdout]
- assert_equal [count_message_lines $stdout "Issue during loading of configuration moduleconfigs.string : Cannot set string to 'rejectisfreed'"] 1
+ catch {exec src/redis-server --loadmodule "$testmodule" --moduleconfigs.string "rejectisfreed"} err
+ assert_match {*Issue during loading of configuration moduleconfigs.string : Cannot set string to 'rejectisfreed'*} $err
- set noload [start_server [list overrides [list loadmodule "$testmodule noload" moduleconfigs.string "hello"]]]
- wait_for_condition 100 50 {
- ! [is_alive $noload]
- } else {
- fail "startup with moduleconfigs and no loadconfigs call should've failed"
- }
- set stdout [dict get $noload stdout]
- assert_equal [count_message_lines $stdout "Module Configurations were not set, likely a missing LoadConfigs call. Unloading the module."] 1
+ # missing LoadConfigs call
+ catch {exec src/redis-server --loadmodule "$testmodule" noload --moduleconfigs.string "hello"} err
+ assert_match {*Module Configurations were not set, likely a missing LoadConfigs call. Unloading the module.*} $err
+ # successful
start_server [list overrides [list loadmodule "$testmodule" moduleconfigs.string "bootedup" moduleconfigs.enum two moduleconfigs.flags "two four"]] {
assert_equal [r config get moduleconfigs.string] "moduleconfigs.string bootedup"
assert_equal [r config get moduleconfigs.mutable_bool] "moduleconfigs.mutable_bool yes"