← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:charmcraft-fetch-dependencies into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:charmcraft-fetch-dependencies into launchpad:master.

Commit message:
charm: Fetch dependencies using charmcraft

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

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

Now that `ols-layers` is open-source, we can fetch it directly using `charmcraft`, which is much simpler and should let us use Launchpad charm recipes.

I had to split out `charm/layer/` to a separate https://git.launchpad.net/launchpad-layers project, because `charmcraft` can't deal with referencing the parent directory from one of a charm's parts.  That separation isn't ideal, but the benefits of being able to use charm recipes should outweigh the costs.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:charmcraft-fetch-dependencies into launchpad:master.
diff --git a/charm/.gitignore b/charm/.gitignore
index de07da3..da831d3 100644
--- a/charm/.gitignore
+++ b/charm/.gitignore
@@ -1,5 +1,4 @@
 *.charm
 bundle.yaml
 dist
-layer/*/codetree-collect-info.yaml
 tmp
diff --git a/charm/Makefile b/charm/Makefile
index 2e659ca..24ac014 100644
--- a/charm/Makefile
+++ b/charm/Makefile
@@ -5,8 +5,6 @@ APP_NAME := launchpad
 
 BUILDDIR := $(CURDIR)/dist
 TMPDIR := $(CURDIR)/tmp
-CHARM_LAYERS_DIR := $(TMPDIR)/deps/ols-layers/layer
-CHARM_INTERFACES_DIR := $(TMPDIR)/deps/ols-layers/interface
 
 CHARM_SERIES ?= 20.04
 ARCH := $(shell dpkg --print-architecture)
@@ -28,23 +26,13 @@ help: ## display this help message
 $(BUILDDIR) $(TMPDIR):
 	@mkdir -p $@
 
-# We have to clone our dependencies by hand rather than letting charmcraft
-# do it, since some of them are in private repositories and charmcraft
-# doesn't have suitable credentials.
-CHARM_DEPS := $(CHARM_LAYERS_DIR)/.done $(CHARM_INTERFACES_DIR)/.done
-$(CHARM_DEPS): $(CURDIR)/dependencies.txt | $(TMPDIR)
-	@echo "Fetching dependencies..."
-	@mkdir -p $(TMPDIR)/deps
-	@cd $(TMPDIR)/deps && codetree $<
-	@touch $(CHARM_DEPS)
-
 build: ## build all the charms
 build: $(foreach charm,$(CHARMS),build-$(charm))
 
 build-launchpad-appserver: ## build the launchpad-appserver charm
 build-launchpad-appserver: dist/$(call charm_file,launchpad-appserver)
 
-dist/%_ubuntu-$(CHARM_SERIES)-$(ARCH).charm: $(CHARM_DEPS) | $(BUILDDIR)
+dist/%_ubuntu-$(CHARM_SERIES)-$(ARCH).charm: $(BUILDDIR)
 	echo "Building $*..."
 	rm -rf $*/tmp
 	cp -a tmp $*/tmp
@@ -58,7 +46,6 @@ clean: $(foreach charm,$(CHARMS),clean-$(charm))
 	@find . -name \*.pyc -delete
 	@find . -depth -name '__pycache__' -exec rm -rf '{}' \;
 	@rm -f bundle.yaml
-	@rm -f layer/*/codetree-collect-info.yaml
 	@rm -rf $(BUILDDIR) $(TMPDIR)
 
 clean-%:
diff --git a/charm/dependencies.txt b/charm/dependencies.txt
deleted file mode 100644
index 1ca5896..0000000
--- a/charm/dependencies.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-ols-layers		git+ssh://git.launchpad.net/~ubuntuone-pqm-team/ols-charm-deps/+git/ols-layers;revno=c2faacbd
-charm-wheels		git+ssh://git.launchpad.net/~ubuntuone-hackers/ols-charm-deps/+git/wheels;revno=fe523e25
diff --git a/charm/launchpad-appserver/charmcraft.yaml b/charm/launchpad-appserver/charmcraft.yaml
index ff2bada..adddf81 100644
--- a/charm/launchpad-appserver/charmcraft.yaml
+++ b/charm/launchpad-appserver/charmcraft.yaml
@@ -7,15 +7,52 @@ bases:
     - 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: "a5ad373e6aadc94aa828c76d29849a610ad09bc1"
+    source-submodules: []
+    source-type: git
+    plugin: dump
+    organize:
+      launchpad-base: layers/layer/launchpad-base
+    stage:
+      - layers
+    prime:
+      - "-layers"
   launchpad-appserver:
+    after:
+      - charm-wheels
+      - launchpad-layers
     source: .
     plugin: reactive
     build-snaps: [charm/2.x/stable]
     build-packages: [libpq-dev]
     build-environment:
-      - CHARM_LAYERS_DIR: tmp/deps/ols-layers/layer
-      - CHARM_INTERFACES_DIR: tmp/deps/ols-layers/interface
+      - CHARM_LAYERS_DIR: $CRAFT_STAGE/layers/layer
+      - CHARM_INTERFACES_DIR: $CRAFT_STAGE/layers/interface
       - PIP_NO_INDEX: "true"
-      - PIP_FIND_LINKS: tmp/deps/charm-wheels
-    stage:
-      - -tmp
+      - PIP_FIND_LINKS: $CRAFT_STAGE/charm-wheels
diff --git a/charm/launchpad/charmcraft.yaml b/charm/launchpad/charmcraft.yaml
index 0c3d3f2..cd7136c 100644
--- a/charm/launchpad/charmcraft.yaml
+++ b/charm/launchpad/charmcraft.yaml
@@ -7,14 +7,52 @@ bases:
     - 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: "a5ad373e6aadc94aa828c76d29849a610ad09bc1"
+    source-submodules: []
+    source-type: git
+    plugin: dump
+    organize:
+      launchpad-base: layers/layer/launchpad-base
+    stage:
+      - layers
+    prime:
+      - "-layers"
   launchpad:
+    after:
+      - charm-wheels
+      - launchpad-layers
     source: .
     plugin: reactive
     build-snaps: [charm/2.x/stable]
+    build-packages: [libpq-dev]
     build-environment:
-      - CHARM_LAYERS_DIR: tmp/deps/ols-layers/layer
-      - CHARM_INTERFACES_DIR: tmp/deps/ols-layers/interface
+      - CHARM_LAYERS_DIR: $CRAFT_STAGE/layers/layer
+      - CHARM_INTERFACES_DIR: $CRAFT_STAGE/layers/interface
       - PIP_NO_INDEX: "true"
-      - PIP_FIND_LINKS: tmp/deps/charm-wheels
-    stage:
-      - -tmp
+      - PIP_FIND_LINKS: $CRAFT_STAGE/charm-wheels
diff --git a/charm/layer/launchpad-base/config.yaml b/charm/layer/launchpad-base/config.yaml
deleted file mode 100644
index 4f2b83b..0000000
--- a/charm/layer/launchpad-base/config.yaml
+++ /dev/null
@@ -1,267 +0,0 @@
-options:
-  bounce_address:
-    type: string
-    description: Envelope sender address for outgoing email.
-    default: "noreply@xxxxxxxxxxxxxx"
-  bzr_imports_root_url:
-    type: string
-    description: >
-      Internal URL prefix for Bazaar branches imported from other revision
-      control systems, used by the branch puller.
-    default:
-  bzr_lp_prefix:
-    type: string
-    description: >
-      URL prefix used to address Bazaar branches on this instance.
-    default: lp://dev/
-  bzr_lp_url_hosts:
-    type: string
-    description: >
-      Comma-separated list of hosts which may be used to refer to this
-      server's branches in "lp:" URLs.
-    default: dev
-  candid_service_root:
-    type: string
-    description: >
-      URL to the Candid service, used to discharge certain kinds of
-      macaroons.
-    default:
-  charmhub_secrets_public_key:
-    type: string
-    description: >
-      Base64-encoded NaCl public key for encrypting Charmhub upload tokens.
-    default:
-  charmhub_storage_url:
-    type: string
-    description: Charmhub's storage URL endpoint.
-    default:
-  charmhub_url:
-    type: string
-    description: Charmhub's primary URL endpoint.
-    default:
-  cron_control_url:
-    type: string
-    description: URL of file used to control whether cron scripts run.
-    default: "file:cronscripts.ini"
-  databases:
-    type: string
-    description: >
-      YAML-encoded information about database relations, overriding the
-      defaults.  For example, setting this to "db: {name: launchpad_prod}"
-      changes the name of the database used by the "db" relation.
-    default: ""
-  db_statement_timeout:
-    type: int
-    description: SQL statement timeout in milliseconds.
-    default:
-  default_batch_size:
-    type: int
-    description: The default size used in a batched listing of results.
-    default: 50
-  domain:
-    type: string
-    description: Domain name for this instance.
-    default: "launchpad.test"
-  domain_bzr:
-    type: string
-    description: Domain name for this instance's Bazaar service, if any.
-    default:
-  domain_git:
-    type: string
-    description: Domain name for this instance's Git service, if any.
-    default:
-  domain_lists:
-    type: string
-    description: >
-      Domain name for this instance's mailing list service, if any.
-    default:
-  domain_xmlrpc_private:
-    type: string
-    description: Domain name for this instance's private XML-RPC service.
-    default: "xmlrpc-private.launchpad.test"
-  geoip_database:
-    type: string
-    description: >
-      The database used by our GeoIP library.  Only GeoIP2/GeoLite2 Country
-      databases are supported.
-    default:
-  git_loose_objects_threshold:
-    type: int
-    description: >
-      Threshold for the number of loose objects that triggers automatic
-      repacking of Git repositories.
-    default:
-  git_packs_threshold:
-    type: int
-    description: >
-      Threshold for the number of pack files that triggers automatic
-      repacking of Git repositories.
-    default:
-  gpg_upload_keys:
-    type: boolean
-    description: Should we allow uploading keys to the keyserver?
-    default: false
-  is_demo:
-    type: boolean
-    description: >
-      Should pages be styled to indicate the use of a demo system?
-    default: true
-  http_proxy:
-    type: string
-    description: Proxy to be used when issuing HTTP requests.
-    default:
-  internal_bzr_api_endpoint:
-    type: string
-    description: The URL of the internal Bazaar hosting API endpoint.
-    default:
-  librarian_download_host:
-    type: string
-    description: Host the Librarian is listening on for HTTP requests.
-    default:
-  librarian_download_port:
-    type: int
-    description: >
-      Port number the Librarian listens for HTTP GET and HEAD requests on.
-    default:
-  librarian_download_url:
-    type: string
-    description: The base URL used to generate URLs to the Library contents.
-    default:
-  librarian_restricted_download_host:
-    type: string
-    description: >
-      Host the Restricted Librarian is listening on for HTTP requests.
-    default:
-  librarian_restricted_download_port:
-    type: int
-    description: >
-      Port number the Restricted Librarian listens for HTTP GET and HEAD
-      requests on.
-    default:
-  librarian_restricted_download_url:
-    type: string
-    description: >
-      The base URL used to generate URLs to the Restricted Library contents.
-    default:
-  librarian_restricted_upload_host:
-    type: string
-    description: >
-      Host the Restricted Librarian is listening on for storage requests.
-    default:
-  librarian_restricted_upload_port:
-    type: int
-    description: >
-      Port number the Restricted Librarian listens for storage requests on.
-    default:
-  librarian_upload_host:
-    type: string
-    description: Host the Librarian is listening on for storage requests.
-    default:
-  librarian_upload_port:
-    type: int
-    description: >
-      Port number the Librarian listens for storage requests on.
-    default:
-  log_hosts_allow:
-    type: string
-    description: >
-      Hosts that should be allowed to rsync logs.  Note that this relies on
-      the nrpe subordinate charm to set up /etc/rsyncd.conf properly.
-    default: ""
-  mailman_shared_secret:
-    type: string
-    description: >
-      Shared secret used to pre-approve Launchpad-generated messages to
-      Launchpad mailing lists.
-    default:
-  oci_registry_credentials_public_key:
-    type: string
-    description: >
-      Base64-encoded NaCl public key for encrypting OCI registry upload
-      credentials.
-    default:
-  oops_prefix:
-    type: string
-    description: A prefix for OOPS codes for this instance.
-    default: "TEST"
-  openid_alternate_provider_roots:
-    type: string
-    description: >
-      Comma-separated list of additional URLs to recognise as valid prefixes
-      for our accounts' OpenID identifiers.
-    default:
-  openid_provider_root:
-    type: string
-    description: URL to the OpenID provider to authenticate against.
-    default: https://testopenid.test/
-  port_xmlrpc:
-    type: int
-    description: Port for the XML-RPC application server.
-    default: 8087
-  ppa_base_url:
-    type: string
-    description: External base URL for PPAs.
-    default: http://ppa.launchpad.test/
-  ppa_private_base_url:
-    type: string
-    description: External base URL for private PPAs.
-    default: http://private-ppa.launchpad.test/
-  rabbitmq_user:
-    type: string
-    description: Username to use with RabbitMQ.
-    default: test
-  session_cookie_name:
-    type: string
-    description: The ID of the cookie used to store the session token.
-    default: launchpad_dev
-  site_message:
-    type: string
-    description: >
-      If provided, this message will appear in the site status bar at the
-      top of every page.
-    default:
-  snap_store_secrets_public_key:
-    type: string
-    description: >
-      Base64-encoded NaCl public key for encrypting snap store upload
-      tokens.
-    default:
-  snap_store_upload_url:
-    type: string
-    description: The snap store's upload URL endpoint.
-    default:
-  snap_store_url:
-    type: string
-    description: The snap store's primary URL endpoint.
-    default:
-  soft_request_timeout:
-    type: int
-    description: Soft request timeout in milliseconds.
-    default:
-  statsd_environment:
-    type: string
-    description: Statsd environment name.
-    default:
-  ubuntu_disable_filebug:
-    type: boolean
-    description: Should +filebug be disabled for Ubuntu?
-    default: false
-  uploader_default_recipient:
-    type: string
-    description: Default email recipient for package upload notifications.
-    default:
-  uploader_default_sender:
-    type: string
-    description: Default email sender for package upload notifications.
-    default:
-  webhooks_proxy_url:
-    type: string
-    description: Outbound webhook request proxy URL.
-    default:
-  # layer-apt
-  install_sources:
-    default: |
-      - ppa:launchpad/ppa
-  install_keys:
-    default: |
-      - null  # PPA keys securely added via Launchpad.
diff --git a/charm/layer/launchpad-base/icon.svg b/charm/layer/launchpad-base/icon.svg
deleted file mode 100644
index b2889cc..0000000
--- a/charm/layer/launchpad-base/icon.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg"; viewBox="0 0 165.39062 165.39062"><defs><style>.cls-1{fill:#e9500e;}.cls-2{fill:#fff;}</style></defs><rect class="cls-1" width="165.39062" height="165.39062"/><path class="cls-2" d="M29.63876,57.97189C43.189,67.692,61.13456,69.25577,77.65457,62.15038c16.25576-6.87157,27.74036-21.43444,29.97828-38.0075.04663-.34331.11016-.81367-1.59861-1.24044l-10.10934-2.197c-.3254-.04494-.79136-.04967-1.15258,1.22455C91.37844,36.07384,84.34062,45.04243,72.6347,50.1123c-11.77316,5.10029-23.18748,4.05279-35.91893-3.29386-.58119-.27843-.91909-.26086-1.45568.52577l-5.77947,8.65163A1.34512,1.34512,0,0,0,29.63876,57.97189Z" transform="translate(0.39062 0.39062)"/><path class="cls-2" d="M79.86106,139.66026l10.3631.565c1.74155.03446,1.79122-.42981,1.83717-.77312,2.23826-16.5734-4.97222-33.66107-18.81739-44.59422C59.196,83.62132,41.47815,80.36935,25.83365,86.14747a1.33956,1.33956,0,0,0-.67918,1.85373l3.28,9.88226c.30952.90153.62816,1.011,1.26443.89409,14.22464-3.70543,25.50717-1.68748,35.50635,6.3512,9.94174,7.9934,14.34865,18.50754,13.86883,33.08867C79.08524,139.50144,79.53735,139.615,79.86106,139.66026Z" transform="translate(0.39062 0.39062)"/><path class="cls-2" d="M86.50488,70.59048a10.50817,10.50817,0,0,0-1.39587-.09461A9.35237,9.35237,0,0,0,79.39915,72.382a9.61981,9.61981,0,1,0,7.10573-1.79156Z" transform="translate(0.39062 0.39062)"/><path class="cls-2" d="M138.26869,53.18923,133.457,43.97736c-.68628-1.51583-1.22793-1.36985-1.79594-1.17657-15.382,6.63165-25.99848,21.22156-28.40434,39.03776-2.40755,17.82971,3.97169,34.72681,17.0647,45.19906a1.177,1.177,0,0,0,.90794.32844,1.48362,1.48362,0,0,0,.99546-.54l6.76175-8.11166c.62342-.78393.35783-1.18333.0321-1.52461-10.60639-10.44454-14.5764-20.81677-12.84905-33.60769,1.73682-12.86121,8.51918-22.08254,21.34457-29.019C138.52854,53.95289,138.36533,53.421,138.26869,53.18923Z" transform="translate(0.39062 0.39062)"/></svg>
\ No newline at end of file
diff --git a/charm/layer/launchpad-base/layer.yaml b/charm/layer/launchpad-base/layer.yaml
deleted file mode 100644
index 9ef3fe4..0000000
--- a/charm/layer/launchpad-base/layer.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-includes:
-  - layer:basic
-  - layer:ols-pg
-  - interface:rabbitmq
-options:
-  apt:
-    packages:
-      - launchpad-dependencies
-  ols:
-    service_name: launchpad
-    config_filename: service.conf
-    user: launchpad
-    tarball_payload: true
-    symlink_switch_payload: true
-    python_bin: /usr/bin/python3
-repo: https://git.launchpad.net/launchpad
diff --git a/charm/layer/launchpad-base/lib/charms/launchpad/base.py b/charm/layer/launchpad-base/lib/charms/launchpad/base.py
deleted file mode 100644
index 71f0dbe..0000000
--- a/charm/layer/launchpad-base/lib/charms/launchpad/base.py
+++ /dev/null
@@ -1,195 +0,0 @@
-# Copyright 2022 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-import grp
-import os.path
-import pwd
-import re
-from dataclasses import dataclass
-from email.utils import parseaddr
-
-from charmhelpers.core import hookenv, host, templating
-from ols import base
-from psycopg2.extensions import make_dsn, parse_dsn
-
-
-def home_dir():
-    return os.path.join("/home", base.user())
-
-
-def oopses_dir():
-    return os.path.join(base.base_dir(), "oopses")
-
-
-def secrets_dir():
-    return os.path.join(base.base_dir(), "secrets")
-
-
-def var_dir():
-    return os.path.join(base.base_dir(), "var")
-
-
-def ensure_lp_directories():
-    for dirpath in oopses_dir(), var_dir():
-        host.mkdir(dirpath, group=base.user(), perms=0o775)
-    host.mkdir(secrets_dir(), group=base.user(), perms=0o750)
-    host.mkdir(home_dir(), owner=base.user(), group=base.user(), perms=0o755)
-
-
-def get_service_config():
-    config = dict(hookenv.config())
-    config.update(
-        {
-            "base_dir": base.base_dir(),
-            "code_dir": base.code_dir(),
-            "logs_dir": base.logs_dir(),
-            "oopses_dir": oopses_dir(),
-            # Used by some templates.
-            "parseaddr": parseaddr,
-            "secrets_dir": secrets_dir(),
-            "user": base.user(),
-            "var_dir": var_dir(),
-        }
-    )
-    return config
-
-
-def config_file_path(name, secret=False):
-    if secret:
-        config_dir = os.path.join(base.base_dir(), "secrets")
-    else:
-        config_dir = os.path.join(base.code_dir(), "production-configs")
-    return os.path.join(config_dir, name)
-
-
-def configure_lazr(config, template, name, secret=False):
-    hookenv.log("Writing service configuration.")
-    templating.render(
-        template,
-        config_file_path(name, secret=secret),
-        config,
-        owner="root",
-        group=base.user(),
-        perms=0o440 if secret else 0o444,
-    )
-
-
-def lazr_config_files():
-    return [
-        config_file_path("launchpad-base-lazr.conf"),
-        config_file_path("launchpad-base-secrets-lazr.conf", secret=True),
-    ]
-
-
-def configure_rsync(config, template, name):
-    hookenv.log("Writing rsync configuration.")
-    rsync_path = os.path.join("/etc/rsync-juju.d", name)
-    if config["log_hosts_allow"]:
-        templating.render(template, rsync_path, config, perms=0o644)
-    elif os.path.exists(rsync_path):
-        os.unlink(rsync_path)
-
-
-@dataclass
-class PgPassLine:
-    hostname: str
-    port: str
-    database: str
-    username: str
-    password: str
-
-
-def update_pgpass(dsn):
-    # See https://www.postgresql.org/docs/current/libpq-pgpass.html.
-
-    def unescape(entry):
-        return re.sub(r"\\(.)", r"\1", entry)
-
-    def escape(entry):
-        return re.sub(r"([:\\])", r"\\\1", entry)
-
-    parsed_dsn = parse_dsn(dsn)
-    pgpass_path = os.path.join(home_dir(), ".pgpass")
-    pgpass = []
-    try:
-        with open(pgpass_path) as f:
-            for line in f:
-                if line.startswith("#"):
-                    continue
-                match = re.match(
-                    r"""
-                        ^
-                        (?P<hostname>(?:[^:\\]|\\.)*):
-                        (?P<port>(?:[^:\\]|\\.)*):
-                        (?P<database>(?:[^:\\]|\\.)*):
-                        (?P<username>(?:[^:\\]|\\.)*):
-                        (?P<password>(?:[^:\\]|\\.)*)
-                        $
-                    """,
-                    line.rstrip("\n"),
-                    flags=re.X,
-                )
-                if match is None:
-                    continue
-                pgpass.append(
-                    PgPassLine(
-                        hostname=unescape(match.group("hostname")),
-                        port=unescape(match.group("port")),
-                        database=unescape(match.group("database")),
-                        username=unescape(match.group("username")),
-                        password=unescape(match.group("password")),
-                    )
-                )
-    except OSError:
-        pass
-
-    modified = False
-    for line in pgpass:
-        if (
-            line.hostname in ("*", parsed_dsn["host"])
-            and line.port in ("*", parsed_dsn["port"])
-            and line.database in ("*", parsed_dsn["dbname"])
-            and line.username in ("*", parsed_dsn["user"])
-        ):
-            if line.password != parsed_dsn["password"]:
-                line.password = parsed_dsn["password"]
-                modified = True
-            break
-    else:
-        pgpass.append(
-            PgPassLine(
-                hostname=parsed_dsn["host"],
-                port=parsed_dsn["port"],
-                database=parsed_dsn["dbname"],
-                username=parsed_dsn["user"],
-                password=parsed_dsn["password"],
-            )
-        )
-        modified = True
-
-    if modified:
-        uid = pwd.getpwnam(base.user()).pw_uid
-        gid = grp.getgrnam(base.user()).gr_gid
-        with open(pgpass_path, "w") as f:
-            for line in pgpass:
-                print(
-                    ":".join(
-                        [
-                            escape(line.hostname),
-                            escape(line.port),
-                            escape(line.database),
-                            escape(line.username),
-                            escape(line.password),
-                        ]
-                    ),
-                    file=f,
-                )
-            os.fchown(f.fileno(), uid, gid)
-            os.fchmod(f.fileno(), 0o600)
-
-
-def strip_dsn_authentication(dsn):
-    parsed_dsn = parse_dsn(dsn)
-    parsed_dsn.pop("user", None)
-    parsed_dsn.pop("password", None)
-    return make_dsn(**parsed_dsn)
diff --git a/charm/layer/launchpad-base/metadata.yaml b/charm/layer/launchpad-base/metadata.yaml
deleted file mode 100644
index eafdcc0..0000000
--- a/charm/layer/launchpad-base/metadata.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-requires:
-  db:
-    interface: pgsql
-  rabbitmq:
-    interface: rabbitmq
diff --git a/charm/layer/launchpad-base/reactive/launchpad-base.py b/charm/layer/launchpad-base/reactive/launchpad-base.py
deleted file mode 100644
index a3473f7..0000000
--- a/charm/layer/launchpad-base/reactive/launchpad-base.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# Copyright 2022 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-import subprocess
-
-from charmhelpers.core import hookenv
-from charms.launchpad.base import (
-    configure_lazr,
-    configure_rsync,
-    ensure_lp_directories,
-    get_service_config,
-    strip_dsn_authentication,
-    update_pgpass,
-)
-from charms.reactive import hook, remove_state, set_state, when, when_not
-from ols import base, postgres
-from psycopg2.extensions import parse_dsn
-
-
-# Monkey-patch layer:ols.
-def create_virtualenv(wheels_dir, codedir, python_exe):
-    subprocess.run(
-        ["make", "compile", "PYTHON={}".format(python_exe)],
-        cwd=codedir,
-        check=True,
-    )
-
-
-base.create_virtualenv = create_virtualenv
-
-
-@when("rabbitmq.connected")
-def prepare_rabbitmq(rabbitmq):
-    config = hookenv.config()
-    rabbitmq.request_access(config["rabbitmq_user"], config["domain"])
-
-
-def get_rabbitmq_uris(rabbitmq):
-    for conversation in rabbitmq.conversations():
-        for relation_id in conversation.relation_ids:
-            for unit in hookenv.related_units(relation_id):
-                hostname = hookenv.relation_get(
-                    "private-address", unit, relation_id
-                )
-                vhost = rabbitmq.vhost()
-                username = rabbitmq.username()
-                password = rabbitmq.password()
-                yield f"amqp://{username}:{password}@{hostname}/{vhost}"
-
-
-@when("ols.configured", "db.master.available", "rabbitmq.available")
-@when_not("launchpad.base.configured")
-def configure(db, rabbitmq):
-    ensure_lp_directories()
-    config = get_service_config()
-    db_primary, db_standby = postgres.get_db_uris(db)
-    # XXX cjwatson 2022-09-23: Mangle the connection strings into forms
-    # Launchpad understands.  In the long term it would be better to have
-    # Launchpad be able to consume unmodified connection strings.
-    for dsn in [db_primary] + db_standby:
-        update_pgpass(dsn)
-    config["db_primary"] = strip_dsn_authentication(db_primary)
-    config["db_standby"] = ",".join(
-        strip_dsn_authentication(dsn) for dsn in db_standby
-    )
-    # XXX cjwatson 2022-09-23: This is a layering violation, since it's
-    # specific to the appserver.  We need to teach Launchpad to be able to
-    # log in as one role and then switch to another.
-    config["db_user"] = parse_dsn(db_primary)["user"]
-    config["rabbitmq_broker_urls"] = sorted(get_rabbitmq_uris(rabbitmq))
-    configure_lazr(
-        config,
-        "launchpad-base-lazr.conf",
-        "launchpad-base-lazr.conf",
-    )
-    configure_lazr(
-        config,
-        "launchpad-base-secrets-lazr.conf",
-        "launchpad-base-secrets-lazr.conf",
-        secret=True,
-    )
-    configure_rsync(
-        config, "launchpad-base-rsync.conf", "010-launchpad-base.conf"
-    )
-    set_state("launchpad.base.configured")
-
-
-@hook("upgrade-charm")
-def upgrade_charm():
-    # The ols layer takes care of removing the ols.service.installed,
-    # ols.configured, and service.configured states.  Remove
-    # launchpad.base.configured as well so that we have an opportunity to
-    # rewrite base configuration files.
-    remove_state("launchpad.base.configured")
-
-
-@when("config.changed.build_label")
-def build_label_changed():
-    remove_state("ols.service.installed")
-    remove_state("ols.configured")
-    remove_state("launchpad.base.configured")
-    remove_state("service.configured")
-
-
-@when("config.changed")
-def config_changed():
-    remove_state("launchpad.base.configured")
-    remove_state("service.configured")
-
-
-@hook("{requires:rabbitmq}-relation-changed")
-def rabbitmq_relation_changed(rabbitmq):
-    remove_state("launchpad.base.configured")
-    remove_state("service.configured")
diff --git a/charm/layer/launchpad-base/templates/launchpad-base-lazr.conf b/charm/layer/launchpad-base/templates/launchpad-base-lazr.conf
deleted file mode 100644
index 9e597f5..0000000
--- a/charm/layer/launchpad-base/templates/launchpad-base-lazr.conf
+++ /dev/null
@@ -1,136 +0,0 @@
-# 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: ../lib/lp/services/config/schema-lazr.conf
-
-[answertracker]
-email_domain: answers.{{ domain }}
-
-[canonical]
-bounce_address: {{ bounce_address }}
-cron_control_url: {{ cron_control_url }}
-pid_dir: {{ var_dir }}
-
-[charms]
-{{- opt("charmhub_secrets_public_key", charmhub_secrets_public_key) }}
-{{- opt("charmhub_storage_url", charmhub_storage_url) }}
-{{- opt("charmhub_url", charmhub_url) }}
-
-[codehosting]
-{%- if domain_bzr %}
-authentication_endpoint: http://{{ domain_xmlrpc_private }}:{{ port_xmlrpc }}/authserver
-bzr_lp_prefix: {{ bzr_lp_prefix }}
-codehosting_endpoint: http://{{ domain_xmlrpc_private }}:{{ port_xmlrpc }}/codehosting
-{{- opt("internal_bzr_api_endpoint", internal_bzr_api_endpoint) }}
-lp_url_hosts: {{ bzr_lp_url_hosts }}
-secure_codebrowse_root: https://{{ domain_bzr }}/
-supermirror_root: http://{{ domain_bzr }}
-{%- endif %}
-{%- if domain_git %}
-internal_git_api_endpoint: http://{{ domain_git }}:19417/
-git_anon_root: git://{{ domain_git }}/
-git_browse_root: https://{{ domain_git }}/
-git_ssh_root: git+ssh://{{ domain_git }}/
-{{- opt("loose_objects_threshold", git_loose_objects_threshold) }}
-{{- opt("packs_threshold", git_packs_threshold) }}
-{%- endif %}
-
-[database]
-{{- opt("db_statement_timeout", db_statement_timeout) }}
-rw_main_primary: {{ db_primary }}
-rw_main_standby: {{ db_standby or db_primary }}
-{{- opt("soft_request_timeout", soft_request_timeout) }}
-
-[error_reports]
-error_dir: {{ oopses_dir }}
-oops_prefix: {{ oops_prefix }}
-
-[gpghandler]
-upload_keys: {{ gpg_upload_keys }}
-
-[launchpad]
-bugs_domain: bugs.{{ domain }}
-{{- opt("bzr_imports_root_url", bzr_imports_root_url) }}
-{{- opt("candid_service_root", candid_service_root) }}
-code_domain: code.{{ domain }}
-config_overlay_dir: {{ secrets_dir }}
-dbuser: {{ db_user }}
-default_batch_size: {{ default_batch_size }}
-{{- opt("geoip_database", geoip_database) }}
-{{- opt("http_proxy", http_proxy) }}
-is_demo: {{ is_demo }}
-{{- opt("openid_alternate_provider_roots", openid_alternate_provider_roots) }}
-openid_provider_root: {{ openid_provider_root }}
-{{- opt("site_message", site_message) }}
-
-[librarian]
-authentication_endpoint: http://{{ domain_xmlrpc_private }}:{{ port_xmlrpc }}/authserver
-{{- opt("download_host", librarian_download_host) }}
-
-[mailman]
-{{- opt("build_host_name", domain_lists) }}
-
-[malone]
-buglist_batch_size: {{ default_batch_size }}
-bugmail_error_from_address: noreply@bugs.{{ domain }}
-
-{%- if statsd_environment %}
-[statsd]
-host: 127.0.0.1
-port: 8125
-prefix: lp
-environment: {{ statsd_environment }}
-{%- endif %}
-
-[uploader]
-{%- if uploader_default_recipient %}
-default_recipient_address: {{ parseaddr(uploader_default_recipient)[1] }}
-default_recipient_name: {{ parseaddr(uploader_default_recipient)[0] }}
-{%- endif %}
-{%- if uploader_default_sender %}
-default_sender_address: {{ parseaddr(uploader_default_sender)[1] }}
-default_sender_name: {{ parseaddr(uploader_default_sender)[0] }}
-{%- endif %}
-
-[vhost.mainsite]
-hostname: {{ domain }}
-althostnames: localhost, www.{{ domain }}
-openid_delegate_profile: true
-
-[vhost.answers]
-hostname: answers.{{ domain }}
-
-[vhost.api]
-hostname: api.{{ domain }}
-
-[vhost.blueprints]
-hostname: blueprints.{{ domain }}
-
-[vhost.bugs]
-hostname: bugs.{{ domain }}
-
-[vhost.code]
-hostname: code.{{ domain }}
-
-[vhost.feeds]
-hostname: feeds.{{ domain }}
-# Don't link to HTTPS for feeds.
-rooturl: http://feeds.{{ domain }}/
-
-[vhost.translations]
-hostname: translations.{{ domain }}
-
-[vhost.xmlrpc]
-hostname: xmlrpc.{{ domain }}
-
-[vhost.xmlrpc_private]
-hostname: {{ domain_xmlrpc_private }}
-
diff --git a/charm/layer/launchpad-base/templates/launchpad-base-rsync.conf b/charm/layer/launchpad-base/templates/launchpad-base-rsync.conf
deleted file mode 100644
index 2921300..0000000
--- a/charm/layer/launchpad-base/templates/launchpad-base-rsync.conf
+++ /dev/null
@@ -1,8 +0,0 @@
-
-[lp-logs]
-  path = {{ logs_dir }}
-  comment = LP Logs
-  list = false
-  read only = true
-  hosts allow = {{ log_hosts_allow }}
-
diff --git a/charm/layer/launchpad-base/templates/launchpad-base-secrets-lazr.conf b/charm/layer/launchpad-base/templates/launchpad-base-secrets-lazr.conf
deleted file mode 100644
index 5b45030..0000000
--- a/charm/layer/launchpad-base/templates/launchpad-base-secrets-lazr.conf
+++ /dev/null
@@ -1,18 +0,0 @@
-# Secret configuration data.  This is stored in an overlay directory, mainly
-# to avoid accidental information leaks from the public configuration file.
-# Entries in this file should not be shared with developers, although the
-# structure of the file is not secret, only configuration values.
-
-# 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 -%}
-
-[mailman]
-{{- opt("shared_secret", mailman_shared_secret) }}
-
-[rabbitmq]
-broker_urls: {{ rabbitmq_broker_urls|join(" ") }}
-
diff --git a/charm/layer/launchpad-base/templates/macros.j2 b/charm/layer/launchpad-base/templates/macros.j2
deleted file mode 100644
index 8cddb14..0000000
--- a/charm/layer/launchpad-base/templates/macros.j2
+++ /dev/null
@@ -1,6 +0,0 @@
-{#- An optional configuration entry. #}
-{%- macro opt(name, value) %}
-{%-   if value is defined and value is not none %}
-{{ name }}: {{ value }}
-{%-   endif %}
-{%- endmacro %}
diff --git a/charm/packages.txt b/charm/packages.txt
index c33fce5..7cd3faf 100644
--- a/charm/packages.txt
+++ b/charm/packages.txt
@@ -1,3 +1,2 @@
 flake8
-python-codetree
 squashfuse