Add support to set env to a container
Docker run support an option to set environment variables to a container. container-create in Magnum also needs this. This will help for the user to create a container with some environment variables. Also, swarm use some special environments to scheduler. This patch add support to do this. Implements: blueprint support-to-set-env-variables Change-Id: Ifa46eb6d0e528eadca44d265e906c92ee752af43
This commit is contained in:
parent
2dff5b1a4e
commit
c5317ebf03
|
@ -94,6 +94,9 @@ class Container(base.APIBase):
|
|||
memory = wtypes.text
|
||||
"""Memory limit for the container. Example: 512m"""
|
||||
|
||||
environment = wtypes.DictType(str, str)
|
||||
"""One or more key/value pairs"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.fields = []
|
||||
for field in objects.Container.fields:
|
||||
|
@ -108,7 +111,7 @@ class Container(base.APIBase):
|
|||
if not expand:
|
||||
container.unset_fields_except(['uuid', 'name', 'bay_uuid',
|
||||
'image', 'command', 'status',
|
||||
'memory'])
|
||||
'memory', 'environment'])
|
||||
|
||||
container.links = [link.Link.make_link(
|
||||
'self', url,
|
||||
|
@ -133,6 +136,7 @@ class Container(base.APIBase):
|
|||
command='env',
|
||||
status='Running',
|
||||
memory='512m',
|
||||
environment={'key1': 'val1', 'key2': 'val2'},
|
||||
bay_uuid="fff114da-3bfa-4a0f-a123-c0dffad9718e",
|
||||
created_at=timeutils.utcnow(),
|
||||
updated_at=timeutils.utcnow())
|
||||
|
|
|
@ -79,7 +79,8 @@ class Handler(object):
|
|||
docker.create_container(image, name=name,
|
||||
hostname=container_uuid,
|
||||
command=container.command,
|
||||
mem_limit=container.memory)
|
||||
mem_limit=container.memory,
|
||||
environment=container.environment)
|
||||
container.status = fields.ContainerStatus.STOPPED
|
||||
return container
|
||||
except errors.APIError:
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# 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-env-to-container
|
||||
|
||||
Revision ID: 5977879072a7
|
||||
Revises: 417917e778f5
|
||||
Create Date: 2015-11-26 04:10:39.462966
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '5977879072a7'
|
||||
down_revision = '417917e778f5'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column('container', sa.Column('environment',
|
||||
sa.Text(), nullable=True))
|
|
@ -196,6 +196,7 @@ class Container(Base):
|
|||
bay_uuid = Column(String(36))
|
||||
status = Column(String(20))
|
||||
memory = Column(String(255))
|
||||
environment = Column(JSONEncodedDict)
|
||||
|
||||
|
||||
class Node(Base):
|
||||
|
|
|
@ -23,7 +23,8 @@ class Container(base.MagnumPersistentObject, base.MagnumObject,
|
|||
base.MagnumObjectDictCompat):
|
||||
# Version 1.0: Initial version
|
||||
# Version 1.1: Add memory field
|
||||
VERSION = '1.1'
|
||||
# Version 1.2: Add environment field
|
||||
VERSION = '1.2'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
|
||||
|
@ -38,6 +39,7 @@ class Container(base.MagnumPersistentObject, base.MagnumObject,
|
|||
'bay_uuid': fields.StringField(nullable=True),
|
||||
'status': m_fields.ContainerStatusField(nullable=True),
|
||||
'memory': fields.StringField(nullable=True),
|
||||
'environment': fields.DictOfStringsField(nullable=True),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -45,7 +45,8 @@ class TestContainerController(api_base.FunctionalTest):
|
|||
|
||||
params = ('{"name": "My Docker", "image": "ubuntu",'
|
||||
'"command": "env", "memory": "512m",'
|
||||
'"bay_uuid": "fff114da-3bfa-4a0f-a123-c0dffad9718e"}')
|
||||
'"bay_uuid": "fff114da-3bfa-4a0f-a123-c0dffad9718e",'
|
||||
'"environment": {"key1": "val1", "key2": "val2"}}')
|
||||
response = self.app.post('/v1/containers',
|
||||
params=params,
|
||||
content_type='application/json')
|
||||
|
@ -64,7 +65,8 @@ class TestContainerController(api_base.FunctionalTest):
|
|||
|
||||
params = ('{"name": "My Docker", "image": "ubuntu",'
|
||||
'"command": "env", "memory": "512m",'
|
||||
'"bay_uuid": "fff114da-3bfa-4a0f-a123-c0dffad9718e"}')
|
||||
'"bay_uuid": "fff114da-3bfa-4a0f-a123-c0dffad9718e",'
|
||||
'"environment": {"key1": "val1", "key2": "val2"}}')
|
||||
self.app.post('/v1/containers',
|
||||
params=params,
|
||||
content_type='application/json')
|
||||
|
@ -80,7 +82,8 @@ class TestContainerController(api_base.FunctionalTest):
|
|||
# Create a container with a command
|
||||
params = ('{"name": "My Docker", "image": "ubuntu",'
|
||||
'"command": "env", "memory": "512m",'
|
||||
'"bay_uuid": "fff114da-3bfa-4a0f-a123-c0dffad9718e"}')
|
||||
'"bay_uuid": "fff114da-3bfa-4a0f-a123-c0dffad9718e",'
|
||||
'"environment": {"key1": "val1", "key2": "val2"}}')
|
||||
response = self.app.post('/v1/containers',
|
||||
params=params,
|
||||
content_type='application/json')
|
||||
|
@ -98,6 +101,8 @@ class TestContainerController(api_base.FunctionalTest):
|
|||
self.assertEqual('env', c.get('command'))
|
||||
self.assertEqual('Stopped', c.get('status'))
|
||||
self.assertEqual('512m', c.get('memory'))
|
||||
self.assertEqual({"key1": "val1", "key2": "val2"},
|
||||
c.get('environment'))
|
||||
# Delete the container we created
|
||||
response = self.app.delete('/v1/containers/%s' % c.get('uuid'))
|
||||
self.assertEqual(204, response.status_int)
|
||||
|
@ -119,7 +124,8 @@ class TestContainerController(api_base.FunctionalTest):
|
|||
# Create a container with a command
|
||||
params = ('{"name": "My Docker", "image": "ubuntu",'
|
||||
'"command": "env", "memory": "512m",'
|
||||
'"bay_uuid": "fff114da-3bfa-4a0f-a123-c0dffad9718e"}')
|
||||
'"bay_uuid": "fff114da-3bfa-4a0f-a123-c0dffad9718e",'
|
||||
'"environment": {"key1": "val1", "key2": "val2"}}')
|
||||
response = self.app.post('/v1/containers',
|
||||
params=params,
|
||||
content_type='application/json')
|
||||
|
@ -137,6 +143,8 @@ class TestContainerController(api_base.FunctionalTest):
|
|||
self.assertEqual('env', c.get('command'))
|
||||
self.assertEqual('Stopped', c.get('status'))
|
||||
self.assertEqual('512m', c.get('memory'))
|
||||
self.assertEqual({"key1": "val1", "key2": "val2"},
|
||||
c.get('environment'))
|
||||
# Delete the container we created
|
||||
response = self.app.delete('/v1/containers/%s' % c.get('uuid'))
|
||||
self.assertEqual(204, response.status_int)
|
||||
|
@ -156,7 +164,8 @@ class TestContainerController(api_base.FunctionalTest):
|
|||
# Create a container with a command
|
||||
params = ('{"name": "My Docker", "image": "ubuntu",'
|
||||
'"command": "env",'
|
||||
'"bay_uuid": "fff114da-3bfa-4a0f-a123-c0dffad9718e"}')
|
||||
'"bay_uuid": "fff114da-3bfa-4a0f-a123-c0dffad9718e",'
|
||||
'"environment": {"key1": "val1", "key2": "val2"}}')
|
||||
response = self.app.post('/v1/containers',
|
||||
params=params,
|
||||
content_type='application/json')
|
||||
|
@ -174,12 +183,44 @@ class TestContainerController(api_base.FunctionalTest):
|
|||
self.assertEqual('env', c.get('command'))
|
||||
self.assertEqual('Stopped', c.get('status'))
|
||||
self.assertIsNone(c.get('memory'))
|
||||
self.assertEqual({"key1": "val1", "key2": "val2"},
|
||||
c.get('environment'))
|
||||
|
||||
@patch('magnum.conductor.api.API.container_show')
|
||||
@patch('magnum.conductor.api.API.container_create')
|
||||
def test_create_container_without_environment(self,
|
||||
mock_container_create,
|
||||
mock_container_show):
|
||||
mock_container_create.side_effect = lambda x: x
|
||||
# Create a container with a command
|
||||
params = ('{"name": "My Docker", "image": "ubuntu",'
|
||||
'"command": "env", "memory": "512m",'
|
||||
'"bay_uuid": "fff114da-3bfa-4a0f-a123-c0dffad9718e"}')
|
||||
response = self.app.post('/v1/containers',
|
||||
params=params,
|
||||
content_type='application/json')
|
||||
self.assertEqual(201, response.status_int)
|
||||
# get all containers
|
||||
container = objects.Container.list(self.context)[0]
|
||||
container.status = 'Stopped'
|
||||
mock_container_show.return_value = container
|
||||
response = self.app.get('/v1/containers')
|
||||
self.assertEqual(200, response.status_int)
|
||||
self.assertEqual(1, len(response.json))
|
||||
c = response.json['containers'][0]
|
||||
self.assertIsNotNone(c.get('uuid'))
|
||||
self.assertEqual('My Docker', c.get('name'))
|
||||
self.assertEqual('env', c.get('command'))
|
||||
self.assertEqual('Stopped', c.get('status'))
|
||||
self.assertEqual('512m', c.get('memory'))
|
||||
self.assertEqual({}, c.get('environment'))
|
||||
|
||||
@patch('magnum.conductor.api.API.container_create')
|
||||
def test_create_container_without_name(self, mock_container_create):
|
||||
# No name param
|
||||
params = ('{"image": "ubuntu", "command": "env", "memory": "512m",'
|
||||
'"bay_uuid": "fff114da-3bfa-4a0f-a123-c0dffad9718e"}')
|
||||
'"bay_uuid": "fff114da-3bfa-4a0f-a123-c0dffad9718e",'
|
||||
'"environment": {"key1": "val1", "key2": "val2"}}')
|
||||
self.assertRaises(AppError, self.app.post, '/v1/containers',
|
||||
params=params, content_type='application/json')
|
||||
self.assertTrue(mock_container_create.not_called)
|
||||
|
@ -263,6 +304,7 @@ class TestContainerController(api_base.FunctionalTest):
|
|||
self.assertIn('image', actual_containers[0])
|
||||
self.assertIn('command', actual_containers[0])
|
||||
self.assertIn('memory', actual_containers[0])
|
||||
self.assertIn('environment', actual_containers[0])
|
||||
|
||||
@patch('magnum.conductor.api.API.container_show')
|
||||
@patch('magnum.objects.Container.list')
|
||||
|
|
|
@ -47,6 +47,7 @@ class TestDockerHandler(base.BaseTestCase):
|
|||
mock_container.image = 'test_image:some_tag'
|
||||
mock_container.command = None
|
||||
mock_container.memory = None
|
||||
mock_container.environment = None
|
||||
|
||||
container = self.conductor.container_create(
|
||||
None, mock_container)
|
||||
|
@ -60,7 +61,8 @@ class TestDockerHandler(base.BaseTestCase):
|
|||
name='some-name',
|
||||
hostname='some-uuid',
|
||||
command=None,
|
||||
mem_limit=None)
|
||||
mem_limit=None,
|
||||
environment=None)
|
||||
self.assertEqual(fields.ContainerStatus.STOPPED, container.status)
|
||||
|
||||
def test_container_create_with_command(self):
|
||||
|
@ -70,6 +72,7 @@ class TestDockerHandler(base.BaseTestCase):
|
|||
mock_container.image = 'test_image:some_tag'
|
||||
mock_container.command = 'env'
|
||||
mock_container.memory = None
|
||||
mock_container.environment = None
|
||||
|
||||
container = self.conductor.container_create(
|
||||
None, mock_container)
|
||||
|
@ -83,7 +86,8 @@ class TestDockerHandler(base.BaseTestCase):
|
|||
name='some-name',
|
||||
hostname='some-uuid',
|
||||
command='env',
|
||||
mem_limit=None)
|
||||
mem_limit=None,
|
||||
environment=None)
|
||||
self.assertEqual(fields.ContainerStatus.STOPPED, container.status)
|
||||
|
||||
def test_container_create_with_memory(self):
|
||||
|
@ -93,7 +97,7 @@ class TestDockerHandler(base.BaseTestCase):
|
|||
mock_container.image = 'test_image:some_tag'
|
||||
mock_container.command = None
|
||||
mock_container.memory = '512m'
|
||||
|
||||
mock_container.environment = None
|
||||
container = self.conductor.container_create(
|
||||
None, mock_container)
|
||||
|
||||
|
@ -106,7 +110,32 @@ class TestDockerHandler(base.BaseTestCase):
|
|||
name='some-name',
|
||||
hostname='some-uuid',
|
||||
command=None,
|
||||
mem_limit='512m')
|
||||
mem_limit='512m',
|
||||
environment=None)
|
||||
self.assertEqual(fields.ContainerStatus.STOPPED, container.status)
|
||||
|
||||
def test_container_create_with_environment(self):
|
||||
mock_container = mock.MagicMock()
|
||||
mock_container.name = 'some-name'
|
||||
mock_container.uuid = 'some-uuid'
|
||||
mock_container.image = 'test_image:some_tag'
|
||||
mock_container.command = None
|
||||
mock_container.memory = '512m'
|
||||
mock_container.environment = {'key1': 'val1', 'key2': 'val2'}
|
||||
container = self.conductor.container_create(
|
||||
None, mock_container)
|
||||
|
||||
utf8_image = self.conductor._encode_utf8(mock_container.image)
|
||||
self.mock_docker.pull.assert_called_once_with('test_image',
|
||||
tag='some_tag')
|
||||
self.mock_docker.inspect_image.assert_called_once_with(utf8_image)
|
||||
self.mock_docker.create_container.assert_called_once_with(
|
||||
mock_container.image,
|
||||
name='some-name',
|
||||
hostname='some-uuid',
|
||||
command=None,
|
||||
mem_limit='512m',
|
||||
environment={'key1': 'val1', 'key2': 'val2'})
|
||||
self.assertEqual(fields.ContainerStatus.STOPPED, container.status)
|
||||
|
||||
def test_encode_utf8_unicode(self):
|
||||
|
|
|
@ -222,6 +222,7 @@ def get_test_container(**kw):
|
|||
'bay_uuid': kw.get('bay_uuid', 'fff114da-3bfa-4a0f-a123-c0dffad9718e'),
|
||||
'status': kw.get('state', 'Running'),
|
||||
'memory': kw.get('memory', '512m'),
|
||||
'environment': kw.get('environment', {'key1': 'val1', 'key2': 'val2'}),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -99,11 +99,13 @@ class TestContainerObject(base.DbTestCase):
|
|||
container = objects.Container.get_by_uuid(self.context, uuid)
|
||||
container.image = 'container.img'
|
||||
container.memory = '512m'
|
||||
container.environment = {"key1": "val", "key2": "val2"}
|
||||
container.save()
|
||||
|
||||
mock_get_container.assert_called_once_with(self.context, uuid)
|
||||
mock_update_container.assert_called_once_with(
|
||||
uuid, {'image': 'container.img', 'memory': '512m'})
|
||||
uuid, {'image': 'container.img', 'memory': '512m',
|
||||
'environment': {"key1": "val", "key2": "val2"}})
|
||||
self.assertEqual(self.context, container._context)
|
||||
|
||||
def test_refresh(self):
|
||||
|
|
|
@ -427,7 +427,7 @@ object_data = {
|
|||
'BayLock': '1.0-7d1eb08cf2070523bd210369c7a2e076',
|
||||
'BayModel': '1.8-a4bb0976be245f06edbd1db087a18071',
|
||||
'Certificate': '1.0-2aff667971b85c1edf8d15684fd7d5e2',
|
||||
'Container': '1.1-968c62bc65ee08027a2cdbba95f5819c',
|
||||
'Container': '1.2-fc9c7d7d89bfa72c0ed7a32597d41e82',
|
||||
'MyObj': '1.0-b43567e512438205e32f4e95ca616697',
|
||||
'Node': '1.0-30943e6e3387a2fae7490b57c4239a17',
|
||||
'Pod': '1.1-7a31c372f163742845c10a008f47cc15',
|
||||
|
|
Loading…
Reference in New Issue