| """ |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| """ |
| |
| |
| import subprocess |
| import shutil |
| from config import Config |
| import os |
| from docker import Docker |
| from docker_image.launcher_agent import replace_conf |
| |
| |
| class VM: |
| """ |
| This class represents VM, including its network setting and the possible Docker instance list |
| """ |
| def __init__(self, external_ip, domain_name, weave_dns_ip, weave_ip_mask): |
| self.external_ip = external_ip |
| self.domain_name = domain_name |
| self.hostname = self._gce_get_hostname(domain_name) |
| self.weave_domain_name = self._get_weave_domain_name(self.hostname) |
| self.weave_dns_ip = weave_dns_ip |
| self.weave_internal_ip = "" |
| self.weave_ip_mask = weave_ip_mask |
| self.docker_list = [] |
| |
| def to_json(self): |
| """ |
| create a map to hold the information of the VM instance |
| :return: A map, which is JSON format object. |
| """ |
| vm_json = {} |
| vm_json["external_ip"] = self.external_ip |
| vm_json["domain_name"] = self.domain_name |
| vm_json["weave_dns_ip"] = self.weave_dns_ip |
| vm_json["weave_internal_ip"] = self.weave_internal_ip |
| vm_json["weave_domain_name"] = self.weave_domain_name |
| vm_json["weave_ip_mask"] = self.weave_ip_mask |
| vm_json["docker_list"] = [] |
| for docker in self.docker_list: |
| vm_json["docker_list"].append(docker.to_json()) |
| return vm_json |
| |
| @staticmethod |
| def load_from_json(json_data): |
| """ |
| load the VM information from a JSON object |
| :param json_data: a map, which is a JSON object |
| :return: a VM object |
| """ |
| external_ip = json_data["external_ip"] |
| domain_name = json_data["domain_name"] |
| weave_dns_ip = json_data["weave_dns_ip"] |
| weave_internal_ip = json_data["weave_internal_ip"] |
| weave_domain_name = json_data["weave_domain_name"] |
| weave_ip_mask = json_data["weave_ip_mask"] |
| docker_list = [] |
| for json_docker in json_data["docker_list"]: |
| docker_list.append(Docker.load_from_json(json_docker)) |
| |
| vm = VM(external_ip, domain_name, weave_dns_ip, weave_ip_mask) |
| vm.docker_list = docker_list |
| vm.weave_internal_ip = weave_internal_ip |
| vm.weave_domain_name = weave_domain_name |
| return vm |
| |
| def _get_weave_domain_name(self, hostname): |
| """ |
| get the Weave domain name of the VM |
| :param hostname: the hostname of the VM |
| :return:the Weave domain name |
| """ |
| return "{0}.weave.local".format(hostname) |
| |
| def _gce_get_hostname(self, domain_name): |
| """ |
| The hostname of GCE VM is the first part of the internal domain name |
| :param domain_name: the internal domain name of GCE VM |
| :return: the hostname of GCE VM |
| """ |
| return domain_name.split(".")[0] |
| |
| def get_ssh_output_file_path(self): |
| """ |
| get the file name to hold the SSH output of the VM |
| :return: a file name |
| """ |
| vm_output_file_path = "{0}/vm-{1}-{2}".format(Config.ATTRIBUTES["output_folder"], |
| self.hostname, self.external_ip) |
| return vm_output_file_path |
| |
| def add_docker(self, docker): |
| """ |
| add a Docker instance to the VM instance |
| :param docker: the docker instance |
| :return: None |
| """ |
| self.docker_list.append(docker) |
| |
| def _centos7_weave_install(self): |
| """ |
| install Weave on this VM |
| :return: None |
| """ |
| subprocess.call("./Linux/CentOS7/weave_install.sh") |
| |
| def _set_weave_network(self, vm_external_ip_list, weave_dns_ip): |
| """ |
| launch Weave, make this VM connect with other VM |
| :param vm_external_ip_list: external IP list of all VMs |
| :param weave_dns_ip: the IP of DNS in this VM |
| :return: None |
| """ |
| # add other VMs and the ambari-server to set up connections |
| weave_launch_command = ["sudo", "weave", "launch"] |
| weave_launch_command.extend(vm_external_ip_list) |
| |
| print weave_launch_command |
| |
| with open(os.devnull, 'w') as shutup: |
| subprocess.call(weave_launch_command, stdout=shutup) |
| |
| # establish DNS server |
| weave_dns_ip_with_mask = "{0}/{1}".format(weave_dns_ip, Config.ATTRIBUTES["weave_ip_mask"]) |
| weave_launch_dns_command = ["sudo", "weave", "launch-dns", weave_dns_ip_with_mask] |
| subprocess.call(weave_launch_dns_command) |
| |
| def _centos7_docker_install(self): |
| """ |
| install Docker on this VM |
| :return: None |
| """ |
| subprocess.call("./Linux/CentOS7/docker_install.sh") |
| |
| def _build_docker_image(self, image_name): |
| """ |
| build docker image |
| :param image_name: the name of the Docker image |
| :return: None |
| """ |
| # choose the right Dockerfile |
| target_dockerfile_name = "docker_image/{0}".format(Config.ATTRIBUTES["dockerfile_name"]) |
| standard_dockerfile_name = "docker_image/Dockerfile" |
| shutil.copyfile(target_dockerfile_name, standard_dockerfile_name) |
| with open(os.devnull, 'w') as shutup: |
| subprocess.call(["sudo", "docker", "build", "-t", image_name, "docker_image/"]) |
| # subprocess.call(["sudo", "docker", "build", "-q", "-t", image_name, "docker_image/"], stdout=shutup) |
| os.remove(standard_dockerfile_name) |
| |
| def _pull_docker_image(self, image_name): |
| with open(os.devnull, 'w') as shutup: |
| subprocess.call(["sudo", "docker", "pull", image_name], stdout=shutup) |
| |
| def _launch_containers(self, docker_image, server_weave_ip): |
| """ |
| launch Docker containers, issue the script to install, |
| configure and launch Ambari-gent inside Docker. |
| :param docker_image: the name of the Docker image |
| :param server_weave_ip: Weave internal IP of Ambari-server |
| :return: None |
| """ |
| for docker in self.docker_list: |
| docker_ip_with_mask = "{0}/{1}".format(docker.ip, docker.mask) |
| cmd = "python /launcher_agent.py {0} {1}; /bin/bash".format(server_weave_ip, docker.ip) |
| |
| command = ["sudo", "weave", "run", docker_ip_with_mask, "-d", "-it", |
| "-h", docker.weave_domain_name, |
| "--name", docker.get_container_name(), |
| docker_image, "bash", "-c", cmd] |
| print command |
| subprocess.call(command) |
| |
| def _set_docker_partition(self, mount_point): |
| """ |
| set docker container to use the disk storage of other partitions. |
| :param mount_point: the mount point of the partition to be used |
| :return: None |
| """ |
| subprocess.call(["./Linux/CentOS7/set_docker_partition.sh", mount_point]) |
| |
| def run_ambari_server(self): |
| """ |
| set up Weave network, run Ambari-server in this VM |
| :return: None |
| """ |
| # set up network, run script inside the network directory |
| os.chdir("network") |
| subprocess.call(["./set_ambari_server_network.sh", self.weave_internal_ip, |
| self.weave_dns_ip, self.weave_ip_mask]) |
| os.chdir("..") |
| |
| # install ambari server and start service |
| subprocess.call(["./server/ambari_server_install.sh"]) |
| |
| # start service |
| subprocess.call(["./server/ambari_server_start.sh"]) |
| |
| def run_service_server(self, ambari_server_weave_ip, ambari_server_external_ip): |
| """ |
| set up Weave network, run Ambari-agent in this VM |
| :param ambari_server_weave_ip: the Weave IP of Ambari-server |
| :param ambari_server_external_ip: the external IP of Ambari-server |
| :return: None |
| """ |
| # set up network, run script inside the network directory |
| os.chdir("network") |
| subprocess.call(["./set_host_network.sh", self.weave_internal_ip, |
| self.weave_dns_ip, self.weave_ip_mask, self.hostname, |
| self.weave_domain_name, ambari_server_external_ip]) |
| os.chdir("..") |
| |
| # install ambari agent and start service |
| subprocess.call(["./docker_image/ambari_agent_install.sh"]) |
| replace_conf(ambari_server_weave_ip) |
| |
| # start service |
| subprocess.call(["./docker_image/ambari_agent_start.sh"]) |
| |
| # forward public IP to Weave IP for server UI access |
| port_list = Config.ATTRIBUTES["server_port_list"].split(",") |
| for port in port_list: |
| subprocess.call(["./network/set_ui_port_forward.sh", self.external_ip, self.weave_internal_ip, port]) |
| |
| |
| def run_docker(self, server_weave_ip, vm_ip_list): |
| """ |
| run all Docker containers with Ambari-agent inside |
| :param server_weave_ip: Weave internal IP of Ambari-server |
| :param vm_ip_list: external IP list of all other VMs to be connected |
| each docker vm connect to each other and service VM (and ambari-server) |
| :return: None |
| """ |
| self._centos7_docker_install() |
| |
| if "use_partition" in Config.ATTRIBUTES: |
| self._set_docker_partition(Config.ATTRIBUTES["use_partition"]) |
| |
| self._centos7_weave_install() |
| |
| image_name = Config.ATTRIBUTES["docker_image_name"] |
| if "pull_docker_hub" in Config.ATTRIBUTES and Config.ATTRIBUTES["pull_docker_hub"] == "yes": |
| self._pull_docker_image(image_name) |
| else: |
| self._build_docker_image(image_name) |
| |
| self._set_weave_network(vm_ip_list, self.weave_dns_ip) |
| self._launch_containers(Config.ATTRIBUTES["docker_image_name"], server_weave_ip) |
| |
| @staticmethod |
| def get_ambari_agent_vm_name(cluster_name): |
| return "{0}-agent-vm".format(cluster_name) |
| |
| @staticmethod |
| def get_ambari_server_vm_name(cluster_name): |
| return "{0}-ambari-server".format(cluster_name) |
| |
| @staticmethod |
| def get_service_server_vm_name(cluster_name): |
| return "{0}-service-server".format(cluster_name) |