docker.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. # -*- coding: utf-8 -*-
  2. '''
  3. Common code used in Docker integration tests
  4. '''
  5. # Import Python libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. import functools
  8. import random
  9. import string
  10. # Import Salt libs
  11. from salt.exceptions import CommandExecutionError
  12. # Import 3rd-party libs
  13. from salt._compat import ipaddress
  14. from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin
  15. def random_name(prefix=''):
  16. ret = prefix
  17. for _ in range(8):
  18. ret += random.choice(string.ascii_lowercase)
  19. return ret
  20. class Network(object):
  21. def __init__(self, name, **kwargs):
  22. self.kwargs = kwargs
  23. self.name = name
  24. try:
  25. self.net = ipaddress.ip_network(self.kwargs['subnet'])
  26. self._rand_indexes = random.sample(
  27. range(2, self.net.num_addresses - 1),
  28. self.net.num_addresses - 3)
  29. self.ip_arg = 'ipv{0}_address'.format(self.net.version)
  30. except KeyError:
  31. # No explicit subnet passed
  32. self.net = self.ip_arg = None
  33. def __getitem__(self, index):
  34. try:
  35. return self.net[self._rand_indexes[index]].compressed
  36. except (TypeError, AttributeError):
  37. raise ValueError(
  38. 'Indexing not supported for networks without a custom subnet')
  39. def arg_map(self, arg_name):
  40. return {'ipv4_address': 'IPv4Address',
  41. 'ipv6_address': 'IPv6Address',
  42. 'links': 'Links',
  43. 'aliases': 'Aliases'}[arg_name]
  44. @property
  45. def subnet(self):
  46. try:
  47. return self.net.compressed
  48. except AttributeError:
  49. return None
  50. @property
  51. def gateway(self):
  52. try:
  53. return self.kwargs['gateway']
  54. except KeyError:
  55. try:
  56. return self.net[1].compressed
  57. except (AttributeError, IndexError):
  58. return None
  59. class with_network(object):
  60. '''
  61. Generate a network for the test. Information about the network will be
  62. passed to the wrapped function.
  63. '''
  64. def __init__(self, **kwargs):
  65. self.create = kwargs.pop('create', False)
  66. self.network = Network(random_name(prefix='salt_net_'), **kwargs)
  67. if self.network.net is not None:
  68. if 'enable_ipv6' not in kwargs:
  69. kwargs['enable_ipv6'] = self.network.net.version == 6
  70. self.kwargs = kwargs
  71. def __call__(self, func):
  72. self.func = func
  73. return functools.wraps(func)(
  74. lambda testcase, *args, **kwargs: self.wrap(testcase, *args, **kwargs) # pylint: disable=W0108
  75. )
  76. def wrap(self, testcase, *args, **kwargs):
  77. if self.create:
  78. testcase.run_function(
  79. 'docker.create_network',
  80. [self.network.name],
  81. **self.kwargs)
  82. try:
  83. return self.func(testcase, self.network, *args, **kwargs)
  84. finally:
  85. try:
  86. testcase.run_function(
  87. 'docker.disconnect_all_containers_from_network',
  88. [self.network.name])
  89. except CommandExecutionError as exc:
  90. if '404' not in exc.__str__():
  91. raise
  92. else:
  93. testcase.run_function(
  94. 'docker.remove_network',
  95. [self.network.name])