Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes to compose syntax for volumes_from, volumes, and optional cpu parameter #42

36 changes: 35 additions & 1 deletion container_transform/compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,36 @@ def emit_entrypoint(self, entrypoint):
return entrypoint

def ingest_volumes_from(self, volumes_from):
return volumes_from
ingested_volumes_from = []
for vol in volumes_from:
ingested = {}
parts = vol.split(':')
rwo_value = None

assert(len(parts) <= 3)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add an explanation parameter to this assert so the error is a little more clear? ``assert(len(parts) <=3, "volume string '{}' has too many colons".format(vol))` or something like that?


if len(parts) == 3:
# Is form 'service:name:ro' or 'container:name:ro'
# in new compose v2 format.
source_container, rwo_value = parts[1:]
elif len(parts) == 2:
# Is form 'name:ro' or 'service:name' (for >= v2)
if self.stream_version > 1 and parts[0] == 'service':
source_container = parts[1]
else:
assert(parts[1] in ['ro', 'rw'])
source_container = parts[0]
rwo_value = parts[1]
else:
source_container = parts[0]

if rwo_value == 'ro':
ingested['read_only'] = True

ingested['source_container'] = source_container
ingested_volumes_from.append(ingested)

return ingested_volumes_from

def emit_volumes_from(self, volumes_from):
return volumes_from
Expand Down Expand Up @@ -249,6 +278,11 @@ def _ingest_volume(volume):
'container': parts[1],
'readonly': True
}
if len(parts) == 3 and parts[-1] == 'rw':
return {
'host': parts[0],
'container': parts[1],
}

def ingest_volumes(self, volumes):
return [
Expand Down
12 changes: 10 additions & 2 deletions container_transform/ecs.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import json
import uuid

from copy import copy

from .schema import TransformationTypes
from .transformer import BaseTransformer
Expand Down Expand Up @@ -193,7 +193,15 @@ def ingest_volumes_from(self, volumes_from):
return [vol['sourceContainer'] for vol in volumes_from]

def emit_volumes_from(self, volumes_from):
return [{'sourceContainer': vol} for vol in volumes_from]
emitted = []
volumes_from = copy(volumes_from)
for vol in volumes_from:
emit = {}
if vol.get('read_only'):
emit['readOnly'] = vol['read_only']
emit['sourceContainer'] = vol['source_container']
emitted.append(emit)
return emitted

def ingest_volumes_param(self, volumes):
"""
Expand Down
2 changes: 1 addition & 1 deletion container_transform/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class OutputTransformationTypes(Enum):
'cpu': {
TransformationTypes.ECS.value: {
'name': 'cpu',
'required': True
'required': False,
},
TransformationTypes.COMPOSE.value: {
'name': 'cpu_shares',
Expand Down
4 changes: 1 addition & 3 deletions container_transform/tests/client_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,7 @@ def test_prompt_fig_no_quiet(self):
messages = set(result.output.split('\n')[1:])

self.assertEqual(
{'Container web2 is missing required parameter "cpu".',
'Container web is missing required parameter "cpu".',
'Container web2 is missing required parameter "image".',
{'Container web2 is missing required parameter "image".',
''},
messages
)
Expand Down
19 changes: 19 additions & 0 deletions container_transform/tests/composev2_extended.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,22 @@ services:
labels:
- io.redis.name=redis
- io.redis.novalue
web2:
build: .
ports:
- "5001:5000"
volumes:
- .:/code
- /bob/:/codeforbob:rw
volumes_from:
- service:web
- service:redis:ro
labels:
com.example.name: "web"
com.example.emptyvalue: ""
logging:
driver: gelf
options:
tag: web
gelf-address: "udp://127.0.0.1:12900"

46 changes: 46 additions & 0 deletions container_transform/tests/composev2_extended_output.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,46 @@
"hostPort": 5000
}
]
},
{
"dockerLabels": {
"com.example.emptyvalue": "",
"com.example.name": "web"
},
"essential": true,
"logConfiguration": {
"logDriver": "gelf",
"options": {
"gelf-address": "udp://127.0.0.1:12900",
"tag": "web"
}
},
"mountPoints": [
{
"containerPath": "/code",
"sourceVolume": "_"
},
{
"containerPath": "/codeforbob",
"sourceVolume": "Bob"
}
],
"name": "web2",
"portMappings": [
{
"containerPort": 5000,
"hostPort": 5001
}
],
"volumesFrom": [
{
"sourceContainer": "web"
},
{
"readOnly": true,
"sourceContainer": "redis"
}
]
}
],
"family": "",
Expand All @@ -49,6 +89,12 @@
"sourcePath": "."
},
"name": "_"
},
{
"host": {
"sourcePath": "/bob/"
},
"name": "Bob"
}
]
}
11 changes: 11 additions & 0 deletions container_transform/tests/converter_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ def test_compose_converter_in(self):
conv = Converter(filename, 'compose', 'ecs')

output = conv.convert()
output_dict = json.loads(output)

# NOTE: We can't just check an output file because it appears the
# environment dictionary is being serialized in a non-deterministic
# order. TODO: Fix that.
for definition in output_dict['containerDefinitions']:
if definition['name'] == 'web4':
# Check read only volumes definition
volumesFrom = definition['volumesFrom']
self.assertIn({'sourceContainer': 'web3', 'readOnly': True}, volumesFrom)
self.assertIn({'sourceContainer': 'logs'}, volumesFrom)

self.assertIsInstance(output, str)

Expand Down
9 changes: 9 additions & 0 deletions container_transform/tests/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@ web3:
entrypoint: uwsgi
command: --json uwsgi.json
cpu_shares: 200
web4:
image: me/myapp
mem_limit: 1024
entrypoint: uwsgi
command: --json uwsgi.json
cpu_shares: 200
volumes_from:
- web3:ro
- logs:rw
dummy:
image: me/myapp
entrypoint: ["noop", "param0"]
Expand Down
2 changes: 1 addition & 1 deletion container_transform/transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
'environment': dict, # A simple key: value dictionary
'entrypoint': str, # An unsplit string
'command': str, # An unsplit string
'volumes_from': list, # A list of containers, ignoring read_only
'volumes_from': list, # A list of containers
'volumes': list, # A list of dict {'host': '/path', 'container': '/path', 'readonly': True}
}

Expand Down