interpolation.py 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import logging
  2. import os
  3. from string import Template
  4. import six
  5. from .errors import ConfigurationError
  6. log = logging.getLogger(__name__)
  7. def interpolate_environment_variables(config):
  8. mapping = BlankDefaultDict(os.environ)
  9. return dict(
  10. (service_name, process_service(service_name, service_dict, mapping))
  11. for (service_name, service_dict) in config.items()
  12. )
  13. def process_service(service_name, service_dict, mapping):
  14. if not isinstance(service_dict, dict):
  15. raise ConfigurationError(
  16. 'Service "%s" doesn\'t have any configuration options. '
  17. 'All top level keys in your docker-compose.yml must map '
  18. 'to a dictionary of configuration options.' % service_name
  19. )
  20. return dict(
  21. (key, interpolate_value(service_name, key, val, mapping))
  22. for (key, val) in service_dict.items()
  23. )
  24. def interpolate_value(service_name, config_key, value, mapping):
  25. try:
  26. return recursive_interpolate(value, mapping)
  27. except InvalidInterpolation as e:
  28. raise ConfigurationError(
  29. 'Invalid interpolation format for "{config_key}" option '
  30. 'in service "{service_name}": "{string}"'
  31. .format(
  32. config_key=config_key,
  33. service_name=service_name,
  34. string=e.string,
  35. )
  36. )
  37. def recursive_interpolate(obj, mapping):
  38. if isinstance(obj, six.string_types):
  39. return interpolate(obj, mapping)
  40. elif isinstance(obj, dict):
  41. return dict(
  42. (key, recursive_interpolate(val, mapping))
  43. for (key, val) in obj.items()
  44. )
  45. elif isinstance(obj, list):
  46. return [recursive_interpolate(val, mapping) for val in obj]
  47. else:
  48. return obj
  49. def interpolate(string, mapping):
  50. try:
  51. return Template(string).substitute(mapping)
  52. except ValueError:
  53. raise InvalidInterpolation(string)
  54. class BlankDefaultDict(dict):
  55. def __init__(self, *args, **kwargs):
  56. super(BlankDefaultDict, self).__init__(*args, **kwargs)
  57. self.missing_keys = []
  58. def __getitem__(self, key):
  59. try:
  60. return super(BlankDefaultDict, self).__getitem__(key)
  61. except KeyError:
  62. if key not in self.missing_keys:
  63. log.warn(
  64. "The {} variable is not set. Substituting a blank string."
  65. .format(key)
  66. )
  67. self.missing_keys.append(key)
  68. return ""
  69. class InvalidInterpolation(Exception):
  70. def __init__(self, string):
  71. self.string = string