vm.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. """
  2. Licensed to the Apache Software Foundation (ASF) under one
  3. or more contributor license agreements. See the NOTICE file
  4. distributed with this work for additional information
  5. regarding copyright ownership. The ASF licenses this file
  6. to you under the Apache License, Version 2.0 (the
  7. "License"); you may not use this file except in compliance
  8. with the License. You may obtain a copy of the License at
  9. http://www.apache.org/licenses/LICENSE-2.0
  10. Unless required by applicable law or agreed to in writing, software
  11. distributed under the License is distributed on an "AS IS" BASIS,
  12. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. See the License for the specific language governing permissions and
  14. limitations under the License.
  15. """
  16. import subprocess
  17. import shutil
  18. from config import Config
  19. import os
  20. from docker import Docker
  21. from docker_image.launcher_agent import replace_conf
  22. class VM:
  23. """
  24. This class represents VM, including its network setting and the possible Docker instance list
  25. """
  26. def __init__(self, external_ip, domain_name, weave_dns_ip, weave_ip_mask):
  27. self.external_ip = external_ip
  28. self.domain_name = domain_name
  29. self.hostname = self._gce_get_hostname(domain_name)
  30. self.weave_domain_name = self._get_weave_domain_name(self.hostname)
  31. self.weave_dns_ip = weave_dns_ip
  32. self.weave_internal_ip = ""
  33. self.weave_ip_mask = weave_ip_mask
  34. self.docker_list = []
  35. def to_json(self):
  36. """
  37. create a map to hold the information of the VM instance
  38. :return: A map, which is JSON format object.
  39. """
  40. vm_json = {}
  41. vm_json["external_ip"] = self.external_ip
  42. vm_json["domain_name"] = self.domain_name
  43. vm_json["weave_dns_ip"] = self.weave_dns_ip
  44. vm_json["weave_internal_ip"] = self.weave_internal_ip
  45. vm_json["weave_domain_name"] = self.weave_domain_name
  46. vm_json["weave_ip_mask"] = self.weave_ip_mask
  47. vm_json["docker_list"] = []
  48. for docker in self.docker_list:
  49. vm_json["docker_list"].append(docker.to_json())
  50. return vm_json
  51. @staticmethod
  52. def load_from_json(json_data):
  53. """
  54. load the VM information from a JSON object
  55. :param json_data: a map, which is a JSON object
  56. :return: a VM object
  57. """
  58. external_ip = json_data["external_ip"]
  59. domain_name = json_data["domain_name"]
  60. weave_dns_ip = json_data["weave_dns_ip"]
  61. weave_internal_ip = json_data["weave_internal_ip"]
  62. weave_domain_name = json_data["weave_domain_name"]
  63. weave_ip_mask = json_data["weave_ip_mask"]
  64. docker_list = []
  65. for json_docker in json_data["docker_list"]:
  66. docker_list.append(Docker.load_from_json(json_docker))
  67. vm = VM(external_ip, domain_name, weave_dns_ip, weave_ip_mask)
  68. vm.docker_list = docker_list
  69. vm.weave_internal_ip = weave_internal_ip
  70. vm.weave_domain_name = weave_domain_name
  71. return vm
  72. def _get_weave_domain_name(self, hostname):
  73. """
  74. get the Weave domain name of the VM
  75. :param hostname: the hostname of the VM
  76. :return:the Weave domain name
  77. """
  78. return "{0}.weave.local".format(hostname)
  79. def _gce_get_hostname(self, domain_name):
  80. """
  81. The hostname of GCE VM is the first part of the internal domain name
  82. :param domain_name: the internal domain name of GCE VM
  83. :return: the hostname of GCE VM
  84. """
  85. return domain_name.split(".")[0]
  86. def get_ssh_output_file_path(self):
  87. """
  88. get the file name to hold the SSH output of the VM
  89. :return: a file name
  90. """
  91. vm_output_file_path = "{0}/vm-{1}-{2}".format(Config.ATTRIBUTES["output_folder"],
  92. self.hostname, self.external_ip)
  93. return vm_output_file_path
  94. def add_docker(self, docker):
  95. """
  96. add a Docker instance to the VM instance
  97. :param docker: the docker instance
  98. :return: None
  99. """
  100. self.docker_list.append(docker)
  101. def _centos7_weave_install(self):
  102. """
  103. install Weave on this VM
  104. :return: None
  105. """
  106. subprocess.call("./Linux/CentOS7/weave_install.sh")
  107. def _set_weave_network(self, vm_external_ip_list, weave_dns_ip):
  108. """
  109. launch Weave, make this VM connect with other VM
  110. :param vm_external_ip_list: external IP list of all VMs
  111. :param weave_dns_ip: the IP of DNS in this VM
  112. :return: None
  113. """
  114. # add other VMs and the ambari-server to set up connections
  115. weave_launch_command = ["sudo", "weave", "launch"]
  116. weave_launch_command.extend(vm_external_ip_list)
  117. print weave_launch_command
  118. with open(os.devnull, 'w') as shutup:
  119. subprocess.call(weave_launch_command, stdout=shutup)
  120. # establish DNS server
  121. weave_dns_ip_with_mask = "{0}/{1}".format(weave_dns_ip, Config.ATTRIBUTES["weave_ip_mask"])
  122. weave_launch_dns_command = ["sudo", "weave", "launch-dns", weave_dns_ip_with_mask]
  123. subprocess.call(weave_launch_dns_command)
  124. def _centos7_docker_install(self):
  125. """
  126. install Docker on this VM
  127. :return: None
  128. """
  129. subprocess.call("./Linux/CentOS7/docker_install.sh")
  130. def _build_docker_image(self, image_name):
  131. """
  132. build docker image
  133. :param image_name: the name of the Docker image
  134. :return: None
  135. """
  136. # choose the right Dockerfile
  137. target_dockerfile_name = "docker_image/{0}".format(Config.ATTRIBUTES["dockerfile_name"])
  138. standard_dockerfile_name = "docker_image/Dockerfile"
  139. shutil.copyfile(target_dockerfile_name, standard_dockerfile_name)
  140. with open(os.devnull, 'w') as shutup:
  141. subprocess.call(["sudo", "docker", "build", "-t", image_name, "docker_image/"])
  142. # subprocess.call(["sudo", "docker", "build", "-q", "-t", image_name, "docker_image/"], stdout=shutup)
  143. os.remove(standard_dockerfile_name)
  144. def _pull_docker_image(self, image_name):
  145. with open(os.devnull, 'w') as shutup:
  146. subprocess.call(["sudo", "docker", "pull", image_name], stdout=shutup)
  147. def _launch_containers(self, docker_image, server_weave_ip):
  148. """
  149. launch Docker containers, issue the script to install,
  150. configure and launch Ambari-gent inside Docker.
  151. :param docker_image: the name of the Docker image
  152. :param server_weave_ip: Weave internal IP of Ambari-server
  153. :return: None
  154. """
  155. for docker in self.docker_list:
  156. docker_ip_with_mask = "{0}/{1}".format(docker.ip, docker.mask)
  157. cmd = "python /launcher_agent.py {0} {1}; /bin/bash".format(server_weave_ip, docker.ip)
  158. command = ["sudo", "weave", "run", docker_ip_with_mask, "-d", "-it",
  159. "-h", docker.weave_domain_name,
  160. "--name", docker.get_container_name(),
  161. docker_image, "bash", "-c", cmd]
  162. print command
  163. subprocess.call(command)
  164. def _set_docker_partition(self, mount_point):
  165. """
  166. set docker container to use the disk storage of other partitions.
  167. :param mount_point: the mount point of the partition to be used
  168. :return: None
  169. """
  170. subprocess.call(["./Linux/CentOS7/set_docker_partition.sh", mount_point])
  171. def run_ambari_server(self):
  172. """
  173. set up Weave network, run Ambari-server in this VM
  174. :return: None
  175. """
  176. # set up network, run script inside the network directory
  177. os.chdir("network")
  178. subprocess.call(["./set_ambari_server_network.sh", self.weave_internal_ip,
  179. self.weave_dns_ip, self.weave_ip_mask])
  180. os.chdir("..")
  181. # install ambari server and start service
  182. subprocess.call(["./server/ambari_server_install.sh"])
  183. # start service
  184. subprocess.call(["./server/ambari_server_start.sh"])
  185. def run_service_server(self, ambari_server_weave_ip, ambari_server_external_ip):
  186. """
  187. set up Weave network, run Ambari-agent in this VM
  188. :param ambari_server_weave_ip: the Weave IP of Ambari-server
  189. :param ambari_server_external_ip: the external IP of Ambari-server
  190. :return: None
  191. """
  192. # set up network, run script inside the network directory
  193. os.chdir("network")
  194. subprocess.call(["./set_host_network.sh", self.weave_internal_ip,
  195. self.weave_dns_ip, self.weave_ip_mask, self.hostname,
  196. self.weave_domain_name, ambari_server_external_ip])
  197. os.chdir("..")
  198. # install ambari agent and start service
  199. subprocess.call(["./docker_image/ambari_agent_install.sh"])
  200. replace_conf(ambari_server_weave_ip)
  201. # start service
  202. subprocess.call(["./docker_image/ambari_agent_start.sh"])
  203. # forward public IP to Weave IP for server UI access
  204. port_list = Config.ATTRIBUTES["server_port_list"].split(",")
  205. for port in port_list:
  206. subprocess.call(["./network/set_ui_port_forward.sh", self.external_ip, self.weave_internal_ip, port])
  207. def run_docker(self, server_weave_ip, vm_ip_list):
  208. """
  209. run all Docker containers with Ambari-agent inside
  210. :param server_weave_ip: Weave internal IP of Ambari-server
  211. :param vm_ip_list: external IP list of all other VMs to be connected
  212. each docker vm connect to each other and service VM (and ambari-server)
  213. :return: None
  214. """
  215. self._centos7_docker_install()
  216. if "use_partition" in Config.ATTRIBUTES:
  217. self._set_docker_partition(Config.ATTRIBUTES["use_partition"])
  218. self._centos7_weave_install()
  219. image_name = Config.ATTRIBUTES["docker_image_name"]
  220. if "pull_docker_hub" in Config.ATTRIBUTES and Config.ATTRIBUTES["pull_docker_hub"] == "yes":
  221. self._pull_docker_image(image_name)
  222. else:
  223. self._build_docker_image(image_name)
  224. self._set_weave_network(vm_ip_list, self.weave_dns_ip)
  225. self._launch_containers(Config.ATTRIBUTES["docker_image_name"], server_weave_ip)
  226. @staticmethod
  227. def get_ambari_agent_vm_name(cluster_name):
  228. return "{0}-agent-vm".format(cluster_name)
  229. @staticmethod
  230. def get_ambari_server_vm_name(cluster_name):
  231. return "{0}-ambari-server".format(cluster_name)
  232. @staticmethod
  233. def get_service_server_vm_name(cluster_name):
  234. return "{0}-service-server".format(cluster_name)