Merge ~cjwatson/launchpad:charm-scripts-actions into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 7169f5d2a6c300e02bbd651044caf2cd49165769
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:charm-scripts-actions
Merge into: launchpad:master
Diff against target: 116 lines (+82/-0)
5 files modified
charm/launchpad-scripts/README.md (+11/-0)
charm/launchpad-scripts/actions.yaml (+9/-0)
charm/launchpad-scripts/actions/actions.py (+60/-0)
charm/launchpad-scripts/actions/start-services (+1/-0)
charm/launchpad-scripts/actions/stop-services (+1/-0)
Reviewer Review Type Date Requested Status
Guruprasad Approve
Ines Almeida Approve
Review via email: mp+445674@code.launchpad.net

Commit message

charm/launchpad-scripts: Add start-services/stop-services actions

Description of the change

In our legacy production deployment, we stop and start these services around certain kinds of maintenance actions, mainly database schema upgrades. 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.

To post a comment you must log in.
Revision history for this message
Ines Almeida (ines-almeida) wrote :

Makes sense to me

Added a small question in the comments.
Also what's the purpose of `hookenv.action_set()`? In the docs it seems to be the value that the action returns - but we don't seem to use any return value from the actions (?). Is it mostly because as action needs to return something?

review: Approve
Revision history for this message
Guruprasad (lgp171188) :
review: Approve
5458c60... by Colin Watson

Clarify a couple of documentation points

Revision history for this message
Colin Watson (cjwatson) :
Revision history for this message
Colin Watson (cjwatson) wrote :

`hookenv.action_set` is indeed just because it's generally expected that actions return something. The arguments to that should show up in the output from `juju run-action --wait`.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/charm/launchpad-scripts/README.md b/charm/launchpad-scripts/README.md
2index ec07c92..257a0f7 100644
3--- a/charm/launchpad-scripts/README.md
4+++ b/charm/launchpad-scripts/README.md
5@@ -8,3 +8,14 @@ You will need the following relations:
6 juju relate launchpad-scripts:session-db postgresql:db
7 juju relate launchpad-scripts memcached
8 juju relate launchpad-scripts rabbitmq-server
9+
10+## Maintenance actions
11+
12+To stop Celery workers and `number-cruncher` (perhaps in preparation for a
13+schema upgrade), run:
14+
15+ juju run-action --wait launchpad-scripts/leader stop-services
16+
17+To start them again once maintenance is complete:
18+
19+ juju run-action --wait launchpad-scripts/leader start-services
20diff --git a/charm/launchpad-scripts/actions.yaml b/charm/launchpad-scripts/actions.yaml
21new file mode 100644
22index 0000000..aa1c55c
23--- /dev/null
24+++ b/charm/launchpad-scripts/actions.yaml
25@@ -0,0 +1,9 @@
26+start-services:
27+ description: Start services. Usually run after maintenance.
28+stop-services:
29+ description: |
30+ Stop services. Usually run in preparation for maintenance. (Note that
31+ this does not stop services in a way that will persist across a reboot.
32+ It also doesn't disable cron jobs, since those are handled by the
33+ cron-control mechanism instead; see
34+ lp.services.scripts.base.cronscript_enabled.)
35diff --git a/charm/launchpad-scripts/actions/actions.py b/charm/launchpad-scripts/actions/actions.py
36new file mode 100755
37index 0000000..67d862c
38--- /dev/null
39+++ b/charm/launchpad-scripts/actions/actions.py
40@@ -0,0 +1,60 @@
41+#! /usr/bin/python3
42+# Copyright 2023 Canonical Ltd. This software is licensed under the
43+# GNU Affero General Public License version 3 (see the file LICENSE).
44+
45+import subprocess
46+import sys
47+import traceback
48+from pathlib import Path
49+
50+sys.path.append("lib")
51+
52+from charms.layer import basic # noqa: E402
53+
54+basic.bootstrap_charm_deps()
55+basic.init_config_states()
56+
57+from charmhelpers.core import hookenv # noqa: E402
58+
59+services = (
60+ "celerybeat_launchpad.service",
61+ "celeryd_launchpad_job.service",
62+ "celeryd_launchpad_job_slow.service",
63+ "number-cruncher.service",
64+)
65+
66+
67+def start_services():
68+ for service in services:
69+ hookenv.log(f"Starting {service}.")
70+ subprocess.run(["systemctl", "start", service], check=True)
71+ hookenv.action_set({"result": "Services started"})
72+
73+
74+def stop_services():
75+ for service in services:
76+ hookenv.log(f"Stopping {service}.")
77+ subprocess.run(["systemctl", "stop", service], check=True)
78+ hookenv.action_set({"result": "Services stopped"})
79+
80+
81+def main(argv):
82+ action = Path(argv[0]).name
83+ try:
84+ if action == "start-services":
85+ start_services()
86+ elif action == "stop-services":
87+ stop_services()
88+ else:
89+ hookenv.action_fail(f"Action {action} not implemented.")
90+ except Exception:
91+ hookenv.action_fail("Unhandled exception")
92+ tb = traceback.format_exc()
93+ hookenv.action_set(dict(traceback=tb))
94+ hookenv.log(f"Unhandled exception in action {action}:")
95+ for line in tb.splitlines():
96+ hookenv.log(line)
97+
98+
99+if __name__ == "__main__":
100+ main(sys.argv)
101diff --git a/charm/launchpad-scripts/actions/start-services b/charm/launchpad-scripts/actions/start-services
102new file mode 120000
103index 0000000..405a394
104--- /dev/null
105+++ b/charm/launchpad-scripts/actions/start-services
106@@ -0,0 +1 @@
107+actions.py
108\ No newline at end of file
109diff --git a/charm/launchpad-scripts/actions/stop-services b/charm/launchpad-scripts/actions/stop-services
110new file mode 120000
111index 0000000..405a394
112--- /dev/null
113+++ b/charm/launchpad-scripts/actions/stop-services
114@@ -0,0 +1 @@
115+actions.py
116\ No newline at end of file

Subscribers

People subscribed via source and target branches

to status/vote changes: