Merge "Add "run" parameter to the exec API"
This commit is contained in:
commit
15c540d3dc
@ -410,15 +410,21 @@ class ContainersController(rest.RestController):
|
||||
|
||||
@pecan.expose('json')
|
||||
@exception.wrap_pecan_controller_exception
|
||||
def execute(self, container_id, **kw):
|
||||
def execute(self, container_id, run=True, **kw):
|
||||
container = _get_container(container_id)
|
||||
check_policy_on_container(container.as_dict(), "container:execute")
|
||||
try:
|
||||
run = strutils.bool_from_string(run, strict=True)
|
||||
except ValueError:
|
||||
msg = _('Valid run values are true, false, 0, 1, yes and no')
|
||||
raise exception.InvalidValue(msg)
|
||||
utils.validate_container_state(container, 'execute')
|
||||
LOG.debug('Calling compute.container_exec with %s command %s'
|
||||
% (container.uuid, kw['command']))
|
||||
context = pecan.request.context
|
||||
compute_api = pecan.request.compute_api
|
||||
return compute_api.container_exec(context, container, kw['command'])
|
||||
return compute_api.container_exec(context, container, kw['command'],
|
||||
run)
|
||||
|
||||
@pecan.expose('json')
|
||||
@exception.wrap_pecan_controller_exception
|
||||
|
@ -330,11 +330,15 @@ class Manager(object):
|
||||
raise
|
||||
|
||||
@translate_exception
|
||||
def container_exec(self, context, container, command):
|
||||
def container_exec(self, context, container, command, run):
|
||||
# TODO(hongbin): support exec command interactively
|
||||
LOG.debug('Executing command in container: %s', container.uuid)
|
||||
try:
|
||||
return self.driver.execute(container, command)
|
||||
exec_id = self.driver.execute_create(container, command)
|
||||
if run:
|
||||
return self.driver.execute_run(exec_id)
|
||||
else:
|
||||
return exec_id
|
||||
except exception.DockerError as e:
|
||||
LOG.error("Error occurred while calling Docker exec API: %s",
|
||||
six.text_type(e))
|
||||
|
@ -75,9 +75,9 @@ class API(rpc_service.API):
|
||||
stdout=stdout, stderr=stderr,
|
||||
timestamps=timestamps, tail=tail, since=since)
|
||||
|
||||
def container_exec(self, context, container, command):
|
||||
def container_exec(self, context, container, command, run):
|
||||
return self._call(container.host, 'container_exec',
|
||||
container=container, command=command)
|
||||
container=container, command=command, run=run)
|
||||
|
||||
def container_kill(self, context, container, signal):
|
||||
self._cast(container.host, 'container_kill', container=container,
|
||||
|
@ -287,11 +287,15 @@ class DockerDriver(driver.ContainerDriver):
|
||||
timestamps, tail, since)
|
||||
|
||||
@check_container_id
|
||||
def execute(self, container, command):
|
||||
def execute_create(self, container, command):
|
||||
with docker_utils.docker_client() as docker:
|
||||
create_res = docker.exec_create(
|
||||
container.container_id, command, True, True, False)
|
||||
exec_id = create_res['Id']
|
||||
return exec_id
|
||||
|
||||
def execute_run(self, exec_id):
|
||||
with docker_utils.docker_client() as docker:
|
||||
output = docker.exec_start(exec_id, False, False, False)
|
||||
inspect_res = docker.exec_inspect(exec_id)
|
||||
return {"output": output, "exit_code": inspect_res['ExitCode']}
|
||||
|
@ -100,8 +100,12 @@ class ContainerDriver(object):
|
||||
"""Show logs of a container."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def execute(self, container, command):
|
||||
"""Execute a command in a running container."""
|
||||
def execute_create(self, container, command):
|
||||
"""Create an execute instance for running a command."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def execute_run(self, exec_id):
|
||||
"""Run the command specified by an execute instance."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def kill(self, container, signal):
|
||||
|
@ -807,7 +807,7 @@ class TestContainerController(api_base.FunctionalTest):
|
||||
response = self.app.post(url, cmd)
|
||||
self.assertEqual(200, response.status_int)
|
||||
mock_container_exec.assert_called_once_with(
|
||||
mock.ANY, test_container_obj, cmd['command'])
|
||||
mock.ANY, test_container_obj, cmd['command'], True)
|
||||
|
||||
def test_exec_command_by_uuid_invalid_state(self):
|
||||
uuid = uuidutils.generate_uuid()
|
||||
|
@ -390,20 +390,23 @@ class TestManager(base.TestCase):
|
||||
self.context, container, True, True,
|
||||
False, 'all', None)
|
||||
|
||||
@mock.patch.object(fake_driver, 'execute')
|
||||
def test_container_execute(self, mock_execute):
|
||||
@mock.patch.object(fake_driver, 'execute_run')
|
||||
@mock.patch.object(fake_driver, 'execute_create')
|
||||
def test_container_execute(self, mock_execute_create, mock_execute_run):
|
||||
mock_execute_create.return_value = 'fake_exec_id'
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
self.compute_manager.container_exec(
|
||||
self.context, container, 'fake_cmd')
|
||||
mock_execute.assert_called_once_with(container, 'fake_cmd')
|
||||
self.context, container, 'fake_cmd', True)
|
||||
mock_execute_create.assert_called_once_with(container, 'fake_cmd')
|
||||
mock_execute_run.assert_called_once_with('fake_exec_id')
|
||||
|
||||
@mock.patch.object(fake_driver, 'execute')
|
||||
def test_container_execute_failed(self, mock_execute):
|
||||
@mock.patch.object(fake_driver, 'execute_create')
|
||||
def test_container_execute_failed(self, mock_execute_create):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_execute.side_effect = exception.DockerError
|
||||
mock_execute_create.side_effect = exception.DockerError
|
||||
self.assertRaises(exception.DockerError,
|
||||
self.compute_manager.container_exec,
|
||||
self.context, container, 'fake_cmd')
|
||||
self.context, container, 'fake_cmd', True)
|
||||
|
||||
@mock.patch.object(fake_driver, 'kill')
|
||||
def test_container_kill(self, mock_kill):
|
||||
|
@ -238,15 +238,19 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
mock_container.container_id, True, True, False, False,
|
||||
'all', None)
|
||||
|
||||
def test_execute(self):
|
||||
def test_execute_create(self):
|
||||
self.mock_docker.exec_create = mock.Mock(return_value={'Id': 'test'})
|
||||
mock_container = mock.MagicMock()
|
||||
exec_id = self.driver.execute_create(mock_container, 'ls')
|
||||
self.assertEqual('test', exec_id)
|
||||
self.mock_docker.exec_create.assert_called_once_with(
|
||||
mock_container.container_id, 'ls', True, True, False)
|
||||
|
||||
def test_execute_run(self):
|
||||
self.mock_docker.exec_start = mock.Mock(return_value='test')
|
||||
self.mock_docker.exec_inspect = mock.Mock(
|
||||
return_value={u'ExitCode': 0})
|
||||
mock_container = mock.MagicMock()
|
||||
self.driver.execute(mock_container, 'ls')
|
||||
self.mock_docker.exec_create.assert_called_once_with(
|
||||
mock_container.container_id, 'ls', True, True, False)
|
||||
self.driver.execute_run('test')
|
||||
self.mock_docker.exec_start.assert_called_once_with('test', False,
|
||||
False, False)
|
||||
self.mock_docker.exec_inspect.assert_called_once()
|
||||
|
Loading…
Reference in New Issue
Block a user