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

Commit b881015

Browse files
author
Feng Honglin
authored
add a label to turn on/off a service balanced in haproxy in swarm mode (#150)
* add a label to switch services on blue/green testing * bump ver
1 parent a341a3f commit b881015

File tree

8 files changed

+31
-20
lines changed

8 files changed

+31
-20
lines changed

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,14 @@ Settings here can overwrite the settings in HAProxy, which are only applied to t
251251
|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.
252252
|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.|
253253
|VIRTUAL_HOST|specify virtual host and virtual path. Format: `[scheme://]domain[:port][/path], ...`. wildcard `*` can be used in `domain` and `path` part|
254-
|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|
254+
255+
Swarm Mode only settings:
256+
257+
|Name|Type|Description|
258+
|:--:|:--:|:---------:|
259+
|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|
260+
|`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|
261+
255262

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

haproxy/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.6.1"
1+
__version__ = "1.6.2"

haproxy/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def parse_extra_frontend_settings(envvars):
3232
settings_dict[port] = settings
3333
return settings_dict
3434

35+
3536
def parse_additional_backend_settings(envvars):
3637
settings_dict = {}
3738
if isinstance(envvars, os._Environ) or isinstance(envvars, dict):
@@ -47,6 +48,7 @@ def parse_additional_backend_settings(envvars):
4748
settings_dict[server] = settings
4849
return settings_dict
4950

51+
5052
# envvar
5153
ADDITIONAL_BACKENDS = parse_additional_backend_settings(os.environ)
5254
ADDITIONAL_SERVICES = os.getenv("ADDITIONAL_SERVICES")
@@ -94,6 +96,7 @@ def parse_additional_backend_settings(envvars):
9496
API_RETRY = 10 # seconds
9597
PID_FILE = "/tmp/dockercloud-haproxy.pid"
9698
SERVICE_PORTS_ENVVAR_NAME = "SERVICE_PORTS"
99+
LABEL_SWARM_MODE_DEACTIVATE = "com.docker.dockercloud.haproxy.deactivate"
97100

98101
# regular expressions
99102
SERVICE_NAME_MATCH = re.compile(r"(.+)_\d+$")

haproxy/eventhandler.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import config
1111
import helper.cloud_mode_link_helper
12+
import helper.swarm_mode_link_helper as SwarmModeLinkHelper
1213
from haproxycfg import add_haproxy_run_task, Haproxy
1314
from utils import get_uuid_from_resource_uri
1415

@@ -106,17 +107,11 @@ def polling_service_status_swarm_mode():
106107
except:
107108
docker = docker_client(os.environ)
108109

110+
services = docker.services()
109111
tasks = docker.tasks(filters={"desired-state": "running"})
110-
linked_tasks = set()
111-
for task in tasks:
112-
task_nets = [network.get("Network", {}).get("ID", "") for network in
113-
task.get("NetworksAttachments", [])]
114-
task_service_id = task.get("ServiceID", "")
115-
if task_service_id != Haproxy.cls_service_id and Haproxy.cls_nets.intersection(set(task_nets)):
116-
task_id = task.get("ID", "")
117-
linked_tasks.add(task_id)
118-
119-
if Haproxy.cls_linked_tasks != linked_tasks:
112+
_, linked_tasks = SwarmModeLinkHelper.get_task_links(tasks, services, Haproxy.cls_service_id,
113+
Haproxy.cls_nets)
114+
if cmp(Haproxy.cls_linked_tasks, linked_tasks) != 0:
120115
add_haproxy_run_task("Tasks are updated")
121116
except APIError as e:
122117
logger.info("Docker API error: %s" % e)

haproxy/haproxycfg.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,4 +395,4 @@ def _config_adittional_backends_sections(self):
395395
for key in ADDITIONAL_BACKENDS:
396396
cfg["backend %s" % key] = ADDITIONAL_BACKENDS[key]
397397

398-
return cfg
398+
return cfg

haproxy/helper/backend_helper.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def get_backend_routes(route_setting, is_sticky, routes, routes_added, service_a
4545

4646
return sorted(backend_routes)
4747

48+
4849
def get_route_health_check(details, service_alias, default_health_check):
4950
health_check = get_service_attribute(details, "health_check", service_alias)
5051
health_check = health_check if health_check else default_health_check

haproxy/helper/swarm_mode_link_helper.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import logging
22

33
import compose_mode_link_helper
4-
from haproxy.config import SERVICE_PORTS_ENVVAR_NAME
4+
from haproxy.config import SERVICE_PORTS_ENVVAR_NAME, LABEL_SWARM_MODE_DEACTIVATE
55

66
logger = logging.getLogger("haproxy")
77

@@ -27,14 +27,14 @@ def get_swarm_mode_haproxy_id_nets(docker, haproxy_container_short_id):
2727
def get_swarm_mode_links(docker, haproxy_service_id, haproxy_nets):
2828
services = docker.services()
2929
tasks = docker.tasks(filters={"desired-state": "running"})
30-
links, linked_tasks = get_task_links(tasks, services, haproxy_service_id, haproxy_nets)
31-
return links, linked_tasks
30+
return get_task_links(tasks, services, haproxy_service_id, haproxy_nets)
3231

3332

3433
def get_task_links(tasks, services, haproxy_service_id, haproxy_nets):
3534
services_id_name = {s.get("ID"): s.get("Spec", {}).get("Name", "") for s in services}
35+
services_id_labels = {s.get("ID"): s.get("Spec", {}).get("Labels", {}) for s in services}
3636
links = {}
37-
linked_tasks = set()
37+
linked_tasks = {}
3838
for task in tasks:
3939
task_nets = [network.get("Network", {}).get("ID", "") for network in task.get("NetworksAttachments", [])]
4040
task_service_id = task.get("ServiceID", "")
@@ -44,6 +44,11 @@ def get_task_links(tasks, services, haproxy_service_id, haproxy_nets):
4444
task_slot = "%d" % task.get("Slot", 0)
4545
task_service_id = task.get("ServiceID", "")
4646
task_service_name = services_id_name.get(task_service_id, "")
47+
task_labels = services_id_labels.get(task_service_id)
48+
49+
if task_labels.get(LABEL_SWARM_MODE_DEACTIVATE, "").lower() == "true":
50+
continue
51+
4752
container_name = ".".join([task_service_name, task_slot, task_id])
4853
task_envvars = get_task_envvars(task.get("Spec", {}).get("ContainerSpec", {}).get("Env", []))
4954

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

6974
links[task_id] = {"endpoints": task_endpoints, "container_name": container_name,
7075
"service_name": task_service_name, "container_envvars": task_envvars}
71-
linked_tasks.add(task_id)
76+
linked_tasks[task_id] = task_labels
7277
return links, linked_tasks
7378

7479

tests/unit/helper/test_swarm_mode_link_helper.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,8 @@
913913
u'31b6fuwub6dcgdrvy0kivxvug': {'service_name': u'app', 'endpoints': {u'80/tcp': u'tcp://10.0.0.7:80'},
914914
'container_envvars': [{'value': u'80', 'key': u'SERVICE_PORTS'}],
915915
'container_name': u'app.3.31b6fuwub6dcgdrvy0kivxvug'}}
916-
expected_linked_tasks = {u'7y45xdhy929wzcq94wqdqb8d3', u'bbref0yvjbix87pv6xz1jc3pr', u'31b6fuwub6dcgdrvy0kivxvug'}
916+
expected_linked_tasks = {u'7y45xdhy929wzcq94wqdqb8d3':{}, u'bbref0yvjbix87pv6xz1jc3pr':{},
917+
u'31b6fuwub6dcgdrvy0kivxvug':{}}
917918
expected_nets = {"b951j4at14qali5nxevshec93", "0l130ctu8xay6vfft1mb4tjv0"}
918919
expected_service_id = "07ql4q5a48seh1uhcr2m7ngar"
919920

@@ -944,7 +945,6 @@ def services(self):
944945

945946
def tasks(self, filters):
946947
return [t for t in tasks if t.get("DesiredState", "") == "running"]
947-
948948
links, linked_tasks = get_swarm_mode_links(Docker(), expected_service_id, expected_nets)
949949
self.assertEquals(expected_links, links)
950950
self.assertEquals(expected_linked_tasks, linked_tasks)

0 commit comments

Comments
 (0)