def download_iso(self, name, path):
     infra_env = self.info_infra_env(name).to_dict()
     iso_url = infra_env['download_url']
     if self._expired_iso(iso_url):
         warning("Generating new iso url")
         iso_url = self.client.get_infra_env_download_url(infra_env['id']).url
     urlretrieve(iso_url, f"{path}/{name}.iso")
 def create_cluster(self, name, overrides={}):
     existing_ids = [x['id'] for x in self.list_clusters() if x['name'] == name]
     if existing_ids:
         error(f"Cluster {name} already there. Leaving")
         sys.exit(1)
     if name.endswith('-day2'):
         self.create_day2_cluster(name, overrides)
         return
     self.set_default_values(overrides)
     new_cluster_params = default_cluster_params
     new_cluster_params['name'] = name
     extra_overrides = {}
     allowed_parameters = self._allowed_parameters(models.ClusterCreateParams)
     for parameter in overrides:
         if parameter == 'network_type' and overrides[parameter] not in ['OpenShiftSDN', 'OVNKubernetes']:
             extra_overrides[parameter] = overrides[parameter]
             continue
         if parameter in ['cluster_networks', 'service_networks']:
             extra_overrides[parameter] = overrides[parameter]
             continue
         if parameter in allowed_parameters:
             new_cluster_params[parameter] = overrides[parameter]
         elif parameter not in ['api_ip', 'ingress_ip']:
             extra_overrides[parameter] = overrides[parameter]
         else:
             warning(f"Omitting parameter {parameter} at creation time")
     cluster_params = models.ClusterCreateParams(**new_cluster_params)
     self.client.v2_register_cluster(new_cluster_params=cluster_params)
     if extra_overrides:
         self.update_cluster(name, extra_overrides)
 def __init__(self, url, token=None, offlinetoken=None):
     self.url = url
     self.config = Configuration()
     self.config.host = self.url + "/api/assisted-install"
     self.config.verify_ssl = False
     proxies = urllib.request.getproxies()
     if proxies:
         proxy = proxies.get('https') or proxies.get('http')
         if 'http' not in proxy:
             proxy = "http://" + proxy
             warning(f"Detected proxy env var without scheme, updating proxy to {proxy}")
         self.config.proxy = proxy
     aihome = f"{os.environ['HOME']}/.aicli"
     if not os.path.exists(aihome):
         os.mkdir(aihome)
     if url in ['https://api.openshift.com', 'https://api.stage.openshift.com']:
         if offlinetoken is None:
             if os.path.exists(f'{aihome}/offlinetoken.txt'):
                 offlinetoken = open(f'{aihome}/offlinetoken.txt').read().strip()
             else:
                 error(f"offlinetoken needs to be set to gather token for {url}")
                 error("get it at https://cloud.redhat.com/openshift/token")
                 if os.path.exists('/i_am_a_container'):
                     error("use -e AI_OFFLINETOKEN=$AI_OFFLINETOKEN to expose it in container mode")
                 sys.exit(1)
         if not os.path.exists(f'{aihome}/offlinetoken.txt'):
             with open(f'{aihome}/offlinetoken.txt', 'w') as f:
                 f.write(offlinetoken)
         self.offlinetoken = offlinetoken
         self.token = token
         if os.path.exists(f'{aihome}/token.txt'):
             self.token = open(f'{aihome}/token.txt').read().strip()
         try:
             self.token = get_token(token=self.token, offlinetoken=self.offlinetoken)
         except Exception as e:
             error(f"Hit issue when trying to set token. Got {e}")
             if os.path.exists(f'{aihome}/offlinetoken.txt'):
                 error("Removing offlinetoken file")
                 os.remove(f'{aihome}/offlinetoken.txt')
             sys.exit(1)
         self.config.api_key['Authorization'] = self.token
         self.config.api_key_prefix['Authorization'] = 'Bearer'
     self.api = ApiClient(configuration=self.config)
     self.client = api.InstallerApi(api_client=self.api)
 def upload_manifests(self, name, directory, openshift=False):
     cluster_id = self.get_cluster_id(name)
     if not os.path.exists(directory):
         error(f"Directory {directory} not found")
         sys.exit(1)
     elif not os.path.isdir(directory):
         error(f"{directory} is not a directory")
         sys.exit(1)
     manifests_api = api.ManifestsApi(api_client=self.api)
     _fics = os.listdir(directory)
     if not _fics:
         error(f"No files found in directory {directory}")
         sys.exit(0)
     for _fic in _fics:
         if not _fic.endswith('.yml') and not _fic.endswith('.yaml'):
             warning(f"skipping file {_fic}")
             continue
         info(f"uploading file {_fic}")
         content = base64.b64encode(open(f"{directory}/{_fic}").read().encode()).decode("UTF-8")
         folder = 'manifests' if not openshift else 'openshift'
         manifest_info = {'file_name': _fic, 'content': content, 'folder': folder}
         create_manifest_params = models.CreateManifestParams(**manifest_info)
         manifests_api.v2_create_cluster_manifest(cluster_id, create_manifest_params)
 def set_default_values(self, overrides, existing=False):
     if 'openshift_version' in overrides and isinstance(overrides['openshift_version'], float):
         overrides['openshift_version'] = str(overrides['openshift_version'])
     if 'domain' in overrides:
         overrides['base_dns_domain'] = overrides['domain']
     if not existing:
         if 'pull_secret' not in overrides:
             warning("Using openshift_pull.json as pull_secret file")
             overrides['pull_secret'] = "openshift_pull.json"
         pull_secret = os.path.expanduser(overrides['pull_secret'])
         if not os.path.exists(pull_secret):
             error(f"Missing pull secret file {pull_secret}")
             sys.exit(1)
         overrides['pull_secret'] = re.sub(r"\s", "", open(pull_secret).read())
         if 'ssh_public_key' not in overrides:
             pub_key = overrides.get('public_key', f"{os.environ['HOME']}/.ssh/id_rsa.pub")
             if os.path.exists(pub_key):
                 overrides['ssh_public_key'] = open(pub_key).read().strip()
             else:
                 error(f"Missing public key file {pub_key}")
                 sys.exit(1)
     if 'sno' in overrides:
         if overrides['sno']:
             overrides['high_availability_mode'] = "None"
             overrides['user_managed_networking'] = True
     if 'high_availability_mode' in overrides and overrides['high_availability_mode'] is None:
         overrides['high_availability_mode'] = "None"
     if 'olm_operators' in overrides:
         overrides['olm_operators'] = self.set_olm_operators(overrides['olm_operators'])
     if 'tpm' in overrides and overrides['tpm']:
         overrides['disk_encryption'] = {"enable_on": "all", "mode": "tpmv2"}
     if 'tang_servers' in overrides:
         tang_servers = overrides['tang_servers']
         if isinstance(tang_servers, list):
             tang_servers = ','.join(tang_servers)
         overrides['disk_encryption'] = {"enable_on": "all", "mode": "tpmv2", "tang_servers": tang_servers}
 def update_cluster(self, name, overrides):
     cluster_id = self.get_cluster_id(name)
     if 'api_ip' in overrides:
         overrides['api_vip'] = overrides['api_ip']
     if 'ingress_ip' in overrides:
         overrides['ingress_vip'] = overrides['ingress_ip']
     if 'pull_secret' in overrides:
         pull_secret = os.path.expanduser(overrides['pull_secret'])
         if os.path.exists(pull_secret):
             overrides['pull_secret'] = re.sub(r"\s", "", open(pull_secret).read())
         else:
             warning("Using pull_secret as string")
     if 'role' in overrides:
         role = overrides['role']
         hosts_roles = [{"id": host['id'], "role": role} for host in self.client.list_hosts(cluster_id=cluster_id)]
         overrides['hosts_roles'] = hosts_roles
     installconfig = {}
     if 'network_type' in overrides:
         installconfig['networking'] = {'networkType': overrides['network_type']}
         del overrides['network_type']
     if 'sno_disk' in overrides:
         sno_disk = overrides['sno_disk']
         if '/dev' not in sno_disk:
             sno_disk = f'/dev/{sno_disk}'
         installconfig['BootstrapInPlace'] = {'InstallationDisk': sno_disk}
     if 'tpm' in overrides and overrides['tpm']:
         if overrides.get('tpm_masters', False):
             enable_on = 'masters'
         elif overrides.get('tpm_workers', False):
             enable_on = 'masters'
         else:
             enable_on = 'all'
         installconfig['disk_encryption'] = {"enable_on": enable_on, "mode": "tpmv2"}
     if 'tang_servers' in overrides and isinstance(overrides['tang_servers'], list):
         if overrides.get('tpm_masters', False):
             enable_on = 'masters'
         elif overrides.get('tpm_workers', False):
             enable_on = 'masters'
         else:
             enable_on = 'all'
         tang_servers = overrides['tang_servers']
         installconfig['disk_encryption'] = {"enable_on": "all", "mode": "tpmv2", "tang_servers": tang_servers}
     if 'proxy' in overrides:
         proxy = overrides['proxy']
         if isinstance(proxy, str):
             httpProxy, httpsProxy = proxy, proxy
             noproxy = overrides.get('noproxy')
         elif isinstance(proxy, dict):
             httpProxy = proxy.get('http_proxy') or proxy.get('httpProxy')
             httpsProxy = proxy.get('https_proxy') or proxy.get('httpsProxy')
             noproxy = proxy.get('no_proxy') or proxy.get('noProxy')
         else:
             error(f"Invalid entry for proxy: {proxy}")
             sys.exit(1)
         if not httpProxy.startswith('http'):
             httpProxy = f'http://{httpProxy}'
         if not httpsProxy.startswith('http'):
             httpsProxy = f'http://{httpsProxy}'
         installconfig['proxy'] = {'httpProxy': httpProxy, 'httpsProxy': httpsProxy, 'noProxy': noproxy}
     if 'installconfig' in overrides:
         installconfig = overrides['installconfig']
     if installconfig:
         self.client.v2_update_cluster_install_config(cluster_id, json.dumps(installconfig))
     if 'olm_operators' in overrides:
         overrides['olm_operators'] = self.set_olm_operators(overrides['olm_operators'])
     if 'machine_networks' in overrides:
         overrides['machine_networks'] = self.set_machine_networks(cluster_id, overrides['machine_networks'])
     if 'service_networks' in overrides:
         overrides['service_networks'] = self.set_service_networks(cluster_id, overrides['service_networks'])
     if 'cluster_networks' in overrides:
         overrides['cluster_networks'] = self.set_cluster_networks(cluster_id, overrides['cluster_networks'])
     if overrides:
         cluster_update_params = overrides.copy()
         allowed_parameters = self._allowed_parameters(models.V2ClusterUpdateParams)
         for parameter in overrides:
             if parameter not in allowed_parameters:
                 del cluster_update_params[parameter]
         cluster_update_params = models.V2ClusterUpdateParams(**cluster_update_params)
         self.client.v2_update_cluster(cluster_id=cluster_id, cluster_update_params=cluster_update_params)
 def update_host(self, hostname, overrides):
     infra_envs = {}
     if 'infraenv' in overrides:
         infra_env = overrides['infraenv']
         infra_env_id = self.get_infra_env_id(infra_env)
         hosts = self.client.v2_list_hosts(infra_env_id=infra_env_id)
         matchingids = [host['id'] for host in hosts
                        if host['requested_hostname'] == hostname or host['id'] == hostname]
     else:
         for infra_env in self.client.list_infra_envs():
             infra_env_id = infra_env['id']
             hosts = self.client.v2_list_hosts(infra_env_id=infra_env_id)
             matchingids = [host['id'] for host in hosts
                            if host['requested_hostname'] == hostname or host['id'] == hostname]
             if matchingids:
                 infra_envs[infra_env_id] = matchingids
     if not infra_envs:
         error(f"No Matching Host with name {hostname} found")
     for infra_env_id in infra_envs:
         host_ids = infra_envs[infra_env_id]
         for index, host_id in enumerate(host_ids):
             role = None
             bind_updated = False
             host_update_params = {}
             if 'cluster' in overrides:
                 cluster = overrides['cluster']
                 if cluster is None or cluster == '':
                     self.client.unbind_host(infra_env_id=infra_env_id, host_id=host_id)
                 else:
                     cluster_id = self.get_cluster_id(cluster)
                     bind_host_params = {'cluster_id': cluster_id}
                     bind_host_params = models.BindHostParams(**bind_host_params)
                     self.client.bind_host(infra_env_id, host_id, bind_host_params)
                 bind_updated = True
             if 'role' in overrides:
                 role = overrides['role']
                 host_update_params['host_role'] = role
             if 'name' in overrides or 'requested_hostname' in overrides:
                 newname = overrides.get('name', overrides.get('requested_hostname'))
                 if len(host_ids) > 1:
                     newname = f"{newname}-{index}"
                 host_update_params['host_name'] = newname
             if 'ignition' in overrides:
                 ignition_path = overrides['ignition']
                 if not os.path.exists(ignition_path):
                     warning(f"Ignition {ignition_path} not found. Ignoring")
                 else:
                     ignition_data = open(ignition_path).read()
                     host_ignition_params = models.HostIgnitionParams(config=ignition_data)
                     self.client.v2_update_host_ignition(infra_env_id, host_id, host_ignition_params)
             if 'extra_args' in overrides and cluster_id is not None:
                 extra_args = overrides['extra_args']
                 installer_args_params = models.InstallerArgsParams(args=extra_args)
                 self.client.v2_update_host_installer_args(cluster_id, host_id, installer_args_params)
             if 'mcp' in overrides:
                 valid_status = ["discovering", "known", "disconnected", "insufficient", "pending-for-input"]
                 currenthost = self.client.v2_get_host(infra_env_id=infra_env_id, host_id=host_id)
                 currentstatus = currenthost.status
                 if currentstatus not in valid_status:
                     error(f"Mcp can't be set for host {hostname} because of incorrect status {currentstatus}")
                 else:
                     mcp = overrides['mcp']
                     host_update_params['machine_config_pool_name'] = mcp
             if host_update_params:
                 info(f"Updating host with id {host_id}")
                 host_update_params = models.HostUpdateParams(**host_update_params)
                 self.client.v2_update_host(infra_env_id=infra_env_id, host_id=host_id,
                                            host_update_params=host_update_params)
             elif not bind_updated:
                 warning("Nothing updated for this host")
 def create_day2_cluster(self, name, overrides={}):
     cluster_name = name.replace('-day2', '')
     cluster_id = None
     existing_ids = [x['id'] for x in self.list_clusters() if x['name'] == cluster_name]
     api_ip = None
     if not existing_ids:
         warning(f"Base Cluster {cluster_name} not found. Populating with default values")
         if 'version' in overrides:
             openshift_version = overrides['version']
         elif 'openshift_version' in overrides:
             openshift_version = overrides['openshift_version']
         else:
             openshift_version = default_cluster_params["openshift_version"]
             warning(f"No openshift_version provided.Using {openshift_version}")
         if 'domain' in overrides:
             domain = overrides['domain']
             del overrides['domain']
         elif 'base_dns_domain' in overrides:
             domain = overrides['base_dns_domain']
         else:
             domain = default_cluster_params["base_dns_domain"]
             warning(f"No base_dns_domain provided.Using {domain}")
         overrides['base_dns_domain'] = domain
         api_name = "api." + cluster_name + "." + domain
         self.set_default_values(overrides)
         pull_secret, ssh_public_key = overrides['pull_secret'], overrides['ssh_public_key']
     else:
         cluster_id = self.get_cluster_id(cluster_name)
         cluster = self.client.v2_get_cluster(cluster_id=cluster_id)
         openshift_version = cluster.openshift_version
         ssh_public_key = cluster.image_info.ssh_public_key
         api_name = "api." + cluster_name + "." + cluster.base_dns_domain
         api_ip = cluster.api_vip
         response = self.client.v2_download_cluster_files(cluster_id=cluster_id, file_name="install-config.yaml",
                                                          _preload_content=False)
         data = yaml.safe_load(response.read().decode("utf-8"))
         pull_secret = data.get('pullSecret')
     try:
         socket.gethostbyname(api_name)
     except:
         if api_ip is not None:
             warning(f"Forcing api_vip_dnsname to {api_ip}")
             api_name = api_ip
         else:
             warning(f"{api_name} doesn't resolve")
             warning(f"run aicli update cluster {name} -P api_vip_dnsname=$api_ip")
     if cluster_id is None:
         cluster_id = str(uuid1())
     new_import_cluster_params = {"name": name, "openshift_version": str(openshift_version),
                                  "api_vip_dnsname": api_name, 'openshift_cluster_id': cluster_id}
     new_import_cluster_params = models.ImportClusterParams(**new_import_cluster_params)
     self.client.v2_import_cluster(new_import_cluster_params=new_import_cluster_params)
     cluster_update_params = {'pull_secret': pull_secret, 'ssh_public_key': ssh_public_key}
     cluster_update_params = models.ClusterUpdateParams(**cluster_update_params)
     new_cluster_id = self.get_cluster_id(name)
     self.client.v2_update_cluster(cluster_id=new_cluster_id, cluster_update_params=cluster_update_params)