Support for docker swarm mode
diff --git a/Makefile b/Makefile
index fc83783..e4c5a0e 100644
--- a/Makefile
+++ b/Makefile
@@ -14,6 +14,7 @@
cp -a $(FORMULANAME) $(DESTDIR)/$(SALTENVDIR)/
[ ! -d _modules ] || cp -a _modules $(DESTDIR)/$(SALTENVDIR)/
[ ! -d _states ] || cp -a _states $(DESTDIR)/$(SALTENVDIR)/ || true
+ [ ! -d _grains ] || cp -a _grains $(DESTDIR)/$(SALTENVDIR)/ || true
# Metadata
[ -d $(DESTDIR)/$(RECLASSDIR)/service/$(FORMULANAME) ] || mkdir -p $(DESTDIR)/$(RECLASSDIR)/service/$(FORMULANAME)
cp -a metadata/service/* $(DESTDIR)/$(RECLASSDIR)/service/$(FORMULANAME)
diff --git a/README.rst b/README.rst
index 4a51162..7884960 100644
--- a/README.rst
+++ b/README.rst
@@ -26,6 +26,43 @@
insecure_registries:
- 127.0.0.1
+Swarm
+-----
+
+Role can be master, manager or worker. Where master is the first manager that
+will initialize the swarm.
+
+Metadata for manager (first node):
+
+.. code-block:: yaml
+
+ docker:
+ host:
+ enabled: true
+ swarm:
+ role: manager
+ advertise_addr: 192.168.1.5
+ bind:
+ address: 192.168.1.5
+ port: 2377
+
+Metadata for worker:
+
+.. code-block:: yaml
+
+ docker:
+ host:
+ enabled: true
+ swarm:
+ role: worker
+ master:
+ host: 192.168.1.5
+ port: 2377
+
+Token to join to master node is obtained from grains using salt.mine. In case
+of any ``join_token undefined`` issues, ensure you have ``docker_swarm_``
+grains available.
+
Client
------
diff --git a/_grains/docker_swarm.py b/_grains/docker_swarm.py
new file mode 100644
index 0000000..8b8ecb7
--- /dev/null
+++ b/_grains/docker_swarm.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+import os
+import yaml
+import subprocess
+
+
+def main():
+ output = {}
+ if os.path.exists('/var/lib/docker/swarm/control.sock'):
+ try:
+ output["docker_swarm_tokens"] = {
+ 'worker': subprocess.check_output(["docker", "swarm", "join-token", "-q", "worker"]).strip(),
+ 'manager': subprocess.check_output(["docker", "swarm", "join-token", "-q", "manager"]).strip()
+ }
+ except subprocess.CalledProcessError:
+ pass
+
+ if os.path.exists('/var/lib/docker/swarm/state.json'):
+ with open('/var/lib/docker/swarm/state.json') as fh:
+ state = yaml.load(fh)
+ for key, value in state[0].iteritems():
+ output["docker_swarm_%s" % key] = value
+
+ if os.path.exists('/var/lib/docker/swarm/docker-state.json'):
+ with open('/var/lib/docker/swarm/docker-state.json') as fh:
+ state = yaml.load(fh)
+ for key, value in state.iteritems():
+ output["docker_swarm_%s" % key] = value
+
+ if output:
+ return output
+ else:
+ return None
diff --git a/docker/init.sls b/docker/init.sls
index 6256940..ac6eeca 100644
--- a/docker/init.sls
+++ b/docker/init.sls
@@ -3,6 +3,9 @@
{%- if pillar.docker.host is defined %}
- docker.host
{%- endif %}
+{%- if pillar.docker.swarm is defined %}
+- docker.swarm
+{%- endif %}
{%- if pillar.docker.client is defined %}
- docker.client
{%- endif %}
diff --git a/docker/map.jinja b/docker/map.jinja
index d475371..8644de5 100644
--- a/docker/map.jinja
+++ b/docker/map.jinja
@@ -18,6 +18,14 @@
},
}, grain='os', merge=salt['pillar.get']('docker:host')) %}
+{% set swarm = salt['grains.filter_by']({
+ 'default': {
+ 'master': {
+ 'port': 2377
+ }
+ }
+}, grain='os', merge=salt['pillar.get']('docker:swarm')) %}
+
{% set client = salt['grains.filter_by']({
'default': {
'pkgs': ['python-docker'],
diff --git a/docker/swarm.sls b/docker/swarm.sls
new file mode 100644
index 0000000..314c183
--- /dev/null
+++ b/docker/swarm.sls
@@ -0,0 +1,48 @@
+{% from "docker/map.jinja" import swarm with context %}
+{%- if swarm.enabled|default(True) %}
+
+include:
+ - docker.host
+
+{%- if swarm.role == 'master' %}
+
+docker_swarm_init:
+ cmd.run:
+ - name: >
+ docker swarm init
+ {%- if swarm.advertise_addr is defined %} --advertise-addr {{ swarm.advertise_addr }}{%- endif %}
+ {%- if swarm.get('bind', {}).get('address', None) %} --listen-addr {{ swarm.bind.address }}{% if swarm.bind.port is defined %}:{{ swarm.bind.port }}{% endif %}{%- endif %}
+ - unless: "test -e /var/lib/docker/swarm/control.sock"
+ - require:
+ - service: docker_service
+
+docker_swarm_grains_publish:
+ module.run:
+ - name: mine.update
+ - watch:
+ - cmd: docker_swarm_init
+
+{%- else %}
+
+{%- for node_name, node_grains in salt['mine.get']('*', 'grains.items').iteritems() %}
+{%- if node_grains.get("docker_swarm_AdvertiseAddr", None) == swarm.master.host+":"+swarm.master.port|string %}
+{%- set join_token = node_grains.get('docker_swarm_tokens').get(swarm.role, "unknown") %}
+
+docker_swarm_join:
+ cmd.run:
+ - name: >
+ docker swarm join
+ --token {{ join_token }}
+ {%- if swarm.advertise_addr is defined %} --advertise-addr {{ swarm.advertise_addr }}{%- endif %}
+ {%- if swarm.get('bind', {}).get('address', None) %} --listen-addr {{ swarm.bind.address }}{% if swarm.bind.port is defined %}:{{ swarm.bind.port }}{% endif %}{%- endif %}
+ {{ swarm.master.host }}:{{ swarm.master.port }}
+ - unless: "test -e /var/lib/docker/swarm/control.sock"
+ - require:
+ - service: docker_service
+
+{%- endif %}
+{%- endfor %}
+
+{%- endif %}
+
+{%- endif %}