Import upstream version 0.10
Debian Janitor
2 years ago
0 | sudo: required | |
1 | dist: trusty | |
2 | ||
3 | os: linux | |
4 | ||
5 | language: c | |
6 | ||
7 | compiler: gcc | |
8 | ||
9 | addons: | |
10 | apt: | |
11 | packages: | |
12 | - luarocks | |
13 | - redis | |
14 | - lsof | |
15 | ||
16 | cache: | |
17 | directories: | |
18 | - download-cache | |
19 | ||
20 | env: | |
21 | global: | |
22 | - JOBS=3 | |
23 | - NGX_BUILD_JOBS=$JOBS | |
24 | - LUAJIT_PREFIX=/opt/luajit21 | |
25 | - LUAJIT_LIB=$LUAJIT_PREFIX/lib | |
26 | - LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1 | |
27 | - LUA_INCLUDE_DIR=$LUAJIT_INC | |
28 | - OPENSSL_PREFIX=/opt/ssl | |
29 | - OPENSSL_LIB=$OPENSSL_PREFIX/lib | |
30 | - OPENSSL_INC=$OPENSSL_PREFIX/include | |
31 | - OPENSSL_VER=1.1.1f | |
32 | - LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH | |
33 | - TEST_NGINX_SLEEP=0.006 | |
34 | - LUACHECK_VER=0.21.1 | |
35 | jobs: | |
36 | - NGINX_VERSION=1.17.8 | |
37 | ||
38 | before_install: | |
39 | - sudo luarocks install luacov | |
40 | - sudo luarocks install lua-resty-redis | |
41 | - sudo luarocks install luacheck $LUACHECK_VER | |
42 | - luacheck -q . | |
43 | ||
44 | install: | |
45 | - if [ ! -d download-cache ]; then mkdir download-cache; fi | |
46 | - if [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -O download-cache/openssl-$OPENSSL_VER.tar.gz https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz; fi | |
47 | - sudo apt-get install -qq -y cpanminus axel | |
48 | - sudo cpanm --notest Test::Nginx > build.log 2>&1 || (cat build.log && exit 1) | |
49 | - git clone https://github.com/openresty/openresty.git ../openresty | |
50 | - git clone https://github.com/openresty/nginx-devel-utils.git | |
51 | - git clone https://github.com/openresty/lua-cjson.git | |
52 | - git clone https://github.com/openresty/lua-nginx-module.git ../lua-nginx-module | |
53 | - git clone https://github.com/openresty/stream-lua-nginx-module.git ../stream-lua-nginx-module | |
54 | - git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core | |
55 | - git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache | |
56 | - git clone https://github.com/openresty/echo-nginx-module.git ../echo-nginx-module | |
57 | - git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx | |
58 | - git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git | |
59 | ||
60 | script: | |
61 | - sudo iptables -A OUTPUT -p tcp --dst 127.0.0.2 --dport 12345 -j DROP | |
62 | - cd luajit2/ | |
63 | - make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT' > build.log 2>&1 || (cat build.log && exit 1) | |
64 | - sudo make install PREFIX=$LUAJIT_PREFIX > build.log 2>&1 || (cat build.log && exit 1) | |
65 | - cd ../lua-cjson && make && sudo PATH=$PATH make install && cd .. | |
66 | - tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz | |
67 | - cd openssl-$OPENSSL_VER/ | |
68 | - ./config shared --prefix=$OPENSSL_PREFIX -DPURIFY > build.log 2>&1 || (cat build.log && exit 1) | |
69 | - make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1) | |
70 | - sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1) | |
71 | - cd .. | |
72 | - export PATH=$PWD/work/nginx/sbin:$PWD/nginx-devel-utils:$PATH | |
73 | - export NGX_BUILD_CC=$CC | |
74 | - ngx-build $NGINX_VERSION --with-ipv6 --with-http_realip_module --with-http_ssl_module --with-cc-opt="-I$OPENSSL_INC" --with-ld-opt="-L$OPENSSL_LIB -Wl,-rpath,$OPENSSL_LIB" --add-module=../echo-nginx-module --add-module=../lua-nginx-module --add-module=../stream-lua-nginx-module --with-stream --with-stream_ssl_module --with-debug > build.log 2>&1 || (cat build.log && exit 1) | |
75 | - nginx -V | |
76 | - ldd `which nginx`|grep -E 'luajit|ssl|pcre' | |
77 | - mkdir -p tmp | |
78 | - TMP_DIR=$PWD/tmp make test_all |
2 | 2 | OPENRESTY_PREFIX = /usr/local/openresty |
3 | 3 | |
4 | 4 | TEST_FILE ?= t |
5 | TMP_DIR ?= /tmp | |
5 | 6 | SENTINEL_TEST_FILE ?= $(TEST_FILE)/sentinel |
6 | 7 | |
7 | 8 | REDIS_CMD = redis-server |
10 | 11 | REDIS_SOCK = /redis.sock |
11 | 12 | REDIS_PID = /redis.pid |
12 | 13 | REDIS_LOG = /redis.log |
13 | REDIS_PREFIX = /tmp/redis- | |
14 | REDIS_PREFIX = $(TMP_DIR)/redis- | |
14 | 15 | |
15 | 16 | # Overrideable redis test variables |
16 | TEST_REDIS_PORTS ?= 6379 6380 6378 | |
17 | TEST_REDIS_DATABASE ?= 1 | |
17 | TEST_REDIS_PORT ?= 6380 | |
18 | TEST_REDIS_PORT_SL1 ?= 6381 | |
19 | TEST_REDIS_PORT_SL2 ?= 6382 | |
20 | TEST_REDIS_PORTS ?= $(TEST_REDIS_PORT) $(TEST_REDIS_PORT_SL1) $(TEST_REDIS_PORT_SL2) | |
21 | TEST_REDIS_DATABASE ?= 1 | |
22 | TEST_REDIS_SOCKET ?= $(REDIS_PREFIX)$(TEST_REDIS_PORT)$(REDIS_SOCK) | |
18 | 23 | |
19 | REDIS_FIRST_PORT := $(firstword $(TEST_REDIS_PORTS)) | |
20 | REDIS_SLAVE_ARG := --slaveof 127.0.0.1 $(REDIS_FIRST_PORT) | |
21 | REDIS_CLI := redis-cli -p $(REDIS_FIRST_PORT) -n $(TEST_REDIS_DATABASE) | |
22 | ||
23 | # Override socket for running make test on its own | |
24 | # (make test TEST_REDIS_SOCKET=/path/to/sock.sock) | |
25 | TEST_REDIS_SOCKET ?= $(REDIS_PREFIX)$(REDIS_FIRST_PORT)$(REDIS_SOCK) | |
24 | REDIS_SLAVE_ARG := --slaveof 127.0.0.1 $(TEST_REDIS_PORT) | |
25 | REDIS_CLI := redis-cli -p $(TEST_REDIS_PORT) -n $(TEST_REDIS_DATABASE) | |
26 | 26 | |
27 | 27 | # Overrideable redis + sentinel test variables |
28 | TEST_SENTINEL_PORTS ?= 6381 6382 6383 | |
28 | TEST_SENTINEL_PORT1 ?= 6390 | |
29 | TEST_SENTINEL_PORT2 ?= 6391 | |
30 | TEST_SENTINEL_PORT3 ?= 6392 | |
31 | TEST_SENTINEL_PORTS ?= $(TEST_SENTINEL_PORT1) $(TEST_SENTINEL_PORT2) $(TEST_SENTINEL_PORT3) | |
29 | 32 | TEST_SENTINEL_MASTER_NAME ?= mymaster |
30 | 33 | TEST_SENTINEL_PROMOTION_TIME ?= 20 |
31 | 34 | |
32 | 35 | # Command line arguments for redis tests |
33 | 36 | TEST_REDIS_VARS = PATH=$(OPENRESTY_PREFIX)/nginx/sbin:$(PATH) \ |
34 | TEST_REDIS_SOCKET=unix://$(TEST_REDIS_SOCKET) \ | |
35 | TEST_REDIS_DATABASE=$(TEST_REDIS_DATABASE) \ | |
37 | TEST_NGINX_REDIS_PORT=$(TEST_REDIS_PORT) \ | |
38 | TEST_NGINX_REDIS_PORT_SL1=$(TEST_REDIS_PORT_SL1) \ | |
39 | TEST_NGINX_REDIS_PORT_SL2=$(TEST_REDIS_PORT_SL2) \ | |
40 | TEST_NGINX_REDIS_SOCKET=unix:$(TEST_REDIS_SOCKET) \ | |
41 | TEST_NGINX_REDIS_DATABASE=$(TEST_REDIS_DATABASE) \ | |
36 | 42 | TEST_NGINX_NO_SHUFFLE=1 |
37 | 43 | |
38 | 44 | # Command line arguments for sentinel tests |
39 | 45 | TEST_SENTINEL_VARS = PATH=$(OPENRESTY_PREFIX)/nginx/sbin:$(PATH) \ |
40 | TEST_SENTINEL_PORT=$(firstword $(TEST_SENTINEL_PORTS)) \ | |
41 | TEST_SENTINEL_MASTER_NAME=$(TEST_SENTINEL_MASTER_NAME) \ | |
42 | TEST_REDIS_DATABASE=$(TEST_REDIS_DATABASE) \ | |
46 | TEST_NGINX_REDIS_PORT=$(TEST_NGINX_REDIS_PORT) \ | |
47 | TEST_NGINX_REDIS_PORT_SL1=$(TEST_NGINX_REDIS_PORT_SL1) \ | |
48 | TEST_NGINX_REDIS_PORT_SL2=$(TEST_NGINX_REDIS_PORT_SL2) \ | |
49 | TEST_NGINX_SENTINEL_PORT1=$(TEST_NGINX_SENTINEL_PORT1) \ | |
50 | TEST_NGINX_SENTINEL_PORT2=$(TEST_NGINX_SENTINEL_PORT2) \ | |
51 | TEST_NGINX_SENTINEL_PORT3=$(TEST_NGINX_SENTINEL_PORT3) \ | |
52 | TEST_NGINX_SENTINEL_MASTER_NAME=$(TEST_NGINX_SENTINEL_MASTER_NAME) \ | |
53 | TEST_NGINX_REDIS_DATABASE=$(TEST_NGINX_REDIS_DATABASE) \ | |
43 | 54 | TEST_NGINX_NO_SHUFFLE=1 |
44 | 55 | |
45 | 56 | # Sentinel configuration can only be set by a config file |
46 | 57 | define TEST_SENTINEL_CONFIG |
47 | sentinel monitor $(TEST_SENTINEL_MASTER_NAME) 127.0.0.1 $(REDIS_FIRST_PORT) 2 | |
58 | sentinel monitor $(TEST_SENTINEL_MASTER_NAME) 127.0.0.1 $(TEST_REDIS_PORT) 2 | |
48 | 59 | sentinel down-after-milliseconds $(TEST_SENTINEL_MASTER_NAME) 2000 |
49 | 60 | sentinel failover-timeout $(TEST_SENTINEL_MASTER_NAME) 10000 |
50 | 61 | sentinel parallel-syncs $(TEST_SENTINEL_MASTER_NAME) 5 |
75 | 86 | test: test_redis |
76 | 87 | test_all: start_redis_instances sleep test_redis stop_redis_instances |
77 | 88 | |
89 | check: | |
90 | luacheck lib | |
91 | ||
78 | 92 | sleep: |
79 | 93 | sleep 3 |
80 | 94 | |
81 | 95 | start_redis_instances: check_ports create_sentinel_config |
96 | $(REDIS_CMD) --version | |
97 | ||
82 | 98 | @$(foreach port,$(TEST_REDIS_PORTS), \ |
83 | [[ "$(port)" != "$(REDIS_FIRST_PORT)" ]] && \ | |
99 | [[ "$(port)" != "$(TEST_REDIS_PORT)" ]] && \ | |
84 | 100 | SLAVE="$(REDIS_SLAVE_ARG)" || \ |
85 | 101 | SLAVE="" && \ |
86 | 102 | $(MAKE) start_redis_instance args="$$SLAVE" port=$(port) \ |
93 | 109 | prefix=$(REDIS_PREFIX)$(port) && \ |
94 | 110 | ) true |
95 | 111 | |
96 | ||
97 | 112 | stop_redis_instances: delete_sentinel_config |
98 | 113 | -@$(foreach port,$(TEST_REDIS_PORTS) $(TEST_SENTINEL_PORTS), \ |
99 | 114 | $(MAKE) stop_redis_instance cleanup_redis_instance port=$(port) \ |
104 | 119 | start_redis_instance: |
105 | 120 | -@echo "Starting redis on port $(port) with args: \"$(args)\"" |
106 | 121 | -@mkdir -p $(prefix) |
107 | @$(REDIS_CMD) $(args) \ | |
122 | $(REDIS_CMD) $(args) \ | |
108 | 123 | --pidfile $(prefix)$(REDIS_PID) \ |
109 | 124 | --bind 127.0.0.1 --port $(port) \ |
110 | 125 | --unixsocket $(prefix)$(REDIS_SOCK) \ |
0 | 0 | # lua-resty-redis-connector |
1 | ||
2 | [![Build Status](https://travis-ci.org/ledgetech/lua-resty-redis-connector.svg?branch=master)](https://travis-ci.org/ledgetech/lua-resty-redis-connector) | |
1 | 3 | |
2 | 4 | Connection utilities for [lua-resty-redis](https://github.com/openresty/lua-resty-redis), making it easy and reliable to connect to Redis hosts, either directly or via [Redis Sentinel](http://redis.io/topics/sentinel). |
3 | 5 | |
90 | 92 | |
91 | 93 | Again, `PASSWORD` and `DB` are optional. `ROLE` must be either `m` or `s` for master / slave respectively. |
92 | 94 | |
95 | On versions of Redis newer than 5.0.1, Sentinels can optionally require their own password. If enabled, provide this password in the `sentinel_password` parameter. | |
96 | ||
93 | 97 | A table of `sentinels` must also be supplied. e.g. |
94 | 98 | |
95 | 99 | ```lua |
96 | 100 | local redis, err = rc:connect{ |
97 | 101 | url = "sentinel://mymaster:a/2", |
98 | 102 | sentinels = { |
99 | { host = "127.0.0.1", port = 26379" }, | |
100 | } | |
103 | { host = "127.0.0.1", port = 26379 }, | |
104 | }, | |
105 | sentinel_password = "password" | |
101 | 106 | } |
102 | 107 | ``` |
103 | 108 | |
132 | 137 | port = "6379", |
133 | 138 | path = "", -- unix socket path, e.g. /tmp/redis.sock |
134 | 139 | password = "", |
140 | sentinel_password = "", | |
135 | 141 | db = 0, |
136 | 142 | |
137 | 143 | master_name = "mymaster", |
4 | 4 | license=2bsd |
5 | 5 | lib_dir=lib |
6 | 6 | doc_dir=lib |
7 | repo_link=https://github.com/pintsized/lua-resty-redis-connector | |
7 | repo_link=https://github.com/ledgetech/lua-resty-redis-connector | |
8 | 8 | main_module=lib/resty/redis/connector.lua |
4 | 4 | local ngx_ERR = ngx.ERR |
5 | 5 | local ngx_re_match = ngx.re.match |
6 | 6 | |
7 | local str_find = string.find | |
7 | 8 | local tbl_remove = table.remove |
8 | 9 | local tbl_sort = table.sort |
9 | 10 | local ok, tbl_new = pcall(require, "table.new") |
10 | 11 | if not ok then |
11 | tbl_new = function (narr, nrec) return {} end | |
12 | tbl_new = function (narr, nrec) return {} end -- luacheck: ignore 212 | |
12 | 13 | end |
13 | 14 | |
14 | 15 | local redis = require("resty.redis") |
21 | 22 | -- A metatable which prevents undefined fields from being created / accessed |
22 | 23 | local fixed_field_metatable = { |
23 | 24 | __index = |
24 | function(t, k) | |
25 | function(t, k) -- luacheck: ignore 212 | |
25 | 26 | error("field " .. tostring(k) .. " does not exist", 3) |
26 | 27 | end, |
27 | 28 | __newindex = |
28 | function(t, k, v) | |
29 | function(t, k, v) -- luacheck: ignore 212 | |
29 | 30 | error("attempt to create new field " .. tostring(k), 3) |
30 | 31 | end, |
31 | 32 | } |
65 | 66 | if t1 == nil then t1 = {} end |
66 | 67 | if defaults == nil then defaults = {} end |
67 | 68 | if type(t1) == "table" and type(defaults) == "table" then |
68 | local mt = getmetatable(defaults) | |
69 | 69 | local copy = {} |
70 | 70 | for t1_key, t1_value in next, t1, nil do |
71 | 71 | copy[tbl_copy(t1_key)] = tbl_copy_merge_defaults( |
95 | 95 | port = 6379, |
96 | 96 | path = "", -- /tmp/redis.sock |
97 | 97 | password = "", |
98 | sentinel_password = "", | |
98 | 99 | db = 0, |
99 | 100 | url = "", -- DSN url |
100 | 101 | |
123 | 124 | |
124 | 125 | |
125 | 126 | local _M = { |
126 | _VERSION = '0.06', | |
127 | _VERSION = '0.09', | |
127 | 128 | } |
128 | 129 | |
129 | 130 | local mt = { __index = _M } |
155 | 156 | local parsed_params = {} |
156 | 157 | |
157 | 158 | for i,v in ipairs(fields) do |
158 | parsed_params[v] = m[i + 1] | |
159 | if v == "db" or v == "port" then | |
160 | parsed_params[v] = tonumber(m[i + 1]) | |
161 | else | |
162 | parsed_params[v] = m[i + 1] | |
163 | end | |
164 | ||
159 | 165 | if v == "role" then |
160 | 166 | parsed_params[v] = roles[parsed_params[v]] |
161 | 167 | end |
163 | 169 | |
164 | 170 | return tbl_copy_merge_defaults(params, parsed_params) |
165 | 171 | end |
172 | ||
173 | return params | |
166 | 174 | end |
167 | 175 | _M.parse_dsn = parse_dsn |
168 | 176 | |
172 | 180 | if config and config.url then |
173 | 181 | local err |
174 | 182 | config, err = parse_dsn(config) |
175 | if not ok then ngx_log(ngx_ERR, err) end | |
183 | if err then ngx_log(ngx_ERR, err) end | |
176 | 184 | end |
177 | 185 | |
178 | 186 | local ok, config = pcall(tbl_copy_merge_defaults, config, DEFAULTS) |
197 | 205 | if params and params.url then |
198 | 206 | local err |
199 | 207 | params, err = parse_dsn(params) |
200 | if not ok then ngx_log(ngx_ERR, err) end | |
208 | if err then ngx_log(ngx_ERR, err) end | |
201 | 209 | end |
202 | 210 | |
203 | 211 | params = tbl_copy_merge_defaults(params, self.config) |
225 | 233 | local role = params.role |
226 | 234 | local db = params.db |
227 | 235 | local password = params.password |
236 | local sentinel_password = params.sentinel_password | |
237 | if sentinel_password then | |
238 | for _,host in ipairs(sentinels) do | |
239 | host.password = sentinel_password | |
240 | end | |
241 | end | |
228 | 242 | |
229 | 243 | local sentnl, err, previous_errors = self:try_hosts(sentinels) |
230 | 244 | if not sentnl then |
233 | 247 | |
234 | 248 | if role == "master" then |
235 | 249 | local master, err = get_master(sentnl, master_name) |
236 | if master then | |
237 | master.db = db | |
238 | master.password = password | |
239 | ||
240 | local redis, err = self:connect_to_host(master) | |
241 | if redis then | |
242 | sentnl:set_keepalive() | |
243 | return redis, err | |
244 | else | |
245 | if role == "master" then | |
246 | return nil, err | |
247 | end | |
248 | end | |
249 | end | |
250 | ||
250 | if not master then | |
251 | return nil, err | |
252 | end | |
253 | ||
254 | sentnl:set_keepalive() | |
255 | ||
256 | master.db = db | |
257 | master.password = password | |
258 | ||
259 | local redis, err = self:connect_to_host(master) | |
260 | if not redis then | |
261 | return nil, err | |
262 | end | |
263 | ||
264 | return redis | |
251 | 265 | else |
252 | 266 | -- We want a slave |
253 | 267 | local slaves, err = get_slaves(sentnl, master_name) |
254 | sentnl:set_keepalive() | |
255 | ||
256 | 268 | if not slaves then |
257 | 269 | return nil, err |
258 | 270 | end |
259 | 271 | |
272 | sentnl:set_keepalive() | |
273 | ||
260 | 274 | -- Put any slaves on 127.0.0.1 at the front |
261 | 275 | tbl_sort(slaves, sort_by_localhost) |
262 | 276 | |
263 | 277 | if db or password then |
264 | for i,slave in ipairs(slaves) do | |
278 | for _, slave in ipairs(slaves) do | |
265 | 279 | slave.db = db |
266 | 280 | slave.password = password |
267 | 281 | end |
270 | 284 | local slave, err, previous_errors = self:try_hosts(slaves) |
271 | 285 | if not slave then |
272 | 286 | return nil, err, previous_errors |
273 | else | |
274 | return slave | |
275 | end | |
287 | end | |
288 | ||
289 | return slave | |
276 | 290 | end |
277 | 291 | end |
278 | 292 | |
297 | 311 | |
298 | 312 | function _M.connect_to_host(self, host) |
299 | 313 | local r = redis.new() |
300 | local config = self.config | |
314 | ||
315 | -- config options in 'host' should override the global defaults | |
316 | -- host contains keys that aren't in config | |
317 | -- this can break tbl_copy_merge_defaults, hence the mannual loop here | |
318 | local config = tbl_copy(self.config) | |
319 | for k, _ in pairs(config) do | |
320 | if host[k] then | |
321 | config[k] = host[k] | |
322 | end | |
323 | end | |
324 | ||
301 | 325 | r:set_timeout(config.connect_timeout) |
302 | 326 | |
303 | 327 | -- Stub out methods for disabled commands |
304 | 328 | if next(config.disabled_commands) then |
305 | 329 | for _, cmd in ipairs(config.disabled_commands) do |
306 | r[cmd] = function(...) | |
330 | r[cmd] = function() | |
307 | 331 | return nil, ("Command "..cmd.." is disabled") |
308 | 332 | end |
309 | 333 | end |
329 | 353 | if not ok then |
330 | 354 | return nil, err |
331 | 355 | else |
332 | r:set_timeout(self, config.read_timeout) | |
356 | r:set_timeout(config.read_timeout) | |
333 | 357 | |
334 | 358 | local password = host.password |
335 | 359 | if password and password ~= "" then |
336 | 360 | local res, err = r:auth(password) |
337 | 361 | if err then |
338 | ngx_log(ngx_ERR, err) | |
339 | 362 | return res, err |
340 | 363 | end |
341 | 364 | end |
342 | 365 | |
343 | 366 | -- No support for DBs in proxied Redis. |
344 | 367 | if config.connection_is_proxied ~= true and host.db ~= nil then |
345 | r:select(host.db) | |
368 | local res, err = r:select(host.db) | |
369 | ||
370 | -- SELECT will fail if we are connected to sentinel: | |
371 | -- detect it and ignore error message it that's the case | |
372 | if err and str_find(err, "ERR unknown command") then | |
373 | local role = r:role() | |
374 | if role and role[1] == "sentinel" then | |
375 | err = nil | |
376 | end | |
377 | end | |
378 | if err then | |
379 | return res, err | |
380 | end | |
346 | 381 | end |
347 | 382 | return r, nil |
348 | 383 | end |
349 | 384 | end |
350 | 385 | |
351 | 386 | |
352 | local function set_keepalive(self, redis) | |
387 | function _M.set_keepalive(self, redis) | |
353 | 388 | -- Restore connection to "NORMAL" before putting into keepalive pool, |
354 | 389 | -- ignoring any errors. |
355 | 390 | -- Proxied Redis does not support transactions. |
362 | 397 | config.keepalive_timeout, config.keepalive_poolsize |
363 | 398 | ) |
364 | 399 | end |
365 | _M.set_keepalive = set_keepalive | |
366 | ||
367 | 400 | |
368 | 401 | |
369 | 402 | -- Deprecated: use config table in new() or connect() instead. |
4 | 4 | local tbl_insert = table.insert |
5 | 5 | local ok, tbl_new = pcall(require, "table.new") |
6 | 6 | if not ok then |
7 | tbl_new = function (narr, nrec) return {} end | |
7 | tbl_new = function (narr, nrec) return {} end -- luacheck: ignore 212 | |
8 | 8 | end |
9 | 9 | |
10 | 10 | |
11 | 11 | local _M = { |
12 | _VERSION = '0.06' | |
12 | _VERSION = '0.09' | |
13 | 13 | } |
14 | 14 | |
15 | 15 | |
38 | 38 | host[slave[i]] = slave[i + 1] |
39 | 39 | end |
40 | 40 | |
41 | if host["master-link-status"] == "ok" then | |
41 | local master_link_status_ok = host["master-link-status"] == "ok" | |
42 | local is_down = host["flags"] and (string.find(host["flags"],"s_down") | |
43 | or string.find(host["flags"],"disconnected")) | |
44 | if master_link_status_ok and not is_down then | |
42 | 45 | host.host = host.ip -- for parity with other functions |
43 | 46 | tbl_insert(hosts, host) |
44 | 47 | end |
0 | package = "lua-resty-redis-connector" | |
1 | version = "0.06-0" | |
2 | source = { | |
3 | url = "git://github.com/pintsized/lua-resty-redis-connector", | |
4 | tag = "v0.06" | |
5 | } | |
6 | description = { | |
7 | summary = "Connection utilities for lua-resty-redis.", | |
8 | detailed = [[ | |
9 | Connection utilities for lua-resty-redis, making it easy and | |
10 | reliable to connect to Redis hosts, either directly or via Redis | |
11 | Sentinel. | |
12 | ]], | |
13 | homepage = "https://github.com/pintsized/lua-resty-redis-connector", | |
14 | license = "2-clause BSD", | |
15 | maintainer = "James Hurst <james@pintsized.co.uk>" | |
16 | } | |
17 | dependencies = { | |
18 | "lua >= 5.1", | |
19 | } | |
20 | build = { | |
21 | type = "builtin", | |
22 | modules = { | |
23 | ["resty.redis.connector"] = "lib/resty/redis/connector.lua", | |
24 | ["resty.redis.sentinel"] = "lib/resty/redis/sentinel.lua" | |
25 | } | |
26 | } |
0 | package = "lua-resty-redis-connector" | |
1 | version = "0.09-0" | |
2 | source = { | |
3 | url = "git://github.com/ledgetech/lua-resty-redis-connector", | |
4 | tag = "v0.09" | |
5 | } | |
6 | description = { | |
7 | summary = "Connection utilities for lua-resty-redis.", | |
8 | detailed = [[ | |
9 | Connection utilities for lua-resty-redis, making it easy and | |
10 | reliable to connect to Redis hosts, either directly or via Redis | |
11 | Sentinel. | |
12 | ]], | |
13 | homepage = "https://github.com/ledgetech/lua-resty-redis-connector", | |
14 | license = "2-clause BSD", | |
15 | maintainer = "James Hurst <james@pintsized.co.uk>" | |
16 | } | |
17 | dependencies = { | |
18 | "lua >= 5.1", | |
19 | } | |
20 | build = { | |
21 | type = "builtin", | |
22 | modules = { | |
23 | ["resty.redis.connector"] = "lib/resty/redis/connector.lua", | |
24 | ["resty.redis.sentinel"] = "lib/resty/redis/sentinel.lua" | |
25 | } | |
26 | } |
26 | 26 | --- config |
27 | 27 | location /t { |
28 | 28 | content_by_lua_block { |
29 | local rc = require("resty.redis.connector").new() | |
30 | ||
31 | local redis = assert(rc:connect(), "rc:connect should return postively") | |
32 | assert(redis:set("foo", "bar"), "redis:set should return positvely") | |
33 | assert(redis:get("foo") == "bar", "get(foo) should return bar") | |
34 | redis:close() | |
29 | local rc = assert(require("resty.redis.connector").new()) | |
35 | 30 | } |
36 | 31 | } |
37 | 32 | --- request |
47 | 42 | content_by_lua_block { |
48 | 43 | local config = { |
49 | 44 | connect_timeout = 500, |
50 | port = 6380, | |
45 | port = $TEST_NGINX_REDIS_PORT, | |
51 | 46 | db = 6, |
52 | 47 | } |
53 | 48 | local rc = require("resty.redis.connector").new(config) |
71 | 66 | content_by_lua_block { |
72 | 67 | local rc = require("resty.redis.connector").new({ |
73 | 68 | connect_timeout = 500, |
74 | port = 6380, | |
69 | port = $TEST_NGINX_REDIS_PORT, | |
75 | 70 | db = 6, |
76 | 71 | keepalive_poolsize = 10, |
77 | 72 | }) |
83 | 78 | assert(rc.config.keepalive_poolsize == 10, |
84 | 79 | "keepalive_poolsize should be 10") |
85 | 80 | |
86 | local redis = assert(rc:connect({ port = 6379 }), | |
81 | local redis = assert(rc:connect({ port = $TEST_NGINX_REDIS_PORT, disabled_commands = {"set"} }), | |
87 | 82 | "rc:connect should return positively") |
83 | ||
84 | local ok, err = redis:set("foo", "bar") | |
85 | assert( ok == nil and (string.find(err, "disabled") ~= nil) , "Disabled commands not passed through" ) | |
88 | 86 | } |
89 | 87 | } |
90 | 88 | --- request |
100 | 98 | content_by_lua_block { |
101 | 99 | local rc, err = require("resty.redis.connector").new({ |
102 | 100 | connect_timeout = 500, |
103 | port = 6380, | |
101 | port = $TEST_NGINX_REDIS_PORT, | |
104 | 102 | db = 6, |
105 | 103 | foo = "bar", |
106 | 104 | }) |
119 | 117 | keepalive_poolsize = 30, |
120 | 118 | |
121 | 119 | host = "127.0.0.1", |
122 | port = 6379, | |
120 | port = $TEST_NGINX_REDIS_PORT, | |
123 | 121 | path = "", |
124 | 122 | password = "", |
125 | 123 | db = 0, |
143 | 141 | keepalive_poolsize = 30, |
144 | 142 | |
145 | 143 | host = "127.0.0.1", |
146 | port = 6379, | |
144 | port = $TEST_NGINX_REDIS_PORT, | |
147 | 145 | path = "", |
148 | 146 | password = "", |
149 | 147 | db = 0, |
12 | 12 | |
13 | 13 | $ENV{TEST_NGINX_RESOLVER} = '8.8.8.8'; |
14 | 14 | $ENV{TEST_NGINX_REDIS_PORT} ||= 6379; |
15 | $ENV{TEST_NGINX_REDIS_SOCKET} ||= 'unix://tmp/redis/redis.sock'; | |
15 | 16 | |
16 | 17 | no_long_string(); |
17 | 18 | run_tests(); |
62 | 63 | assert(redis and not err, |
63 | 64 | "try_hosts should return a connection and no error") |
64 | 65 | |
65 | assert(previous_errors[1] == "connection refused", | |
66 | "previous_errors[1] should be 'connection refused'") | |
67 | assert(previous_errors[2] == "connection refused", | |
68 | "previous_errors[2] should be 'connection refused'") | |
66 | assert(string.len(previous_errors[1]) > 0, | |
67 | "previous_errors[1] should contain an error") | |
68 | assert(string.len(previous_errors[2]) > 0, | |
69 | "previous_errors[2] should contain an error") | |
69 | 70 | |
70 | 71 | assert(redis:set("dog", "an animal"), |
71 | 72 | "redis connection should be working") |
81 | 82 | assert(not redis and err == "no hosts available", |
82 | 83 | "no available hosts should return an error") |
83 | 84 | |
84 | assert(previous_errors[1] == "connection refused", | |
85 | "previous_errors[1] should be 'connection refused'") | |
86 | assert(previous_errors[2] == "connection refused", | |
87 | "previous_errors[2] should be 'connection refused'") | |
85 | assert(string.len(previous_errors[1]) > 0, | |
86 | "previous_errors[1] should contain an error") | |
87 | assert(string.len(previous_errors[2]) > 0, | |
88 | "previous_errors[2] should contain an error") | |
88 | 89 | } |
89 | 90 | } |
90 | 91 | --- request |
201 | 202 | }) |
202 | 203 | |
203 | 204 | local redis, err = rc:connect() |
204 | assert(not redis and string.find(err, "ERR Client sent AUTH, but no password is set"), | |
205 | assert(not redis and string.find(err, "ERR") and string.find(err, "AUTH"), | |
205 | 206 | "connect should fail with password error") |
206 | 207 | |
207 | 208 | } |
208 | 209 | } |
209 | 210 | --- request |
210 | 211 | GET /t |
211 | --- error_log | |
212 | ERR Client sent AUTH, but no password is set | |
213 | ||
214 | ||
215 | === TEST 7: unix domain socket | |
212 | --- no_error_log | |
213 | [error] | |
214 | ||
215 | ||
216 | === TEST 7: Bad unix domain socket path should fail | |
216 | 217 | --- http_config eval: $::HttpConfig |
217 | 218 | --- config |
218 | 219 | location /t { |
219 | 220 | lua_socket_log_errors Off; |
220 | 221 | content_by_lua_block { |
221 | 222 | local redis, err = require("resty.redis.connector").new({ |
222 | path = "unix://tmp/redis.sock", | |
223 | path = "unix://GARBAGE_PATH_AKFDKAJSFKJSAFLKJSADFLKJSANCKAJSNCKJSANCLKAJS", | |
223 | 224 | }):connect() |
224 | 225 | |
225 | 226 | assert(not redis and err == "no such file or directory", |
226 | 227 | "bad domain socket should fail") |
228 | } | |
229 | } | |
230 | --- request | |
231 | GET /t | |
232 | --- no_error_log | |
233 | [error] | |
234 | ||
235 | ||
236 | === TEST 7.1: Good unix domain socket path should succeed | |
237 | --- http_config eval: $::HttpConfig | |
238 | --- config | |
239 | location /t { | |
240 | lua_socket_log_errors Off; | |
241 | content_by_lua_block { | |
242 | local redis, err = require("resty.redis.connector").new({ | |
243 | path = "$TEST_NGINX_REDIS_SOCKET", | |
244 | }):connect() | |
245 | ||
246 | assert (redis and not err, | |
247 | "connection should be valid") | |
248 | ||
249 | redis:close() | |
227 | 250 | } |
228 | 251 | } |
229 | 252 | --- request |
292 | 315 | local rc = require("resty.redis.connector") |
293 | 316 | |
294 | 317 | local user_params = { |
295 | url = "redis://foo@127.0.0.1:6381/4", | |
318 | url = "redis://foo@127.0.0.1:$TEST_NGINX_REDIS_PORT/4", | |
296 | 319 | db = 2, |
297 | 320 | password = "bar", |
298 | 321 | host = "example.com", |
306 | 329 | assert(params.password == "bar", "password should be bar") |
307 | 330 | assert(params.host == "example.com", "host should be example.com") |
308 | 331 | |
309 | assert(tonumber(params.port) == 6381, "ort should still be 6381") | |
332 | assert(tonumber(params.port) == $TEST_NGINX_REDIS_PORT, "port should still be $TEST_NGINX_REDIS_PORT") | |
310 | 333 | |
311 | 334 | } |
312 | 335 | } |
359 | 382 | GET /t |
360 | 383 | --- no_error_log |
361 | 384 | [error] |
385 | ||
386 | ||
387 | === TEST 10: DSN without DB | |
388 | --- http_config eval: $::HttpConfig | |
389 | --- config | |
390 | location /t { | |
391 | lua_socket_log_errors Off; | |
392 | content_by_lua_block { | |
393 | local user_params = { | |
394 | url = "redis://foo.example:$TEST_NGINX_REDIS_PORT", | |
395 | host = "127.0.0.1", | |
396 | } | |
397 | ||
398 | local rc, err = require("resty.redis.connector").new(user_params) | |
399 | assert(rc and not err, "new should return positively") | |
400 | ||
401 | local redis, err = rc:connect() | |
402 | assert(redis and not err, "connect should return positively") | |
403 | assert(redis:set("cat", "dog") and redis:get("cat") == "dog") | |
404 | } | |
405 | } | |
406 | --- request | |
407 | GET /t | |
408 | --- no_error_log | |
409 | [error] |
11 | 11 | }; |
12 | 12 | |
13 | 13 | $ENV{TEST_NGINX_RESOLVER} = '8.8.8.8'; |
14 | $ENV{TEST_NGINX_REDIS_PORT} ||= 6379; | |
14 | $ENV{TEST_NGINX_REDIS_PORT} ||= 6380; | |
15 | $ENV{TEST_NGINX_REDIS_PORT_SL1} ||= 6381; | |
16 | $ENV{TEST_NGINX_REDIS_PORT_SL2} ||= 6382; | |
17 | $ENV{TEST_NGINX_SENTINEL_PORT1} ||= 6390; | |
18 | $ENV{TEST_NGINX_SENTINEL_PORT2} ||= 6391; | |
19 | $ENV{TEST_NGINX_SENTINEL_PORT3} ||= 6392; | |
15 | 20 | |
16 | 21 | no_long_string(); |
17 | 22 | run_tests(); |
25 | 30 | content_by_lua_block { |
26 | 31 | local rc = require("resty.redis.connector").new() |
27 | 32 | |
28 | local sentinel, err = rc:connect{ url = "redis://127.0.0.1:6381" } | |
29 | assert(sentinel and not err, "sentinel should connect without errors") | |
33 | local sentinel, err = rc:connect{ url = "redis://127.0.0.1:$TEST_NGINX_SENTINEL_PORT1" } | |
34 | assert(sentinel and not err, "sentinel should connect without errors but got " .. tostring(err)) | |
30 | 35 | |
31 | 36 | local master, err = require("resty.redis.sentinel").get_master( |
32 | 37 | sentinel, |
35 | 40 | |
36 | 41 | assert(master and not err, "get_master should return the master") |
37 | 42 | |
38 | assert(master.host == "127.0.0.1" and tonumber(master.port) == 6379, | |
39 | "host should be 127.0.0.1 and port should be 6379") | |
43 | assert(master.host == "127.0.0.1" and tonumber(master.port) == $TEST_NGINX_REDIS_PORT, | |
44 | "host should be 127.0.0.1 and port should be $TEST_NGINX_REDIS_PORT") | |
40 | 45 | |
41 | 46 | sentinel:close() |
42 | 47 | } |
57 | 62 | local master, err = rc:connect({ |
58 | 63 | url = "sentinel://mymaster:m/3", |
59 | 64 | sentinels = { |
60 | { host = "127.0.0.1", port = 6381 } | |
65 | { host = "127.0.0.1", port = $TEST_NGINX_SENTINEL_PORT1 } | |
61 | 66 | } |
62 | 67 | }) |
63 | 68 | |
81 | 86 | content_by_lua_block { |
82 | 87 | local rc = require("resty.redis.connector").new() |
83 | 88 | |
84 | local sentinel, err = rc:connect{ url = "redis://127.0.0.1:6381" } | |
89 | local sentinel, err = rc:connect{ url = "redis://127.0.0.1:$TEST_NGINX_SENTINEL_PORT1" } | |
85 | 90 | assert(sentinel and not err, "sentinel should connect without error") |
86 | 91 | |
87 | 92 | local slaves, err = require("resty.redis.sentinel").get_slaves( |
91 | 96 | |
92 | 97 | assert(slaves and not err, "slaves should be returned without error") |
93 | 98 | |
94 | local slaveports = { ["6378"] = false, ["6380"] = false } | |
99 | local slaveports = { ["$TEST_NGINX_REDIS_PORT_SL1"] = false, ["$TEST_NGINX_REDIS_PORT_SL2"] = false } | |
95 | 100 | |
96 | 101 | for _,slave in ipairs(slaves) do |
97 | 102 | slaveports[tostring(slave.port)] = true |
98 | 103 | end |
99 | 104 | |
100 | assert(slaveports["6378"] == true and slaveports["6380"] == true, | |
105 | assert(slaveports["$TEST_NGINX_REDIS_PORT_SL1"] == true and slaveports["$TEST_NGINX_REDIS_PORT_SL2"] == true, | |
101 | 106 | "slaves should both be found") |
102 | 107 | |
103 | 108 | sentinel:close() |
116 | 121 | content_by_lua_block { |
117 | 122 | local rc = require("resty.redis.connector").new() |
118 | 123 | |
119 | local sentinel, err = rc:connect({ url = "redis://127.0.0.1:6381" }) | |
124 | local sentinel, err = rc:connect({ url = "redis://127.0.0.1:$TEST_NGINX_SENTINEL_PORT1" }) | |
120 | 125 | assert(sentinel and not err, "sentinel should connect without error") |
121 | 126 | |
122 | 127 | local slaves, err = require("resty.redis.sentinel").get_slaves( |
126 | 131 | |
127 | 132 | assert(slaves and not err, "slaves should be returned without error") |
128 | 133 | |
129 | local slaveports = { ["6378"] = false, ["6380"] = false } | |
134 | local slaveports = { ["$TEST_NGINX_REDIS_PORT_SL1"] = false, ["$TEST_NGINX_REDIS_PORT_SL2"] = false } | |
130 | 135 | |
131 | 136 | for _,slave in ipairs(slaves) do |
132 | 137 | slaveports[tostring(slave.port)] = true |
133 | 138 | end |
134 | 139 | |
135 | assert(slaveports["6378"] == true and slaveports["6380"] == true, | |
140 | assert(slaveports["$TEST_NGINX_REDIS_PORT_SL1"] == true and slaveports["$TEST_NGINX_REDIS_PORT_SL2"] == true, | |
136 | 141 | "slaves should both be found") |
137 | 142 | |
138 | 143 | -- connect to one and remove it |
139 | 144 | local r = require("resty.redis.connector").new():connect({ |
140 | port = 6378, | |
145 | port = $TEST_NGINX_REDIS_PORT_SL1, | |
141 | 146 | }) |
142 | 147 | r:slaveof("127.0.0.1", 7000) |
143 | 148 | |
150 | 155 | |
151 | 156 | assert(slaves and not err, "slaves should be returned without error") |
152 | 157 | |
153 | local slaveports = { ["6378"] = false, ["6380"] = false } | |
158 | local slaveports = { ["$TEST_NGINX_REDIS_PORT_SL1"] = false, ["$TEST_NGINX_REDIS_PORT_SL2"] = false } | |
154 | 159 | |
155 | 160 | for _,slave in ipairs(slaves) do |
156 | 161 | slaveports[tostring(slave.port)] = true |
157 | 162 | end |
158 | 163 | |
159 | assert(slaveports["6378"] == false and slaveports["6380"] == true, | |
160 | "only 6380 should be found") | |
161 | ||
162 | r:slaveof("127.0.0.1", 6379) | |
164 | assert(slaveports["$TEST_NGINX_REDIS_PORT_SL1"] == false and slaveports["$TEST_NGINX_REDIS_PORT_SL2"] == true, | |
165 | "only $TEST_NGINX_REDIS_PORT_SL2 should be found") | |
166 | ||
167 | r:slaveof("127.0.0.1", $TEST_NGINX_REDIS_PORT) | |
163 | 168 | |
164 | 169 | sentinel:close() |
165 | 170 | } |
180 | 185 | |
181 | 186 | local params = { |
182 | 187 | sentinels = { |
183 | { host = "127.0.0.1", port = 6381 }, | |
184 | { host = "127.0.0.1", port = 6382 }, | |
185 | { host = "127.0.0.1", port = 6383 }, | |
188 | { host = "127.0.0.1", port = $TEST_NGINX_SENTINEL_PORT1 }, | |
189 | { host = "127.0.0.1", port = $TEST_NGINX_SENTINEL_PORT2 }, | |
190 | { host = "127.0.0.1", port = $TEST_NGINX_SENTINEL_PORT3 }, | |
186 | 191 | }, |
187 | 192 | master_name = "mymaster", |
188 | 193 | role = "master", |
213 | 218 | |
214 | 219 | local params = { |
215 | 220 | sentinels = { |
216 | { host = "127.0.0.1", port = 6381 }, | |
217 | { host = "127.0.0.1", port = 6382 }, | |
218 | { host = "127.0.0.1", port = 6383 }, | |
221 | { host = "127.0.0.1", port = $TEST_NGINX_SENTINEL_PORT1 }, | |
222 | { host = "127.0.0.1", port = $TEST_NGINX_SENTINEL_PORT2 }, | |
223 | { host = "127.0.0.1", port = $TEST_NGINX_SENTINEL_PORT3 }, | |
219 | 224 | }, |
220 | 225 | master_name = "mymaster", |
221 | 226 | role = "slave", |
225 | 230 | local sentinel = require("resty.redis.sentinel") |
226 | 231 | sentinel.get_slaves = function() |
227 | 232 | return { |
228 | { host = "127.0.0.1", port = 6380 }, | |
229 | { host = "127.0.0.1", port = 6378 }, | |
230 | { host = "127.0.0.1", port = 6377 }, | |
231 | { host = "134.123.51.2", port = 6380 }, | |
233 | { host = "127.0.0.1", port = $TEST_NGINX_REDIS_PORT_SL1 }, | |
234 | { host = "127.0.0.1", port = $TEST_NGINX_REDIS_PORT_SL2 }, | |
235 | { host = "134.123.51.2", port = $TEST_NGINX_REDIS_PORT_SL1 }, | |
232 | 236 | } |
233 | 237 | end |
234 | 238 |
39 | 39 | close $in; |
40 | 40 | |
41 | 41 | #print "Checking use of Lua global variables in file $file ...\n"; |
42 | system("luac5.1 -p -l $file | grep ETGLOBAL | grep -vE '(require|type|tostring|error|ngx|ndk|jit|setmetatable|getmetatable|string|table|io|os|print|tonumber|math|pcall|xpcall|unpack|pairs|ipairs|assert|module|package|coroutine|[gs]etfenv|next|select|rawset|rawget|debug)\$'"); | |
42 | system("luac -p -l $file | grep ETGLOBAL | grep -vE '(require|type|tostring|error|ngx|ndk|jit|setmetatable|getmetatable|string|table|io|os|print|tonumber|math|pcall|xpcall|unpack|pairs|ipairs|assert|module|package|coroutine|[gs]etfenv|next|select|rawset|rawget|debug)\$'"); | |
43 | 43 | #file_contains($file, "attempt to write to undeclared variable"); |
44 | 44 | system("grep -H -n -E --color '.{120}' $file"); |
45 | 45 | } |