Merge ~cjwatson/launchpad:charm-loggerhead into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 9182602aa4cb8664b6a483df59d9906f7de44f01
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:charm-loggerhead
Merge into: launchpad:master
Diff against target: 498 lines (+438/-0)
10 files modified
charm/launchpad-loggerhead/README.md (+7/-0)
charm/launchpad-loggerhead/charmcraft.yaml (+75/-0)
charm/launchpad-loggerhead/config.yaml (+43/-0)
charm/launchpad-loggerhead/layer.yaml (+5/-0)
charm/launchpad-loggerhead/metadata.yaml (+18/-0)
charm/launchpad-loggerhead/reactive/launchpad-loggerhead.py (+219/-0)
charm/launchpad-loggerhead/templates/crontab.j2 (+10/-0)
charm/launchpad-loggerhead/templates/launchpad-loggerhead-lazr.conf (+24/-0)
charm/launchpad-loggerhead/templates/launchpad-loggerhead.service.j2 (+22/-0)
charm/launchpad-loggerhead/templates/logrotate.conf.j2 (+15/-0)
Reviewer Review Type Date Requested Status
Guruprasad Approve
Review via email: mp+453470@code.launchpad.net

Commit message

charm: Add launchpad-loggerhead

To post a comment you must log in.
Revision history for this message
Guruprasad (lgp171188) wrote :

LGTM 👍

review: Approve
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/launchpad-loggerhead/README.md b/charm/launchpad-loggerhead/README.md
2new file mode 100644
3index 0000000..92efbe0
4--- /dev/null
5+++ b/charm/launchpad-loggerhead/README.md
6@@ -0,0 +1,7 @@
7+# Launchpad Bazaar/Breezy code browsing server
8+
9+This charm runs a code browsing server for Bazaar/Breezy branches.
10+
11+You will need the following relations:
12+
13+ juju relate launchpad-loggerhead rabbitmq-server
14diff --git a/charm/launchpad-loggerhead/charmcraft.yaml b/charm/launchpad-loggerhead/charmcraft.yaml
15new file mode 100644
16index 0000000..71dcf7f
17--- /dev/null
18+++ b/charm/launchpad-loggerhead/charmcraft.yaml
19@@ -0,0 +1,75 @@
20+type: charm
21+bases:
22+ - build-on:
23+ - name: ubuntu
24+ channel: "20.04"
25+ architectures: [amd64]
26+ run-on:
27+ - name: ubuntu
28+ channel: "20.04"
29+ architectures: [amd64]
30+parts:
31+ charm-wheels:
32+ source: https://git.launchpad.net/~ubuntuone-hackers/ols-charm-deps/+git/wheels
33+ source-commit: "42c89d9c66dbe137139b047fd54aed49b66d1a5e"
34+ source-submodules: []
35+ source-type: git
36+ plugin: dump
37+ organize:
38+ "*": charm-wheels/
39+ prime:
40+ - "-charm-wheels"
41+ ols-layers:
42+ source: https://git.launchpad.net/ols-charm-deps
43+ source-commit: "9c59a9804f1f40e2a74be7dac9bf18a655a7864f"
44+ source-submodules: []
45+ source-type: git
46+ plugin: dump
47+ organize:
48+ "*": layers/
49+ stage:
50+ - layers
51+ prime:
52+ - "-layers"
53+ launchpad-layers:
54+ after:
55+ - ols-layers
56+ source: https://git.launchpad.net/launchpad-layers
57+ source-commit: "58edb3e5a88794c3baa2274a94e21d3a298a6c79"
58+ source-submodules: []
59+ source-type: git
60+ plugin: dump
61+ organize:
62+ launchpad-base: layers/layer/launchpad-base
63+ launchpad-payload: layers/layer/launchpad-payload
64+ stage:
65+ - layers
66+ prime:
67+ - "-layers"
68+ layer-coordinator:
69+ source: https://git.launchpad.net/layer-coordinator
70+ source-commit: "fa27fc93e0b08000963e83a6bfe49812d890dfcf"
71+ source-submodules: []
72+ source-type: git
73+ plugin: dump
74+ organize:
75+ "*": layers/layer/coordinator/
76+ stage:
77+ - layers
78+ prime:
79+ - "-layers"
80+ charm:
81+ after:
82+ - charm-wheels
83+ - launchpad-layers
84+ - layer-coordinator
85+ source: .
86+ plugin: reactive
87+ build-snaps: [charm]
88+ build-packages: [libpq-dev, python3-dev]
89+ build-environment:
90+ - CHARM_LAYERS_DIR: $CRAFT_STAGE/layers/layer
91+ - CHARM_INTERFACES_DIR: $CRAFT_STAGE/layers/interface
92+ - PIP_NO_INDEX: "true"
93+ - PIP_FIND_LINKS: $CRAFT_STAGE/charm-wheels
94+ reactive-charm-build-arguments: [--binary-wheels-from-source]
95diff --git a/charm/launchpad-loggerhead/config.yaml b/charm/launchpad-loggerhead/config.yaml
96new file mode 100644
97index 0000000..3145bff
98--- /dev/null
99+++ b/charm/launchpad-loggerhead/config.yaml
100@@ -0,0 +1,43 @@
101+options:
102+ haproxy_server_options:
103+ type: string
104+ description: Options to add to HAProxy "server" lines.
105+ default: check inter 10000 rise 2 fall 2 maxconn 15
106+ haproxy_service_options:
107+ type: string
108+ description: HAProxy options for codebrowse services.
109+ default: |
110+ - mode http
111+ - option httplog
112+ - option httpchk GET /robots.txt HTTP/1.0
113+ - option forwardfor
114+ - balance leastconn
115+ internal_branch_by_id_root:
116+ type: string
117+ description: |
118+ The URL prefix for where branches are served by URLs based on the
119+ branch ID.
120+ default:
121+ nagios_check_branch:
122+ type: string
123+ description: If set, add Nagios checks for this branch.
124+ default: ""
125+ port_loggerhead:
126+ type: int
127+ description: >
128+ Port to expose to the public (indirectly; we expect Apache on the
129+ Bazaar codehosting system to ProxyPass to this port). This serves
130+ both public and private branches, but requests for private branches
131+ must be authenticated.
132+ default: 10007
133+ port_loggerhead_api:
134+ type: int
135+ description: >
136+ Private port for read-only API requests. This must not be exposed to
137+ the public; other parts of Launchpad with access to this port must
138+ ensure that the appropriate security checks are performed.
139+ default: 10017
140+ session_secret:
141+ type: string
142+ description: A base64-encoded secret key used to sign session cookies.
143+ default: ""
144diff --git a/charm/launchpad-loggerhead/layer.yaml b/charm/launchpad-loggerhead/layer.yaml
145new file mode 100644
146index 0000000..5743ccb
147--- /dev/null
148+++ b/charm/launchpad-loggerhead/layer.yaml
149@@ -0,0 +1,5 @@
150+includes:
151+ - layer:launchpad-base
152+ - layer:coordinator
153+ - interface:http
154+repo: https://git.launchpad.net/launchpad
155diff --git a/charm/launchpad-loggerhead/metadata.yaml b/charm/launchpad-loggerhead/metadata.yaml
156new file mode 100644
157index 0000000..186e666
158--- /dev/null
159+++ b/charm/launchpad-loggerhead/metadata.yaml
160@@ -0,0 +1,18 @@
161+name: launchpad-loggerhead
162+display-name: launchpad-loggerhead
163+summary: Launchpad Bazaar/Breezy code browsing server
164+maintainer: Launchpad Developers <launchpad-dev@lists.launchpad.net>
165+description: |
166+ Launchpad is an open source suite of tools that help people and teams
167+ to work together on software projects.
168+
169+ This charm runs a code browsing server for Bazaar/Breezy branches.
170+tags:
171+ # https://juju.is/docs/charm-metadata#heading--charm-store-fields
172+ - network
173+series:
174+ - focal
175+subordinate: false
176+provides:
177+ loadbalancer:
178+ interface: http
179diff --git a/charm/launchpad-loggerhead/reactive/launchpad-loggerhead.py b/charm/launchpad-loggerhead/reactive/launchpad-loggerhead.py
180new file mode 100644
181index 0000000..e12dd1a
182--- /dev/null
183+++ b/charm/launchpad-loggerhead/reactive/launchpad-loggerhead.py
184@@ -0,0 +1,219 @@
185+# Copyright 2023 Canonical Ltd. This software is licensed under the
186+# GNU Affero General Public License version 3 (see the file LICENSE).
187+
188+import base64
189+import os.path
190+import subprocess
191+
192+import yaml
193+from charmhelpers.core import hookenv, host, templating
194+from charms.coordinator import acquire
195+from charms.launchpad.base import (
196+ get_service_config,
197+ lazr_config_files,
198+ secrets_dir,
199+)
200+from charms.launchpad.payload import (
201+ config_file_path,
202+ configure_cron,
203+ configure_lazr,
204+)
205+from charms.reactive import (
206+ clear_flag,
207+ endpoint_from_flag,
208+ helpers,
209+ set_flag,
210+ when,
211+ when_none,
212+ when_not,
213+ when_not_all,
214+)
215+from ols import base
216+
217+
218+@host.restart_on_change(
219+ {
220+ "/lib/systemd/system/launchpad-loggerhead.service": [
221+ "launchpad-loggerhead.service"
222+ ],
223+ },
224+)
225+def configure_systemd(config):
226+ hookenv.log("Writing systemd service.")
227+ templating.render(
228+ "launchpad-loggerhead.service.j2",
229+ "/lib/systemd/system/launchpad-loggerhead.service",
230+ config,
231+ )
232+ subprocess.run(["systemctl", "daemon-reload"], check=True)
233+
234+
235+def configure_logrotate(config):
236+ hookenv.log("Writing logrotate configuration.")
237+ templating.render(
238+ "logrotate.conf.j2",
239+ "/etc/logrotate.d/loggerhead",
240+ config,
241+ perms=0o644,
242+ )
243+
244+
245+def session_secret_path():
246+ return os.path.join(secrets_dir(), "cookies.hmac")
247+
248+
249+def configure_session_secret(config):
250+ session_secret = base64.b64decode(config["session_secret"].encode())
251+ host.write_file(
252+ session_secret_path(), session_secret, group=base.user(), perms=0o440
253+ )
254+
255+
256+def config_files():
257+ files = []
258+ files.extend(lazr_config_files())
259+ files.append(config_file_path("launchpad-loggerhead/launchpad-lazr.conf"))
260+ files.append(session_secret_path())
261+ return files
262+
263+
264+@when(
265+ "config.set.domain_bzr",
266+ "config.set.session_secret",
267+ "launchpad.base.configured",
268+)
269+@when_none("coordinator.requested.restart", "service.configured")
270+def configure():
271+ config = get_service_config()
272+ config["cache_dir"] = os.path.join(base.base_dir(), "cache")
273+ host.mkdir(
274+ config["cache_dir"], owner=base.user(), group=base.user(), perms=0o700
275+ )
276+ configure_lazr(
277+ config,
278+ "launchpad-loggerhead-lazr.conf",
279+ "launchpad-loggerhead/launchpad-lazr.conf",
280+ )
281+ configure_systemd(config)
282+ configure_logrotate(config)
283+ configure_cron(config, "crontab.j2")
284+ configure_session_secret(config)
285+
286+ if helpers.any_file_changed(
287+ [
288+ base.version_info_path(),
289+ "/lib/systemd/system/launchpad-loggerhead.service",
290+ ]
291+ + config_files()
292+ ):
293+ hookenv.log("Config files changed; waiting for restart lock")
294+ acquire("restart")
295+ else:
296+ hookenv.log("Not restarting, since no config files were changed")
297+ set_flag("service.configured")
298+
299+
300+@when("coordinator.granted.restart")
301+def restart():
302+ hookenv.log("Restarting application server")
303+ host.service_restart("launchpad-loggerhead.service")
304+ set_flag("service.configured")
305+
306+
307+@when("service.configured")
308+def check_is_running():
309+ hookenv.status_set("active", "Ready")
310+
311+
312+@when("service.configured")
313+@when_not_all(
314+ "config.set.domain_bzr",
315+ "config.set.session_secret",
316+ "launchpad.base.configured",
317+)
318+def deconfigure():
319+ clear_flag("service.configured")
320+
321+
322+@when("nrpe-external-master.available", "service.configured")
323+@when_not("launchpad.loggerhead.nrpe-external-master.published")
324+def nrpe_available():
325+ nrpe = endpoint_from_flag("nrpe-external-master.available")
326+ config = hookenv.config()
327+ if config["nagios_check_branch"]:
328+ nrpe.add_check(
329+ [
330+ "/usr/lib/nagios/plugins/check_http",
331+ "-H",
332+ "localhost",
333+ "-p",
334+ str(config["port_loggerhead"]),
335+ "-u",
336+ f"{config['nagios_check_branch']}/files",
337+ ],
338+ name="check_launchpad_loggerhead",
339+ description="Launchpad loggerhead",
340+ context=config["nagios_context"],
341+ )
342+ set_flag("launchpad.loggerhead.nrpe-external-master.published")
343+
344+
345+@when("launchpad.loggerhead.nrpe-external-master.published")
346+@when_not("nrpe-external-master.available")
347+def nrpe_unavailable():
348+ clear_flag("launchpad.loggerhead.nrpe-external-master.published")
349+
350+
351+@when("loadbalancer.available", "service.configured")
352+@when_not("launchpad.loadbalancer.configured")
353+def configure_loadbalancer():
354+ config = hookenv.config()
355+
356+ try:
357+ service_options = yaml.safe_load(config["haproxy_service_options"])
358+ except yaml.YAMLError:
359+ hookenv.log("Could not parse haproxy_service_options YAML")
360+ hookenv.status_set(
361+ "blocked", "Bad haproxy_service_options YAML configuration"
362+ )
363+ return
364+ server_options = config["haproxy_server_options"]
365+
366+ unit_name = hookenv.local_unit().replace("/", "-")
367+ unit_ip = hookenv.unit_private_ip()
368+ services = [
369+ {
370+ "service_name": "launchpad-loggerhead",
371+ "service_port": config["port_loggerhead"],
372+ "service_host": "0.0.0.0",
373+ "service_options": list(service_options),
374+ "servers": [
375+ [
376+ f"public_{unit_name}",
377+ unit_ip,
378+ config["port_loggerhead"],
379+ server_options,
380+ ]
381+ ],
382+ },
383+ {
384+ "service_name": "launchpad-loggerhead-api",
385+ "service_port": config["port_loggerhead_api"],
386+ "service_host": "0.0.0.0",
387+ "service_options": list(service_options),
388+ "servers": [
389+ [
390+ f"public_{unit_name}",
391+ unit_ip,
392+ config["port_loggerhead_api"],
393+ server_options,
394+ ]
395+ ],
396+ },
397+ ]
398+ services_yaml = yaml.dump(services)
399+
400+ for rel in hookenv.relations_of_type("loadbalancer"):
401+ hookenv.relation_set(rel["__relid__"], services=services_yaml)
402+
403+ set_flag("launchpad.loadbalancer.configured")
404diff --git a/charm/launchpad-loggerhead/templates/crontab.j2 b/charm/launchpad-loggerhead/templates/crontab.j2
405new file mode 100644
406index 0000000..0a532ba
407--- /dev/null
408+++ b/charm/launchpad-loggerhead/templates/crontab.j2
409@@ -0,0 +1,10 @@
410+TZ=UTC
411+MAILTO={{ cron_mailto }}
412+
413+# Clean up cache directory.
414+25 0 * * * find {{ cache_dir }} -maxdepth 1 -type d -mtime +240 -execdir rm -rf {} +
415+
416+# Catch up with publishing OOPSes that were temporarily spooled to disk due
417+# to RabbitMQ being unavailable.
418+*/15 * * * * {{ code_dir }}/bin/datedir2amqp --exchange oopses --host {{ rabbitmq_host }} --username {{ rabbitmq_username }} --password {{ rabbitmq_password }} --vhost {{ rabbitmq_vhost }} --repo {{ oopses_dir }} --key ""
419+
420diff --git a/charm/launchpad-loggerhead/templates/launchpad-loggerhead-lazr.conf b/charm/launchpad-loggerhead/templates/launchpad-loggerhead-lazr.conf
421new file mode 100644
422index 0000000..d1212e9
423--- /dev/null
424+++ b/charm/launchpad-loggerhead/templates/launchpad-loggerhead-lazr.conf
425@@ -0,0 +1,24 @@
426+# Public configuration data. The contents of this file may be freely shared
427+# with developers if needed for debugging.
428+
429+# A schema's sections, keys, and values are automatically inherited, except
430+# for '.optional' sections. Update this config to override key values.
431+# Values are strings, except for numbers that look like ints. The tokens
432+# true, false, and none are treated as True, False, and None.
433+
434+{% from "macros.j2" import opt -%}
435+
436+[meta]
437+extends: ../launchpad-base-lazr.conf
438+
439+[codebrowse]
440+cachepath: {{ cache_dir }}
441+launchpad_root: https://code.{{ domain }}/
442+log_folder: {{ logs_dir }}
443+port: {{ port_loggerhead }}
444+private_port: {{ port_loggerhead_api }}
445+secret_path: {{ secrets_dir }}/cookies.hmac
446+
447+[codehosting]
448+{{- opt("internal_branch_by_id_root", internal_branch_by_id_root) }}
449+
450diff --git a/charm/launchpad-loggerhead/templates/launchpad-loggerhead.service.j2 b/charm/launchpad-loggerhead/templates/launchpad-loggerhead.service.j2
451new file mode 100644
452index 0000000..4a98153
453--- /dev/null
454+++ b/charm/launchpad-loggerhead/templates/launchpad-loggerhead.service.j2
455@@ -0,0 +1,22 @@
456+[Unit]
457+Description=Launchpad Bazaar/Breezy code browsing server
458+After=network.target
459+ConditionPathExists=!{{ code_dir }}/maintenance.txt
460+
461+[Service]
462+Type=notify
463+User=launchpad
464+Group=launchpad
465+WorkingDirectory={{ code_dir }}
466+Environment=BRZ_PLUGIN_PATH=brzplugins
467+Environment=LPCONFIG=launchpad-loggerhead
468+SyslogIdentifier=loggerhead
469+ExecStart={{ code_dir }}/scripts/start-loggerhead.py
470+ExecReload=/bin/kill -HUP $MAINPID
471+KillMode=mixed
472+Restart=on-failure
473+PrivateTmp=true
474+
475+[Install]
476+WantedBy=multi-user.target
477+
478diff --git a/charm/launchpad-loggerhead/templates/logrotate.conf.j2 b/charm/launchpad-loggerhead/templates/logrotate.conf.j2
479new file mode 100644
480index 0000000..5bde352
481--- /dev/null
482+++ b/charm/launchpad-loggerhead/templates/logrotate.conf.j2
483@@ -0,0 +1,15 @@
484+{{ logs_dir }}/access.log {{ logs_dir }}/debug.log
485+{
486+ rotate 21
487+ daily
488+ dateext
489+ delaycompress
490+ compress
491+ notifempty
492+ missingok
493+ create 0644 {{ user }} {{ user }}
494+ postrotate
495+ systemctl restart launchpad-loggerhead.service
496+ endscript
497+}
498+

Subscribers

People subscribed via source and target branches

to status/vote changes: