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)