Colin Watson has proposed merging ~cjwatson/launchpad:charm-buildd-manager into launchpad:master.
Commit message: charm: Add a launchpad-buildd-manager charm Requested reviews: Launchpad code reviewers (launchpad-reviewers) For more details, see: https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/441481 I'm sure this needs some more work, but it should be a reasonable starting point. -- Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:charm-buildd-manager into launchpad:master.
diff --git a/charm/Makefile b/charm/Makefile index 800f2de..e56d6e3 100644 --- a/charm/Makefile +++ b/charm/Makefile @@ -15,7 +15,8 @@ ASSET = ../build/$(BUILD_LABEL)/$(TARBALL) CHARMS := \ launchpad-admin \ - launchpad-appserver + launchpad-appserver \ + launchpad-buildd-manager all: ## alias to build all: build diff --git a/charm/launchpad-buildd-manager/charmcraft.yaml b/charm/launchpad-buildd-manager/charmcraft.yaml new file mode 100644 index 0000000..7eec557 --- /dev/null +++ b/charm/launchpad-buildd-manager/charmcraft.yaml @@ -0,0 +1,60 @@ +type: charm +bases: + - build-on: + - name: ubuntu + channel: "20.04" + architectures: [amd64] + run-on: + - name: ubuntu + channel: "20.04" + architectures: [amd64] +parts: + charm-wheels: + source: https://git.launchpad.net/~ubuntuone-hackers/ols-charm-deps/+git/wheels + source-commit: "59b32ae07f98051385c96d6d8e7e02ca4f197fe5" + 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: "56d219f60a293a6c73759b8439ef5fdb11e19d1f" + 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: "0311e05ec2e856e61a2620f68aa3ea35c0a3029b" + source-submodules: [] + source-type: git + plugin: dump + organize: + launchpad-base: layers/layer/launchpad-base + stage: + - layers + prime: + - "-layers" + launchpad-buildd-manager: + 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-buildd-manager/config.yaml b/charm/launchpad-buildd-manager/config.yaml new file mode 100644 index 0000000..ea622d3 --- /dev/null +++ b/charm/launchpad-buildd-manager/config.yaml @@ -0,0 +1,60 @@ +options: + active: + type: boolean + description: If true, enable jobs that may change the database. + default: true + artifactory_read_credentials: + type: string + description: > + Credentials for reading from Artifactory repositories (formatted as + "user:token"). + default: "" + builder_proxy_auth_api_admin_secret: + type: string + description: > + Admin secret for requesting tokens from the builder proxy service. + default: "" + builder_proxy_auth_api_admin_username: + type: string + description: Admin username for the builder proxy service. + default: "" + builder_proxy_auth_api_endpoint: + type: string + description: Endpoint for builder proxy authentication service. + default: "" + builder_proxy_host: + type: string + description: Builder HTTP proxy host. + default: "" + builder_proxy_port: + type: int + description: Builder HTTP proxy port. + default: 3128 + builder_reset_private_ssh_key: + type: string + description: > + Base64-encoded private SSH key, used to request builder resets. + default: "" + builder_reset_public_ssh_key: + type: string + description: > + Base64-encoded public SSH key, used to request builder resets. + default: "" + cibuild_config: + type: string + description: > + YAML-encoded dictionary mapping pillars to dictionaries of + configuration items to set for CI builds of those pillars. + default: "" + socket_timeout: + type: int + description: > + The time in seconds that buildd-manager will wait for a reply from + non-virtualized builders. + default: 40 + virtualized_socket_timeout: + type: int + description: > + The time in seconds that buildd-manager will wait for a reply from + non-virtualized builders. + default: 30 diff --git a/charm/launchpad-buildd-manager/layer.yaml b/charm/launchpad-buildd-manager/layer.yaml new file mode 100644 index 0000000..38bd356 --- /dev/null +++ b/charm/launchpad-buildd-manager/layer.yaml @@ -0,0 +1,12 @@ +includes: + - layer:launchpad-base +repo: https://git.launchpad.net/launchpad +options: + ols-pg: + databases: + db: + name: launchpad_dev + roles: + - buildd_manager + - process_upload + - retry_depwait diff --git a/charm/launchpad-buildd-manager/metadata.yaml b/charm/launchpad-buildd-manager/metadata.yaml new file mode 100644 index 0000000..0e28e9f --- /dev/null +++ b/charm/launchpad-buildd-manager/metadata.yaml @@ -0,0 +1,16 @@ +name: launchpad-buildd-manager +display-name: launchpad-buildd-manager +summary: Launchpad build farm manager +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 runs a service that supervises the Launchpad build farm, + dispatching jobs to idle builders and collecting results. +tags: + # https://juju.is/docs/charm-metadata#heading--charm-store-fields + - network +series: + - focal +subordinate: false diff --git a/charm/launchpad-buildd-manager/reactive/launchpad-buildd-manager.py b/charm/launchpad-buildd-manager/reactive/launchpad-buildd-manager.py new file mode 100644 index 0000000..87c46de --- /dev/null +++ b/charm/launchpad-buildd-manager/reactive/launchpad-buildd-manager.py @@ -0,0 +1,142 @@ +# Copyright 2023 Canonical Ltd. This software is licensed under the +# GNU Affero General Public License version 3 (see the file LICENSE). + +import base64 +import os.path +import subprocess + +import yaml +from charmhelpers.core import hookenv, host, templating +from charms.launchpad.base import ( + config_file_path, + configure_cron, + configure_lazr, + get_service_config, + home_dir, + lazr_config_files, +) +from charms.reactive import helpers, set_state, when, when_not +from ols import base + + +def base64_decode(value): + return base64.b64decode(value.encode("ASCII")) + + +def configure_keys(config): + ssh_dir = os.path.join(home_dir(), ".ssh") + ssh_private_path = os.path.join(ssh_dir, "builder-reset") + ssh_public_path = os.path.join(ssh_dir, "builder-reset.pub") + if ( + config["builder_reset_private_ssh_key"] + and config["builder_reset_public_ssh_key"] + ): + hookenv.log("Writing SSH keys.") + if not os.path.exists(ssh_dir): + host.mkdir( + ssh_dir, owner=base.user(), group=base.user(), perms=0o700 + ) + host.write_file( + ssh_private_path, + base64_decode(config["builder_reset_private_ssh_key"]), + owner=base.user(), + group=base.user(), + perms=0o600, + ) + host.write_file( + ssh_public_path, + base64_decode(config["builder_reset_public_ssh_key"]), + owner=base.user(), + group=base.user(), + perms=0o644, + ) + else: + for path in (ssh_private_path, ssh_public_path): + if os.path.exists(path): + os.unlink(path) + + +def configure_service(config): + hookenv.log("Writing systemd service.") + templating.render( + "launchpad-buildd-manager.service.j2", + "/lib/systemd/system/launchpad-buildd-manager.service", + config, + ) + subprocess.run(["systemctl", "daemon-reload"], check=True) + + +def configure_logrotate(config): + hookenv.log("Writing logrotate configuration.") + templating.render( + "logrotate.conf.j2", + "/etc/logrotate.d/launchpad-buildd-manager", + config, + perms=0o644, + ) + + +def config_files(): + files = [] + files.extend(lazr_config_files()) + files.append( + config_file_path("launchpad-buildd-manager/launchpad-lazr.conf") + ) + files.append( + config_file_path( + "launchpad-buildd-manager-secrets-lazr.conf", secret=True + ) + ) + return files + + +@when("launchpad.base.configured") +@when_not("service.configured") +def configure(): + config = get_service_config() + config["buildd_manager_dir"] = os.path.join( + base.base_dir(), "buildd-manager" + ) + config["cibuild_config"] = yaml.safe_load(config["cibuild_config"]) + host.mkdir( + config["buildd_manager_dir"], + owner=base.user(), + group=base.user(), + perms=0o755, + ) + configure_lazr( + config, + "launchpad-buildd-manager-lazr.conf", + "launchpad-buildd-manager/launchpad-lazr.conf", + ) + configure_lazr( + config, + "launchpad-buildd-manager-secrets-lazr.conf", + "launchpad-buildd-manager-secrets-lazr.conf", + secret=True, + ) + configure_keys(config) + configure_service(config) + configure_logrotate(config) + configure_cron(config, "crontab.j2") + + if config["active"]: + if helpers.any_file_changed( + [ + base.version_info_path(), + "/lib/systemd/system/launchpad-buildd-manager.service", + ] + + config_files() + ): + hookenv.log("Config files changed; restarting buildd-manager") + host.service_restart("launchpad-buildd-manager") + host.service_resume("launchpad-buildd-manager") + else: + host.service_pause("launchpad-buildd-manager") + + set_state("service.configured") + + +@when("service.configured") +def check_is_running(): + hookenv.status_set("active", "Ready") diff --git a/charm/launchpad-buildd-manager/templates/crontab.j2 b/charm/launchpad-buildd-manager/templates/crontab.j2 new file mode 100644 index 0000000..435cf43 --- /dev/null +++ b/charm/launchpad-buildd-manager/templates/crontab.j2 @@ -0,0 +1,30 @@ +TZ=UTC +MAILTO={{ cron_mailto }} +LPCONFIG=launchpad-buildd-manager + +{% if active -%} +# Automatically retry builds in the "Dependency wait" state if their +# dependencies can now be satisfied. +25 * * * * {{ code_dir }}/cronscripts/buildd-retry-depwait.py -q --log-file=DEBUG2:{{ logs_dir }}/buildd-retry-depwait.log + +# Process uploaded builds. +* * * * * {{ code_dir }}/scripts/process-upload.py -C buildd --builds {{ buildd_manager_dir }}/ -q --log-file=DEBUG:{{ logs_dir }}/process-build-uploads.log + +{% endif -%} +# Clean up the accepted queue every hour, as it's redundant: +# https://bugs.launchpad.net/launchpad/+bug/361192 +45 * * * * find {{ buildd_manager_dir }}/accepted/ -maxdepth 1 -type d -execdir rm -rf {} + >/dev/null 2>&1 + +# Directories older than 1 month can be deleted +00 00 * * * find {{ buildd_manager_dir }}/rejected/ -maxdepth 1 -type d -mtime +30 -execdir rm -rf {} + >/dev/null 2>&1 + +# Clean out failed directory: https://portal.admin.canonical.com/C98568 +0 1 * * * find {{ buildd_manager_dir }}/failed/ -maxdepth 1 -type d -mtime +7 -execdir rm -rf {} + >/dev/null 2>&1 + +# Give up on in-progress downloads from builders after a couple of days +0 2 * * * find {{ buildd_manager_dir }}/grabbing/ -maxdepth 1 -type d -mtime +2 -execdir rm -rf {} + >/dev/null 2>&1 + +# Catch up with publishing OOPSes that were temporarily spooled to disk due +# to RabbitMQ being unavailable. +*/15 * * * * {{ code_dir }}/bin/datedir2amqp --exchange oopses --host {{ rabbitmq_host }} --username {{ rabbitmq_username }} --password {{ rabbitmq_password }} --vhost {{ rabbitmq_vhost }} --repo {{ oopses_dir }} --key "" + diff --git a/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager-lazr.conf b/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager-lazr.conf new file mode 100644 index 0000000..613f8e6 --- /dev/null +++ b/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager-lazr.conf @@ -0,0 +1,36 @@ +# 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 + +[builddmaster] +authentication_endpoint: http://{{ domain_xmlrpc_private }}:{{ port_xmlrpc }}/authserver +authentication_timeout: 60 +{{- opt("builder_proxy_auth_api_admin_username", builder_proxy_auth_api_admin_username) }} +{{- opt("builder_proxy_auth_api_endpoint", builder_proxy_auth_api_endpoint) }} +{{- opt("builder_proxy_host", builder_proxy_host) }} +{{- opt("builder_proxy_port", builder_proxy_port) }} +root: {{ buildd_manager_dir }} +socket_timeout: {{ socket_timeout }} +virtualized_socket_timeout: {{ virtualized_socket_timeout }} +{%- if builder_reset_private_ssh_key and builder_reset_public_ssh_key %} +vm_resume_command: ssh -o StrictHostKeyChecking=no -i /home/{{ user }}/.ssh/builder-reset ppa@%(vm_host)s ppa-reset %(buildd_name)s +{%- endif %} + +{% if cibuild_config -%} +{% for pillar, config in cibuild_config.items() -%} +[cibuild.{{ pillar }}] +{%- for key, value in config.items() %} +{{ key }}: {{ value }} +{%- endfor %} +{%- endfor %} +{% endif %} + diff --git a/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager-secrets-lazr.conf b/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager-secrets-lazr.conf new file mode 100644 index 0000000..af20066 --- /dev/null +++ b/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager-secrets-lazr.conf @@ -0,0 +1,18 @@ +# 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 -%} + +[artifactory] +{{- opt("read_credentials", artifactory_read_credentials) }} + +[builddmaster] +{{- opt("builder_proxy_auth_api_admin_secret", builder_proxy_auth_api_admin_secret) }} + diff --git a/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager.service.j2 b/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager.service.j2 new file mode 100644 index 0000000..0e6ae18 --- /dev/null +++ b/charm/launchpad-buildd-manager/templates/launchpad-buildd-manager.service.j2 @@ -0,0 +1,18 @@ +[Unit] +Description=Launchpad build farm manager +After=network.target +ConditionPathExists=!{{ code_dir }}/maintenance.txt + +[Service] +User={{ user }} +Group={{ user }} +WorkingDirectory={{ code_dir }} +Environment=LPCONFIG=launchpad-buildd-manager +ExecStart={{ code_dir }}/bin/twistd --python={{ code_dir }}/daemons/buildd-manager.tac --logfile={{ logs_dir }}/buildd-manager.log --pidfile= --nodaemon --umask=0022 +ExecReload=/bin/kill -USR1 $MAINPID +Restart=on-failure +LimitNOFILE=65536 + +[Install] +WantedBy=multi-user.target + diff --git a/charm/launchpad-buildd-manager/templates/logrotate.conf.j2 b/charm/launchpad-buildd-manager/templates/logrotate.conf.j2 new file mode 100644 index 0000000..657e00d --- /dev/null +++ b/charm/launchpad-buildd-manager/templates/logrotate.conf.j2 @@ -0,0 +1,16 @@ +{{ logs_dir }}/*.log +{ + rotate 90 + daily + dateext + delaycompress + compress + notifempty + missingok + create 0644 {{ user }} {{ user }} + sharedscripts + postrotate + systemctl reload buildd-manager.service + endscript +} +
_______________________________________________ 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