add support for creating volume and network with label definition

Signed-off-by: dbdd <wangtong2712@gmail.com>
This commit is contained in:
dbdd 2016-09-27 11:02:56 +08:00
parent 9248298a4a
commit bdcce13f4a
9 changed files with 211 additions and 5 deletions

View File

@ -361,6 +361,9 @@ def load_mapping(config_files, get_func, entity_type):
config['driver_opts']
)
if 'labels' in config:
config['labels'] = parse_labels(config['labels'])
return mapping

View File

@ -246,7 +246,8 @@
"name": {"type": "string"}
},
"additionalProperties": false
}
},
"labels": {"$ref": "#/definitions/list_or_dict"}
},
"additionalProperties": false
},
@ -268,6 +269,7 @@
"name": {"type": "string"}
}
},
"labels": {"$ref": "#/definitions/list_or_dict"},
"additionalProperties": false
},
"additionalProperties": false

View File

@ -15,7 +15,7 @@ log = logging.getLogger(__name__)
class Network(object):
def __init__(self, client, project, name, driver=None, driver_opts=None,
ipam=None, external_name=None, internal=False):
ipam=None, external_name=None, internal=False, labels=None):
self.client = client
self.project = project
self.name = name
@ -24,6 +24,7 @@ class Network(object):
self.ipam = create_ipam_config_from_dict(ipam)
self.external_name = external_name
self.internal = internal
self.labels = labels
def ensure(self):
if self.external_name:
@ -70,6 +71,7 @@ class Network(object):
options=self.driver_opts,
ipam=self.ipam,
internal=self.internal,
labels=self.labels,
)
def remove(self):
@ -118,6 +120,7 @@ def build_networks(name, config_data, client):
ipam=data.get('ipam'),
external_name=data.get('external_name'),
internal=data.get('internal'),
labels=data.get('labels'),
)
for network_name, data in network_config.items()
}

View File

@ -12,17 +12,18 @@ log = logging.getLogger(__name__)
class Volume(object):
def __init__(self, client, project, name, driver=None, driver_opts=None,
external_name=None):
external_name=None, labels=None):
self.client = client
self.project = project
self.name = name
self.driver = driver
self.driver_opts = driver_opts
self.external_name = external_name
self.labels = labels
def create(self):
return self.client.create_volume(
self.full_name, self.driver, self.driver_opts
self.full_name, self.driver, self.driver_opts, labels=self.labels
)
def remove(self):
@ -68,7 +69,8 @@ class ProjectVolumes(object):
name=vol_name,
driver=data.get('driver'),
driver_opts=data.get('driver_opts'),
external_name=data.get('external_name')
external_name=data.get('external_name'),
labels=data.get('labels')
)
for vol_name, data in config_volumes.items()
}

View File

@ -22,6 +22,7 @@ from compose.project import OneOffFilter
from tests.integration.testcases import DockerClientTestCase
from tests.integration.testcases import get_links
from tests.integration.testcases import pull_busybox
from tests.integration.testcases import v2_1_only
from tests.integration.testcases import v2_only
@ -767,6 +768,46 @@ class CLITestCase(DockerClientTestCase):
container = self.project.containers()[0]
assert list(container.get('NetworkSettings.Networks')) == [network_name]
@v2_1_only()
def test_up_with_network_labels(self):
filename = 'network-label.yml'
self.base_dir = 'tests/fixtures/networks'
self._project = get_project(self.base_dir, [filename])
self.dispatch(['-f', filename, 'up', '-d'], returncode=0)
network_with_label = '{}_network_with_label'.format(self.project.name)
networks = [
n for n in self.client.networks()
if n['Name'].startswith('{}_'.format(self.project.name))
]
assert [n['Name'] for n in networks] == [network_with_label]
assert networks[0]['Labels'] == {'label_key': 'label_val'}
@v2_1_only()
def test_up_with_volume_labels(self):
filename = 'volume-label.yml'
self.base_dir = 'tests/fixtures/volumes'
self._project = get_project(self.base_dir, [filename])
self.dispatch(['-f', filename, 'up', '-d'], returncode=0)
volume_with_label = '{}_volume_with_label'.format(self.project.name)
volumes = [
v for v in self.client.volumes().get('Volumes', [])
if v['Name'].startswith('{}_'.format(self.project.name))
]
assert [v['Name'] for v in volumes] == [volume_with_label]
assert volumes[0]['Labels'] == {'label_key': 'label_val'}
@v2_only()
def test_up_no_services(self):
self.base_dir = 'tests/fixtures/no-services'

View File

@ -0,0 +1,13 @@
version: "2.1"
services:
web:
image: busybox
command: top
networks:
- network_with_label
networks:
network_with_label:
labels:
- "label_key=label_val"

13
tests/fixtures/volumes/volume-label.yml vendored Normal file
View File

@ -0,0 +1,13 @@
version: "2.1"
services:
web:
image: busybox
command: top
volumes:
- volume_with_label:/data
volumes:
volume_with_label:
labels:
- "label_key=label_val"

View File

@ -821,6 +821,42 @@ class ProjectTest(DockerClientTestCase):
assert network['Internal'] is True
@v2_1_only()
def test_project_up_with_network_label(self):
self.require_api_version('1.23')
network_name = 'network_with_label'
config_data = config.Config(
version=V2_0,
services=[{
'name': 'web',
'image': 'busybox:latest',
'networks': {network_name: None}
}],
volumes={},
networks={
network_name: {'labels': {'label_key': 'label_val'}}
}
)
project = Project.from_config(
client=self.client,
name='composetest',
config_data=config_data
)
project.up()
networks = [
n for n in self.client.networks()
if n['Name'].startswith('composetest_')
]
assert [n['Name'] for n in networks] == ['composetest_{}'.format(network_name)]
assert networks[0]['Labels'] == {'label_key': 'label_val'}
@v2_only()
def test_project_up_volumes(self):
vol_name = '{0:x}'.format(random.getrandbits(32))
@ -847,6 +883,46 @@ class ProjectTest(DockerClientTestCase):
self.assertEqual(volume_data['Name'], full_vol_name)
self.assertEqual(volume_data['Driver'], 'local')
@v2_1_only()
def test_project_up_with_volume_labels(self):
self.require_api_version('1.23')
volume_name = 'volume_with_label'
config_data = config.Config(
version=V2_0,
services=[{
'name': 'web',
'image': 'busybox:latest',
'volumes': [VolumeSpec.parse('{}:/data'.format(volume_name))]
}],
volumes={
volume_name: {
'labels': {
'label_key': 'label_val'
}
}
},
networks={},
)
project = Project.from_config(
client=self.client,
name='composetest',
config_data=config_data,
)
project.up()
volumes = [
v for v in self.client.volumes().get('Volumes', [])
if v['Name'].startswith('composetest_')
]
assert [v['Name'] for v in volumes] == ['composetest_{}'.format(volume_name)]
assert volumes[0]['Labels'] == {'label_key': 'label_val'}
@v2_only()
def test_project_up_logging_with_multiple_files(self):
base_file = config.ConfigFile(

View File

@ -376,6 +376,59 @@ class ConfigTest(unittest.TestCase):
}
}
def test_load_config_volume_and_network_labels(self):
base_file = config.ConfigFile(
'base.yaml',
{
'version': '2.1',
'services': {
'web': {
'image': 'example/web',
},
},
'networks': {
'with_label': {
'labels': {
'label_key': 'label_val'
}
}
},
'volumes': {
'with_label': {
'labels': {
'label_key': 'label_val'
}
}
}
}
)
details = config.ConfigDetails('.', [base_file])
network_dict = config.load(details).networks
volume_dict = config.load(details).volumes
self.assertEqual(
network_dict,
{
'with_label': {
'labels': {
'label_key': 'label_val'
}
}
}
)
self.assertEqual(
volume_dict,
{
'with_label': {
'labels': {
'label_key': 'label_val'
}
}
}
)
def test_load_config_invalid_service_names(self):
for invalid_name in ['?not?allowed', ' ', '', '!', '/', '\xe2']:
with pytest.raises(ConfigurationError) as exc: