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
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