← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:charm-appserver-more-config into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:charm-appserver-more-config into launchpad:master.

Commit message:
charm: Flesh out appserver configuration

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

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

This is enough to allow a charmed appserver deployment to have equivalent configuration to each of our current production and staging environments (apart from rabbitmq and memcached configuration, which will be handled separately based on relations).

To avoid this being too overwhelming, I've stuck to only those bits of configuration that are relevant to running the appserver.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:charm-appserver-more-config into launchpad:master.
diff --git a/charm/launchpad-appserver/config.yaml b/charm/launchpad-appserver/config.yaml
index 43f4a45..5748257 100644
--- a/charm/launchpad-appserver/config.yaml
+++ b/charm/launchpad-appserver/config.yaml
@@ -1,24 +1,33 @@
 options:
+  bing_custom_config_id:
+    type: string
+    description: Identifier for the Bing Custom Search instance.
+    default:
+  bing_subscription_key:
+    type: string
+    description: >
+      Cognitive Services subscription key for the Bing Custom Search API.
+    default:
   devmode:
     type: boolean
     description: Is this server running in dev mode?
     default: true
+  mailman_archive_url_template:
+    type: string
+    description: Template expanded to form URLs for Launchpad list archives.
+    default: "http://lists.launchpad.test/$team_name";
   min_legitimate_account_age:
     type: int
     description: Minimum account age in days that indicates a legitimate user.
-    default: 0
+    default:
   min_legitimate_karma:
     type: int
     description: Minimum karma value that indicates a legitimate user.
-    default: 0
+    default:
   port_main:
     type: int
     description: Port for the main application server.
     default: 8085
-  port_xmlrpc:
-    type: int
-    description: Port for the XML-RPC application server.
-    default: 8087
   wsgi_workers:
     type: int
     default: 0
diff --git a/charm/launchpad-appserver/reactive/launchpad-appserver.py b/charm/launchpad-appserver/reactive/launchpad-appserver.py
index 30b1f40..3f68d99 100644
--- a/charm/launchpad-appserver/reactive/launchpad-appserver.py
+++ b/charm/launchpad-appserver/reactive/launchpad-appserver.py
@@ -84,6 +84,9 @@ def config_files():
     files = []
     files.extend(lazr_config_files())
     files.append(config_file_path("launchpad-appserver/launchpad-lazr.conf"))
+    files.append(
+        config_file_path("launchpad-appserver-secrets-lazr.conf", secret=True)
+    )
     return files
 
 
@@ -98,13 +101,17 @@ def configure(session_db):
     update_pgpass(session_db_primary)
     config["db_session"] = strip_dsn_authentication(session_db_primary)
     config["db_session_user"] = parse_dsn(session_db_primary)["user"]
-    # XXX cjwatson 2022-09-07: Some config items have no reasonable default.
-    # We should set the workload status to blocked in that case.
     configure_lazr(
         config,
         "launchpad-appserver-lazr.conf",
         "launchpad-appserver/launchpad-lazr.conf",
     )
+    configure_lazr(
+        config,
+        "launchpad-appserver-secrets-lazr.conf",
+        "launchpad-appserver-secrets-lazr.conf",
+        secret=True,
+    )
     configure_gunicorn(config)
     configure_logrotate(config)
 
diff --git a/charm/launchpad-appserver/templates/launchpad-appserver-lazr.conf b/charm/launchpad-appserver/templates/launchpad-appserver-lazr.conf
index bafc316..7faa040 100644
--- a/charm/launchpad-appserver/templates/launchpad-appserver-lazr.conf
+++ b/charm/launchpad-appserver/templates/launchpad-appserver-lazr.conf
@@ -6,15 +6,24 @@
 # 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
 
+[bing]
+{{- opt("custom_config_id", bing_custom_config_id) }}
+
 [launchpad]
 devmode: {{ devmode }}
-min_legitimate_account_age: {{ min_legitimate_account_age }}
-min_legitimate_karma: {{ min_legitimate_karma }}
+{{- opt("min_legitimate_account_age", min_legitimate_account_age) }}
+{{- opt("min_legitimate_karma", min_legitimate_karma) }}
 
 [launchpad_session]
 database: {{ db_session }}
 dbuser: {{ db_session_user }}
 cookie: {{ session_cookie_name }}
+
+[mailman]
+{{- opt("archive_url_template", mailman_archive_url_template) }}
+
diff --git a/charm/launchpad-appserver/templates/launchpad-appserver-secrets-lazr.conf b/charm/launchpad-appserver/templates/launchpad-appserver-secrets-lazr.conf
new file mode 100644
index 0000000..e95e5ce
--- /dev/null
+++ b/charm/launchpad-appserver/templates/launchpad-appserver-secrets-lazr.conf
@@ -0,0 +1,15 @@
+# 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 -%}
+
+[bing]
+{{- opt("subscription_key", bing_subscription_key) }}
+
diff --git a/charm/layer/launchpad-base/config.yaml b/charm/layer/launchpad-base/config.yaml
index c33c239..b0f96f5 100644
--- a/charm/layer/launchpad-base/config.yaml
+++ b/charm/layer/launchpad-base/config.yaml
@@ -1,4 +1,44 @@
 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.
@@ -10,24 +50,136 @@ options:
       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: ""
+    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.
@@ -37,15 +189,71 @@ options:
     description: >
       Comma-separated list of additional URLs to recognise as valid prefixes
       for our accounts' OpenID identifiers.
-    default: ""
+    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/
   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: |
diff --git a/charm/layer/launchpad-base/lib/charms/launchpad/base.py b/charm/layer/launchpad-base/lib/charms/launchpad/base.py
index da811fe..71f0dbe 100644
--- a/charm/layer/launchpad-base/lib/charms/launchpad/base.py
+++ b/charm/layer/launchpad-base/lib/charms/launchpad/base.py
@@ -6,6 +6,7 @@ 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
@@ -43,6 +44,8 @@ def get_service_config():
             "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(),
diff --git a/charm/layer/launchpad-base/reactive/launchpad-base.py b/charm/layer/launchpad-base/reactive/launchpad-base.py
index cd4bef1..71b2196 100644
--- a/charm/layer/launchpad-base/reactive/launchpad-base.py
+++ b/charm/layer/launchpad-base/reactive/launchpad-base.py
@@ -47,8 +47,6 @@ def configure(db):
     # 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"]
-    # XXX cjwatson 2022-09-07: Some config items have no reasonable default.
-    # We should set the workload status to blocked in that case.
     configure_lazr(
         config,
         "launchpad-base-lazr.conf",
diff --git a/charm/layer/launchpad-base/templates/launchpad-base-lazr.conf b/charm/layer/launchpad-base/templates/launchpad-base-lazr.conf
index 4b50d48..9e597f5 100644
--- a/charm/layer/launchpad-base/templates/launchpad-base-lazr.conf
+++ b/charm/layer/launchpad-base/templates/launchpad-base-lazr.conf
@@ -6,29 +6,99 @@
 # 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: noreply@xxxxxxxxxxxxx
+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]
-db_statement_timeout: 15000
+{{- opt("db_statement_timeout", db_statement_timeout) }}
 rw_main_primary: {{ db_primary }}
 rw_main_standby: {{ db_standby or db_primary }}
-soft_request_timeout: 8000
+{{- 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 }}
-http_proxy: {{ http_proxy or "none" }}
-openid_alternate_provider_roots: {{ openid_alternate_provider_roots or "none" }}
+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 }}
diff --git a/charm/layer/launchpad-base/templates/launchpad-base-secrets-lazr.conf b/charm/layer/launchpad-base/templates/launchpad-base-secrets-lazr.conf
index 7229414..a01a72d 100644
--- a/charm/layer/launchpad-base/templates/launchpad-base-secrets-lazr.conf
+++ b/charm/layer/launchpad-base/templates/launchpad-base-secrets-lazr.conf
@@ -7,3 +7,9 @@
 # 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) }}
+
diff --git a/charm/layer/launchpad-base/templates/macros.j2 b/charm/layer/launchpad-base/templates/macros.j2
new file mode 100644
index 0000000..8cddb14
--- /dev/null
+++ b/charm/layer/launchpad-base/templates/macros.j2
@@ -0,0 +1,6 @@
+{#- An optional configuration entry. #}
+{%- macro opt(name, value) %}
+{%-   if value is defined and value is not none %}
+{{ name }}: {{ value }}
+{%-   endif %}
+{%- endmacro %}