← Back to team overview

launchpad-reviewers team mailing list archive

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

 

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

Commit message:
charm: Add a simple launchpad-admin charm

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

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

This is useful as a way to get hold of database superuser credentials in a charmed deployment, without having to SSH into a `postgresql` unit directly.

For now this is just for interactive use, but I can think of a couple of natural future extensions: we could do with an action to initialize a new Launchpad database, and it might well make sense to use this charm as a place to run our schema upgrade machinery.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:charm-launchpad-admin into launchpad:master.
diff --git a/charm/Makefile b/charm/Makefile
index 24ac014..1b97cdd 100644
--- a/charm/Makefile
+++ b/charm/Makefile
@@ -14,7 +14,9 @@ BUILD_LABEL = $(shell git rev-parse HEAD)
 TARBALL = $(APP_NAME).tar.gz
 ASSET = ../build/$(BUILD_LABEL)/$(TARBALL)
 
-CHARMS := launchpad-appserver
+CHARMS := \
+	launchpad-admin \
+	launchpad-appserver
 
 all: ## alias to build
 all: build
@@ -29,6 +31,9 @@ $(BUILDDIR) $(TMPDIR):
 build: ## build all the charms
 build: $(foreach charm,$(CHARMS),build-$(charm))
 
+build-launchpad-admin: ## build the launchpad-admin charm
+build-launchpad-admin: dist/$(call charm_file,launchpad-admin)
+
 build-launchpad-appserver: ## build the launchpad-appserver charm
 build-launchpad-appserver: dist/$(call charm_file,launchpad-appserver)
 
diff --git a/charm/launchpad-admin/README.md b/charm/launchpad-admin/README.md
new file mode 100644
index 0000000..4241d3d
--- /dev/null
+++ b/charm/launchpad-admin/README.md
@@ -0,0 +1,22 @@
+# Launchpad administrative tools
+
+This charm provides administrative tools for use with a Launchpad
+deployment.
+
+You will need the following relations:
+
+    juju relate launchpad-admin:db postgresql:db
+    juju relate launchpad-admin:db-admin postgresql:db
+    juju relate launchpad-admin:session-db postgresql:db
+    juju relate launchpad-admin rabbitmq-server
+
+This will give you an environment you can SSH into for interactive database
+tasks.
+
+The `db` and `db-admin` commands give you `launchpad_main` and
+superuser-level PostgreSQL clients respectively connected to the main
+database, while the `db-session` command gives you a PostgreSQL client
+connected to the session database.
+
+You can run `/srv/launchpad/code/bin/iharness launchpad_main` to get an
+interactive Python harness authenticated as `launchpad_main`.
diff --git a/charm/launchpad-admin/charmcraft.yaml b/charm/launchpad-admin/charmcraft.yaml
new file mode 100644
index 0000000..f831b9f
--- /dev/null
+++ b/charm/launchpad-admin/charmcraft.yaml
@@ -0,0 +1,58 @@
+type: charm
+bases:
+  - build-on:
+    - name: ubuntu
+      channel: "20.04"
+    run-on:
+    - name: ubuntu
+      channel: "20.04"
+parts:
+  charm-wheels:
+    source: https://git.launchpad.net/~ubuntuone-hackers/ols-charm-deps/+git/wheels
+    source-commit: "fe523e25521254c2034eea96e2fde079034b593a"
+    source-submodules: []
+    source-type: git
+    plugin: dump
+    organize:
+      "*": charm-wheels/
+    prime:
+      - "-charm-wheels"
+  ols-layers:
+    source: https://git.launchpad.net/ols-charm-deps
+    source-commit: "c2faacbd6d227b2ae40ee57ab162b28691e88ca6"
+    source-submodules: []
+    source-type: git
+    plugin: dump
+    organize:
+      "*": layers/
+    stage:
+      - layers
+    prime:
+      - "-layers"
+  launchpad-layers:
+    after:
+      - ols-layers
+    source: https://git.launchpad.net/launchpad-layers
+    source-commit: "624df58b5b21a34f8931bba12931e1e3a37ac7b5"
+    source-submodules: []
+    source-type: git
+    plugin: dump
+    organize:
+      launchpad-base: layers/layer/launchpad-base
+    stage:
+      - layers
+    prime:
+      - "-layers"
+  launchpad-admin:
+    after:
+      - charm-wheels
+      - launchpad-layers
+    source: .
+    plugin: reactive
+    build-snaps: [charm/2.x/stable]
+    build-packages: [libpq-dev]
+    build-environment:
+      - CHARM_LAYERS_DIR: $CRAFT_STAGE/layers/layer
+      - CHARM_INTERFACES_DIR: $CRAFT_STAGE/layers/interface
+      - PIP_NO_INDEX: "true"
+      - PIP_FIND_LINKS: $CRAFT_STAGE/charm-wheels
diff --git a/charm/launchpad-admin/layer.yaml b/charm/launchpad-admin/layer.yaml
new file mode 100644
index 0000000..352e6d4
--- /dev/null
+++ b/charm/launchpad-admin/layer.yaml
@@ -0,0 +1,21 @@
+includes:
+  - layer:launchpad-base
+repo: https://git.launchpad.net/launchpad
+options:
+  apt:
+    packages:
+      - postgresql-client
+  ols:
+    # This charm is intended mainly for interactive use, so it's more
+    # convenient to just use the `ubuntu` user.
+    user: ubuntu
+  ols-pg:
+    databases:
+      db:
+        name: launchpad_dev
+        roles: launchpad_main
+      db-admin:
+        name: launchpad_dev
+      session-db:
+        name: session_dev
+        roles: session
diff --git a/charm/launchpad-admin/metadata.yaml b/charm/launchpad-admin/metadata.yaml
new file mode 100644
index 0000000..974315f
--- /dev/null
+++ b/charm/launchpad-admin/metadata.yaml
@@ -0,0 +1,21 @@
+name: launchpad-admin
+display-name: launchpad-admin
+summary: Launchpad administrative tools
+maintainer: Colin Watson <cjwatson@xxxxxxxxxxxxx>
+description: |
+  Launchpad is an open source suite of tools that help people and teams
+  to work together on software projects.
+
+  This charm provides administrative tools for use with a Launchpad
+  deployment.
+tags:
+  # https://juju.is/docs/charm-metadata#heading--charm-store-fields
+  - network
+series:
+  - focal
+subordinate: false
+requires:
+  db-admin:
+    interface: pgsql
+  session-db:
+    interface: pgsql
diff --git a/charm/launchpad-admin/reactive/launchpad-admin.py b/charm/launchpad-admin/reactive/launchpad-admin.py
new file mode 100644
index 0000000..0a31116
--- /dev/null
+++ b/charm/launchpad-admin/reactive/launchpad-admin.py
@@ -0,0 +1,71 @@
+# Copyright 2023 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+import os.path
+
+from charmhelpers.core import hookenv, host, templating
+from charms.launchpad.base import (
+    configure_lazr,
+    get_service_config,
+    home_dir,
+    strip_dsn_authentication,
+    update_pgpass,
+)
+from charms.reactive import set_state, when, when_not
+from ols import base, postgres
+from psycopg2.extensions import make_dsn, parse_dsn
+
+
+def strip_password(dsn):
+    parsed_dsn = parse_dsn(dsn)
+    parsed_dsn.pop("password", None)
+    return make_dsn(**parsed_dsn)
+
+
+@when(
+    "launchpad.base.configured",
+    "db.master.available",
+    "db-admin.master.available",
+    "session-db.master.available",
+)
+@when_not("service_configured")
+def configure(db, db_admin, session_db):
+    config = get_service_config()
+    db_primary, _ = postgres.get_db_uris(db)
+    db_admin_primary, _ = postgres.get_db_uris(db_admin)
+    session_db_primary, _ = postgres.get_db_uris(session_db)
+    update_pgpass(db_admin_primary)
+    update_pgpass(session_db_primary)
+    config["db_primary"] = strip_password(db_primary)
+    config["db_admin_primary"] = strip_password(db_admin_primary)
+    config["db_session_primary"] = strip_password(session_db_primary)
+    config["db_session"] = strip_dsn_authentication(session_db_primary)
+    config["db_session_user"] = parse_dsn(session_db_primary)["user"]
+    configure_lazr(
+        config,
+        "launchpad-admin-lazr.conf",
+        "launchpad-admin/launchpad-lazr.conf",
+    )
+    templating.render(
+        "bash_aliases.j2",
+        os.path.join(home_dir(), ".bash_aliases"),
+        config,
+        owner=base.user(),
+        group=base.user(),
+        perms=0o644,
+    )
+    bin_dir = os.path.join(home_dir(), "bin")
+    host.mkdir(bin_dir, owner=base.user(), group=base.user(), perms=0o755)
+    for script in ("db", "db-admin", "db-session"):
+        script_path = os.path.join(bin_dir, script)
+        templating.render(
+            f"{script}.j2",
+            script_path,
+            config,
+            owner=base.user(),
+            group=base.user(),
+            perms=0o755,
+        )
+
+    set_state("service.configured")
+    hookenv.status_set("active", "Ready")
diff --git a/charm/launchpad-admin/templates/bash_aliases.j2 b/charm/launchpad-admin/templates/bash_aliases.j2
new file mode 100644
index 0000000..b5f4133
--- /dev/null
+++ b/charm/launchpad-admin/templates/bash_aliases.j2
@@ -0,0 +1,9 @@
+# Copyright 2023 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+# Part of the launchpad-admin Juju charm.
+
+# This isn't an alias, but ~/.bash_aliases is conveniently already sourced
+# by the default ~/.bashrc.
+export LPCONFIG=launchpad-admin
+
diff --git a/charm/launchpad-admin/templates/db-admin.j2 b/charm/launchpad-admin/templates/db-admin.j2
new file mode 100644
index 0000000..aa0f73d
--- /dev/null
+++ b/charm/launchpad-admin/templates/db-admin.j2
@@ -0,0 +1,10 @@
+#! /bin/sh
+# Copyright 2023 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+# Part of the launchpad-admin Juju charm.
+
+set -e
+
+psql '{{ db_admin_primary }}'
+
diff --git a/charm/launchpad-admin/templates/db-session.j2 b/charm/launchpad-admin/templates/db-session.j2
new file mode 100755
index 0000000..4d776ae
--- /dev/null
+++ b/charm/launchpad-admin/templates/db-session.j2
@@ -0,0 +1,10 @@
+#! /bin/sh
+# Copyright 2023 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+# Part of the launchpad-admin Juju charm.
+
+set -e
+
+psql '{{ db_session_primary }}'
+
diff --git a/charm/launchpad-admin/templates/db.j2 b/charm/launchpad-admin/templates/db.j2
new file mode 100644
index 0000000..f07f7e8
--- /dev/null
+++ b/charm/launchpad-admin/templates/db.j2
@@ -0,0 +1,10 @@
+#! /bin/sh
+# Copyright 2023 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+# Part of the launchpad-admin Juju charm.
+
+set -e
+
+psql '{{ db_primary }}'
+
diff --git a/charm/launchpad-admin/templates/launchpad-admin-lazr.conf b/charm/launchpad-admin/templates/launchpad-admin-lazr.conf
new file mode 100644
index 0000000..b652e52
--- /dev/null
+++ b/charm/launchpad-admin/templates/launchpad-admin-lazr.conf
@@ -0,0 +1,17 @@
+# Public configuration data.  The contents of this file may be freely shared
+# with developers if needed for debugging.
+
+# A schema's sections, keys, and values are automatically inherited, except
+# for '.optional' sections.  Update this config to override key values.
+# Values are strings, except for numbers that look like ints.  The tokens
+# true, false, and none are treated as True, False, and None.
+
+{% from "macros.j2" import opt -%}
+
+[meta]
+extends: ../launchpad-base-lazr.conf
+
+[launchpad_session]
+database: {{ db_session }}
+dbuser: {{ db_session_user }}
+