Docker plugin add cpu share property
Docker API 1.8 and docker-py 0.3.0 support the cpu-shares parameter when creating containers(docker run --cpu-shares=0). By default, all containers run at the same priority and get the same proportion of CPU cycles, but you can tell the kernel to give more shares of CPU time to one or more containers when you start them via Docker. Change-Id: Ic20cc56070c120ab46379aa42d5da6ac9425cae7 Closes-bug: #1439033
This commit is contained in:
parent
f65079fe74
commit
41437ff8a3
@ -31,7 +31,7 @@ from heat.engine import support
|
|||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
DOCKER_INSTALLED = False
|
DOCKER_INSTALLED = False
|
||||||
READ_ONLY_MIN_API_VERSION = '1.17'
|
MIN_API_VERSION_MAP = {'read_only': '1.17', 'cpu_shares': '1.8'}
|
||||||
# conditionally import so tests can work without having the dependency
|
# conditionally import so tests can work without having the dependency
|
||||||
# satisfied
|
# satisfied
|
||||||
try:
|
try:
|
||||||
@ -47,12 +47,12 @@ class DockerContainer(resource.Resource):
|
|||||||
DOCKER_ENDPOINT, HOSTNAME, USER, MEMORY, PORT_SPECS,
|
DOCKER_ENDPOINT, HOSTNAME, USER, MEMORY, PORT_SPECS,
|
||||||
PRIVILEGED, TTY, OPEN_STDIN, STDIN_ONCE, ENV, CMD, DNS,
|
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, READ_ONLY,
|
RESTART_POLICY, CAP_ADD, CAP_DROP, READ_ONLY, CPU_SHARES,
|
||||||
) = (
|
) = (
|
||||||
'docker_endpoint', 'hostname', 'user', 'memory', 'port_specs',
|
'docker_endpoint', 'hostname', 'user', 'memory', 'port_specs',
|
||||||
'privileged', 'tty', 'open_stdin', 'stdin_once', 'env', 'cmd', 'dns',
|
'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', 'read_only'
|
'restart_policy', 'cap_add', 'cap_drop', 'read_only', 'cpu_shares',
|
||||||
)
|
)
|
||||||
|
|
||||||
ATTRIBUTES = (
|
ATTRIBUTES = (
|
||||||
@ -220,9 +220,17 @@ class DockerContainer(resource.Resource):
|
|||||||
properties.Schema.BOOLEAN,
|
properties.Schema.BOOLEAN,
|
||||||
_('If true, mount the container\'s root filesystem '
|
_('If true, mount the container\'s root filesystem '
|
||||||
'as read only (only supported for API version >= %s).') %
|
'as read only (only supported for API version >= %s).') %
|
||||||
READ_ONLY_MIN_API_VERSION,
|
MIN_API_VERSION_MAP['read_only'],
|
||||||
default=False,
|
default=False,
|
||||||
support_status=support.SupportStatus(version='2015.1'),
|
support_status=support.SupportStatus(version='2015.1'),
|
||||||
|
),
|
||||||
|
CPU_SHARES: properties.Schema(
|
||||||
|
properties.Schema.INTEGER,
|
||||||
|
_('Relative weight which determines the allocation of the CPU '
|
||||||
|
'processing power(only supported for API version >= %s).') %
|
||||||
|
MIN_API_VERSION_MAP['cpu_shares'],
|
||||||
|
default=0,
|
||||||
|
support_status=support.SupportStatus(version='2015.2'),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,10 +348,10 @@ class DockerContainer(resource.Resource):
|
|||||||
'environment': self.properties[self.ENV],
|
'environment': self.properties[self.ENV],
|
||||||
'dns': self.properties[self.DNS],
|
'dns': self.properties[self.DNS],
|
||||||
'volumes': self.properties[self.VOLUMES],
|
'volumes': self.properties[self.VOLUMES],
|
||||||
'name': self.properties[self.NAME]
|
'name': self.properties[self.NAME],
|
||||||
|
'cpu_shares': self.properties[self.CPU_SHARES]
|
||||||
}
|
}
|
||||||
client = self.get_client()
|
client = self.get_client()
|
||||||
version = client.version()['ApiVersion']
|
|
||||||
client.pull(self.properties[self.IMAGE])
|
client.pull(self.properties[self.IMAGE])
|
||||||
result = client.create_container(**create_args)
|
result = client.create_container(**create_args)
|
||||||
container_id = result['Id']
|
container_id = result['Id']
|
||||||
@ -368,12 +376,7 @@ class DockerContainer(resource.Resource):
|
|||||||
if self.properties[self.CAP_DROP]:
|
if self.properties[self.CAP_DROP]:
|
||||||
start_args['cap_drop'] = self.properties[self.CAP_DROP]
|
start_args['cap_drop'] = self.properties[self.CAP_DROP]
|
||||||
if self.properties[self.READ_ONLY]:
|
if self.properties[self.READ_ONLY]:
|
||||||
if compare_version(READ_ONLY_MIN_API_VERSION, version) >= 0:
|
start_args[self.READ_ONLY] = True
|
||||||
start_args[self.READ_ONLY] = True
|
|
||||||
else:
|
|
||||||
raise InvalidArgForVersion(arg=self.READ_ONLY,
|
|
||||||
min_version=(
|
|
||||||
READ_ONLY_MIN_API_VERSION))
|
|
||||||
|
|
||||||
client.start(container_id, **start_args)
|
client.start(container_id, **start_args)
|
||||||
return container_id
|
return container_id
|
||||||
@ -436,6 +439,22 @@ class DockerContainer(resource.Resource):
|
|||||||
status = self._get_container_status(container_id)
|
status = self._get_container_status(container_id)
|
||||||
return status['Running']
|
return status['Running']
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
super(DockerContainer, self).validate()
|
||||||
|
self._validate_arg_for_api_version()
|
||||||
|
|
||||||
|
def _validate_arg_for_api_version(self):
|
||||||
|
version = None
|
||||||
|
for key in MIN_API_VERSION_MAP:
|
||||||
|
if self.properties[key]:
|
||||||
|
if not version:
|
||||||
|
client = self.get_client()
|
||||||
|
version = client.version()['ApiVersion']
|
||||||
|
min_version = MIN_API_VERSION_MAP[key]
|
||||||
|
if compare_version(min_version, version) < 0:
|
||||||
|
raise InvalidArgForVersion(arg=key,
|
||||||
|
min_version=min_version)
|
||||||
|
|
||||||
|
|
||||||
def resource_mapping():
|
def resource_mapping():
|
||||||
return {
|
return {
|
||||||
|
@ -19,6 +19,7 @@ from oslo_utils import importutils
|
|||||||
import six
|
import six
|
||||||
|
|
||||||
from heat.common import exception
|
from heat.common import exception
|
||||||
|
from heat.common.i18n import _
|
||||||
from heat.common import template_format
|
from heat.common import template_format
|
||||||
from heat.engine import resource
|
from heat.engine import resource
|
||||||
from heat.engine import rsrc_defn
|
from heat.engine import rsrc_defn
|
||||||
@ -314,24 +315,48 @@ class DockerContainerTest(common.HeatTestCase):
|
|||||||
self.assertEqual(['samalba/wordpress'], client.pulled_images)
|
self.assertEqual(['samalba/wordpress'], client.pulled_images)
|
||||||
self.assertIs(True, client.container_start[0]['read_only'])
|
self.assertIs(True, client.container_start[0]['read_only'])
|
||||||
|
|
||||||
def test_start_with_read_only_for_low_api_version(self):
|
def arg_for_low_api_version(self, arg, value, low_version):
|
||||||
t = template_format.parse(template)
|
t = template_format.parse(template)
|
||||||
stack = utils.parse_stack(t)
|
stack = utils.parse_stack(t)
|
||||||
definition = stack.t.resource_definitions(stack)['Blog']
|
definition = stack.t.resource_definitions(stack)['Blog']
|
||||||
definition['Properties']['read_only'] = True
|
definition['Properties'][arg] = value
|
||||||
my_resource = docker_container.DockerContainer(
|
my_resource = docker_container.DockerContainer(
|
||||||
'Blog', definition, stack)
|
'Blog', definition, stack)
|
||||||
get_client_mock = self.patchobject(my_resource, 'get_client')
|
get_client_mock = self.patchobject(my_resource, 'get_client')
|
||||||
get_client_mock.return_value = fakeclient.FakeDockerClient()
|
get_client_mock.return_value = fakeclient.FakeDockerClient()
|
||||||
get_client_mock.return_value.set_api_version('1.16')
|
get_client_mock.return_value.set_api_version(low_version)
|
||||||
self.assertIsNone(my_resource.validate())
|
msg = self.assertRaises(docker_container.InvalidArgForVersion,
|
||||||
msg = self.assertRaises(exception.ResourceFailure,
|
my_resource.validate)
|
||||||
scheduler.TaskRunner(my_resource.create))
|
min_version = docker_container.MIN_API_VERSION_MAP[arg]
|
||||||
expected = ('InvalidArgForVersion: "read_only" is not supported '
|
args = dict(arg=arg, min_version=min_version)
|
||||||
'for API version < "1.17"')
|
expected = _('"%(arg)s" is not supported for API version '
|
||||||
|
'< "%(min_version)s"') % args
|
||||||
self.assertEqual(expected, six.text_type(msg))
|
self.assertEqual(expected, six.text_type(msg))
|
||||||
|
|
||||||
|
def test_start_with_read_only_for_low_api_version(self):
|
||||||
|
self.arg_for_low_api_version('read_only', True, '1.16')
|
||||||
|
|
||||||
def test_compare_version(self):
|
def test_compare_version(self):
|
||||||
self.assertEqual(docker_container.compare_version('1.17', '1.17'), 0)
|
self.assertEqual(docker_container.compare_version('1.17', '1.17'), 0)
|
||||||
self.assertEqual(docker_container.compare_version('1.17', '1.16'), -1)
|
self.assertEqual(docker_container.compare_version('1.17', '1.16'), -1)
|
||||||
self.assertEqual(docker_container.compare_version('1.17', '1.18'), 1)
|
self.assertEqual(docker_container.compare_version('1.17', '1.18'), 1)
|
||||||
|
|
||||||
|
def test_create_with_cpu_shares(self):
|
||||||
|
t = template_format.parse(template)
|
||||||
|
stack = utils.parse_stack(t)
|
||||||
|
definition = stack.t.resource_definitions(stack)['Blog']
|
||||||
|
definition['Properties']['cpu_shares'] = 512
|
||||||
|
my_resource = docker_container.DockerContainer(
|
||||||
|
'Blog', definition, stack)
|
||||||
|
get_client_mock = self.patchobject(my_resource, 'get_client')
|
||||||
|
get_client_mock.return_value = fakeclient.FakeDockerClient()
|
||||||
|
self.assertIsNone(my_resource.validate())
|
||||||
|
scheduler.TaskRunner(my_resource.create)()
|
||||||
|
self.assertEqual((my_resource.CREATE, my_resource.COMPLETE),
|
||||||
|
my_resource.state)
|
||||||
|
client = my_resource.get_client()
|
||||||
|
self.assertEqual(['samalba/wordpress'], client.pulled_images)
|
||||||
|
self.assertEqual(512, client.container_create[0]['cpu_shares'])
|
||||||
|
|
||||||
|
def test_create_with_cpu_shares_for_low_api_version(self):
|
||||||
|
self.arg_for_low_api_version('cpu_shares', 512, '1.7')
|
||||||
|
Loading…
Reference in New Issue
Block a user