about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCollin J. Doering2024-05-31 09:08:19 -0400
committerCollin J. Doering2024-05-31 09:19:17 -0400
commitb4dda63855d5b1fb5dd18e78dfe0ca1b59ddbb15 (patch)
tree0cba21247b0fa701fb7da8c42dc6c6d992c09fa1
parent10c47f382699f41048ca790933977121c0134e54 (diff)
downloadguix-north-america-b4dda63855d5b1fb5dd18e78dfe0ca1b59ddbb15.tar.gz
balg02: Initial implementation of Guix build farm
* .guix/guix-na/config/balg02.scm (%automation-user): Removed variable (only used in one place).
(%cuirass-specs): New variable. (Initial) Cuirass specifications that are run by the guix-na build farm.
(publish-robots.txt): New variable. Used in nginx configuration.
(publish-locations): New function. Defines nginx publish locations (used for http and https servers).
(balg02-locations): New function. Defines nginx publish locations used for guix-na.
(%publish-url): New variable. String representing local publish URL.
(%tls-settings): New variable. Captures nginx tls settings used in nginx configuration.
(le): New function. Generates lets encrypt path given a host and optionally a private key.
(languages-to-accept): New variable. Languages for i8ln.
(accept-languages): New function.
(%balg02-servers): New variable. balg02 nginx servers.
(%extra-content): New variable. Extra nginx configuration content.
(%nginx-configuration): New variable. Capture nginx configuration given all previous helper
functions and variables.
(%nginx-cache-activation): New variable. Service the ensures /var/cache/nginx exists on the
first run.
(%nginx-deploy-hook): New variable. Hook used upon cerbot certificate updates.
(balg02 (packages)): Add btrfs-progs.
(balg02): Remove root ssh key (not necessary as ssh root login is disabled).
(balg02 (services)): Add cuirass, certbot, nginx, and guix-publish services.
-rw-r--r--.guix/guix-na/config/balg02.scm419
1 files changed, 413 insertions, 6 deletions
diff --git a/.guix/guix-na/config/balg02.scm b/.guix/guix-na/config/balg02.scm
index ab17951..fb211ea 100644
--- a/.guix/guix-na/config/balg02.scm
+++ b/.guix/guix-na/config/balg02.scm
@@ -22,14 +22,400 @@
   #:use-module (gnu system)
   #:use-module (gnu packages bash)
   #:use-module (gnu packages shells)
+  #:use-module (gnu packages web)
   #:use-module (gnu services base)
   #:use-module (gnu services cuirass)
+  #:use-module (gnu services certbot)
   #:use-module (gnu services networking)
   #:use-module (gnu services ssh)
   #:use-module (gnu services web)
   #:export (balg02 %system))
 
-(define %automation-user "auto")
+(define %cuirass-specs
+  #~(list (specification
+             (name "guix")
+             (priority 0)
+             (build '(channels guix))
+             (channels %default-channels))))
+
+;; Taken from: https://git.savannah.gnu.org/cgit/guix/maintenance.git/tree/hydra/nginx/berlin.scm
+(define publish-robots.txt
+  ;; Try to prevent good-faith crawlers from downloading substitutes.  Allow
+  ;; indexing the root—which is expected to be static or cheap—to remain visible
+  ;; in search engine results for, e.g., ‘Guix CI’.
+  "\
+User-agent: *\r
+Disallow: /\r
+Allow: /$\r
+\r
+")
+
+(define (publish-locations url)
+  "Return the nginx location blocks for 'guix publish' running on URL."
+  (list (nginx-location-configuration
+         (uri "/nix-cache-info")
+         (body
+          (list
+           (string-append
+            "proxy_pass " url "/nix-cache-info;")
+           ;; Cache this file since that's always the first thing we ask
+           ;; for.
+           "proxy_cache static;"
+           "proxy_cache_valid 200 100d;"     ; cache hits for a looong time.
+           "proxy_cache_valid any 5m;"       ; cache misses/others for 5 min.
+           "proxy_ignore_client_abort on;"
+
+           ;; We need to hide and ignore the Set-Cookie header to enable
+           ;; caching.
+           "proxy_hide_header    Set-Cookie;"
+           "proxy_ignore_headers Set-Cookie;")))
+
+        (nginx-location-configuration
+         (uri "/nar/")
+         (body
+          (list
+           (string-append "proxy_pass " url ";")
+           "client_body_buffer_size 256k;"
+
+           ;; Be more tolerant of delays when fetching a nar.
+           "proxy_read_timeout 60s;"
+           "proxy_send_timeout 60s;"
+
+           ;; Enable caching for nar files, to avoid reconstructing and
+           ;; recompressing archives.
+           "proxy_cache nar;"
+           "proxy_cache_valid 200 30d;"           ; cache hits for 1 month
+           "proxy_cache_valid 504 3m;" ; timeout, when hydra.gnu.org is overloaded
+           "proxy_cache_valid any 1h;" ; cache misses/others for 1h.
+
+           "proxy_ignore_client_abort on;"
+
+           ;; Nars are already compressed.
+           "gzip off;"
+
+           ;; We need to hide and ignore the Set-Cookie header to enable
+           ;; caching.
+           "proxy_hide_header    Set-Cookie;"
+           "proxy_ignore_headers Set-Cookie;"
+
+           ;; Provide a 'content-length' header so that 'guix
+           ;; substitute-binary' knows upfront how much it is downloading.
+           ;; "add_header Content-Length $body_bytes_sent;"
+           )))
+
+        (nginx-location-configuration
+         (uri "~ \\.narinfo$")
+         (body
+          (list
+           ;; Since 'guix publish' has its own caching, and since it relies
+           ;; on the atime of cached narinfos to determine whether a
+           ;; narinfo can be removed from the cache, don't do any caching
+           ;; here.
+           (string-append "proxy_pass " url ";")
+
+           ;; For HTTP pipelining.  This has a dramatic impact on
+           ;; performance.
+           "client_body_buffer_size 128k;"
+
+           ;; Narinfos requests are short, serve many of them on a
+           ;; connection.
+           "keepalive_requests 600;"
+
+           ;; Do not tolerate slowness of hydra.gnu.org when fetching
+           ;; narinfos: better return 504 quickly than wait forever.
+           "proxy_connect_timeout 10s;"
+           "proxy_read_timeout 10s;"
+           "proxy_send_timeout 10s;"
+
+           ;; 'guix publish --ttl' produces a 'Cache-Control' header for
+           ;; use by 'guix substitute'.  Let it through rather than use
+           ;; nginx's "expire" directive since the expiration time defined
+           ;; by 'guix publish' is the right one.
+           "proxy_pass_header Cache-Control;"
+
+           "proxy_ignore_client_abort on;"
+
+           ;; We need to hide and ignore the Set-Cookie header to enable
+           ;; caching.
+           "proxy_hide_header    Set-Cookie;"
+           "proxy_ignore_headers Set-Cookie;")))
+
+        ;; Content-addressed files served by 'guix publish'.
+        (nginx-location-configuration
+         (uri "/file/")
+         (body
+          (list
+           (string-append "proxy_pass " url ";")
+
+           "proxy_cache cas;"
+           "proxy_cache_valid 200 200d;"          ; cache hits
+           "proxy_cache_valid any 5m;"            ; cache misses/others
+
+           "proxy_ignore_client_abort on;")))
+
+	;; Try to prevent good-faith crawlers from downloading substitutes.
+	(nginx-location-configuration
+	 (uri "= /robots.txt")
+	 (body
+	  (list
+	   #~(string-append "try_files "
+			    #$(plain-file "robots.txt" publish-robots.txt)
+			    " =404;")
+	   "root /;")))))
+
+;; TODO
+;; (define %ci-onion
+;;   ;; Onion service name of ci.guix.
+;;   "4zwzi66wwdaalbhgnix55ea3ab4pvvw66ll2ow53kjub6se4q2bclcyd.onion")
+
+(define (balg02-locations publish-url)
+  "Return nginx location blocks with 'guix publish' reachable at
+PUBLISH-URL."
+  (append (publish-locations publish-url)
+          (list
+           ;; Cuirass.
+           (nginx-location-configuration
+            (uri "/")
+            (body (list "proxy_pass http://localhost:8081;"
+                        ;; ;; See
+                        ;; ;; <https://community.torproject.org/onion-services/advanced/onion-location/>.
+                        ;; (string-append
+                        ;;  "add_header Onion-Location http://" %ci-onion
+                        ;;  "$request_uri;")
+                        )))
+           (nginx-location-configuration
+            (uri "~ ^/admin")
+            (body
+             (list "if ($ssl_client_verify != SUCCESS) { return 403; } proxy_pass http://localhost:8081;")))
+
+           (nginx-location-configuration
+            (uri "/static")
+            (body
+             (list
+              "proxy_pass http://localhost:8081;"
+              ;; Cuirass adds a 'Cache-Control' header, honor it.
+              "proxy_cache static;"
+              "proxy_cache_valid 200 2d;"
+              "proxy_cache_valid any 10m;"
+              "proxy_ignore_client_abort on;")))
+
+           (nginx-location-configuration
+            (uri "/download")                     ;Cuirass "build products"
+            (body
+             (list
+              "proxy_pass http://localhost:8081;"
+              "expires 10d;"                      ;override 'Cache-Control'
+              "proxy_cache static;"
+              "proxy_cache_valid 200 30d;"
+              "proxy_cache_valid any 10m;"
+              "proxy_ignore_client_abort on;")))
+
+           (nginx-location-configuration          ;certbot
+            (uri "/.well-known")
+            (body (list "root /var/www;"))))))
+
+(define %publish-url "http://localhost:3000")
+
+;; Taken from https://git.savannah.gnu.org/cgit/guix/maintenance.git/tree/hydra/modules/sysadmin/nginx.scm
+(define %tls-settings
+  (list
+   ;; Make sure SSL is disabled.
+   "ssl_protocols       TLSv1.1 TLSv1.2 TLSv1.3;"
+   ;; Disable weak cipher suites.
+   "ssl_ciphers         HIGH:!aNULL:!MD5;"
+   "ssl_prefer_server_ciphers on;"
+
+   ;; TODO: these need to be generated
+   ;; Use our own DH parameters created with:
+   ;;    openssl dhparam -out dhparams.pem 2048
+   ;; as suggested at <https://weakdh.org/sysadmin.html>.
+   "ssl_dhparam         /etc/dhparams.pem;"))
+
+;; Taken from https://git.savannah.gnu.org/cgit/guix/maintenance.git/tree/hydra/modules/sysadmin/nginx.scm
+(define* (le host #:optional privkey)
+  (string-append "/etc/letsencrypt/live/"
+                 host "/"
+                 (if privkey "privkey" "fullchain")
+                 ".pem"))
+
+;; Taken from https://git.savannah.gnu.org/cgit/guix/maintenance.git/tree/hydra/modules/sysadmin/nginx.scm
+(define languages-to-accept
+  ;; List of languages for redirection; see 'accept-languages' further
+  ;; below.
+  '(("en")
+    ("de")
+    ("eo")
+    ("es")
+    ("fr")
+    ("ja")
+    ("ko")
+    ("ru")
+    ("sk")
+    ("tr")
+    ("zh-CN" "zh" "zh-Hans" "zh-Hans-CN")
+    ("zh-TW" "zh-Hant" "zh-Hant-TW")))
+
+;; Taken from https://git.savannah.gnu.org/cgit/guix/maintenance.git/tree/hydra/modules/sysadmin/nginx.scm
+(define* (accept-languages
+          #:optional (language-lists
+                      languages-to-accept))
+  "Returns nginx configuration code to set up the $lang variable
+according to the Accept-Language header in the HTTP request.  The
+requesting user agent will be served the files at /$lang/some/url.
+Each list in LANGUAGE-LISTS starts with the $lang and is followed by
+synonymous IETF language tags that should be mapped to the same $lang."
+  (define (language-mappings language-list)
+    (define (language-mapping language)
+      (string-join (list "    "  language (car language-list) ";")))
+    (string-join (map language-mapping language-list) "\n"))
+
+  (let ((directives
+         `(,(string-join
+             `("set_from_accept_language $lang_unmapped"
+               ,@(map string-join language-lists)
+               ";"))
+           "map $lang_unmapped $lang {"
+           ,@(map language-mappings language-lists)
+           "}")))
+    (string-join directives "\n")))
+
+
+(define %balg02-servers
+  (list
+   ;; Redirect domains that don't explicitly support HTTP (below) to HTTPS.
+   (nginx-server-configuration
+    (listen '("80"))
+    (raw-content
+     (list "return 308 https://$host$request_uri;")))
+
+   ;; Domains that still explicitly support plain HTTP.
+   (nginx-server-configuration
+    (listen '("80"))
+    (server-name `("ci.guix.gnu.org"
+		   ;; <https://logs.guix.gnu.org/guix/2021-11-20.log#155427>
+		   "~[0-9]$"
+; TODO: onion
+;                   ,(regexp-quote %ci-onion)
+                   ))
+    (locations (balg02-locations %publish-url))
+    (raw-content
+     (list
+      "access_log  /var/run/anonip/http.access.log;"
+      "proxy_set_header X-Forwarded-Host $host;"
+      "proxy_set_header X-Forwarded-Port $server_port;"
+      "proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;")))
+
+   ;; HTTPS servers
+   (nginx-server-configuration
+    (listen '("443 ssl"))
+    (server-name '("ci.guix.gnu.org"))
+    (ssl-certificate (le "ci.guix.gnu.org"))
+    (ssl-certificate-key (le "ci.guix.gnu.org" 'key))
+    (locations (balg02-locations %publish-url))
+    (raw-content
+     (append
+      %tls-settings
+      (list
+       "access_log  /var/run/anonip/https.access.log;"
+       "proxy_set_header X-Forwarded-Host $host;"
+       "proxy_set_header X-Forwarded-Port $server_port;"
+       "proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;"
+       ;; For Cuirass admin interface authentication
+       "ssl_client_certificate /etc/ssl-ca/certs/ca.crt;"
+       "ssl_verify_client optional;"))))))
+
+(define %extra-content
+  (list
+   "default_type  application/octet-stream;"
+   "sendfile        on;"
+
+   (accept-languages)
+
+   ;; Maximum chunk size to send.  Partly this is a workaround for
+   ;; <http://bugs.gnu.org/19939>, but also the nginx docs mention that
+   ;; "Without the limit, one fast connection may seize the worker
+   ;; process entirely."
+   ;;  <http://nginx.org/en/docs/http/ngx_http_core_module#sendfile_max_chunk>
+   "sendfile_max_chunk 1m;"
+
+   "keepalive_timeout  65;"
+
+   ;; Use HTTP 1.1 to talk to the backend so we benefit from keep-alive
+   ;; connections and chunked transfer encoding.  The latter allows us to
+   ;; make sure we do not cache partial downloads.
+   "proxy_http_version 1.1;"
+
+   ;; The 'inactive' parameter for caching is not very useful in our
+   ;; case: all that matters is that LRU sweeping happens when 'max_size'
+   ;; is hit.
+
+   ;; cache for nar files
+   "proxy_cache_path /var/cache/nginx/nar"
+   "     levels=2"
+   "     inactive=8d"	    ; inactive keys removed after 8d
+   "     keys_zone=nar:4m"  ; nar cache meta data: ~32K keys
+   "     max_size=10g;"     ; total cache data size max
+
+   ;; cache for content-addressed files
+   "proxy_cache_path /var/cache/nginx/cas"
+   "     levels=2"
+   "     inactive=180d"	    ; inactive keys removed after 180d
+   "     keys_zone=cas:8m"  ; nar cache meta data: ~64K keys
+   "     max_size=50g;"         ; total cache data size max
+
+   ;; cache for build logs
+   "proxy_cache_path /var/cache/nginx/logs"
+   "     levels=2"
+   "     inactive=60d"          ; inactive keys removed after 60d
+   "     keys_zone=logs:8m"     ; narinfo meta data: ~64K keys
+   "     max_size=4g;"          ; total cache data size max
+
+   ;; cache for static data
+   "proxy_cache_path /var/cache/nginx/static"
+   "     levels=1"
+   "     inactive=10d"	       ; inactive keys removed after 10d
+   "     keys_zone=static:1m"   ; nar cache meta data: ~8K keys
+   "     max_size=200m;"        ; total cache data size max
+
+   ;; If Hydra cannot honor these delays, then something is wrong and
+   ;; we'd better drop the connection and return 504.
+   "proxy_connect_timeout 10s;"
+   "proxy_read_timeout 10s;"
+   "proxy_send_timeout 10s;"
+
+   ;; Cache timeouts for a little while to avoid increasing pressure.
+   "proxy_cache_valid 504 30s;"))
+
+(define %nginx-configuration
+  (nginx-configuration
+   (server-blocks %balg02-servers)
+   (server-names-hash-bucket-size 128)
+   (modules
+    (list
+     ;; Module to redirect users to the localized pages of their choice.
+     (file-append nginx-accept-language-module
+                  "/etc/nginx/modules/ngx_http_accept_language_module.so")))
+   (global-directives
+    '((worker_processes . 16)
+      (pcre_jit . on)
+      (events . ((worker_connections . 1024)))))
+   (extra-content
+    (string-join %extra-content "\n"))))
+
+(define %nginx-cache-activation
+  ;; Make sure /var/cache/nginx exists on the first run.
+  (simple-service 'nginx-/var/cache/nginx
+                  activation-service-type
+                  (with-imported-modules '((guix build utils))
+                    #~(begin
+                        (use-modules (guix build utils))
+                        (mkdir-p "/var/cache/nginx")))))
+
+(define %nginx-deploy-hook
+  (program-file
+   "nginx-deploy-hook"
+   #~(let ((pid (call-with-input-file "/var/run/nginx/pid" read)))
+       (kill pid SIGHUP))))
 
 (define (balg02 efi-boot-uuid)
   (operating-system
@@ -76,7 +462,7 @@
                                  file-systems)))))
 
    (users (cons* (user-account
-                  (name %automation-user)
+                  (name "auto")
                   (comment "Automation User")
                   (group "users")
 	          (shell #~(string-append #$bash "/bin/bash"))
@@ -112,7 +498,7 @@
    (packages
     (append
      (map specification->package
-          '("nss-certs"
+          '("btrfs-progs"
             "recutils"
             "openssh"
             "tmux"
@@ -137,8 +523,7 @@
                     ,(local-file "../../../.pubkeys/pjotr-gaeta.pub")
                     ,(local-file "../../../.pubkeys/pjotr-napoli.pub")
                     ,(local-file "../../../.pubkeys/pjotr-stromboli.pub")
-                    ,(local-file "../../../.pubkeys/pjotr-tb-arm-01.pub"))
-		   ("root" ,(local-file "../../../.pubkeys/collin.pub"))))))
+                    ,(local-file "../../../.pubkeys/pjotr-tb-arm-01.pub"))))))
       (service static-networking-service-type
                (list (static-networking
                       (addresses
@@ -150,7 +535,29 @@
                               (destination "default")
                               (gateway "216.37.76.1"))))
                       (name-servers '("216.37.64.2" "216.37.64.3")))))
-      (service ntp-service-type))
+      (service ntp-service-type)
+
+      (service certbot-service-type
+               (certbot-configuration
+                (email "collin@rekahsoft.ca")
+                (certificates
+                 (list
+                  (certificate-configuration
+                   (domains '("cuirass.genenetwork.org"))
+                   (deploy-hook %nginx-deploy-hook))))))
+
+      (service cuirass-service-type
+               (cuirass-configuration
+                (host "localhost")
+                (specifications %cuirass-specs)))
+
+      %nginx-cache-activation
+      (service nginx-service-type %nginx-configuration)
+
+      (service guix-publish-service-type
+               (guix-publish-configuration
+                (port 3000)
+                (cache "/var/cache/guix/publish"))))
       %base-services))))
 
 (define %system (balg02 "3AF8-9E67"))