# -*- coding: utf-8 -*- ''' Common code used in Docker integration tests ''' # Import Python libs from __future__ import absolute_import, print_function, unicode_literals 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])