def __init__(self, vcd_api_client: vcd_client.Client, oauth_client_name: str, logger_debug: logging.Logger = NULL_LOGGER, logger_wire: logging.Logger = NULL_LOGGER): self.vcd_api_client: vcd_client.Client = vcd_api_client cloudapi_url = vcd_api_client.get_cloudapi_uri() super().__init__(base_url=cloudapi_url, token=vcd_api_client.get_access_token(), api_version=vcd_api_client.get_api_version(), logger_debug=logger_debug, logger_wire=logger_wire, verify_ssl=vcd_api_client._verify_ssl_certs, is_sys_admin=vcd_api_client.is_sysadmin()) self.oauth_client_name = oauth_client_name # cloudapi_url will be of the format https://vcd-host/cloudapi # since /oauth endpoint is not associated with /cloudapi or /api, # we need to format the cloudapi_url so that only https://vcd-host # part is retained url_host = urlparse(cloudapi_url) self._host_url = f"{url_host.scheme}://{url_host.netloc}" self.oauth_client_id = None self.refresh_token = None
def __new__(cls, client: vcd_client.Client, k8_runtime=None): """Create the right cluster class for the negotiated API version. In case of ApiVersion.VERSION_35, return specific instance if the cluster kind is known up-front. If the cluster entity kind is unknown, return instance of DefEntityCluster for all common operations like get_cluster_info(), list_clusters() :param pyvcloud.vcd.client client: vcd client :param dict cluster_config: cluster configuration :return: instance of version specific client side cluster """ api_version = client.get_api_version() if float(api_version) < float( vcd_client.ApiVersion.VERSION_35.value): # noqa: E501 return LegacyClusterNative(client) elif float(api_version) >= float( vcd_client.ApiVersion.VERSION_35.value): # noqa: E501 if k8_runtime == ClusterEntityKind.NATIVE.value or k8_runtime == ClusterEntityKind.TKG_PLUS.value: # noqa: E501 return DEClusterNative(client) elif k8_runtime == ClusterEntityKind.TKG.value: return DEClusterTKG(client) else: return DECluster(client)
def get_cloudapi_client_from_vcd_client(client: vcd_client.Client, logger_debug=NULL_LOGGER, logger_wire=NULL_LOGGER): token = client.get_access_token() return cloud_api_client.CloudApiClient( base_url=client.get_cloudapi_uri(), token=token, api_version=client.get_api_version(), logger_debug=logger_debug, logger_wire=logger_wire, verify_ssl=client._verify_ssl_certs, is_sys_admin=client.is_sysadmin())
def __new__(cls, client: vcd_client.Client): """Create the right ovdc class for the negotiated API version. For apiVersion < 35 return MetadataBasedOvdc class For apiVersoin >= 35 return PolicyBasedOvdc class :param pyvcloud.vcd.client client: vcd client :return: instance of version specific client side Ovdc class """ api_version = client.get_api_version() if float(api_version) < float(vcd_client.ApiVersion.VERSION_35.value): return MetadataBasedOvdc(client) elif float(api_version) >= float( vcd_client.ApiVersion.VERSION_35.value): # noqa: E501 return PolicyBasedOvdc(client)
def get_cloudapi_client_from_vcd_client(client: vcd_client.Client, logger_debug=NULL_LOGGER, logger_wire=NULL_LOGGER): token = client.get_access_token() is_jwt = True if not token: token = client.get_xvcloud_authorization_token() is_jwt = False return cloudApiClient.CloudApiClient(base_url=client.get_cloudapi_uri(), token=token, is_jwt_token=is_jwt, api_version=client.get_api_version(), logger_debug=logger_debug, logger_wire=logger_wire, verify_ssl=client._verify_ssl_certs, is_sys_admin=client.is_sysadmin())
def __init__(self, sysadmin_client: vcd_client.Client, debug_logger=logger.SERVER_LOGGER, log_wire=True): # Ensure correct credentials and api version vcd_utils.raise_error_if_not_sysadmin(sysadmin_client) client_api_version = float(sysadmin_client.get_api_version()) if client_api_version < constants.MQTT_MIN_API_VERSION: raise ValueError(f'API version {client_api_version} ' f'is less than required version ' f'{constants.MQTT_MIN_API_VERSION} to use MQTT') self._sysadmin_client: vcd_client.Client = sysadmin_client wire_logger = logger.NULL_LOGGER if log_wire: wire_logger = logger.SERVER_CLOUDAPI_WIRE_LOGGER self._wire_logger = wire_logger self._debug_logger = debug_logger self._cloudapi_client = \ vcd_utils.get_cloudapi_client_from_vcd_client( self._sysadmin_client, self._debug_logger, self._wire_logger)
def get_pvdc_id(sysadmin_client: vcd_client.Client, ovdc: VDC): """Get id of pvdc backing an ovdc. :param pyvcloud.vcd.VDC ovdc: This ovdc object has to be created with a sys admin client. :return: pvdc id :rtype: str """ raise_error_if_not_sysadmin(sysadmin_client) pvdc_element = ovdc.get_resource().ProviderVdcReference # To support <= VCD 9.1 where no 'id' is present in pvdc # element, it has to be extracted from href. Once VCD 9.1 support # is discontinued, this code is not required. if float(sysadmin_client.get_api_version()) < float(vcd_client.ApiVersion.VERSION_31.value): # noqa: E501 pvdc_href = pvdc_element.get('href') return pvdc_href.split("/")[-1] else: pvdc_id = pvdc_element.get('id') return extract_id(pvdc_id)
def _register_def_schema(client: Client, msg_update_callback=utils.NullPrinter(), log_wire=False): """Register defined entity interface and defined entity type. If vCD api version is >= 35, register the vCD api version based defined entity interface and defined entity type. Read the schema present in the location dictated by api version to register the defined entity type. :param pyvcloud.vcd.client.Client client: :param utils.ConsoleMessagePrinter msg_update_callback: Callback object. :param bool log_wire: wire logging enabled """ msg = "Registering defined entity schema" msg_update_callback.info(msg) INSTALL_LOGGER.debug(msg) logger_wire = SERVER_CLOUDAPI_WIRE_LOGGER if log_wire else NULL_LOGGER cloudapi_client = vcd_utils.get_cloudapi_client_from_vcd_client( client=client, # noqa: E501 logger_debug=INSTALL_LOGGER, # noqa: E501 logger_wire=logger_wire) # noqa: E501 schema_file = None try: def_utils.raise_error_if_def_not_supported(cloudapi_client) schema_svc = def_schema_svc.DefSchemaService(cloudapi_client) keys_map = def_utils.MAP_API_VERSION_TO_KEYS[float( client.get_api_version())] # noqa: E501 defKey = def_utils.DefKey native_interface = def_models.\ DefInterface(name=keys_map[defKey.INTERFACE_NAME], vendor=keys_map[defKey.VENDOR], nss=keys_map[defKey.INTERFACE_NSS], version=keys_map[defKey.INTERFACE_VERSION], # noqa: E501 readonly=False) msg = "" try: schema_svc.get_interface(native_interface.get_id()) msg = "defined entity interface already exists." \ " Skipping defined entity interface creation" except HTTPError: # TODO handle this part only if the interface was not found native_interface = schema_svc.create_interface(native_interface) msg = "Successfully created defined entity interface" msg_update_callback.general(msg) INSTALL_LOGGER.debug(msg) # TODO stop-gap fix - find efficient way to import schema import importlib import importlib.resources as pkg_resources schema_module = importlib.import_module( f'{def_utils.DEF_SCHEMA_DIRECTORY}.{keys_map[defKey.ENTITY_TYPE_SCHEMA_VERSION]}' ) # noqa: E501 schema_file = pkg_resources.open_text( schema_module, def_utils.DEF_ENTITY_TYPE_SCHEMA_FILE) # noqa: E501 native_entity_type = def_models.\ DefEntityType(name=keys_map[defKey.ENTITY_TYPE_NAME], description='', vendor=keys_map[defKey.VENDOR], nss=keys_map[defKey.ENTITY_TYPE_NSS], version=keys_map[defKey.ENTITY_TYPE_VERSION], schema=json.load(schema_file), interfaces=[native_interface.get_id()], readonly=False) msg = "" try: schema_svc.get_entity_type(native_entity_type.get_id()) msg = "defined entity type already exists." \ " Skipping defined entity type creation" except HTTPError: # TODO handle this part only if the entity type was not found native_entity_type = schema_svc.create_entity_type( native_entity_type) # noqa: E501 msg = "Successfully registered defined entity type" msg_update_callback.general(msg) INSTALL_LOGGER.debug(msg) except cse_exception.DefNotSupportedException: msg = "Skipping defined entity type and defined entity interface" \ " registration" msg_update_callback.general(msg) INSTALL_LOGGER.debug(msg) except Exception as e: msg = f"Error occured while registering defined entity schema: {str(e)}" # noqa: E501 msg_update_callback.error(msg) INSTALL_LOGGER.error(msg) raise (e) finally: try: schema_file.close() except Exception: pass
def login(ctx, user, host, password, api_version, org, verify_ssl_certs, disable_warnings, vdc, session_id, use_browser_session): """Login to vCloud Director \b Login to a vCloud Director service. \b Examples vcd login mysp.com org1 usr1 Login to host 'mysp.com'. \b vcd login test.mysp.com org1 usr1 -i -w Login to a host with self-signed SSL certificate. \b vcd login mysp.com org1 usr1 --use-browser-session Login using active session from browser. \b vcd login session list chrome List active session ids from browser. \b vcd login mysp.com org1 usr1 \\ --session-id ee968665bf3412d581bbc6192508eec4 Login using active session id. \b Environment Variables VCD_PASSWORD If this environment variable is set, the command will use its value as the password to login and will not ask for one. The --password option has precedence over the environment variable. """ if not verify_ssl_certs: if disable_warnings: pass else: click.secho( 'InsecureRequestWarning: ' 'Unverified HTTPS request is being made. ' 'Adding certificate verification is strongly ' 'advised.', fg='yellow', err=True) requests.packages.urllib3.disable_warnings() if host == 'session' and org == 'list': sessions = [] if user == 'chrome': cookies = browsercookie.chrome() for c in cookies: if c.name == 'vcloud_session_id': sessions.append({'host': c.domain, 'session_id': c.value}) stdout(sessions, ctx) return client = Client( host, api_version=api_version, verify_ssl_certs=verify_ssl_certs, log_file='vcd.log', log_requests=True, log_headers=True, log_bodies=True) try: if session_id is not None or use_browser_session: if use_browser_session: browser_session_id = None cookies = browsercookie.chrome() for c in cookies: if c.name == 'vcloud_session_id' and \ c.domain == host: browser_session_id = c.value break if browser_session_id is None: raise Exception('Session not found in browser.') session_id = browser_session_id client.rehydrate_from_token(session_id) else: if password is None: password = click.prompt('Password', hide_input=True, type=str) client.set_credentials(BasicLoginCredentials(user, org, password)) negotiated_api_version = client.get_api_version() profiles = Profiles.load() logged_in_org = client.get_org() org_href = logged_in_org.get('href') vdc_href = '' in_use_vdc = '' links = [] if float(negotiated_api_version) < float(ApiVersion.VERSION_33.value): links = get_links(logged_in_org, media_type=EntityType.VDC.value) else: if logged_in_org.get('name') != 'System': links = client.get_resource_link_from_query_object( logged_in_org, media_type=EntityType.RECORDS.value, type='vdc') if vdc is None: if len(links) > 0: in_use_vdc = links[0].name vdc_href = links[0].href else: for v in links: if vdc == v.name: in_use_vdc = v.name vdc_href = v.href break if len(in_use_vdc) == 0: raise Exception('VDC not found') token = client.get_access_token() is_jwt_token = True if not token: token = client.get_xvcloud_authorization_token() is_jwt_token = False profiles.update( host, org, user, token, negotiated_api_version, verify_ssl_certs, disable_warnings, vdc=in_use_vdc, org_href=org_href, vdc_href=vdc_href, log_request=True, log_header=True, log_body=True, vapp='', vapp_href='', is_jwt_token=is_jwt_token) alt_text = f"{user} logged in, org: '{org}', vdc: '{in_use_vdc}'" d = { 'user': user, 'org': org, 'vdc': in_use_vdc, 'logged_in': True } stdout(d, ctx, alt_text) except Exception as e: try: profiles = Profiles.load() profiles.set('token', '') except Exception: pass stderr(e, ctx)
def _load_template_definition_from_catalog( self, msg_update_callback=utils.NullPrinter()): # noqa: E501 # NOTE: If `enable_tkg_plus` in the config file is set to false, # CSE server will skip loading the TKG+ template this will prevent # users from performing TKG+ related operations. msg = "Loading k8s template definition from catalog" logger.SERVER_LOGGER.info(msg) msg_update_callback.general_no_color(msg) client = None try: log_filename = None log_wire = \ utils.str_to_bool(self.config['service'].get('log_wire')) if log_wire: log_filename = logger.SERVER_DEBUG_WIRELOG_FILEPATH client = Client(self.config['vcd']['host'], api_version=self.config['vcd']['api_version'], verify_ssl_certs=self.config['vcd']['verify'], log_file=log_filename, log_requests=log_wire, log_headers=log_wire, log_bodies=log_wire) credentials = BasicLoginCredentials( self.config['vcd']['username'], server_constants.SYSTEM_ORG_NAME, # noqa: E501 self.config['vcd']['password']) client.set_credentials(credentials) is_tkg_plus_enabled = server_utils.is_tkg_plus_enabled(self.config) org_name = self.config['broker']['org'] catalog_name = self.config['broker']['catalog'] k8_templates = ltm.get_all_k8s_local_template_definition( client=client, catalog_name=catalog_name, org_name=org_name, logger_debug=logger.SERVER_LOGGER) if not k8_templates: msg = "No valid K8 templates were found in catalog " \ f"'{catalog_name}'. Unable to start CSE server." msg_update_callback.error(msg) logger.SERVER_LOGGER.error(msg) sys.exit(1) # Check that default k8s template exists in vCD at the correct # revision default_template_name = \ self.config['broker']['default_template_name'] default_template_revision = \ str(self.config['broker']['default_template_revision']) found_default_template = False for template in k8_templates: api_version = float(client.get_api_version()) if api_version >= float(vCDApiVersion.VERSION_35.value) and \ template[server_constants.LocalTemplateKey.KIND] == \ shared_constants.ClusterEntityKind.TKG_PLUS.value and \ not is_tkg_plus_enabled: # TKG+ is not enabled on CSE config. Skip the template and # log the relevant information. msg = "Skipping loading template data for " \ f"'{template[server_constants.LocalTemplateKey.NAME]}' as " \ "TKG+ is not enabled" # noqa: E501 logger.SERVER_LOGGER.debug(msg) k8_templates.remove(template) continue if str(template[server_constants.LocalTemplateKey.REVISION]) == default_template_revision and \ template[server_constants.LocalTemplateKey.NAME] == default_template_name: # noqa: E501 found_default_template = True msg = f"Found K8 template '{template['name']}' at revision " \ f"{template['revision']} in catalog '{catalog_name}'" msg_update_callback.general(msg) logger.SERVER_LOGGER.info(msg) if not found_default_template: msg = f"Default template {default_template_name} with " \ f"revision {default_template_revision} not found." \ " Unable to start CSE server." msg_update_callback.error(msg) logger.SERVER_LOGGER.error(msg) sys.exit(1) self.config['broker']['templates'] = k8_templates finally: if client: client.logout()
def __init__(self, ovf_file, vcd_url=None, username=None, password=None, orgname=None): self.ovf_file = os.path.abspath(ovf_file) self.vcd_url = vcd_url self.username = username self.password = password self.orgname = orgname try: client = Client(self.vcd_url, verify_ssl_certs=False, api_version=ApiVersion.VERSION_32.value, log_requests=True, log_headers=True, log_bodies=True, log_file=LOG_FILE) # sclient.set_highest_supported_version() client.set_credentials( BasicLoginCredentials(self.username, self.orgname, self.password)) logger.info("Logged into {} using version {}".format( self.vcd_url, client.get_api_version())) self.client = client self.org = Org(self.client, resource=self.client.get_org()) except Exception as exp: problem = Exception( "Failed to connect to vCD at {}, org {}, username {}:\n{}". format(self.vcd_url, self.orgname, self.username, exp)) logger.error(problem) raise problem try: # Retrieve the VM name from the OVF. We will use this as both the image and catalog name OVF_tree = etree.parse(self.ovf_file) root = OVF_tree.getroot() nsmap = {k: v for k, v in root.nsmap.items() if k} nsmap["xmlns"] = "http://schemas.dmtf.org/ovf/envelope/1" virtuasystem = root.find('xmlns:VirtualSystem', nsmap) name_tag = virtuasystem.find('xmlns:Name', nsmap) self.image_name = name_tag.text info_tag = virtuasystem.find('xmlns:Info', nsmap) self.image_description = info_tag.text references = root.find('xmlns:References', nsmap) file = references.find('xmlns:File', nsmap) self.vmdk_file = "{}/{}".format( os.path.dirname(self.ovf_file), file.attrib['{http://schemas.dmtf.org/ovf/envelope/1}href']) logger.info("Loaded VM {}: {}".format(self.image_name, self.image_description)) except Exception as exp: problem = Exception( "Failed to fetch VirtualSystem Name element from OVF {}:\n{}". format(self.ovf_file, exp)) logger.error(problem) raise problem
if len(sys.argv) != 6: print("Usage: python3 {0} host org user password vdc".format(sys.argv[0])) sys.exit(1) host = sys.argv[1] org = sys.argv[2] user = sys.argv[3] password = sys.argv[4] task = sys.argv[5] # Disable warnings from self-signed certificates. requests.packages.urllib3.disable_warnings() print("Logging in: host={0}, org={1}, user={2}".format(host, org, user)) client = Client(host, api_version='29.0', verify_ssl_certs=False, log_file='pyvcloud.log', log_requests=True, log_headers=True, log_bodies=True) client.set_credentials(BasicLoginCredentials(user, org, password)) print("API URL is :" + client.get_api_uri()) print("API Version is :" + client.get_api_version()) taskhref = client.get_uriobject_uuid(task, UriObjectType.TASK.value) print("Task HREF : " + taskhref) task = _TaskMonitor(client) task_resource= task._get_task_status(taskhref) task_status = task.wait_for_success(task_resource) print("Complete")