diff --git a/Dockerfile b/Dockerfile index d700c0b..f36740e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,19 +1,36 @@ -FROM ubuntu:trusty +FROM alpine:edge MAINTAINER Feng Honglin -# Install pip and haproxy -RUN echo 'deb http://ppa.launchpad.net/vbernat/haproxy-1.5/ubuntu trusty main' >> /etc/apt/sources.list && \ - echo 'deb-src http://ppa.launchpad.net/vbernat/haproxy-1.5/ubuntu trusty main' >> /etc/apt/sources.list && \ - apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 505D97A41C61B9CD && \ - apt-get update && \ - apt-get install -y --no-install-recommends haproxy python-pip && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* +# Install tini, haproxy, pip and the dockercloud-haproxy python package: +RUN apk --no-cache add \ + tini \ + haproxy \ + py-pip \ + && apk --no-cache add --virtual deps git \ + && pip install --upgrade \ + pip \ + && apk del deps \ + # Clean up obsolete files: + && rm -rf \ + # Clean up any temporary files: + /tmp/* \ + # Clean up the pip cache: + /root/.cache \ + # Remove any compiled python files (compile on demand): + `find / -regex '.*\.py[co]'` COPY reload.sh /reload.sh COPY . haproxy-src/ RUN cd /haproxy-src/ && \ - pip install . + pip install . \ + # Clean up obsolete files: + && rm -rf \ + # Clean up any temporary files: + /tmp/* \ + # Clean up the pip cache: + /root/.cache \ + # Remove any compiled python files (compile on demand): + `find / -regex '.*\.py[co]'` ENV RSYSLOG_DESTINATION=127.0.0.1 \ MODE=http \ @@ -28,4 +45,5 @@ ENV RSYSLOG_DESTINATION=127.0.0.1 \ HEALTH_CHECK="check" EXPOSE 80 443 1936 +ENTRYPOINT ["tini", "--"] CMD ["dockercloud-haproxy"] diff --git a/README.md b/README.md index 3bd5c73..f195d16 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ Settings in this part is immutable, you have to redeploy HAProxy service to make |EXTRA_BIND_SETTINGS||comma-separated string(`:`) of extra settings, and each part will be appended to the related port bind section in the configuration file. To escape comma, use `\,`. Possible value: `443:accept-proxy, 80:name http`| |EXTRA_DEFAULT_SETTINGS||comma-separated string of extra settings, and each part will be appended to DEFAULT section in the configuration file. To escape comma, use `\,`| |EXTRA_GLOBAL_SETTINGS||comma-separated string of extra settings, and each part will be appended to GLOBAL section in the configuration file. To escape comma, use `\,`. Possible value: `tune.ssl.cachesize 20000, tune.ssl.default-dh-param 2048`| -|EXTRA_SSL_CERTS||List of extra certificate names separated by comma, eg. `CERT1, CERT2, CERT3`. You also need to specify each certificate as separate env variables like so: `CERT1=""`, `CERT2=""`, `CERT3=""`| +|EXTRA_SSL_CERTS||list of extra certificate names separated by comma, eg. `CERT1, CERT2, CERT3`. You also need to specify each certificate as separate env variables like so: `CERT1=""`, `CERT2=""`, `CERT3=""`| |HEALTH_CHECK|check|set health check on each backend route, possible value: "check inter 2000 rise 2 fall 3". See:[HAProxy:check](https://cbonte.github.io/haproxy-dconv/configuration-1.5.html#5.2-check)| |HTTP_BASIC_AUTH||a comma-separated list of credentials(`:`) for HTTP basic auth, which applies to all the backend routes. To escape comma, use `\,`. *Attention:* DO NOT rely on this for authentication in production| |MAXCONN|4096|sets the maximum per-process number of concurrent connections.| @@ -152,6 +152,9 @@ Settings in this part is immutable, you have to redeploy HAProxy service to make |STATS_AUTH|stats:stats|username and password required to access the Haproxy stats.| |STATS_PORT|1936|port for the HAProxy stats section. If this port is published, stats can be accessed at `http://:/` |TIMEOUT|connect 5000, client 50000, server 50000|comma-separated list of HAProxy `timeout` entries to the `default` section.| +|ADDITIONAL_SERVICES||list of additional services to balance (es: `prj1:web,prj2:sql`). Discovery will be based on `com.docker.compose.[project|service]` container labels. This environment variable only works on compose v2, and the referenced services must be on a network accessible to this containers.| +|CA_CERT_FILE|the path of a ca-cert file. This allows you to mount your ca-cert file directly from a volume instead of from envvar. If set, `CA_CERT` envvar will be ignored. Possible value: `/cacerts/cert0.pem`| +|CERT_FOLDER|the path of certificates. This allows you to mount your certificate files directly from a volume instead of from envvars. If set, `DEFAULT_SSL_CERT` and `SSL_CERT` from linked services are ignored. Possible value:`/certs/`| ### Settings in linked application services### @@ -159,9 +162,9 @@ Settings here can overwrite the settings in HAProxy, which are only applied to t |env var|description| |:-----:|:----------| -|APPSESSION|sticky session option. possible value `JSESSIONID len 52 timeout 3h`. See:[HAProxy:appsession](http://cbonte.github.io/haproxy-dconv/configuration-1.5.html#4-appsession)| +|APPSESSION|sticky session option, possible value `JSESSIONID len 52 timeout 3h`. See:[HAProxy:appsession](http://cbonte.github.io/haproxy-dconv/configuration-1.5.html#4-appsession)| |BALANCE|load balancing algorithm to use. Possible values include: `roundrobin`, `static-rr`, `source`, `leastconn`. See:[HAProxy:balance](https://cbonte.github.io/haproxy-dconv/configuration-1.5.html#4-balance)| -|COOKIE|sticky session option. possible value `SRV insert indirect nocache`. See:[HAProxy:cookie](http://cbonte.github.io/haproxy-dconv/configuration-1.5.html#4-cookie)| +|COOKIE|sticky session option. Possible value `SRV insert indirect nocache`. See:[HAProxy:cookie](http://cbonte.github.io/haproxy-dconv/configuration-1.5.html#4-cookie)| |DEFAULT_SSL_CERT|similar to SSL_CERT, but stores the pem file at `/certs/cert0.pem` as the default ssl certs. If multiple `DEFAULT_SSL_CERT` are specified in linked services and HAProxy, the behavior is undefined| |EXCLUDE_PORTS|comma separated port numbers(e.g. 3306, 3307). By default, HAProxy will add all the ports exposed by the application services to the backend routes. You can exclude the ports that you don't want to be routed, like database port| |EXTRA_SETTINGS|comma-separated string of extra settings, and each part will be appended to either related backend section or listen session in the configuration file. To escape comma, use `\,`. Possible value: `balance source`| @@ -344,6 +347,13 @@ Use the following: docker run -d -e FORCE_SSL=yes -e SSL_CERT="YOUR_CERT_TEXT" --name webapp dockercloud/hello-world docker run -d --link webapp:webapp -p 443:443 dockercloud/haproxy +#### I want to load my SSL certificate from volume instead of passing it through environment variable + +You can use `CERT_FOLDER` envvar to specify which folder the certificates are mounted in the container, using the following: + + docker run -d --name webapp dockercloud/hello-world + docker run -d --link webapp:webapp -e CERT_FOLDER="/certs/" -v $(pwd)/cert1.pem:/certs/cert1.pem -p 443:443 dockercloud/haproxy + #### I want to set up virtual host routing by domain Virtual hosts can be configured by the proxy reading linked container environment variables (`VIRTUAL_HOST`). Here is an example: @@ -426,5 +436,3 @@ In most cases, `dockercloud/haproxy` will configure itself automatically when th * `docker exec /reload.sh`, if you are on the node where dockercloud/haproxy deploys * `docker-cloud exec /reload.sh`, if you use docker-cloud cli - -Note: when `reload.sh` is invoked, it doesn't necessarily mean that HAProxy will be restarted. In fact, `dockercloud/haproxy` will try to get the current information of the the service and calculate a new configuration. HAProxy will only be restarted when the newly generated configuration differs from the current one. diff --git a/haproxy/config.py b/haproxy/config.py index eaed410..1467a6a 100644 --- a/haproxy/config.py +++ b/haproxy/config.py @@ -37,6 +37,9 @@ def parse_extra_bind_settings(extra_bind_settings): HAPROXY_CONTAINER_URI = os.getenv("DOCKERCLOUD_CONTAINER_API_URI") HAPROXY_SERVICE_URI = os.getenv("DOCKERCLOUD_SERVICE_API_URI") API_AUTH = os.getenv("DOCKERCLOUD_AUTH") +CA_CERT_FILE = os.getenv("CA_CERT_FILE") +CERT_FOLDER = os.getenv("CERT_FOLDER") +ADDITIONAL_SERVICES = os.environ.get("ADDITIONAL_SERVICES") DEBUG = os.getenv("DEBUG", False) LINK_MODE = "" diff --git a/haproxy/eventhandler.py b/haproxy/eventhandler.py index cad7e04..3dbed21 100644 --- a/haproxy/eventhandler.py +++ b/haproxy/eventhandler.py @@ -45,7 +45,11 @@ def on_websocket_close(): def on_user_reload(signum, frame): - run_haproxy("User reload") + Haproxy.cls_cfg = None + if config.LINK_MODE == "legacy": + logger.info("User reload is not supported in legacy link mode") + else: + run_haproxy("User reload") def listen_dockercloud_events(): diff --git a/haproxy/haproxycfg.py b/haproxy/haproxycfg.py index 6a2c951..2584125 100644 --- a/haproxy/haproxycfg.py +++ b/haproxy/haproxycfg.py @@ -30,6 +30,7 @@ class Haproxy(object): cls_cfg = None cls_process = None cls_certs = [] + cls_ca_certs = [] def __init__(self, link_mode="", msg=""): logger.info("==========BEGIN==========") @@ -80,6 +81,16 @@ def _init_new_links(): logger.info("Docker API error, regressing to legacy links mode: ", e) return None links, Haproxy.cls_linked_services = NewLinkHelper.get_new_links(docker, haproxy_container) + + try: + if ADDITIONAL_SERVICES: + additional_services = ADDITIONAL_SERVICES.split(",") + NewLinkHelper.get_additional_links(docker, additional_services, haproxy_container, + links, Haproxy.cls_linked_services) + except Exception as e: + logger.info("Error loading ADDITIONAL_SERVICES: %s" % str(e)) + return None + logger.info("Linked service: %s", ", ".join(NewLinkHelper.get_service_links_str(links))) logger.info("Linked container: %s", ", ".join(NewLinkHelper.get_container_links_str(links))) return links @@ -121,8 +132,16 @@ def _update_haproxy(self, cfg): def _config_ssl(self): ssl_bind_string = "" - ssl_bind_string += self._config_ssl_certs() - ssl_bind_string += self._config_ssl_cacerts() + if CERT_FOLDER: + ssl_bind_string += "ssl crt %s" % CERT_FOLDER + else: + ssl_bind_string += self._config_ssl_certs() + + if CA_CERT_FILE: + ssl_bind_string += " ca-file %s verify required" % CA_CERT_FILE + else: + ssl_bind_string += self._config_ssl_cacerts() + if ssl_bind_string: self.ssl_bind_string = ssl_bind_string @@ -149,8 +168,8 @@ def _config_ssl_cacerts(self): if DEFAULT_CA_CERT: cacerts.append(DEFAULT_CA_CERT) if cacerts: - if set(cacerts) != set(Haproxy.cls_certs): - Haproxy.cls_certs = copy.copy(cacerts) + if set(cacerts) != set(Haproxy.cls_ca_certs): + Haproxy.cls_ca_certs = copy.copy(cacerts) self.ssl_updated = True SslHelper.save_certs(CACERT_DIR, cacerts) logger.info("SSL CA certificates are updated") diff --git a/haproxy/helper/new_link_helper.py b/haproxy/helper/new_link_helper.py index 0f1e974..0c7390c 100644 --- a/haproxy/helper/new_link_helper.py +++ b/haproxy/helper/new_link_helper.py @@ -16,6 +16,43 @@ def get_new_links(docker, haproxy_container): return links, ["%s_%s" % (project, service) for service in linked_compose_services] +def get_additional_links(docker, additional_services, haproxy_container, links, linked_services): + networks_data = docker.networks() + haproxy_networks_ids = _find_container_networks_ids(haproxy_container, networks_data) + for _container in docker.containers(): + container_id = _container.get("Id", "") + container = docker.inspect_container(container_id) + compose_project = container.get("Config", {}).get("Labels", {}).get("com.docker.compose.project", "") + compose_service = container.get("Config", {}).get("Labels", {}).get("com.docker.compose.service", "") + for _service in additional_services: + terms = _service.strip().split(":") + if len(terms) == 2: + if terms[0].strip() == compose_project and terms[1].strip() == compose_service: + container_networks_ids = _find_container_networks_ids(container, networks_data) + if set(container_networks_ids).intersection(haproxy_networks_ids): + if _service not in linked_services: + linked_services.append(_service) + container_name = container.get("Name").lstrip("/") + container_evvvars = _get_container_envvars(container) + endpoints = _get_container_endpoints(container, container_name) + links[container_id] = {"service_name": _service, + "container_envvars": container_evvvars, + "container_name": container_name, + "endpoints": endpoints, + "compose_service": compose_service, + "compose_project": compose_project} + else: + logger.info("Ignoring container '%s': no shared network with haproxy") + + +def _find_container_networks_ids(container, networks_data): + ids = [] + for network in networks_data: + if container['Id'] in network['Containers'].keys(): + ids.append(network['Id']) + return ids + + def _calc_links(docker, linked_compose_services, project): links = {} for _container in docker.containers(): @@ -76,7 +113,9 @@ def _get_linked_compose_services(networks, project): haproxy_links = [] for network in networks.itervalues(): - haproxy_links.extend(network.get("Links", [])) + network_links = network.get("Links", []) + if network_links: + haproxy_links.extend(network_links) linked_services = [] for link in haproxy_links: diff --git a/test.sh b/test.sh index fba8e96..b14bda6 100755 --- a/test.sh +++ b/test.sh @@ -8,6 +8,6 @@ pip install -r test-requirements.txt nosetests -v --with-coverage --cover-package haproxy if [ "$(uname -s)" != "Darwin" ]; then - echo ==================== Integration Test ======================= - tests/integration_test.sh + echo ==================== Integration Test on Legacy links ======================= + tests/test_legacy_links.sh fi diff --git a/tests/integration_test.sh b/tests/test_legacy_links.sh similarity index 83% rename from tests/integration_test.sh rename to tests/test_legacy_links.sh index 9d3473b..043e20e 100755 --- a/tests/integration_test.sh +++ b/tests/test_legacy_links.sh @@ -65,7 +65,7 @@ echo "=> Running Tests" echo "=> Test if haproxy is running properly" rm_container web-a lb -docker run -d --name web-a -e HOSTNAME="web-a" tutum/hello-world +docker run -d --name web-a -e HOSTNAME="web-a" dockercloud/hello-world docker run -d --name lb --link web-a:web-a -p 8000:80 haproxy wait_for_startup http://${DOCKER_HOST_IP}:8000 curl -ssfL -I http://${DOCKER_HOST_IP}:8000 > /dev/null @@ -73,7 +73,7 @@ echo echo "=> Test Default_SSL_CERT(client verifies server)" rm_container web-a lb -docker run -d --name web-a -e HOSTNAME="web-a" tutum/hello-world +docker run -d --name web-a -e HOSTNAME="web-a" dockercloud/hello-world docker run -d --name lb --link web-a:web-a -e DEFAULT_SSL_CERT="$(awk 1 ORS='\\n' cert1.pem)" -p 443:443 haproxy wait_for_startup https://${DOCKER_HOST_IP} curl -sSfL --resolve web-a.org:443:${DOCKER_HOST_IP} https://web-a.org 2>&1 | grep -iF "SSL certificate problem" > /dev/null @@ -82,7 +82,7 @@ echo echo "=> Test SSL verification(server verifies client)" rm_container web-a lb -docker run -d --name web-a -e HOSTNAME="web-a" tutum/hello-world +docker run -d --name web-a -e HOSTNAME="web-a" dockercloud/hello-world docker run -d --name lb --link web-a:web-a -e DEFAULT_SSL_CERT="$(awk 1 ORS='\\n' cert1.pem)" -e CA_CERT="$(awk 1 ORS='\\n' ca0.pem)" -p 443:443 haproxy wait_for_startup https://${DOCKER_HOST_IP} echo " Sending request without certificate" @@ -93,10 +93,32 @@ echo " Sending request with the correct certificate" curl -sSfL --cacert ca1.pem --cert cert0.pem --resolve web-a.org:443:${DOCKER_HOST_IP} https://web-a.org 2>&1 | grep -iF 'My hostname is web-a' > /dev/null echo +echo "=> Test mounting certs from volume" +rm_container web-a lb +docker run -d --name web-a -e HOSTNAME="web-a" dockercloud/hello-world +docker run -d --name lb --link web-a:web-a -e CERT_FOLDER="/certs/" -v $(pwd)/cert1.pem:/certs/cert1.pem -p 443:443 haproxy +wait_for_startup https://${DOCKER_HOST_IP} +curl -sSfL --resolve web-a.org:443:${DOCKER_HOST_IP} https://web-a.org 2>&1 | grep -iF "SSL certificate problem" > /dev/null +curl -sSfL --cacert ca1.pem --resolve web-a.org:443:${DOCKER_HOST_IP} https://web-a.org 2>&1 | grep -iF 'My hostname is web-a' > /dev/null +echo + +echo "=> Test mounting ca-cert from volume" +rm_container web-a lb +docker run -d --name web-a -e HOSTNAME="web-a" dockercloud/hello-world +docker run -d --name lb --link web-a:web-a -e CERT_FOLDER="/certs/" -v $(pwd)/cert1.pem:/certs/cert1.pem -e CA_CERT_FILE="/cacert/ca0.pem" -v $(pwd)/ca0.pem:/cacert/ca0.pem -p 443:443 haproxy +wait_for_startup https://${DOCKER_HOST_IP} +echo " Sending request without certificate" +curl -sSfL --cacert ca1.pem --resolve web-a.org:443:${DOCKER_HOST_IP} https://web-a.org 2>&1 > /dev/null | grep 'handshake' > /dev/null +echo " Sending request with a wrong certificate" +curl -sSfL --cacert ca1.pem --cert cert1.pem --resolve web-a.org:443:${DOCKER_HOST_IP} https://web-a.org 2>&1 > /dev/null | grep 'alert unknown ca' > /dev/null +echo " Sending request with the correct certificate"c +curl -sSfL --cacert ca1.pem --cert cert0.pem --resolve web-a.org:443:${DOCKER_HOST_IP} https://web-a.org 2>&1 | grep -iF 'My hostname is web-a' > /dev/null +echo + echo "=> Test virtual host" rm_container web-a web-b lb -docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST=web-a.org tutum/hello-world -docker run -d --name web-b -e HOSTNAME=web-b -e VIRTUAL_HOST=web-b.org tutum/hello-world +docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST=web-a.org dockercloud/hello-world +docker run -d --name web-b -e HOSTNAME=web-b -e VIRTUAL_HOST=web-b.org dockercloud/hello-world docker run -d --name lb --link web-a:web-a --link web-b:web-b -p 80:80 haproxy wait_for_startup http://${DOCKER_HOST_IP} curl -sSfL --resolve web-a.org:80:${DOCKER_HOST_IP} web-a.org 2>&1 | grep -iF 'My hostname is web-a' > /dev/null @@ -105,8 +127,8 @@ echo echo "=> Test multiple ssl certificates" rm_container web-a web-b lb -docker run -d --name web-a -e HOSTNAME="web-a" -e VIRTUAL_HOST="https://web-a.org" -e SSL_CERT="$(awk 1 ORS='\\n' cert1.pem)" tutum/hello-world -docker run -d --name web-b -e HOSTNAME="web-b" -e VIRTUAL_HOST="https://web-b.org" -e SSL_CERT="$(awk 1 ORS='\\n' cert2.pem)" tutum/hello-world +docker run -d --name web-a -e HOSTNAME="web-a" -e VIRTUAL_HOST="https://web-a.org" -e SSL_CERT="$(awk 1 ORS='\\n' cert1.pem)" dockercloud/hello-world +docker run -d --name web-b -e HOSTNAME="web-b" -e VIRTUAL_HOST="https://web-b.org" -e SSL_CERT="$(awk 1 ORS='\\n' cert2.pem)" dockercloud/hello-world docker run -d --name lb --link web-a:web-a --link web-b:web-b -p 443:443 haproxy wait_for_startup https://${DOCKER_HOST_IP} curl -sSfL --cacert ca1.pem --resolve web-a.org:443:${DOCKER_HOST_IP} https://web-a.org 2>&1 | grep -iF 'My hostname is web-a' > /dev/null @@ -117,8 +139,8 @@ echo echo "=> Test multiple virtual host entries" rm_container web-a web-b lb -docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST='web-a.org, web-a.com' tutum/hello-world -docker run -d --name web-b -e HOSTNAME=web-b -e VIRTUAL_HOST='web-b.org, web-b.com' tutum/hello-world +docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST='web-a.org, web-a.com' dockercloud/hello-world +docker run -d --name web-b -e HOSTNAME=web-b -e VIRTUAL_HOST='web-b.org, web-b.com' dockercloud/hello-world docker run -d --name lb --link web-a:web-a --link web-b:web-b -p 80:80 haproxy wait_for_startup http://${DOCKER_HOST_IP} curl -sSfL --resolve web-a.org:80:${DOCKER_HOST_IP} http://web-a.org 2>&1 | grep -iF 'My hostname is web-a' > /dev/null @@ -129,8 +151,8 @@ echo echo "=> Test virtual host with duplicated entries" rm_container web-a web-b lb -docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST='web-a.org, web-a.org:80' tutum/hello-world -docker run -d --name web-b -e HOSTNAME=web-b -e VIRTUAL_HOST='web-b.org:8080, web-b.org:8080' tutum/hello-world +docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST='web-a.org, web-a.org:80' dockercloud/hello-world +docker run -d --name web-b -e HOSTNAME=web-b -e VIRTUAL_HOST='web-b.org:8080, web-b.org:8080' dockercloud/hello-world docker run -d --name lb --link web-a:web-a --link web-b:web-b -p 80:80 -p 8080:8080 haproxy wait_for_startup http://${DOCKER_HOST_IP} curl -sSfL --resolve web-a.org:80:${DOCKER_HOST_IP} web-a.org 2>&1 | grep -iF 'My hostname is web-a' > /dev/null @@ -141,8 +163,8 @@ echo echo "=> Test virtual host with ports" rm_container web-a web-b lb -docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST='web-a.org' tutum/hello-world -docker run -d --name web-b -e HOSTNAME=web-b -e VIRTUAL_HOST='web-b.org:8080' tutum/hello-world +docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST='web-a.org' dockercloud/hello-world +docker run -d --name web-b -e HOSTNAME=web-b -e VIRTUAL_HOST='web-b.org:8080' dockercloud/hello-world docker run -d --name lb --link web-a:web-a --link web-b:web-b -p 80:80 -p 8080:8080 haproxy wait_for_startup http://${DOCKER_HOST_IP} curl -sSfL --resolve web-a.org:80:${DOCKER_HOST_IP} web-a.org 2>&1 | grep -iF 'My hostname is web-a' > /dev/null @@ -153,8 +175,8 @@ echo echo "=> Test virtual host with scheme and ports" rm_container web-a web-b lb -docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="https://web-a.org:442" -e SSL_CERT="$(awk 1 ORS='\\n' cert1.pem)" tutum/hello-world -docker run -d --name web-b -e HOSTNAME=web-b -e VIRTUAL_HOST="http://web-b.org:8080" tutum/hello-world +docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="https://web-a.org:442" -e SSL_CERT="$(awk 1 ORS='\\n' cert1.pem)" dockercloud/hello-world +docker run -d --name web-b -e HOSTNAME=web-b -e VIRTUAL_HOST="http://web-b.org:8080" dockercloud/hello-world docker run -d --name lb --link web-a:web-a --link web-b:web-b -p 442:442 -p 8080:8080 haproxy wait_for_startup http://${DOCKER_HOST_IP}:8080 curl -sSfL --cacert ca1.pem --resolve web-a.org:442:${DOCKER_HOST_IP} https://web-a.org:442 2>&1 | grep -iF 'My hostname is web-a' > /dev/null @@ -165,7 +187,7 @@ echo echo "=> Test virtual host with a value of *" rm_container web-a lb -docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="*" tutum/hello-world +docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="*" dockercloud/hello-world docker run -d --name lb --link web-a:web-a -p 80:80 haproxy wait_for_startup http://${DOCKER_HOST_IP}:80 curl -sSfL --resolve web-a.org:80:${DOCKER_HOST_IP} web-a.org:80 2>&1 | grep -iF 'My hostname is web-a' > /dev/null @@ -174,7 +196,7 @@ echo echo "=> Test virtual host with a value of */" rm_container web-a lb -docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="*/" tutum/hello-world +docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="*/" dockercloud/hello-world docker run -d --name lb --link web-a:web-a -p 80:80 haproxy wait_for_startup http://${DOCKER_HOST_IP}:80 curl -sSfL --resolve web-a.org:80:${DOCKER_HOST_IP} web-a.org:80 2>&1 | grep -iF 'My hostname is web-a' > /dev/null @@ -184,7 +206,7 @@ echo echo "=> Test virtual host with a value of */*" rm_container web-a lb -docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="*/*" tutum/hello-world +docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="*/*" dockercloud/hello-world docker run -d --name lb --link web-a:web-a -p 80:80 haproxy wait_for_startup http://${DOCKER_HOST_IP}:80 curl -sSfL --resolve web-a.org:80:${DOCKER_HOST_IP} web-a.org:80 2>&1 | grep -iF 'My hostname is web-a' > /dev/null @@ -195,7 +217,7 @@ echo echo "=> Test virtual host with wildcard in host and on a non-default port" rm_container web-a lb -docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="http://web-*.org:8080" tutum/hello-world +docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="http://web-*.org:8080" dockercloud/hello-world docker run -d --name lb --link web-a:web-a -p 8080:8080 haproxy wait_for_startup http://${DOCKER_HOST_IP}:8080 curl -sSfL --resolve web-a.org:8080:${DOCKER_HOST_IP} web-a.org:8080 2>&1 | grep -iF 'My hostname is web-a' > /dev/null @@ -204,7 +226,7 @@ echo echo "=> Test virtual host that starts with wildcard" rm_container web-a lb -docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="*.web-a.org" tutum/hello-world +docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="*.web-a.org" dockercloud/hello-world docker run -d --name lb --link web-a:web-a -p 80:80 haproxy wait_for_startup http://${DOCKER_HOST_IP}:80 curl -sSfL --resolve www.web-a.org:80:${DOCKER_HOST_IP} www.web-a.org 2>&1 | grep -iF 'My hostname is web-a' > /dev/null @@ -217,7 +239,7 @@ echo echo "=> Test virtual host that ends with wildcard" rm_container web-a lb -docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="web-a.*" tutum/hello-world +docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="web-a.*" dockercloud/hello-world docker run -d --name lb --link web-a:web-a -p 80:80 haproxy wait_for_startup http://${DOCKER_HOST_IP}:80 curl -sSfL --resolve web-a.org:80:${DOCKER_HOST_IP} web-a.org 2>&1 | grep -iF 'My hostname is web-a' > /dev/null @@ -229,13 +251,13 @@ echo echo "=> Test virtual path" rm_container web-a web-b web-c web-d web-e web-f web-g lb -docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="*/pa/, */pa, */pa/*, */*/pa/*" tutum/hello-world -docker run -d --name web-b -e HOSTNAME=web-b -e VIRTUAL_HOST="*/pb" tutum/hello-world -docker run -d --name web-c -e HOSTNAME=web-c -e VIRTUAL_HOST="*/pc/" tutum/hello-world -docker run -d --name web-d -e HOSTNAME=web-d -e VIRTUAL_HOST="*/pd/*" tutum/hello-world -docker run -d --name web-e -e HOSTNAME=web-e -e VIRTUAL_HOST="*/*/pe/*" tutum/hello-world -docker run -d --name web-f -e HOSTNAME=web-f -e VIRTUAL_HOST="*/p*f/" tutum/hello-world -docker run -d --name web-g -e HOSTNAME=web-g -e VIRTUAL_HOST="*/*.js" tutum/hello-world +docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="*/pa/, */pa, */pa/*, */*/pa/*" dockercloud/hello-world +docker run -d --name web-b -e HOSTNAME=web-b -e VIRTUAL_HOST="*/pb" dockercloud/hello-world +docker run -d --name web-c -e HOSTNAME=web-c -e VIRTUAL_HOST="*/pc/" dockercloud/hello-world +docker run -d --name web-d -e HOSTNAME=web-d -e VIRTUAL_HOST="*/pd/*" dockercloud/hello-world +docker run -d --name web-e -e HOSTNAME=web-e -e VIRTUAL_HOST="*/*/pe/*" dockercloud/hello-world +docker run -d --name web-f -e HOSTNAME=web-f -e VIRTUAL_HOST="*/p*f/" dockercloud/hello-world +docker run -d --name web-g -e HOSTNAME=web-g -e VIRTUAL_HOST="*/*.js" dockercloud/hello-world docker run -d --name lb --link web-a:web-a --link web-b:web-b --link web-c:web-c --link web-d:web-d --link web-e:web-e --link web-f:web-f --link web-g:web-g -p 80:80 haproxy wait_for_startup http://${DOCKER_HOST_IP}:80 @@ -293,7 +315,7 @@ echo echo "=> Test virtual host combined with virtual path" rm_container web-a lb -docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="http://www.web-a.org/p3/" tutum/hello-world +docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="http://www.web-a.org/p3/" dockercloud/hello-world docker run -d --name lb --link web-a:web-a -p 80:80 haproxy wait_for_startup http://${DOCKER_HOST_IP}:80 curl -sSfL --resolve www.web-a.org:80:${DOCKER_HOST_IP} www.web-a.org/p3/ 2>&1 | grep -iF 'My hostname is web-a' > /dev/null @@ -306,7 +328,7 @@ echo echo "=> Test virtual host combined with virtual path including wildcard" rm_container web-a lb -docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="http://www.web-*.org/p*/" tutum/hello-world +docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="http://www.web-*.org/p*/" dockercloud/hello-world docker run -d --name lb --link web-a:web-a -p 80:80 haproxy wait_for_startup http://${DOCKER_HOST_IP}:80 curl -sSfL --resolve www.web-a.org:80:${DOCKER_HOST_IP} www.web-a.org/p1/ 2>&1 | grep -iF 'My hostname is web-a' > /dev/null @@ -318,7 +340,7 @@ echo echo "=> Test virtual host combined with virtual path including wildcard on a none default port" rm_container web-a lb -docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="http://www.web-*.org:8080/p*/" tutum/hello-world +docker run -d --name web-a -e HOSTNAME=web-a -e VIRTUAL_HOST="http://www.web-*.org:8080/p*/" dockercloud/hello-world docker run -d --name lb --link web-a:web-a -p 8080:8080 haproxy wait_for_startup http://${DOCKER_HOST_IP}:8080 curl -sSfL --resolve www.web-a.org:8080:${DOCKER_HOST_IP} www.web-a.org:8080/p1/ 2>&1 | grep -iF 'My hostname is web-a' > /dev/null @@ -331,9 +353,9 @@ echo echo "=> Test multiple frontends" rm_container web-a web-b web-c lb -docker run -d --name web-a -e HOSTNAME="web-a" -e VIRTUAL_HOST="https://web-a.org:444, weba2.org:8008" -e SSL_CERT="$(awk 1 ORS='\\n' cert1.pem)" tutum/hello-world -docker run -d --name web-b -e HOSTNAME="web-b" -e VIRTUAL_HOST="https://web-b.org, http://webb2.org" -e SSL_CERT="$(awk 1 ORS='\\n' cert2.pem)" tutum/hello-world -docker run -d --name web-c -e HOSTNAME="web-c" -e VIRTUAL_HOST="webc.org, http://webc1.org:8009, webc2.org/path/, */*.do/, *:8011/*.php/" tutum/hello-world +docker run -d --name web-a -e HOSTNAME="web-a" -e VIRTUAL_HOST="https://web-a.org:444, weba2.org:8008" -e SSL_CERT="$(awk 1 ORS='\\n' cert1.pem)" dockercloud/hello-world +docker run -d --name web-b -e HOSTNAME="web-b" -e VIRTUAL_HOST="https://web-b.org, http://webb2.org" -e SSL_CERT="$(awk 1 ORS='\\n' cert2.pem)" dockercloud/hello-world +docker run -d --name web-c -e HOSTNAME="web-c" -e VIRTUAL_HOST="webc.org, http://webc1.org:8009, webc2.org/path/, */*.do/, *:8011/*.php/" dockercloud/hello-world docker run -d --name lb --link web-a:web-a --link web-b:web-b --link web-c:web-c -p 443:443 -p 444:444 -p 8008:8008 -p 8009:8009 -p 80:80 -p 8011:8011 haproxy wait_for_startup http://${DOCKER_HOST_IP}:80 curl -sSfL --cacert ca1.pem --resolve web-a.org:444:${DOCKER_HOST_IP} https://web-a.org:444 2>&1 | grep -iF 'My hostname is web-a' > /dev/null @@ -350,27 +372,27 @@ curl -sSfL ${DOCKER_HOST_IP}:8011/abc.php/ 2>&1 | grep -iF 'My hostname is web-c echo echo "=> Test force_ssl with virtual host" -rm_container web-a web-b lb -docker run -d --name web-a -e HOSTNAME="web-a" -e VIRTUAL_HOST="https://web-a.org, web-a.org" -e SSL_CERT="$(awk 1 ORS='\\n' cert1.pem)" tutum/hello-world -docker run -d --name web-b -e HOSTNAME="web-b" -e VIRTUAL_HOST="https://web-b.org, web-b.org" -e SSL_CERT="$(awk 1 ORS='\\n' cert2.pem)" -e FORCE_SSL=true tutum/hello-world +rm_container web-a web-b lb +docker run -d --name web-a -e HOSTNAME="web-a" -e VIRTUAL_HOST="https://web-a.org, web-a.org" -e SSL_CERT="$(awk 1 ORS='\\n' cert1.pem)" dockercloud/hello-world +docker run -d --name web-b -e HOSTNAME="web-b" -e VIRTUAL_HOST="https://web-b.org, web-b.org" -e SSL_CERT="$(awk 1 ORS='\\n' cert2.pem)" -e FORCE_SSL=true dockercloud/hello-world docker run -d --name lb --link web-a:web-a --link web-b:web-b -p 443:443 -p 80:80 haproxy wait_for_startup http://${DOCKER_HOST_IP}:80 -curl -sSfL --cacert ca1.pem --resolve web-a.org:443:127.0.0.1 https://web-a.org 2>&1 | grep -iF 'My hostname is web-a' > /dev/null -curl -sSfL --cacert ca2.pem --resolve web-b.org:443:127.0.0.1 https://web-b.org 2>&1 | grep -iF 'My hostname is web-b' > /dev/null -curl -sSfL --cacert ca1.pem --resolve web-a.org:443:127.0.0.1 --resolve web-a.org:80:127.0.0.1 http://web-a.org 2>&1 | grep -iF 'My hostname is web-a' > /dev/null -curl -sSfL --cacert ca2.pem --resolve web-b.org:443:127.0.0.1 --resolve web-b.org:80:127.0.0.1 http://web-b.org 2>&1 | grep -iF 'My hostname is web-b' > /dev/null -curl -sSIL --cacert ca1.pem --resolve web-a.org:443:127.0.0.1 --resolve web-a.org:80:127.0.0.1 http://web-a.org 2>&1 | grep -iF "http/1.1" | grep -v "301" > /dev/null -curl -sSIL --cacert ca2.pem --resolve web-b.org:443:127.0.0.1 --resolve web-b.org:80:127.0.0.1 http://web-b.org 2>&1 | grep -iF '301 Moved Permanently' > /dev/null +curl -sSfL --cacert ca1.pem --resolve web-a.org:443:${DOCKER_HOST_IP} https://web-a.org 2>&1 | grep -iF 'My hostname is web-a' > /dev/null +curl -sSfL --cacert ca2.pem --resolve web-b.org:443:${DOCKER_HOST_IP} https://web-b.org 2>&1 | grep -iF 'My hostname is web-b' > /dev/null +curl -sSfL --cacert ca1.pem --resolve web-a.org:443:${DOCKER_HOST_IP} --resolve web-a.org:80:${DOCKER_HOST_IP} http://web-a.org 2>&1 | grep -iF 'My hostname is web-a' > /dev/null +curl -sSfL --cacert ca2.pem --resolve web-b.org:443:${DOCKER_HOST_IP} --resolve web-b.org:80:${DOCKER_HOST_IP} http://web-b.org 2>&1 | grep -iF 'My hostname is web-b' > /dev/null +curl -sSIL --cacert ca1.pem --resolve web-a.org:443:${DOCKER_HOST_IP} --resolve web-a.org:80:${DOCKER_HOST_IP} http://web-a.org 2>&1 | grep -iF "http/1.1" | grep -v "301" > /dev/null +curl -sSIL --cacert ca2.pem --resolve web-b.org:443:${DOCKER_HOST_IP} --resolve web-b.org:80:${DOCKER_HOST_IP} http://web-b.org 2>&1 | grep -iF '301 Moved Permanently' > /dev/null echo echo "=> Testing force_ssl without virtual host" rm_container web-a web-b lb -docker run -d --name web-a -e HOSTNAME="web-ab" -e SSL_CERT="$(awk 1 ORS='\\n' cert0.pem)" tutum/hello-world -docker run -d --name web-b -e HOSTNAME="web-ab" -e FORCE_SSL=true tutum/hello-world +docker run -d --name web-a -e HOSTNAME="web-ab" -e SSL_CERT="$(awk 1 ORS='\\n' cert1.pem)" dockercloud/hello-world +docker run -d --name web-b -e HOSTNAME="web-ab" -e FORCE_SSL=true dockercloud/hello-world docker run -d --name lb --link web-a:web-a --link web-b:web-b -p 443:443 -p 80:80 haproxy wait_for_startup http://${DOCKER_HOST_IP}:80 -curl -sSfL --cacert ca0.pem ${DOCKER_HOST_IP} 2>&1 | grep -iF 'My hostname is web-ab' > /dev/null -curl -sSIL --cacert ca0.pem ${DOCKER_HOST_IP} 2>&1 | grep -iF '301 Moved Permanently' > /dev/null +curl -sSfL --cacert ca1.pem --resolve web-a.org:443:${DOCKER_HOST_IP} https://web-a.org 2>&1 | grep -iF 'My hostname is web-ab' > /dev/null +curl -sSIL --cacert ca1.pem --resolve web-a.org:443:${DOCKER_HOST_IP} https://web-a.org > /dev/null echo echo "=> Clean up" diff --git a/tests/unit/test_haproxycfg.py b/tests/unit/test_haproxycfg.py index b4c0a2d..89570da 100644 --- a/tests/unit/test_haproxycfg.py +++ b/tests/unit/test_haproxycfg.py @@ -151,7 +151,7 @@ def test_config_ssl_certs(self, mock_init, mock_save): haproxycfg.DEFAULT_CA_CERT = "cacert" Haproxy.cls_certs = [] self.assertEqual(" ca-file /cacerts/cert0.pem verify required", haproxy._config_ssl_cacerts()) - self.assertEqual(["cacert"], Haproxy.cls_certs) + self.assertEqual(["cacert"], Haproxy.cls_ca_certs) self.assertTrue(haproxy.ssl_updated) haproxy = Haproxy()