Merge ~cjwatson/launchpad:charm-buildd-manager into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: db5d9bd97f9570f0631afbc7911c82b33e9538f6
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:charm-buildd-manager
Merge into: launchpad:master
Diff against target: 606 lines (+503/-0)
16 files modified
charm/Makefile (+1/-0)
charm/launchpad-buildd-manager/README.md (+19/-0)
charm/launchpad-buildd-manager/actions.yaml (+11/-0)
charm/launchpad-buildd-manager/actions/actions.py (+53/-0)
charm/launchpad-buildd-manager/actions/start-services (+1/-0)
charm/launchpad-buildd-manager/actions/stop-services (+1/-0)
charm/launchpad-buildd-manager/charmcraft.yaml (+63/-0)
charm/launchpad-buildd-manager/config.yaml (+60/-0)
charm/launchpad-buildd-manager/layer.yaml (+12/-0)
charm/launchpad-buildd-manager/metadata.yaml (+16/-0)
charm/launchpad-buildd-manager/reactive/launchpad-buildd-manager.py (+148/-0)
charm/launchpad-buildd-manager/templates/crontab.j2 (+30/-0)
charm/launchpad-buildd-manager/templates/launchpad-buildd-manager-lazr.conf (+36/-0)
charm/launchpad-buildd-manager/templates/launchpad-buildd-manager-secrets-lazr.conf (+18/-0)
charm/launchpad-buildd-manager/templates/launchpad-buildd-manager.service.j2 (+18/-0)
charm/launchpad-buildd-manager/templates/logrotate.conf.j2 (+16/-0)
Reviewer Review Type Date Requested Status
Guruprasad Approve
Review via email: mp+441481@code.launchpad.net

Commit message

charm: Add a launchpad-buildd-manager charm

Description of the change

I'm sure this needs some more work, but it should be a reasonable starting point.

To post a comment you must log in.
b60d785... by Colin Watson

Add a basic README

c96fdd5... by Colin Watson

Add start-services/stop-services actions

In our legacy production deployment, we stop and start these services
around certain kinds of maintenance actions, mainly network maintenance
affecting the build farm. The preferred way to do this sort of thing in
Juju is using actions, so define a couple of suitable actions; once we
deploy this to production, we'll set up an SSH trigger allowing
developers to run any of an allowlist of actions on production.

Revision history for this message
Guruprasad (lgp171188) wrote :

LGTM 👍

review: Approve
db5d9bd... by Colin Watson

Explain which services are started/stopped

Revision history for this message
Colin Watson (cjwatson) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/charm/Makefile b/charm/Makefile
2index 857f6b2..2106149 100644
3--- a/charm/Makefile
4+++ b/charm/Makefile
5@@ -17,6 +17,7 @@ CHARMS := \
6 launchpad-admin \
7 launchpad-appserver \
8 launchpad-assets \
9+ launchpad-buildd-manager \
10 launchpad-debian-importer \
11 launchpad-librarian
12
13diff --git a/charm/launchpad-buildd-manager/README.md b/charm/launchpad-buildd-manager/README.md
14new file mode 100644
15index 0000000..ad0c783
16--- /dev/null
17+++ b/charm/launchpad-buildd-manager/README.md
18@@ -0,0 +1,19 @@
19+# Launchpad build farm manager
20+
21+This charm runs a service that supervises the Launchpad build farm.
22+
23+You will need the following relations:
24+
25+ juju relate launchpad-buildd-manager:db postgresql:db
26+ juju relate launchpad-buildd-manager rabbitmq-server
27+
28+## Maintenance actions
29+
30+To stop the build farm manager (perhaps in preparation for network
31+maintenance affecting the build farm), run:
32+
33+ juju run-action --wait launchpad-buildd-manager/leader stop-services
34+
35+To start them again once maintenance is complete:
36+
37+ juju run-action --wait launchpad-buildd-manager/leader start-services
38diff --git a/charm/launchpad-buildd-manager/actions.yaml b/charm/launchpad-buildd-manager/actions.yaml
39new file mode 100644
40index 0000000..7bfe649
41--- /dev/null
42+++ b/charm/launchpad-buildd-manager/actions.yaml
43@@ -0,0 +1,11 @@
44+start-services:
45+ description: |
46+ Start the launchpad-buildd-manager service. Usually run after
47+ maintenance.
48+stop-services:
49+ description: |
50+ Stop the launchpad-buildd-manager service. Usually run in preparation
51+ for maintenance. (Note that this does not stop services in a way that
52+ will persist across a reboot. It also doesn't disable cron jobs, since
53+ those are handled by the cron-control mechanism instead; see
54+ lp.services.scripts.base.cronscript_enabled.)
55diff --git a/charm/launchpad-buildd-manager/actions/actions.py b/charm/launchpad-buildd-manager/actions/actions.py
56new file mode 100755
57index 0000000..a27a67e
58--- /dev/null
59+++ b/charm/launchpad-buildd-manager/actions/actions.py
60@@ -0,0 +1,53 @@
61+#! /usr/bin/python3
62+# Copyright 2023 Canonical Ltd. This software is licensed under the
63+# GNU Affero General Public License version 3 (see the file LICENSE).
64+
65+import subprocess
66+import sys
67+import traceback
68+from pathlib import Path
69+
70+sys.path.append("lib")
71+
72+from charms.layer import basic # noqa: E402
73+
74+basic.bootstrap_charm_deps()
75+basic.init_config_states()
76+
77+from charmhelpers.core import hookenv # noqa: E402
78+
79+
80+def start_services():
81+ service = "launchpad-buildd-manager.service"
82+ hookenv.log(f"Starting {service}.")
83+ subprocess.run(["systemctl", "start", service], check=True)
84+ hookenv.action_set({"result": "Services started"})
85+
86+
87+def stop_services():
88+ service = "launchpad-buildd-manager.service"
89+ hookenv.log(f"Stopping {service}.")
90+ subprocess.run(["systemctl", "stop", service], check=True)
91+ hookenv.action_set({"result": "Services stopped"})
92+
93+
94+def main(argv):
95+ action = Path(argv[0]).name
96+ try:
97+ if action == "start-services":
98+ start_services()
99+ elif action == "stop-services":
100+ stop_services()
101+ else:
102+ hookenv.action_fail(f"Action {action} not implemented.")
103+ except Exception:
104+ hookenv.action_fail("Unhandled exception")
105+ tb = traceback.format_exc()
106+ hookenv.action_set(dict(traceback=tb))
107+ hookenv.log(f"Unhandled exception in action {action}:")
108+ for line in tb.splitlines():
109+ hookenv.log(line)
110+
111+
112+if __name__ == "__main__":
113+ main(sys.argv)
114diff --git a/charm/launchpad-buildd-manager/actions/start-services b/charm/launchpad-buildd-manager/actions/start-services
115new file mode 120000
116index 0000000..405a394
117--- /dev/null
118+++ b/charm/launchpad-buildd-manager/actions/start-services
119@@ -0,0 +1 @@
120+actions.py
121\ No newline at end of file
122diff --git a/charm/launchpad-buildd-manager/actions/stop-services b/charm/launchpad-buildd-manager/actions/stop-services
123new file mode 120000
124index 0000000..405a394
125--- /dev/null
126+++ b/charm/launchpad-buildd-manager/actions/stop-services
127@@ -0,0 +1 @@
128+actions.py
129\ No newline at end of file
130diff --git a/charm/launchpad-buildd-manager/charmcraft.yaml b/charm/launchpad-buildd-manager/charmcraft.yaml
131new file mode 100644
132index 0000000..1e26547
133--- /dev/null
134+++ b/charm/launchpad-buildd-manager/charmcraft.yaml
135@@ -0,0 +1,63 @@
136+type: charm
137+bases:
138+ - build-on:
139+ - name: ubuntu
140+ channel: "20.04"
141+ architectures: [amd64]
142+ run-on:
143+ - name: ubuntu
144+ channel: "20.04"
145+ architectures: [amd64]
146+parts:
147+ charm-wheels:
148+ source: https://git.launchpad.net/~ubuntuone-hackers/ols-charm-deps/+git/wheels
149+ source-commit: "42c89d9c66dbe137139b047fd54aed49b66d1a5e"
150+ source-submodules: []
151+ source-type: git
152+ plugin: dump
153+ organize:
154+ "*": charm-wheels/
155+ prime:
156+ - "-charm-wheels"
157+ ols-layers:
158+ source: https://git.launchpad.net/ols-charm-deps
159+ source-commit: "f63ae0386275bf9089b30c8abae252a0ea523633"
160+ source-submodules: []
161+ source-type: git
162+ plugin: dump
163+ organize:
164+ "*": layers/
165+ stage:
166+ - layers
167+ prime:
168+ - "-layers"
169+ launchpad-layers:
170+ after:
171+ - ols-layers
172+ source: https://git.launchpad.net/launchpad-layers
173+ source-commit: "42a4b4c4f62936b1d050c775e84f7364dfb5efc0"
174+ source-submodules: []
175+ source-type: git
176+ plugin: dump
177+ organize:
178+ launchpad-base: layers/layer/launchpad-base
179+ launchpad-db: layers/layer/launchpad-db
180+ launchpad-payload: layers/layer/launchpad-payload
181+ stage:
182+ - layers
183+ prime:
184+ - "-layers"
185+ launchpad-buildd-manager:
186+ after:
187+ - charm-wheels
188+ - launchpad-layers
189+ source: .
190+ plugin: reactive
191+ build-snaps: [charm]
192+ build-packages: [libpq-dev, python3-dev]
193+ build-environment:
194+ - CHARM_LAYERS_DIR: $CRAFT_STAGE/layers/layer
195+ - CHARM_INTERFACES_DIR: $CRAFT_STAGE/layers/interface
196+ - PIP_NO_INDEX: "true"
197+ - PIP_FIND_LINKS: $CRAFT_STAGE/charm-wheels
198+ reactive-charm-build-arguments: [--binary-wheels-from-source]
199diff --git a/charm/launchpad-buildd-manager/config.yaml b/charm/launchpad-buildd-manager/config.yaml
200new file mode 100644
201index 0000000..ea622d3
202--- /dev/null
203+++ b/charm/launchpad-buildd-manager/config.yaml
204@@ -0,0 +1,60 @@
205+options:
206+ active:
207+ type: boolean
208+ description: If true, enable jobs that may change the database.
209+ default: true
210+ artifactory_read_credentials:
211+ type: string
212+ description: >
213+ Credentials for reading from Artifactory repositories (formatted as
214+ "user:token").
215+ default: ""
216+ builder_proxy_auth_api_admin_secret:
217+ type: string
218+ description: >
219+ Admin secret for requesting tokens from the builder proxy service.
220+ default: ""
221+ builder_proxy_auth_api_admin_username:
222+ type: string
223+ description: Admin username for the builder proxy service.
224+ default: ""
225+ builder_proxy_auth_api_endpoint:
226+ type: string
227+ description: Endpoint for builder proxy authentication service.
228+ default: ""
229+ builder_proxy_host:
230+ type: string
231+ description: Builder HTTP proxy host.
232+ default: ""
233+ builder_proxy_port:
234+ type: int
235+ description: Builder HTTP proxy port.
236+ default: 3128
237+ builder_reset_private_ssh_key:
238+ type: string
239+ description: >
240+ Base64-encoded private SSH key, used to request builder resets.
241+ default: ""
242+ builder_reset_public_ssh_key:
243+ type: string
244+ description: >
245+ Base64-encoded public SSH key, used to request builder resets.
246+ default: ""
247+ cibuild_config:
248+ type: string
249+ description: >
250+ YAML-encoded dictionary mapping pillars to dictionaries of
251+ configuration items to set for CI builds of those pillars.
252+ default: ""
253+ socket_timeout:
254+ type: int
255+ description: >
256+ The time in seconds that buildd-manager will wait for a reply from
257+ non-virtualized builders.
258+ default: 40
259+ virtualized_socket_timeout:
260+ type: int
261+ description: >
262+ The time in seconds that buildd-manager will wait for a reply from
263+ non-virtualized builders.
264+ default: 30
265diff --git a/charm/launchpad-buildd-manager/layer.yaml b/charm/launchpad-buildd-manager/layer.yaml
266new file mode 100644
267index 0000000..a9518a1
268--- /dev/null
269+++ b/charm/launchpad-buildd-manager/layer.yaml
270@@ -0,0 +1,12 @@
271+includes:
272+ - layer:launchpad-db
273+repo: https://git.launchpad.net/launchpad
274+options:
275+ ols-pg:
276+ databases:
277+ db:
278+ name: launchpad_dev
279+ roles:
280+ - buildd_manager
281+ - process_upload
282+ - retry_depwait
283diff --git a/charm/launchpad-buildd-manager/metadata.yaml b/charm/launchpad-buildd-manager/metadata.yaml
284new file mode 100644
285index 0000000..0e28e9f
286--- /dev/null
287+++ b/charm/launchpad-buildd-manager/metadata.yaml
288@@ -0,0 +1,16 @@
289+name: launchpad-buildd-manager
290+display-name: launchpad-buildd-manager
291+summary: Launchpad build farm manager
292+maintainer: Colin Watson <cjwatson@canonical.com>
293+description: |
294+ Launchpad is an open source suite of tools that help people and teams
295+ to work together on software projects.
296+
297+ This charm runs a service that supervises the Launchpad build farm,
298+ dispatching jobs to idle builders and collecting results.
299+tags:
300+ # https://juju.is/docs/charm-metadata#heading--charm-store-fields
301+ - network
302+series:
303+ - focal
304+subordinate: false
305diff --git a/charm/launchpad-buildd-manager/reactive/launchpad-buildd-manager.py b/charm/launchpad-buildd-manager/reactive/launchpad-buildd-manager.py
306new file mode 100644
307index 0000000..708a4a5
308--- /dev/null
309+++ b/charm/launchpad-buildd-manager/reactive/launchpad-buildd-manager.py
310@@ -0,0 +1,148 @@
311+# Copyright 2023 Canonical Ltd. This software is licensed under the
312+# GNU Affero General Public License version 3 (see the file LICENSE).
313+
314+import base64
315+import os.path
316+import subprocess
317+
318+import yaml
319+from charmhelpers.core import hookenv, host, templating
320+from charms.launchpad.base import get_service_config
321+from charms.launchpad.db import lazr_config_files
322+from charms.launchpad.payload import (
323+ config_file_path,
324+ configure_cron,
325+ configure_lazr,
326+ home_dir,
327+)
328+from charms.reactive import helpers, remove_state, set_state, when, when_not
329+from ols import base
330+
331+
332+def base64_decode(value):
333+ return base64.b64decode(value.encode("ASCII"))
334+
335+
336+def configure_keys(config):
337+ ssh_dir = os.path.join(home_dir(), ".ssh")
338+ ssh_private_path = os.path.join(ssh_dir, "builder-reset")
339+ ssh_public_path = os.path.join(ssh_dir, "builder-reset.pub")
340+ if (
341+ config["builder_reset_private_ssh_key"]
342+ and config["builder_reset_public_ssh_key"]
343+ ):
344+ hookenv.log("Writing SSH keys.")
345+ if not os.path.exists(ssh_dir):
346+ host.mkdir(
347+ ssh_dir, owner=base.user(), group=base.user(), perms=0o700
348+ )
349+ host.write_file(
350+ ssh_private_path,
351+ base64_decode(config["builder_reset_private_ssh_key"]),
352+ owner=base.user(),
353+ group=base.user(),
354+ perms=0o600,
355+ )
356+ host.write_file(
357+ ssh_public_path,
358+ base64_decode(config["builder_reset_public_ssh_key"]),
359+ owner=base.user(),
360+ group=base.user(),
361+ perms=0o644,
362+ )
363+ else:
364+ for path in (ssh_private_path, ssh_public_path):
365+ if os.path.exists(path):
366+ os.unlink(path)
367+
368+
369+def configure_service(config):
370+ hookenv.log("Writing systemd service.")
371+ templating.render(
372+ "launchpad-buildd-manager.service.j2",
373+ "/lib/systemd/system/launchpad-buildd-manager.service",
374+ config,
375+ )
376+ subprocess.run(["systemctl", "daemon-reload"], check=True)
377+
378+
379+def configure_logrotate(config):
380+ hookenv.log("Writing logrotate configuration.")
381+ templating.render(
382+ "logrotate.conf.j2",
383+ "/etc/logrotate.d/launchpad-buildd-manager",
384+ config,
385+ perms=0o644,
386+ )
387+
388+
389+def config_files():
390+ files = []
391+ files.extend(lazr_config_files())
392+ files.append(
393+ config_file_path("launchpad-buildd-manager/launchpad-lazr.conf")
394+ )
395+ files.append(
396+ config_file_path(
397+ "launchpad-buildd-manager-secrets-lazr.conf", secret=True
398+ )
399+ )
400+ return files
401+
402+
403+@when("launchpad.db.configured")
404+@when_not("service.configured")
405+def configure():
406+ config = get_service_config()
407+ config["buildd_manager_dir"] = os.path.join(
408+ base.base_dir(), "buildd-manager"
409+ )
410+ config["cibuild_config"] = yaml.safe_load(config["cibuild_config"])
411+ host.mkdir(
412+ config["buildd_manager_dir"],
413+ owner=base.user(),
414+ group=base.user(),
415+ perms=0o755,
416+ )
417+ configure_lazr(
418+ config,
419+ "launchpad-buildd-manager-lazr.conf",
420+ "launchpad-buildd-manager/launchpad-lazr.conf",
421+ )
422+ configure_lazr(
423+ config,
424+ "launchpad-buildd-manager-secrets-lazr.conf",
425+ "launchpad-buildd-manager-secrets-lazr.conf",
426+ secret=True,
427+ )
428+ configure_keys(config)
429+ configure_service(config)
430+ configure_logrotate(config)
431+ configure_cron(config, "crontab.j2")
432+
433+ if config["active"]:
434+ if helpers.any_file_changed(
435+ [
436+ base.version_info_path(),
437+ "/lib/systemd/system/launchpad-buildd-manager.service",
438+ ]
439+ + config_files()
440+ ):
441+ hookenv.log("Config files changed; restarting buildd-manager")
442+ host.service_restart("launchpad-buildd-manager")
443+ host.service_resume("launchpad-buildd-manager")
444+ else:
445+ host.service_pause("launchpad-buildd-manager")
446+
447+ set_state("service.configured")
448+
449+
450+@when("service.configured")
451+@when_not("launchpad.db.configured")
452+def deconfigure():
453+ remove_state("service.configured")
454+
455+
456+@when("service.configured")
457+def check_is_running():
458+ hookenv.status_set("active", "Ready")
459diff --git a/charm/launchpad-buildd-manager/templates/crontab.j2 b/charm/launchpad-buildd-manager/templates/crontab.j2
460new file mode 100644
461index 0000000..435cf43
462--- /dev/null
463+++ b/charm/launchpad-buildd-manager/templates/crontab.j2
464@@ -0,0 +1,30 @@
465+TZ=UTC
466+MAILTO={{ cron_mailto }}
467+LPCONFIG=launchpad-buildd-manager
468+
469+{% if active -%}
470+# Automatically retry builds in the "Dependency wait" state if their
471+# dependencies can now be satisfied.
472+25 * * * * {{ code_dir }}/cronscripts/buildd-retry-depwait.py -q --log-file=DEBUG2:{{ logs_dir }}/buildd-retry-depwait.log
473+
474+# Process uploaded builds.
475+* * * * * {{ code_dir }}/scripts/process-upload.py -C buildd --builds {{ buildd_manager_dir }}/ -q --log-file=DEBUG:{{ logs_dir }}/process-build-uploads.log
476+
477+{% endif -%}
478+# Clean up the accepted queue every hour, as it's redundant:
479+# https://bugs.launchpad.net/launchpad/+bug/361192
480+45 * * * * find {{ buildd_manager_dir }}/accepted/ -maxdepth 1 -type d -execdir rm -rf {} + >/dev/null 2>&1
481+
482+# Directories older than 1 month can be deleted
483+00 00 * * * find {{ buildd_manager_dir }}/rejected/ -maxdepth 1 -type d -mtime +30 -execdir rm -rf {} + >/dev/null 2>&1
484+
485+# Clean out failed directory: https://portal.admin.canonical.com/C98568
486+0 1 * * * find {{ buildd_manager_dir }}/failed/ -maxdepth 1 -type d -mtime +7 -execdir rm -rf {} + >/dev/null 2>&1
487+
488+# Give up on in-progress downloads from builders after a couple of days
489+0 2 * * * find {{ buildd_manager_dir }}/grabbing/ -maxdepth 1 -type d -mtime +2 -execdir rm -rf {} + >/dev/null 2>&1
490+
491+# Catch up with publishing OOPSes that were temporarily spooled to disk due
492+# to RabbitMQ being unavailable.
493+*/15 * * * * {{ code_dir }}/bin/datedir2amqp --exchange oopses --host {{ rabbitmq_host }} --username {{ rabbitmq_username }} --password {{ rabbitmq_password }} --vhost {{ rabbitmq_vhost }} --repo {{ oopses_dir }} --key ""
494+
495diff --git a/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager-lazr.conf b/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager-lazr.conf
496new file mode 100644
497index 0000000..d09009c
498--- /dev/null
499+++ b/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager-lazr.conf
500@@ -0,0 +1,36 @@
501+# Public configuration data. The contents of this file may be freely shared
502+# with developers if needed for debugging.
503+
504+# A schema's sections, keys, and values are automatically inherited, except
505+# for '.optional' sections. Update this config to override key values.
506+# Values are strings, except for numbers that look like ints. The tokens
507+# true, false, and none are treated as True, False, and None.
508+
509+{% from "macros.j2" import opt -%}
510+
511+[meta]
512+extends: ../launchpad-db-lazr.conf
513+
514+[builddmaster]
515+authentication_endpoint: http://{{ domain_xmlrpc_private }}:{{ port_xmlrpc }}/authserver
516+authentication_timeout: 60
517+{{- opt("builder_proxy_auth_api_admin_username", builder_proxy_auth_api_admin_username) }}
518+{{- opt("builder_proxy_auth_api_endpoint", builder_proxy_auth_api_endpoint) }}
519+{{- opt("builder_proxy_host", builder_proxy_host) }}
520+{{- opt("builder_proxy_port", builder_proxy_port) }}
521+root: {{ buildd_manager_dir }}
522+socket_timeout: {{ socket_timeout }}
523+virtualized_socket_timeout: {{ virtualized_socket_timeout }}
524+{%- if builder_reset_private_ssh_key and builder_reset_public_ssh_key %}
525+vm_resume_command: ssh -o StrictHostKeyChecking=no -i /home/{{ user }}/.ssh/builder-reset ppa@%(vm_host)s ppa-reset %(buildd_name)s
526+{%- endif %}
527+
528+{% if cibuild_config -%}
529+{% for pillar, config in cibuild_config.items() -%}
530+[cibuild.{{ pillar }}]
531+{%- for key, value in config.items() %}
532+{{ key }}: {{ value }}
533+{%- endfor %}
534+{%- endfor %}
535+{% endif %}
536+
537diff --git a/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager-secrets-lazr.conf b/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager-secrets-lazr.conf
538new file mode 100644
539index 0000000..af20066
540--- /dev/null
541+++ b/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager-secrets-lazr.conf
542@@ -0,0 +1,18 @@
543+# Secret configuration data. This is stored in an overlay directory, mainly
544+# to avoid accidental information leaks from the public configuration file.
545+# Entries in this file should not be shared with developers, although the
546+# structure of the file is not secret, only configuration values.
547+
548+# A schema's sections, keys, and values are automatically inherited, except
549+# for '.optional' sections. Update this config to override key values.
550+# Values are strings, except for numbers that look like ints. The tokens
551+# true, false, and none are treated as True, False, and None.
552+
553+{% from "macros.j2" import opt -%}
554+
555+[artifactory]
556+{{- opt("read_credentials", artifactory_read_credentials) }}
557+
558+[builddmaster]
559+{{- opt("builder_proxy_auth_api_admin_secret", builder_proxy_auth_api_admin_secret) }}
560+
561diff --git a/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager.service.j2 b/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager.service.j2
562new file mode 100644
563index 0000000..0e6ae18
564--- /dev/null
565+++ b/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager.service.j2
566@@ -0,0 +1,18 @@
567+[Unit]
568+Description=Launchpad build farm manager
569+After=network.target
570+ConditionPathExists=!{{ code_dir }}/maintenance.txt
571+
572+[Service]
573+User={{ user }}
574+Group={{ user }}
575+WorkingDirectory={{ code_dir }}
576+Environment=LPCONFIG=launchpad-buildd-manager
577+ExecStart={{ code_dir }}/bin/twistd --python={{ code_dir }}/daemons/buildd-manager.tac --logfile={{ logs_dir }}/buildd-manager.log --pidfile= --nodaemon --umask=0022
578+ExecReload=/bin/kill -USR1 $MAINPID
579+Restart=on-failure
580+LimitNOFILE=65536
581+
582+[Install]
583+WantedBy=multi-user.target
584+
585diff --git a/charm/launchpad-buildd-manager/templates/logrotate.conf.j2 b/charm/launchpad-buildd-manager/templates/logrotate.conf.j2
586new file mode 100644
587index 0000000..657e00d
588--- /dev/null
589+++ b/charm/launchpad-buildd-manager/templates/logrotate.conf.j2
590@@ -0,0 +1,16 @@
591+{{ logs_dir }}/*.log
592+{
593+ rotate 90
594+ daily
595+ dateext
596+ delaycompress
597+ compress
598+ notifempty
599+ missingok
600+ create 0644 {{ user }} {{ user }}
601+ sharedscripts
602+ postrotate
603+ systemctl reload buildd-manager.service
604+ endscript
605+}
606+

Subscribers

People subscribed via source and target branches

to status/vote changes: