gitlab: Introduce macro library
[slapos.git] / software / gitlab / instance-gitlab.cfg.in
1 # GitLab instance
2 # NOTE instance/software layout is inspired by gitlab omnibus
3 # NOTE all services are interconnected via unix sockets - because of easier
4 #      security and performance reasons (unix has 2x less latency and more
5 #      throughput compared to tcp over loopback).
6 [buildout]
7 extends = {{ gitlab_parameters_cfg }}
8 parts =
9     directory
10
11 #   gitlab-<prog>
12 # ? mailroom
13 {% set gitlab_progv = 'rails rake unicorn sidekiq' .split() %}
14 {% for prog in gitlab_progv %}
15     gitlab-{{ prog }}
16 {% endfor %}
17
18     gitlab-work
19     gitlab-shell-work
20
21     service-postgresql
22     service-redis
23
24     service-cron
25
26 # std stuff for slapos instance
27 eggs-directory = {{ eggs_directory }}
28 develop-eggs-directory = {{ develop_eggs_directory }}
29 offline = true
30
31
32 ##################################
33 #   GitLab instance parameters   #
34 ##################################
35
36 [instance-parameter]
37 # std stuff to fetch slapos instance parameters
38 recipe  = slapos.cookbook:slapconfiguration
39 computer= ${slap-connection:computer-id}
40 partition=${slap-connection:partition-id}
41 url     = ${slap-connection:server-url}
42 key     = ${slap-connection:key-file}
43 cert    = ${slap-connection:cert-file}
44
45 # autogenerated gitlab instance parameters
46 <= gitlab-parameters
47
48
49
50 #############################
51 #   GitLab instance setup   #
52 #############################
53
54 # 1. directories
55 [directory]
56 recipe  = slapos.cookbook:mkdirectory
57 home    = ${buildout:directory}
58 bin     = ${:home}/bin
59 etc     = ${:home}/etc
60 var     = ${:home}/var
61 log     = ${:var}/log
62 run     = ${:var}/run
63 srv     = ${:home}/srv
64 # slapos startup/service/promise scripts live here:
65 startup = ${:etc}/run
66 service = ${:etc}/service
67 promise = ${:etc}/promise
68
69 # gitlab: etc/ log/ ...
70 [gitlab-dir]
71 recipe  = slapos.cookbook:mkdirectory
72 etc     = ${directory:etc}/gitlab
73 log     = ${directory:log}/gitlab
74
75 var     = ${directory:var}/gitlab
76 tmp     = ${:var}/tmp
77 uploads = ${:var}/uploads
78 assets  = ${:var}/assets
79 backup  = ${directory:var}/backup
80
81 [gitlab-repo-dir]
82 recipe  = slapos.cookbook:mkdirectory
83 repositories    = ${directory:var}/repositories
84 # gitlab wants it to be drwxrws---
85 # FIXME setting such mode with :mkdirectory is not possible, because mkdir(2)
86 # does & 0777 and also there is umask. So we workaround:
87 [gitlab-repo-xdir]
88 recipe  = plone.recipe.command
89 stop-on-error = yes
90 repositories = ${gitlab-repo-dir:repositories}
91 command = chmod 02770 ${:repositories}
92
93 [gitlab]
94 etc     = ${gitlab-dir:etc}
95 log     = ${gitlab-dir:log}
96 var     = ${gitlab-dir:var}
97 tmp     = ${gitlab-dir:tmp}
98 uploads = ${gitlab-dir:uploads}
99 assets  = ${gitlab-dir:assets}
100 backup  = ${gitlab-dir:backup}
101 repositories = ${gitlab-repo-xdir:repositories}
102
103
104 # gitlab-shell: etc/ log/ gitlab_shell_secret ...
105 [gitlab-shell-dir]
106 recipe  = slapos.cookbook:mkdirectory
107 etc     = ${directory:etc}/gitlab-shell
108 log     = ${directory:log}/gitlab-shell
109
110 [gitlab-shell]
111 etc     = ${gitlab-shell-dir:etc}
112 log     = ${gitlab-shell-dir:log}
113 secret  = ${secrets:secrets}/gitlab_shell_secret
114
115
116 # place to keep all secrets
117 [secrets]
118 recipe  = slapos.cookbook:mkdirectory
119 secrets = ${directory:var}/secrets
120 mode    = 0700
121
122
123
124
125 # 2. configuration files
126 [etc-template]
127 recipe  = slapos.recipe.template:jinja2
128 extensions = jinja2.ext.do
129 mode    = 0640
130 import-list =
131     rawfile macrolib.cfg.in     {{ macrolib_cfg_in }}
132 context =
133     raw     autogenerated       # This file was autogenerated. (DO NOT EDIT - changes will be lost)
134     section instance_parameter  instance-parameter
135     ${:context-extra}
136 context-extra =
137
138 [gitlab-etc-template]
139 <= etc-template
140 rendered= ${gitlab:etc}/${:_buildout_section_name_}
141
142
143 [config.ru]
144 <= gitlab-etc-template
145 template = {{ config_ru_in }}
146
147 [database.yml]
148 <= gitlab-etc-template
149 template= {{ database_yml_in }}
150
151 [gitlab-shell-config.yml]
152 <= etc-template
153 template= {{ gitlab_shell_config_yml_in }}
154 rendered= ${gitlab-shell:etc}/config.yml
155
156 [gitlab.yml]
157 <= gitlab-etc-template
158 template= {{ gitlab_yml_in }}
159
160 [rack_attack.rb]
161 <= gitlab-etc-template
162 template = {{ rack_attack_rb_in }}
163
164 [resque.yml]
165 <= gitlab-etc-template
166 template= {{ resque_yml_in }}
167
168 [smtp_settings.rb]
169 <= gitlab-etc-template
170 template= {{ smtp_settings_rb_in }}
171
172 [unicorn.rb]
173 <= gitlab-etc-template
174 template = {{ unicorn_rb_in }}
175
176
177
178 # 3. bin/
179 #   gitlab-<prog>
180 [gitlab-bin]
181 recipe  = slapos.cookbook:wrapper
182 wrapper-path = ${directory:bin}/${:_buildout_section_name_}
183 environment  =
184     BUNDLE_GEMFILE = {{ gitlab_repository_location }}/Gemfile
185     RAILS_ENV = production
186
187 # NOTE sys.argv[1:] implicitly appended
188 # (by slapos.recipe.librecipe.execute.generic_exec() at runtime)
189 command-line =
190     {{ bundler_4gitlab }} exec sh -c
191     'cd ${gitlab-work:location} && ${:prog} "$@"' ${:prog}
192
193 {% for prog in gitlab_progv %}
194 [gitlab-{{ prog }}]
195 <= gitlab-bin
196 prog    = {{ prog }}
197 {% endfor %}
198
199
200 # 4. gitlab- & gitlab-shell- work directories
201 #
202 # Gitlab/Rails operation is tightened that config/ lives inside code, which goes
203 # against having ability to create several instances configured differently
204 # from 1 SR.
205 #
206 # One possibility to overcome this could be to make another Gitlab root
207 # symbolically linked to original SR _and_ several configuration files
208 # symbolically linked to instance place. Unfortunately this does not work -
209 # Ruby determines realpath on module import and Gitlab and Rails lookup config
210 # files relative to imported modules.
211 #
212 # we clone cloned gitlab and add proper links to vendor/bundle and instance
213 # config files.
214 # XXX there is no need for full clone - we only need worktree checkout (a-la `git
215 # worktree add`, but without creating files in original clone)
216 #
217 # This way Gitlab/Rails still think they work in 1 code / 1 instance way,
218 # and we can reuse SR.
219 # XXX better do such tricks with bind mounting, but that requires user namespaces
220
221 [work-base]
222 recipe  = plone.recipe.command
223 stop-on-error = yes
224 location = ${directory:home}/${:_buildout_section_name_}
225 command =
226 # make sure we start from well-defined empty state
227 # (needed e.g. if previous install failed in the middle)
228     rm -rf ${:location}  &&
229 # init work repository and add `software` remote pointing to main repo in SR software/...
230     {{ git }} init ${:location}  &&
231     cd ${:location}  &&
232     {{ git }} remote add software ${:software}  &&
233     ${:update-command}
234
235 update-command =
236     cd ${:location}  &&
237     {{ git }} fetch software  &&
238     {{ git }} reset --hard `cd ${:software} && {{ git }} rev-parse HEAD`  &&
239     ${:tune-command}
240
241
242 # NOTE there is no need to link/create .gitlab_shell_secret - we will set path to it
243 # in gitlab & gitlab-shell configs, and gitlab creates it on its first start
244 [gitlab-work]
245 <= work-base
246 software = {{ gitlab_repository_location }}
247 tune-command =
248 # secret* config.ru tmp/ log/
249     rm -f .secret  &&
250     rm -f config.ru  &&
251     rm -rf log tmp  &&
252     ln -sf ${secrets:secrets}/gitlab_rails_secret .secret  &&
253     ln -sf ${config.ru:rendered} config.ru  &&
254     ln -sf ${gitlab:log} log  &&
255     ln -sf ${gitlab:tmp} tmp  &&
256 # config/
257     cd config  &&
258     ln -sf ${unicorn.rb:rendered} unicorn.rb  &&
259     ln -sf ${gitlab.yml:rendered} gitlab.yml  &&
260     ln -sf ${database.yml:rendered} database.yml  &&
261     ln -sf ${resque.yml:rendered} resque.yml  &&
262     ln -sf ${secrets:secrets}/gitlab_secrets.yml secrets.yml  &&
263 # config/initializers/
264     cd initializers  &&
265     ln -sf ${rack_attack.rb:rendered} rack_attack.rb  &&
266     ln -sf ${smtp_settings.rb:rendered} smtp_settings.rb  &&
267 # public/
268     cd ../../public  &&
269     rm -rf uploads assets  &&
270     ln -sf ${gitlab:uploads} uploads  &&
271     ln -sf ${gitlab:assets} assets  &&
272     true
273
274
275 # ----//---- for gitlab-shell
276 [gitlab-shell-work]
277 <= work-base
278 software = {{ gitlab_shell_repository_location }}
279
280 tune-command =
281     ln -sf ${gitlab-shell-config.yml:rendered}   config.yml  &&
282     true
283
284
285
286 # 5. services
287
288 # [promise-<something>] to generate promise wrapper <something>
289 [promise-wrapper]
290 recipe  = slapos.cookbook:wrapper
291 wrapper-path = !py! '${directory:promise}/' + '${:_buildout_section_name_}'[8:]
292
293
294
295
296 #####################
297 #   Postgresql db   #
298 #####################
299
300 # XXX gitlab-omnibus also tunes:
301 # - shared_buffers
302 # - work_mem
303 # - checkpoint_*
304 # - effective_check_size
305 # - lc_* en_US.UTF-8 -> C  (?)
306 [service-postgresql]
307 recipe  = slapos.cookbook:postgres
308 bin     = {{ postgresql_location }}/bin
309 services= ${directory:service}
310
311 dbname  = gitlabhq_production
312 # NOTE db name must match to what was used in KVM on lab.nexedi.com (restore script grants access to this user)
313 superuser = gitlab-psql
314 # no password - pgsql will listen only on unix sockets (see below) thus access
315 # is protected with filesystem-level permissions.
316 # ( besides, if we use slapos.cookbook:generate.password and do `password = ...`
317 #   the password is stored in plain text in .installed and thus becomes insecure )
318 password=
319
320 pgdata-directory = ${directory:srv}/postgresql
321
322 # empty addresses - listen only on unix socket
323 ipv4    = !py!set([])
324 ipv6    = !py!set([])
325 ipv6-random =
326 port    =
327
328 depend  =
329     ${promise-postgresql:recipe}
330
331 [promise-postgresql]
332 <= promise-wrapper
333 command-line =
334     {{ postgresql_location }}/bin/psql
335         -h ${service-postgresql:pgdata-directory}
336         -U ${service-postgresql:superuser}
337         -d ${service-postgresql:dbname}
338         -c '\q'
339
340 # postgresql logs to stdout/stderr - logs are handled by slapos not us
341 # [logrotate-entry-postgresql]
342
343
344 #############
345 #   Redis   #
346 #############
347 [redis]
348 recipe  = slapos.cookbook:mkdirectory
349 srv     = ${directory:srv}/redis
350 log     = ${directory:log}/redis
351
352
353 [service-redis]
354 recipe  = slapos.cookbook:redis.server
355 wrapper = ${directory:service}/redis
356 promise_wrapper = ${directory:promise}/redis
357
358 server_dir  = ${redis:srv}
359 config_file = ${directory:etc}/redis.conf
360 log_file    = ${redis:log}/redis.log
361 pid_file    = ${directory:run}/redis.pid
362 use_passwd  = false
363 unixsocket  = ${:server_dir}/redis.socket
364 # port = 0 means "don't listen on TCP at all" - listen only on unix socket
365 ipv6    = ::1
366 port    = 0
367
368 server_bin  = {{ redis_binprefix }}/redis-server
369 depend  =
370     ${logrotate-entry-redis:recipe}
371
372
373 # NOTE slapos.cookbook:redis.server setups promise automatically
374
375 [logrotate-entry-redis]
376 <= logrotate-entry
377 log     = ${redis:log}/*.log
378
379
380
381 #############
382 #   cron    #
383 #############
384 [cron-dir]
385 recipe  = slapos.cookbook:mkdirectory
386 cron.d  = ${directory:etc}/cron.d
387 crontabs= ${directory:srv}/cron/crontabs
388 cronstamps = ${directory:var}/cron/cronstamps
389 log     = ${directory:log}/cron
390
391 [service-cron]
392 recipe  = slapos.cookbook:cron
393 binary  = ${directory:service}/crond
394 cron-entries    = ${cron-dir:cron.d}
395 crontabs        = ${cron-dir:crontabs}
396 cronstamps      = ${cron-dir:cronstamps}
397 catcher         = ${cron-simplelogger:wrapper}
398
399 dcrond-binary   = {{ dcron_bin }}
400
401 depends =
402     ${logrotate-entry-cron:recipe}
403
404 # "mailer" that cron uses to emit messages to logfile
405 [cron-simplelogger]
406 recipe  = slapos.cookbook:simplelogger
407 wrapper = ${directory:bin}/${:_buildout_section_name_}
408 log     = ${cron-dir:log}/cron.log
409
410
411 # base entry for clients who registers to cron
412 [cron-entry]
413 recipe  = slapos.cookbook:cron.d
414 # name  = <section-name>.strip_prefix('cron-entry-')
415 # XXX len() is not available in !py! - 11 hardcoded
416 name    = !py!'${:_buildout_section_name_}' [11:]
417 # NOTE _not_ ${service-cron:cron-entries}  - though the value is the same we do
418 # not want service-cron to be instantiated just if a cron-entry is registered.
419 cron-entries = ${cron-dir:cron.d}
420
421 # cron logs are also rotated
422 [logrotate-entry-cron]
423 <= logrotate-entry
424 log     = ${cron-dir:log}/*.log
425
426
427 #######################################
428 #   logrotate base for all services   #
429 #######################################
430 [logrotate-dir]
431 recipe  = slapos.cookbook:mkdirectory
432 srv     = ${directory:srv}/logrotate
433 entries = ${directory:etc}/logrotate.d
434
435 [logrotate]
436 recipe  = slapos.cookbook:logrotate
437 wrapper = ${directory:bin}/${:_buildout_section_name_}
438 conf    = ${directory:etc}/logrotate.conf
439 logrotate-entries   = ${logrotate-dir:entries}
440 state-file  = ${logrotate-dir:srv}/logrotate.status
441
442 logrotate-binary    = {{ logrotate_bin }}
443 gzip-binary     = {{ gzip_bin }}
444 gunzip-binary   = {{ gunzip_bin }}
445
446 depend  = ${cron-entry-logrotate:recipe}
447
448
449 # base entry for clients who registers to logrotate
450 [logrotate-entry]
451 recipe  = slapos.cookbook:logrotate.d
452 logrotate-entries   = ${logrotate:logrotate-entries}
453 # name  = <section-name>.strip_prefix('logrotate-entry-')
454 # XXX len is not available in !py! - 16 hardcoded
455 name    = !py!'${:_buildout_section_name_}'[16:]
456 # NOTE frequency is hardcoded to `daily` in slapos.cookbook:logrotate.d
457 # NOTE backup is also used to add custom logrotate options (hack)
458 backup  = ...
459 # TODO settle whether we need/want olddir or not
460     noolddir
461 # override create emitted by slapos.cookbook:logrotate.d
462     nocreate
463 # do not move log file and this way we do not need to signal its program to
464 # reopen the log. There are a lot of bugs when on such reopen / restart /
465 # graceful-restart something bad happens. Even if copytruncate is a bit racy
466 # and can loose some data, it is better to keep the system the stable way.
467     copytruncate
468
469
470 # hook logrotate into cron
471 [cron-entry-logrotate]
472 <= cron-entry
473 time    = daily
474 command = ${logrotate:wrapper}