docker.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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 3rd-party libs
  11. from salt._compat import ipaddress
  12. # Import Salt libs
  13. from salt.exceptions import CommandExecutionError
  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), self.net.num_addresses - 3
  28. )
  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. )
  40. def arg_map(self, arg_name):
  41. return {
  42. "ipv4_address": "IPv4Address",
  43. "ipv6_address": "IPv6Address",
  44. "links": "Links",
  45. "aliases": "Aliases",
  46. }[arg_name]
  47. @property
  48. def subnet(self):
  49. try:
  50. return self.net.compressed
  51. except AttributeError:
  52. return None
  53. @property
  54. def gateway(self):
  55. try:
  56. return self.kwargs["gateway"]
  57. except KeyError:
  58. try:
  59. return self.net[1].compressed
  60. except (AttributeError, IndexError):
  61. return None
  62. class with_network(object):
  63. """
  64. Generate a network for the test. Information about the network will be
  65. passed to the wrapped function.
  66. """
  67. def __init__(self, **kwargs):
  68. self.create = kwargs.pop("create", False)
  69. self.network = Network(random_name(prefix="salt_net_"), **kwargs)
  70. if self.network.net is not None:
  71. if "enable_ipv6" not in kwargs:
  72. kwargs["enable_ipv6"] = self.network.net.version == 6
  73. self.kwargs = kwargs
  74. def __call__(self, func):
  75. self.func = func
  76. return functools.wraps(func)(
  77. # pylint: disable=W0108
  78. lambda testcase, *args, **kwargs: self.wrap(testcase, *args, **kwargs)
  79. # pylint: enable=W0108
  80. )
  81. def wrap(self, testcase, *args, **kwargs):
  82. if self.create:
  83. testcase.run_function(
  84. "docker.create_network", [self.network.name], **self.kwargs
  85. )
  86. try:
  87. return self.func(testcase, self.network, *args, **kwargs)
  88. finally:
  89. try:
  90. testcase.run_function(
  91. "docker.disconnect_all_containers_from_network", [self.network.name]
  92. )
  93. except CommandExecutionError as exc:
  94. if "404" not in exc.__str__():
  95. raise
  96. else:
  97. testcase.run_function("docker.remove_network", [self.network.name])