From 005a03d0101f62a1083dcd2846819f9873bc2bf1 Mon Sep 17 00:00:00 2001 From: Kevin Zhao Date: Wed, 28 Dec 2016 14:38:42 +0800 Subject: [PATCH] Add stdin_open tty flags to container Change-Id: I6a679cc02a407bb866f2d740d127f22de60b6ae1 Partially-Implements: BP support-interactive-mode --- doc/source/dev/quickstart.rst | 2 +- specs/container-interactive-mode.rst | 2 +- zun/api/controllers/v1/containers.py | 9 +++++ zun/api/controllers/v1/schemas/containers.py | 6 ++- .../controllers/v1/views/containers_view.py | 4 +- zun/common/validation/parameter_types.py | 7 +++- zun/container/docker/driver.py | 2 + .../d1ef05fd92c8_add_tty_stdin_open.py | 37 +++++++++++++++++++ zun/db/sqlalchemy/models.py | 2 + zun/objects/container.py | 7 +++- .../container/docker/test_docker_driver.py | 4 ++ zun/tests/unit/db/utils.py | 2 + 12 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 zun/db/sqlalchemy/alembic/versions/d1ef05fd92c8_add_tty_stdin_open.py diff --git a/doc/source/dev/quickstart.rst b/doc/source/dev/quickstart.rst index d7e062a7f..40814c1d9 100644 --- a/doc/source/dev/quickstart.rst +++ b/doc/source/dev/quickstart.rst @@ -133,7 +133,7 @@ Using the service We will create a container that pings the address 8.8.8.8 four times:: - zun create --name test --image cirros --command "ping -c 4 8.8.8.8" + zun create --name test --command "ping -c 4 8.8.8.8" cirros zun start test You should see a similar output to:: diff --git a/specs/container-interactive-mode.rst b/specs/container-interactive-mode.rst index fdaf9ecd0..959250a99 100644 --- a/specs/container-interactive-mode.rst +++ b/specs/container-interactive-mode.rst @@ -55,7 +55,7 @@ Proposed change it in the follow bp/bug). The diagram below offers an overview of the interactive mode architecture. -E.g : zun run -it --name test --image cirros --command "/bin/sh" +E.g : zun run -i -t --name test --command "/bin/sh" cirros The sequence diagram is in this link: https://github.com/kevin-zhaoshuai/workflow diff --git a/zun/api/controllers/v1/containers.py b/zun/api/controllers/v1/containers.py index c687b2336..036c25259 100644 --- a/zun/api/controllers/v1/containers.py +++ b/zun/api/controllers/v1/containers.py @@ -192,6 +192,15 @@ class ContainersController(rest.RestController): except ValueError: msg = _('Valid run values are true, false, 0, 1, yes and no') raise exception.InvalidValue(msg) + try: + container_dict['tty'] = strutils.bool_from_string( + container_dict.get('tty', False), strict=True) + container_dict['stdin_open'] = strutils.bool_from_string( + container_dict.get('stdin_open', False), strict=True) + except ValueError: + msg = _('Valid tty and stdin_open values are ''true'', ' + '"false", True, False, "True" and "False"') + raise exception.InvalidValue(msg) # NOTE(mkrai): Intent here is to check the existence of image # before proceeding to create container. If image is not found, diff --git a/zun/api/controllers/v1/schemas/containers.py b/zun/api/controllers/v1/schemas/containers.py index 2fe9cdc0f..f3b7fb3b3 100644 --- a/zun/api/controllers/v1/schemas/containers.py +++ b/zun/api/controllers/v1/schemas/containers.py @@ -25,6 +25,8 @@ _container_properties = { 'labels': parameter_types.labels, 'environment': parameter_types.environment, 'restart_policy': parameter_types.restart_policy, + 'tty': parameter_types.boolean, + 'stdin_open': parameter_types.boolean, } container_create = { @@ -45,7 +47,7 @@ query_param_rename = { query_param_create = { 'type': 'object', 'properties': { - 'run': parameter_types.boolean + 'run': parameter_types.boolean_extended }, 'additionalProperties': False } @@ -64,7 +66,7 @@ container_update = { query_param_delete = { 'type': 'object', 'properties': { - 'force': parameter_types.boolean + 'force': parameter_types.boolean_extended }, 'additionalProperties': False } diff --git a/zun/api/controllers/v1/views/containers_view.py b/zun/api/controllers/v1/views/containers_view.py index 8e1d87c3b..ec168c471 100644 --- a/zun/api/controllers/v1/views/containers_view.py +++ b/zun/api/controllers/v1/views/containers_view.py @@ -35,7 +35,9 @@ _basic_keys = ( 'image_pull_policy', 'host', 'restart_policy', - 'status_detail' + 'status_detail', + 'tty', + 'stdin_open' ) diff --git a/zun/common/validation/parameter_types.py b/zun/common/validation/parameter_types.py index f0dff7c69..990927a60 100644 --- a/zun/common/validation/parameter_types.py +++ b/zun/common/validation/parameter_types.py @@ -18,7 +18,7 @@ non_negative_integer = { 'pattern': '^[0-9]*$', 'minimum': 0 } -boolean = { +boolean_extended = { 'type': ['boolean', 'string'], 'enum': [True, 'True', 'TRUE', 'true', '1', 'ON', 'On', 'on', 'YES', 'Yes', 'yes', @@ -26,6 +26,11 @@ boolean = { 'NO', 'No', 'no'], } +boolean = { + 'type': ['boolean', 'string'], + 'enum': [True, 'True', 'true', False, 'False', 'false'], +} + container_name = { 'type': ['string', 'null'], 'minLength': 2, diff --git a/zun/container/docker/driver.py b/zun/container/docker/driver.py index 440533553..6c25aa946 100644 --- a/zun/container/docker/driver.py +++ b/zun/container/docker/driver.py @@ -74,6 +74,8 @@ class DockerDriver(driver.ContainerDriver): 'environment': container.environment, 'working_dir': container.workdir, 'labels': container.labels, + 'tty': container.tty, + 'stdin_open': container.stdin_open, } host_config = {} diff --git a/zun/db/sqlalchemy/alembic/versions/d1ef05fd92c8_add_tty_stdin_open.py b/zun/db/sqlalchemy/alembic/versions/d1ef05fd92c8_add_tty_stdin_open.py new file mode 100644 index 000000000..d1f4cc60f --- /dev/null +++ b/zun/db/sqlalchemy/alembic/versions/d1ef05fd92c8_add_tty_stdin_open.py @@ -0,0 +1,37 @@ +# 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. + +"""add tty stdin_open + +Revision ID: d1ef05fd92c8 +Revises: ad43a2179cf2 +Create Date: 2016-11-09 09:40:59.839380 + +""" + +# revision identifiers, used by Alembic. +revision = 'd1ef05fd92c8' +down_revision = 'ad43a2179cf2' +branch_labels = None +depends_on = None + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('container', + sa.Column('tty', sa.Boolean, + nullable=True)) + op.add_column('container', + sa.Column('stdin_open', sa.Boolean, + nullable=True)) diff --git a/zun/db/sqlalchemy/models.py b/zun/db/sqlalchemy/models.py index d748e26b9..d339c5230 100644 --- a/zun/db/sqlalchemy/models.py +++ b/zun/db/sqlalchemy/models.py @@ -148,6 +148,8 @@ class Container(Base): host = Column(String(255)) restart_policy = Column(JSONEncodedDict) status_detail = Column(String(50)) + tty = Column(Boolean, default=False) + stdin_open = Column(Boolean, default=False) class Image(Base): diff --git a/zun/objects/container.py b/zun/objects/container.py index c41e690cd..d5b368bae 100644 --- a/zun/objects/container.py +++ b/zun/objects/container.py @@ -29,7 +29,8 @@ class Container(base.ZunPersistentObject, base.ZunObject): # Version 1.7: Add host column # Version 1.8: Add restart_policy # Version 1.9: Add status_detail column - VERSION = '1.9' + # Version 1.10: Add tty, stdin_open + VERSION = '1.10' fields = { 'id': fields.IntegerField(), @@ -55,7 +56,9 @@ class Container(base.ZunPersistentObject, base.ZunObject): 'image_pull_policy': fields.StringField(nullable=True), 'host': fields.StringField(nullable=True), 'restart_policy': fields.DictOfStringsField(nullable=True), - 'status_detail': fields.StringField(nullable=True) + 'status_detail': fields.StringField(nullable=True), + 'tty': fields.BooleanField(nullable=True), + 'stdin_open': fields.BooleanField(nullable=True), } @staticmethod diff --git a/zun/tests/unit/container/docker/test_docker_driver.py b/zun/tests/unit/container/docker/test_docker_driver.py index 92f7530ed..2d8096e7c 100644 --- a/zun/tests/unit/container/docker/test_docker_driver.py +++ b/zun/tests/unit/container/docker/test_docker_driver.py @@ -85,6 +85,8 @@ class TestDockerDriver(base.DriverTestCase): 'working_dir': '/home/ubuntu', 'labels': {'key1': 'val1', 'key2': 'val2'}, 'host_config': {'Id1': 'val1', 'key2': 'val2'}, + 'stdin_open': True, + 'tty': True, } self.mock_docker.create_container.assert_called_once_with( mock_container.image, **kwargs) @@ -127,6 +129,8 @@ class TestDockerDriver(base.DriverTestCase): 'labels': {'key1': 'val1', 'key2': 'val2'}, 'host_config': {'Id1': 'val1', 'key2': 'val2'}, 'name': 'zun-ea8e2a25-2901-438d-8157-de7ffd68d051', + 'stdin_open': True, + 'tty': True, } self.mock_docker.create_container.assert_called_once_with( mock_container.image, **kwargs) diff --git a/zun/tests/unit/db/utils.py b/zun/tests/unit/db/utils.py index e2ae89490..28d5aa882 100644 --- a/zun/tests/unit/db/utils.py +++ b/zun/tests/unit/db/utils.py @@ -60,6 +60,8 @@ def get_test_container(**kw): 'restart_policy': kw.get('restart_policy', {'Name': 'no', 'MaximumRetryCount': '0'}), 'status_detail': kw.get('status_detail', 'up from 5 hours'), + 'tty': kw.get('tty', True), + 'stdin_open': kw.get('stdin_open', True), }