mirror of
https://github.com/docker/compose.git
synced 2025-07-23 13:45:00 +02:00
add support for creating volume and network with label definition
Signed-off-by: dbdd <wangtong2712@gmail.com>
This commit is contained in:
parent
9248298a4a
commit
bdcce13f4a
@ -361,6 +361,9 @@ def load_mapping(config_files, get_func, entity_type):
|
|||||||
config['driver_opts']
|
config['driver_opts']
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if 'labels' in config:
|
||||||
|
config['labels'] = parse_labels(config['labels'])
|
||||||
|
|
||||||
return mapping
|
return mapping
|
||||||
|
|
||||||
|
|
||||||
|
@ -246,7 +246,8 @@
|
|||||||
"name": {"type": "string"}
|
"name": {"type": "string"}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
}
|
},
|
||||||
|
"labels": {"$ref": "#/definitions/list_or_dict"}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
@ -268,6 +269,7 @@
|
|||||||
"name": {"type": "string"}
|
"name": {"type": "string"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"labels": {"$ref": "#/definitions/list_or_dict"},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
@ -15,7 +15,7 @@ log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class Network(object):
|
class Network(object):
|
||||||
def __init__(self, client, project, name, driver=None, driver_opts=None,
|
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.client = client
|
||||||
self.project = project
|
self.project = project
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -24,6 +24,7 @@ class Network(object):
|
|||||||
self.ipam = create_ipam_config_from_dict(ipam)
|
self.ipam = create_ipam_config_from_dict(ipam)
|
||||||
self.external_name = external_name
|
self.external_name = external_name
|
||||||
self.internal = internal
|
self.internal = internal
|
||||||
|
self.labels = labels
|
||||||
|
|
||||||
def ensure(self):
|
def ensure(self):
|
||||||
if self.external_name:
|
if self.external_name:
|
||||||
@ -70,6 +71,7 @@ class Network(object):
|
|||||||
options=self.driver_opts,
|
options=self.driver_opts,
|
||||||
ipam=self.ipam,
|
ipam=self.ipam,
|
||||||
internal=self.internal,
|
internal=self.internal,
|
||||||
|
labels=self.labels,
|
||||||
)
|
)
|
||||||
|
|
||||||
def remove(self):
|
def remove(self):
|
||||||
@ -118,6 +120,7 @@ def build_networks(name, config_data, client):
|
|||||||
ipam=data.get('ipam'),
|
ipam=data.get('ipam'),
|
||||||
external_name=data.get('external_name'),
|
external_name=data.get('external_name'),
|
||||||
internal=data.get('internal'),
|
internal=data.get('internal'),
|
||||||
|
labels=data.get('labels'),
|
||||||
)
|
)
|
||||||
for network_name, data in network_config.items()
|
for network_name, data in network_config.items()
|
||||||
}
|
}
|
||||||
|
@ -12,17 +12,18 @@ log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class Volume(object):
|
class Volume(object):
|
||||||
def __init__(self, client, project, name, driver=None, driver_opts=None,
|
def __init__(self, client, project, name, driver=None, driver_opts=None,
|
||||||
external_name=None):
|
external_name=None, labels=None):
|
||||||
self.client = client
|
self.client = client
|
||||||
self.project = project
|
self.project = project
|
||||||
self.name = name
|
self.name = name
|
||||||
self.driver = driver
|
self.driver = driver
|
||||||
self.driver_opts = driver_opts
|
self.driver_opts = driver_opts
|
||||||
self.external_name = external_name
|
self.external_name = external_name
|
||||||
|
self.labels = labels
|
||||||
|
|
||||||
def create(self):
|
def create(self):
|
||||||
return self.client.create_volume(
|
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):
|
def remove(self):
|
||||||
@ -68,7 +69,8 @@ class ProjectVolumes(object):
|
|||||||
name=vol_name,
|
name=vol_name,
|
||||||
driver=data.get('driver'),
|
driver=data.get('driver'),
|
||||||
driver_opts=data.get('driver_opts'),
|
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()
|
for vol_name, data in config_volumes.items()
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ from compose.project import OneOffFilter
|
|||||||
from tests.integration.testcases import DockerClientTestCase
|
from tests.integration.testcases import DockerClientTestCase
|
||||||
from tests.integration.testcases import get_links
|
from tests.integration.testcases import get_links
|
||||||
from tests.integration.testcases import pull_busybox
|
from tests.integration.testcases import pull_busybox
|
||||||
|
from tests.integration.testcases import v2_1_only
|
||||||
from tests.integration.testcases import v2_only
|
from tests.integration.testcases import v2_only
|
||||||
|
|
||||||
|
|
||||||
@ -767,6 +768,46 @@ class CLITestCase(DockerClientTestCase):
|
|||||||
container = self.project.containers()[0]
|
container = self.project.containers()[0]
|
||||||
assert list(container.get('NetworkSettings.Networks')) == [network_name]
|
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()
|
@v2_only()
|
||||||
def test_up_no_services(self):
|
def test_up_no_services(self):
|
||||||
self.base_dir = 'tests/fixtures/no-services'
|
self.base_dir = 'tests/fixtures/no-services'
|
||||||
|
13
tests/fixtures/networks/network-label.yml
vendored
Normal file
13
tests/fixtures/networks/network-label.yml
vendored
Normal 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
13
tests/fixtures/volumes/volume-label.yml
vendored
Normal 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"
|
@ -821,6 +821,42 @@ class ProjectTest(DockerClientTestCase):
|
|||||||
|
|
||||||
assert network['Internal'] is True
|
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()
|
@v2_only()
|
||||||
def test_project_up_volumes(self):
|
def test_project_up_volumes(self):
|
||||||
vol_name = '{0:x}'.format(random.getrandbits(32))
|
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['Name'], full_vol_name)
|
||||||
self.assertEqual(volume_data['Driver'], 'local')
|
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()
|
@v2_only()
|
||||||
def test_project_up_logging_with_multiple_files(self):
|
def test_project_up_logging_with_multiple_files(self):
|
||||||
base_file = config.ConfigFile(
|
base_file = config.ConfigFile(
|
||||||
|
@ -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):
|
def test_load_config_invalid_service_names(self):
|
||||||
for invalid_name in ['?not?allowed', ' ', '', '!', '/', '\xe2']:
|
for invalid_name in ['?not?allowed', ' ', '', '!', '/', '\xe2']:
|
||||||
with pytest.raises(ConfigurationError) as exc:
|
with pytest.raises(ConfigurationError) as exc:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user