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 <cjwat...@canonical.com> +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 }} +
_______________________________________________ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp