docker

Форк
0
/
tarantool-entrypoint.lua 
306 строк · 11.2 Кб
1
#!/usr/bin/env tarantool
2

3
local fio = require('fio')
4
local errno = require('errno')
5
local urilib = require('uri')
6
local console = require('console')
7
local term = require('term')
8
local log = require('log')
9
local yaml = require('yaml')
10

11
local TARANTOOL_DEFAULT_PORT = 3301
12
local CONSOLE_SOCKET_PATH = 'unix/:/var/run/tarantool/tarantool.sock'
13
local CFG_FILE_PATH = '/etc/tarantool/config.yml'
14

15

16
local orig_cfg = box.cfg
17

18
local function read_config()
19
    local f = io.open(CFG_FILE_PATH, "rb")
20
    if f == nil then
21
        log.error("Can't open " .. CFG_FILE_PATH ..": ", errno.strerror())
22
        os.exit(1)
23
    end
24
    local content = f:read("*all")
25
    f:close()
26
    return yaml.decode(content)
27
end
28

29
local function write_config(cfg)
30
    local f = io.open(CFG_FILE_PATH, "w+")
31
    if f == nil then
32
        print("Can't open " .. CFG_FILE_PATH ..": ", errno.strerror())
33
        os.exit(1)
34
    end
35
    local content = yaml.encode(cfg)
36
    f:write(content)
37
    f:close()
38
end
39

40
local function parse_replication_source(replication_source, user_name, user_password)
41
    if replication_source == nil then
42
        return nil
43
    end
44

45
    local replication_source_table = {}
46
    for uri in string.gmatch(replication_source, "[^,]+") do
47
        local parsed_uri = urilib.parse(uri)
48
        if parsed_uri == nil then
49
            error("Incorrect replication source URI format: '"..uri.."'")
50
        end
51
        local host = parsed_uri.host
52
        local port = parsed_uri.service or TARANTOOL_DEFAULT_PORT
53
        local user = parsed_uri.login or user_name
54
        local password = parsed_uri.password or user_password
55

56
        if user == 'guest' or user == nil then
57
            replication_source = string.format("%s:%s", host, port)
58
        elseif password == nil then
59
            replication_source = string.format("%s:@%s:%s", user, host, port)
60
        else
61
            replication_source = string.format("%s:%s@%s:%s", user, password,
62
                                               host, port)
63
        end
64

65
        table.insert(replication_source_table, replication_source)
66
    end
67

68
    return replication_source_table
69
end
70

71
local function choose_option(main, substitute, cfg)
72
    if cfg[main] then
73
        return main
74
    end
75
    if cfg[substitute] then
76
        return substitute
77
    end
78
    return main
79
end
80

81
function set_replication_source(replication_source, user_name, user_password)
82
    local replication_source_table = parse_replication_source(
83
        replication_source, user_name, user_password
84
    )
85
    local choice = choose_option('replication', 'replication_source', box.cfg)
86
    box.cfg{[choice] = replication_source_table}
87
    log.info("Updated box.cfg.%s to %s", choice, replication_source)
88
end
89

90
local function create_user(user_name, user_password)
91
    if user_name ~= 'guest' and user_password == nil then
92
        user_password = ""
93

94
        local warn_str = [[****************************************************
95
WARNING: No password has been set for the database.
96
         This will allow anyone with access to the
97
         Tarantool port to access your database. In
98
         Docker's default configuration, this is
99
         effectively any other container on the same
100
         system.
101
         Use "-e TARANTOOL_USER_PASSWORD=password"
102
         to set it in "docker run".
103
****************************************************]]
104
        log.warn('\n'..warn_str)
105
    end
106

107
    if user_name == 'guest' and user_password == nil then
108
        local warn_str = [[****************************************************
109
WARNING: 'guest' is chosen as primary user.
110
         Since it is not allowed to set a password for
111
         guest user, your instance will be accessible
112
         by anyone having direct access to the Tarantool
113
         port.
114
         If you wanted to create an authenticated user,
115
         specify "-e TARANTOOL_USER_NAME=username" and
116
         pick a user name other than "guest".
117
****************************************************]]
118
        log.warn('\n'..warn_str)
119
    end
120

121
    if user_name == 'guest' and user_password ~= nil then
122
        user_password = nil
123

124
        local warn_str = [[****************************************************
125
WARNING: A password for guest user has been specified.
126
         In Tarantool, guest user can't have a password
127
         and is always allowed to login, if it has
128
         enough privileges.
129
         If you wanted to create an authenticated user,
130
         specify "-e TARANTOOL_USER_NAME=username" and
131
         pick a user name other than "guest".
132
****************************************************]]
133
        log.warn('\n'..warn_str)
134
    end
135

136
    if user_name ~= 'admin' and user_name ~= 'guest' then
137
        if not box.schema.user.exists(user_name) then
138
            log.info("Creating user '%s'", user_name)
139
            box.schema.user.create(user_name)
140
        end
141
    end
142

143
    if user_name ~= 'admin' then
144
        log.info("Granting admin privileges to user '%s'", user_name)
145
        box.schema.user.grant(user_name, 'read,write,execute,create,drop',
146
                              'universe', nil, {if_not_exists = true})
147
        box.schema.user.grant(user_name, 'replication',
148
                              nil, nil, {if_not_exists = true})
149
    end
150

151
    if user_name ~= 'guest' then
152
        log.info("Setting password for user '%s'", user_name)
153
        box.schema.user.passwd(user_name, user_password)
154
    end
155
end
156

157
function set_credentials(user_name, user_password)
158
    create_user(user_name, user_password)
159
end
160

161
local function wrapper_cfg(override)
162
    local work_dir = '/var/lib/tarantool'
163
    local snap_filename = "*.snap"
164
    local snap_path = work_dir..'/'..snap_filename
165

166
    local first_run = false
167
    if next(fio.glob(snap_path)) == nil then
168
        first_run = true
169
    end
170

171

172
    local file_cfg = {}
173
    local config_file_exists = fio.stat(CFG_FILE_PATH) ~= nil
174
    if not config_file_exists then
175
        log.info("Creating configuration file: " .. CFG_FILE_PATH)
176

177
        file_cfg.TARANTOOL_USER_NAME = os.getenv('TARANTOOL_USER_NAME')
178
        file_cfg.TARANTOOL_USER_PASSWORD = os.getenv('TARANTOOL_USER_PASSWORD')
179
        file_cfg.TARANTOOL_SLAB_ALLOC_ARENA = os.getenv('TARANTOOL_SLAB_ALLOC_ARENA')
180
        file_cfg.TARANTOOL_SLAB_ALLOC_FACTOR = os.getenv('TARANTOOL_SLAB_ALLOC_FACTOR')
181
        file_cfg.TARANTOOL_SLAB_ALLOC_MINIMAL = os.getenv('TARANTOOL_SLAB_ALLOC_MINIMAL')
182
        file_cfg.TARANTOOL_SLAB_ALLOC_MAXIMAL = os.getenv('TARANTOOL_SLAB_ALLOC_MAXIMAL')
183
        file_cfg.TARANTOOL_PORT = os.getenv('TARANTOOL_PORT')
184
        file_cfg.TARANTOOL_FORCE_RECOVERY = os.getenv('TARANTOOL_FORCE_RECOVERY')
185
        file_cfg.TARANTOOL_LOG_FORMAT = os.getenv('TARANTOOL_LOG_FORMAT')
186
        file_cfg.TARANTOOL_LOG_LEVEL = os.getenv('TARANTOOL_LOG_LEVEL')
187
        file_cfg.TARANTOOL_WAL_MODE = os.getenv('TARANTOOL_WAL_MODE')
188
        file_cfg.TARANTOOL_REPLICATION_SOURCE = os.getenv('TARANTOOL_REPLICATION_SOURCE')
189
        file_cfg.TARANTOOL_REPLICATION = os.getenv('TARANTOOL_REPLICATION')
190
        file_cfg.TARANTOOL_SNAPSHOT_PERIOD = os.getenv('TARANTOOL_SNAPSHOT_PERIOD')
191
        file_cfg.TARANTOOL_MEMTX_MEMORY = os.getenv('TARANTOOL_MEMTX_MEMORY')
192
        file_cfg.TARANTOOL_CHECKPOINT_INTERVAL = os.getenv('TARANTOOL_CHECKPOINT_INTERVAL')
193
        file_cfg.TARANTOOL_MEMTX_MIN_TUPLE_SIZE = os.getenv('TARANTOOL_MEMTX_MIN_TUPLE_SIZE')
194
        file_cfg.TARANTOOL_MEMTX_MAX_TUPLE_SIZE = os.getenv('TARANTOOL_MEMTX_MAX_TUPLE_SIZE')
195

196
        write_config(file_cfg)
197
    else
198
        log.info("Loading existing configuration file: " .. CFG_FILE_PATH)
199

200
        file_cfg = read_config()
201
    end
202

203
    local user_name = file_cfg.TARANTOOL_USER_NAME or
204
        os.getenv('TARANTOOL_USER_NAME') or 'guest'
205
    local user_password = file_cfg.TARANTOOL_USER_PASSWORD or
206
        os.getenv('TARANTOOL_USER_PASSWORD')
207

208

209
    local cfg = override or {}
210
    -- Placeholders for deprecated options
211
    cfg.slab_alloc_arena = tonumber(file_cfg.TARANTOOL_SLAB_ALLOC_ARENA) or
212
        override.slab_alloc_arena
213
    cfg.slab_alloc_maximal = tonumber(file_cfg.TARANTOOL_SLAB_ALLOC_MAXIMAL) or
214
        override.slab_alloc_maximal
215
    cfg.slab_alloc_minimal = tonumber(file_cfg.TARANTOOL_SLAB_ALLOC_MINIMAL) or
216
        override.slab_alloc_minimal
217
    cfg.snapshot_period = tonumber(file_cfg.TARANTOOL_SNAPSHOT_PERIOD) or
218
        override.snapshot_period
219
    -- Replacements for deprecated options
220
    cfg.memtx_memory = tonumber(file_cfg.TARANTOOL_MEMTX_MEMORY) or
221
        override.memtx_memory
222
    cfg.memtx_min_tuple_size = tonumber(file_cfg.TARANTOOL_MEMTX_MIN_TUPLE_SIZE) or
223
        override.memtx_min_tuple_size
224
    cfg.memtx_max_tuple_size = tonumber(file_cfg.TARANTOOL_MEMTX_MAX_TUPLE_SIZE) or
225
        override.memtx_max_tuple_size
226
    cfg.checkpoint_interval = tonumber(file_cfg.TARANTOOL_CHECKPOINT_INTERVAL) or
227
        override.checkpoint_interval
228
    -- Deprecated options with default values
229
    local choice = choose_option('memtx_dir', 'snap_dir', override)
230
    cfg[choice] = override[choice] or '/var/lib/tarantool'
231

232
    -- Remaining configuration
233
    cfg.slab_alloc_factor = tonumber(file_cfg.TARANTOOL_SLAB_ALLOC_FACTOR) or
234
        override.slab_alloc_factor
235
    cfg.listen = tonumber(file_cfg.TARANTOOL_PORT) or
236
        override.listen or TARANTOOL_DEFAULT_PORT
237
    cfg.wal_mode = file_cfg.TARANTOOL_WAL_MODE or
238
        override.wal_mode
239

240
    cfg.force_recovery = file_cfg.TARANTOOL_FORCE_RECOVERY == 'true'
241
    cfg.log_format = file_cfg.TARANTOOL_LOG_FORMAT or 'plain'
242
    cfg.log_level = tonumber(file_cfg.TARANTOOL_LOG_LEVEL) or 5
243

244
    cfg.wal_dir = override.wal_dir or '/var/lib/tarantool'
245
    cfg.vinyl_dir = override.vinyl_dir or '/var/lib/tarantool'
246
    cfg.pid_file = override.pid_file or '/var/run/tarantool/tarantool.pid'
247

248
    local choice = choose_option('TARANTOOL_REPLICATION', 'TARANTOOL_REPLICATION_SOURCE', file_cfg)
249
    local replication_source_table = parse_replication_source(file_cfg[choice],
250
                                                              user_name,
251
                                                              user_password)
252

253
    if replication_source_table then
254
        cfg.replication = replication_source_table
255
    else
256
        local choice = choose_option('replication', 'replication_source', override)
257
        cfg[choice] = override[choice]
258
    end
259

260
    log.info("Config:\n" .. yaml.encode(cfg))
261

262
    orig_cfg(cfg)
263

264
    box.once('tarantool-entrypoint', function ()
265
        if first_run then
266
            log.info("Initializing database")
267

268
            create_user(user_name, user_password)
269
        end
270
    end)
271

272
    console.listen(CONSOLE_SOCKET_PATH)
273

274
    local metrics_port = tonumber(os.getenv('TARANTOOL_PROMETHEUS_DEFAULT_METRICS_PORT')) or 0
275
    if metrics_port > 0 then
276
        require('metrics').enable_default_metrics()
277
        local prometheus = require('metrics.plugins.prometheus')
278
        local httpd = require('http.server').new('0.0.0.0', metrics_port)
279
        httpd:route( { path = '/metrics' }, prometheus.collect_http)
280
        httpd:start()
281
    end
282
end
283

284
box.cfg = wrapper_cfg
285

286
-- re-run the script passed as parameter with all arguments that follow
287
execute_script = arg[1]
288
if execute_script == nil then
289
    box.cfg {}
290

291
    if term.isatty(io.stdout) then
292
        console.start()
293
        os.exit(0)
294
    end
295
else
296
    narg = 0
297
    while true do
298
        arg[narg] = arg[narg + 1]
299
        if arg[narg] == nil then
300
            break
301
        end
302
        narg = narg + 1
303
    end
304

305
    dofile(execute_script)
306
end
307

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.