Example #1
0
    def __init__(self):
        LOG.info("xh: compass_server=%s" % CONF.compass_server)
        self.client = Client(CONF.compass_server)
        self.subnet_mapping = {}
        self.role_mapping = {}
        self.host_mapping = {}
        self.host_ips = defaultdict(list)
        self.host_roles = {}

        self.login()
Example #2
0
    def __init__(self):
        LOG.info("xh: compass_server=%s" % CONF.compass_server)
        self.client = Client(CONF.compass_server)
        self.subnet_mapping = {}
        self.role_mapping = {}
        self.host_mapping = {}
        self.host_ips = defaultdict(list)
        self.host_roles = {}

        self.login()
Example #3
0
class CompassClient(object):
    def __init__(self):
        LOG.info("xh: compass_server=%s" % CONF.compass_server)
        self.client = Client(CONF.compass_server)
        self.subnet_mapping = {}
        self.role_mapping = {}
        self.host_mapping = {}
        self.host_ips = defaultdict(list)
        self.host_roles = {}

        self.login()

    def is_ok(self, status):
        if status < 300 and status >= 200:
            return True

    def login(self):
        status, resp = self.client.get_token(
            CONF.compass_user_email,
            CONF.compass_user_password
        )

        LOG.info(
            'login status: %s, resp: %s',
            status, resp
        )
        if self.is_ok(status):
            return resp["token"]
        else:
            raise Exception(
                'failed to login %s with user %s',
                CONF.compass_server,
                CONF.compass_user_email
            )

    def get_machines(self):
        status, resp = self.client.list_machines()
        if not self.is_ok(status):
            LOG.error(
                'get all machines status: %s, resp: %s', status, resp)
            raise RuntimeError('failed to get machines')

        machines_to_add = list(set([
            machine for machine in CONF.machines.split(',')
            if machine
        ]))

        machines_db = [str(m["mac"]) for m in resp]
        LOG.info('machines in db: %s\n to add: %s', machines_db, machines_to_add)
        if not set(machines_to_add).issubset(set(machines_db)):
            raise RuntimeError('unidentify machine to add')

        return [m["id"] for m in resp if str(m["mac"]) in machines_to_add]

    def list_clusters(self):
        status, resp = self.client.list_clusters(name=CONF.cluster_name)
        if not self.is_ok(status) or not resp:
            raise RuntimeError('failed to list cluster')

        cluster = resp[0]

        return cluster['id']

    def get_adapter(self):
        """get adapter."""
        status, resp = self.client.list_adapters(name=CONF.adapter_name)
        LOG.info(
            'get all adapters status: %s, resp: %s',
            status, resp
        )

        if not self.is_ok(status) or not resp:
            raise RuntimeError('failed to get adapters')

        os_re = re.compile(CONF.adapter_os_pattern)
        flavor_re = re.compile(CONF.adapter_flavor_pattern)

        adapter_id = None
        os_id = None
        flavor_id = None
        adapter = None

        adapter = resp[0]
        adapter_id = adapter['id']
        for supported_os in adapter['supported_oses']:
            if not os_re or os_re.match(supported_os['name']):
                os_id = supported_os['os_id']
                break

        if 'flavors' in adapter:
            for flavor in adapter['flavors']:
                if not flavor_re or flavor_re.match(flavor['name']):
                    flavor_id = flavor['id']
                    break

        assert(os_id and flavor_id)
        return (adapter_id, os_id, flavor_id)

    def add_subnets(self):
        subnets = [
            subnet for subnet in CONF.subnets.split(',')
            if subnet
        ]

        assert(subnets)

        subnet_mapping = {}
        for subnet in subnets:
            try:
                netaddr.IPNetwork(subnet)
            except:
                raise RuntimeError('subnet %s format is invalid' % subnet)

            status, resp = self.client.add_subnet(subnet)
            LOG.info('add subnet %s status %s response %s',
                         subnet, status, resp)
            if not self.is_ok(status):
                raise RuntimeError('failed to add subnet %s' % subnet)

            subnet_mapping[resp['subnet']] = resp['id']

        self.subnet_mapping = subnet_mapping

    def add_cluster(self, adapter_id, os_id, flavor_id):
        """add a cluster."""
        cluster_name = CONF.cluster_name
        assert(cluster_name)
        status, resp = self.client.add_cluster(
            cluster_name, adapter_id,
            os_id, flavor_id)

        if not self.is_ok(status):
            raise RuntimeError("add cluster failed")

        LOG.info('add cluster %s status: %s resp:%s',
                     cluster_name, status,resp)

        if isinstance(resp, list):
            cluster = resp[0]
        else:
            cluster = resp

        cluster_id = cluster['id']
        flavor = cluster.get('flavor', {})
        roles = flavor.get('roles', [])

        for role in roles:
            if role.get('optional', False):
                self.role_mapping[role['name']] = ROLE_ASSIGNED
            else:
                self.role_mapping[role['name']] = ROLE_UNASSIGNED

        return cluster_id

    def add_cluster_hosts(self, cluster_id, machines):
        hostnames = [
            hostname for hostname in CONF.hostnames.split(',')
            if hostname
        ]

        assert(len(machines) == len(hostnames))

        machines_dict = []
        for machine_id, hostname in zip(machines, hostnames):
            machines_dict.append({
                'machine_id': machine_id,
                'name': hostname
            })

        # add hosts to the cluster.
        status, resp = self.client.add_hosts_to_cluster(
            cluster_id,
            {'machines': machines_dict})

        LOG.info('add machines %s to cluster %s status: %s, resp: %s',
                     machines_dict, cluster_id, status, resp)

        if not self.is_ok(status):
            raise RuntimeError("add host to cluster failed")

        for host in resp['hosts']:
            self.host_mapping[host['hostname']] = host['id']

        assert(len(self.host_mapping) == len(machines))

    def set_cluster_os_config(self, cluster_id):
        """set cluster os config."""
        os_config = {}
        language = CONF.language
        timezone = CONF.timezone
        http_proxy = CONF.http_proxy
        https_proxy = CONF.https_proxy
        local_repo_url = CONF.local_repo_url
        repo_name = CONF.repo_name
        deploy_type = CONF.deploy_type
        if not https_proxy and http_proxy:
            https_proxy = http_proxy

        no_proxy = [
            no_proxy for no_proxy in CONF.no_proxy.split(',')
            if no_proxy
        ]

        compass_server = CONF.compass_server
        if http_proxy:
            for hostname, ips in self.host_ips.items():
                no_proxy.append(hostname)
                no_proxy.extend(ips)

        ntp_server = CONF.ntp_server or compass_server

        dns_servers = [
            dns_server for dns_server in CONF.dns_servers.split(',')
            if dns_server
        ]
        if not dns_servers:
            dns_servers = [compass_server]

        domain = CONF.domain
        if not domain:
            raise Exception('domain is not defined')

        search_path = [
            search_path for search_path in CONF.search_path.split(',')
            if search_path
        ]

        if not search_path:
            search_path = [domain]

        default_gateway = CONF.default_gateway
        if not default_gateway:
            raise Exception('default gateway is not defined')

        general_config = {
            'language': language,
            'timezone': timezone,
            'ntp_server': ntp_server,
            'dns_servers': dns_servers,
            'default_gateway': default_gateway
        }

        if http_proxy:
            general_config['http_proxy'] = http_proxy
        if https_proxy:
            general_config['https_proxy'] = https_proxy
        if no_proxy:
            general_config['no_proxy'] = no_proxy
        if domain:
            general_config['domain'] = domain
        if search_path:
            general_config['search_path'] = search_path
        if local_repo_url:
            general_config['local_repo'] = local_repo_url
        if repo_name:
            general_config['repo_name'] = repo_name
        if deploy_type:
            general_config['deploy_type'] = deploy_type

        os_config["general"] = general_config

        server_credential = CONF.server_credential
        if '=' in server_credential:
            server_username, server_password = server_credential.split('=', 1)
        elif server_credential:
            server_username = server_password = server_credential
        else:
            server_username = '******'
            server_password = '******'

        os_config['server_credentials'] = {
            'username': server_username,
            'password': server_password
        }

        partitions = [
            partition for partition in CONF.partitions.split(',')
            if partition
        ]

        partition_config = {}
        for partition in partitions:
            assert("=" in partition)

            partition_name, partition_value = partition.split('=', 1)
            partition_name = partition_name.strip()
            partition_value = partition_value.strip()

            assert(partition_name and partition_value)

            if partition_value.endswith('%'):
                partition_type = 'percentage'
                partition_value = int(partition_value[:-1])
            else:
                partition_type = 'size'

            partition_config[partition_name] = {
                partition_type: partition_value
            }

        os_config['partition'] = partition_config

        """
        os_config_filename = CONF.os_config_json_file
        if os_config_filename:
            util.merge_dict(
                os_config, _load_config(os_config_filename)
            )
        """

        status, resp = self.client.update_cluster_config(
            cluster_id, os_config=os_config)
        LOG.info(
            'set os config %s to cluster %s status: %s, resp: %s',
            os_config, cluster_id, status, resp)
        if not self.is_ok(status):
            raise RuntimeError('failed to set os config %s to cluster %s' \
                    % (os_config, cluster_id))

    def set_host_networking(self):
        """set cluster hosts networking."""
        def get_subnet(ip_str):
            try:
                LOG.info("subnets: %s" % self.subnet_mapping.keys())
                ip = netaddr.IPAddress(ip_str)
                for cidr, subnet_id in self.subnet_mapping.items():
                    subnet = netaddr.IPNetwork(cidr)
                    if ip in subnet:
                        return True, subnet_id

                    LOG.info("ip %s not in %s" % (ip_str, cidr))
                return False, None
            except:
                LOG.exception("ip addr %s is invalid" % ip_str)
                return False, None

        for host_network in CONF.host_networks.split(';'):
            hostname, networks_str = host_network.split(':', 1)
            hostname = hostname.strip()
            networks_str = networks_str.strip()

            assert(hostname in self.host_mapping)

            host_id = self.host_mapping[hostname]
            intf_list = networks_str.split(',')
            for intf_str in intf_list:
                interface, intf_properties = intf_str.split('=', 1)
                intf_properties = intf_properties.strip().split('|')

                assert(intf_properties)
                ip_str = intf_properties[0]

                status, subnet_id = get_subnet(ip_str)
                if not status:
                    raise RuntimeError("ip addr %s is invalid" % ip_str)

                properties = dict([
                    (intf_property, True)
                    for intf_property in intf_properties[1:]
                ])

                LOG.info(
                    'add host %s interface %s ip %s network proprties %s',
                    hostname, interface, ip_str, properties)

                status, response = self.client.add_host_network(
                    host_id, interface, ip=ip_str, subnet_id=subnet_id,
                    **properties
                )

                LOG.info(
                    'add host %s interface %s ip %s network properties %s '
                    'status %s: %s',
                    hostname, interface, ip_str, properties,
                    status, response
                )

                if not self.is_ok(status):
                    raise RuntimeError("add host network failed")

                self.host_ips[hostname].append(ip_str)

    def set_cluster_package_config(self, cluster_id):
        """set cluster package config."""
        package_config = {"security": {}}

        service_credentials = [
            service_credential
            for service_credential in CONF.service_credentials.split(',')
            if service_credential
        ]

        service_credential_cfg = {}
        LOG.info(
            'service credentials: %s', service_credentials
        )

        for service_credential in service_credentials:
            if ':' not in service_credential:
                raise Exception(
                    'there is no : in service credential %s' % service_credential
                )
            service_name, service_pair = service_credential.split(':', 1)
            if '=' not in service_pair:
                raise Exception(
                    'there is no = in service %s security' % service_name
                )

            username, password = service_pair.split('=', 1)
            service_credential_cfg[service_name] = {
                'username': username,
                'password': password
            }

        console_credentials = [
            console_credential
            for console_credential in CONF.console_credentials.split(',')
            if console_credential
        ]

        LOG.info(
            'console credentials: %s', console_credentials
        )

        console_credential_cfg = {}
        for console_credential in console_credentials:
            if ':' not in console_credential:
                raise Exception(
                    'there is no : in console credential %s' % console_credential
                )
            console_name, console_pair = console_credential.split(':', 1)
            if '=' not in console_pair:
                raise Exception(
                    'there is no = in console %s security' % console_name
                )
            username, password = console_pair.split('=', 1)
            console_credential_cfg[console_name] = {
                'username': username,
                'password': password
            }

        package_config["security"] = {"service_credentials": service_credential_cfg,
                                      "console_credentials": console_credential_cfg}

        network_mapping = dict([
            network_pair.split('=', 1)
            for network_pair in CONF.network_mapping.split(',')
            if '=' in network_pair
        ])

        package_config['network_mapping'] = network_mapping

        assert(os.path.exists(CONF.network_cfg))
        network_cfg = yaml.load(open(CONF.network_cfg))
        package_config["network_cfg"] = network_cfg

        assert(os.path.exists(CONF.neutron_cfg))
        neutron_cfg = yaml.load(open(CONF.neutron_cfg))
        package_config["neutron_config"] = neutron_cfg

        """
        package_config_filename = CONF.package_config_json_file
        if package_config_filename:
            util.merge_dict(
                package_config, _load_config(package_config_filename)
            )
        """
        package_config['ha_proxy'] = {}
        if CONF.cluster_vip:
            package_config["ha_proxy"]["vip"] = CONF.cluster_vip

        package_config['enable_secgroup'] = (CONF.enable_secgroup == "true")
        package_config['enable_fwaas'] = (CONF.enable_fwaas== "true")
        package_config['enable_vpnaas'] = (CONF.enable_vpnaas== "true")

        status, resp = self.client.update_cluster_config(
            cluster_id, package_config=package_config)
        LOG.info(
            'set package config %s to cluster %s status: %s, resp: %s',
            package_config, cluster_id, status, resp)

        if not self.is_ok(status):
            raise RuntimeError("set cluster package_config failed")

    def set_host_roles(self, cluster_id, host_id, roles):
        status, response = self.client.update_cluster_host(
            cluster_id, host_id, roles=roles)

        LOG.info(
            'set cluster %s host %s roles %s status %s: %s',
            cluster_id, host_id, roles, status, response
        )

        if not self.is_ok(status):
            raise RuntimeError("set host roles failed")

        for role in roles:
            if role in self.role_mapping:
                self.role_mapping[role] = ROLE_ASSIGNED

    def set_all_hosts_roles(self, cluster_id):
        for host_str in CONF.host_roles.split(';'):
            host_str = host_str.strip()
            hostname, roles_str = host_str.split('=', 1)

            assert(hostname in self.host_mapping)
            host_id = self.host_mapping[hostname]

            roles = [role.strip() for role in roles_str.split(',') if role]

            self.set_host_roles(cluster_id, host_id, roles)
            self.host_roles[hostname] = roles

        unassigned_hostnames = list(set(self.host_mapping.keys()) \
                                    - set(self.host_roles.keys()))

        unassigned_roles = [ role for role, status in self.role_mapping.items()
                             if is_role_unassigned(status)]

        assert(len(unassigned_hostnames) >= len(unassigned_roles))

        for hostname, role in map(None, unassigned_hostnames, unassigned_roles):
            host_id = self.host_mapping[hostname]
            self.set_host_roles(cluster_id, host_id, [role])
            self.host_roles[hostname] = [role]

        unassigned_hostnames = list(set(self.host_mapping.keys()) \
                                    - set(self.host_roles.keys()))

        if not unassigned_hostnames:
            return

        # assign default roles to unassigned hosts
        default_roles = [
            role for role in CONF.default_roles.split(',')
            if role
        ]

        assert(default_roles)

        cycle_roles = itertools.cycle(default_roles)
        for hostname in unassigned_hostnames:
            host_id = self.host_mapping[hostname]
            roles = [cycle_roles.next()]
            self.set_host_roles(cluster_id, host_id, roles)
            self.host_roles[hostname] = roles

    def deploy_clusters(self, cluster_id):
        host_ids = self.host_mapping.values()

        status, response = self.client.review_cluster(
            cluster_id, review={'hosts': host_ids}
        )
        LOG.info(
            'review cluster %s hosts %s, status %s: %s',
            cluster_id, host_ids, status, response
        )

        #TODO, what this doning?
        if not self.is_ok(status):
            raise RuntimeError("review cluster host failed")

        status, response = self.client.deploy_cluster(
            cluster_id, deploy={'hosts': host_ids}
        )
        LOG.info(
            'deploy cluster %s hosts %s status %s: %s',
            cluster_id, host_ids, status, response
        )

        if not self.is_ok(status):
            raise RuntimeError("deploy cluster failed")

    def redeploy_clusters(self, cluster_id):
        status, response = self.client.redeploy_cluster(
            cluster_id
        )

        if not self.is_ok(status):
            LOG.info(
                'deploy cluster %s status %s: %s',
                cluster_id, status, response
            )
            raise RuntimeError("redeploy cluster failed")

    def get_installing_progress(self, cluster_id):
        """get intalling progress."""
        action_timeout = time.time() + 60 * float(CONF.action_timeout)
        deployment_timeout = time.time() + 60 * float(
            CONF.deployment_timeout)

        current_time = time.time
        deployment_failed = True
        while current_time() < deployment_timeout:
            status, cluster_state = self.client.get_cluster_state(cluster_id)
            if not self.is_ok(status):
                raise RuntimeError("can not get cluster state")

            if cluster_state['state'] in ['UNINITIALIZED', 'INITIALIZED']:
                if current_time() >= action_timeout:
                    deployment_failed = True
                    LOG.info(
                         'get cluster %s state status %s: %s, successful',
                         cluster_id, status, cluster_state
                    )
                    break
                else:
                    time.sleep(5)
                    continue

            elif cluster_state['state'] == 'SUCCESSFUL':
                deployment_failed = False
                LOG.info(
                     'get cluster %s state status %s: %s, successful',
                     cluster_id, status, cluster_state
                )
                break
            elif cluster_state['state'] == 'ERROR':
                deployment_failed = True
                LOG.info(
                     'get cluster %s state status %s: %s, error',
                     cluster_id, status, cluster_state
                )
                break

        kill_print_proc()
        if deployment_failed:
            raise RuntimeError("deploy cluster failed")

    def check_dashboard_links(self, cluster_id):
        dashboard_url = CONF.dashboard_url
        if not dashboard_url:
            LOG.info('no dashboarde url set')
            return
        dashboard_link_pattern = re.compile(
            CONF.dashboard_link_pattern)
        r = requests.get(dashboard_url, verify=False)
        r.raise_for_status()
        match = dashboard_link_pattern.search(r.text)
        if match:
            LOG.info(
                'dashboard login page for cluster %s can be downloaded',
                cluster_id)
        else:
            msg = (
                '%s failed to be downloaded\n'
                'the context is:\n%s\n'
            ) % (dashboard_url, r.text)
            raise Exception(msg)
Example #4
0
class CompassClient(object):
    def __init__(self):
        LOG.info("xh: compass_server=%s" % CONF.compass_server)
        self.client = Client(CONF.compass_server)
        self.subnet_mapping = {}
        self.role_mapping = {}
        self.host_mapping = {}
        self.host_ips = defaultdict(list)
        self.host_roles = {}

        self.login()

    def is_ok(self, status):
        if status < 300 and status >= 200:
            return True

    def login(self):
        status, resp = self.client.get_token(CONF.compass_user_email, CONF.compass_user_password)

        LOG.info("login status: %s, resp: %s", status, resp)
        if self.is_ok(status):
            return resp["token"]
        else:
            raise Exception("failed to login %s with user %s", CONF.compass_server, CONF.compass_user_email)

    def get_machines(self):
        status, resp = self.client.list_machines()
        if not self.is_ok(status):
            LOG.error("get all machines status: %s, resp: %s", status, resp)
            raise RuntimeError("failed to get machines")

        machines_to_add = list(set([machine for machine in CONF.machines.split(",") if machine]))

        machines_db = [str(m["mac"]) for m in resp]
        LOG.info("machines in db: %s\n to add: %s", machines_db, machines_to_add)
        if not set(machines_to_add).issubset(set(machines_db)):
            raise RuntimeError("unidentify machine to add")

        return [m["id"] for m in resp if str(m["mac"]) in machines_to_add]

    def list_clusters(self):
        status, resp = self.client.list_clusters(name=CONF.cluster_name)
        if not self.is_ok(status) or not resp:
            raise RuntimeError("failed to list cluster")

        cluster = resp[0]

        return cluster["id"]

    def get_adapter(self):
        """get adapter."""
        status, resp = self.client.list_adapters(name=CONF.adapter_name)
        LOG.info("get all adapters status: %s, resp: %s", status, resp)

        if not self.is_ok(status) or not resp:
            raise RuntimeError("failed to get adapters")

        os_re = re.compile(CONF.adapter_os_pattern)
        flavor_re = re.compile(CONF.adapter_flavor_pattern)

        adapter_id = None
        os_id = None
        flavor_id = None
        adapter = None

        adapter = resp[0]
        adapter_id = adapter["id"]
        for supported_os in adapter["supported_oses"]:
            if not os_re or os_re.match(supported_os["name"]):
                os_id = supported_os["os_id"]
                break

        if "flavors" in adapter:
            for flavor in adapter["flavors"]:
                if not flavor_re or flavor_re.match(flavor["name"]):
                    flavor_id = flavor["id"]
                    break

        assert os_id and flavor_id
        return (adapter_id, os_id, flavor_id)

    def add_subnets(self):
        subnets = [subnet for subnet in CONF.subnets.split(",") if subnet]

        assert subnets

        subnet_mapping = {}
        for subnet in subnets:
            try:
                netaddr.IPNetwork(subnet)
            except:
                raise RuntimeError("subnet %s format is invalid" % subnet)

            status, resp = self.client.add_subnet(subnet)
            LOG.info("add subnet %s status %s response %s", subnet, status, resp)
            if not self.is_ok(status):
                raise RuntimeError("failed to add subnet %s" % subnet)

            subnet_mapping[resp["subnet"]] = resp["id"]

        self.subnet_mapping = subnet_mapping

    def add_cluster(self, adapter_id, os_id, flavor_id):
        """add a cluster."""
        cluster_name = CONF.cluster_name
        assert cluster_name
        status, resp = self.client.add_cluster(cluster_name, adapter_id, os_id, flavor_id)

        if not self.is_ok(status):
            raise RuntimeError("add cluster failed")

        LOG.info("add cluster %s status: %s resp:%s", cluster_name, status, resp)

        if isinstance(resp, list):
            cluster = resp[0]
        else:
            cluster = resp

        cluster_id = cluster["id"]
        flavor = cluster.get("flavor", {})
        roles = flavor.get("roles", [])

        for role in roles:
            if role.get("optional", False):
                self.role_mapping[role["name"]] = ROLE_ASSIGNED
            else:
                self.role_mapping[role["name"]] = ROLE_UNASSIGNED

        return cluster_id

    def add_cluster_hosts(self, cluster_id, machines):
        hostnames = [hostname for hostname in CONF.hostnames.split(",") if hostname]

        assert len(machines) == len(hostnames)

        machines_dict = []
        for machine_id, hostname in zip(machines, hostnames):
            machines_dict.append({"machine_id": machine_id, "name": hostname})

        # add hosts to the cluster.
        status, resp = self.client.add_hosts_to_cluster(cluster_id, {"machines": machines_dict})

        LOG.info("add machines %s to cluster %s status: %s, resp: %s", machines_dict, cluster_id, status, resp)

        if not self.is_ok(status):
            raise RuntimeError("add host to cluster failed")

        for host in resp["hosts"]:
            self.host_mapping[host["hostname"]] = host["id"]

        assert len(self.host_mapping) == len(machines)

    def set_cluster_os_config(self, cluster_id):
        """set cluster os config."""
        os_config = {}
        language = CONF.language
        timezone = CONF.timezone
        http_proxy = CONF.http_proxy
        https_proxy = CONF.https_proxy
        local_repo_url = CONF.local_repo_url
        repo_name = CONF.repo_name
        deploy_type = CONF.deploy_type
        if not https_proxy and http_proxy:
            https_proxy = http_proxy

        no_proxy = [no_proxy for no_proxy in CONF.no_proxy.split(",") if no_proxy]

        compass_server = CONF.compass_server
        if http_proxy:
            for hostname, ips in self.host_ips.items():
                no_proxy.append(hostname)
                no_proxy.extend(ips)

        ntp_server = CONF.ntp_server or compass_server

        dns_servers = [dns_server for dns_server in CONF.dns_servers.split(",") if dns_server]
        if not dns_servers:
            dns_servers = [compass_server]

        domain = CONF.domain
        if not domain:
            raise Exception("domain is not defined")

        search_path = [search_path for search_path in CONF.search_path.split(",") if search_path]

        if not search_path:
            search_path = [domain]

        default_gateway = CONF.default_gateway
        if not default_gateway:
            raise Exception("default gateway is not defined")

        general_config = {
            "language": language,
            "timezone": timezone,
            "ntp_server": ntp_server,
            "dns_servers": dns_servers,
            "default_gateway": default_gateway,
        }

        if http_proxy:
            general_config["http_proxy"] = http_proxy
        if https_proxy:
            general_config["https_proxy"] = https_proxy
        if no_proxy:
            general_config["no_proxy"] = no_proxy
        if domain:
            general_config["domain"] = domain
        if search_path:
            general_config["search_path"] = search_path
        if local_repo_url:
            general_config["local_repo"] = local_repo_url
        if repo_name:
            general_config["repo_name"] = repo_name
        if deploy_type:
            general_config["deploy_type"] = deploy_type

        os_config["general"] = general_config

        server_credential = CONF.server_credential
        if "=" in server_credential:
            server_username, server_password = server_credential.split("=", 1)
        elif server_credential:
            server_username = server_password = server_credential
        else:
            server_username = "******"
            server_password = "******"

        os_config["server_credentials"] = {"username": server_username, "password": server_password}

        partitions = [partition for partition in CONF.partitions.split(",") if partition]

        partition_config = {}
        for partition in partitions:
            assert "=" in partition

            partition_name, partition_value = partition.split("=", 1)
            partition_name = partition_name.strip()
            partition_value = partition_value.strip()

            assert partition_name and partition_value

            if partition_value.endswith("%"):
                partition_type = "percentage"
                partition_value = int(partition_value[:-1])
            else:
                partition_type = "size"

            partition_config[partition_name] = {partition_type: partition_value}

        os_config["partition"] = partition_config

        """
        os_config_filename = CONF.os_config_json_file
        if os_config_filename:
            util.merge_dict(
                os_config, _load_config(os_config_filename)
            )
        """

        status, resp = self.client.update_cluster_config(cluster_id, os_config=os_config)
        LOG.info("set os config %s to cluster %s status: %s, resp: %s", os_config, cluster_id, status, resp)
        if not self.is_ok(status):
            raise RuntimeError("failed to set os config %s to cluster %s" % (os_config, cluster_id))

    def set_host_networking(self):
        """set cluster hosts networking."""

        def get_subnet(ip_str):
            try:
                LOG.info("subnets: %s" % self.subnet_mapping.keys())
                ip = netaddr.IPAddress(ip_str)
                for cidr, subnet_id in self.subnet_mapping.items():
                    subnet = netaddr.IPNetwork(cidr)
                    if ip in subnet:
                        return True, subnet_id

                    LOG.info("ip %s not in %s" % (ip_str, cidr))
                return False, None
            except:
                LOG.exception("ip addr %s is invalid" % ip_str)
                return False, None

        for host_network in CONF.host_networks.split(";"):
            hostname, networks_str = host_network.split(":", 1)
            hostname = hostname.strip()
            networks_str = networks_str.strip()

            assert hostname in self.host_mapping

            host_id = self.host_mapping[hostname]
            intf_list = networks_str.split(",")
            for intf_str in intf_list:
                interface, intf_properties = intf_str.split("=", 1)
                intf_properties = intf_properties.strip().split("|")

                assert intf_properties
                ip_str = intf_properties[0]

                status, subnet_id = get_subnet(ip_str)
                if not status:
                    raise RuntimeError("ip addr %s is invalid" % ip_str)

                properties = dict([(intf_property, True) for intf_property in intf_properties[1:]])

                LOG.info("add host %s interface %s ip %s network proprties %s", hostname, interface, ip_str, properties)

                status, response = self.client.add_host_network(
                    host_id, interface, ip=ip_str, subnet_id=subnet_id, **properties
                )

                LOG.info(
                    "add host %s interface %s ip %s network properties %s " "status %s: %s",
                    hostname,
                    interface,
                    ip_str,
                    properties,
                    status,
                    response,
                )

                if not self.is_ok(status):
                    raise RuntimeError("add host network failed")

                self.host_ips[hostname].append(ip_str)

    def set_cluster_package_config(self, cluster_id):
        """set cluster package config."""
        package_config = {"security": {}}

        service_credentials = [
            service_credential for service_credential in CONF.service_credentials.split(",") if service_credential
        ]

        service_credential_cfg = {}
        LOG.info("service credentials: %s", service_credentials)

        for service_credential in service_credentials:
            if ":" not in service_credential:
                raise Exception("there is no : in service credential %s" % service_credential)
            service_name, service_pair = service_credential.split(":", 1)
            if "=" not in service_pair:
                raise Exception("there is no = in service %s security" % service_name)

            username, password = service_pair.split("=", 1)
            service_credential_cfg[service_name] = {"username": username, "password": password}

        console_credentials = [
            console_credential for console_credential in CONF.console_credentials.split(",") if console_credential
        ]

        LOG.info("console credentials: %s", console_credentials)

        console_credential_cfg = {}
        for console_credential in console_credentials:
            if ":" not in console_credential:
                raise Exception("there is no : in console credential %s" % console_credential)
            console_name, console_pair = console_credential.split(":", 1)
            if "=" not in console_pair:
                raise Exception("there is no = in console %s security" % console_name)
            username, password = console_pair.split("=", 1)
            console_credential_cfg[console_name] = {"username": username, "password": password}

        package_config["security"] = {
            "service_credentials": service_credential_cfg,
            "console_credentials": console_credential_cfg,
        }

        network_mapping = dict(
            [network_pair.split("=", 1) for network_pair in CONF.network_mapping.split(",") if "=" in network_pair]
        )

        package_config["network_mapping"] = network_mapping

        assert os.path.exists(CONF.network_cfg)
        network_cfg = yaml.load(open(CONF.network_cfg))
        package_config["network_cfg"] = network_cfg

        assert os.path.exists(CONF.neutron_cfg)
        neutron_cfg = yaml.load(open(CONF.neutron_cfg))
        package_config["neutron_config"] = neutron_cfg

        """
        package_config_filename = CONF.package_config_json_file
        if package_config_filename:
            util.merge_dict(
                package_config, _load_config(package_config_filename)
            )
        """
        package_config["ha_proxy"] = {}
        if CONF.cluster_vip:
            package_config["ha_proxy"]["vip"] = CONF.cluster_vip

        package_config["enable_secgroup"] = CONF.enable_secgroup == "true"
        package_config["enable_fwaas"] = CONF.enable_fwaas == "true"
        package_config["enable_vpnaas"] = CONF.enable_vpnaas == "true"

        status, resp = self.client.update_cluster_config(cluster_id, package_config=package_config)
        LOG.info("set package config %s to cluster %s status: %s, resp: %s", package_config, cluster_id, status, resp)

        if not self.is_ok(status):
            raise RuntimeError("set cluster package_config failed")

    def set_host_roles(self, cluster_id, host_id, roles):
        status, response = self.client.update_cluster_host(cluster_id, host_id, roles=roles)

        LOG.info("set cluster %s host %s roles %s status %s: %s", cluster_id, host_id, roles, status, response)

        if not self.is_ok(status):
            raise RuntimeError("set host roles failed")

        for role in roles:
            if role in self.role_mapping:
                self.role_mapping[role] = ROLE_ASSIGNED

    def set_all_hosts_roles(self, cluster_id):
        for host_str in CONF.host_roles.split(";"):
            host_str = host_str.strip()
            hostname, roles_str = host_str.split("=", 1)

            assert hostname in self.host_mapping
            host_id = self.host_mapping[hostname]

            roles = [role.strip() for role in roles_str.split(",") if role]

            self.set_host_roles(cluster_id, host_id, roles)
            self.host_roles[hostname] = roles

        unassigned_hostnames = list(set(self.host_mapping.keys()) - set(self.host_roles.keys()))

        unassigned_roles = [role for role, status in self.role_mapping.items() if is_role_unassigned(status)]

        assert len(unassigned_hostnames) >= len(unassigned_roles)

        for hostname, role in map(None, unassigned_hostnames, unassigned_roles):
            host_id = self.host_mapping[hostname]
            self.set_host_roles(cluster_id, host_id, [role])
            self.host_roles[hostname] = [role]

        unassigned_hostnames = list(set(self.host_mapping.keys()) - set(self.host_roles.keys()))

        if not unassigned_hostnames:
            return

        # assign default roles to unassigned hosts
        default_roles = [role for role in CONF.default_roles.split(",") if role]

        assert default_roles

        cycle_roles = itertools.cycle(default_roles)
        for hostname in unassigned_hostnames:
            host_id = self.host_mapping[hostname]
            roles = [cycle_roles.next()]
            self.set_host_roles(cluster_id, host_id, roles)
            self.host_roles[hostname] = roles

    def deploy_clusters(self, cluster_id):
        host_ids = self.host_mapping.values()

        status, response = self.client.review_cluster(cluster_id, review={"hosts": host_ids})
        LOG.info("review cluster %s hosts %s, status %s: %s", cluster_id, host_ids, status, response)

        # TODO, what this doning?
        if not self.is_ok(status):
            raise RuntimeError("review cluster host failed")

        status, response = self.client.deploy_cluster(cluster_id, deploy={"hosts": host_ids})
        LOG.info("deploy cluster %s hosts %s status %s: %s", cluster_id, host_ids, status, response)

        if not self.is_ok(status):
            raise RuntimeError("deploy cluster failed")

    def redeploy_clusters(self, cluster_id):
        status, response = self.client.redeploy_cluster(cluster_id)

        if not self.is_ok(status):
            LOG.info("deploy cluster %s status %s: %s", cluster_id, status, response)
            raise RuntimeError("redeploy cluster failed")

    def get_cluster_state(self, cluster_id):
        for _ in range(10):
            try:
                status, cluster_state = self.client.get_cluster_state(cluster_id)
                if self.is_ok(status):
                    break
            except:
                status = 500
                cluster_state = ""

            LOG.error("can not get cluster %s's state, try again" % cluster_id)
            time.sleep(6)

        return status, cluster_state

    def get_installing_progress(self, cluster_id):
        def _get_installing_progress():
            """get intalling progress."""
            deployment_timeout = time.time() + 60 * float(CONF.deployment_timeout)
            current_time = time.time
            while current_time() < deployment_timeout:
                status, cluster_state = self.get_cluster_state(cluster_id)
                if not self.is_ok(status):
                    raise RuntimeError("can not get cluster state")

                elif cluster_state["state"] == "SUCCESSFUL":
                    LOG.info("get cluster %s state status %s: %s, successful", cluster_id, status, cluster_state)
                    break
                elif cluster_state["state"] == "ERROR":
                    raise RuntimeError("get cluster %s state status %s: %s, error", (cluster_id, status, cluster_state))

                LOG.info("current_time=%s, deployment_timeout=%s" % (current_time(), deployment_timeout))
                time.sleep(5)

            if not current_time() < deployment_timeout:
                raise RuntimeError("installation timeout")

        try:
            _get_installing_progress()
        finally:
            # do this twice, make sure process be killed
            kill_print_proc()
            kill_print_proc()

    def check_dashboard_links(self, cluster_id):
        dashboard_url = CONF.dashboard_url
        if not dashboard_url:
            LOG.info("no dashboarde url set")
            return
        dashboard_link_pattern = re.compile(CONF.dashboard_link_pattern)
        r = requests.get(dashboard_url, verify=False)
        r.raise_for_status()
        match = dashboard_link_pattern.search(r.text)
        if match:
            LOG.info("dashboard login page for cluster %s can be downloaded", cluster_id)
        else:
            msg = ("%s failed to be downloaded\n" "the context is:\n%s\n") % (dashboard_url, r.text)
            raise Exception(msg)
Example #5
0
class CompassClient(object):
    def __init__(self):
        LOG.info("xh: compass_server=%s" % CONF.compass_server)
        self.client = Client(CONF.compass_server)
        self.subnet_mapping = {}
        self.role_mapping = {}
        self.host_mapping = {}
        self.host_ips = defaultdict(list)
        self.host_roles = {}

        self.login()

    def is_ok(self, status):
        if status < 300 and status >= 200:
            return True

    def login(self):
        status, resp = self.client.get_token(CONF.compass_user_email,
                                             CONF.compass_user_password)

        LOG.info('login status: %s, resp: %s', status, resp)
        if self.is_ok(status):
            return resp["token"]
        else:
            raise Exception('failed to login %s with user %s',
                            CONF.compass_server, CONF.compass_user_email)

    def get_machines(self):
        status, resp = self.client.list_machines()
        if not self.is_ok(status):
            LOG.error('get all machines status: %s, resp: %s', status, resp)
            raise RuntimeError('failed to get machines')

        machines_to_add = list(
            set([machine for machine in CONF.machines.split(',') if machine]))

        machines_db = [str(m["mac"]) for m in resp]
        LOG.info('machines in db: %s\n to add: %s', machines_db,
                 machines_to_add)
        if not set(machines_to_add).issubset(set(machines_db)):
            raise RuntimeError('unidentify machine to add')

        return [m["id"] for m in resp if str(m["mac"]) in machines_to_add]

    def list_clusters(self):
        status, resp = self.client.list_clusters(name=CONF.cluster_name)
        if not self.is_ok(status) or not resp:
            raise RuntimeError('failed to list cluster')

        cluster = resp[0]

        return cluster['id']

    def get_adapter(self):
        """get adapter."""
        status, resp = self.client.list_adapters(name=CONF.adapter_name)
        LOG.info('get all adapters status: %s, resp: %s', status, resp)

        if not self.is_ok(status) or not resp:
            raise RuntimeError('failed to get adapters')

        os_re = re.compile(CONF.adapter_os_pattern)
        flavor_re = re.compile(CONF.adapter_flavor_pattern)

        adapter_id = None
        os_id = None
        flavor_id = None
        adapter = None

        adapter = resp[0]
        adapter_id = adapter['id']
        for supported_os in adapter['supported_oses']:
            if not os_re or os_re.match(supported_os['name']):
                os_id = supported_os['os_id']
                break

        if 'flavors' in adapter:
            for flavor in adapter['flavors']:
                if not flavor_re or flavor_re.match(flavor['name']):
                    flavor_id = flavor['id']
                    break

        assert (os_id and flavor_id)
        return (adapter_id, os_id, flavor_id)

    def add_subnets(self):
        subnets = [subnet for subnet in CONF.subnets.split(',') if subnet]

        assert (subnets)

        subnet_mapping = {}
        _, subnets_in_db = self.client.list_subnets()
        for subnet in subnets:
            try:
                netaddr.IPNetwork(subnet)
            except:
                raise RuntimeError('subnet %s format is invalid' % subnet)

            if CONF.expansion == "false":
                status, resp = self.client.add_subnet(subnet)
                LOG.info('add subnet %s status %s response %s', subnet, status,
                         resp)
                if not self.is_ok(status):
                    raise RuntimeError('failed to add subnet %s' % subnet)
                subnet_mapping[resp['subnet']] = resp['id']
            else:
                for subnet_in_db in subnets_in_db:
                    if subnet == subnet_in_db['subnet']:
                        subnet_mapping[subnet] = subnet_in_db['id']

        self.subnet_mapping = subnet_mapping

    def add_cluster(self, adapter_id, os_id, flavor_id):
        """add a cluster."""
        cluster_name = CONF.cluster_name
        assert (cluster_name)
        status, resp = self.client.add_cluster(cluster_name, adapter_id, os_id,
                                               flavor_id)

        if not self.is_ok(status):
            raise RuntimeError("add cluster failed")

        LOG.info('add cluster %s status: %s resp:%s', cluster_name, status,
                 resp)

        if isinstance(resp, list):
            cluster = resp[0]
        else:
            cluster = resp

        cluster_id = cluster['id']
        flavor = cluster.get('flavor', {})
        roles = flavor.get('roles', [])

        for role in roles:
            if role.get('optional', False):
                self.role_mapping[role['name']] = ROLE_ASSIGNED
            else:
                self.role_mapping[role['name']] = ROLE_UNASSIGNED

        return cluster_id

    def add_cluster_hosts(self, cluster_id, machines):
        hostnames = [
            hostname for hostname in CONF.hostnames.split(',') if hostname
        ]

        machines = machines[-len(hostnames):]
        assert (len(machines) == len(hostnames))

        machines_dict = []
        for machine_id, hostname in zip(machines, hostnames):
            machines_dict.append({'machine_id': machine_id, 'name': hostname})

        # add hosts to the cluster.
        status, resp = self.client.add_hosts_to_cluster(
            cluster_id, {'machines': machines_dict})

        LOG.info('add machines %s to cluster %s status: %s, resp: %s',
                 machines_dict, cluster_id, status, resp)

        if not self.is_ok(status):
            raise RuntimeError("add host to cluster failed")

        for host in resp['hosts']:
            if host['hostname'] in hostnames:
                self.host_mapping[host['hostname']] = host['id']

        if CONF.expansion == "false":
            assert (len(self.host_mapping) == len(machines))

    def set_cluster_os_config(self, cluster_id):
        """set cluster os config."""
        os_config = {}
        language = CONF.language
        timezone = CONF.timezone
        http_proxy = CONF.http_proxy
        https_proxy = CONF.https_proxy
        local_repo_url = CONF.local_repo_url
        repo_name = CONF.repo_name
        deploy_type = CONF.deploy_type
        if not https_proxy and http_proxy:
            https_proxy = http_proxy

        no_proxy = [
            no_proxy for no_proxy in CONF.no_proxy.split(',') if no_proxy
        ]

        compass_server = CONF.compass_server
        if http_proxy:
            for hostname, ips in self.host_ips.items():
                no_proxy.append(hostname)
                no_proxy.extend(ips)

        ntp_server = CONF.ntp_server or compass_server

        dns_servers = [
            dns_server for dns_server in CONF.dns_servers.split(',')
            if dns_server
        ]
        if not dns_servers:
            dns_servers = [compass_server]

        domain = CONF.domain
        if not domain:
            raise Exception('domain is not defined')

        search_path = [
            search_path for search_path in CONF.search_path.split(',')
            if search_path
        ]

        if not search_path:
            search_path = [domain]

        default_gateway = CONF.default_gateway
        if not default_gateway:
            raise Exception('default gateway is not defined')

        general_config = {
            'language': language,
            'timezone': timezone,
            'ntp_server': ntp_server,
            'dns_servers': dns_servers,
            'default_gateway': default_gateway
        }

        if http_proxy:
            general_config['http_proxy'] = http_proxy
        if https_proxy:
            general_config['https_proxy'] = https_proxy
        if no_proxy:
            general_config['no_proxy'] = no_proxy
        if domain:
            general_config['domain'] = domain
        if search_path:
            general_config['search_path'] = search_path
        if local_repo_url:
            general_config['local_repo'] = local_repo_url
        if repo_name:
            general_config['repo_name'] = repo_name
        if deploy_type:
            general_config['deploy_type'] = deploy_type

        os_config["general"] = general_config

        server_credential = CONF.server_credential
        if '=' in server_credential:
            server_username, server_password = server_credential.split('=', 1)
        elif server_credential:
            server_username = server_password = server_credential
        else:
            server_username = '******'
            server_password = '******'

        os_config['server_credentials'] = {
            'username': server_username,
            'password': server_password
        }

        partitions = [
            partition for partition in CONF.partitions.split(',') if partition
        ]

        partition_config = {}
        for partition in partitions:
            assert ("=" in partition)

            partition_name, partition_value = partition.split('=', 1)
            partition_name = partition_name.strip()
            partition_value = partition_value.strip()

            assert (partition_name and partition_value)

            if partition_value.endswith('%'):
                partition_type = 'percentage'
                partition_value = int(partition_value[:-1])
            else:
                partition_type = 'size'

            partition_config[partition_name] = {
                partition_type: partition_value
            }

        os_config['partition'] = partition_config
        """
        os_config_filename = CONF.os_config_json_file
        if os_config_filename:
            util.merge_dict(
                os_config, _load_config(os_config_filename)
            )
        """

        status, resp = self.client.update_cluster_config(cluster_id,
                                                         os_config=os_config)
        LOG.info('set os config %s to cluster %s status: %s, resp: %s',
                 os_config, cluster_id, status, resp)
        if not self.is_ok(status):
            raise RuntimeError('failed to set os config %s to cluster %s' %
                               (os_config, cluster_id))

    def set_host_networking(self):
        """set cluster hosts networking."""
        def get_subnet(ip_str):
            try:
                LOG.info("subnets: %s" % self.subnet_mapping.keys())
                ip = netaddr.IPAddress(ip_str)
                for cidr, subnet_id in self.subnet_mapping.items():
                    subnet = netaddr.IPNetwork(cidr)
                    if ip in subnet:
                        return True, subnet_id

                    LOG.info("ip %s not in %s" % (ip_str, cidr))
                return False, None
            except:
                LOG.exception("ip addr %s is invalid" % ip_str)
                return False, None

        for host_network in CONF.host_networks.split(';'):
            hostname, networks_str = host_network.split(':', 1)
            hostname = hostname.strip()
            networks_str = networks_str.strip()

            assert (hostname in self.host_mapping)

            host_id = self.host_mapping[hostname]
            intf_list = networks_str.split(',')
            for intf_str in intf_list:
                interface, intf_properties = intf_str.split('=', 1)
                intf_properties = intf_properties.strip().split('|')

                assert (intf_properties)
                ip_str = intf_properties[0]

                status, subnet_id = get_subnet(ip_str)
                if not status:
                    raise RuntimeError("ip addr %s is invalid" % ip_str)

                properties = dict([(intf_property, True)
                                   for intf_property in intf_properties[1:]])

                LOG.info(
                    'add host %s interface %s ip %s network properties %s',
                    hostname, interface, ip_str, properties)

                status, response = self.client.add_host_network(
                    host_id,
                    interface,
                    ip=ip_str,
                    subnet_id=subnet_id,
                    **properties)

                LOG.info(
                    'add host %s interface %s ip %s network properties %s '
                    'status %s: %s', hostname, interface, ip_str, properties,
                    status, response)

                if not self.is_ok(status):
                    raise RuntimeError("add host network failed")

                self.host_ips[hostname].append(ip_str)

    def set_cluster_package_config(self, cluster_id):
        """set cluster package config."""
        package_config = {"security": {}}

        service_credentials = [
            service_credential
            for service_credential in CONF.service_credentials.split(',')
            if service_credential
        ]

        service_credential_cfg = {}
        LOG.info('service credentials: %s', service_credentials)

        for service_credential in service_credentials:
            if ':' not in service_credential:
                raise Exception('there is no : in service credential %s' %
                                service_credential  # noqa
                                )
            service_name, service_pair = service_credential.split(':', 1)
            if '=' not in service_pair:
                raise Exception('there is no = in service %s security' %
                                service_name)

            username, password = service_pair.split('=', 1)
            service_credential_cfg[service_name] = {
                'username': username,
                'password': password
            }

        console_credentials = [
            console_credential
            for console_credential in CONF.console_credentials.split(',')
            if console_credential
        ]

        LOG.info('console credentials: %s', console_credentials)

        console_credential_cfg = {}
        for console_credential in console_credentials:
            if ':' not in console_credential:
                raise Exception('there is no : in console credential %s' %
                                console_credential  # noqa
                                )
            console_name, console_pair = console_credential.split(':', 1)
            if '=' not in console_pair:
                raise Exception('there is no = in console %s security' %
                                console_name)
            username, password = console_pair.split('=', 1)
            console_credential_cfg[console_name] = {
                'username': username,
                'password': password
            }

        moon_cfgs = [cfg for cfg in CONF.moon_cfg.split(',') if cfg]
        LOG.info('moon configure: %s', moon_cfgs)
        moon_cfg = {}
        for cfg in moon_cfgs:
            if ':' not in cfg:
                raise Exception('there is no : in cfg %s' % cfg  # noqa
                                )
            role, conf_pair = cfg.split(':', 1)
            if '=' not in conf_pair:
                raise Exception('there is no = in %s configure pair' %
                                conf_pair)
            key, value = conf_pair.split('=', 1)
            moon_cfg[role] = {} if role not in moon_cfg else moon_cfg[role]
            moon_cfg[role][key] = value
        package_config["moon_cfg"] = moon_cfg

        package_config["security"] = {
            "service_credentials": service_credential_cfg,  # noqa
            "console_credentials": console_credential_cfg
        }  # noqa

        network_mapping = dict([
            network_pair.split('=', 1)
            for network_pair in CONF.network_mapping.split(',')
            if '=' in network_pair
        ])

        package_config['network_mapping'] = network_mapping

        assert (os.path.exists(CONF.network_cfg))
        network_cfg = yaml.safe_load(open(CONF.network_cfg))
        package_config["network_cfg"] = network_cfg

        assert (os.path.exists(CONF.neutron_cfg))
        neutron_cfg = yaml.safe_load(open(CONF.neutron_cfg))
        package_config["neutron_config"] = neutron_cfg
        """
        package_config_filename = CONF.package_config_json_file
        if package_config_filename:
            util.merge_dict(
                package_config, _load_config(package_config_filename)
            )
        """
        package_config['ha_proxy'] = {}
        if CONF.cluster_vip:
            package_config["ha_proxy"]["vip"] = CONF.cluster_vip

        package_config['enable_secgroup'] = (CONF.enable_secgroup == "true")
        package_config['enable_fwaas'] = (CONF.enable_fwaas == "true")
        package_config['enable_vpnaas'] = (CONF.enable_vpnaas == "true")
        package_config[
            'odl_l3_agent'] = "Enable" if CONF.odl_l3_agent == "Enable" else "Disable"  # noqa
        package_config[
            'onos_sfc'] = "Enable" if CONF.onos_sfc == "Enable" else "Disable"  # noqa
        package_config['plugins'] = []
        if CONF.plugins:
            for item in CONF.plugins.split(','):
                key, value = item.split(':')
                package_config['plugins'].append({key: value})

        status, resp = self.client.update_cluster_config(
            cluster_id, package_config=package_config)
        LOG.info('set package config %s to cluster %s status: %s, resp: %s',
                 package_config, cluster_id, status, resp)

        if not self.is_ok(status):
            raise RuntimeError("set cluster package_config failed")

    def set_host_roles(self, cluster_id, host_id, roles):
        status, response = self.client.update_cluster_host(cluster_id,
                                                           host_id,
                                                           roles=roles)

        LOG.info('set cluster %s host %s roles %s status %s: %s', cluster_id,
                 host_id, roles, status, response)

        if not self.is_ok(status):
            raise RuntimeError("set host roles failed")

        for role in roles:
            if role in self.role_mapping:
                self.role_mapping[role] = ROLE_ASSIGNED

    def set_all_hosts_roles(self, cluster_id):
        for host_str in CONF.host_roles.split(';'):
            host_str = host_str.strip()
            hostname, roles_str = host_str.split('=', 1)

            assert (hostname in self.host_mapping)
            host_id = self.host_mapping[hostname]

            roles = [role.strip() for role in roles_str.split(',') if role]

            self.set_host_roles(cluster_id, host_id, roles)
            self.host_roles[hostname] = roles

        unassigned_hostnames = list(
            set(self.host_mapping.keys()) -
            set(self.host_roles.keys()))  # noqa

        unassigned_roles = [
            role for role, status in self.role_mapping.items()
            if is_role_unassigned(status)
        ]

        assert (len(unassigned_hostnames) >= len(unassigned_roles))

        for hostname, role in map(None, unassigned_hostnames,
                                  unassigned_roles):
            host_id = self.host_mapping[hostname]
            self.set_host_roles(cluster_id, host_id, [role])
            self.host_roles[hostname] = [role]

        unassigned_hostnames = list(
            set(self.host_mapping.keys()) -
            set(self.host_roles.keys()))  # noqa

        if not unassigned_hostnames:
            return

        # assign default roles to unassigned hosts
        default_roles = [
            role for role in CONF.default_roles.split(',') if role
        ]

        assert (default_roles)

        cycle_roles = itertools.cycle(default_roles)
        for hostname in unassigned_hostnames:
            host_id = self.host_mapping[hostname]
            roles = [cycle_roles.next()]
            self.set_host_roles(cluster_id, host_id, roles)
            self.host_roles[hostname] = roles

    def deploy_clusters(self, cluster_id):
        host_ids = self.host_mapping.values()

        status, response = self.client.review_cluster(
            cluster_id, review={'hosts': host_ids})
        LOG.info('review cluster %s hosts %s, status %s: %s', cluster_id,
                 host_ids, status, response)

        # TODO, what this doning?
        if not self.is_ok(status):
            raise RuntimeError("review cluster host failed")

        status, response = self.client.deploy_cluster(
            cluster_id, deploy={'hosts': host_ids})
        LOG.info('deploy cluster %s hosts %s status %s: %s', cluster_id,
                 host_ids, status, response)

        if not self.is_ok(status):
            raise RuntimeError("deploy cluster failed")

    def redeploy_clusters(self, cluster_id):
        status, response = self.client.redeploy_cluster(cluster_id)

        if not self.is_ok(status):
            LOG.info('deploy cluster %s status %s: %s', cluster_id, status,
                     response)
            raise RuntimeError("redeploy cluster failed")

    def get_cluster_state(self, cluster_id):
        for _ in range(10):
            try:
                status, cluster_state = self.client.get_cluster_state(
                    cluster_id)
                if self.is_ok(status):
                    break
            except:
                status = 500
                cluster_state = ""

            LOG.error("can not get cluster %s's state, try again" % cluster_id)
            time.sleep(6)

        return status, cluster_state

    def get_ansible_print(self):
        def print_log(log):
            try:
                with open(log, 'r') as file:
                    while True:
                        line = file.readline()
                        if not line:
                            time.sleep(0.1)
                            continue
                        line = line.replace('\n', '')
                        print line
                        sys.stdout.flush()
            except:
                raise RuntimeError("open ansible.log error")

        current_time = time.time()
        install_timeout = current_time + 60 * CONF.install_os_timeout
        while current_time < install_timeout:
            ready = True
            for id in self.host_mapping.values():
                status, response = self.client.get_host_state(id)
                if response['state'] != 'SUCCESSFUL':
                    ready = False
                    break

            current_time = time.time()
            if not ready:
                time.sleep(8)
            else:
                break

        if current_time >= install_timeout:
            raise RuntimeError("OS installation timeout")
        else:
            LOG.info("OS installation complete")

        # time.sleep(CONF.ansible_start_wait)
        compass_dir = os.getenv('COMPASS_DIR')
        ansible_log = "%s/work/deploy/docker/ansible/run/%s-%s/ansible.log" \
                      % (compass_dir, CONF.adapter_name, CONF.cluster_name)
        os.system("sudo touch %s" % ansible_log)
        os.system("sudo chmod +x -R %s/work/deploy/docker/ansible/run/" %
                  compass_dir)
        ansible_print = multiprocessing.Process(target=print_log,
                                                args=(ansible_log, ))
        ansible_print.start()
        return ansible_print

    def get_installing_progress(self, cluster_id, ansible_print):
        def _get_installing_progress():
            """get intalling progress."""
            deployment_timeout = time.time() + 60 * float(
                CONF.deployment_timeout)  # noqa
            current_time = time.time
            while current_time() < deployment_timeout:
                if not ansible_print.is_alive():
                    raise RuntimeError("can not get ansible log")

                status, cluster_state = self.get_cluster_state(cluster_id)
                if not self.is_ok(status):
                    raise RuntimeError("can not get cluster state")

                elif cluster_state['state'] == 'SUCCESSFUL':
                    LOG.info('get cluster %s state status %s: %s, successful',
                             cluster_id, status, cluster_state)
                    break
                elif cluster_state['state'] == 'ERROR':
                    raise RuntimeError(
                        'get cluster %s state status %s: %s, error',
                        (cluster_id, status, cluster_state))

                time.sleep(10)

            if current_time() >= deployment_timeout:
                LOG.info("current_time=%s, deployment_timeout=%s" %
                         (current_time(), deployment_timeout))
                LOG.info("cobbler status:")
                os.system("sudo docker exec compass-cobbler bash -c \
                          'cobbler status'")
                raise RuntimeError("installation timeout")

        try:
            _get_installing_progress()
        finally:
            ansible_print.terminate()

    def check_dashboard_links(self, cluster_id):
        dashboard_url = CONF.dashboard_url
        if not dashboard_url:
            LOG.info('no dashboarde url set')
            return
        dashboard_link_pattern = re.compile(CONF.dashboard_link_pattern)
        r = requests.get(dashboard_url, verify=False)
        r.raise_for_status()
        match = dashboard_link_pattern.search(r.text)
        if match:
            LOG.info('dashboard login page for cluster %s can be downloaded',
                     cluster_id)
        else:
            msg = ('%s failed to be downloaded\n'
                   'the context is:\n%s\n') % (dashboard_url, r.text)
            raise Exception(msg)
Example #6
0
    'ROLES_LIST': ['allinone-compute'],
    'MACHINES_TO_ADD': ['00:0c:29:a7:ea:4b'],
    'BUILD_TIMEOUT': 60,
    'SEARCH_PATH': ['ods.com'],
    'SERVER_USERNAME': '******',
    'SERVER_PASSWORD': '******'
}
for v in PRESET_VALUES:
    if v in os.environ.keys():
        PRESET_VALUES[v] = os.environ.get(v)
        print (v + PRESET_VALUES[v] + " is set by env variables")
    else:
        print (PRESET_VALUES[v])

# instantiate a client
client = Client(COMPASS_SERVER_URL)

# login
status, response = client.login(COMPASS_LOGIN_EMAIL, COMPASS_LOGIN_PASSWORD)
print '============================================================'
print 'login status: %s response: %s' % (status, response)
if status >= 400:
    sys.exit(1)

# list all switches
status, response = client.list_switches()
print '============================================================='
print 'get all switches status: %s response: %s' % (status, response)

# add a switch
status, response = client.add_switch(
Example #7
0
    'ROLES_LIST': ['allinone-compute'],
    'MACHINES_TO_ADD': ['00:0c:29:a7:ea:4b'],
    'BUILD_TIMEOUT': 60,
    'SEARCH_PATH': ['ods.com'],
    'SERVER_USERNAME': '******',
    'SERVER_PASSWORD': '******'
}
for v in PRESET_VALUES:
    if v in os.environ.keys():
        PRESET_VALUES[v] = os.environ.get(v)
        print(v + PRESET_VALUES[v] + " is set by env variables")
    else:
        print(PRESET_VALUES[v])

# instantiate a client
client = Client(COMPASS_SERVER_URL)

# login
status, response = client.login(COMPASS_LOGIN_EMAIL, COMPASS_LOGIN_PASSWORD)
print '============================================================'
print 'login status: %s response: %s' % (status, response)
if status >= 400:
    sys.exit(1)

# list all switches
status, response = client.list_switches()
print '============================================================='
print 'get all switches status: %s response: %s' % (status, response)

# add a switch
status, response = client.add_switch(SWITCH_IP, SWITCH_SNMP_VERSION,
Example #8
0
class CompassClient(object):
    def __init__(self):
        LOG.info("xh: compass_server=%s" % CONF.compass_server)
        self.client = Client(CONF.compass_server)
        self.subnet_mapping = {}
        self.role_mapping = {}
        self.host_mapping = {}
        self.host_ips = defaultdict(list)
        self.host_roles = {}

        self.login()

    def is_ok(self, status):
        if status < 300 and status >= 200:
            return True

    def login(self):
        status, resp = self.client.get_token(
            CONF.compass_user_email,
            CONF.compass_user_password
        )

        LOG.info(
            'login status: %s, resp: %s',
            status, resp
        )
        if self.is_ok(status):
            return resp["token"]
        else:
            raise Exception(
                'failed to login %s with user %s',
                CONF.compass_server,
                CONF.compass_user_email
            )

    def get_machines(self):
        status, resp = self.client.list_machines()
        LOG.info(
            'get all machines status: %s, resp: %s', status, resp)
        if not self.is_ok(status):
            raise RuntimeError('failed to get machines')

        machines_to_add = list(set([
            machine for machine in CONF.machines.split(',')
            if machine
        ]))

        LOG.info('machines to add: %s', machines_to_add)
        machines_db = [str(m["mac"]) for m in resp]
        LOG.info('machines in db: %s', machines_db)
        assert(set(machines_db) == set(machines_to_add))

        return [m["id"] for m in resp]

    def get_adapter(self):
        """get adapter."""
        status, resp = self.client.list_adapters(name=CONF.adapter_name)
        LOG.info(
            'get all adapters status: %s, resp: %s',
            status, resp
        )

        if not self.is_ok(status) or not resp:
            raise RuntimeError('failed to get adapters')

        os_re = re.compile(CONF.adapter_os_pattern)
        flavor_re = re.compile(CONF.adapter_flavor_pattern)

        adapter_id = None
        os_id = None
        flavor_id = None
        adapter = None

        adapter = resp[0]
        adapter_id = adapter['id']
        for supported_os in adapter['supported_oses']:
            if not os_re or os_re.match(supported_os['name']):
                os_id = supported_os['os_id']
                break

        if 'flavors' in adapter:
            for flavor in adapter['flavors']:
                if not flavor_re or flavor_re.match(flavor['name']):
                    flavor_id = flavor['id']
                    break

        assert(os_id and flavor_id)
        return (adapter_id, os_id, flavor_id)

    def add_subnets(self):
        subnets = [
            subnet for subnet in CONF.subnets.split(',')
            if subnet
        ]

        assert(subnets)

        subnet_mapping = {}
        for subnet in subnets:
            try:
                netaddr.IPNetwork(subnet)
            except Exception:
                raise RuntimeError('subnet %s format is invalid' % subnet)

            status, resp = self.client.add_subnet(subnet)
            LOG.info(
                'add subnet %s status %s response %s',
                subnet,
                status,
                resp
            )
            if not self.is_ok(status):
                raise RuntimeError('failed to add subnet %s' % subnet)

            subnet_mapping[resp['subnet']] = resp['id']

        self.subnet_mapping = subnet_mapping

    def add_cluster(self, adapter_id, os_id, flavor_id):
        """add a cluster."""
        cluster_name = CONF.cluster_name
        assert(cluster_name)
        status, resp = self.client.add_cluster(
            cluster_name, adapter_id,
            os_id, flavor_id)

        if not self.is_ok(status):
            raise RuntimeError("add cluster failed")

        LOG.info(
            'add cluster %s status: %s resp:%s',
            cluster_name,
            status,
            resp
        )

        if isinstance(resp, list):
            cluster = resp[0]
        else:
            cluster = resp

        cluster_id = cluster['id']
        flavor = cluster.get('flavor', {})
        roles = flavor.get('roles', [])

        for role in roles:
            if role.get('optional', False):
                self.role_mapping[role['name']] = ROLE_ASSIGNED
            else:
                self.role_mapping[role['name']] = ROLE_UNASSIGNED

        return cluster_id

    def add_cluster_hosts(self, cluster_id, machines):
        hostnames = [
            hostname for hostname in CONF.hostnames.split(',')
            if hostname
        ]

        assert(len(machines) == len(hostnames))

        machines_dict = []
        for machine_id, hostname in zip(machines, hostnames):
            machines_dict.append({
                'machine_id': machine_id,
                'name': hostname
            })

        # add hosts to the cluster.
        status, resp = self.client.add_hosts_to_cluster(
            cluster_id,
            {'machines': machines_dict})

        LOG.info(
            'add machines %s to cluster %s status: %s, resp: %s',
            machines_dict,
            cluster_id,
            status,
            resp
        )

        if not self.is_ok(status):
            raise RuntimeError("add host to cluster failed")

        for host in resp['hosts']:
            self.host_mapping[host['hostname']] = host['id']

        assert(len(self.host_mapping) == len(machines))

    def set_cluster_os_config(self, cluster_id):
        """set cluster os config."""
        os_config = {}
        language = CONF.language
        timezone = CONF.timezone
        http_proxy = CONF.http_proxy
        https_proxy = CONF.https_proxy
        local_repo_url = CONF.local_repo_url
        repo_name = CONF.repo_name
        deploy_type = CONF.deploy_type
        if not https_proxy and http_proxy:
            https_proxy = http_proxy

        no_proxy = [
            no_proxy for no_proxy in CONF.no_proxy.split(',')
            if no_proxy
        ]

        compass_server = CONF.compass_server
        if http_proxy:
            for hostname, ips in self.host_ips.items():
                no_proxy.append(hostname)
                no_proxy.extend(ips)

        ntp_server = CONF.ntp_server or compass_server

        dns_servers = [
            dns_server for dns_server in CONF.dns_servers.split(',')
            if dns_server
        ]
        if not dns_servers:
            dns_servers = [compass_server]

        domain = CONF.domain
        if not domain:
            raise Exception('domain is not defined')

        search_path = [
            search_path for search_path in CONF.search_path.split(',')
            if search_path
        ]

        if not search_path:
            search_path = [domain]

        default_gateway = CONF.default_gateway
        if not default_gateway:
            raise Exception('default gateway is not defined')

        general_config = {
            'language': language,
            'timezone': timezone,
            'ntp_server': ntp_server,
            'dns_servers': dns_servers,
            'default_gateway': default_gateway
        }

        if http_proxy:
            general_config['http_proxy'] = http_proxy
        if https_proxy:
            general_config['https_proxy'] = https_proxy
        if no_proxy:
            general_config['no_proxy'] = no_proxy
        if domain:
            general_config['domain'] = domain
        if search_path:
            general_config['search_path'] = search_path
        if local_repo_url:
            general_config['local_repo'] = local_repo_url
        if repo_name:
            general_config['repo_name'] = repo_name
        if deploy_type:
            general_config['deploy_type'] = deploy_type

        os_config["general"] = general_config

        server_credential = CONF.server_credential
        if '=' in server_credential:
            server_username, server_password = server_credential.split('=', 1)
        elif server_credential:
            server_username = server_password = server_credential
        else:
            server_username = '******'
            server_password = '******'

        os_config['server_credentials'] = {
            'username': server_username,
            'password': server_password
        }

        partitions = [
            partition for partition in CONF.partitions.split(',')
            if partition
        ]

        partition_config = {}
        for partition in partitions:
            assert("=" in partition)

            partition_name, partition_value = partition.split('=', 1)
            partition_name = partition_name.strip()
            partition_value = partition_value.strip()

            assert(partition_name and partition_value)

            if partition_value.endswith('%'):
                partition_type = 'percentage'
                partition_value = int(partition_value[:-1])
            else:
                partition_type = 'size'

            partition_config[partition_name] = {
                partition_type: partition_value
            }

        os_config['partition'] = partition_config

        """
        os_config_filename = CONF.os_config_json_file
        if os_config_filename:
            util.merge_dict(
                os_config, _load_config(os_config_filename)
            )
        """

        status, resp = self.client.update_cluster_config(
            cluster_id, os_config=os_config)
        LOG.info(
            'set os config %s to cluster %s status: %s, resp: %s',
            os_config, cluster_id, status, resp)
        if not self.is_ok(status):
            raise RuntimeError('failed to set os config %s to cluster %s'
                               % (os_config, cluster_id))

    def set_host_networking(self):
        """set cluster hosts networking."""
        def get_subnet(ip_str):
            try:
                LOG.info("subnets: %s" % self.subnet_mapping.keys())
                ip = netaddr.IPAddress(ip_str)
                for cidr, subnet_id in self.subnet_mapping.items():
                    subnet = netaddr.IPNetwork(cidr)
                    if ip in subnet:
                        return True, subnet_id

                    LOG.info("ip %s not in %s" % (ip_str, cidr))
                return False, None
            except Exception:
                LOG.exception("ip addr %s is invalid" % ip_str)
                return False, None

        for host_network in CONF.host_networks.split(';'):
            hostname, networks_str = host_network.split(':', 1)
            hostname = hostname.strip()
            networks_str = networks_str.strip()

            assert(hostname in self.host_mapping)

            host_id = self.host_mapping[hostname]
            intf_list = networks_str.split(',')
            for intf_str in intf_list:
                interface, intf_properties = intf_str.split('=', 1)
                intf_properties = intf_properties.strip().split('|')

                assert(intf_properties)
                ip_str = intf_properties[0]

                status, subnet_id = get_subnet(ip_str)
                if not status:
                    raise RuntimeError("ip addr %s is invalid" % ip_str)

                properties = dict([
                    (intf_property, True)
                    for intf_property in intf_properties[1:]
                ])

                LOG.info(
                    'add host %s interface %s ip %s network proprties %s',
                    hostname, interface, ip_str, properties)

                status, response = self.client.add_host_network(
                    host_id, interface, ip=ip_str, subnet_id=subnet_id,
                    **properties
                )

                LOG.info(
                    'add host %s interface %s ip %s network properties %s '
                    'status %s: %s',
                    hostname, interface, ip_str, properties,
                    status, response
                )

                if not self.is_ok(status):
                    raise RuntimeError("add host network failed")

                self.host_ips[hostname].append(ip_str)

    def set_cluster_package_config(self, cluster_id):
        """set cluster package config."""
        package_config = {"security": {}}

        service_credentials = [
            service_credential
            for service_credential in CONF.service_credentials.split(',')
            if service_credential
        ]

        service_credential_cfg = {}
        LOG.info(
            'service credentials: %s', service_credentials
        )

        for service_credential in service_credentials:
            if ':' not in service_credential:
                raise Exception(
                    'no : in service credential %s' % service_credential
                )
            service_name, service_pair = service_credential.split(':', 1)
            if '=' not in service_pair:
                raise Exception(
                    'there is no = in service %s security' % service_name
                )

            username, password = service_pair.split('=', 1)
            service_credential_cfg[service_name] = {
                'username': username,
                'password': password
            }

        console_credentials = [
            console_credential
            for console_credential in CONF.console_credentials.split(',')
            if console_credential
        ]

        LOG.info(
            'console credentials: %s', console_credentials
        )

        console_credential_cfg = {}
        for console_credential in console_credentials:
            if ':' not in console_credential:
                raise Exception(
                    'there is no : in console credential %s'
                    % console_credential
                )
            console_name, console_pair = console_credential.split(':', 1)
            if '=' not in console_pair:
                raise Exception(
                    'there is no = in console %s security' % console_name
                )
            username, password = console_pair.split('=', 1)
            console_credential_cfg[console_name] = {
                'username': username,
                'password': password
            }

        package_config["security"] = {
            "service_credentials": service_credential_cfg,
            "console_credentials": console_credential_cfg
        }

        network_mapping = dict([
            network_pair.split('=', 1)
            for network_pair in CONF.network_mapping.split(',')
            if '=' in network_pair
        ])

        package_config['network_mapping'] = network_mapping

        assert(os.path.exists(CONF.network_cfg))
        network_cfg = yaml.load(open(CONF.network_cfg))
        package_config["network_cfg"] = network_cfg

        assert(os.path.exists(CONF.neutron_cfg))
        neutron_cfg = yaml.load(open(CONF.neutron_cfg))
        package_config["neutron_config"] = neutron_cfg

        """
        package_config_filename = CONF.package_config_json_file
        if package_config_filename:
            util.merge_dict(
                package_config, _load_config(package_config_filename)
            )
        """
        package_config['ha_proxy'] = {}
        if CONF.cluster_vip:
            package_config["ha_proxy"]["vip"] = CONF.cluster_vip

        package_config['enable_secgroup'] = (CONF.enable_secgroup == "true")

        status, resp = self.client.update_cluster_config(
            cluster_id, package_config=package_config)
        LOG.info(
            'set package config %s to cluster %s status: %s, resp: %s',
            package_config, cluster_id, status, resp)

        if not self.is_ok(status):
            raise RuntimeError("set cluster package_config failed")

    def set_host_roles(self, cluster_id, host_id, roles):
        status, response = self.client.update_cluster_host(
            cluster_id, host_id, roles=roles)

        LOG.info(
            'set cluster %s host %s roles %s status %s: %s',
            cluster_id, host_id, roles, status, response
        )

        if not self.is_ok(status):
            raise RuntimeError("set host roles failed")

        for role in roles:
            if role in self.role_mapping:
                self.role_mapping[role] = ROLE_ASSIGNED

    def set_all_hosts_roles(self, cluster_id):
        for host_str in CONF.host_roles.split(';'):
            host_str = host_str.strip()
            hostname, roles_str = host_str.split('=', 1)

            assert(hostname in self.host_mapping)
            host_id = self.host_mapping[hostname]

            roles = [role.strip() for role in roles_str.split(',') if role]

            self.set_host_roles(cluster_id, host_id, roles)
            self.host_roles[hostname] = roles

        unassigned_hostnames = list(set(self.host_mapping.keys())
                                    - set(self.host_roles.keys()))

        unassigned_roles = [role for role, status in self.role_mapping.items()
                            if is_role_unassigned(status)]

        assert(len(unassigned_hostnames) >= len(unassigned_roles))

        for hostname, role in map(
            None,
            unassigned_hostnames,
            unassigned_roles
        ):
            host_id = self.host_mapping[hostname]
            self.set_host_roles(cluster_id, host_id, [role])
            self.host_roles[hostname] = [role]

        unassigned_hostnames = list(set(self.host_mapping.keys())
                                    - set(self.host_roles.keys()))

        if not unassigned_hostnames:
            return

        # assign default roles to unassigned hosts
        default_roles = [
            role for role in CONF.default_roles.split(',')
            if role
        ]

        assert(default_roles)

        cycle_roles = itertools.cycle(default_roles)
        for hostname in unassigned_hostnames:
            host_id = self.host_mapping[hostname]
            roles = [cycle_roles.next()]
            self.set_host_roles(cluster_id, host_id, roles)
            self.host_roles[hostname] = roles

    def deploy_clusters(self, cluster_id):
        host_ids = self.host_mapping.values()

        status, response = self.client.review_cluster(
            cluster_id, review={'hosts': host_ids}
        )
        LOG.info(
            'review cluster %s hosts %s, status %s: %s',
            cluster_id, host_ids, status, response
        )

        # TODO('what this doning?')
        if not self.is_ok(status):
            raise RuntimeError("review cluster host failed")

        status, response = self.client.deploy_cluster(
            cluster_id, deploy={'hosts': host_ids}
        )
        LOG.info(
            'deploy cluster %s hosts %s status %s: %s',
            cluster_id, host_ids, status, response
        )

        if not self.is_ok(status):
            raise RuntimeError("deploy cluster failed")

    def get_installing_progress(self, cluster_id):
        """get intalling progress."""
        action_timeout = time.time() + 60 * float(CONF.action_timeout)
        deployment_timeout = time.time() + 60 * float(
            CONF.deployment_timeout)

        current_time = time.time()
        deployment_failed = True
        while current_time < deployment_timeout:
            status, cluster_state = self.client.get_cluster_state(cluster_id)
            LOG.info(
                'get cluster %s state status %s: %s',
                cluster_id, status, cluster_state
            )
            if not self.is_ok(status):
                raise RuntimeError("can not get cluster state")

            if cluster_state['state'] in ['UNINITIALIZED', 'INITIALIZED']:
                if current_time >= action_timeout:
                    deployment_failed = True
                    break
                else:
                    continue

            elif cluster_state['state'] == 'SUCCESSFUL':
                deployment_failed = False
                break
            elif cluster_state['state'] == 'ERROR':
                deployment_failed = True
                break

        if deployment_failed:
            raise RuntimeError("deploy cluster failed")

    def check_dashboard_links(self, cluster_id):
        dashboard_url = CONF.dashboard_url
        if not dashboard_url:
            LOG.info('no dashboarde url set')
            return
        dashboard_link_pattern = re.compile(
            CONF.dashboard_link_pattern)
        r = requests.get(dashboard_url, verify=False)
        r.raise_for_status()
        match = dashboard_link_pattern.search(r.text)
        if match:
            LOG.info(
                'dashboard login page for cluster %s can be downloaded',
                cluster_id)
        else:
            msg = (
                '%s failed to be downloaded\n'
                'the context is:\n%s\n'
            ) % (dashboard_url, r.text)
            raise Exception(msg)