Skip to content
This repository was archived by the owner on Dec 13, 2018. It is now read-only.

add a label to turn on/off a service balanced in haproxy in swarm mode #150

Merged
merged 2 commits into from
Dec 16, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,14 @@ Settings here can overwrite the settings in HAProxy, which are only applied to t
|TCP_PORTS|comma separated ports(e.g. 9000, 9001, 2222/ssl). The port listed in `TCP_PORTS` will be load-balanced in TCP mode. Port ends with `/ssl` indicates that port needs SSL termination.
|VIRTUAL_HOST_WEIGHT|an integer of the weight of an virtual host, used together with `VIRTUAL_HOST`, default:0. It affects the order of acl rules of the virtual hosts. The higher weight one virtual host has, the more priority that acl rules applies.|
|VIRTUAL_HOST|specify virtual host and virtual path. Format: `[scheme://]domain[:port][/path], ...`. wildcard `*` can be used in `domain` and `path` part|
|SERVICE_PORTS|comma separated ports(e.g. 80, 8080), which are the ports you would like to expose in your application service. This envvar is swarm mode only, and it is **MUST** be set in swarm mode|

Swarm Mode only settings:

|Name|Type|Description|
|:--:|:--:|:---------:|
|SERVICE_PORTS|envvar|comma separated ports(e.g. 80, 8080), which are the ports you would like to expose in your application service. This envvar is swarm mode only, and it is **MUST** be set in swarm mode|
|`com.docker.dockercloud.haproxy.deactivate=<true|false>`|label|when this label is set to true, haproxy will ignore the service. Could be useful for switching services on blue/green testing|


Check [the HAProxy configuration manual](http://cbonte.github.io/haproxy-dconv/configuration-1.5.html) for more information on the above.

Expand Down
2 changes: 1 addition & 1 deletion haproxy/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.6.1"
__version__ = "1.6.2"
3 changes: 3 additions & 0 deletions haproxy/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def parse_extra_frontend_settings(envvars):
settings_dict[port] = settings
return settings_dict


def parse_additional_backend_settings(envvars):
settings_dict = {}
if isinstance(envvars, os._Environ) or isinstance(envvars, dict):
Expand All @@ -47,6 +48,7 @@ def parse_additional_backend_settings(envvars):
settings_dict[server] = settings
return settings_dict


# envvar
ADDITIONAL_BACKENDS = parse_additional_backend_settings(os.environ)
ADDITIONAL_SERVICES = os.getenv("ADDITIONAL_SERVICES")
Expand Down Expand Up @@ -94,6 +96,7 @@ def parse_additional_backend_settings(envvars):
API_RETRY = 10 # seconds
PID_FILE = "/tmp/dockercloud-haproxy.pid"
SERVICE_PORTS_ENVVAR_NAME = "SERVICE_PORTS"
LABEL_SWARM_MODE_DEACTIVATE = "com.docker.dockercloud.haproxy.deactivate"

# regular expressions
SERVICE_NAME_MATCH = re.compile(r"(.+)_\d+$")
Expand Down
15 changes: 5 additions & 10 deletions haproxy/eventhandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import config
import helper.cloud_mode_link_helper
import helper.swarm_mode_link_helper as SwarmModeLinkHelper
from haproxycfg import add_haproxy_run_task, Haproxy
from utils import get_uuid_from_resource_uri

Expand Down Expand Up @@ -106,17 +107,11 @@ def polling_service_status_swarm_mode():
except:
docker = docker_client(os.environ)

services = docker.services()
tasks = docker.tasks(filters={"desired-state": "running"})
linked_tasks = set()
for task in tasks:
task_nets = [network.get("Network", {}).get("ID", "") for network in
task.get("NetworksAttachments", [])]
task_service_id = task.get("ServiceID", "")
if task_service_id != Haproxy.cls_service_id and Haproxy.cls_nets.intersection(set(task_nets)):
task_id = task.get("ID", "")
linked_tasks.add(task_id)

if Haproxy.cls_linked_tasks != linked_tasks:
_, linked_tasks = SwarmModeLinkHelper.get_task_links(tasks, services, Haproxy.cls_service_id,
Haproxy.cls_nets)
if cmp(Haproxy.cls_linked_tasks, linked_tasks) != 0:
add_haproxy_run_task("Tasks are updated")
except APIError as e:
logger.info("Docker API error: %s" % e)
2 changes: 1 addition & 1 deletion haproxy/haproxycfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,4 +395,4 @@ def _config_adittional_backends_sections(self):
for key in ADDITIONAL_BACKENDS:
cfg["backend %s" % key] = ADDITIONAL_BACKENDS[key]

return cfg
return cfg
1 change: 1 addition & 0 deletions haproxy/helper/backend_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def get_backend_routes(route_setting, is_sticky, routes, routes_added, service_a

return sorted(backend_routes)


def get_route_health_check(details, service_alias, default_health_check):
health_check = get_service_attribute(details, "health_check", service_alias)
health_check = health_check if health_check else default_health_check
Expand Down
15 changes: 10 additions & 5 deletions haproxy/helper/swarm_mode_link_helper.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging

import compose_mode_link_helper
from haproxy.config import SERVICE_PORTS_ENVVAR_NAME
from haproxy.config import SERVICE_PORTS_ENVVAR_NAME, LABEL_SWARM_MODE_DEACTIVATE

logger = logging.getLogger("haproxy")

Expand All @@ -27,14 +27,14 @@ def get_swarm_mode_haproxy_id_nets(docker, haproxy_container_short_id):
def get_swarm_mode_links(docker, haproxy_service_id, haproxy_nets):
services = docker.services()
tasks = docker.tasks(filters={"desired-state": "running"})
links, linked_tasks = get_task_links(tasks, services, haproxy_service_id, haproxy_nets)
return links, linked_tasks
return get_task_links(tasks, services, haproxy_service_id, haproxy_nets)


def get_task_links(tasks, services, haproxy_service_id, haproxy_nets):
services_id_name = {s.get("ID"): s.get("Spec", {}).get("Name", "") for s in services}
services_id_labels = {s.get("ID"): s.get("Spec", {}).get("Labels", {}) for s in services}
links = {}
linked_tasks = set()
linked_tasks = {}
for task in tasks:
task_nets = [network.get("Network", {}).get("ID", "") for network in task.get("NetworksAttachments", [])]
task_service_id = task.get("ServiceID", "")
Expand All @@ -44,6 +44,11 @@ def get_task_links(tasks, services, haproxy_service_id, haproxy_nets):
task_slot = "%d" % task.get("Slot", 0)
task_service_id = task.get("ServiceID", "")
task_service_name = services_id_name.get(task_service_id, "")
task_labels = services_id_labels.get(task_service_id)

if task_labels.get(LABEL_SWARM_MODE_DEACTIVATE, "").lower() == "true":
continue

container_name = ".".join([task_service_name, task_slot, task_id])
task_envvars = get_task_envvars(task.get("Spec", {}).get("ContainerSpec", {}).get("Env", []))

Expand All @@ -68,7 +73,7 @@ def get_task_links(tasks, services, haproxy_service_id, haproxy_nets):

links[task_id] = {"endpoints": task_endpoints, "container_name": container_name,
"service_name": task_service_name, "container_envvars": task_envvars}
linked_tasks.add(task_id)
linked_tasks[task_id] = task_labels
return links, linked_tasks


Expand Down
4 changes: 2 additions & 2 deletions tests/unit/helper/test_swarm_mode_link_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,8 @@
u'31b6fuwub6dcgdrvy0kivxvug': {'service_name': u'app', 'endpoints': {u'80/tcp': u'tcp://10.0.0.7:80'},
'container_envvars': [{'value': u'80', 'key': u'SERVICE_PORTS'}],
'container_name': u'app.3.31b6fuwub6dcgdrvy0kivxvug'}}
expected_linked_tasks = {u'7y45xdhy929wzcq94wqdqb8d3', u'bbref0yvjbix87pv6xz1jc3pr', u'31b6fuwub6dcgdrvy0kivxvug'}
expected_linked_tasks = {u'7y45xdhy929wzcq94wqdqb8d3':{}, u'bbref0yvjbix87pv6xz1jc3pr':{},
u'31b6fuwub6dcgdrvy0kivxvug':{}}
expected_nets = {"b951j4at14qali5nxevshec93", "0l130ctu8xay6vfft1mb4tjv0"}
expected_service_id = "07ql4q5a48seh1uhcr2m7ngar"

Expand Down Expand Up @@ -944,7 +945,6 @@ def services(self):

def tasks(self, filters):
return [t for t in tasks if t.get("DesiredState", "") == "running"]

links, linked_tasks = get_swarm_mode_links(Docker(), expected_service_id, expected_nets)
self.assertEquals(expected_links, links)
self.assertEquals(expected_linked_tasks, linked_tasks)
Expand Down