Merge "Optimize kitchen tests for Travis CI"
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/docker/client/init.sls b/docker/client/init.sls
index 8e0ca58..f628ddc 100644
--- a/docker/client/init.sls
+++ b/docker/client/init.sls
@@ -2,20 +2,22 @@
{%- if client.get('enabled') %}
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 3a6d1d4..60b3cca 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..0bde54c
--- /dev/null
+++ b/docker/meta/fluentd.yml
@@ -0,0 +1,42 @@
+{%- 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
+ record:
+ - name: severity_label
+ value: INFO
+ - name: Severity
+ value: 6
+ - name: programname
+ value: docker
+ 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/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} $*
}