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