salt/tests/support/docker.py
Erik Johnson 64aa4fbbec
Many improvements to docker network and container states
Much Improved Support for Docker Networking
===========================================

The `docker_network.present` state has undergone a full rewrite, which
includes the following improvements:

Full API Support for Network Management
---------------------------------------

The improvements made to input handling in the
`docker_container.running` state for 2017.7.0 have now been expanded to
docker_network.present`.  This brings with it full support for all
tunable configuration arguments.

Custom Subnets
--------------

Custom subnets can now be configured. Both IPv4 and mixed IPv4/IPv6
networks are supported.

Network Configuration in :py:func:`docker_container.running` States
-------------------------------------------------------------------

It is now possible to configure static IPv4/IPv6 addresses, as well as
links and labels.

Improved Handling of Images from Custom Registries
==================================================

Rather than attempting to parse the tag from the passed image name, Salt
will now resolve that tag down to an image ID and use that ID instead.

Due to this change, there are some backward-incompatible changes to
image management. See below for a full list of these changes.

Backward-incompatible Changes to Docker Image Management
--------------------------------------------------------

Passing image names to the following functions must now be done using separate
`repository` and `tag` arguments:

- `docker.build`
- `docker.commit`
- `docker.import`
- `docker.load`
- `docker.tag`
- `docker.sls_build`

Additionally, the `tag` argument must now be explicitly passed to the
`docker_image.present` state, unless the image is being pulled from a
docker registry.
2017-12-06 12:12:25 -06:00

110 lines
3.3 KiB
Python

# -*- coding: utf-8 -*-
'''
Common code used in Docker integration tests
'''
# Import Python libs
from __future__ import absolute_import
import functools
import random
import string
# Import Salt libs
from salt.exceptions import CommandExecutionError
# Import 3rd-party libs
from salt._compat import ipaddress
from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin
def random_name(prefix=''):
ret = prefix
for _ in range(8):
ret += random.choice(string.ascii_lowercase)
return ret
class Network(object):
def __init__(self, name, **kwargs):
self.kwargs = kwargs
self.name = name
try:
self.net = ipaddress.ip_network(self.kwargs['subnet'])
self._rand_indexes = random.sample(
range(2, self.net.num_addresses - 1),
self.net.num_addresses - 3)
self.ip_arg = 'ipv{0}_address'.format(self.net.version)
except KeyError:
# No explicit subnet passed
self.net = self.ip_arg = None
def __getitem__(self, index):
try:
return self.net[self._rand_indexes[index]].compressed
except (TypeError, AttributeError):
raise ValueError(
'Indexing not supported for networks without a custom subnet')
def arg_map(self, arg_name):
return {'ipv4_address': 'IPv4Address',
'ipv6_address': 'IPv6Address',
'links': 'Links',
'aliases': 'Aliases'}[arg_name]
@property
def subnet(self):
try:
return self.net.compressed
except AttributeError:
return None
@property
def gateway(self):
try:
return self.kwargs['gateway']
except KeyError:
try:
return self.net[1].compressed
except (AttributeError, IndexError):
return None
class with_network(object):
'''
Generate a network for the test. Information about the network will be
passed to the wrapped function.
'''
def __init__(self, **kwargs):
self.create = kwargs.pop('create', False)
self.network = Network(random_name(prefix='salt_net_'), **kwargs)
if self.network.net is not None:
if 'enable_ipv6' not in kwargs:
kwargs['enable_ipv6'] = self.network.net.version == 6
self.kwargs = kwargs
def __call__(self, func):
self.func = func
return functools.wraps(func)(
lambda testcase, *args, **kwargs: self.wrap(testcase, *args, **kwargs) # pylint: disable=W0108
)
def wrap(self, testcase, *args, **kwargs):
if self.create:
testcase.run_function(
'docker.create_network',
[self.network.name],
**self.kwargs)
try:
return self.func(testcase, self.network, *args, **kwargs)
finally:
try:
testcase.run_function(
'docker.disconnect_all_containers_from_network',
[self.network.name])
except CommandExecutionError as exc:
if '404' not in exc.__str__():
raise
else:
testcase.run_function(
'docker.remove_network',
[self.network.name])