Bring hostname option back

Zun already had this option before, but had to remove due to the
Conflict Exception (relate to sandbox). At this time, we made sandbox
optional. Therefore, if use_sandbox option is False, we can use
hostname option. If it is True, raise the Exception to let user know.

This option will help us to implement the
blueprint internal-dns-resolution.

Change-Id: I2f8826fc66e94c0d4452ff32e3bc17700ef6b668
Closes-Bug: #1716849
This commit is contained in:
Kien Nguyen 2017-09-14 10:40:15 +07:00
parent 179225b5ae
commit 2057b668bf
15 changed files with 99 additions and 27 deletions

View File

@ -49,6 +49,7 @@ Request
- security_groups: security_groups
- nets: nets
- runtime: runtime
- hostname: hostname
Request Example
----------------

View File

@ -134,9 +134,8 @@ host_list:
type: array
hostname:
description: |
The host where container is running.
The hostname of container.
in: body
required: true
type: string
id_s:
description: |

View File

@ -27,5 +27,6 @@
"port": "890699a9-4690-4bd6-8b70-3a9c1be77ecb"
}
],
"runtime": "runc"
"runtime": "runc",
"hostname": "testhost"
}

View File

@ -34,5 +34,6 @@
"command": "/bin/sh -c 'echo hello'",
"cpu": 2.0,
"interactive": false,
"runtime": "runc"
"runtime": "runc",
"hostname": "testhost"
}

View File

@ -252,12 +252,9 @@ class ContainersController(base.Controller):
msg = _('Auto_remove value are true or false')
raise exception.InvalidValue(msg)
else:
msg = _('Invalid param auto_remove because current request '
'version is %(req_version)s. Auto_remove is only '
'supported from version %(min_version)s') % \
{'req_version': req_version,
'min_version': min_version}
raise exception.InvalidParam(msg)
raise exception.InvalidParamInVersion(param='auto_remove',
req_version=req_version,
min_version=min_version)
runtime = container_dict.pop('runtime', None)
if runtime is not None:
@ -266,12 +263,26 @@ class ContainersController(base.Controller):
if req_version >= min_version:
container_dict['runtime'] = runtime
else:
msg = _('Invalid param runtime because current request '
'version is %(req_version)s. `runtime` is only '
'supported from version %(min_version)s') % \
{'req_version': req_version,
'min_version': min_version}
raise exception.InvalidParam(msg)
raise exception.InvalidParamInVersion(param='runtime',
req_version=req_version,
min_version=min_version)
hostname = container_dict.pop('hostname', None)
if hostname is not None:
if CONF.use_sandbox:
raise exception.ConflictOptions(
'Cannot set container\'s hostname when use sandbox. '
'Because with sandbox, network_mode will be set, it '
'is incompatible with legacy network (hostname).')
req_version = pecan.request.version
min_version = versions.Version('', '', '', '1.9')
container_dict['hostname'] = hostname
if req_version >= min_version:
container_dict['hostname'] = hostname
else:
raise exception.InvalidParamInVersion(param='hostname',
req_version=req_version,
min_version=min_version)
nets = container_dict.get('nets', [])
requested_networks = self._build_requested_networks(context, nets)

View File

@ -31,7 +31,8 @@ _container_properties = {
'security_groups': parameter_types.security_groups,
'hints': parameter_types.hints,
'nets': parameter_types.nets,
'runtime': parameter_types.runtime
'runtime': parameter_types.runtime,
'hostname': parameter_types.hostname,
}
container_create = {

View File

@ -40,7 +40,8 @@ _basic_keys = (
'image_driver',
'security_groups',
'auto_remove',
'runtime'
'runtime',
'hostname',
)

View File

@ -41,10 +41,11 @@ REST_API_VERSION_HISTORY = """REST API Version History:
* 1.6 - Support detach network from a container
* 1.7 - Disallow non-admin users to force delete containers
* 1.8 - Support attach a network to a container
* 1.9 - Add support set container's hostname
"""
BASE_VER = '1.1'
CURRENT_MAX_VER = '1.8'
CURRENT_MAX_VER = '1.9'
class Version(object):

View File

@ -76,3 +76,9 @@ user documentation.
Add attach a network to a container.
Users can use this api to attach a neutron network to a container.
1.9
---
Add a new attribute 'hostname' to the request to create a container.
Users can use this attribute to specify container's hostname.

View File

@ -313,6 +313,10 @@ class Conflict(ZunException):
code = 409
class ConflictOptions(Conflict):
message = _('Conflicting options.')
class InvalidState(Conflict):
message = _("Invalid resource state.")
@ -323,8 +327,10 @@ class InvalidParameterValue(Invalid):
message = _("%(err)s")
class InvalidParam(Invalid):
message = _('Invalid param %(param)s')
class InvalidParamInVersion(Invalid):
message = _('Invalid param %(param)s because current request '
'version is %(req_version)s. %(param)s is only '
'supported from version %(min_version)s')
class PatchError(Invalid):

View File

@ -122,6 +122,12 @@ environment = {
},
}
hostname = {
'type': ['string', 'null'],
'minLength': 2,
'maxLength': 63
}
runtime = {
'type': ['string', 'null'],
}

View File

@ -132,6 +132,7 @@ class DockerDriver(driver.ContainerDriver):
'labels': container.labels,
'tty': container.interactive,
'stdin_open': container.interactive,
'hostname': container.hostname,
}
runtime = container.runtime if container.runtime\
@ -396,8 +397,9 @@ class DockerDriver(driver.ContainerDriver):
container.command = command_str
def _populate_hostname_and_ports(self, container, config):
# populate hostname
container.hostname = config.get('Hostname')
# populate hostname only when container.hostname wasn't set
if container.hostname is None:
container.hostname = config.get('Hostname')
# populate ports
ports = []
exposed_ports = config.get('ExposedPorts')

View File

@ -17,7 +17,7 @@ import webtest
from zun.api import app
from zun.tests.unit.api import base as api_base
CURRENT_VERSION = "container 1.8"
CURRENT_VERSION = "container 1.9"
class TestRootController(api_base.FunctionalTest):
@ -27,7 +27,7 @@ class TestRootController(api_base.FunctionalTest):
'default_version':
{'id': 'v1',
'links': [{'href': 'http://localhost/v1/', 'rel': 'self'}],
'max_version': '1.8',
'max_version': '1.9',
'min_version': '1.1',
'status': 'CURRENT'},
'description': 'Zun is an OpenStack project which '
@ -35,7 +35,7 @@ class TestRootController(api_base.FunctionalTest):
'versions': [{'id': 'v1',
'links': [{'href': 'http://localhost/v1/',
'rel': 'self'}],
'max_version': '1.8',
'max_version': '1.9',
'min_version': '1.1',
'status': 'CURRENT'}]}

View File

@ -23,7 +23,7 @@ from zun.tests.unit.api import base as api_base
from zun.tests.unit.db import utils
from zun.tests.unit.objects import utils as obj_utils
CURRENT_VERSION = "container 1.8"
CURRENT_VERSION = "container 1.9"
class TestContainerController(api_base.FunctionalTest):
@ -108,6 +108,41 @@ class TestContainerController(api_base.FunctionalTest):
params=params, content_type='application/json',
headers=api_version)
def test_run_container_with_hostname_wrong_api_version(self):
params = ('{"name": "MyDocker", "image": "ubuntu",'
'"command": "env", "memory": "512",'
'"environment": {"key1": "val1", "key2": "val2"},'
'"hostname": "testhost"}')
headers = {"OpenStack-API-Version": "container 1.7",
"Accept": "application/json"}
with self.assertRaisesRegex(AppError,
"Invalid param hostname"):
self.app.post('/v1/containers?run=true',
params=params, content_type='application/json',
headers=headers)
@patch('zun.network.neutron.NeutronAPI.get_available_network')
@patch('zun.compute.api.API.container_create')
@patch('zun.compute.api.API.image_search')
def test_run_container_with_hostname_successfully(
self, mock_search,
mock_container_create,
mock_neutron_get_network):
params = ('{"name": "MyDocker", "image": "ubuntu",'
'"command": "env", "memory": "512",'
'"environment": {"key1": "val1", "key2": "val2"},'
'"hostname": "testhost"}')
api_version = {"OpenStack-API-Version": CURRENT_VERSION}
response = self.app.post('/v1/containers?run=true',
params=params,
content_type='application/json',
headers=api_version)
self.assertEqual(202, response.status_int)
self.assertTrue(mock_container_create.called)
self.assertTrue(mock_container_create.call_args[1]['run'] is True)
mock_neutron_get_network.assert_called_once()
@patch('zun.network.neutron.NeutronAPI.get_available_network')
@patch('zun.compute.api.API.container_create')
@patch('zun.compute.api.API.image_search')

View File

@ -111,6 +111,7 @@ class TestDockerDriver(base.DriverTestCase):
'host_config': {'Id1': 'val1', 'key2': 'val2'},
'stdin_open': True,
'tty': True,
'hostname': 'testhost',
}
self.mock_docker.create_container.assert_called_once_with(
image['repo'] + ":" + image['tag'], **kwargs)