├── .gitignore
├── .settings
└── org.eclipse.ldt.prefs
├── .travis.yml
├── scripts
├── start.sh
├── stop.sh
├── restart.sh
└── debug.sh
├── .buildpath
├── conf
├── fake.conf
├── dyn.conf
├── nginx.conf
└── api.conf
├── src
├── ngx_dynamic_upstream_lua.h
├── ngx_dynamic_upstream_lua_module.c
├── ngx_dynamic_upstream_stream_lua_module.c
├── ngx_dynamic_upstream_stream_lua.c
└── ngx_dynamic_upstream_lua.c
├── .project
├── ChangeLog
├── tests.sh
├── config
├── LICENSE
├── t
├── up-down.t
├── list.t
├── add.t
├── update.t
└── remove.t
└── README.markdown
/.gitignore:
--------------------------------------------------------------------------------
1 | servroot
2 | install
3 | download
4 | build
5 | tmp
6 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.ldt.prefs:
--------------------------------------------------------------------------------
1 | Grammar__default_id=lua-5.2
2 | eclipse.preferences.version=1
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 |
3 | compiler:
4 | - gcc
5 |
6 | script:
7 | - ./build.sh
8 |
--------------------------------------------------------------------------------
/scripts/start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | DIR=$(pwd)
4 | export LD_LIBRARY_PATH=$DIR/lib
5 | ./sbin/nginx -p $DIR
--------------------------------------------------------------------------------
/scripts/stop.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | DIR=$(pwd)
4 | export LD_LIBRARY_PATH=$DIR/lib
5 | ./sbin/nginx -s stop -p $DIR
--------------------------------------------------------------------------------
/scripts/restart.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | DIR=$(pwd)
4 | export LD_LIBRARY_PATH=$DIR/lib
5 | ./sbin/nginx -s reload -p $DIR
--------------------------------------------------------------------------------
/.buildpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/scripts/debug.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ulimit -c unlimited
4 | DIR=$(pwd)
5 | export LD_LIBRARY_PATH=$DIR/lib
6 | ./sbin/nginx.debug -p $DIR
7 |
--------------------------------------------------------------------------------
/conf/fake.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 9090;
3 | listen 9091;
4 |
5 | default_type text/plain;
6 |
7 | location / {
8 | return 200 'Hello world!';
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/conf/dyn.conf:
--------------------------------------------------------------------------------
1 | http {
2 | lua_package_path "/path/to/lua-ngx-dynamic-upstream-lua/lib/?.lua;;";
3 |
4 | lua_socket_log_errors off;
5 |
6 | include fake.conf;
7 | include api.conf;
8 | }
9 |
--------------------------------------------------------------------------------
/src/ngx_dynamic_upstream_lua.h:
--------------------------------------------------------------------------------
1 | #ifndef _ngx_dynamic_upstream_lua_h_
2 | #define _ngx_dynamic_upstream_lua_h_
3 |
4 |
5 | #include
6 |
7 |
8 | ngx_int_t
9 | ngx_http_dynamic_upstream_lua_init(ngx_conf_t *cf);
10 |
11 |
12 | #endif
--------------------------------------------------------------------------------
/conf/nginx.conf:
--------------------------------------------------------------------------------
1 | worker_processes 1;
2 |
3 | pid logs/nginx.pid;
4 |
5 | error_log logs/error.log info;
6 | error_log logs/debug.log debug;
7 |
8 | events {
9 | use epoll;
10 | worker_connections 1024;
11 | multi_accept on;
12 | }
13 |
14 | include "dyn.conf";
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | ngx_dynamic_upstream_lua
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.dltk.core.scriptbuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.ldt.nature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/ChangeLog:
--------------------------------------------------------------------------------
1 | 2.0.0
2 |
3 | 1) Remove: Healthcheck directives and lua healthcheck api removed. Use ngx_dynamic_healthcheck module.
4 | 2) Update: Upstreams without 'zone' directive are not supported.
5 |
6 | 1.1.0
7 |
8 | 03.01.2017
9 |
10 | 1) Fix: crash on try to get information from the upstream without backups peers.
11 | 2) New: check_request_body, check_response_body to stream upstreams.
12 | 3) New: disconnect_if_market_down stream upstream directive.
13 |
14 | 1.0.0
15 |
16 | Initial release
--------------------------------------------------------------------------------
/tests.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | DIR=$(pwd)
4 | nginx_fname=$(ls -1 $DIR/install/*.tar.gz)
5 |
6 | [ -d install/tmp ] || mkdir install/tmp
7 | tar zxf $nginx_fname -C install/tmp
8 |
9 | folder="$(ls -1 $DIR/install/tmp | grep nginx)"
10 |
11 | export PATH=$DIR/install/tmp/$folder/sbin:$PATH
12 | export LD_LIBRARY_PATH=$DIR/install/tmp/$folder/lib
13 | export LUA_PATH="$DIR/install/tmp/$folder/lib/?.lua"
14 | export LUA_CPATH="$DIR/install/tmp/$folder/lib/lua/5.1/?.so"
15 |
16 | ret=0
17 |
18 | for t in $(ls t/*.t)
19 | do
20 | echo "Tests : "$t
21 | prove $t
22 | if [ $? -ne 0 ]; then
23 | ret=$?
24 | fi
25 | done
26 |
27 | rm -rf t/servroot
28 | rm -rf install/tmp
29 |
30 | exit $ret
--------------------------------------------------------------------------------
/config:
--------------------------------------------------------------------------------
1 | ngx_addon_name="ngx_http_dynamic_upstream_lua_module ngx_stream_dynamic_upstream_lua_module"
2 |
3 | HTTP_LUA_UPSTREAM_SRCS="$ngx_addon_dir/src/ngx_dynamic_upstream_lua.c \
4 | $ngx_addon_dir/src/ngx_dynamic_upstream_lua_module.c \
5 | $ngx_addon_dir/src/ngx_dynamic_upstream_stream_lua.c \
6 | $ngx_addon_dir/src/ngx_dynamic_upstream_stream_lua_module.c"
7 |
8 | stream_lua_nginx_module_incs="$(echo $CORE_INCS | awk '{
9 | match($0, /([^ ]*\/stream-lua-nginx-module\/src)/, arr)
10 | print arr[1]
11 | }')"
12 | CORE_INCS="$CORE_INCS $stream_lua_nginx_module_incs"
13 |
14 | if test -n "$ngx_module_link"; then
15 | ngx_module_type=HTTP
16 | ngx_module_name=$ngx_addon_name
17 | ngx_module_srcs="$HTTP_LUA_UPSTREAM_SRCS"
18 |
19 | . auto/module
20 | else
21 | HTTP_MODULES="$HTTP_MODULES $ngx_addon_name"
22 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $HTTP_LUA_UPSTREAM_SRCS"
23 | fi
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 2-Clause License
2 |
3 | Copyright (c) 2016, Aleksey Konovkin
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
--------------------------------------------------------------------------------
/src/ngx_dynamic_upstream_lua_module.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "ngx_http_lua_api.h"
5 |
6 |
7 | #include "ngx_dynamic_upstream_lua.h"
8 |
9 |
10 | ngx_module_t ngx_http_dynamic_upstream_lua_module;
11 |
12 |
13 | static ngx_int_t
14 | ngx_http_dynamic_upstream_lua_post_conf(ngx_conf_t *cf);
15 |
16 |
17 | static ngx_http_module_t ngx_http_dynamic_upstream_lua_ctx = {
18 | NULL, /* preconfiguration */
19 | ngx_http_dynamic_upstream_lua_post_conf, /* postconfiguration */
20 | NULL, /* create main */
21 | NULL, /* init main */
22 | NULL, /* create server */
23 | NULL, /* merge server */
24 | NULL, /* create location */
25 | NULL /* merge location */
26 | };
27 |
28 |
29 | ngx_module_t ngx_http_dynamic_upstream_lua_module = {
30 | NGX_MODULE_V1,
31 | &ngx_http_dynamic_upstream_lua_ctx, /* module context */
32 | NULL, /* module directives */
33 | NGX_HTTP_MODULE, /* module type */
34 | NULL, /* init master */
35 | NULL, /* init module */
36 | NULL, /* init process */
37 | NULL, /* init thread */
38 | NULL, /* exit thread */
39 | NULL, /* exit process */
40 | NULL, /* exit master */
41 | NGX_MODULE_V1_PADDING
42 | };
43 |
44 | extern int
45 | ngx_stream_dynamic_upstream_lua_create_module(lua_State *L);
46 |
47 | ngx_int_t
48 | ngx_http_dynamic_upstream_lua_post_conf(ngx_conf_t *cf)
49 | {
50 | if (ngx_http_dynamic_upstream_lua_init(cf) != NGX_OK) {
51 | return NGX_ERROR;
52 | }
53 |
54 | if (ngx_http_lua_add_package_preload(cf, "ngx.dynamic_upstream.stream",
55 | ngx_stream_dynamic_upstream_lua_create_module) != NGX_OK) {
56 | return NGX_ERROR;
57 | }
58 |
59 | return NGX_OK;
60 | }
61 |
--------------------------------------------------------------------------------
/conf/api.conf:
--------------------------------------------------------------------------------
1 | upstream backend {
2 | zone backend 1m;
3 | server 127.0.0.1:9090;
4 | }
5 |
6 | server {
7 | listen 8888;
8 |
9 | default_type text/plain;
10 |
11 | # curl "http://localhost:8888/backend/add?peer=127.0.0.1:9091&primary=1&weight=1&max_fails=2&fail_timeout=30&max_conns=100"
12 | # curl "http://localhost:8888/backend/add?peer=127.0.0.1:9091&backup=1&weight=1&max_fails=2&fail_timeout=30&max_conns=100"
13 | location ~* ^/(.+)/add {
14 | set $upstream $1;
15 | content_by_lua_block {
16 | local upstream = require "ngx.dynamic_upstream"
17 |
18 | local peer = ngx.var.arg_peer
19 | local u = ngx.var.upstream
20 |
21 | local ok, err
22 | if ngx.var.arg_backup and ngx.var.arg_backup == 1 then
23 | ok, _, err = upstream.add_backup_peer(u, peer)
24 | else
25 | ok, _, err = upstream.add_primary_peer(u, peer)
26 | end
27 |
28 | if not ok then
29 | ngx.say("Failed to add peer " .. peer .. ": ", err)
30 | return
31 | end
32 |
33 | local peer_args = {
34 | weight = ngx.var.arg_weight or 1,
35 | max_fails = ngx.var.arg_max_fails or 2,
36 | fail_timeout = ngx.var.arg_fail_timeout or 5,
37 | max_conns = ngx.var.arg_max_conns or 1,
38 | down = 1
39 | }
40 |
41 | ok, _, err = upstream.update_peer(u, peer, peer_args)
42 | if not ok then
43 | ngx.say("Failed to update peer " .. peer .. " params, error: ", err)
44 | return
45 | end
46 |
47 | ngx.say("Added " .. peer .. " to " .. u .. " upstream")
48 | }
49 | }
50 |
51 | # remove peer
52 | # curl "http://localhost:8888/backend/remove?peer=127.0.0.1:9091"
53 | location ~* ^/(.+)/remove {
54 | set $upstream $1;
55 | content_by_lua_block {
56 | local upstream = require "ngx.dynamic_upstream"
57 |
58 | local peer = ngx.var.arg_peer
59 | local u = ngx.var.upstream
60 |
61 | local ok, _, err = upstream.remove_peer(u, peer)
62 | if not ok then
63 | ngx.say("Failed to remove peer " .. peer .. ": ", err)
64 | return
65 | end
66 |
67 | ngx.say("Removed " .. peer .. " from " .. u .. " upstream")
68 | }
69 | }
70 |
71 | # status page for all the peers:
72 | location = /status {
73 | content_by_lua_block {
74 | local upstream = require "ngx.dynamic_upstream"
75 |
76 | local ok, upstreams, err = upstream.get_upstreams()
77 | if not ok then
78 | ngx.say(err)
79 | ngx.exit(200)
80 | end
81 |
82 | local get_peers = function(u)
83 | local ok, peers, err = upstream.get_primary_peers(u)
84 | if not ok then
85 | ngx.say(err)
86 | ngx.exit(200)
87 | end
88 |
89 | local t = {}
90 |
91 | for _, peer in pairs(peers)
92 | do
93 | table.insert(t, peer)
94 | end
95 |
96 | ok, peers, err = upstream.get_backup_peers(u)
97 | if not ok then
98 | ngx.say(err)
99 | ngx.exit(200)
100 | end
101 |
102 | for _, peer in pairs(peers)
103 | do
104 | table.insert(t, peer)
105 | end
106 |
107 | return t
108 | end
109 |
110 | local tointeger = function (b) if b then return 1 else return 0 end end
111 |
112 | for _, u in pairs(upstreams)
113 | do
114 | ngx.say(u)
115 |
116 | for _, peer in pairs(get_peers(u))
117 | do
118 | local status = "up"
119 | if peer.down ~= nil then
120 | status = "down"
121 | end
122 |
123 | ngx.say(" server " .. peer.name .. " backup=" .. tointeger(peer.backup) .. " weight=" .. peer.weight .. " max_conns=" .. peer.max_conns .. " max_fails=" .. peer.max_fails .. " fail_timeout=" .. peer.fail_timeout .. " status=" .. status)
124 | end
125 | end
126 | }
127 | }
128 | }
--------------------------------------------------------------------------------
/t/up-down.t:
--------------------------------------------------------------------------------
1 | use Test::Nginx::Socket;
2 | use Test::Nginx::Socket::Lua::Stream;
3 |
4 | repeat_each(1);
5 |
6 | plan tests => repeat_each() * 2 * blocks();
7 |
8 | run_tests();
9 |
10 | __DATA__
11 |
12 | === TEST 1: down primary peer
13 | --- http_config
14 | upstream backends {
15 | zone shm-backends 128k;
16 | server 127.0.0.1:6001;
17 | server 127.0.0.1:6002;
18 | }
19 | --- config
20 | location /test {
21 | content_by_lua_block {
22 | local upstream = require "ngx.dynamic_upstream"
23 | local ok, err = upstream.update_peer(ngx.var.arg_upstream, ngx.var.arg_peer, { down = 1 })
24 | if not ok then
25 | ngx.say(err)
26 | ngx.exit(200)
27 | end
28 | local tointeger = function(b) if b then return 1 else return 0 end end
29 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
30 | if not ok then
31 | ngx.say(err)
32 | ngx.exit(200)
33 | end
34 | for _, peer in pairs(peers)
35 | do
36 | ngx.say(peer.name .. " down=" .. tointeger(peer.down))
37 | end
38 | }
39 | }
40 | --- request
41 | GET /test?upstream=backends&peer=127.0.0.1:6002
42 | --- response_body
43 | 127.0.0.1:6001 down=0
44 | 127.0.0.1:6002 down=1
45 |
46 |
47 | === TEST 2: up primary peer
48 | --- http_config
49 | upstream backends {
50 | zone shm-backends 128k;
51 | server 127.0.0.1:6001 down;
52 | server 127.0.0.1:6002 down;
53 | }
54 | --- config
55 | location /test {
56 | content_by_lua_block {
57 | local upstream = require "ngx.dynamic_upstream"
58 | local ok, err = upstream.update_peer(ngx.var.arg_upstream, ngx.var.arg_peer, { down = 0 })
59 | if not ok then
60 | ngx.say(err)
61 | ngx.exit(200)
62 | end
63 | local tointeger = function(b) if b then return 1 else return 0 end end
64 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
65 | if not ok then
66 | ngx.say(err)
67 | ngx.exit(200)
68 | end
69 | for _, peer in pairs(peers)
70 | do
71 | ngx.say(peer.name .. " down=" .. tointeger(peer.down))
72 | end
73 | }
74 | }
75 | --- request
76 | GET /test?upstream=backends&peer=127.0.0.1:6001
77 | --- response_body
78 | 127.0.0.1:6001 down=0
79 | 127.0.0.1:6002 down=1
80 |
81 |
82 | === TEST 3: down primary peer
83 | --- stream_config
84 | upstream backends {
85 | zone shm-backends 128k;
86 | server 127.0.0.1:6001;
87 | server 127.0.0.1:6002;
88 | }
89 | --- stream_server_config
90 | proxy_pass backends;
91 | --- config
92 | location /test {
93 | content_by_lua_block {
94 | local upstream = require "ngx.dynamic_upstream.stream"
95 | local ok, err = upstream.update_peer(ngx.var.arg_upstream, ngx.var.arg_peer, { down = 1 })
96 | if not ok then
97 | ngx.say(err)
98 | ngx.exit(200)
99 | end
100 | local tointeger = function(b) if b then return 1 else return 0 end end
101 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
102 | if not ok then
103 | ngx.say(err)
104 | ngx.exit(200)
105 | end
106 | for _, peer in pairs(peers)
107 | do
108 | ngx.say(peer.name .. " down=" .. tointeger(peer.down))
109 | end
110 | }
111 | }
112 | --- request
113 | GET /test?upstream=backends&peer=127.0.0.1:6002
114 | --- response_body
115 | 127.0.0.1:6001 down=0
116 | 127.0.0.1:6002 down=1
117 |
118 |
119 | === TEST 3: up stream primary peer
120 | --- stream_config
121 | upstream backends {
122 | zone shm-backends 128k;
123 | server 127.0.0.1:6001 down;
124 | server 127.0.0.1:6002 down;
125 | }
126 | --- stream_server_config
127 | proxy_pass backends;
128 | --- config
129 | location /test {
130 | content_by_lua_block {
131 | local upstream = require "ngx.dynamic_upstream.stream"
132 | local ok, err = upstream.update_peer(ngx.var.arg_upstream, ngx.var.arg_peer, { down = 0 })
133 | if not ok then
134 | ngx.say(err)
135 | ngx.exit(200)
136 | end
137 | local tointeger = function(b) if b then return 1 else return 0 end end
138 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
139 | if not ok then
140 | ngx.say(err)
141 | ngx.exit(200)
142 | end
143 | for _, peer in pairs(peers)
144 | do
145 | ngx.say(peer.name .. " down=" .. tointeger(peer.down))
146 | end
147 | }
148 | }
149 | --- request
150 | GET /test?upstream=backends&peer=127.0.0.1:6001
151 | --- response_body
152 | 127.0.0.1:6001 down=0
153 | 127.0.0.1:6002 down=1
154 |
--------------------------------------------------------------------------------
/t/list.t:
--------------------------------------------------------------------------------
1 | use Test::Nginx::Socket;
2 | use Test::Nginx::Socket::Lua::Stream;
3 |
4 | repeat_each(1);
5 |
6 | plan tests => repeat_each() * 2 * blocks();
7 |
8 | run_tests();
9 |
10 | __DATA__
11 |
12 | === TEST 1: list upstreams
13 | --- http_config
14 | upstream backends1 {
15 | zone shm-backends1 128k;
16 | server 127.0.0.1:6001;
17 | }
18 | upstream backends2 {
19 | zone shm-backends2 128k;
20 | server 127.0.0.1:6002;
21 | }
22 | upstream backends3 {
23 | server 127.0.0.1:6003;
24 | }
25 | --- config
26 | location /test {
27 | content_by_lua_block {
28 | local upstream = require "ngx.dynamic_upstream"
29 | local ok, ups, err = upstream.get_upstreams()
30 | if not ok then
31 | ngx.say(err)
32 | ngx.exit(500)
33 | end
34 | for _, u in pairs(ups)
35 | do
36 | ngx.say(u)
37 | end
38 | }
39 | }
40 | --- request
41 | GET /test
42 | --- response_body
43 | backends1
44 | backends2
45 | backends3
46 |
47 |
48 | === TEST 2: list peers
49 | --- http_config
50 | upstream backends {
51 | zone shm-backends 128k;
52 | server 127.0.0.1:6001 weight=1 max_fails=2 max_conns=100 fail_timeout=10 down;
53 | server 127.0.0.1:6002 weight=1 max_fails=2 max_conns=100 fail_timeout=10;
54 | server 127.0.0.1:6003 weight=1 max_fails=1 max_conns=200 fail_timeout=10 backup;
55 | }
56 | --- config
57 | location /test {
58 | content_by_lua_block {
59 | local upstream = require "ngx.dynamic_upstream"
60 | local ok, pp, err = upstream.get_primary_peers(ngx.var.arg_upstream)
61 | if not ok then
62 | ngx.say(err)
63 | ngx.exit(500)
64 | end
65 | local ok, bp, err = upstream.get_backup_peers(ngx.var.arg_upstream)
66 | if not ok then
67 | ngx.say(err)
68 | ngx.exit(500)
69 | end
70 | local tointeger = function(b) if b then return 1 else return 0 end end
71 | for _, peer in pairs(pp)
72 | do
73 | ngx.say(peer.name .. ";" .. peer.weight .. ";" .. peer.max_fails .. ";" .. peer.max_conns .. ";" .. peer.fail_timeout .. ";" .. tointeger(peer.down))
74 | end
75 | for _, peer in pairs(bp)
76 | do
77 | ngx.say(peer.name .. ";" .. peer.weight .. ";" .. peer.max_fails .. ";" .. peer.max_conns .. ";" .. peer.fail_timeout .. ";" .. tointeger (peer.down) .. ";backup")
78 | end
79 | }
80 | }
81 | --- request
82 | GET /test?upstream=backends
83 | --- response_body
84 | 127.0.0.1:6001;1;2;100;10;1
85 | 127.0.0.1:6002;1;2;100;10;0
86 | 127.0.0.1:6003;1;1;200;10;0;backup
87 |
88 |
89 | === TEST 3: list stream upstreams
90 | --- stream_config
91 | upstream backends1 {
92 | zone shm-backends1 128k;
93 | server 127.0.0.1:6001;
94 | }
95 | upstream backends2 {
96 | zone shm-backends2 128k;
97 | server 127.0.0.1:6002;
98 | }
99 | upstream backends3 {
100 | server 127.0.0.1:6003;
101 | }
102 | --- stream_server_config
103 | proxy_pass backends1;
104 | --- config
105 | location /test {
106 | content_by_lua_block {
107 | local upstream = require "ngx.dynamic_upstream.stream"
108 | local ok, ups, err = upstream.get_upstreams()
109 | if not ok then
110 | ngx.say(err)
111 | ngx.exit(500)
112 | end
113 | for _, u in pairs(ups)
114 | do
115 | ngx.say(u)
116 | end
117 | }
118 | }
119 | --- request
120 | GET /test
121 | --- response_body
122 | backends1
123 | backends2
124 | backends3
125 |
126 | === TEST 4: list stream peers
127 | --- stream_config
128 | upstream backends {
129 | zone shm-backends 128k;
130 | server 127.0.0.1:6001 weight=1 max_fails=2 max_conns=100 fail_timeout=10 down;
131 | server 127.0.0.1:6002 weight=1 max_fails=2 max_conns=100 fail_timeout=10;
132 | server 127.0.0.1:6003 weight=1 max_fails=1 max_conns=200 fail_timeout=10 backup;
133 | }
134 | --- stream_server_config
135 | proxy_pass backends;
136 | --- config
137 | location /test {
138 | content_by_lua_block {
139 | local upstream = require "ngx.dynamic_upstream.stream"
140 | local ok, pp, err = upstream.get_primary_peers(ngx.var.arg_upstream)
141 | if not ok then
142 | ngx.say(err)
143 | ngx.exit(500)
144 | end
145 | local ok, bp, err = upstream.get_backup_peers(ngx.var.arg_upstream)
146 | if not ok then
147 | ngx.say(err)
148 | ngx.exit(500)
149 | end
150 | local tointeger = function(b) if b then return 1 else return 0 end end
151 | for _, peer in pairs(pp)
152 | do
153 | ngx.say(peer.name .. ";" .. peer.weight .. ";" .. peer.max_fails .. ";" .. peer.max_conns .. ";" .. peer.fail_timeout .. ";" .. tointeger(peer.down))
154 | end
155 | for _, peer in pairs(bp)
156 | do
157 | ngx.say(peer.name .. ";" .. peer.weight .. ";" .. peer.max_fails .. ";" .. peer.max_conns .. ";" .. peer.fail_timeout .. ";" .. tointeger (peer.down) .. ";backup")
158 | end
159 | }
160 | }
161 | --- request
162 | GET /test?upstream=backends
163 | --- response_body
164 | 127.0.0.1:6001;1;2;100;10;1
165 | 127.0.0.1:6002;1;2;100;10;0
166 | 127.0.0.1:6003;1;1;200;10;0;backup
167 |
--------------------------------------------------------------------------------
/src/ngx_dynamic_upstream_stream_lua_module.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "ngx_stream_lua_request.h"
5 | #include "ngx_stream_lua_api.h"
6 |
7 |
8 | ngx_module_t ngx_stream_dynamic_upstream_lua_module;
9 |
10 |
11 | static ngx_int_t
12 | ngx_stream_dynamic_upstream_lua_post_conf(ngx_conf_t *cf);
13 |
14 | static void *
15 | ngx_stream_dynamic_upstream_lua_create_srv_conf(ngx_conf_t *cf);
16 |
17 |
18 | static ngx_int_t ngx_stream_dynamic_upstream_write_filter
19 | (ngx_stream_session_t *s, ngx_chain_t *in, ngx_uint_t from_upstream);
20 |
21 |
22 | typedef struct {
23 | ngx_flag_t disconnect_backup;
24 | ngx_flag_t disconnect_down;
25 | ngx_flag_t disconnect_on_exiting;
26 | } ngx_stream_dynamic_upstream_lua_srv_conf_t;
27 |
28 |
29 | static char *
30 | ngx_stream_dynamic_upstream_lua_disconnect_backup_if_primary_up(ngx_conf_t *cf,
31 | ngx_command_t *cmd, void *conf);
32 |
33 | static char *
34 | ngx_stream_dynamic_upstream_lua_disconnect_if_market_down(ngx_conf_t *cf,
35 | ngx_command_t *cmd, void *conf);
36 |
37 | static char *
38 | ngx_stream_dynamic_upstream_lua_disconnect_on_exiting(ngx_conf_t *cf,
39 | ngx_command_t *cmd, void *conf);
40 |
41 |
42 | static ngx_command_t ngx_stream_dynamic_upstream_lua_commands[] = {
43 |
44 | { ngx_string("disconnect_backup_if_primary_up"),
45 | NGX_STREAM_UPS_CONF|NGX_CONF_NOARGS,
46 | ngx_stream_dynamic_upstream_lua_disconnect_backup_if_primary_up,
47 | NGX_STREAM_SRV_CONF_OFFSET,
48 | 0,
49 | NULL },
50 |
51 | { ngx_string("disconnect_if_market_down"),
52 | NGX_STREAM_UPS_CONF|NGX_CONF_NOARGS,
53 | ngx_stream_dynamic_upstream_lua_disconnect_if_market_down,
54 | NGX_STREAM_SRV_CONF_OFFSET,
55 | 0,
56 | NULL },
57 |
58 | { ngx_string("disconnect_on_exiting"),
59 | NGX_STREAM_UPS_CONF|NGX_CONF_NOARGS,
60 | ngx_stream_dynamic_upstream_lua_disconnect_on_exiting,
61 | NGX_STREAM_SRV_CONF_OFFSET,
62 | 0,
63 | NULL },
64 |
65 | ngx_null_command
66 |
67 | };
68 |
69 |
70 | static ngx_stream_module_t ngx_stream_dynamic_upstream_lua_ctx = {
71 | NULL, /* preconfiguration */
72 | ngx_stream_dynamic_upstream_lua_post_conf, /* postconfiguration */
73 | NULL, /* create main */
74 | NULL, /* init main */
75 | ngx_stream_dynamic_upstream_lua_create_srv_conf, /* create server */
76 | NULL /* merge server */
77 | };
78 |
79 |
80 | ngx_module_t ngx_stream_dynamic_upstream_lua_module = {
81 | NGX_MODULE_V1,
82 | &ngx_stream_dynamic_upstream_lua_ctx, /* module context */
83 | ngx_stream_dynamic_upstream_lua_commands, /* module directives */
84 | NGX_STREAM_MODULE, /* module type */
85 | NULL, /* init master */
86 | NULL, /* init module */
87 | NULL, /* init process */
88 | NULL, /* init thread */
89 | NULL, /* exit thread */
90 | NULL, /* exit process */
91 | NULL, /* exit master */
92 | NGX_MODULE_V1_PADDING
93 | };
94 |
95 |
96 | static ngx_stream_filter_pt
97 | ngx_stream_next_filter;
98 |
99 |
100 | static ngx_uint_t
101 | ngx_stream_dynamic_upstream_alive_primary(ngx_stream_upstream_rr_peers_t *peers,
102 | ngx_stream_upstream_rr_peer_t *current)
103 | {
104 | ngx_stream_upstream_rr_peer_t *peer;
105 | int alive = 0;
106 |
107 | for (peer = peers->peer; peer; peer = peer->next) {
108 |
109 | if (current == peer)
110 | return 0;
111 |
112 | alive = alive + (peer->down == 0 ? 1 : 0);
113 | }
114 |
115 | return alive;
116 | }
117 |
118 |
119 | static ngx_stream_upstream_rr_peer_t *
120 | ngx_stream_dynamic_upstream_get_peer(ngx_stream_upstream_rr_peers_t *primary,
121 | ngx_str_t *name)
122 | {
123 | ngx_stream_upstream_rr_peer_t *peer;
124 | ngx_stream_upstream_rr_peers_t *peers;
125 |
126 | for (peers = primary; peers; peers = peers->next) {
127 |
128 | for (peer = peers->peer; peer; peer = peer->next) {
129 |
130 | if (peer->name.len == name->len &&
131 | ngx_strncmp(peer->name.data, name->data, name->len) == 0) {
132 | return peer;
133 | }
134 | }
135 | }
136 |
137 | return NULL;
138 | }
139 |
140 |
141 | static ngx_int_t
142 | ngx_have_upstream(ngx_stream_session_t *s)
143 | {
144 | return s->upstream &&
145 | s->upstream->upstream &&
146 | s->upstream->upstream->srv_conf &&
147 | s->upstream->state &&
148 | s->upstream->state->peer;
149 | }
150 |
151 |
152 | typedef struct {
153 | ngx_stream_upstream_rr_peer_t *peer;
154 | ngx_msec_t check_ms;
155 | } context_t;
156 |
157 |
158 | static ngx_int_t
159 | ngx_stream_dynamic_upstream_write_filter(ngx_stream_session_t *s,
160 | ngx_chain_t *in, ngx_uint_t from_upstream)
161 | {
162 | ngx_stream_dynamic_upstream_lua_srv_conf_t *ucscf;
163 | ngx_stream_upstream_srv_conf_t *uscf;
164 | ngx_stream_upstream_rr_peers_t *peers = NULL;
165 | context_t *ctx;
166 |
167 | if (!ngx_have_upstream(s))
168 | goto skip;
169 |
170 | uscf = s->upstream->upstream;
171 | peers = uscf->peer.data;
172 |
173 | ngx_stream_upstream_rr_peers_rlock(peers);
174 |
175 | ctx = ngx_stream_get_module_ctx(s, ngx_stream_dynamic_upstream_lua_module);
176 |
177 | if (ctx == NULL) {
178 | ctx = ngx_pcalloc(s->connection->pool, sizeof(context_t));
179 | if (ctx == NULL)
180 | goto skip;
181 |
182 | ngx_stream_set_ctx(s, ctx, ngx_stream_dynamic_upstream_lua_module);
183 |
184 | ctx->peer = ngx_stream_dynamic_upstream_get_peer(peers,
185 | s->upstream->state->peer);
186 |
187 | if (ctx->peer == NULL)
188 | goto skip;
189 | }
190 |
191 | if (ctx->peer == NULL)
192 | goto skip;
193 |
194 | if (ngx_current_msec - ctx->check_ms < 1000)
195 | goto skip;
196 |
197 | ucscf = ngx_stream_conf_upstream_srv_conf(uscf,
198 | ngx_stream_dynamic_upstream_lua_module);
199 |
200 | if (ucscf->disconnect_down && ctx->peer->down) {
201 |
202 | ngx_log_error(NGX_LOG_WARN, ngx_cycle->log, 0,
203 | "[disconnect_if_market_down] peer=%V upstream=%V",
204 | &ctx->peer->name, &uscf->host);
205 |
206 | ngx_stream_upstream_rr_peers_unlock(peers);
207 | return NGX_ERROR;
208 | }
209 |
210 | if (ucscf->disconnect_on_exiting
211 | && (ngx_exiting || ngx_quit || ngx_terminate)) {
212 |
213 | ngx_log_error(NGX_LOG_WARN, ngx_cycle->log, 0,
214 | "[disconnect_on_exiting] peer=%V upstream=%V",
215 | &ctx->peer->name, &uscf->host);
216 |
217 | ngx_stream_upstream_rr_peers_unlock(peers);
218 | return NGX_ERROR;
219 | }
220 |
221 | if (ucscf->disconnect_backup &&
222 | ngx_stream_dynamic_upstream_alive_primary(peers, ctx->peer)) {
223 |
224 | ngx_log_error(NGX_LOG_WARN, ngx_cycle->log, 0,
225 | "[disconnect_backup_if_primary_up] peer=%V "
226 | "upstream=%V", &ctx->peer->name, &uscf->host);
227 |
228 | ngx_stream_upstream_rr_peers_unlock(peers);
229 | return NGX_ERROR;
230 | }
231 |
232 | ctx->check_ms = ngx_current_msec;
233 |
234 | skip:
235 |
236 | if (peers)
237 | ngx_stream_upstream_rr_peers_unlock(peers);
238 |
239 | if (ngx_stream_next_filter)
240 | return ngx_stream_next_filter(s, in, from_upstream);
241 |
242 | return NGX_OK;
243 | }
244 |
245 |
246 | extern int
247 | ngx_stream_dynamic_upstream_lua_create_module(lua_State *L);
248 |
249 |
250 | ngx_int_t
251 | ngx_stream_dynamic_upstream_lua_post_conf(ngx_conf_t *cf)
252 | {
253 | #ifndef NO_NGX_STREAM_LUA_MODULE
254 | if (ngx_stream_lua_add_package_preload(cf, "ngx.dynamic_upstream.stream",
255 | ngx_stream_dynamic_upstream_lua_create_module) != NGX_OK)
256 | return NGX_ERROR;
257 | #endif
258 |
259 | ngx_stream_next_filter = ngx_stream_top_filter;
260 | ngx_stream_top_filter = ngx_stream_dynamic_upstream_write_filter;
261 |
262 | return NGX_OK;
263 | }
264 |
265 |
266 | static void *
267 | ngx_stream_dynamic_upstream_lua_create_srv_conf(ngx_conf_t *cf)
268 | {
269 | ngx_stream_dynamic_upstream_lua_srv_conf_t *ucscf;
270 |
271 | ucscf = ngx_palloc(cf->pool,
272 | sizeof(ngx_stream_dynamic_upstream_lua_srv_conf_t));
273 | if (ucscf == NULL) {
274 | return NULL;
275 | }
276 |
277 | ucscf->disconnect_backup = 0;
278 | ucscf->disconnect_down = 0;
279 | ucscf->disconnect_on_exiting = 0;
280 |
281 | return ucscf;
282 | }
283 |
284 |
285 | static char *
286 | ngx_stream_dynamic_upstream_lua_disconnect_backup_if_primary_up(ngx_conf_t *cf,
287 | ngx_command_t *cmd, void *conf)
288 | {
289 | ngx_stream_dynamic_upstream_lua_srv_conf_t *ucscf = conf;
290 |
291 | ucscf->disconnect_backup = 1;
292 |
293 | return NGX_CONF_OK;
294 | }
295 |
296 |
297 | static char *
298 | ngx_stream_dynamic_upstream_lua_disconnect_if_market_down(ngx_conf_t *cf,
299 | ngx_command_t *cmd, void *conf)
300 | {
301 | ngx_stream_dynamic_upstream_lua_srv_conf_t *ucscf = conf;
302 |
303 | ucscf->disconnect_down = 1;
304 |
305 | return NGX_CONF_OK;
306 | }
307 |
308 |
309 | static char *
310 | ngx_stream_dynamic_upstream_lua_disconnect_on_exiting(ngx_conf_t *cf,
311 | ngx_command_t *cmd, void *conf)
312 | {
313 | ngx_stream_dynamic_upstream_lua_srv_conf_t *ucscf = conf;
314 |
315 | ucscf->disconnect_on_exiting = 1;
316 |
317 | return NGX_CONF_OK;
318 | }
319 |
--------------------------------------------------------------------------------
/t/add.t:
--------------------------------------------------------------------------------
1 | use Test::Nginx::Socket;
2 | use Test::Nginx::Socket::Lua::Stream;
3 |
4 | repeat_each(1);
5 |
6 | plan tests => repeat_each() * 2 * blocks();
7 |
8 | run_tests();
9 |
10 | __DATA__
11 |
12 | === TEST 1: add primary peer
13 | --- http_config
14 | upstream backends {
15 | zone shm-backends 128k;
16 | server 127.0.0.1:6001;
17 | }
18 | --- config
19 | location /test {
20 | content_by_lua_block {
21 | local upstream = require "ngx.dynamic_upstream"
22 | local ok, _, err = upstream.add_primary_peer(ngx.var.arg_upstream, ngx.var.arg_peer)
23 | if not ok then
24 | ngx.say(err)
25 | ngx.exit(200)
26 | end
27 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
28 | if not ok then
29 | ngx.say(err)
30 | ngx.exit(200)
31 | end
32 | for _, peer in pairs(peers)
33 | do
34 | ngx.say(peer.name)
35 | end
36 | }
37 | }
38 | --- request
39 | GET /test?upstream=backends&peer=127.0.0.1:6666
40 | --- response_body
41 | 127.0.0.1:6666
42 | 127.0.0.1:6001
43 |
44 |
45 | === TEST 2: add primary server
46 | --- http_config
47 | upstream backends {
48 | zone shm-backends 128k;
49 | dns_update 1s;
50 | server 127.0.0.1:6001;
51 | }
52 | --- config
53 | location /test {
54 | content_by_lua_block {
55 | local upstream = require "ngx.dynamic_upstream"
56 | local ok, _, err = upstream.add_primary_peer(ngx.var.arg_upstream, ngx.var.arg_peer)
57 | if not ok then
58 | ngx.say(err)
59 | ngx.exit(200)
60 | end
61 | ngx.sleep(2)
62 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
63 | if not ok then
64 | ngx.say(err)
65 | ngx.exit(200)
66 | end
67 | for _, peer in pairs(peers)
68 | do
69 | ngx.say(peer.server)
70 | ngx.say(peer.name)
71 | end
72 | }
73 | }
74 | --- request
75 | GET /test?upstream=backends&peer=localhost4:6666
76 | --- response_body_like
77 | localhost4:6666
78 | 127.0.0.1:6666
79 | 127.0.0.1:6001
80 | 127.0.0.1:6001
81 | --- timeout: 3
82 |
83 |
84 | === TEST 3: add backup peer
85 | --- http_config
86 | upstream backends {
87 | zone shm-backends 128k;
88 | server 127.0.0.1:6001;
89 | }
90 | --- config
91 | location /test {
92 | content_by_lua_block {
93 | local upstream = require "ngx.dynamic_upstream"
94 | local ok, _, err = upstream.add_backup_peer(ngx.var.arg_upstream, ngx.var.arg_peer)
95 | if not ok then
96 | ngx.say(err)
97 | ngx.exit(200)
98 | end
99 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
100 | if not ok then
101 | ngx.say(err)
102 | ngx.exit(200)
103 | end
104 | for _, peer in pairs(peers)
105 | do
106 | ngx.say(peer.name)
107 | end
108 | local ok, peers, err = upstream.get_backup_peers(ngx.var.arg_upstream)
109 | if not ok then
110 | ngx.say(err)
111 | ngx.exit(200)
112 | end
113 | for _, peer in pairs(peers)
114 | do
115 | ngx.say(peer.name .. " backup")
116 | end
117 | }
118 | }
119 | --- request
120 | GET /test?upstream=backends&peer=127.0.0.1:6666
121 | --- response_body
122 | 127.0.0.1:6001
123 | 127.0.0.1:6666 backup
124 |
125 |
126 | === TEST 4: add backup server
127 | --- http_config
128 | upstream backends {
129 | zone shm-backends 128k;
130 | dns_update 1s;
131 | server 127.0.0.1:6001;
132 | }
133 | --- config
134 | location /test {
135 | content_by_lua_block {
136 | local upstream = require "ngx.dynamic_upstream"
137 | local ok, _, err = upstream.add_backup_peer(ngx.var.arg_upstream, ngx.var.arg_peer)
138 | if not ok then
139 | ngx.say(err)
140 | ngx.exit(200)
141 | end
142 | ngx.sleep(2)
143 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
144 | if not ok then
145 | ngx.say(err)
146 | ngx.exit(200)
147 | end
148 | for _, peer in pairs(peers)
149 | do
150 | ngx.say(peer.server)
151 | ngx.say(peer.name)
152 | end
153 | local ok, peers, err = upstream.get_backup_peers(ngx.var.arg_upstream)
154 | if not ok then
155 | ngx.say(err)
156 | ngx.exit(200)
157 | end
158 | for _, peer in pairs(peers)
159 | do
160 | ngx.say(peer.server .. " backup")
161 | ngx.say(peer.name .. " backup")
162 | end
163 | }
164 | }
165 | --- request
166 | GET /test?upstream=backends&peer=localhost4:6666
167 | --- response_body
168 | 127.0.0.1:6001
169 | 127.0.0.1:6001
170 | localhost4:6666 backup
171 | 127.0.0.1:6666 backup
172 | --- timeout: 3
173 |
174 |
175 | === TEST 5: add stream primary peer
176 | --- stream_config
177 | upstream backends {
178 | zone shm-backends 128k;
179 | server 127.0.0.1:6001;
180 | }
181 | --- stream_server_config
182 | proxy_pass backends;
183 | --- config
184 | location /test {
185 | content_by_lua_block {
186 | local upstream = require "ngx.dynamic_upstream.stream"
187 | local ok, _, err = upstream.add_primary_peer(ngx.var.arg_upstream, ngx.var.arg_peer)
188 | if not ok then
189 | ngx.say(err)
190 | ngx.exit(200)
191 | end
192 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
193 | if not ok then
194 | ngx.say(err)
195 | ngx.exit(200)
196 | end
197 | for _, peer in pairs(peers)
198 | do
199 | ngx.say(peer.name)
200 | end
201 | }
202 | }
203 | --- request
204 | GET /test?upstream=backends&peer=127.0.0.1:6666
205 | --- response_body
206 | 127.0.0.1:6666
207 | 127.0.0.1:6001
208 |
209 |
210 | === TEST 6: add stream primary server
211 | --- stream_config
212 | upstream backends {
213 | zone shm-backends 128k;
214 | dns_update 1s;
215 | server 127.0.0.1:6001;
216 | }
217 | --- stream_server_config
218 | proxy_pass backends;
219 | --- config
220 | location /test {
221 | content_by_lua_block {
222 | local upstream = require "ngx.dynamic_upstream.stream"
223 | local ok, _, err = upstream.add_primary_peer(ngx.var.arg_upstream, ngx.var.arg_peer)
224 | if not ok then
225 | ngx.say(err)
226 | ngx.exit(200)
227 | end
228 | ngx.sleep(2)
229 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
230 | if not ok then
231 | ngx.say(err)
232 | ngx.exit(200)
233 | end
234 | for _, peer in pairs(peers)
235 | do
236 | ngx.say(peer.server)
237 | ngx.say(peer.name)
238 | end
239 | }
240 | }
241 | --- request
242 | GET /test?upstream=backends&peer=localhost4:6666
243 | --- response_body
244 | localhost4:6666
245 | 127.0.0.1:6666
246 | 127.0.0.1:6001
247 | 127.0.0.1:6001
248 | --- timeout: 3
249 |
250 |
251 | === TEST 7: add stream backup peer
252 | --- stream_config
253 | upstream backends {
254 | zone shm-backends 128k;
255 | server 127.0.0.1:6001;
256 | }
257 | --- stream_server_config
258 | proxy_pass backends;
259 | --- config
260 | location /test {
261 | content_by_lua_block {
262 | local upstream = require "ngx.dynamic_upstream.stream"
263 | local ok, _, err = upstream.add_backup_peer(ngx.var.arg_upstream, ngx.var.arg_peer)
264 | if not ok then
265 | ngx.say(err)
266 | ngx.exit(200)
267 | end
268 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
269 | if not ok then
270 | ngx.say(err)
271 | ngx.exit(200)
272 | end
273 | for _, peer in pairs(peers)
274 | do
275 | ngx.say(peer.name)
276 | end
277 | local ok, peers, err = upstream.get_backup_peers(ngx.var.arg_upstream)
278 | if not ok then
279 | ngx.say(err)
280 | ngx.exit(200)
281 | end
282 | for _, peer in pairs(peers)
283 | do
284 | ngx.say(peer.name .. " backup")
285 | end
286 | }
287 | }
288 | --- request
289 | GET /test?upstream=backends&peer=127.0.0.1:6666
290 | --- response_body
291 | 127.0.0.1:6001
292 | 127.0.0.1:6666 backup
293 |
294 |
295 | === TEST 8: add stream backup server
296 | --- stream_config
297 | upstream backends {
298 | zone shm-backends 128k;
299 | dns_update 1s;
300 | server 127.0.0.1:6001;
301 | }
302 | --- stream_server_config
303 | proxy_pass backends;
304 | --- config
305 | location /test {
306 | content_by_lua_block {
307 | local upstream = require "ngx.dynamic_upstream.stream"
308 | local ok, _, err = upstream.add_backup_peer(ngx.var.arg_upstream, ngx.var.arg_peer)
309 | if not ok then
310 | ngx.say(err)
311 | ngx.exit(200)
312 | end
313 | ngx.sleep(2)
314 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
315 | if not ok then
316 | ngx.say(err)
317 | ngx.exit(200)
318 | end
319 | for _, peer in pairs(peers)
320 | do
321 | ngx.say(peer.server)
322 | ngx.say(peer.name)
323 | end
324 | local ok, peers, err = upstream.get_backup_peers(ngx.var.arg_upstream)
325 | if not ok then
326 | ngx.say(err)
327 | ngx.exit(200)
328 | end
329 | for _, peer in pairs(peers)
330 | do
331 | ngx.say(peer.server .. " backup")
332 | ngx.say(peer.name .. " backup")
333 | end
334 | }
335 | }
336 | --- request
337 | GET /test?upstream=backends&peer=localhost4:6666
338 | --- response_body
339 | 127.0.0.1:6001
340 | 127.0.0.1:6001
341 | localhost4:6666 backup
342 | 127.0.0.1:6666 backup
343 | --- timeout: 3
344 |
345 |
--------------------------------------------------------------------------------
/t/update.t:
--------------------------------------------------------------------------------
1 | use Test::Nginx::Socket;
2 | use Test::Nginx::Socket::Lua::Stream;
3 |
4 | repeat_each(1);
5 |
6 | plan tests => repeat_each() * 2 * blocks();
7 |
8 | run_tests();
9 |
10 | __DATA__
11 |
12 | === TEST 1: update primary peer
13 | --- http_config
14 | upstream backends {
15 | zone shm-backends 128k;
16 | server 127.0.0.1:6001 weight=1 max_fails=2 max_conns=100 fail_timeout=10 down;
17 | server 127.0.0.1:6002 weight=1 max_fails=2 max_conns=100 fail_timeout=10;
18 | server 127.0.0.1:6003 weight=1 max_fails=1 max_conns=200 fail_timeout=10 backup;
19 | }
20 | --- config
21 | location /test {
22 | content_by_lua_block {
23 | local upstream = require "ngx.dynamic_upstream"
24 | local ok, pp, err = upstream.get_primary_peers(ngx.var.arg_upstream)
25 | if not ok then
26 | ngx.say(err)
27 | ngx.exit(500)
28 | end
29 | local ok, bp, err = upstream.get_backup_peers(ngx.var.arg_upstream)
30 | if not ok then
31 | ngx.say(err)
32 | ngx.exit(500)
33 | end
34 | local tointeger = function(b) if b then return 1 else return 0 end end
35 | for _, peer in pairs(pp)
36 | do
37 | ngx.say(peer.name .. ";" .. peer.weight .. ";" .. peer.max_fails .. ";" .. peer.max_conns .. ";" .. peer.fail_timeout .. ";" .. tointeger(peer.down))
38 | end
39 | for _, peer in pairs(bp)
40 | do
41 | ngx.say(peer.name .. ";" .. peer.weight .. ";" .. peer.max_fails .. ";" .. peer.max_conns .. ";" .. peer.fail_timeout .. ";" .. tointeger (peer.down) .. ";backup")
42 | end
43 | local ok, err = upstream.update_peer(ngx.var.arg_upstream, ngx.var.arg_peer, {
44 | max_fails=ngx.var.arg_max_fails,
45 | max_conns=ngx.var.arg_max_conns,
46 | fail_timeout=ngx.var.arg_fail_timeout,
47 | weight=ngx.var.arg_weight,
48 | down=ngx.var.arg_down
49 | })
50 | local ok, pp, err = upstream.get_primary_peers(ngx.var.arg_upstream)
51 | if not ok then
52 | ngx.say(err)
53 | ngx.exit(500)
54 | end
55 | for _, peer in pairs(pp)
56 | do
57 | ngx.say(peer.name .. ";" .. peer.weight .. ";" .. peer.max_fails .. ";" .. peer.max_conns .. ";" .. peer.fail_timeout .. ";" .. tointeger(peer.down))
58 | end
59 | }
60 | }
61 | --- request
62 | GET /test?upstream=backends&peer=127.0.0.1:6002&max_fails=99&max_conns=88&fail_timeout=77&weight=66&down=1
63 | --- response_body
64 | 127.0.0.1:6001;1;2;100;10;1
65 | 127.0.0.1:6002;1;2;100;10;0
66 | 127.0.0.1:6003;1;1;200;10;0;backup
67 | 127.0.0.1:6001;1;2;100;10;1
68 | 127.0.0.1:6002;66;99;88;77;1
69 |
70 |
71 | === TEST 2: update backup peer
72 | --- http_config
73 | upstream backends {
74 | zone shm-backends 128k;
75 | server 127.0.0.1:6001 weight=1 max_fails=2 max_conns=100 fail_timeout=10 down;
76 | server 127.0.0.1:6002 weight=1 max_fails=2 max_conns=100 fail_timeout=10;
77 | server 127.0.0.1:6003 weight=1 max_fails=1 max_conns=200 fail_timeout=10 backup;
78 | }
79 | --- config
80 | location /test {
81 | content_by_lua_block {
82 | local upstream = require "ngx.dynamic_upstream"
83 | local ok, pp, err = upstream.get_primary_peers(ngx.var.arg_upstream)
84 | if not ok then
85 | ngx.say(err)
86 | ngx.exit(500)
87 | end
88 | local ok, bp, err = upstream.get_backup_peers(ngx.var.arg_upstream)
89 | if not ok then
90 | ngx.say(err)
91 | ngx.exit(500)
92 | end
93 | local tointeger = function(b) if b then return 1 else return 0 end end
94 | for _, peer in pairs(pp)
95 | do
96 | ngx.say(peer.name .. ";" .. peer.weight .. ";" .. peer.max_fails .. ";" .. peer.max_conns .. ";" .. peer.fail_timeout .. ";" .. tointeger(peer.down))
97 | end
98 | for _, peer in pairs(bp)
99 | do
100 | ngx.say(peer.name .. ";" .. peer.weight .. ";" .. peer.max_fails .. ";" .. peer.max_conns .. ";" .. peer.fail_timeout .. ";" .. tointeger (peer.down) .. ";backup")
101 | end
102 | local ok, err = upstream.update_peer(ngx.var.arg_upstream, ngx.var.arg_peer, {
103 | max_fails=ngx.var.arg_max_fails,
104 | max_conns=ngx.var.arg_max_conns,
105 | fail_timeout=ngx.var.arg_fail_timeout,
106 | weight=ngx.var.arg_weight,
107 | down=ngx.var.arg_down
108 | })
109 | local ok, pp, err = upstream.get_backup_peers(ngx.var.arg_upstream)
110 | if not ok then
111 | ngx.say(err)
112 | ngx.exit(500)
113 | end
114 | for _, peer in pairs(pp)
115 | do
116 | ngx.say(peer.name .. ";" .. peer.weight .. ";" .. peer.max_fails .. ";" .. peer.max_conns .. ";" .. peer.fail_timeout .. ";" .. tointeger(peer.down) .. ";backup")
117 | end
118 | }
119 | }
120 | --- request
121 | GET /test?upstream=backends&peer=127.0.0.1:6003&max_fails=99&max_conns=88&fail_timeout=77&weight=66&down=1
122 | --- response_body
123 | 127.0.0.1:6001;1;2;100;10;1
124 | 127.0.0.1:6002;1;2;100;10;0
125 | 127.0.0.1:6003;1;1;200;10;0;backup
126 | 127.0.0.1:6003;66;99;88;77;1;backup
127 |
128 |
129 | === TEST 3: update stream primary peer
130 | --- stream_config
131 | upstream backends {
132 | zone shm-backends 128k;
133 | server 127.0.0.1:6001 weight=1 max_fails=2 max_conns=100 fail_timeout=10 down;
134 | server 127.0.0.1:6002 weight=1 max_fails=2 max_conns=100 fail_timeout=10;
135 | server 127.0.0.1:6003 weight=1 max_fails=1 max_conns=200 fail_timeout=10 backup;
136 | }
137 | --- stream_server_config
138 | proxy_pass backends;
139 | --- config
140 | location /test {
141 | content_by_lua_block {
142 | local upstream = require "ngx.dynamic_upstream.stream"
143 | local ok, pp, err = upstream.get_primary_peers(ngx.var.arg_upstream)
144 | if not ok then
145 | ngx.say(err)
146 | ngx.exit(500)
147 | end
148 | local ok, bp, err = upstream.get_backup_peers(ngx.var.arg_upstream)
149 | if not ok then
150 | ngx.say(err)
151 | ngx.exit(500)
152 | end
153 | local tointeger = function(b) if b then return 1 else return 0 end end
154 | for _, peer in pairs(pp)
155 | do
156 | ngx.say(peer.name .. ";" .. peer.weight .. ";" .. peer.max_fails .. ";" .. peer.max_conns .. ";" .. peer.fail_timeout .. ";" .. tointeger(peer.down))
157 | end
158 | for _, peer in pairs(bp)
159 | do
160 | ngx.say(peer.name .. ";" .. peer.weight .. ";" .. peer.max_fails .. ";" .. peer.max_conns .. ";" .. peer.fail_timeout .. ";" .. tointeger (peer.down) .. ";backup")
161 | end
162 | local ok, err = upstream.update_peer(ngx.var.arg_upstream, ngx.var.arg_peer, {
163 | max_fails=ngx.var.arg_max_fails,
164 | max_conns=ngx.var.arg_max_conns,
165 | fail_timeout=ngx.var.arg_fail_timeout,
166 | weight=ngx.var.arg_weight,
167 | down=ngx.var.arg_down
168 | })
169 | local ok, pp, err = upstream.get_primary_peers(ngx.var.arg_upstream)
170 | if not ok then
171 | ngx.say(err)
172 | ngx.exit(500)
173 | end
174 | for _, peer in pairs(pp)
175 | do
176 | ngx.say(peer.name .. ";" .. peer.weight .. ";" .. peer.max_fails .. ";" .. peer.max_conns .. ";" .. peer.fail_timeout .. ";" .. tointeger(peer.down))
177 | end
178 | }
179 | }
180 | --- request
181 | GET /test?upstream=backends&peer=127.0.0.1:6002&max_fails=99&max_conns=88&fail_timeout=77&weight=66&down=1
182 | --- response_body
183 | 127.0.0.1:6001;1;2;100;10;1
184 | 127.0.0.1:6002;1;2;100;10;0
185 | 127.0.0.1:6003;1;1;200;10;0;backup
186 | 127.0.0.1:6001;1;2;100;10;1
187 | 127.0.0.1:6002;66;99;88;77;1
188 |
189 |
190 | === TEST 4: update backup peer
191 | --- stream_config
192 | upstream backends {
193 | zone shm-backends 128k;
194 | server 127.0.0.1:6001 weight=1 max_fails=2 max_conns=100 fail_timeout=10 down;
195 | server 127.0.0.1:6002 weight=1 max_fails=2 max_conns=100 fail_timeout=10;
196 | server 127.0.0.1:6003 weight=1 max_fails=1 max_conns=200 fail_timeout=10 backup;
197 | }
198 | --- stream_server_config
199 | proxy_pass backends;
200 | --- config
201 | location /test {
202 | content_by_lua_block {
203 | local upstream = require "ngx.dynamic_upstream.stream"
204 | local ok, pp, err = upstream.get_primary_peers(ngx.var.arg_upstream)
205 | if not ok then
206 | ngx.say(err)
207 | ngx.exit(500)
208 | end
209 | local ok, bp, err = upstream.get_backup_peers(ngx.var.arg_upstream)
210 | if not ok then
211 | ngx.say(err)
212 | ngx.exit(500)
213 | end
214 | local tointeger = function(b) if b then return 1 else return 0 end end
215 | for _, peer in pairs(pp)
216 | do
217 | ngx.say(peer.name .. ";" .. peer.weight .. ";" .. peer.max_fails .. ";" .. peer.max_conns .. ";" .. peer.fail_timeout .. ";" .. tointeger(peer.down))
218 | end
219 | for _, peer in pairs(bp)
220 | do
221 | ngx.say(peer.name .. ";" .. peer.weight .. ";" .. peer.max_fails .. ";" .. peer.max_conns .. ";" .. peer.fail_timeout .. ";" .. tointeger (peer.down) .. ";backup")
222 | end
223 | local ok, err = upstream.update_peer(ngx.var.arg_upstream, ngx.var.arg_peer, {
224 | max_fails=ngx.var.arg_max_fails,
225 | max_conns=ngx.var.arg_max_conns,
226 | fail_timeout=ngx.var.arg_fail_timeout,
227 | weight=ngx.var.arg_weight,
228 | down=ngx.var.arg_down
229 | })
230 | local ok, pp, err = upstream.get_backup_peers(ngx.var.arg_upstream)
231 | if not ok then
232 | ngx.say(err)
233 | ngx.exit(500)
234 | end
235 | for _, peer in pairs(pp)
236 | do
237 | ngx.say(peer.name .. ";" .. peer.weight .. ";" .. peer.max_fails .. ";" .. peer.max_conns .. ";" .. peer.fail_timeout .. ";" .. tointeger(peer.down) .. ";backup")
238 | end
239 | }
240 | }
241 | --- request
242 | GET /test?upstream=backends&peer=127.0.0.1:6003&max_fails=99&max_conns=88&fail_timeout=77&weight=66&down=1
243 | --- response_body
244 | 127.0.0.1:6001;1;2;100;10;1
245 | 127.0.0.1:6002;1;2;100;10;0
246 | 127.0.0.1:6003;1;1;200;10;0;backup
247 | 127.0.0.1:6003;66;99;88;77;1;backup
248 |
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | Name
2 | ====
3 |
4 | dynamic-upstream-module-lua - Lua bindings for dynamic-upstream-module
5 |
6 | This module supports http and stream upstream types.
7 |
8 | Healthcheck directives and lua api removed. Use [ngx_dynamic_healthcheck](https://github.com/ZigzagAK/ngx_dynamic_healthcheck) module.
9 | Upstreams without [zone](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#zone) directive are unsupported.
10 |
11 | Build status
12 | ======
13 | [](https://travis-ci.org/ZigzagAK/ngx_dynamic_upstream_lua)
14 |
15 | Table of Contents
16 | =================
17 |
18 | * [Name](#name)
19 | * [Status](#status)
20 | * [Synopsis](#synopsis)
21 | * [Description](#description)
22 | * [Install](#install)
23 | * [Configuration directives](#configuration-directives)
24 | * [disconnect_backup_if_primary_up](#disconnect_backup_if_primary_up)
25 | * [disconnect_if_market_down](#disconnect_if_market_down)
26 | * [disconnect_on_exiting](#disconnect_on_exiting)
27 | * [Packages](#packages)
28 | * [Methods](#methods)
29 | * [get_upstreams](#get_upstreams)
30 | * [get_peers](#get_peers)
31 | * [get_primary_peers](#get_primary_peers)
32 | * [get_backup_peers](#get_backup_peers)
33 | * [set_peer_down](#set_peer_down)
34 | * [set_peer_up](#set_peer_up)
35 | * [add_primary_peer](#add_primary_peer)
36 | * [add_backup_peer](#add_backup_peer)
37 | * [remove_peer](#remove_peer)
38 | * [update_peer](#update_peer)
39 | * [current_upstream](#current_upstream)
40 |
41 | Dependencies
42 | ============
43 |
44 | This module has several dependencies:
45 | * [dynamic-upstream-module](https://github.com/ZigzagAK/ngx_dynamic_upstream)
46 |
47 | Status
48 | ======
49 |
50 | This library is production ready.
51 |
52 | Description
53 | ===========
54 |
55 | This module provides Lua bindings to manage content of nginx upstreams.
56 |
57 | [Back to TOC](#table-of-contents)
58 |
59 | Install
60 | =======
61 |
62 | Build nginx.
63 | All dependencies are downloaded automaticaly.
64 |
65 | ```
66 | git clone git@github.com:ZigzagAK/ngx_dynamic_upstream_lua.git
67 | cd ngx_dynamic_upstream_lua
68 | ./build.sh
69 | ```
70 |
71 | Archive will be placed in the `install` folder after successful build.
72 |
73 | [Back to TOC](#table-of-contents)
74 |
75 | Configuration directives
76 | ========================
77 |
78 | disconnect_backup_if_primary_up
79 | -------------------------------
80 | * **syntax**: `disconnect_backup_if_primary_up`
81 | * **default**: `none`
82 | * **context**: `stream/upstream`
83 |
84 | Disconnect from backup peers when primary peers becomes available.
85 |
86 | disconnect_if_market_down
87 | -------------------------
88 | * **syntax**: `disconnect_if_market_down`
89 | * **default**: `none`
90 | * **context**: `stream/upstream`
91 |
92 | Disconnect peers when server is market down by healthcheck.
93 |
94 | disconnect_on_exiting
95 | ---------------------
96 | * **syntax**: `disconnect_on_exiting`
97 | * **default**: `none`
98 | * **context**: `stream/upstream`
99 |
100 | Disconnect from upstream when nginx reloaded.
101 |
102 | [Back to TOC](#table-of-contents)
103 |
104 | Synopsis
105 | ========
106 |
107 | ```nginx
108 | http {
109 | lua_package_path "/path/to/lua-ngx-dynamic-upstream-lua/lib/?.lua;;";
110 |
111 | upstream backend {
112 | zone backend 1m;
113 | server 127.0.0.1:9090;
114 | }
115 |
116 | server {
117 | listen 8888;
118 |
119 | default_type text/plain;
120 |
121 | # curl "http://localhost:8888/backend/add?peer=127.0.0.1:9091&weight=1&max_fails=2&fail_timeout=30&max_conns=100"
122 | # curl "http://localhost:8888/backend/add?peer=127.0.0.1:9092&backup=1&weight=1&max_fails=2&fail_timeout=30&max_conns=100"
123 | location ~* ^/(.+)/add {
124 | set $upstream $1;
125 | content_by_lua_block {
126 | local upstream = require "ngx.dynamic_upstream"
127 |
128 | local peer = ngx.var.arg_peer
129 | local u = ngx.var.upstream
130 |
131 | local ok, err
132 | if ngx.var.arg_backup and ngx.var.arg_backup == 1 then
133 | ok, _, err = upstream.add_backup_peer(u, peer)
134 | else
135 | ok, _, err = upstream.add_primary_peer(u, peer)
136 | end
137 |
138 | if not ok then
139 | say("Failed to add peer " .. peer .. ": ", err)
140 | return
141 | end
142 |
143 | local peer_args = {
144 | weight = ngx.var.arg_weight or 1,
145 | max_fails = ngx.var.arg_max_fails or 2,
146 | fail_timeout = ngx.var.arg_fail_timeout or 5,
147 | max_conns = ngx.var.arg_max_conns or 1,
148 | down = 1
149 | }
150 |
151 | ok, _, err = upstream.update_peer(u, peer, peer_args)
152 | if not ok then
153 | ngx.say("Failed to update peer " .. peer .. " params, error: ", err)
154 | return
155 | end
156 |
157 | ngx.say("Added " .. peer .. " to " .. u .. " upstream")
158 | }
159 | }
160 |
161 | # remove peer
162 | # curl "http://localhost:8888/backend/remove?peer=127.0.0.1:9091"
163 | location ~* ^/(.+)/remove {
164 | set $upstream $1;
165 | content_by_lua_block {
166 | local upstream = require "ngx.dynamic_upstream"
167 |
168 | local peer = ngx.var.arg_peer
169 | local u = ngx.var.upstream
170 |
171 | local ok, _, err = upstream.remove_peer(u, peer)
172 | if not ok then
173 | ngx.say("Failed to remove peer " .. peer .. ": ", err)
174 | return
175 | end
176 |
177 | ngx.say("Removed " .. peer .. " from " .. u .. " upstream")
178 | }
179 | }
180 |
181 | # status page for all the peers:
182 | location = /status {
183 | content_by_lua_block {
184 | local upstream = require "ngx.dynamic_upstream"
185 |
186 | local ok, upstreams, err = upstream.get_upstreams()
187 | if not ok then
188 | ngx.say(err)
189 | ngx.exit(200)
190 | end
191 |
192 | local get_peers = function(u)
193 | local ok, peers, err = upstream.get_primary_peers(u)
194 | if not ok then
195 | ngx.say(err)
196 | ngx.exit(200)
197 | end
198 |
199 | local t = {}
200 |
201 | for _, peer in pairs(peers)
202 | do
203 | table.insert(t, peer)
204 | end
205 |
206 | ok, peers, err = upstream.get_backup_peers(u)
207 | if not ok then
208 | ngx.say(err)
209 | ngx.exit(200)
210 | end
211 |
212 | for _, peer in pairs(peers)
213 | do
214 | table.insert(t, peer)
215 | end
216 |
217 | return t
218 | end
219 |
220 | local tointeger = function (b) if b then return 1 else return 0 end end
221 |
222 | for _, u in pairs(upstreams)
223 | do
224 | ngx.say(u)
225 |
226 | for _, peer in pairs(get_peers(u))
227 | do
228 | local status = "up"
229 | if peer.down ~= nil then
230 | status = "down"
231 | end
232 |
233 | ngx.say(" server " .. peer.name .. " backup=" .. tointeger(peer.backup) .. " weight=" .. peer.weight .. " max_conns=" .. peer.max_conns .. " max_fails=" .. peer.max_fails .. " fail_timeout=" .. peer.fail_timeout .. " status=" .. status)
234 | end
235 | end
236 | }
237 | }
238 | }
239 | }
240 | ```
241 | [Back to TOC](#table-of-contents)
242 |
243 | Packages
244 | =======
245 |
246 | Package `ngx.dynamic_upstream` is used for manipulation http upstreams.
247 | Package `ngx.dynamic_upstream.stream` is used for manipulation stream upstreams.
248 |
249 | Functionality of both packages are same.
250 |
251 |
252 | Methods
253 | =======
254 |
255 | get_upstreams
256 | -------------
257 | **syntax:** `ok, upstreams, error = dynamic_upstream.get_upstreams()`
258 |
259 | **context:** **_by_lua**
260 |
261 | Get table of upstreams.
262 |
263 | Returns true and lua table on success, or false and a string describing an error otherwise.
264 |
265 |
266 | get_peers
267 | -------------
268 | **syntax:** `ok, servers, error = dynamic_upstream.get_peers(upstream)`
269 |
270 | **context:** **_by_lua**
271 |
272 | Get table of servers in the `upstream`.
273 |
274 | Returns true and lua table on success, or false and a string describing an error otherwise.
275 |
276 |
277 | get_primary_peers
278 | -------------
279 | **syntax:** `ok, peers, error = dynamic_upstream.get_primary_peers(upstream)`
280 |
281 | **context:** **_by_lua**
282 |
283 | Get table of primary peers in the `upstream`.
284 |
285 | Returns true and lua table on success, or false and a string describing an error otherwise.
286 |
287 |
288 | get_backup_peers
289 | -------------
290 | **syntax:** `ok, peers, error = dynamic_upstream.get_backup_peers(upstream)`
291 |
292 | **context:** **_by_lua**
293 |
294 | Get table of backup peers in the `upstream`.
295 |
296 | Returns true and lua table on success, or false and a string describing an error otherwise.
297 |
298 |
299 | set_peer_down
300 | -------------
301 | **syntax:** `ok, _, error = dynamic_upstream.set_peer_down(upstream, peer)`
302 |
303 | **context:** **_by_lua**
304 |
305 | Go `peer` of the `upstream` to DOWN state.
306 |
307 | Returns true on success, or false and a string describing an error otherwise.
308 |
309 |
310 | set_peer_up
311 | -------------
312 | **syntax:** `ok, _, error = dynamic_upstream.set_peer_up(upstream, peer)`
313 |
314 | **context:** **_by_lua**
315 |
316 | Go `peer` of the `upstream` to UP state.
317 |
318 | Returns true on success, or false and a string describing an error otherwise.
319 |
320 |
321 | add_primary_peer
322 | -------------
323 | **syntax:** `ok, _, error = dynamic_upstream.add_primary_peer(upstream, peer)`
324 |
325 | **context:** **_by_lua**
326 |
327 | Add `peer` to the `upstream` as primary.
328 |
329 | Returns true on success, or false and a string describing an error otherwise.
330 |
331 |
332 | add_backup_peer
333 | -------------
334 | **syntax:** `ok, _, error = dynamic_upstream.add_backup_peer(upstream, peer)`
335 |
336 | **context:** **_by_lua**
337 |
338 | Add `peer` to the `upstream` as backup.
339 |
340 | Returns true on success, or false and a string describing an error otherwise.
341 |
342 |
343 | remove_peer
344 | -------------
345 | **syntax:** `ok, _, error = dynamic_upstream.remove_peer(upstream, peer)`
346 |
347 | **context:** **_by_lua**
348 |
349 | Remove `peer` from the `upstream`.
350 |
351 | Returns true on success, or false and a string describing an error otherwise.
352 |
353 |
354 | update_peer
355 | -----------
356 | **syntax:** `ok, _, error = dynamic_upstream.update_peer(upstream, peer, {
357 | weight = N,
358 | max_fails = N,
359 | fail_timeout = N (seconds),
360 | max_conns = N,
361 | down = 0/1
362 | })`
363 |
364 | **context:** **_by_lua**
365 |
366 | Update `peer` attributes.
367 |
368 | Returns true on success, or false and a string describing an error otherwise.
369 |
370 |
371 | current_upstream
372 | ----------------
373 | **syntax:** `ok, _, error = dynamic_upstream.current_upstream()`
374 |
375 | **context:** **_by_lua**
376 |
377 | Returns true and current upstream name on success, or false and a string describing an error otherwise.
378 |
379 | [Back to TOC](#table-of-contents)
--------------------------------------------------------------------------------
/t/remove.t:
--------------------------------------------------------------------------------
1 | use Test::Nginx::Socket;
2 | use Test::Nginx::Socket::Lua::Stream;
3 |
4 | repeat_each(1);
5 |
6 | plan tests => repeat_each() * 2 * blocks();
7 |
8 | run_tests();
9 |
10 | __DATA__
11 |
12 | === TEST 1: remove primary peer
13 | --- http_config
14 | upstream backends {
15 | zone shm-backends 128k;
16 | server 127.0.0.1:6001;
17 | server 127.0.0.1:6002;
18 | }
19 | --- config
20 | location /test {
21 | content_by_lua_block {
22 | local upstream = require "ngx.dynamic_upstream"
23 | local ok, _, err = upstream.remove_peer(ngx.var.arg_upstream, ngx.var.arg_peer)
24 | if not ok then
25 | ngx.say(err)
26 | ngx.exit(200)
27 | end
28 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
29 | if not ok then
30 | ngx.say(err)
31 | ngx.exit(200)
32 | end
33 | for _, peer in pairs(peers)
34 | do
35 | ngx.say(peer.name)
36 | end
37 | }
38 | }
39 | --- request
40 | GET /test?upstream=backends&peer=127.0.0.1:6002
41 | --- response_body_like
42 | 127.0.0.1:6001
43 |
44 |
45 | === TEST 2: remove primary server
46 | --- http_config
47 | upstream backends {
48 | zone shm-backends 128k;
49 | server 127.0.0.1:6001;
50 | server localhost4:6002;
51 | }
52 | --- config
53 | location /test {
54 | content_by_lua_block {
55 | local upstream = require "ngx.dynamic_upstream"
56 | local ok, _, err = upstream.remove_peer(ngx.var.arg_upstream, ngx.var.arg_peer)
57 | if not ok then
58 | ngx.say(err)
59 | ngx.exit(200)
60 | end
61 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
62 | if not ok then
63 | ngx.say(err)
64 | ngx.exit(200)
65 | end
66 | for _, peer in pairs(peers)
67 | do
68 | ngx.say(peer.name)
69 | end
70 | }
71 | }
72 | --- request
73 | GET /test?upstream=backends&peer=localhost4:6002
74 | --- response_body_like
75 | 127.0.0.1:6001
76 |
77 |
78 | === TEST 3: remove backup peer
79 | --- http_config
80 | upstream backends {
81 | zone shm-backends 128k;
82 | server 127.0.0.1:6001;
83 | server 127.0.0.1:6002 backup;
84 | server 127.0.0.1:6003 backup;
85 | }
86 | --- config
87 | location /test {
88 | content_by_lua_block {
89 | local upstream = require "ngx.dynamic_upstream"
90 | local ok, _, err = upstream.remove_peer(ngx.var.arg_upstream, ngx.var.arg_peer)
91 | if not ok then
92 | ngx.say(err)
93 | ngx.exit(200)
94 | end
95 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
96 | if not ok then
97 | ngx.say(err)
98 | ngx.exit(200)
99 | end
100 | for _, peer in pairs(peers)
101 | do
102 | ngx.say(peer.name)
103 | end
104 | local ok, peers, err = upstream.get_backup_peers(ngx.var.arg_upstream)
105 | if not ok then
106 | ngx.say(err)
107 | ngx.exit(200)
108 | end
109 | for _, peer in pairs(peers)
110 | do
111 | ngx.say(peer.name .. " backup")
112 | end
113 | }
114 | }
115 | --- request
116 | GET /test?upstream=backends&peer=127.0.0.1:6002
117 | --- response_body_like
118 | 127.0.0.1:6001
119 | 127.0.0.1:6003 backup
120 |
121 |
122 | === TEST 4: remove backup server
123 | --- http_config
124 | upstream backends {
125 | zone shm-backends 128k;
126 | server 127.0.0.1:6001;
127 | server localhost4:6002 backup;
128 | server 127.0.0.1:6003 backup;
129 | }
130 | --- config
131 | location /test {
132 | content_by_lua_block {
133 | local upstream = require "ngx.dynamic_upstream"
134 | local ok, _, err = upstream.remove_peer(ngx.var.arg_upstream, ngx.var.arg_peer)
135 | if not ok then
136 | ngx.say(err)
137 | ngx.exit(200)
138 | end
139 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
140 | if not ok then
141 | ngx.say(err)
142 | ngx.exit(200)
143 | end
144 | for _, peer in pairs(peers)
145 | do
146 | ngx.say(peer.name)
147 | end
148 | local ok, peers, err = upstream.get_backup_peers(ngx.var.arg_upstream)
149 | if not ok then
150 | ngx.say(err)
151 | ngx.exit(200)
152 | end
153 | for _, peer in pairs(peers)
154 | do
155 | ngx.say(peer.name .. " backup")
156 | end
157 | }
158 | }
159 | --- request
160 | GET /test?upstream=backends&peer=localhost4:6002
161 | --- response_body_like
162 | 127.0.0.1:6001
163 | 127.0.0.1:6003 backup
164 |
165 |
166 | === TEST 5: remove all backup peers
167 | --- http_config
168 | upstream backends {
169 | zone shm-backends 128k;
170 | server 127.0.0.1:6001;
171 | server 127.0.0.1:6002 backup;
172 | server 127.0.0.1:6003 backup;
173 | server 127.0.0.1:6004 backup;
174 | }
175 | --- config
176 | location /test {
177 | content_by_lua_block {
178 | local upstream = require "ngx.dynamic_upstream"
179 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
180 | if not ok then
181 | ngx.say(err)
182 | ngx.exit(200)
183 | end
184 | for _, peer in pairs(peers)
185 | do
186 | ngx.say(peer.name)
187 | end
188 | local ok, peers, err = upstream.get_backup_peers(ngx.var.arg_upstream)
189 | if not ok then
190 | ngx.say(err)
191 | ngx.exit(200)
192 | end
193 | for _, peer in pairs(peers)
194 | do
195 | ngx.say(peer.name .. " backup")
196 | local ok, _, err = upstream.remove_peer(ngx.var.arg_upstream, peer.name)
197 | if not ok then
198 | ngx.say(err)
199 | ngx.exit(200)
200 | end
201 | ngx.say("removed " .. peer.name)
202 | end
203 | local ok, peers, err = upstream.get_backup_peers(ngx.var.arg_upstream)
204 | if not ok then
205 | ngx.say(err)
206 | ngx.exit(200)
207 | end
208 | for _, peer in pairs(peers)
209 | do
210 | ngx.say(peer.name .. " backup")
211 | end
212 | }
213 | }
214 | --- request
215 | GET /test?upstream=backends
216 | --- response_body_like
217 | 127.0.0.1:6001
218 | 127.0.0.1:6002 backup
219 | removed 127.0.0.1:6002
220 | 127.0.0.1:6003 backup
221 | removed 127.0.0.1:6003
222 | 127.0.0.1:6004 backup
223 | removed 127.0.0.1:6004
224 |
225 |
226 | === TEST 6: remove stream primary peer
227 | --- stream_config
228 | upstream backends {
229 | zone shm-backends 128k;
230 | server 127.0.0.1:6001;
231 | server 127.0.0.1:6002;
232 | }
233 | --- stream_server_config
234 | proxy_pass backends;
235 | --- config
236 | location /test {
237 | content_by_lua_block {
238 | local upstream = require "ngx.dynamic_upstream.stream"
239 | local ok, _, err = upstream.remove_peer(ngx.var.arg_upstream, ngx.var.arg_peer)
240 | if not ok then
241 | ngx.say(err)
242 | ngx.exit(200)
243 | end
244 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
245 | if not ok then
246 | ngx.say(err)
247 | ngx.exit(200)
248 | end
249 | for _, peer in pairs(peers)
250 | do
251 | ngx.say(peer.name)
252 | end
253 | }
254 | }
255 | --- request
256 | GET /test?upstream=backends&peer=127.0.0.1:6002
257 | --- response_body_like
258 | 127.0.0.1:6001
259 |
260 |
261 | === TEST 7: remove stream primary server
262 | --- stream_config
263 | upstream backends {
264 | zone shm-backends 128k;
265 | server 127.0.0.1:6001;
266 | server localhost4:6002;
267 | }
268 | --- stream_server_config
269 | proxy_pass backends;
270 | --- config
271 | location /test {
272 | content_by_lua_block {
273 | local upstream = require "ngx.dynamic_upstream.stream"
274 | local ok, _, err = upstream.remove_peer(ngx.var.arg_upstream, ngx.var.arg_peer)
275 | if not ok then
276 | ngx.say(err)
277 | ngx.exit(200)
278 | end
279 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
280 | if not ok then
281 | ngx.say(err)
282 | ngx.exit(200)
283 | end
284 | for _, peer in pairs(peers)
285 | do
286 | ngx.say(peer.name)
287 | end
288 | }
289 | }
290 | --- request
291 | GET /test?upstream=backends&peer=localhost4:6002
292 | --- response_body_like
293 | 127.0.0.1:6001
294 |
295 |
296 | === TEST 8: remove backup peer
297 | --- stream_config
298 | upstream backends {
299 | zone shm-backends 128k;
300 | server 127.0.0.1:6001;
301 | server 127.0.0.1:6002 backup;
302 | server 127.0.0.1:6003 backup;
303 | }
304 | --- stream_server_config
305 | proxy_pass backends;
306 | --- config
307 | location /test {
308 | content_by_lua_block {
309 | local upstream = require "ngx.dynamic_upstream.stream"
310 | local ok, _, err = upstream.remove_peer(ngx.var.arg_upstream, ngx.var.arg_peer)
311 | if not ok then
312 | ngx.say(err)
313 | ngx.exit(200)
314 | end
315 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
316 | if not ok then
317 | ngx.say(err)
318 | ngx.exit(200)
319 | end
320 | for _, peer in pairs(peers)
321 | do
322 | ngx.say(peer.name)
323 | end
324 | local ok, peers, err = upstream.get_backup_peers(ngx.var.arg_upstream)
325 | if not ok then
326 | ngx.say(err)
327 | ngx.exit(200)
328 | end
329 | for _, peer in pairs(peers)
330 | do
331 | ngx.say(peer.name .. " backup")
332 | end
333 | }
334 | }
335 | --- request
336 | GET /test?upstream=backends&peer=127.0.0.1:6002
337 | --- response_body_like
338 | 127.0.0.1:6001
339 | 127.0.0.1:6003 backup
340 |
341 |
342 | === TEST 9: remove backup server
343 | --- stream_config
344 | upstream backends {
345 | zone shm-backends 128k;
346 | server 127.0.0.1:6001;
347 | server localhost4:6002 backup;
348 | server 127.0.0.1:6003 backup;
349 | }
350 | --- stream_server_config
351 | proxy_pass backends;
352 | --- config
353 | location /test {
354 | content_by_lua_block {
355 | local upstream = require "ngx.dynamic_upstream.stream"
356 | local ok, _, err = upstream.remove_peer(ngx.var.arg_upstream, ngx.var.arg_peer)
357 | if not ok then
358 | ngx.say(err)
359 | ngx.exit(200)
360 | end
361 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
362 | if not ok then
363 | ngx.say(err)
364 | ngx.exit(200)
365 | end
366 | for _, peer in pairs(peers)
367 | do
368 | ngx.say(peer.name)
369 | end
370 | local ok, peers, err = upstream.get_backup_peers(ngx.var.arg_upstream)
371 | if not ok then
372 | ngx.say(err)
373 | ngx.exit(200)
374 | end
375 | for _, peer in pairs(peers)
376 | do
377 | ngx.say(peer.name .. " backup")
378 | end
379 | }
380 | }
381 | --- request
382 | GET /test?upstream=backends&peer=localhost4:6002
383 | --- response_body_like
384 | 127.0.0.1:6001
385 | 127.0.0.1:6003 backup
386 |
387 |
388 | === TEST 10: remove all backup peers
389 | --- stream_config
390 | upstream backends {
391 | zone shm-backends 128k;
392 | server 127.0.0.1:6001;
393 | server 127.0.0.1:6002 backup;
394 | server 127.0.0.1:6003 backup;
395 | server 127.0.0.1:6004 backup;
396 | }
397 | --- stream_server_config
398 | proxy_pass backends;
399 | --- config
400 | location /test {
401 | content_by_lua_block {
402 | local upstream = require "ngx.dynamic_upstream.stream"
403 | local ok, peers, err = upstream.get_primary_peers(ngx.var.arg_upstream)
404 | if not ok then
405 | ngx.say(err)
406 | ngx.exit(200)
407 | end
408 | for _, peer in pairs(peers)
409 | do
410 | ngx.say(peer.name)
411 | end
412 | local ok, peers, err = upstream.get_backup_peers(ngx.var.arg_upstream)
413 | if not ok then
414 | ngx.say(err)
415 | ngx.exit(200)
416 | end
417 | for _, peer in pairs(peers)
418 | do
419 | ngx.say(peer.name .. " backup")
420 | local ok, _, err = upstream.remove_peer(ngx.var.arg_upstream, peer.name)
421 | if not ok then
422 | ngx.say(err)
423 | ngx.exit(200)
424 | end
425 | ngx.say("removed " .. peer.name)
426 | end
427 | local ok, peers, err = upstream.get_backup_peers(ngx.var.arg_upstream)
428 | if not ok then
429 | ngx.say(err)
430 | ngx.exit(200)
431 | end
432 | for _, peer in pairs(peers)
433 | do
434 | ngx.say(peer.name .. " backup")
435 | end
436 | }
437 | }
438 | --- request
439 | GET /test?upstream=backends
440 | --- response_body_like
441 | 127.0.0.1:6001
442 | 127.0.0.1:6002 backup
443 | removed 127.0.0.1:6002
444 | 127.0.0.1:6003 backup
445 | removed 127.0.0.1:6003
446 | 127.0.0.1:6004 backup
447 | removed 127.0.0.1:6004
448 |
--------------------------------------------------------------------------------
/src/ngx_dynamic_upstream_stream_lua.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include
6 |
7 | #include "ngx_stream_lua_request.h"
8 | #include "ngx_http_lua_api.h"
9 |
10 |
11 | #include "ngx_dynamic_upstream_module.h"
12 |
13 |
14 | extern ngx_module_t ngx_stream_dynamic_upstream_lua_module;
15 |
16 |
17 | static int
18 | ngx_stream_dynamic_upstream_lua_get_upstreams(lua_State *L);
19 | static int
20 | ngx_stream_dynamic_upstream_lua_get_peers(lua_State *L);
21 | static int
22 | ngx_stream_dynamic_upstream_lua_get_peers_locked(lua_State *L);
23 | static int
24 | ngx_stream_dynamic_upstream_lua_get_primary_peers(lua_State *L);
25 | static int
26 | ngx_stream_dynamic_upstream_lua_get_backup_peers(lua_State *L);
27 | static int
28 | ngx_stream_dynamic_upstream_lua_set_peer_down(lua_State *L);
29 | static int
30 | ngx_stream_dynamic_upstream_lua_set_peer_up(lua_State *L);
31 | static int
32 | ngx_stream_dynamic_upstream_lua_add_primary_peer(lua_State *L);
33 | static int
34 | ngx_stream_dynamic_upstream_lua_add_backup_peer(lua_State *L);
35 | static int
36 | ngx_stream_dynamic_upstream_lua_remove_peer(lua_State *L);
37 | static int
38 | ngx_stream_dynamic_upstream_lua_update_peer(lua_State *L);
39 |
40 |
41 | static ngx_stream_upstream_main_conf_t *
42 | ngx_stream_lua_upstream_get_upstream_main_conf();
43 |
44 |
45 | int
46 | ngx_stream_dynamic_upstream_lua_create_module(lua_State *L)
47 | {
48 | lua_newtable(L);
49 |
50 | lua_pushcfunction(L, ngx_stream_dynamic_upstream_lua_get_upstreams);
51 | lua_setfield(L, -2, "get_upstreams");
52 |
53 | lua_pushcfunction(L, ngx_stream_dynamic_upstream_lua_get_peers);
54 | lua_setfield(L, -2, "get_peers");
55 |
56 | lua_pushcfunction(L, ngx_stream_dynamic_upstream_lua_get_peers_locked);
57 | lua_setfield(L, -2, "get_peers_locked");
58 |
59 | lua_pushcfunction(L, ngx_stream_dynamic_upstream_lua_get_primary_peers);
60 | lua_setfield(L, -2, "get_primary_peers");
61 |
62 | lua_pushcfunction(L, ngx_stream_dynamic_upstream_lua_get_backup_peers);
63 | lua_setfield(L, -2, "get_backup_peers");
64 |
65 | lua_pushcfunction(L, ngx_stream_dynamic_upstream_lua_set_peer_down);
66 | lua_setfield(L, -2, "set_peer_down");
67 |
68 | lua_pushcfunction(L, ngx_stream_dynamic_upstream_lua_set_peer_up);
69 | lua_setfield(L, -2, "set_peer_up");
70 |
71 | lua_pushcfunction(L, ngx_stream_dynamic_upstream_lua_add_primary_peer);
72 | lua_setfield(L, -2, "add_primary_peer");
73 |
74 | lua_pushcfunction(L, ngx_stream_dynamic_upstream_lua_add_backup_peer);
75 | lua_setfield(L, -2, "add_backup_peer");
76 |
77 | lua_pushcfunction(L, ngx_stream_dynamic_upstream_lua_remove_peer);
78 | lua_setfield(L, -2, "remove_peer");
79 |
80 | lua_pushcfunction(L, ngx_stream_dynamic_upstream_lua_update_peer);
81 | lua_setfield(L, -2, "update_peer");
82 |
83 | return 1;
84 | }
85 |
86 |
87 | static ngx_stream_upstream_main_conf_t *
88 | ngx_stream_lua_upstream_get_upstream_main_conf()
89 | {
90 | return ngx_stream_cycle_get_module_main_conf(ngx_cycle,
91 | ngx_stream_upstream_module);
92 | }
93 |
94 |
95 | static ngx_stream_upstream_srv_conf_t *
96 | ngx_dynamic_upstream_get(lua_State *L, ngx_dynamic_upstream_op_t *op)
97 | {
98 | ngx_uint_t i;
99 | ngx_stream_upstream_srv_conf_t *uscf, **uscfp;
100 | ngx_stream_upstream_main_conf_t *umcf;
101 |
102 | umcf = ngx_stream_lua_upstream_get_upstream_main_conf();
103 | if (umcf == NULL) {
104 | return NULL;
105 | }
106 | uscfp = umcf->upstreams.elts;
107 |
108 | for (i = 0; i < umcf->upstreams.nelts; i++) {
109 | uscf = uscfp[i];
110 | if (op->upstream.len == uscf->host.len &&
111 | ngx_strncmp(uscf->host.data, op->upstream.data,
112 | op->upstream.len) == 0) {
113 | return uscf;
114 | }
115 | }
116 |
117 | return NULL;
118 | }
119 |
120 |
121 | static const int PRIMARY = 1;
122 | static const int BACKUP = 2;
123 | static const int LOCK = 4;
124 |
125 |
126 | static void
127 | ngx_dynamic_upstream_lua_create_response(ngx_stream_upstream_rr_peers_t *primary,
128 | lua_State *L, int flags)
129 | {
130 | ngx_stream_upstream_rr_peer_t *peer;
131 | ngx_stream_upstream_rr_peers_t *peers, *backup;
132 | int i = 1;
133 |
134 | backup = primary->next;
135 |
136 | if (flags & LOCK) {
137 | ngx_stream_upstream_rr_peers_rlock(primary);
138 | }
139 |
140 | lua_newtable(L);
141 |
142 | for (peers = primary; peers; peers = peers->next) {
143 |
144 | if ( (flags & PRIMARY && peers == primary)
145 | || (flags & BACKUP && peers == backup) ) {
146 |
147 | for (peer = peers->peer; peer; peer = peer->next, ++i) {
148 | lua_newtable(L);
149 |
150 | lua_pushlstring(L, (char *) peer->server.data,
151 | peer->server.len);
152 | lua_setfield(L, -2, "server");
153 |
154 | lua_pushlstring(L, (char *) peer->name.data,
155 | peer->name.len);
156 | lua_setfield(L, -2, "name");
157 |
158 | lua_pushinteger(L, (lua_Integer) peer->weight);
159 | lua_setfield(L, -2, "weight");
160 |
161 | lua_pushinteger(L, (lua_Integer) peer->max_conns);
162 | lua_setfield(L, -2, "max_conns");
163 |
164 | lua_pushinteger(L, (lua_Integer) peer->conns);
165 | lua_setfield(L, -2, "conns");
166 |
167 | lua_pushinteger(L, (lua_Integer) peer->max_fails);
168 | lua_setfield(L, -2, "max_fails");
169 |
170 | lua_pushinteger(L, (lua_Integer) peer->fail_timeout);
171 | lua_setfield(L, -2, "fail_timeout");
172 |
173 | lua_pushboolean(L, peers != primary);
174 | lua_setfield(L, -2, "backup");
175 |
176 | if (peer->down) {
177 | lua_pushboolean(L, 1);
178 | lua_setfield(L, -2, "down");
179 | }
180 |
181 | lua_rawseti(L, -2, i);
182 | }
183 | }
184 | }
185 |
186 | if (flags & LOCK) {
187 | ngx_stream_upstream_rr_peers_unlock(primary);
188 | }
189 | }
190 |
191 |
192 | static void
193 | ngx_stream_dynamic_upstream_lua_op_defaults(lua_State *L,
194 | ngx_dynamic_upstream_op_t *op, int operation)
195 | {
196 | ngx_memzero(op, sizeof(ngx_dynamic_upstream_op_t));
197 |
198 | op->op = operation;
199 |
200 | op->status = NGX_HTTP_OK;
201 | ngx_str_null(&op->upstream);
202 | op->weight = 1;
203 | op->max_fails = 1;
204 | op->fail_timeout = 10;
205 | op->verbose = 0;
206 | op->backup = 0;
207 | op->op_param = NGX_DYNAMIC_UPSTEAM_OP_PARAM_STREAM;
208 | op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_RESOLVE;
209 |
210 | op->upstream.data = (u_char *) luaL_checklstring(L, 1, &op->upstream.len);
211 | }
212 |
213 |
214 | static int
215 | ngx_stream_dynamic_upstream_lua_error(lua_State *L, const char *error)
216 | {
217 | lua_pushboolean(L, 0);
218 | lua_pushnil(L);
219 | lua_pushlstring(L, error, strlen(error));
220 | return 3;
221 | }
222 |
223 |
224 | static int
225 | ngx_stream_dynamic_upstream_lua_op(lua_State *L, ngx_dynamic_upstream_op_t *op,
226 | int flags)
227 | {
228 | ngx_int_t rc;
229 | ngx_stream_upstream_srv_conf_t *uscf;
230 | ngx_stream_upstream_rr_peers_t *primary;
231 |
232 | uscf = ngx_dynamic_upstream_get(L, op);
233 | if (uscf == NULL) {
234 | return ngx_stream_dynamic_upstream_lua_error(L, "upstream not found");
235 | }
236 |
237 | if (op->op != NGX_DYNAMIC_UPSTEAM_OP_LIST) {
238 | if (flags & LOCK) {
239 | rc = ngx_dynamic_upstream_stream_op(ngx_http_lua_get_request(L)->
240 | connection->log, op, uscf);
241 | if (rc != NGX_OK && rc != NGX_AGAIN) {
242 | return ngx_stream_dynamic_upstream_lua_error(L,
243 | op->err);
244 | }
245 | } else {
246 | return ngx_stream_dynamic_upstream_lua_error(L,
247 | "locked operations can be used only with readonly functions");
248 | }
249 | }
250 |
251 | lua_pushboolean(L, 1);
252 |
253 | if (op->verbose) {
254 | primary = uscf->peer.data;
255 | ngx_dynamic_upstream_lua_create_response(primary, L, flags);
256 | } else {
257 | lua_pushnil(L);
258 | }
259 |
260 | lua_pushnil(L);
261 |
262 | return 3;
263 | }
264 |
265 |
266 | static int
267 | ngx_stream_dynamic_upstream_lua_get_upstreams(lua_State *L)
268 | {
269 | ngx_uint_t i, j, count = 0;
270 | ngx_stream_upstream_srv_conf_t **uscfp, *uscf;
271 | ngx_stream_upstream_main_conf_t *umcf;
272 |
273 | if (lua_gettop(L) != 0) {
274 | return ngx_stream_dynamic_upstream_lua_error(L, "no argument expected");
275 | }
276 |
277 | umcf = ngx_stream_lua_upstream_get_upstream_main_conf();
278 | if (umcf == NULL) {
279 | lua_pushboolean(L, 1);
280 | lua_newtable(L);
281 | return 2;
282 | }
283 |
284 | uscfp = umcf->upstreams.elts;
285 |
286 | lua_pushboolean(L, 1);
287 |
288 | for (i = 0; i < umcf->upstreams.nelts; i++) {
289 | uscf = uscfp[i];
290 | if (uscf->srv_conf != NULL) {
291 | ++count;
292 | }
293 | }
294 |
295 | lua_newtable(L);
296 |
297 | umcf = ngx_stream_lua_upstream_get_upstream_main_conf();
298 | uscfp = umcf->upstreams.elts;
299 |
300 | for (i = 0, j = 1; i < umcf->upstreams.nelts; i++) {
301 | uscf = uscfp[i];
302 | if (uscf->srv_conf != NULL) {
303 | lua_pushlstring(L, (char *) uscf->host.data, uscf->host.len);
304 | lua_rawseti(L, -2, j++);
305 | }
306 | }
307 |
308 | return 2;
309 | }
310 |
311 |
312 | static int
313 | ngx_stream_dynamic_upstream_lua_get_peers(lua_State *L)
314 | {
315 | ngx_dynamic_upstream_op_t op;
316 | if (lua_gettop(L) != 1) {
317 | return ngx_stream_dynamic_upstream_lua_error(L,
318 | "exactly one argument expected");
319 | }
320 | ngx_stream_dynamic_upstream_lua_op_defaults(L, &op,
321 | NGX_DYNAMIC_UPSTEAM_OP_LIST);
322 | op.verbose = 1;
323 | return ngx_stream_dynamic_upstream_lua_op(L, &op, PRIMARY|BACKUP|LOCK);
324 | }
325 |
326 |
327 | static int
328 | ngx_stream_dynamic_upstream_lua_get_peers_locked(lua_State *L)
329 | {
330 | ngx_dynamic_upstream_op_t op;
331 | if (lua_gettop(L) != 1) {
332 | return ngx_stream_dynamic_upstream_lua_error(L,
333 | "exactly one argument expected");
334 | }
335 | ngx_stream_dynamic_upstream_lua_op_defaults(L, &op,
336 | NGX_DYNAMIC_UPSTEAM_OP_LIST);
337 | op.verbose = 1;
338 | return ngx_stream_dynamic_upstream_lua_op(L, &op, PRIMARY|BACKUP);
339 | }
340 |
341 |
342 | static int
343 | ngx_stream_dynamic_upstream_lua_get_primary_peers(lua_State *L)
344 | {
345 | ngx_dynamic_upstream_op_t op;
346 | if (lua_gettop(L) != 1) {
347 | return ngx_stream_dynamic_upstream_lua_error(L,
348 | "exactly one argument expected");
349 | }
350 | ngx_stream_dynamic_upstream_lua_op_defaults(L, &op,
351 | NGX_DYNAMIC_UPSTEAM_OP_LIST);
352 | op.verbose = 1;
353 | return ngx_stream_dynamic_upstream_lua_op(L, &op, PRIMARY|LOCK);
354 | }
355 |
356 |
357 | static int
358 | ngx_stream_dynamic_upstream_lua_get_backup_peers(lua_State *L)
359 | {
360 | ngx_dynamic_upstream_op_t op;
361 | if (lua_gettop(L) != 1) {
362 | return ngx_stream_dynamic_upstream_lua_error(L,
363 | "exactly one argument expected");
364 | }
365 | ngx_stream_dynamic_upstream_lua_op_defaults(L, &op,
366 | NGX_DYNAMIC_UPSTEAM_OP_LIST);
367 | op.verbose = 1;
368 | return ngx_stream_dynamic_upstream_lua_op(L, &op, BACKUP|LOCK);
369 | }
370 |
371 |
372 | static int
373 | ngx_stream_dynamic_upstream_lua_set_peer_down(lua_State *L)
374 | {
375 | ngx_dynamic_upstream_op_t op;
376 |
377 | if (lua_gettop(L) != 2) {
378 | return ngx_stream_dynamic_upstream_lua_error(L,
379 | "exactly 2 arguments expected");
380 | }
381 |
382 | ngx_stream_dynamic_upstream_lua_op_defaults(L, &op,
383 | NGX_DYNAMIC_UPSTEAM_OP_PARAM);
384 |
385 | op.down = 1;
386 | op.op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_DOWN;
387 |
388 | op.server.data = (u_char *) luaL_checklstring(L, 2, &op.server.len);
389 |
390 | return ngx_stream_dynamic_upstream_lua_op(L, &op, LOCK);
391 | }
392 |
393 |
394 | static int
395 | ngx_stream_dynamic_upstream_lua_set_peer_up(lua_State *L)
396 | {
397 | ngx_dynamic_upstream_op_t op;
398 |
399 | if (lua_gettop(L) != 2) {
400 | return ngx_stream_dynamic_upstream_lua_error(L,
401 | "exactly 2 arguments expected");
402 | }
403 |
404 | ngx_stream_dynamic_upstream_lua_op_defaults(L, &op,
405 | NGX_DYNAMIC_UPSTEAM_OP_PARAM);
406 |
407 | op.up = 1;
408 | op.op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_UP;
409 |
410 | op.server.data = (u_char *) luaL_checklstring(L, 2, &op.server.len);
411 |
412 | return ngx_stream_dynamic_upstream_lua_op(L, &op, LOCK);
413 | }
414 |
415 |
416 | static int
417 | ngx_stream_dynamic_upstream_lua_add_peer_impl(lua_State *L, int backup)
418 | {
419 | ngx_dynamic_upstream_op_t op;
420 |
421 | if (lua_gettop(L) != 2) {
422 | return ngx_stream_dynamic_upstream_lua_error(L,
423 | "exactly 2 arguments expected");
424 | }
425 |
426 | ngx_stream_dynamic_upstream_lua_op_defaults(L, &op,
427 | NGX_DYNAMIC_UPSTEAM_OP_ADD);
428 |
429 | op.server.data = (u_char *) luaL_checklstring(L, 2, &op.server.len);
430 |
431 | op.backup = backup;
432 |
433 | return ngx_stream_dynamic_upstream_lua_op(L, &op, LOCK);
434 | }
435 |
436 |
437 | static int
438 | ngx_stream_dynamic_upstream_lua_add_primary_peer(lua_State *L)
439 | {
440 | return ngx_stream_dynamic_upstream_lua_add_peer_impl(L, 0);
441 | }
442 |
443 |
444 | static int
445 | ngx_stream_dynamic_upstream_lua_add_backup_peer(lua_State *L)
446 | {
447 | return ngx_stream_dynamic_upstream_lua_add_peer_impl(L, 1);
448 | }
449 |
450 |
451 | static int
452 | ngx_stream_dynamic_upstream_lua_remove_peer(lua_State *L)
453 | {
454 | ngx_dynamic_upstream_op_t op;
455 |
456 | if (lua_gettop(L) != 2) {
457 | return ngx_stream_dynamic_upstream_lua_error(L,
458 | "exactly 2 arguments expected");
459 | }
460 |
461 | ngx_stream_dynamic_upstream_lua_op_defaults(L, &op,
462 | NGX_DYNAMIC_UPSTEAM_OP_REMOVE);
463 |
464 | op.server.data = (u_char *) luaL_checklstring(L, 2, &op.server.len);
465 |
466 | return ngx_stream_dynamic_upstream_lua_op(L, &op, LOCK);
467 | }
468 |
469 |
470 | static int
471 | ngx_stream_dynamic_upstream_lua_update_peer_parse_params(lua_State *L,
472 | ngx_dynamic_upstream_op_t *op)
473 | {
474 | const char *key;
475 |
476 | lua_pushvalue(L, -1);
477 | lua_pushnil(L);
478 |
479 | while (lua_next(L, -2))
480 | {
481 | lua_pushvalue(L, -2);
482 | key = lua_tostring(L, -1);
483 | if (strcmp(key, "weight") == 0) {
484 | op->weight = lua_tonumber(L, -2);
485 | op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_WEIGHT;
486 | } else if (strcmp(key, "max_fails") == 0) {
487 | op->max_fails = lua_tonumber(L, -2);
488 | op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_MAX_FAILS;
489 | } else if (strcmp(key, "max_conns") == 0) {
490 | op->max_conns = lua_tonumber(L, -2);
491 | op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_MAX_CONNS;
492 | } else if (strcmp(key, "fail_timeout") == 0) {
493 | op->fail_timeout = lua_tonumber(L, -2);
494 | op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_FAIL_TIMEOUT;
495 | } else if (strcmp(key, "down") == 0) {
496 | if (lua_tonumber(L, -2) == 1) {
497 | op->down = 1;
498 | op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_DOWN;
499 | } else if (lua_tonumber(L, -2) == 0) {
500 | op->up = 1;
501 | op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_UP;
502 | }
503 | }
504 | lua_pop(L, 2);
505 | }
506 |
507 | lua_pop(L, 1);
508 |
509 | return NGX_OK;
510 | }
511 |
512 |
513 | static int
514 | ngx_stream_dynamic_upstream_lua_update_peer(lua_State *L)
515 | {
516 | ngx_dynamic_upstream_op_t op;
517 |
518 | if (lua_gettop(L) != 3 || !lua_istable(L, 3)) {
519 | return ngx_stream_dynamic_upstream_lua_error(L,
520 | "exactly 3 arguments expected");
521 | }
522 |
523 | ngx_stream_dynamic_upstream_lua_op_defaults(L, &op,
524 | NGX_DYNAMIC_UPSTEAM_OP_PARAM);
525 |
526 | op.server.data = (u_char *) luaL_checklstring(L, 2, &op.server.len);
527 |
528 | ngx_stream_dynamic_upstream_lua_update_peer_parse_params(L, &op);
529 |
530 | return ngx_stream_dynamic_upstream_lua_op(L, &op, LOCK);
531 | }
532 |
--------------------------------------------------------------------------------
/src/ngx_dynamic_upstream_lua.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "ngx_http_lua_api.h"
5 |
6 |
7 | #include "ngx_dynamic_upstream_lua.h"
8 | #include "ngx_dynamic_upstream_module.h"
9 |
10 |
11 | extern ngx_module_t ngx_http_dynamic_upstream_lua_module;
12 |
13 |
14 | static int
15 | ngx_http_dynamic_upstream_lua_create_module(lua_State *L);
16 |
17 |
18 | static int
19 | ngx_http_dynamic_upstream_lua_get_upstreams(lua_State *L);
20 | static int
21 | ngx_http_dynamic_upstream_lua_get_peers(lua_State *L);
22 | static int
23 | ngx_http_dynamic_upstream_lua_get_peers_locked(lua_State *L);
24 | static int
25 | ngx_http_dynamic_upstream_lua_get_primary_peers(lua_State *L);
26 | static int
27 | ngx_http_dynamic_upstream_lua_get_backup_peers(lua_State *L);
28 | static int
29 | ngx_http_dynamic_upstream_lua_set_peer_down(lua_State *L);
30 | static int
31 | ngx_http_dynamic_upstream_lua_set_peer_up(lua_State *L);
32 | static int
33 | ngx_http_dynamic_upstream_lua_add_primary_peer(lua_State *L);
34 | static int
35 | ngx_http_dynamic_upstream_lua_add_backup_peer(lua_State *L);
36 | static int
37 | ngx_http_dynamic_upstream_lua_remove_peer(lua_State *L);
38 | static int
39 | ngx_http_dynamic_upstream_lua_update_peer(lua_State *L);
40 | static int
41 | ngx_http_dynamic_upstream_lua_current_upstream(lua_State *L);
42 |
43 |
44 | ngx_int_t
45 | ngx_http_dynamic_upstream_lua_init(ngx_conf_t *cf)
46 | {
47 | if (ngx_http_lua_add_package_preload(cf, "ngx.dynamic_upstream",
48 | ngx_http_dynamic_upstream_lua_create_module) != NGX_OK) {
49 | return NGX_ERROR;
50 | }
51 |
52 | return NGX_OK;
53 | }
54 |
55 |
56 | static int
57 | ngx_http_dynamic_upstream_lua_create_module(lua_State *L)
58 | {
59 | lua_newtable(L);
60 |
61 | lua_pushcfunction(L, ngx_http_dynamic_upstream_lua_get_upstreams);
62 | lua_setfield(L, -2, "get_upstreams");
63 |
64 | lua_pushcfunction(L, ngx_http_dynamic_upstream_lua_get_peers);
65 | lua_setfield(L, -2, "get_peers");
66 |
67 | lua_pushcfunction(L, ngx_http_dynamic_upstream_lua_get_peers_locked);
68 | lua_setfield(L, -2, "get_peers_locked");
69 |
70 | lua_pushcfunction(L, ngx_http_dynamic_upstream_lua_get_primary_peers);
71 | lua_setfield(L, -2, "get_primary_peers");
72 |
73 | lua_pushcfunction(L, ngx_http_dynamic_upstream_lua_get_backup_peers);
74 | lua_setfield(L, -2, "get_backup_peers");
75 |
76 | lua_pushcfunction(L, ngx_http_dynamic_upstream_lua_set_peer_down);
77 | lua_setfield(L, -2, "set_peer_down");
78 |
79 | lua_pushcfunction(L, ngx_http_dynamic_upstream_lua_set_peer_up);
80 | lua_setfield(L, -2, "set_peer_up");
81 |
82 | lua_pushcfunction(L, ngx_http_dynamic_upstream_lua_add_primary_peer);
83 | lua_setfield(L, -2, "add_primary_peer");
84 |
85 | lua_pushcfunction(L, ngx_http_dynamic_upstream_lua_add_backup_peer);
86 | lua_setfield(L, -2, "add_backup_peer");
87 |
88 | lua_pushcfunction(L, ngx_http_dynamic_upstream_lua_remove_peer);
89 | lua_setfield(L, -2, "remove_peer");
90 |
91 | lua_pushcfunction(L, ngx_http_dynamic_upstream_lua_update_peer);
92 | lua_setfield(L, -2, "update_peer");
93 |
94 | lua_pushcfunction(L, ngx_http_dynamic_upstream_lua_current_upstream);
95 | lua_setfield(L, -2, "current_upstream");
96 |
97 | return 1;
98 | }
99 |
100 |
101 | static ngx_http_upstream_main_conf_t *
102 | ngx_http_lua_upstream_get_upstream_main_conf(lua_State *L)
103 | {
104 | ngx_http_request_t *r;
105 |
106 | r = ngx_http_lua_get_request(L);
107 |
108 | if (r == NULL) {
109 | return ngx_http_cycle_get_module_main_conf(ngx_cycle,
110 | ngx_http_upstream_module);
111 | }
112 |
113 | return ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
114 | }
115 |
116 |
117 | static ngx_http_upstream_srv_conf_t *
118 | ngx_dynamic_upstream_get(lua_State *L, ngx_dynamic_upstream_op_t *op)
119 | {
120 | ngx_uint_t i;
121 | ngx_http_upstream_srv_conf_t *uscf, **uscfp;
122 | ngx_http_upstream_main_conf_t *umcf;
123 |
124 | umcf = ngx_http_lua_upstream_get_upstream_main_conf(L);
125 | uscfp = umcf->upstreams.elts;
126 |
127 | for (i = 0; i < umcf->upstreams.nelts; i++) {
128 | uscf = uscfp[i];
129 | if (op->upstream.len == uscf->host.len &&
130 | ngx_strncmp(uscf->host.data, op->upstream.data,
131 | op->upstream.len) == 0) {
132 | return uscf;
133 | }
134 | }
135 |
136 | return NULL;
137 | }
138 |
139 |
140 | static const int PRIMARY = 1;
141 | static const int BACKUP = 2;
142 | static const int LOCK = 4;
143 |
144 |
145 | static void
146 | ngx_dynamic_upstream_lua_create_response(ngx_http_upstream_rr_peers_t *primary,
147 | lua_State *L, int flags)
148 | {
149 | ngx_http_upstream_rr_peer_t *peer;
150 | ngx_http_upstream_rr_peers_t *peers, *backup;
151 | int i = 1;
152 |
153 | backup = primary->next;
154 |
155 | if (flags & LOCK) {
156 | ngx_http_upstream_rr_peers_rlock(primary);
157 | }
158 |
159 | lua_newtable(L);
160 |
161 | for (peers = primary; peers; peers = peers->next) {
162 | if ( (flags & PRIMARY && peers == primary)
163 | || (flags & BACKUP && peers == backup) ) {
164 | for (peer = peers->peer; peer; peer = peer->next, ++i) {
165 | lua_newtable(L);
166 |
167 | lua_pushlstring(L, (char *) peer->server.data,
168 | peer->server.len);
169 | lua_setfield(L, -2, "server");
170 |
171 | lua_pushlstring(L, (char *) peer->name.data,
172 | peer->name.len);
173 | lua_setfield(L, -2, "name");
174 |
175 | lua_pushinteger(L, (lua_Integer) peer->weight);
176 | lua_setfield(L, -2, "weight");
177 |
178 | lua_pushinteger(L, (lua_Integer) peer->max_conns);
179 | lua_setfield(L, -2, "max_conns");
180 |
181 | lua_pushinteger(L, (lua_Integer) peer->conns);
182 | lua_setfield(L, -2, "conns");
183 |
184 | lua_pushinteger(L, (lua_Integer) peer->max_fails);
185 | lua_setfield(L, -2, "max_fails");
186 |
187 | lua_pushinteger(L, (lua_Integer) peer->fail_timeout);
188 | lua_setfield(L, -2, "fail_timeout");
189 |
190 | lua_pushboolean(L, peers != primary);
191 | lua_setfield(L, -2, "backup");
192 |
193 | if (peer->down) {
194 | lua_pushboolean(L, 1);
195 | lua_setfield(L, -2, "down");
196 | }
197 |
198 | lua_rawseti(L, -2, i);
199 | }
200 | }
201 | }
202 |
203 | if (flags & LOCK) {
204 | ngx_http_upstream_rr_peers_unlock(primary);
205 | }
206 | }
207 |
208 |
209 | static void
210 | ngx_http_dynamic_upstream_lua_op_defaults(lua_State *L,
211 | ngx_dynamic_upstream_op_t *op, int operation)
212 | {
213 | ngx_memzero(op, sizeof(ngx_dynamic_upstream_op_t));
214 |
215 | op->op = operation;
216 |
217 | op->status = NGX_HTTP_OK;
218 | ngx_str_null(&op->upstream);
219 | op->weight = 1;
220 | op->max_fails = 1;
221 | op->fail_timeout = 10;
222 | op->verbose = 0;
223 | op->backup = 0;
224 | op->op_param = NGX_DYNAMIC_UPSTEAM_OP_PARAM_RESOLVE;
225 |
226 | op->upstream.data = (u_char *) luaL_checklstring(L, 1, &op->upstream.len);
227 | }
228 |
229 |
230 | static int
231 | ngx_http_dynamic_upstream_lua_error(lua_State *L, const char *error)
232 | {
233 | lua_pushboolean(L, 0);
234 | lua_pushnil(L);
235 | lua_pushlstring(L, error, strlen(error));
236 | return 3;
237 | }
238 |
239 |
240 | static int
241 | ngx_http_dynamic_upstream_lua_op(lua_State *L, ngx_dynamic_upstream_op_t *op,
242 | int flags)
243 | {
244 | ngx_int_t rc;
245 | ngx_http_upstream_srv_conf_t *uscf;
246 | ngx_http_upstream_rr_peers_t *primary;
247 |
248 | uscf = ngx_dynamic_upstream_get(L, op);
249 | if (uscf == NULL) {
250 | return ngx_http_dynamic_upstream_lua_error(L, "upstream not found");
251 | }
252 |
253 | if (op->op != NGX_DYNAMIC_UPSTEAM_OP_LIST) {
254 | if (flags & LOCK) {
255 | rc = ngx_dynamic_upstream_op(ngx_http_lua_get_request(L)->
256 | connection->log, op, uscf);
257 | if (rc != NGX_OK && rc != NGX_AGAIN) {
258 | return ngx_http_dynamic_upstream_lua_error(L,
259 | op->err);
260 | }
261 | } else {
262 | return ngx_http_dynamic_upstream_lua_error(L,
263 | "locked operations can be used only with readonly functions");
264 | }
265 | }
266 |
267 | lua_pushboolean(L, 1);
268 |
269 | if (op->verbose) {
270 | primary = uscf->peer.data;
271 | ngx_dynamic_upstream_lua_create_response(primary, L, flags);
272 | } else {
273 | lua_pushnil(L);
274 | }
275 |
276 | lua_pushnil(L);
277 |
278 | return 3;
279 | }
280 |
281 |
282 | static int
283 | ngx_http_dynamic_upstream_lua_get_upstreams(lua_State *L)
284 | {
285 | ngx_uint_t i, j, count = 0;
286 | ngx_http_upstream_srv_conf_t **uscfp, *uscf;
287 | ngx_http_upstream_main_conf_t *umcf;
288 |
289 | if (lua_gettop(L) != 0) {
290 | return ngx_http_dynamic_upstream_lua_error(L, "no argument expected");
291 | }
292 |
293 | umcf = ngx_http_lua_upstream_get_upstream_main_conf(L);
294 | if (umcf == NULL) {
295 | lua_pushboolean(L, 1);
296 | lua_newtable(L);
297 | return 2;
298 | }
299 |
300 | uscfp = umcf->upstreams.elts;
301 |
302 | lua_pushboolean(L, 1);
303 |
304 | for (i = 0; i < umcf->upstreams.nelts; i++) {
305 | uscf = uscfp[i];
306 | if (uscf->srv_conf != NULL) {
307 | ++count;
308 | }
309 | }
310 |
311 | lua_newtable(L);
312 |
313 | umcf = ngx_http_lua_upstream_get_upstream_main_conf(L);
314 | uscfp = umcf->upstreams.elts;
315 |
316 | for (i = 0, j = 1; i < umcf->upstreams.nelts; i++) {
317 | uscf = uscfp[i];
318 | if (uscf->srv_conf != NULL) {
319 | lua_pushlstring(L, (char *) uscf->host.data, uscf->host.len);
320 | lua_rawseti(L, -2, j++);
321 | }
322 | }
323 |
324 | return 2;
325 | }
326 |
327 |
328 | static int
329 | ngx_http_dynamic_upstream_lua_get_peers(lua_State *L)
330 | {
331 | ngx_dynamic_upstream_op_t op;
332 | if (lua_gettop(L) != 1) {
333 | return ngx_http_dynamic_upstream_lua_error(L,
334 | "exactly one argument expected");
335 | }
336 | ngx_http_dynamic_upstream_lua_op_defaults(L, &op,
337 | NGX_DYNAMIC_UPSTEAM_OP_LIST);
338 | op.verbose = 1;
339 | return ngx_http_dynamic_upstream_lua_op(L, &op, PRIMARY|BACKUP|LOCK);
340 | }
341 |
342 |
343 | static int
344 | ngx_http_dynamic_upstream_lua_get_peers_locked(lua_State *L)
345 | {
346 | ngx_dynamic_upstream_op_t op;
347 | if (lua_gettop(L) != 1) {
348 | return ngx_http_dynamic_upstream_lua_error(L,
349 | "exactly one argument expected");
350 | }
351 | ngx_http_dynamic_upstream_lua_op_defaults(L, &op,
352 | NGX_DYNAMIC_UPSTEAM_OP_LIST);
353 | op.verbose = 1;
354 | return ngx_http_dynamic_upstream_lua_op(L, &op, PRIMARY|BACKUP);
355 | }
356 |
357 |
358 | static int
359 | ngx_http_dynamic_upstream_lua_get_primary_peers(lua_State *L)
360 | {
361 | ngx_dynamic_upstream_op_t op;
362 | if (lua_gettop(L) != 1) {
363 | return ngx_http_dynamic_upstream_lua_error(L,
364 | "exactly one argument expected");
365 | }
366 | ngx_http_dynamic_upstream_lua_op_defaults(L, &op,
367 | NGX_DYNAMIC_UPSTEAM_OP_LIST);
368 | op.verbose = 1;
369 | return ngx_http_dynamic_upstream_lua_op(L, &op, PRIMARY|LOCK);
370 | }
371 |
372 |
373 | static int
374 | ngx_http_dynamic_upstream_lua_get_backup_peers(lua_State *L)
375 | {
376 | ngx_dynamic_upstream_op_t op;
377 | if (lua_gettop(L) != 1) {
378 | return ngx_http_dynamic_upstream_lua_error(L,
379 | "exactly one argument expected");
380 | }
381 | ngx_http_dynamic_upstream_lua_op_defaults(L, &op,
382 | NGX_DYNAMIC_UPSTEAM_OP_LIST);
383 | op.verbose = 1;
384 | return ngx_http_dynamic_upstream_lua_op(L, &op, BACKUP|LOCK);
385 | }
386 |
387 |
388 | static int
389 | ngx_http_dynamic_upstream_lua_set_peer_down(lua_State *L)
390 | {
391 | ngx_dynamic_upstream_op_t op;
392 |
393 | if (lua_gettop(L) != 2) {
394 | return ngx_http_dynamic_upstream_lua_error(L,
395 | "exactly 2 arguments expected");
396 | }
397 |
398 | ngx_http_dynamic_upstream_lua_op_defaults(L, &op,
399 | NGX_DYNAMIC_UPSTEAM_OP_PARAM);
400 |
401 | op.down = 1;
402 | op.op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_DOWN;
403 |
404 | op.server.data = (u_char *) luaL_checklstring(L, 2, &op.server.len);
405 |
406 | return ngx_http_dynamic_upstream_lua_op(L, &op, LOCK);
407 | }
408 |
409 |
410 | static int
411 | ngx_http_dynamic_upstream_lua_set_peer_up(lua_State *L)
412 | {
413 | ngx_dynamic_upstream_op_t op;
414 |
415 | if (lua_gettop(L) != 2) {
416 | return ngx_http_dynamic_upstream_lua_error(L,
417 | "exactly 2 arguments expected");
418 | }
419 |
420 | ngx_http_dynamic_upstream_lua_op_defaults(L, &op,
421 | NGX_DYNAMIC_UPSTEAM_OP_PARAM);
422 |
423 | op.up = 1;
424 | op.op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_UP;
425 |
426 | op.server.data = (u_char *) luaL_checklstring(L, 2, &op.server.len);
427 |
428 | return ngx_http_dynamic_upstream_lua_op(L, &op, LOCK);
429 | }
430 |
431 |
432 | static int
433 | ngx_http_dynamic_upstream_lua_add_peer_impl(lua_State *L, int backup)
434 | {
435 | ngx_dynamic_upstream_op_t op;
436 |
437 | if (lua_gettop(L) != 2) {
438 | return ngx_http_dynamic_upstream_lua_error(L,
439 | "exactly 2 arguments expected");
440 | }
441 |
442 | ngx_http_dynamic_upstream_lua_op_defaults(L, &op,
443 | NGX_DYNAMIC_UPSTEAM_OP_ADD);
444 |
445 | op.server.data = (u_char *) luaL_checklstring(L, 2, &op.server.len);
446 |
447 | op.backup = backup;
448 |
449 | return ngx_http_dynamic_upstream_lua_op(L, &op, LOCK);
450 | }
451 |
452 |
453 | static int
454 | ngx_http_dynamic_upstream_lua_add_primary_peer(lua_State *L)
455 | {
456 | return ngx_http_dynamic_upstream_lua_add_peer_impl(L, 0);
457 | }
458 |
459 |
460 | static int
461 | ngx_http_dynamic_upstream_lua_add_backup_peer(lua_State *L)
462 | {
463 | return ngx_http_dynamic_upstream_lua_add_peer_impl(L, 1);
464 | }
465 |
466 |
467 | static int
468 | ngx_http_dynamic_upstream_lua_remove_peer(lua_State *L)
469 | {
470 | ngx_dynamic_upstream_op_t op;
471 |
472 | if (lua_gettop(L) != 2) {
473 | return ngx_http_dynamic_upstream_lua_error(L,
474 | "exactly 2 arguments expected");
475 | }
476 |
477 | ngx_http_dynamic_upstream_lua_op_defaults(L, &op,
478 | NGX_DYNAMIC_UPSTEAM_OP_REMOVE);
479 |
480 | op.server.data = (u_char *) luaL_checklstring(L, 2, &op.server.len);
481 |
482 | return ngx_http_dynamic_upstream_lua_op(L, &op, LOCK);
483 | }
484 |
485 |
486 | static int
487 | ngx_http_dynamic_upstream_lua_update_peer_parse_params(lua_State *L,
488 | ngx_dynamic_upstream_op_t *op)
489 | {
490 | const char *key;
491 |
492 | lua_pushvalue(L, -1);
493 | lua_pushnil(L);
494 |
495 | while (lua_next(L, -2))
496 | {
497 | lua_pushvalue(L, -2);
498 | key = lua_tostring(L, -1);
499 | if (strcmp(key, "weight") == 0) {
500 | op->weight = lua_tonumber(L, -2);
501 | op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_WEIGHT;
502 | } else if (strcmp(key, "max_fails") == 0) {
503 | op->max_fails = lua_tonumber(L, -2);
504 | op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_MAX_FAILS;
505 | } else if (strcmp(key, "max_conns") == 0) {
506 | op->max_conns = lua_tonumber(L, -2);
507 | op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_MAX_CONNS;
508 | } else if (strcmp(key, "fail_timeout") == 0) {
509 | op->fail_timeout = lua_tonumber(L, -2);
510 | op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_FAIL_TIMEOUT;
511 | } else if (strcmp(key, "down") == 0) {
512 | if (lua_tonumber(L, -2) == 1) {
513 | op->down = 1;
514 | op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_DOWN;
515 | } else if (lua_tonumber(L, -2) == 0) {
516 | op->up = 1;
517 | op->op_param |= NGX_DYNAMIC_UPSTEAM_OP_PARAM_UP;
518 | }
519 | }
520 | lua_pop(L, 2);
521 | }
522 |
523 | lua_pop(L, 1);
524 |
525 | return NGX_OK;
526 | }
527 |
528 |
529 | static int
530 | ngx_http_dynamic_upstream_lua_update_peer(lua_State *L)
531 | {
532 | ngx_dynamic_upstream_op_t op;
533 |
534 | if (lua_gettop(L) != 3 || !lua_istable(L, 3)) {
535 | return ngx_http_dynamic_upstream_lua_error(L,
536 | "exactly 3 arguments expected");
537 | }
538 |
539 | ngx_http_dynamic_upstream_lua_op_defaults(L, &op,
540 | NGX_DYNAMIC_UPSTEAM_OP_PARAM);
541 |
542 | op.server.data = (u_char *) luaL_checklstring(L, 2, &op.server.len);
543 |
544 | ngx_http_dynamic_upstream_lua_update_peer_parse_params(L, &op);
545 |
546 | return ngx_http_dynamic_upstream_lua_op(L, &op, LOCK);
547 | }
548 |
549 |
550 | static int
551 | ngx_http_dynamic_upstream_lua_current_upstream(lua_State *L)
552 | {
553 | ngx_http_request_t *r;
554 | ngx_http_upstream_t *us;
555 | ngx_http_upstream_conf_t *ucf;
556 | ngx_http_upstream_srv_conf_t *uscf;
557 |
558 | r = ngx_http_lua_get_request(L);
559 | if (r == NULL) {
560 | return ngx_http_dynamic_upstream_lua_error(L, "no request object");
561 | }
562 |
563 | us = r->upstream;
564 | if (us == NULL) {
565 | return ngx_http_dynamic_upstream_lua_error(L, "no proxying");
566 | }
567 |
568 | uscf = us->upstream;
569 |
570 | if (uscf == NULL) {
571 | ucf = us->conf;
572 | if (ucf == NULL) {
573 | return ngx_http_dynamic_upstream_lua_error(L,"no upstream");
574 | }
575 | uscf = ucf->upstream;
576 | if (uscf == NULL) {
577 | return ngx_http_dynamic_upstream_lua_error(L, "no srv upstream");
578 | }
579 | }
580 |
581 | lua_pushboolean(L, 1);
582 | lua_pushlstring(L, (char *) uscf->host.data, uscf->host.len);
583 | lua_pushnil(L);
584 |
585 | return 3;
586 | }
587 |
--------------------------------------------------------------------------------