Add support of docker secrets

Related-Prod: PROD-35521
Related-Prod: PROD-34268
Change-Id: I45913ca9bbe84874e5d472094fbdfc8784fa39ea
diff --git a/README.rst b/README.rst
index f7a6313..de069f9 100644
--- a/README.rst
+++ b/README.rst
@@ -224,6 +224,40 @@
                   source: /srv/volumes/postgresql/maas
                   destination: /var/lib/postgresql/data
 
+Docker Service configuration samples with docker secrets
+========================================================
+
+To deploy service in Swarm mode using docker secrets, you can use
+``docker.client.service``:
+
+.. code-block:: yaml
+
+    parameters:
+      docker:
+        client:
+          service:
+            postgresql:
+              environment:
+                POSTGRES_USER: user
+                POSTGRES_PASSWORD_FILE: '/run/secrets/postgres'
+                POSTGRES_DB: mydb
+              secrets:
+                - postgres
+              restart:
+                condition: on-failure
+              image: "postgres:9.5"
+              ports:
+                - 5432:5432
+              volume:
+                data:
+                  type: bind
+                  source: /srv/volumes/postgresql/maas
+                  destination: /var/lib/postgresql/data
+          secrets:
+            postgres:
+              external: true
+              value: password
+
 Docker Registry configuration samples
 =====================================
 
diff --git a/docker/client/stack.sls b/docker/client/stack.sls
index ce649c6..b72507b 100644
--- a/docker/client/stack.sls
+++ b/docker/client/stack.sls
@@ -5,6 +5,37 @@
 
 {%- for app, compose in client.stack.iteritems() %}
   {%- if compose.service is defined %}
+    {%- if compose.secrets is defined %}
+      {%- for secret, values in compose.secrets.iteritems() %}
+        {%- if values['external'] is defined and values['external'] == true %}
+docker_secret_{{ secret }}:
+  cmd.run:
+    - name: >
+        retry=5
+        i=1;
+        while [[ $i -lt $retry ]]; do
+          echo "{{ values['value'] }}" | docker secret create {{ secret }} -;
+          ret=$?;
+          if [[ $ret -eq 0 ]]; then echo 'Secret created'; break;
+          else
+            echo "Secret creation failed, retrying in 3 seconds.." >&2;
+            sleep 3;
+            i=$(( i + 1 ));
+          fi;
+          if [[ $i -ge $retry ]]; then
+            echo "Secret creation failed!"; exit 1;
+          fi;
+        done;
+    - shell: /bin/bash
+    - user: {{ compose.user|default("root") }}
+    - unless: "docker secret inspect {{ secret }}"
+    - output_loglevel: quiet
+    - require_in:
+      - cmd: docker_stack_{{ app }}
+      - cmd: docker_stack_{{ app }}_update
+        {%- endif %}
+      {%- endfor %}
+    {%- endif %}
 
 docker_{{ app }}_dir:
   file.directory:
@@ -22,6 +53,7 @@
         volume: {{ compose.volume|default({}) }}
         service: {{ compose.service }}
         network: {{ compose.network|default({}) }}
+        secrets: {{ compose.secrets|default({}) }}
     - require:
         - file: docker_{{ app }}_dir
 
diff --git a/docker/files/docker-compose.yml b/docker/files/docker-compose.yml
index 1228fa1..ac3de28 100644
--- a/docker/files/docker-compose.yml
+++ b/docker/files/docker-compose.yml
@@ -43,6 +43,22 @@
   {%- endfor %}
 {%- endif %}
 
+{%- if secrets|default({}) %}
+secrets:
+  {%- for key, value in secrets.iteritems() %}
+    {%- if value is mapping %}
+  {{ key }}:
+    {%- for key, value in value.iteritems() %}
+      {%- if key != 'value' %}
+    {{ key }}:
+      {{ value|yaml(False)|indent(6) }}
+      {%- endif %}
+    {%- endfor %}
+    {%- else %}
+  {{ key }}:
+    {%- endif %}
+  {%- endfor %}
+{%- endif %}
 
 {%- if network|default({}) %}
 networks: