system-configuration/modules/config/cuirass.scm

cuirass.scm

1
;;; Tyreunom's system administration and configuration tools.
2
;;;
3
;;; Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
4
;;;
5
;;; This program is free software: you can redistribute it and/or modify
6
;;; it under the terms of the GNU General Public License as published by
7
;;; the Free Software Foundation, either version 3 of the License, or
8
;;; (at your option) any later version.
9
;;;
10
;;; This program is distributed in the hope that it will be useful,
11
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
;;; GNU General Public License for more details.
14
;;;
15
;;; You should have received a copy of the GNU General Public License
16
;;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18
;;
19
;; Cuirass service type and related configurations (web, ...)
20
;;
21
22
(define-module (config cuirass)
23
  #:use-module (guix gexp)
24
  #:use-module (gnu services)
25
  #:use-module (gnu services base)
26
  #:use-module (gnu services cuirass)
27
  #:use-module (gnu services web)
28
  #:export (cuirass-services
29
            %cuirass-extra-content))
30
31
(define %publish-port 3000)
32
(define %publish-url
33
  (string-append "http://localhost:" (number->string %publish-port)))
34
35
(define* (guix-input name #:optional (branch "master"))
36
  `((#:name . ,name)
37
    (#:url . "https://git.savannah.gnu.org/git/guix.git")
38
    (#:load-path . ".")
39
    (#:branch . ,branch)
40
    (#:no-compile? . #t)))
41
42
(define %cuirass-specifications
43
  #~(list
44
      '((#:name . "guix-modular-master")
45
        (#:load-path-inputs . ())
46
        (#:package-path-inputs . ())
47
        (#:proc-input . "guix-modular")
48
        (#:proc-file . "build-aux/cuirass/guix-modular.scm")
49
        (#:proc . cuirass-jobs)
50
        (#:proc-args (systems . ("x86_64-linux")))
51
        (#:inputs . (#$(guix-input "guix-modular" "master")))
52
	(#:build-outputs . ()))
53
      '((#:name . "master")
54
        (#:load-path-inputs . ())
55
        (#:package-path-inputs . ())
56
        (#:proc-input . "guix")
57
        (#:proc-file . "build-aux/cuirass/gnu-system.scm")
58
        (#:proc . cuirass-jobs)
59
        (#:proc-args (subset . "all") (systems . ("x86_64-linux")))
60
        (#:inputs . (#$(guix-input "guix" "master")))
61
	(#:build-outputs . ()))))
62
63
(define (publish-locations url)
64
  "Return the nginx location blocks for 'guix publish' running on URL."
65
  (list (nginx-location-configuration
66
         (uri "/nix-cache-info")
67
         (body
68
          (list
69
           (string-append
70
            "proxy_pass " url "/nix-cache-info;")
71
           ;; Cache this file since that's always the first thing we ask
72
           ;; for.
73
           "proxy_cache static;"
74
           "proxy_cache_valid 200 100d;"     ; cache hits for a looong time.
75
           "proxy_cache_valid any 5m;"       ; cache misses/others for 5 min.
76
           "proxy_ignore_client_abort on;"
77
78
           ;; We need to hide and ignore the Set-Cookie header to enable
79
           ;; caching.
80
           "proxy_hide_header    Set-Cookie;"
81
           "proxy_ignore_headers Set-Cookie;")))
82
83
        (nginx-location-configuration
84
         (uri "/nar/")
85
         (body
86
          (list
87
           (string-append "proxy_pass " url ";")
88
           "client_body_buffer_size 256k;"
89
90
           ;; Be more tolerant of delays when fetching a nar.
91
           "proxy_read_timeout 60s;"
92
           "proxy_send_timeout 60s;"
93
94
           ;; Enable caching for nar files, to avoid reconstructing and
95
           ;; recompressing archives.
96
           "proxy_cache nar;"
97
           "proxy_cache_valid 200 30d;"           ; cache hits for 1 month
98
           "proxy_cache_valid 504 3m;" ; timeout, when hydra.gnu.org is overloaded
99
           "proxy_cache_valid any 1h;" ; cache misses/others for 1h.
100
101
           "proxy_ignore_client_abort on;"
102
103
           ;; Nars are already compressed.
104
           "gzip off;"
105
106
           ;; We need to hide and ignore the Set-Cookie header to enable
107
           ;; caching.
108
           "proxy_hide_header    Set-Cookie;"
109
           "proxy_ignore_headers Set-Cookie;"
110
111
           ;; Provide a 'content-length' header so that 'guix
112
           ;; substitute-binary' knows upfront how much it is downloading.
113
           ;; "add_header Content-Length $body_bytes_sent;"
114
           )))
115
116
        (nginx-location-configuration
117
         (uri "~ \\.narinfo$")
118
         (body
119
          (list
120
           ;; Since 'guix publish' has its own caching, and since it relies
121
           ;; on the atime of cached narinfos to determine whether a
122
           ;; narinfo can be removed from the cache, don't do any caching
123
           ;; here.
124
           (string-append "proxy_pass " url ";")
125
126
           ;; For HTTP pipelining.  This has a dramatic impact on
127
           ;; performance.
128
           "client_body_buffer_size 128k;"
129
130
           ;; Narinfos requests are short, serve many of them on a
131
           ;; connection.
132
           "keepalive_requests 600;"
133
134
           ;; Do not tolerate slowness of hydra.gnu.org when fetching
135
           ;; narinfos: better return 504 quickly than wait forever.
136
           "proxy_connect_timeout 2s;"
137
           "proxy_read_timeout 2s;"
138
           "proxy_send_timeout 2s;"
139
140
           ;; 'guix publish --ttl' produces a 'Cache-Control' header for
141
           ;; use by 'guix substitute'.  Let it through rather than use
142
           ;; nginx's "expire" directive since the expiration time defined
143
           ;; by 'guix publish' is the right one.
144
           "proxy_pass_header Cache-Control;"
145
146
           "proxy_ignore_client_abort on;"
147
148
           ;; We need to hide and ignore the Set-Cookie header to enable
149
           ;; caching.
150
           "proxy_hide_header    Set-Cookie;"
151
           "proxy_ignore_headers Set-Cookie;")))
152
153
        (nginx-location-configuration
154
         (uri "/log/")
155
         (body
156
          (list
157
           (string-append "proxy_pass " url ";")
158
159
           ;; Enable caching for build logs.
160
           "proxy_cache logs;"
161
           "proxy_cache_valid 200 60d;"           ; cache hits.
162
           "proxy_cache_valid 504 3m;" ; timeout, when hydra.gnu.org is overloaded
163
           "proxy_cache_valid any 1h;" ; cache misses/others.
164
165
           "proxy_ignore_client_abort on;"
166
167
           ;; We need to hide and ignore the Set-Cookie header to enable
168
           ;; caching.
169
           "proxy_hide_header    Set-Cookie;"
170
           "proxy_ignore_headers Set-Cookie;")))
171
172
        ;; Content-addressed files served by 'guix publish'.
173
        (nginx-location-configuration
174
         (uri "/file/")
175
         (body
176
          (list
177
           (string-append "proxy_pass " url ";")
178
179
           "proxy_cache cas;"
180
           "proxy_cache_valid 200 200d;"          ; cache hits
181
           "proxy_cache_valid any 5m;"            ; cache misses/others
182
183
           "proxy_ignore_client_abort on;")))))
184
185
(define (cuirass-locations publish-url)
186
  "Return nginx location blocks with 'guix publish' reachable at
187
PUBLISH-URL."
188
  (append (publish-locations publish-url)
189
          (list
190
           ;; Cuirass.
191
           (nginx-location-configuration
192
            (uri "/")
193
            (body (list "proxy_pass http://localhost:8081;")))
194
           (nginx-location-configuration
195
            (uri "~ ^/admin")
196
            (body
197
             (list "if ($ssl_client_verify != SUCCESS) { return 403; } proxy_pass http://localhost:8081;")))
198
199
           (nginx-location-configuration
200
            (uri "/static")
201
            (body
202
             (list
203
              "proxy_pass http://localhost:8081;"
204
              ;; Let browsers cache this for a while.
205
              "expires 10d;"
206
              ;; Cache quite aggressively.
207
              "proxy_cache static;"
208
              "proxy_cache_valid 200 5d;"
209
              "proxy_cache_valid any 10m;"
210
              "proxy_ignore_client_abort on;")))
211
212
           (nginx-location-configuration          ;certbot
213
            (uri "/.well-known")
214
            (body (list "root /var/www;")))
215
216
           (nginx-location-configuration
217
            (uri "/berlin.guixsd.org-export.pub")
218
            (body
219
             (list "root /var/www/guix;"))))))
220
221
(define %cuirass-extra-content
222
  (list
223
    "default_type application/octet-stream;"
224
    "sendfile on;"
225
    "sendfile_max_chunk 1m;"
226
    "keepalive_timeout  65;"
227
    "proxy_http_version 1.1;"
228
229
    ;; cache for nar files
230
    "proxy_cache_path /var/cache/nginx/nar"
231
    "     levels=2"
232
    "     inactive=8d"       ; inactive keys removed after 8d
233
    "     keys_zone=nar:4m"  ; nar cache meta data: ~32K keys
234
    "     max_size=10g;"     ; total cache data size max
235
236
    ;; cache for content-addressed-files
237
    "proxy_cache_path /var/cache/nginx/cas"
238
    "     levels=2"
239
    "     inactive=180d"     ; inactive keys removed after 180d
240
    "     keys_zone=cas:8m"  ; nar cache meta data: ~64K keys
241
    "     max_size=50g;"         ; total cache data size max
242
243
    ;; cache for build logs
244
    "proxy_cache_path /var/cache/nginx/logs"
245
    "     levels=2"
246
    "     inactive=60d"          ; inactive keys removed after 60d
247
    "     keys_zone=logs:8m"     ; narinfo meta data: ~64K keys
248
    "     max_size=4g;"          ; total cache data size max
249
250
    ;; cache for static data
251
    "proxy_cache_path /var/cache/nginx/static"
252
    "     levels=1"
253
    "     inactive=10d"         ; inactive keys removed after 10d
254
    "     keys_zone=static:1m"   ; nar cache meta data: ~8K keys
255
    "     max_size=200m;"        ; total cache data size max
256
257
    ;; Cache timeouts for a little while to avoid increasing pressure.
258
    "proxy_cache_valid 504 30s;"))
259
260
(define (cuirass-services root certificate key)
261
  (list
262
    (simple-service 'guix-http-server nginx-service-type
263
      (list (nginx-server-configuration
264
              (ssl-certificate certificate)
265
              (ssl-certificate-key key)
266
              (listen '("443 ssl http2" "[::]:443 ssl http2"))
267
              (server-name (list root))
268
              (locations (cuirass-locations %publish-url)))))
269
    (service guix-publish-service-type
270
      (guix-publish-configuration
271
        (compression '(("lzip" 3) ("gzip" 3)))
272
        (port %publish-port)))
273
    (service cuirass-service-type
274
      (cuirass-configuration
275
        (ttl (* 30 24 3600))
276
        (specifications %cuirass-specifications)))))
277