Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

context.py 7.7KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. import os
  2. import json
  3. from shutil import copyfile, rmtree
  4. from docker.tls import TLSConfig
  5. from docker.errors import ContextException
  6. from docker.context.config import get_meta_dir
  7. from docker.context.config import get_meta_file
  8. from docker.context.config import get_tls_dir
  9. from docker.context.config import get_context_host
  10. class Context:
  11. """A context."""
  12. def __init__(self, name, orchestrator=None, host=None, endpoints=None,
  13. tls=False):
  14. if not name:
  15. raise Exception("Name not provided")
  16. self.name = name
  17. self.context_type = None
  18. self.orchestrator = orchestrator
  19. self.endpoints = {}
  20. self.tls_cfg = {}
  21. self.meta_path = "IN MEMORY"
  22. self.tls_path = "IN MEMORY"
  23. if not endpoints:
  24. # set default docker endpoint if no endpoint is set
  25. default_endpoint = "docker" if (
  26. not orchestrator or orchestrator == "swarm"
  27. ) else orchestrator
  28. self.endpoints = {
  29. default_endpoint: {
  30. "Host": get_context_host(host, tls),
  31. "SkipTLSVerify": not tls
  32. }
  33. }
  34. return
  35. # check docker endpoints
  36. for k, v in endpoints.items():
  37. if not isinstance(v, dict):
  38. # unknown format
  39. raise ContextException("""Unknown endpoint format for
  40. context {}: {}""".format(name, v))
  41. self.endpoints[k] = v
  42. if k != "docker":
  43. continue
  44. self.endpoints[k]["Host"] = v.get("Host", get_context_host(
  45. host, tls))
  46. self.endpoints[k]["SkipTLSVerify"] = bool(v.get(
  47. "SkipTLSVerify", not tls))
  48. def set_endpoint(
  49. self, name="docker", host=None, tls_cfg=None,
  50. skip_tls_verify=False, def_namespace=None):
  51. self.endpoints[name] = {
  52. "Host": get_context_host(host, not skip_tls_verify),
  53. "SkipTLSVerify": skip_tls_verify
  54. }
  55. if def_namespace:
  56. self.endpoints[name]["DefaultNamespace"] = def_namespace
  57. if tls_cfg:
  58. self.tls_cfg[name] = tls_cfg
  59. def inspect(self):
  60. return self.__call__()
  61. @classmethod
  62. def load_context(cls, name):
  63. meta = Context._load_meta(name)
  64. if meta:
  65. instance = cls(
  66. meta["Name"],
  67. orchestrator=meta["Metadata"].get("StackOrchestrator", None),
  68. endpoints=meta.get("Endpoints", None))
  69. instance.context_type = meta["Metadata"].get("Type", None)
  70. instance._load_certs()
  71. instance.meta_path = get_meta_dir(name)
  72. return instance
  73. return None
  74. @classmethod
  75. def _load_meta(cls, name):
  76. meta_file = get_meta_file(name)
  77. if not os.path.isfile(meta_file):
  78. return None
  79. metadata = {}
  80. try:
  81. with open(meta_file) as f:
  82. metadata = json.load(f)
  83. except (OSError, KeyError, ValueError) as e:
  84. # unknown format
  85. raise Exception("""Detected corrupted meta file for
  86. context {} : {}""".format(name, e))
  87. # for docker endpoints, set defaults for
  88. # Host and SkipTLSVerify fields
  89. for k, v in metadata["Endpoints"].items():
  90. if k != "docker":
  91. continue
  92. metadata["Endpoints"][k]["Host"] = v.get(
  93. "Host", get_context_host(None, False))
  94. metadata["Endpoints"][k]["SkipTLSVerify"] = bool(
  95. v.get("SkipTLSVerify", True))
  96. return metadata
  97. def _load_certs(self):
  98. certs = {}
  99. tls_dir = get_tls_dir(self.name)
  100. for endpoint in self.endpoints.keys():
  101. if not os.path.isdir(os.path.join(tls_dir, endpoint)):
  102. continue
  103. ca_cert = None
  104. cert = None
  105. key = None
  106. for filename in os.listdir(os.path.join(tls_dir, endpoint)):
  107. if filename.startswith("ca"):
  108. ca_cert = os.path.join(tls_dir, endpoint, filename)
  109. elif filename.startswith("cert"):
  110. cert = os.path.join(tls_dir, endpoint, filename)
  111. elif filename.startswith("key"):
  112. key = os.path.join(tls_dir, endpoint, filename)
  113. if all([ca_cert, cert, key]):
  114. verify = None
  115. if endpoint == "docker" and not self.endpoints["docker"].get(
  116. "SkipTLSVerify", False):
  117. verify = True
  118. certs[endpoint] = TLSConfig(
  119. client_cert=(cert, key), ca_cert=ca_cert, verify=verify)
  120. self.tls_cfg = certs
  121. self.tls_path = tls_dir
  122. def save(self):
  123. meta_dir = get_meta_dir(self.name)
  124. if not os.path.isdir(meta_dir):
  125. os.makedirs(meta_dir)
  126. with open(get_meta_file(self.name), "w") as f:
  127. f.write(json.dumps(self.Metadata))
  128. tls_dir = get_tls_dir(self.name)
  129. for endpoint, tls in self.tls_cfg.items():
  130. if not os.path.isdir(os.path.join(tls_dir, endpoint)):
  131. os.makedirs(os.path.join(tls_dir, endpoint))
  132. ca_file = tls.ca_cert
  133. if ca_file:
  134. copyfile(ca_file, os.path.join(
  135. tls_dir, endpoint, os.path.basename(ca_file)))
  136. if tls.cert:
  137. cert_file, key_file = tls.cert
  138. copyfile(cert_file, os.path.join(
  139. tls_dir, endpoint, os.path.basename(cert_file)))
  140. copyfile(key_file, os.path.join(
  141. tls_dir, endpoint, os.path.basename(key_file)))
  142. self.meta_path = get_meta_dir(self.name)
  143. self.tls_path = get_tls_dir(self.name)
  144. def remove(self):
  145. if os.path.isdir(self.meta_path):
  146. rmtree(self.meta_path)
  147. if os.path.isdir(self.tls_path):
  148. rmtree(self.tls_path)
  149. def __repr__(self):
  150. return f"<{self.__class__.__name__}: '{self.name}'>"
  151. def __str__(self):
  152. return json.dumps(self.__call__(), indent=2)
  153. def __call__(self):
  154. result = self.Metadata
  155. result.update(self.TLSMaterial)
  156. result.update(self.Storage)
  157. return result
  158. def is_docker_host(self):
  159. return self.context_type is None
  160. @property
  161. def Name(self):
  162. return self.name
  163. @property
  164. def Host(self):
  165. if not self.orchestrator or self.orchestrator == "swarm":
  166. endpoint = self.endpoints.get("docker", None)
  167. if endpoint:
  168. return endpoint.get("Host", None)
  169. return None
  170. return self.endpoints[self.orchestrator].get("Host", None)
  171. @property
  172. def Orchestrator(self):
  173. return self.orchestrator
  174. @property
  175. def Metadata(self):
  176. meta = {}
  177. if self.orchestrator:
  178. meta = {"StackOrchestrator": self.orchestrator}
  179. return {
  180. "Name": self.name,
  181. "Metadata": meta,
  182. "Endpoints": self.endpoints
  183. }
  184. @property
  185. def TLSConfig(self):
  186. key = self.orchestrator
  187. if not key or key == "swarm":
  188. key = "docker"
  189. if key in self.tls_cfg.keys():
  190. return self.tls_cfg[key]
  191. return None
  192. @property
  193. def TLSMaterial(self):
  194. certs = {}
  195. for endpoint, tls in self.tls_cfg.items():
  196. cert, key = tls.cert
  197. certs[endpoint] = list(
  198. map(os.path.basename, [tls.ca_cert, cert, key]))
  199. return {
  200. "TLSMaterial": certs
  201. }
  202. @property
  203. def Storage(self):
  204. return {
  205. "Storage": {
  206. "MetadataPath": self.meta_path,
  207. "TLSPath": self.tls_path
  208. }}