← Back to team overview

launchpad-reviewers team mailing list archive

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

 

Colin Watson has proposed merging ~cjwatson/launchpad:charm-scripts-actions into launchpad:master.

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

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/445674

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.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:charm-scripts-actions into launchpad:master.
diff --git a/charm/launchpad-scripts/README.md b/charm/launchpad-scripts/README.md
index ec07c92..2bc506a 100644
--- a/charm/launchpad-scripts/README.md
+++ b/charm/launchpad-scripts/README.md
@@ -8,3 +8,14 @@ You will need the following relations:
     juju relate launchpad-scripts:session-db postgresql:db
     juju relate launchpad-scripts memcached
     juju relate launchpad-scripts rabbitmq-server
+
+## Maintenance actions
+
+To stop long-running services (perhaps in preparation for a schema upgrade),
+run:
+
+    juju run-action --wait launchpad-scripts/leader stop-services
+
+To start them again once maintenance is complete:
+
+    juju run-action --wait launchpad-scripts/leader start-services
diff --git a/charm/launchpad-scripts/actions.yaml b/charm/launchpad-scripts/actions.yaml
new file mode 100644
index 0000000..910d658
--- /dev/null
+++ b/charm/launchpad-scripts/actions.yaml
@@ -0,0 +1,7 @@
+start-services:
+  description: Start services.  Usually run after maintenance.
+stop-services:
+  description: |
+    Stop services.  Usually run in preparation for maintenance.  (Note that
+    this does not stop services in a way that will persist across a reboot,
+    nor does it disable cron jobs.)
diff --git a/charm/launchpad-scripts/actions/actions.py b/charm/launchpad-scripts/actions/actions.py
new file mode 100755
index 0000000..67d862c
--- /dev/null
+++ b/charm/launchpad-scripts/actions/actions.py
@@ -0,0 +1,60 @@
+#! /usr/bin/python3
+# Copyright 2023 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+import subprocess
+import sys
+import traceback
+from pathlib import Path
+
+sys.path.append("lib")
+
+from charms.layer import basic  # noqa: E402
+
+basic.bootstrap_charm_deps()
+basic.init_config_states()
+
+from charmhelpers.core import hookenv  # noqa: E402
+
+services = (
+    "celerybeat_launchpad.service",
+    "celeryd_launchpad_job.service",
+    "celeryd_launchpad_job_slow.service",
+    "number-cruncher.service",
+)
+
+
+def start_services():
+    for service in services:
+        hookenv.log(f"Starting {service}.")
+        subprocess.run(["systemctl", "start", service], check=True)
+    hookenv.action_set({"result": "Services started"})
+
+
+def stop_services():
+    for service in services:
+        hookenv.log(f"Stopping {service}.")
+        subprocess.run(["systemctl", "stop", service], check=True)
+    hookenv.action_set({"result": "Services stopped"})
+
+
+def main(argv):
+    action = Path(argv[0]).name
+    try:
+        if action == "start-services":
+            start_services()
+        elif action == "stop-services":
+            stop_services()
+        else:
+            hookenv.action_fail(f"Action {action} not implemented.")
+    except Exception:
+        hookenv.action_fail("Unhandled exception")
+        tb = traceback.format_exc()
+        hookenv.action_set(dict(traceback=tb))
+        hookenv.log(f"Unhandled exception in action {action}:")
+        for line in tb.splitlines():
+            hookenv.log(line)
+
+
+if __name__ == "__main__":
+    main(sys.argv)
diff --git a/charm/launchpad-scripts/actions/start-services b/charm/launchpad-scripts/actions/start-services
new file mode 120000
index 0000000..405a394
--- /dev/null
+++ b/charm/launchpad-scripts/actions/start-services
@@ -0,0 +1 @@
+actions.py
\ No newline at end of file
diff --git a/charm/launchpad-scripts/actions/stop-services b/charm/launchpad-scripts/actions/stop-services
new file mode 120000
index 0000000..405a394
--- /dev/null
+++ b/charm/launchpad-scripts/actions/stop-services
@@ -0,0 +1 @@
+actions.py
\ No newline at end of file