Docker plugin add restart policies and capability properties

Add restart_policy, cap_add and cap_drop properties for stability and security.

Closes-bug: #1430197

Change-Id: Iec184fdf5c765217ff7058e8b1390b2f73c59b40
This commit is contained in:
LiangChen 2015-03-11 12:01:23 +08:00
parent 8687997d65
commit 7dfc576736
2 changed files with 151 additions and 1 deletions

View File

@ -20,6 +20,7 @@ import six
from heat.common.i18n import _
from heat.common.i18n import _LW
from heat.engine import attributes
from heat.engine import constraints
from heat.engine import properties
from heat.engine import resource
@ -41,10 +42,12 @@ class DockerContainer(resource.Resource):
DOCKER_ENDPOINT, HOSTNAME, USER, MEMORY, PORT_SPECS,
PRIVILEGED, TTY, OPEN_STDIN, STDIN_ONCE, ENV, CMD, DNS,
IMAGE, VOLUMES, VOLUMES_FROM, PORT_BINDINGS, LINKS, NAME,
RESTART_POLICY, CAP_ADD, CAP_DROP,
) = (
'docker_endpoint', 'hostname', 'user', 'memory', 'port_specs',
'privileged', 'tty', 'open_stdin', 'stdin_once', 'env', 'cmd', 'dns',
'image', 'volumes', 'volumes_from', 'port_bindings', 'links', 'name'
'image', 'volumes', 'volumes_from', 'port_bindings', 'links', 'name',
'restart_policy', 'cap_add', 'cap_drop'
)
ATTRIBUTES = (
@ -57,6 +60,23 @@ class DockerContainer(resource.Resource):
'logs_tail',
)
_RESTART_POLICY_KEYS = (
POLICY_NAME, POLICY_MAXIMUM_RETRY_COUNT,
) = (
'Name', 'MaximumRetryCount',
)
_CAPABILITIES = ['SETPCAP', 'SYS_MODULE', 'SYS_RAWIO', 'SYS_PACCT',
'SYS_ADMIN', 'SYS_NICE', 'SYS_RESOURCE', 'SYS_TIME',
'SYS_TTY_CONFIG', 'MKNOD', 'AUDIT_WRITE',
'AUDIT_CONTROL', 'MAC_OVERRIDE', 'MAC_ADMIN',
'NET_ADMIN', 'SYSLOG', 'CHOWN', 'NET_RAW',
'DAC_OVERRIDE', 'FOWNER', 'DAC_READ_SEARCH', 'FSETID',
'KILL', 'SETGID', 'SETUID', 'LINUX_IMMUTABLE',
'NET_BIND_SERVICE', 'NET_BROADCAST', 'IPC_LOCK',
'IPC_OWNER', 'SYS_CHROOT', 'SYS_PTRACE', 'SYS_BOOT',
'LEASE', 'SETFCAP', 'WAKE_ALARM', 'BLOCK_SUSPEND', 'ALL']
properties_schema = {
DOCKER_ENDPOINT: properties.Schema(
properties.Schema.STRING,
@ -143,6 +163,54 @@ class DockerContainer(resource.Resource):
_('Mount all specified volumes.'),
default=''
),
RESTART_POLICY: properties.Schema(
properties.Schema.MAP,
_('Restart policies (only supported for API version >= 1.2.0).'),
schema={
POLICY_NAME: properties.Schema(
properties.Schema.STRING,
_('The behavior to apply when the container exits.'),
default='no',
constraints=[
constraints.AllowedValues(['no', 'on-failure',
'always']),
]
),
POLICY_MAXIMUM_RETRY_COUNT: properties.Schema(
properties.Schema.INTEGER,
_('A maximum restart count for the '
'on-failure policy.'),
default=0
)
},
default={}
),
CAP_ADD: properties.Schema(
properties.Schema.LIST,
_('Be used to add kernel capabilities (only supported for '
'API version >= 1.2.0).'),
schema=properties.Schema(
properties.Schema.STRING,
_('The security features provided by Linux kernels.'),
constraints=[
constraints.AllowedValues(_CAPABILITIES),
]
),
default=[]
),
CAP_DROP: properties.Schema(
properties.Schema.LIST,
_('Be used to drop kernel capabilities (only supported for '
'API version >= 1.2.0).'),
schema=properties.Schema(
properties.Schema.STRING,
_('The security features provided by Linux kernels.'),
constraints=[
constraints.AllowedValues(_CAPABILITIES),
]
),
default=[]
)
}
attributes_schema = {
@ -279,6 +347,12 @@ class DockerContainer(resource.Resource):
start_args['port_bindings'] = self.properties[self.PORT_BINDINGS]
if self.properties[self.LINKS]:
start_args['links'] = self.properties[self.LINKS]
if self.properties[self.RESTART_POLICY]:
start_args['restart_policy'] = self.properties[self.RESTART_POLICY]
if self.properties[self.CAP_ADD]:
start_args['cap_add'] = self.properties[self.CAP_ADD]
if self.properties[self.CAP_DROP]:
start_args['cap_drop'] = self.properties[self.CAP_DROP]
client.start(container_id, **start_args)
return container_id

View File

@ -219,3 +219,79 @@ class DockerContainerTest(common.HeatTestCase):
container.state)
running = self.get_container_state(container)['Running']
self.assertIs(True, running)
def test_start_with_restart_policy_no(self):
t = template_format.parse(template)
stack = utils.parse_stack(t)
definition = stack.t.resource_definitions(stack)['Blog']
definition['Properties']['restart_policy'] = {
'Name': 'no', 'MaximumRetryCount': 0}
resource = docker_container.DockerContainer(
'Blog', definition, stack)
get_client_mock = self.patchobject(resource, 'get_client')
get_client_mock.return_value = fakeclient.FakeDockerClient()
self.assertIsNone(resource.validate())
scheduler.TaskRunner(resource.create)()
self.assertEqual((resource.CREATE, resource.COMPLETE),
resource.state)
client = resource.get_client()
self.assertEqual(['samalba/wordpress'], client.pulled_images)
self.assertEqual({'Name': 'no', 'MaximumRetryCount': 0},
client.container_start[0]['restart_policy'])
def test_start_with_restart_policy_on_failure(self):
t = template_format.parse(template)
stack = utils.parse_stack(t)
definition = stack.t.resource_definitions(stack)['Blog']
definition['Properties']['restart_policy'] = {
'Name': 'on-failure', 'MaximumRetryCount': 10}
resource = docker_container.DockerContainer(
'Blog', definition, stack)
get_client_mock = self.patchobject(resource, 'get_client')
get_client_mock.return_value = fakeclient.FakeDockerClient()
self.assertIsNone(resource.validate())
scheduler.TaskRunner(resource.create)()
self.assertEqual((resource.CREATE, resource.COMPLETE),
resource.state)
client = resource.get_client()
self.assertEqual(['samalba/wordpress'], client.pulled_images)
self.assertEqual({'Name': 'on-failure', 'MaximumRetryCount': 10},
client.container_start[0]['restart_policy'])
def test_start_with_restart_policy_always(self):
t = template_format.parse(template)
stack = utils.parse_stack(t)
definition = stack.t.resource_definitions(stack)['Blog']
definition['Properties']['restart_policy'] = {
'Name': 'always', 'MaximumRetryCount': 0}
resource = docker_container.DockerContainer(
'Blog', definition, stack)
get_client_mock = self.patchobject(resource, 'get_client')
get_client_mock.return_value = fakeclient.FakeDockerClient()
self.assertIsNone(resource.validate())
scheduler.TaskRunner(resource.create)()
self.assertEqual((resource.CREATE, resource.COMPLETE),
resource.state)
client = resource.get_client()
self.assertEqual(['samalba/wordpress'], client.pulled_images)
self.assertEqual({'Name': 'always', 'MaximumRetryCount': 0},
client.container_start[0]['restart_policy'])
def test_start_with_caps(self):
t = template_format.parse(template)
stack = utils.parse_stack(t)
definition = stack.t.resource_definitions(stack)['Blog']
definition['Properties']['cap_add'] = ['NET_ADMIN']
definition['Properties']['cap_drop'] = ['MKNOD']
resource = docker_container.DockerContainer(
'Blog', definition, stack)
get_client_mock = self.patchobject(resource, 'get_client')
get_client_mock.return_value = fakeclient.FakeDockerClient()
self.assertIsNone(resource.validate())
scheduler.TaskRunner(resource.create)()
self.assertEqual((resource.CREATE, resource.COMPLETE),
resource.state)
client = resource.get_client()
self.assertEqual(['samalba/wordpress'], client.pulled_images)
self.assertEqual(['NET_ADMIN'], client.container_start[0]['cap_add'])
self.assertEqual(['MKNOD'], client.container_start[0]['cap_drop'])