summaryrefslogtreecommitdiff
path: root/src/guix/services.scm
blob: 1e5ae4eb5d59c4686ad3544453bf6b65fb5eb3e1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
(define-module (services)
  #:use-module ((ice-9 popen) #:prefix popen:)
  #:use-module ((ice-9 textual-ports) #:prefix textual-ports:)
  #:use-module ((gnu build linux-container) #:prefix container:)
  #:use-module ((srfi srfi-1) #:prefix srfi-1:)
  #:use-module ((xyz euandreh heredoc) #:prefix heredoc:)
  #:use-module (gnu)
  #:use-module (guix build utils)
  #:use-module (guix least-authority)
  #:use-module (guix records))
(use-package-modules
  admin)
(use-service-modules
  admin
  mcron
  shepherd)
(heredoc:enable-syntax)


(define +working-dir+
  (if (directory-exists? "/opt/deploy/current")
    "/opt/deploy/current"
    (canonicalize-path ".")))

(add-to-load-path
 (string-append +working-dir+ "/src/infrastructure/guix"))
(use-modules
  ((packages) #:prefix packages:))



(define-record-type* <papo-configuration>
  papo-configuration
  make-papo-configuration
  papo-configuration?
  (package              papo-configuration-package              (default packages:papo))
  (user                 papo-configuration-user                 (default "papo"))
  (group                papo-configuration-group                (default "papo"))
  (config-dirname       papo-configuration-config               (default "papo"))
  (port                 papo-configuration-port                 (default 6666))
  (log-file             papo-configuration-log-file             (default "/var/log/papo.log"))
  (data-directory       papo-configuration-data-directory       (default "/var/lib/papo"))
  (run-directory        papo-configuration-run-directory        (default "/var/run/papo"))
  (run-in-container?    papo-configuration-run-in-container?    (default #t))
  (container-name       papo-configuration-container-name       (default "papo-container"))
  (container-namespaces papo-configuration-container-namespaces (default container:%namespaces))
  (extra-mappings       papo-configuration-extra-mappings       (default '())))

(define (papo-etc-files config)
  (match-record config <papo-configuration>
      ()
    `(("papo.json" ,(plain-file "papo.json" "")))))

(define (papo-log-rotations config)
  (match-record config <papo-configuration>
      (log-file)
    (list
      (log-rotation
        (frequency 'weekly)
        (files (list log-file))
        (options '("rotate 5200"))))))

(define (papo-activation config)
  (match-record config <papo-configuration>
      (user log-file data-directory run-directory)
    #~(begin
        (use-modules (guix build utils))
        (format (current-error-port)
         "Creating papo log directory for '~a'.~%" #$log-file)
        (mkdir-p (dirname #$log-file))
        (when (not (file-exists? #$log-file))
          (call-with-output-file #$log-file (const #t)))
        (chmod #$log-file #o644)
        (let ((user (getpwnam #$user)))
          (format (current-error-port)
           "Creating papo data directory '~a'.~%" #$data-directory)
          (mkdir-p #$data-directory)
          (chown #$data-directory (passwd:uid user) (passwd:gid user))
          (chmod #$data-directory #o750)
          (format (current-error-port)
           "Creating papo run directory '~a'.~%" #$run-directory)
          (mkdir-p #$run-directory)
          (chown #$run-directory (passwd:uid user) (passwd:gid user))
          (chmod #$run-directory #o755)))))

(define (papo-cronjobs _config)
  (list))

(define (papo-accounts config)
  (match-record config <papo-configuration>
      (user group)
    (list
     (user-group
       (name group)
       (system? #t))
     (user-account
       (name user)
       (group group)
       (system? #t)
       (comment "The user for runtime execution of papo code")
       (home-directory "/var/empty")
       (shell
         (file-append shadow "/sbin/nologin"))))))

(define (wrapped-command config)
  (match-record config <papo-configuration>
      (package data-directory
       run-in-container? container-name container-namespaces extra-mappings)
    (let ((bin (file-append package "/bin/papo")))
      (if (not run-in-container?)
        bin
        (least-authority-wrapper
         bin
         #:name       container-name
         #:namespaces container-namespaces
         #:directory  data-directory
         #:preserved-environment-variables
         '()
         #:mappings
         (append
          (list
           (file-system-mapping
             (source data-directory)
             (target source)
             (writable? #t))
           (file-system-mapping
             (source (file-append glibc-locales "/lib/locale"))
             (target "/run/current-system/locale")))
          extra-mappings))))))

(define (exec-action config . static-args)
  (match-record config <papo-configuration>
      (user group log-file data-directory)
    #~(lambda dynamic-args
        (fork+exec-command
         (append '(#$@static-args) dynamic-args)
         #:user      #$user
         #:group     #$group
         #:directory #$data-directory
         #:log-file  #$log-file))))

(define (papo-shepherd-services config)
  (let ((cmd (wrapped-command config)))
    (list
     (shepherd-service
       (provision '(papo))
       (requirement '())
       (start (exec-action config cmd "ircd"))
       (stop #~(make-kill-destructor SIGKILL))
       (documentation
         #"-
           The Shepherd service that runs the server via "papo-ircd"."#)))))

(define-public papo-service-type
  (service-type
    (name 'papo)
    (extensions
      (list
       (service-extension shepherd-root-service-type
                          papo-shepherd-services)
       (service-extension etc-service-type
                          papo-etc-files)
       (service-extension profile-service-type
                          (compose list papo-configuration-package))
       (service-extension activation-service-type
                          papo-activation)
       (service-extension account-service-type
                          papo-accounts)
       (service-extension mcron-service-type
                          papo-cronjobs)
       (service-extension rottlog-service-type
                          papo-log-rotations)))
    (default-value (papo-configuration))
    (description
      #"-
        The top-level system service for papo code.

        It includes:
        - the Shepherd service for starting, stopping and reloading the
          service ("papo");
        - a list of cronjobs to be added to the system for sending documents
          proactively;
        - activation script for setting up the initial directories and permissions;
        - the "papo" group and "papo" account for running the production service;
        - log management (storage and rotation) for logs produced by the running services.

        The defaults of <papo-configuration> provide sane values for all of these."#)))