Merge "[docker] Add support for setting CgroupnsMode"
This commit is contained in:
commit
667d145ae3
@ -27,6 +27,8 @@ import traceback
|
|||||||
|
|
||||||
import docker
|
import docker
|
||||||
|
|
||||||
|
from distutils.version import StrictVersion
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
DOCUMENTATION = '''
|
||||||
@ -149,6 +151,16 @@ options:
|
|||||||
default: None
|
default: None
|
||||||
choices:
|
choices:
|
||||||
- host
|
- host
|
||||||
|
cgroupns_mode:
|
||||||
|
description:
|
||||||
|
- Set docker cgroups namespace (default depends on Docker config)
|
||||||
|
- Supported only with Docker 20.10 (Docker API 1.41) and later
|
||||||
|
required: False
|
||||||
|
type: str
|
||||||
|
default: None
|
||||||
|
choices:
|
||||||
|
- private
|
||||||
|
- host
|
||||||
privileged:
|
privileged:
|
||||||
description:
|
description:
|
||||||
- Set the container to privileged
|
- Set the container to privileged
|
||||||
@ -275,6 +287,9 @@ class DockerWorker(object):
|
|||||||
|
|
||||||
self.dc = get_docker_client()(**options)
|
self.dc = get_docker_client()(**options)
|
||||||
|
|
||||||
|
self._cgroupns_mode_supported = (
|
||||||
|
StrictVersion(self.dc._version) >= StrictVersion('1.41'))
|
||||||
|
|
||||||
def generate_tls(self):
|
def generate_tls(self):
|
||||||
tls = {'verify': self.params.get('tls_verify')}
|
tls = {'verify': self.params.get('tls_verify')}
|
||||||
tls_cert = self.params.get('tls_cert'),
|
tls_cert = self.params.get('tls_cert'),
|
||||||
@ -347,6 +362,7 @@ class DockerWorker(object):
|
|||||||
self.compare_labels(container_info) or
|
self.compare_labels(container_info) or
|
||||||
self.compare_privileged(container_info) or
|
self.compare_privileged(container_info) or
|
||||||
self.compare_pid_mode(container_info) or
|
self.compare_pid_mode(container_info) or
|
||||||
|
self.compare_cgroupns_mode(container_info) or
|
||||||
self.compare_tmpfs(container_info) or
|
self.compare_tmpfs(container_info) or
|
||||||
self.compare_volumes(container_info) or
|
self.compare_volumes(container_info) or
|
||||||
self.compare_volumes_from(container_info) or
|
self.compare_volumes_from(container_info) or
|
||||||
@ -402,6 +418,21 @@ class DockerWorker(object):
|
|||||||
if new_pid_mode != current_pid_mode:
|
if new_pid_mode != current_pid_mode:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def compare_cgroupns_mode(self, container_info):
|
||||||
|
if not self._cgroupns_mode_supported:
|
||||||
|
return False
|
||||||
|
new_cgroupns_mode = self.params.get('cgroupns_mode')
|
||||||
|
if new_cgroupns_mode is None:
|
||||||
|
# means we don't care what it is
|
||||||
|
return False
|
||||||
|
current_cgroupns_mode = (container_info['HostConfig']
|
||||||
|
.get('CgroupnsMode'))
|
||||||
|
if current_cgroupns_mode == '':
|
||||||
|
# means the container was created on Docker pre-20.10
|
||||||
|
# it behaves like 'host'
|
||||||
|
current_cgroupns_mode = 'host'
|
||||||
|
return new_cgroupns_mode != current_cgroupns_mode
|
||||||
|
|
||||||
def compare_privileged(self, container_info):
|
def compare_privileged(self, container_info):
|
||||||
new_privileged = self.params.get('privileged')
|
new_privileged = self.params.get('privileged')
|
||||||
current_privileged = container_info['HostConfig']['Privileged']
|
current_privileged = container_info['HostConfig']['Privileged']
|
||||||
@ -760,7 +791,16 @@ class DockerWorker(object):
|
|||||||
if binds:
|
if binds:
|
||||||
options['binds'] = binds
|
options['binds'] = binds
|
||||||
|
|
||||||
return self.dc.create_host_config(**options)
|
host_config = self.dc.create_host_config(**options)
|
||||||
|
|
||||||
|
if self._cgroupns_mode_supported:
|
||||||
|
# NOTE(yoctozepto): python-docker does not support CgroupnsMode
|
||||||
|
# natively so we stuff it in manually.
|
||||||
|
cgroupns_mode = self.params.get('cgroupns_mode')
|
||||||
|
if cgroupns_mode is not None:
|
||||||
|
host_config['CgroupnsMode'] = cgroupns_mode
|
||||||
|
|
||||||
|
return host_config
|
||||||
|
|
||||||
def _inject_env_var(self, environment_info):
|
def _inject_env_var(self, environment_info):
|
||||||
newenv = {
|
newenv = {
|
||||||
@ -1074,6 +1114,8 @@ def generate_module():
|
|||||||
cap_add=dict(required=False, type='list', default=list()),
|
cap_add=dict(required=False, type='list', default=list()),
|
||||||
security_opt=dict(required=False, type='list', default=list()),
|
security_opt=dict(required=False, type='list', default=list()),
|
||||||
pid_mode=dict(required=False, type='str', choices=['host', '']),
|
pid_mode=dict(required=False, type='str', choices=['host', '']),
|
||||||
|
cgroupns_mode=dict(required=False, type='str',
|
||||||
|
choices=['private', 'host']),
|
||||||
privileged=dict(required=False, type='bool', default=False),
|
privileged=dict(required=False, type='bool', default=False),
|
||||||
graceful_timeout=dict(required=False, type='int', default=10),
|
graceful_timeout=dict(required=False, type='int', default=10),
|
||||||
remove_on_exit=dict(required=False, type='bool', default=True),
|
remove_on_exit=dict(required=False, type='bool', default=True),
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Adds support in ``kolla_docker`` module to set ``CgroupnsMode`` for Docker
|
||||||
|
containers (via ``cgroupns_mode`` module param). Requires Docker 20.10.
|
||||||
|
Note that pre-20.10 all containers behave as if they were run with mode
|
||||||
|
``host``.
|
@ -71,6 +71,8 @@ class ModuleArgsTest(base.BaseTestCase):
|
|||||||
cap_add=dict(required=False, type='list', default=list()),
|
cap_add=dict(required=False, type='list', default=list()),
|
||||||
security_opt=dict(required=False, type='list', default=list()),
|
security_opt=dict(required=False, type='list', default=list()),
|
||||||
pid_mode=dict(required=False, type='str', choices=['host', '']),
|
pid_mode=dict(required=False, type='str', choices=['host', '']),
|
||||||
|
cgroupns_mode=dict(required=False, type='str',
|
||||||
|
choices=['private', 'host']),
|
||||||
privileged=dict(required=False, type='bool', default=False),
|
privileged=dict(required=False, type='bool', default=False),
|
||||||
graceful_timeout=dict(required=False, type='int', default=10),
|
graceful_timeout=dict(required=False, type='int', default=10),
|
||||||
remove_on_exit=dict(required=False, type='bool', default=True),
|
remove_on_exit=dict(required=False, type='bool', default=True),
|
||||||
@ -204,12 +206,13 @@ FAKE_DATA = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@mock.patch("docker.APIClient")
|
def get_DockerWorker(mod_param, docker_api_version='1.40'):
|
||||||
def get_DockerWorker(mod_param, mock_dclient):
|
|
||||||
module = mock.MagicMock()
|
module = mock.MagicMock()
|
||||||
module.params = mod_param
|
module.params = mod_param
|
||||||
dw = kd.DockerWorker(module)
|
with mock.patch("docker.APIClient") as MockedDockerClientClass:
|
||||||
return dw
|
MockedDockerClientClass.return_value._version = docker_api_version
|
||||||
|
dw = kd.DockerWorker(module)
|
||||||
|
return dw
|
||||||
|
|
||||||
|
|
||||||
class TestMainModule(base.BaseTestCase):
|
class TestMainModule(base.BaseTestCase):
|
||||||
@ -248,6 +251,15 @@ class TestMainModule(base.BaseTestCase):
|
|||||||
result=False,
|
result=False,
|
||||||
some_key="some_value")
|
some_key="some_value")
|
||||||
|
|
||||||
|
def test_sets_cgroupns_mode_supported_false(self):
|
||||||
|
self.dw = get_DockerWorker(self.fake_data['params'])
|
||||||
|
self.assertFalse(self.dw._cgroupns_mode_supported)
|
||||||
|
|
||||||
|
def test_sets_cgroupns_mode_supported_true(self):
|
||||||
|
self.dw = get_DockerWorker(self.fake_data['params'],
|
||||||
|
docker_api_version='1.41')
|
||||||
|
self.assertTrue(self.dw._cgroupns_mode_supported)
|
||||||
|
|
||||||
|
|
||||||
class TestContainer(base.BaseTestCase):
|
class TestContainer(base.BaseTestCase):
|
||||||
|
|
||||||
@ -976,6 +988,40 @@ class TestAttrComp(base.BaseTestCase):
|
|||||||
self.dw = get_DockerWorker({'pid_mode': 'host2'})
|
self.dw = get_DockerWorker({'pid_mode': 'host2'})
|
||||||
self.assertTrue(self.dw.compare_pid_mode(container_info))
|
self.assertTrue(self.dw.compare_pid_mode(container_info))
|
||||||
|
|
||||||
|
def test_compare_cgroupns_mode_neg(self):
|
||||||
|
container_info = {'HostConfig': dict(CgroupnsMode='host')}
|
||||||
|
self.dw = get_DockerWorker({'cgroupns_mode': 'host'},
|
||||||
|
docker_api_version='1.41')
|
||||||
|
self.assertFalse(self.dw.compare_cgroupns_mode(container_info))
|
||||||
|
|
||||||
|
def test_compare_cgroupns_mode_neg_backward_compat(self):
|
||||||
|
container_info = {'HostConfig': dict(CgroupnsMode='')}
|
||||||
|
self.dw = get_DockerWorker({'cgroupns_mode': 'host'},
|
||||||
|
docker_api_version='1.41')
|
||||||
|
self.assertFalse(self.dw.compare_cgroupns_mode(container_info))
|
||||||
|
|
||||||
|
def test_compare_cgroupns_mode_ignore(self):
|
||||||
|
container_info = {'HostConfig': dict(CgroupnsMode='private')}
|
||||||
|
self.dw = get_DockerWorker({}, docker_api_version='1.41')
|
||||||
|
self.assertFalse(self.dw.compare_cgroupns_mode(container_info))
|
||||||
|
|
||||||
|
def test_compare_cgroupns_mode_pos(self):
|
||||||
|
container_info = {'HostConfig': dict(CgroupnsMode='private')}
|
||||||
|
self.dw = get_DockerWorker({'cgroupns_mode': 'host'},
|
||||||
|
docker_api_version='1.41')
|
||||||
|
self.assertTrue(self.dw.compare_cgroupns_mode(container_info))
|
||||||
|
|
||||||
|
def test_compare_cgroupns_mode_pos_backward_compat(self):
|
||||||
|
container_info = {'HostConfig': dict(CgroupnsMode='')}
|
||||||
|
self.dw = get_DockerWorker({'cgroupns_mode': 'private'},
|
||||||
|
docker_api_version='1.41')
|
||||||
|
self.assertTrue(self.dw.compare_cgroupns_mode(container_info))
|
||||||
|
|
||||||
|
def test_compare_cgroupns_mode_unsupported(self):
|
||||||
|
container_info = {'HostConfig': dict()}
|
||||||
|
self.dw = get_DockerWorker({'cgroupns_mode': 'host'})
|
||||||
|
self.assertFalse(self.dw.compare_cgroupns_mode(container_info))
|
||||||
|
|
||||||
def test_compare_privileged_neg(self):
|
def test_compare_privileged_neg(self):
|
||||||
container_info = {'HostConfig': dict(Privileged=True)}
|
container_info = {'HostConfig': dict(Privileged=True)}
|
||||||
self.dw = get_DockerWorker({'privileged': True})
|
self.dw = get_DockerWorker({'privileged': True})
|
||||||
|
Loading…
Reference in New Issue
Block a user