Skip to content

Commit

Permalink
hotfix(cli) seed random number generator in CLI
Browse files Browse the repository at this point in the history
If spawning multiple nodes at once (making use of the CLI from different
host machines), we need to make sure none of them are using the same
seed. To enforce this, we make use of the patched 'math.randomseed()'
function, which should greatly reduce the probability of seed collision.

To allow for this change, we need a special flag indicating our scripts
if we are running inside of our CLI, so that out 'math.randomseed()'
  does not complain about being called in resty-cli's 'timer' context.

* add `ngx.RESTY_CLI` flag in `bin/kong`
* add an edge case in our patched `math.randomseed()`
* apply `kong.core.globalpatches` to our CLI environment

Fix #1592
  • Loading branch information
thibaultcha authored and subnetmarco committed Oct 28, 2016
1 parent ed36c59 commit 580926a
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 10 deletions.
4 changes: 4 additions & 0 deletions bin/kong
@@ -1,5 +1,9 @@
#!/usr/bin/env resty

-- a flag to detect whether our modules (especially kong.core.globalpatches)
-- are running under resty-cli or in a real ngx_lua, runtime environment.
ngx.RESTY_CLI = true

-- force LuaSocket usage to resolve `/etc/hosts` until
-- supported by resty-cli.
-- See https://github.com/Mashape/kong/issues/1523
Expand Down
7 changes: 5 additions & 2 deletions kong/cmd/init.lua
@@ -1,6 +1,9 @@
require "kong.core.globalpatches"

math.randomseed()

local pl_app = require "pl.lapp"
local log = require "kong.cmd.utils.log"
local meta = require "kong.meta"

local options = [[
--v verbose
Expand Down Expand Up @@ -77,7 +80,7 @@ return function(args)
log.set_lvl(log.levels.debug)
end

log.verbose("Kong: %s", meta._VERSION)
log.verbose("Kong: %s", _KONG._VERSION)
log.debug("ngx_lua: %s", ngx.config.ngx_lua_version)
log.debug("nginx: %s", ngx.config.nginx_version)
log.debug("Lua: %s", jit and jit.version or _VERSION)
Expand Down
24 changes: 16 additions & 8 deletions kong/core/globalpatches.lua
Expand Up @@ -9,21 +9,29 @@ _G._KONG = {
local seed

--- Seeds the random generator, use with care.
-- The uuid.seed() method will create a unique seed per worker
-- process, using a combination of both time and the worker's pid.
-- We only allow it to be called once to prevent third-party modules
-- from overriding our correct seed (many modules make a wrong usage
-- of `math.randomseed()` by calling it multiple times or do not use
-- unique seed for Nginx workers).
-- Once - properly - seeded, this method is replaced with a stub
-- one. This is to enforce best-practises for seeding in ngx_lua,
-- and prevents third-party modules from overriding our correct seed
-- (many modules make a wrong usage of `math.randomseed()` by calling
-- it multiple times or do not use unique seed for Nginx workers).
--
-- This patched method will create a unique seed per worker process,
-- using a combination of both time and the worker's pid.
-- luacheck: globals math
_G.math.randomseed = function()
if not seed then
if ngx.get_phase() ~= "init_worker" then
-- If we're in runtime nginx, we have multiple workers so we _only_
-- accept seeding when in the 'init_worker' phase.
-- That is because that phase is the earliest one before the
-- workers have a chance to process business logic, and because
-- if we'd do that in the 'init' phase, the Lua VM is not forked
-- yet and all workers would end-up using the same seed.
if not ngx.RESTY_CLI and ngx.get_phase() ~= "init_worker" then
error("math.randomseed() must be called in init_worker", 2)
end

seed = ngx.time() + ngx.worker.pid()
ngx.log(ngx.DEBUG, "random seed: ", seed, " for worker n", ngx.worker.id(),
ngx.log(ngx.DEBUG, "random seed: ", seed, " for worker nb ", ngx.worker.id(),
" (pid: ", ngx.worker.pid(), ")")
randomseed(seed)
else
Expand Down

0 comments on commit 580926a

Please sign in to comment.