def get_cluster_name(self, _id):
     matching_names = [x['name'] for x in self.list_clusters() if x['id'] == _id]
     if matching_names:
         return matching_names[0]
     else:
         error(f"Cluster {_id} not found")
         sys.exit(1)
 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 get_infra_env_name(self, _id):
     matching_names = [x['name'] for x in self.list_infra_envs() if x['id'] == _id]
     if matching_names:
         return matching_names[0]
     else:
         error(f"Infraenv {_id} not found")
         sys.exit(1)
 def get_cluster_id(self, name):
     matching_ids = [x['id'] for x in self.list_clusters() if x['name'] == name or x['id'] == name]
     if matching_ids:
         return matching_ids[0]
     else:
         error(f"Cluster {name} not found")
         sys.exit(1)
 def get_infra_env_id(self, name):
     valid_names = [name, f'{name}_infra-env']
     matching_ids = [x['id'] for x in self.list_infra_envs() if x['name'] in valid_names or x['id'] == name]
     if matching_ids:
         return matching_ids[0]
     else:
         error(f"Infraenv {name} not found")
         sys.exit(1)
 def _expired_iso(self, iso_url):
     search = re.search(r".*&image_token=(.*)&type=.*", iso_url)
     if search is not None:
         encoded_token = search.group(1)
         token = str(base64.urlsafe_b64decode(encoded_token + '==='))
         expiration_date = int(re.search(r'.*"exp":(.*),"sub".*"', token).group(1))
         if datetime.fromtimestamp(expiration_date) < datetime.now():
             return True
         else:
             return False
     else:
         error("couldn't parse iso_url")
         sys.exit(1)
 def set_default_infraenv_values(self, overrides):
     if 'cluster' in overrides:
         cluster_id = self.get_cluster_id(overrides['cluster'])
         overrides['cluster_id'] = cluster_id
     if 'minimal' in overrides:
         image_type = "minimal-iso" if overrides['minimal'] else 'full-iso'
         overrides['image_type'] = image_type
     static_network_config = overrides.get('static_network_config', [])
     if static_network_config:
         if isinstance(static_network_config, dict):
             static_network_config = [static_network_config]
         final_network_config = []
         for entry in static_network_config:
             mac_interface_map = entry.get('mac_interface_map', [])
             for interface in entry['interfaces']:
                 bond = True if interface.get('type', 'ethernet') == 'bond' else False
                 if not mac_interface_map:
                     if not bond:
                         logical_nic_name, mac_address = interface['name'], interface['mac-address']
                         mac_interface_map.append({"mac_address": mac_address, "logical_nic_name": logical_nic_name})
                     else:
                         error("Providing mac_interface_map is mandatory when setting bond")
                         sys.exit(1)
             new_entry = {'network_yaml': yaml.dump(entry), 'mac_interface_map': mac_interface_map}
             final_network_config.append(models.HostStaticNetworkConfig(**new_entry))
         static_network_config = final_network_config
         overrides['static_network_config'] = static_network_config
     if 'ssh_authorized_key' not in overrides:
         if 'ssh_public_key' in overrides:
             overrides['ssh_authorized_key'] = overrides['ssh_public_key']
         else:
             pub_key = overrides.get('public_key', f"{os.environ['HOME']}/.ssh/id_rsa.pub")
             if os.path.exists(pub_key):
                 overrides['ssh_authorized_key'] = open(pub_key).read().strip()
             else:
                 error(f"Missing public key file {pub_key}")
                 sys.exit(1)
     if 'ignition_config_override' not in overrides:
         iso_overrides = overrides.copy()
         iso_overrides['ignition_version'] = '3.1.0'
         ignition_config_override = self.set_disconnected_ignition_config_override(infra_env_id=None,
                                                                                   overrides=iso_overrides)
         if ignition_config_override is not None:
             overrides['ignition_config_override'] = ignition_config_override
     if 'proxy' in overrides and isinstance(overrides['proxy'], str):
         proxy = overrides['proxy']
         if not proxy.startswith('http'):
             proxy = f'http://{proxy}'
         overrides['proxy'] = {'http_proxy': proxy, 'https_proxy': proxy}
         if 'noproxy' in overrides:
             overrides['proxy']['no_proxy'] = overrides['noproxy']
 def create_infra_env(self, name, overrides={}):
     existing_ids = [x['id'] for x in self.list_infra_envs() if x['name'] == name]
     if existing_ids:
         error(f"Infraenv {name} already there. Leaving")
         sys.exit(1)
     self.set_default_values(overrides)
     self.set_default_infraenv_values(overrides)
     new_infraenv_params = default_infraenv_params
     new_infraenv_params['name'] = name
     allowed_parameters = self._allowed_parameters(models.InfraEnvCreateParams)
     for parameter in overrides:
         if parameter in allowed_parameters:
             new_infraenv_params[parameter] = overrides[parameter]
     infraenv_create_params = models.InfraEnvCreateParams(**new_infraenv_params)
     self.client.register_infra_env(infraenv_create_params=infraenv_create_params)
 def set_olm_operators(self, olm_operators_data):
     operatorsapi = api.OperatorsApi(api_client=self.api)
     supported_operators = operatorsapi.v2_list_supported_operators()
     olm_operators = []
     for operator in olm_operators_data:
         if isinstance(operator, str):
             operator_name = operator
         elif isinstance(operator, dict) and 'name' in operator:
             operator_name = operator['name']
         else:
             error(f"Invalid entry for olm_operator {operator}")
             sys.exit(1)
         if operator_name not in supported_operators:
             error(f"Incorrect olm_operator {operator_name}. Should be one of {supported_operators}")
             sys.exit(1)
         olm_operators.append({'name': operator_name})
     return olm_operators
Example #10
0
 def set_machine_networks(self, cluster_id, machine_networks_data):
     machine_networks = []
     for machine_network in machine_networks_data:
         if isinstance(machine_network, str):
             cidr = machine_network
         elif isinstance(machine_network, dict) and 'cidr' in machine_network:
             cidr = machine_network['cidr']
         else:
             error(f"Invalid entry for machine_network {machine_network}")
             sys.exit(1)
         try:
             ip_network(cidr)
         except:
             error(f"Invalid cidr for machine_network {machine_network}")
             sys.exit(1)
         machine_networks.append({'cidr': cidr, 'cluster_id': cluster_id})
     return machine_networks
Example #11
0
 def set_service_networks(self, cluster_id, service_networks_data):
     service_networks = []
     for service_network in service_networks_data:
         if isinstance(service_network, str):
             cidr = service_network
         elif isinstance(service_network, dict) and 'cidr' in service_network:
             cidr = service_network['cidr']
         else:
             error(f"Invalid entry for service_network {service_network}")
             sys.exit(1)
         try:
             ip_network(cidr)
         except:
             error(f"Invalid cidr for service_network {service_network}")
             sys.exit(1)
         service_networks.append({'cidr': cidr, 'cluster_id': cluster_id})
     return service_networks
Example #12
0
 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)
Example #13
0
 def update_installconfig(self, name, overrides={}):
     cluster_id = self.get_cluster_id(name)
     installconfig = {}
     if 'network_type' in overrides or 'sno_disk' in overrides:
         if 'network_type' in overrides:
             installconfig['networking'] = {'networkType': 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}
     else:
         installconfig = overrides.get('installconfig')
         if installconfig is None:
             error("installconfig is not set")
             sys.exit(1)
         if not isinstance(installconfig, dict):
             error("installconfig is not in correct format")
             sys.exit(1)
     self.client.v2_update_cluster_install_config(cluster_id, json.dumps(installconfig))
Example #14
0
 def set_cluster_networks(self, cluster_id, cluster_networks_data):
     cluster_networks = []
     for cluster_network in cluster_networks_data:
         host_prefix = None
         if isinstance(cluster_network, str):
             cidr = cluster_network
         elif isinstance(cluster_network, dict) and 'cidr' in cluster_network:
             cidr = cluster_network['cidr']
             host_prefix = cluster_network.get('host_prefix') or cluster_network.get('hostPrefix')
         else:
             error(f"Invalid entry for cluster_network {cluster_network}")
             sys.exit(1)
         try:
             ip_network(cidr)
         except:
             error(f"Invalid cidr for cluster_network {cluster_network}")
             sys.exit(1)
         if host_prefix is None:
             host_prefix = 64 if ':' in cidr else 23
         cluster_networks.append({'cidr': cidr, 'cluster_id': cluster_id, 'host_prefix': host_prefix})
     return cluster_networks
Example #15
0
 def delete_host(self, hostname, overrides={}):
     infra_envs = {}
     if 'infraenv' in overrides:
         infraenv = overrides['infraenv']
         infra_env_id = self.get_infra_env_id(infraenv)
         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 host_id in host_ids:
             info(f"Deleting Host with id {host_id} in infraenv {infra_env_id}")
             self.client.v2_deregister_host(infra_env_id, host_id)
Example #16
0
 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}
Example #17
0
 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)
Example #18
0
 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)
Example #19
0
 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")