mirror of https://github.com/docker/compose.git
Implement 'labels' option
Signed-off-by: Aanand Prasad <aanand.prasad@gmail.com>
This commit is contained in:
parent
da71e01d30
commit
2e6bc078fb
|
@ -32,4 +32,4 @@ def docker_client():
|
|||
)
|
||||
|
||||
timeout = int(os.environ.get('DOCKER_CLIENT_TIMEOUT', 60))
|
||||
return Client(base_url=base_url, tls=tls_config, version='1.17', timeout=timeout)
|
||||
return Client(base_url=base_url, tls=tls_config, version='1.18', timeout=timeout)
|
||||
|
|
|
@ -18,6 +18,7 @@ DOCKER_CONFIG_KEYS = [
|
|||
'extra_hosts',
|
||||
'hostname',
|
||||
'image',
|
||||
'labels',
|
||||
'links',
|
||||
'mem_limit',
|
||||
'net',
|
||||
|
@ -180,6 +181,9 @@ def process_container_options(service_dict, working_dir=None):
|
|||
if 'build' in service_dict:
|
||||
service_dict['build'] = resolve_build_path(service_dict['build'], working_dir=working_dir)
|
||||
|
||||
if 'labels' in service_dict:
|
||||
service_dict['labels'] = parse_labels(service_dict['labels'])
|
||||
|
||||
return service_dict
|
||||
|
||||
|
||||
|
@ -198,6 +202,12 @@ def merge_service_dicts(base, override):
|
|||
override.get('volumes'),
|
||||
)
|
||||
|
||||
if 'labels' in base or 'labels' in override:
|
||||
d['labels'] = merge_labels(
|
||||
base.get('labels'),
|
||||
override.get('labels'),
|
||||
)
|
||||
|
||||
if 'image' in override and 'build' in d:
|
||||
del d['build']
|
||||
|
||||
|
@ -216,7 +226,7 @@ def merge_service_dicts(base, override):
|
|||
if key in base or key in override:
|
||||
d[key] = to_list(base.get(key)) + to_list(override.get(key))
|
||||
|
||||
already_merged_keys = ['environment', 'volumes'] + list_keys + list_or_string_keys
|
||||
already_merged_keys = ['environment', 'volumes', 'labels'] + list_keys + list_or_string_keys
|
||||
|
||||
for k in set(ALLOWED_KEYS) - set(already_merged_keys):
|
||||
if k in override:
|
||||
|
@ -385,6 +395,35 @@ def join_volume(pair):
|
|||
return ":".join((host, container))
|
||||
|
||||
|
||||
def merge_labels(base, override):
|
||||
labels = parse_labels(base)
|
||||
labels.update(parse_labels(override))
|
||||
return labels
|
||||
|
||||
|
||||
def parse_labels(labels):
|
||||
if not labels:
|
||||
return {}
|
||||
|
||||
if isinstance(labels, list):
|
||||
return dict(split_label(e) for e in labels)
|
||||
|
||||
if isinstance(labels, dict):
|
||||
return labels
|
||||
|
||||
raise ConfigurationError(
|
||||
"labels \"%s\" must be a list or mapping" %
|
||||
labels
|
||||
)
|
||||
|
||||
|
||||
def split_label(label):
|
||||
if '=' in label:
|
||||
return label.split('=', 1)
|
||||
else:
|
||||
return label, ''
|
||||
|
||||
|
||||
def expand_path(working_dir, path):
|
||||
return os.path.abspath(os.path.join(working_dir, path))
|
||||
|
||||
|
|
|
@ -79,6 +79,10 @@ class Container(object):
|
|||
return ', '.join(format_port(*item)
|
||||
for item in sorted(six.iteritems(self.ports)))
|
||||
|
||||
@property
|
||||
def labels(self):
|
||||
return self.get('Config.Labels') or {}
|
||||
|
||||
@property
|
||||
def human_readable_state(self):
|
||||
if self.is_running:
|
||||
|
|
|
@ -321,8 +321,8 @@ expose:
|
|||
- "5000"
|
||||
```
|
||||
|
||||
In the case of `environment`, Compose "merges" entries together with
|
||||
locally-defined values taking precedence:
|
||||
In the case of `environment` and `labels`, Compose "merges" entries together
|
||||
with locally-defined values taking precedence:
|
||||
|
||||
```yaml
|
||||
# original service
|
||||
|
|
|
@ -10,7 +10,7 @@ Compose with a `curl` command.
|
|||
|
||||
### Install Docker
|
||||
|
||||
First, install Docker version 1.3 or greater:
|
||||
First, install Docker version 1.6 or greater:
|
||||
|
||||
- [Instructions for Mac OS X](http://docs.docker.com/installation/mac/)
|
||||
- [Instructions for Ubuntu](http://docs.docker.com/installation/ubuntulinux/)
|
||||
|
|
18
docs/yml.md
18
docs/yml.md
|
@ -253,6 +253,24 @@ environment variables (DEBUG) with a new value, and the other one
|
|||
For more on `extends`, see the [tutorial](extends.md#example) and
|
||||
[reference](extends.md#reference).
|
||||
|
||||
### labels
|
||||
|
||||
Add metadata to containers using [Docker labels](http://docs.docker.com/userguide/labels-custom-metadata/). You can use either an array or a dictionary.
|
||||
|
||||
It's recommended that you use reverse-DNS notation to prevent your labels from conflicting with those used by other software.
|
||||
|
||||
```
|
||||
labels:
|
||||
com.example.description: "Accounting webapp"
|
||||
com.example.department: "Finance"
|
||||
com.example.label-with-empty-value: ""
|
||||
|
||||
labels:
|
||||
- "com.example.description=Accounting webapp"
|
||||
- "com.example.department=Finance"
|
||||
- "com.example.label-with-empty-value"
|
||||
```
|
||||
|
||||
### net
|
||||
|
||||
Networking mode. Use the same values as the docker client `--net` parameter.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
PyYAML==3.10
|
||||
docker-py==1.1.0
|
||||
docker-py==1.2.1
|
||||
dockerpty==0.3.2
|
||||
docopt==0.6.1
|
||||
requests==2.6.1
|
||||
|
|
2
setup.py
2
setup.py
|
@ -30,7 +30,7 @@ install_requires = [
|
|||
'requests >= 2.6.1, < 2.7',
|
||||
'texttable >= 0.8.1, < 0.9',
|
||||
'websocket-client >= 0.11.0, < 1.0',
|
||||
'docker-py >= 1.1.0, < 1.2',
|
||||
'docker-py >= 1.2.0, < 1.3',
|
||||
'dockerpty >= 0.3.2, < 0.4',
|
||||
'six >= 1.3.0, < 2',
|
||||
]
|
||||
|
|
|
@ -584,3 +584,30 @@ class ServiceTest(DockerClientTestCase):
|
|||
env = create_and_start_container(service).environment
|
||||
for k, v in {'FILE_DEF': 'F1', 'FILE_DEF_EMPTY': '', 'ENV_DEF': 'E3', 'NO_DEF': ''}.items():
|
||||
self.assertEqual(env[k], v)
|
||||
|
||||
def test_labels(self):
|
||||
labels_dict = {
|
||||
'com.example.description': "Accounting webapp",
|
||||
'com.example.department': "Finance",
|
||||
'com.example.label-with-empty-value': "",
|
||||
}
|
||||
|
||||
service = self.create_service('web', labels=labels_dict)
|
||||
labels = create_and_start_container(service).labels.items()
|
||||
for pair in labels_dict.items():
|
||||
self.assertIn(pair, labels)
|
||||
|
||||
labels_list = ["%s=%s" % pair for pair in labels_dict.items()]
|
||||
|
||||
service = self.create_service('web', labels=labels_list)
|
||||
labels = create_and_start_container(service).labels.items()
|
||||
for pair in labels_dict.items():
|
||||
self.assertIn(pair, labels)
|
||||
|
||||
def test_empty_labels(self):
|
||||
labels_list = ['foo', 'bar']
|
||||
|
||||
service = self.create_service('web', labels=labels_list)
|
||||
labels = create_and_start_container(service).labels.items()
|
||||
for name in labels_list:
|
||||
self.assertIn((name, ''), labels)
|
||||
|
|
|
@ -185,6 +185,47 @@ class MergeStringsOrListsTest(unittest.TestCase):
|
|||
self.assertEqual(set(service_dict['dns']), set(['8.8.8.8', '9.9.9.9']))
|
||||
|
||||
|
||||
class MergeLabelsTest(unittest.TestCase):
|
||||
def test_empty(self):
|
||||
service_dict = config.merge_service_dicts({}, {})
|
||||
self.assertNotIn('labels', service_dict)
|
||||
|
||||
def test_no_override(self):
|
||||
service_dict = config.merge_service_dicts(
|
||||
config.make_service_dict('foo', {'labels': ['foo=1', 'bar']}),
|
||||
config.make_service_dict('foo', {}),
|
||||
)
|
||||
self.assertEqual(service_dict['labels'], {'foo': '1', 'bar': ''})
|
||||
|
||||
def test_no_base(self):
|
||||
service_dict = config.merge_service_dicts(
|
||||
config.make_service_dict('foo', {}),
|
||||
config.make_service_dict('foo', {'labels': ['foo=2']}),
|
||||
)
|
||||
self.assertEqual(service_dict['labels'], {'foo': '2'})
|
||||
|
||||
def test_override_explicit_value(self):
|
||||
service_dict = config.merge_service_dicts(
|
||||
config.make_service_dict('foo', {'labels': ['foo=1', 'bar']}),
|
||||
config.make_service_dict('foo', {'labels': ['foo=2']}),
|
||||
)
|
||||
self.assertEqual(service_dict['labels'], {'foo': '2', 'bar': ''})
|
||||
|
||||
def test_add_explicit_value(self):
|
||||
service_dict = config.merge_service_dicts(
|
||||
config.make_service_dict('foo', {'labels': ['foo=1', 'bar']}),
|
||||
config.make_service_dict('foo', {'labels': ['bar=2']}),
|
||||
)
|
||||
self.assertEqual(service_dict['labels'], {'foo': '1', 'bar': '2'})
|
||||
|
||||
def test_remove_explicit_value(self):
|
||||
service_dict = config.merge_service_dicts(
|
||||
config.make_service_dict('foo', {'labels': ['foo=1', 'bar=2']}),
|
||||
config.make_service_dict('foo', {'labels': ['bar']}),
|
||||
)
|
||||
self.assertEqual(service_dict['labels'], {'foo': '1', 'bar': ''})
|
||||
|
||||
|
||||
class EnvTest(unittest.TestCase):
|
||||
def test_parse_environment_as_list(self):
|
||||
environment = [
|
||||
|
|
Loading…
Reference in New Issue