Colin Watson has proposed merging ~cjwatson/launchpad:charm-librarian-http-interface into launchpad:master.
Commit message: charm/launchpad-librarian: Add http interface support Requested reviews: Launchpad code reviewers (launchpad-reviewers) For more details, see: https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/444200 This allows relating `launchpad-librarian` to a deployment of the `haproxy` charm to have it load-balance the various workers and expose them on the ports expected by other parts of Launchpad. The code is based on the `ols-http` layer, but I had to write custom code for it because the librarian is rather special in a few ways: it has four different sets of ports with different purposes (download, upload, restricted download, and restricted upload), and multiple workers per set; and the current production `haproxy` configuration uses somewhat different options for the download vs. upload workers. While this doesn't result in the exact same `haproxy` configuration that we have on production, I think it's equivalent. -- Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:charm-librarian-http-interface into launchpad:master.
diff --git a/charm/launchpad-librarian/README.md b/charm/launchpad-librarian/README.md index 52ab88c..a67512b 100644 --- a/charm/launchpad-librarian/README.md +++ b/charm/launchpad-librarian/README.md @@ -8,6 +8,11 @@ You will need the following relations: juju relate launchpad-librarian:session-db postgresql:db juju relate launchpad-librarian rabbitmq-server +You can also relate it to a load balancer, which is especially useful if you +set `workers` to something other than 1: + + juju relate launchpad-librarian:loadbalancer haproxy:reverseproxy + The librarian listens on four ports. By default, these are: - Public download: 8000 diff --git a/charm/launchpad-librarian/config.yaml b/charm/launchpad-librarian/config.yaml index 0a46990..937f30d 100644 --- a/charm/launchpad-librarian/config.yaml +++ b/charm/launchpad-librarian/config.yaml @@ -3,6 +3,28 @@ options: type: boolean default: true description: If true, enable jobs that may change the database. + haproxy_server_options: + type: string + description: Options to add to HAProxy "server" lines. + default: check inter 5000 rise 2 fall 5 maxconn 16 + haproxy_service_options_download: + type: string + description: HAProxy options for download services. + default: | + - mode http + - option httplog + - option httpchk HEAD / HTTP/1.0 + - balance leastconn + haproxy_service_options_upload: + type: string + description: HAProxy options for upload services. + default: | + - mode tcp + - option tcplog + - option httpchk HEAD / HTTP/1.0 + - balance leastconn + - timeout client 600000 + - timeout server 600000 old_os_auth_url: type: string description: > diff --git a/charm/launchpad-librarian/layer.yaml b/charm/launchpad-librarian/layer.yaml index cdfe1c7..ce520c3 100644 --- a/charm/launchpad-librarian/layer.yaml +++ b/charm/launchpad-librarian/layer.yaml @@ -1,5 +1,6 @@ includes: - layer:launchpad-db + - interface:http repo: https://git.launchpad.net/launchpad options: apt: diff --git a/charm/launchpad-librarian/metadata.yaml b/charm/launchpad-librarian/metadata.yaml index ed17f6e..5fb0de8 100644 --- a/charm/launchpad-librarian/metadata.yaml +++ b/charm/launchpad-librarian/metadata.yaml @@ -16,3 +16,6 @@ subordinate: false requires: session-db: interface: pgsql +provides: + loadbalancer: + interface: http diff --git a/charm/launchpad-librarian/reactive/launchpad-librarian.py b/charm/launchpad-librarian/reactive/launchpad-librarian.py index 67cc398..2df140a 100644 --- a/charm/launchpad-librarian/reactive/launchpad-librarian.py +++ b/charm/launchpad-librarian/reactive/launchpad-librarian.py @@ -4,6 +4,7 @@ import os.path import subprocess +import yaml from charmhelpers.core import hookenv, host, templating from charms.launchpad.base import configure_email, get_service_config from charms.launchpad.db import ( @@ -167,3 +168,125 @@ def deconfigure(): def session_db_changed(): remove_state("service.configured") remove_state("session-db.database.changed") + + +@when( + "config.set.librarian_download_port", + "config.set.librarian_restricted_download_port", + "config.set.librarian_restricted_upload_port", + "config.set.librarian_upload_port", + "loadbalancer.available", + "service.configured", +) +@when_not("launchpad.loadbalancer.configured") +def configure_loadbalancer(): + config = hookenv.config() + + try: + service_options_download = yaml.safe_load( + config["haproxy_service_options_download"] + ) + except Exception: + hookenv.log("Could not parse haproxy_service_options_download YAML") + hookenv.status_set( + "blocked", + "Bad haproxy_service_options_download YAML configuration", + ) + return + try: + service_options_upload = yaml.safe_load( + config["haproxy_service_options_upload"] + ) + except Exception: + hookenv.log("Could not parse haproxy_service_options_upload YAML") + hookenv.status_set( + "blocked", "Bad haproxy_service_options_upload YAML configuration" + ) + return + server_options = config["haproxy_server_options"] + + unit_name = hookenv.local_unit().replace("/", "-") + unit_ip = hookenv.unit_private_ip() + services = [ + { + "service_name": "librarian-download", + "service_port": config["librarian_download_port"], + "service_host": "0.0.0.0", + "service_options": list(service_options_download), + "servers": [ + [ + f"dl_{unit_name}_{i + 1}", + unit_ip, + config["port_download_base"] + i, + server_options, + ] + for i in range(config["workers"]) + ], + }, + { + "service_name": "librarian-upload", + "service_port": config["librarian_upload_port"], + "service_host": "0.0.0.0", + "service_options": list(service_options_upload), + "servers": [ + [ + f"ul_{unit_name}_{i + 1}", + unit_ip, + config["port_upload_base"] + i, + f"port {config['port_download_base'] + i} " + + server_options, + ] + for i in range(config["workers"]) + ], + }, + { + "service_name": "librarian-restricted-download", + "service_port": config["librarian_restricted_download_port"], + "service_host": "0.0.0.0", + "service_options": list(service_options_download), + "servers": [ + [ + f"dl_restricted_{unit_name}_{i + 1}", + unit_ip, + config["port_restricted_download_base"] + i, + server_options, + ] + for i in range(config["workers"]) + ], + }, + { + "service_name": "librarian-restricted-upload", + "service_port": config["librarian_restricted_upload_port"], + "service_host": "0.0.0.0", + "service_options": list(service_options_upload), + "servers": [ + [ + f"ul_restricted_{unit_name}_{i + 1}", + unit_ip, + config["port_restricted_upload_base"] + i, + f"port {config['port_restricted_download_base'] + i} " + + server_options, + ] + for i in range(config["workers"]) + ], + }, + ] + services_yaml = yaml.dump(services) + + for rel in hookenv.relations_of_type("loadbalancer"): + hookenv.relation_set(rel["__relid__"], services=services_yaml) + + set_state("launchpad.loadbalancer.configured") + + +@when("launchpad.loadbalancer.configured") +@when_not_all( + "config.set.librarian_download_port", + "config.set.librarian_restricted_download_port", + "config.set.librarian_restricted_upload_port", + "config.set.librarian_upload_port", + "loadbalancer.available", + "service.configured", +) +def deconfigure_loadbalancer(): + remove_state("launchpad.loadbalancer.configured")
_______________________________________________ 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