Merge "Adding default False values instead of empty ones"
diff --git a/.kitchen.travis.yml b/.kitchen.travis.yml
deleted file mode 100644
index f847543..0000000
--- a/.kitchen.travis.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-suites:
-
- - name: <%= ENV['SUITE'] %>
- provisioner:
- pillars-from-files:
- neutron.sls: tests/pillar/<%= ENV['SUITE'] %>.sls
diff --git a/.travis.yml b/.travis.yml
index fa7c5f9..64743ee 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,15 +17,16 @@
- bundle install
env:
- - PLATFORM=trevorj/salty-whales:xenial SUITE=client_compose
- - PLATFORM=trevorj/salty-whales:xenial SUITE=client_container
- - PLATFORM=trevorj/salty-whales:xenial SUITE=host_single
+ - PLATFORM=trevorj/salty-whales:xenial SUITE=client-compose
+ - PLATFORM=trevorj/salty-whales:xenial SUITE=client-container
+ - PLATFORM=trevorj/salty-whales:xenial SUITE=host-single
before_script:
- make test | tail
script:
- - KITCHEN_LOCAL_YAML=.kitchen.travis.yml bundle exec kitchen test -t tests/integration
+ - test ! -e .kitchen.yml || bundle exec kitchen converge ${SUITE} || true
+ - test ! -e .kitchen.yml || bundle exec kitchen verify ${SUITE} -t tests/integration
notifications:
webhooks:
diff --git a/README.rst b/README.rst
index 81cb038..4cbdb11 100644
--- a/README.rst
+++ b/README.rst
@@ -279,6 +279,65 @@
password: password2
+Docker container service management
+-----------------------------------
+
+Enforce the service in container is started
+
+.. code-block:: yaml
+
+ contrail_control_started:
+ dockerng_service.start:
+ - container: f020d0d3efa8
+ - service: contrail-control
+
+or
+
+.. code-block:: yaml
+
+ contrail_control_started:
+ dockerng_service.start:
+ - container: contrail_controller
+ - service: contrail-control
+
+
+Enforce the service in container is stoped
+
+.. code-block:: yaml
+
+ contrail_control_stoped:
+ dockerng_service.stop:
+ - container: f020d0d3efa8
+ - service: contrail-control
+
+Enforce the service in container will be restarted
+
+.. code-block:: yaml
+
+ contrail_control_restart:
+ dockerng_service.restart:
+ - container: f020d0d3efa8
+ - service: contrail-control
+
+Enforce the service in container is enabled
+
+.. code-block:: yaml
+
+ contrail_control_enable:
+ dockerng_service.enable:
+ - container: f020d0d3efa8
+ - service: contrail-control
+
+Enforce the service in container is disabled
+
+.. code-block:: yaml
+
+ contrail_control_disable:
+ dockerng_service.disable:
+ - container: f020d0d3efa8
+ - service: contrail-control
+
+
More Information
================
diff --git a/_modules/dockerng_service.py b/_modules/dockerng_service.py
new file mode 100644
index 0000000..081b7e0
--- /dev/null
+++ b/_modules/dockerng_service.py
@@ -0,0 +1,99 @@
+#!/usr/bin/python
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+try:
+ import docker
+ HAS_DOCKER = True
+except ImportError:
+ HAS_DOCKER = False
+
+__opts__ = {}
+__virtualname__ = 'dockerng_service'
+
+
+def __virtual__():
+ '''
+ Only load this module if docker library is installed.
+ '''
+ if HAS_DOCKER:
+ return __virtualname__
+ return (False, 'dockerio execution module not loaded: docker python library not available.')
+
+
+def status(container, service):
+ cmd = "systemctl show " + service + " -p ActiveState,SubState,UnitFileState"
+ data = __salt__['dockerng.run'](container, cmd)
+ data = data.splitlines()
+ result = dict(s.split('=') for s in data)
+ return result
+
+
+def status_retcode(container, service):
+ cmd = "systemctl show " + service + " -p ActiveState,SubState,UnitFileState"
+ data = __salt__['dockerng.run'](container, cmd)
+ data = data.splitlines()
+ result = dict(s.split('=') for s in data)
+ if result['ActiveState'] == "active" and result['SubState'] == "running":
+ return True
+ return False
+
+
+def restart(container, service):
+ cmd = "systemctl restart " + service
+ data = __salt__['dockerng.run'](container, cmd)
+ if len(data) > 0:
+ return False
+ return True
+
+
+def stop(container, service):
+ cmd = "systemctl stop " + service
+ data = __salt__['dockerng.run'](container, cmd)
+ if len(data) > 0:
+ return False
+ return True
+
+
+def start(container, service):
+ cmd = "systemctl start " + service
+ data = __salt__['dockerng.run'](container, cmd)
+ if len(data) > 0:
+ return False
+ return True
+
+
+def enable(container, service):
+ cmd = "systemctl enable " + service
+ data = __salt__['dockerng.run'](container, cmd)
+ if len(data) > 0:
+ return False
+ return True
+
+
+def reload(container, service):
+ cmd = "systemctl reload " + service
+ data = __salt__['dockerng.run'](container, cmd)
+ if len(data) > 0:
+ return False
+ return True
+
+
+def disable(container, service):
+ cmd = "systemctl disable " + service
+ data = __salt__['dockerng.run'](container, cmd)
+ if len(data) > 0:
+ return False
+ return True
diff --git a/_states/dockerng_service.py b/_states/dockerng_service.py
new file mode 100644
index 0000000..ed13798
--- /dev/null
+++ b/_states/dockerng_service.py
@@ -0,0 +1,297 @@
+#!/usr/bin/python
+# Copyright 2017 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+'''
+Management of Contrail resources
+================================
+
+:depends: - vnc_api Python module
+
+
+Enforce the service in container is running
+-------------------------------------------
+
+.. code-block:: yaml
+
+ contrail_control_running:
+ dockerng_service.running:
+ - container: f020d0d3efa8
+ - service: contrail-control
+
+or
+
+.. code-block:: yaml
+
+ contrail_control_running:
+ dockerng_service.running:
+ - container: contrail_controller
+ - service: contrail-control
+
+
+Enforce the service in container is dead
+------------------------------------------
+
+.. code-block:: yaml
+
+ contrail_control_dead:
+ dockerng_service.dead:
+ - container: f020d0d3efa8
+ - service: contrail-control
+
+Enforce the service in container will be restarted
+--------------------------------------------------
+
+.. code-block:: yaml
+
+ contrail_control_restarted:
+ dockerng_service.restarted:
+ - container: f020d0d3efa8
+ - service: contrail-control
+
+Enforce the service in container is enabled
+-------------------------------------------
+
+.. code-block:: yaml
+
+ contrail_control_enabled:
+ dockerng_service.enabled:
+ - container: f020d0d3efa8
+ - service: contrail-control
+
+Enforce the service in container is disabled
+--------------------------------------------
+
+.. code-block:: yaml
+
+ contrail_control_disabled:
+ dockerng_service.disabled:
+ - container: f020d0d3efa8
+ - service: contrail-control
+
+'''
+
+
+def __virtual__():
+ '''
+ Load Contrail module
+ '''
+ return 'dockerng_service'
+
+
+def running(container, service=None, services=None, **kwargs):
+ '''
+ Ensures that the service in the container is running
+
+ :param container: ID or name of the container
+ :param services: List of services
+ :param service: Service name
+ '''
+ ret = {'name': kwargs.get('name', 'dockerng_service.running'),
+ 'changes': {},
+ 'result': True,
+ 'comment': {}
+ }
+
+ if service and not services:
+ services = [service, ]
+
+ for service in services:
+ status = __salt__['dockerng_service.status'](container, service)
+
+ if status['ActiveState'] != "active" and status['SubState'] != "running":
+ if __opts__['test']:
+ ret['result'] = None
+ ret['comment'][service] = " will be started"
+ else:
+ __salt__['dockerng_service.start'](container, service)
+ ret['comment'] = service + " in " + container + " has been started"
+ ret['changes'] = {service: "started"}
+
+ return ret
+
+
+def dead(container, service, **kwargs):
+ '''
+ Ensures that the service in the container is dead
+
+ :param container: ID or name of the container
+ :param service: Service name
+ '''
+ ret = {'name': service + " in " + container,
+ 'changes': {},
+ 'result': True,
+ 'comment': ''}
+
+ status = __salt__['dockerng_service.status'](container, service)
+
+ if status['ActiveState'] != "inactive" and status['SubState'] != "dead":
+ if __opts__['test']:
+ ret['result'] = None
+ ret['comment'] = service + " in " + container + " will be stoped"
+ return ret
+
+ __salt__['dockerng_service.stop'](container, service)
+ ret['comment'] = service + " in " + container + " has been stoped"
+ ret['changes'] = {"new": "stoped", "old": "started"}
+ return ret
+
+ return ret
+
+
+def restarted(container, service, **kwargs):
+ '''
+ Service in the container will be restarted
+
+ :param container: ID or name of the container
+ :param service: Service name
+ '''
+ ret = {'name': service + " in " + container,
+ 'changes': {},
+ 'result': True,
+ 'comment': ''}
+
+ if __opts__['test']:
+ ret['result'] = None
+ ret['comment'] = service + " in " + container + " will be restarted"
+ return ret
+
+ res = __salt__['dockerng_service.restart'](container, service)
+ ret['comment'] = service + " in " + container + " has been restarted"
+ ret['changes'] = {"status": "restarted"}
+ return ret
+
+
+def enabled(container, service, **kwargs):
+ '''
+ Ensures that the service in the container is enabled
+
+ :param container: ID or name of the container
+ :param service: Service name
+ '''
+ ret = {'name': service + " in " + container,
+ 'changes': {},
+ 'result': True,
+ 'comment': ''}
+
+ status = __salt__['dockerng_service.status'](container, service)
+
+ if status['UnitFileState'] != "enabled":
+ if __opts__['test']:
+ ret['result'] = None
+ ret['comment'] = service + " in " + container + " will be enabled"
+ return ret
+
+ __salt__['dockerng_service.enable'](container, service)
+ ret['comment'] = service + " in " + container + " has been enabled"
+ ret['changes'] = {"new": "enabled", "old": "disabled"}
+ return ret
+
+ return ret
+
+
+def disabled(container, service, **kwargs):
+ '''
+ Ensures that the service in the container is disabled
+
+ :param container: ID or name of the container
+ :param service: Service name
+ '''
+ ret = {'name': service + " in " + container,
+ 'changes': {},
+ 'result': True,
+ 'comment': ''}
+
+ status = __salt__['dockerng_service.status'](container, service)
+
+ if status['UnitFileState'] != "disabled":
+ if __opts__['test']:
+ ret['result'] = None
+ ret['comment'] = service + " in " + container + " will be disabled"
+ return ret
+
+ __salt__['dockerng_service.disable'](container, service)
+ ret['comment'] = service + " in " + container + " has been disabled"
+ ret['changes'] = {"old": "enabled", "new": "disabled"}
+ return ret
+
+ return ret
+
+
+def mod_watch(name,
+ contrainer=None,
+ sfun=None,
+ sig=None,
+ reload=False,
+ full_restart=False,
+ init_delay=None,
+ force=False,
+ **kwargs):
+ '''
+ The service watcher, called to invoke the watch command.
+
+ :param name: The name of the init or rc script used to manage the
+ service
+ :param sfun: The original function which triggered the mod_watch
+ call (`service.running`, for example).
+ :param sig: The string to search for when looking for the service
+ process with ps
+ :param reload: Use reload instead of the default restart (exclusive
+ option with full_restart, defaults to reload if both
+ are used)
+ :param full_restart: Use service.full_restart instead of restart
+ (exclusive option with reload)
+ :param force: Use service.force_reload instead of reload
+ (needs reload to be set to True)
+ :param init_delay: Add a sleep command (in seconds) before the service is
+ restarted/reloaded
+ '''
+ ret = {'name': name,
+ 'changes': {},
+ 'result': True,
+ 'comment': {}}
+
+ service = kwargs.get('service')
+ services = kwargs.get('services')
+ if not services and service:
+ services = [service, ]
+ elif not services and not service:
+ ret['result'] = False
+ ret['comment'] = "Service was not defined"
+ return ret
+
+ container = kwargs.get('container', None)
+ if not container:
+ ret['result'] = False
+ ret['comment'] = "Container was not defined"
+ return ret
+
+ ret['comment'] = {}
+ if sfun == 'running':
+
+ for service in services:
+ status = __salt__['dockerng_service.status'](container, service)
+
+
+ if __opts__['test']:
+ ret['result'] = None
+ ret['comment'][service] = "Services will be restarted"
+ ret['changes'][service] = "will be restarted"
+ else:
+ res = __salt__['dockerng_service.restart'](container, service)
+ ret['comment'] = "Services has been restarted"
+ ret['changes'][service] = "restarted"
+ else:
+ ret['comment'] = 'Unable to trigger watch for dockerng_service.{0}'.format(sfun)
+ ret['result'] = False
+ return ret
diff --git a/debian/control b/debian/control
index ca1f1d1..d6faf77 100644
--- a/debian/control
+++ b/debian/control
@@ -10,6 +10,6 @@
Package: salt-formula-docker
Architecture: all
-Depends: ${misc:Depends}, salt-master, reclass
+Depends: ${misc:Depends}
Description: docker salt formula
Install and configure docker system.
diff --git a/docker/client/init.sls b/docker/client/init.sls
index 6ad6ba0..d80dc11 100644
--- a/docker/client/init.sls
+++ b/docker/client/init.sls
@@ -2,20 +2,22 @@
{%- if client.get('enabled', False) %}
include:
- {%- if client.network is defined %}
+ {%- if pillar.docker.client.network is defined %}
- docker.client.network
{%- endif %}
+ {%- if pillar.docker.client.container is defined %}
- docker.client.container
- {%- if client.compose is defined %}
+ {%- endif %}
+ {%- if pillar.docker.client.compose is defined %}
- docker.client.compose
{%- endif %}
- {%- if client.stack is defined %}
+ {%- if pillar.docker.client.stack is defined %}
- docker.client.stack
{%- endif %}
- {%- if client.registry is defined %}
+ {%- if pillar.docker.client.registry is defined %}
- docker.client.registry
{%- endif %}
- {%- if client.service is defined %}
+ {%- if pillar.docker.client.service is defined %}
- docker.client.service
{%- endif %}
diff --git a/docker/host.sls b/docker/host.sls
index 816b0c4..da8291e 100644
--- a/docker/host.sls
+++ b/docker/host.sls
@@ -81,10 +81,11 @@
{%- for name,registry in host.registry.iteritems() %}
-docker_{{ registry.address }}_login:
+docker_{{ registry.get('address', name) }}_login:
cmd.run:
- - name: 'docker login -u {{ registry.user }} -p {{ registry.password }} {{ registry.address }}'
- - unless: grep {{ registry.address }} /root/.docker/config.json
+ - name: 'docker login -u {{ registry.user }} -p {{ registry.password }}{% if registry.get('address') %} {{ registry.address }}{% endif %}'
+ - user: {{ registry.get('system_user', 'root') }}
+ - unless: grep {{ registry.address|default('https://index.docker.io/v1/') }} {{ salt['user.info'](registry.get('system_user', 'root')).home }}/.docker/config.json
{%- endfor %}
diff --git a/docker/meta/fluentd.yml b/docker/meta/fluentd.yml
new file mode 100644
index 0000000..5e41d2a
--- /dev/null
+++ b/docker/meta/fluentd.yml
@@ -0,0 +1,45 @@
+{%- if pillar.get('fluentd', {}).get('agent', {}).get('enabled', False) %}
+{%- set positiondb = pillar.fluentd.agent.dir.positiondb %}
+agent:
+ config:
+ label:
+ docker:
+ input:
+ container:
+ type: tail
+ tag: temp.docker.container.*
+ path: /var/lib/docker/containers/*/*-json.log
+ path_key: log_path
+ pos_file: {{ positiondb }}/docker.container.pos
+ parser:
+ type: json
+ time_format: '%Y-%m-%dT%H:%M:%S.%NZ'
+ keep_time_key: false
+ filter:
+ enrich:
+ tag: 'temp.docker.container.**'
+ type: record_transformer
+ enable_ruby: true
+ remove_keys: log
+ record:
+ - name: severity_label
+ value: INFO
+ - name: Severity
+ value: 6
+ - name: programname
+ value: docker
+ - name: Payload
+ value: ${record['log']}
+ match:
+ cast_service_tag:
+ tag: 'temp.docker.container.**'
+ type: rewrite_tag_filter
+ rule:
+ - name: log_path
+ regexp: '^.*\/(.*)-json\.log$'
+ result: docker.container.$1
+ push_to_default:
+ tag: 'docker.container.*'
+ type: relabel
+ label: default_output
+{%- endif %}
diff --git a/docker/meta/prometheus.yml b/docker/meta/prometheus.yml
index 2d4d7bb..1764543 100644
--- a/docker/meta/prometheus.yml
+++ b/docker/meta/prometheus.yml
@@ -26,31 +26,34 @@
DockerService{{ camel_case_name }}WarningReplicasNumber:
if: >-
count(count_over_time(docker_container_cpu_usage_percent{{ '{' + label_selector + '}' }}[1m])) <= {{ service.deploy.replicas }} * {{ 1 - monitoring.replicas_failed_warning_threshold_percent }}
+ for: 2m
labels:
severity: warning
service: "{{ full_service_name }}"
annotations:
- summary: 'Docker Swarm service {{ full_service_name }} invalid number of replicas'
- description: "{%raw %}{{ $value }}{%- endraw %}/{{ service.deploy.replicas }} replicas are running for the Docker Swarn service '{{ full_service_name }}'."
+ summary: 'Docker Swarm service {{ full_service_name }} invalid number of replicas for 2 minutes'
+ description: "{%raw %}{{ $value }}{%- endraw %}/{{ service.deploy.replicas }} replicas are running for the Docker Swarn service '{{ full_service_name }}' for 2 minutes."
DockerService{{ camel_case_name }}CriticalReplicasNumber:
if: >-
count(count_over_time(docker_container_cpu_usage_percent{{ '{' + label_selector + '}' }}[1m])) <= {{ service.deploy.replicas }} * {{ 1 - monitoring.replicas_failed_critical_threshold_percent }}
+ for: 2m
labels:
severity: critical
service: "{{ full_service_name }}"
annotations:
- summary: 'Docker Swarm service {{ full_service_name }} invalid number of replicas'
- description: "{%raw %}{{ $value }}{%- endraw %}/{{ service.deploy.replicas }} replicas are running for the Docker Swarn service '{{ full_service_name }}'."
+ summary: 'Docker Swarm service {{ full_service_name }} invalid number of replicas for 2 minutes'
+ description: "{%raw %}{{ $value }}{%- endraw %}/{{ service.deploy.replicas }} replicas are running for the Docker Swarn service '{{ full_service_name }}' for 2 minutes."
{%- endif %}
DockerService{{ camel_case_name }}ReplicasDown:
if: >-
count(count_over_time(docker_container_cpu_usage_percent{{ '{' + label_selector + '}' }}[1m])) == 0 or absent(docker_container_cpu_usage_percent{{ '{' + label_selector + '}' }}) == 1
+ for: 2m
labels:
severity: down
service: "{{ full_service_name }}"
annotations:
- summary: 'Docker Swarm service {{ full_service_name }} down'
- description: "No replicas are running for the Docker Swarn service '{{ full_service_name }}'."
+ summary: 'Docker Swarm service {{ full_service_name }} down for 2 minutes'
+ description: "No replicas are running for the Docker Swarn service '{{ full_service_name }}'. for 2 minutes"
{%- endif %}
{%- endfor %}
{%- endfor %}
diff --git a/docker/meta/sphinx.yml b/docker/meta/sphinx.yml
index 203eb0c..a12c200 100644
--- a/docker/meta/sphinx.yml
+++ b/docker/meta/sphinx.yml
@@ -41,4 +41,13 @@
- "{{ name }} (image {{ service.image }})"
{%- endfor %}
{%- endif %}
+ {%- if client.get('stack', {}) %}
+ stacks:
+ value:
+ {%- for name, stack in client.stack.iteritems() %}
+ {%- for svc_name, service in stack.service.iteritems() %}
+ - "{{ name }}-{{ svc_name }} (image {{ service.image }})"
+ {%- endfor %}
+ {%- endfor %}
+ {%- endif %}
{%- endif %}
diff --git a/metadata/service/support.yml b/metadata/service/support.yml
index a1c25d8..2127589 100644
--- a/metadata/service/support.yml
+++ b/metadata/service/support.yml
@@ -1,6 +1,8 @@
parameters:
docker:
_support:
+ fluentd:
+ enabled: true
telegraf:
enabled: true
collectd:
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 3f42101..9451611 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -110,7 +110,7 @@
}
salt_run() {
- [ -e ${VEN_DIR}/bin/activate ] && source ${VENV_DIR}/bin/activate
+ [ -e ${VENV_DIR}/bin/activate ] && source ${VENV_DIR}/bin/activate
salt-call ${SALT_OPTS} $*
}