Example #1
0
    def create_ansible_host(self, name):
        """Create host entry for Ansible inventory."""
        meta_host, meta_domain = get_host_from_metadata(self._metadata, name)
        db_host = self._db.hosts[name]

        ip = db_host.ip
        ansible_host = resolve_hostname(ip) or ip

        python = (
            self._config["python"].get(meta_host["os"])
            or self._config["python"]["default"]
        )

        ansible_user = get_username(db_host, meta_host, self._config)
        password = get_password(db_host, meta_host, self._config)
        ssh_key = get_ssh_key(db_host, meta_host, self._config)

        # Common attributes
        host_info = {
            "ansible_host": ansible_host,
            "ansible_python_interpreter": python,
            "ansible_user": ansible_user,
            "meta_fqdn": name,
            "meta_domain": meta_domain["name"],
            "meta_provider_id": db_host.id,
            "meta_ip": ip,
            "meta_dc_record": ",".join(
                "DC=%s" % dc for dc in meta_domain["name"].split(".")
            ),
        }
        copy_meta_attrs(host_info, meta_host, ["os", "role", "netbios"])

        if "parent" in meta_domain:
            host_info["parent_domain"] = meta_domain["parent"]

        if ssh_key:
            host_info["ansible_ssh_private_key_file"] = ssh_key

        if password:
            host_info["ansible_password"] = password

        if is_windows_host(meta_host):
            host_info.update(
                {
                    "ansible_port": 5986,
                    "ansible_connection": "winrm",
                    "ansible_winrm_server_cert_validation": "ignore",
                    "meta_domain_level": meta_host.get("domain_level", "top"),
                }
            )
        return host_info
Example #2
0
    def create_multihost_config(self):  # pylint: disable=too-many-branches
        """
        Create configuration file for python-pytest-multihost.

        Return in form of dict.
        """
        mhcfg = deepcopy(self._metadata)

        if "phases" in mhcfg:
            del mhcfg["phases"]

        # topology config in metadata contains more values (os, group) than the ones
        # needed by pytest multihost. They need to be removed in order to work.
        host_allowed_attrs = [
            "name",
            "role",
            "hostname",
            "shortname",
            "external_hostname",
            "ip",
            "domain",
            "username",
            "password",
            "host_type",
        ]

        # Use values from provisioning-config mhcfg section - as default values
        for option in self._config["mhcfg"]:
            # options defined in metadata takes precedence over options in
            # provisioning-config as it is "closer" to user.
            if option in mhcfg:
                continue
            mhcfg[option] = self._config["mhcfg"][option]

        for domain in mhcfg["domains"]:
            for host in domain["hosts"]:
                provisioned_host = self._db.hosts.get(host["name"])
                if not provisioned_host:
                    logger.error(
                        f"Host {host['name']} not found in the database.")
                    continue

                password = get_password(provisioned_host, host, self._config)
                # pytest-multihost doesn't support different ssh_keys per host

                if password:
                    host["password"] = password

                ip_addr = provisioned_host.ip_addr
                dns_record = resolve_hostname(ip_addr)
                host["ip"] = ip_addr

                # Using IP as backup for external host name as pytest-multihost is using
                # external_hostname as the host to use in ssh command.
                # If it is not available it uses hostname, but we assume here that
                # hostname is internal and thus not resolvable. IP should be resolvable.
                host["external_hostname"] = dns_record or ip_addr

                if is_windows_host(host):
                    # Set username for Windows, as default for multihost is often 'root'
                    # which doesn't usually work there. But do not set it for other OSes
                    # due to:
                    #  7bb230e170ac0a2373a2316ef23a26bfcb681ad9
                    # TODO: come up with a configurable mechanism which is not based on
                    # so many assumptions.
                    username = get_username(provisioned_host, host,
                                            self._config)
                    if username:
                        host["username"] = username

                if host["group"] == "ad_root":
                    mhcfg["ad_top_domain"] = domain["name"]
                    mhcfg["ad_hostname"] = host["name"]
                    mhcfg["ad_ip"] = host["ip"]
                elif host["group"] == "ad_subdomain":
                    mhcfg["ad_sub_domain"] = domain["name"]
                    mhcfg["ad_sub_hostname"] = host["name"]
                    mhcfg["ad_sub_ip"] = host["ip"]

                rm_keys = [
                    key for key in host.keys() if key not in host_allowed_attrs
                ]
                for key in rm_keys:
                    del host[key]

            domain_rm_keys = [
                key for key in domain.keys()
                if key not in ["name", "type", "hosts"]
            ]
            for key in domain_rm_keys:
                del domain[key]

        # ssh_key_filename must be absolute as it can be used from a different
        # working directory, e.g. running tests from git repo
        ssh_key_filename = mhcfg.get("ssh_key_filename")

        # Update with SSH key path only if not already defined in mhcfg
        if ssh_key_filename and not self._metadata.get("ssh_key_filename"):
            mhcfg["ssh_key_filename"] = os.path.abspath(ssh_key_filename)

        return mhcfg
Example #3
0
    def create_multihost_config(self):
        """
        Create configuration file for python-pytest-multihost.

        Return in form of dict.
        """
        mhcfg = deepcopy(self._metadata)

        if "phases" in mhcfg:
            del mhcfg["phases"]

        # topology config in metadata contains more values (os, group) than the ones
        # needed by pytest multihost. They need to be removed in order to work.
        host_allowed_attrs = [
            "name",
            "role",
            "hostname",
            "shortname",
            "external_hostname",
            "ip",
            "domain",
            "username",
            "password",
            "host_type",
        ]
        domain_allowed_attrs = ["name", "type", "hosts"]

        # Use values from provisioning-config mhcfg section - as default values
        for option in self._config["mhcfg"]:
            # options defined in metadata takes precedence over options in
            # provisioning-config as it is "closer" to user.
            if option in mhcfg:
                continue
            mhcfg[option] = self._config["mhcfg"][option]

        for domain in mhcfg["domains"]:
            for host in domain["hosts"]:
                provisioned_host = self._db.hosts.get(host["name"])
                if not provisioned_host:
                    logger.error(f"Host {host['name']} not found in the database.")
                    continue

                username = get_username(provisioned_host, host, self._config)
                password = get_password(provisioned_host, host, self._config)
                # pytest-multihost doesn't support different ssh_keys per host

                if username:
                    host["username"] = username
                if password:
                    host["password"] = password

                ip = provisioned_host.ip
                dns_record = resolve_hostname(ip)
                host["ip"] = ip
                host["external_hostname"] = dns_record

                if host["group"] == "ad_root":
                    mhcfg["ad_top_domain"] = domain["name"]
                    mhcfg["ad_hostname"] = host["name"]
                    mhcfg["ad_ip"] = host["ip"]
                elif host["group"] == "ad_subdomain":
                    mhcfg["ad_sub_domain"] = domain["name"]
                    mhcfg["ad_sub_hostname"] = host["name"]
                    mhcfg["ad_sub_ip"] = host["ip"]

                rm_keys = [key for key in host.keys() if key not in host_allowed_attrs]
                for key in rm_keys:
                    del host[key]

            domain_rm_keys = [
                key for key in domain.keys() if key not in domain_allowed_attrs
            ]
            for key in domain_rm_keys:
                del domain[key]

        # ssh_key_filename must be absolute as it can be used from a different
        # working directory, e.g. running tests from git repo
        ssh_key_filename = self._config.get("ssh_key_filename")
        if ssh_key_filename and not ssh_key_filename.startswith("~"):
            mhcfg["ssh_key_filename"] = os.path.abspath(ssh_key_filename)

        return mhcfg