def cleanup_rde_artifacts(logger=NULL_LOGGER): """Cleanup all defined entity related artifacts. Deletes the following - - CSE interface - Native entity type """ try: rde_version_in_use = rde_utils.get_runtime_rde_version_by_vcd_api_version( CLIENT.get_api_version()) # noqa: E501 rde_metadata = rde_utils.get_rde_metadata(rde_version_in_use) cloudapi_client = pyvcloud_utils.get_cloudapi_client_from_vcd_client( client=CLIENT, logger_debug=logger, logger_wire=SERVER_CLOUDAPI_WIRE_LOGGER) schema_svc = def_schema_svc.DefSchemaService( cloudapi_client=cloudapi_client) # noqa: E501 if rde_constants.RDEMetadataKey.ENTITY_TYPE in rde_metadata: # delete entity_type entity_type: common_models.DefEntityType = \ rde_metadata[rde_constants.RDEMetadataKey.ENTITY_TYPE] schema_svc.delete_entity_type(entity_type.get_id()) logger.debug(f"Deleted entity type: {entity_type.name}") if rde_constants.RDEMetadataKey.INTERFACES in rde_metadata: # delete interface interfaces: List[common_models.DefInterface] = \ rde_metadata[rde_constants.RDEMetadataKey.INTERFACES] for i in interfaces: interface_id = i.get_id() if interface_id != common_models.K8Interface.VCD_INTERFACE.value.get_id( ): # noqa: E501 schema_svc.delete_interface(interface_id) logger.debug(f"Deleted interface: {i.name}") except Exception as e: logger.warning(f"Failed to clean up RDE artifacts: {e}")
def __init__(self, client): logger_wire = logger.NULL_LOGGER if os.getenv(cli_constants.ENV_CSE_CLIENT_WIRE_LOGGING): logger_wire = logger.CLIENT_WIRE_LOGGER self._cloudapi_client = \ vcd_utils.get_cloudapi_client_from_vcd_client( client=client, logger_debug=logger.CLIENT_LOGGER, logger_wire=logger_wire) self._native_cluster_api = NativeClusterApi(client) self._client = client self._server_rde_version = \ def_utils.get_runtime_rde_version_by_vcd_api_version( float(client.get_api_version()))
def modify_cluster_apply_spec(apply_spec_file_path, properties): modified_spec = None with open(env.APPLY_SPEC_PATH, 'r') as f: # replace worker count content = f.read() sample_apply_spec = yaml.safe_load(content) rde_version = get_runtime_rde_version_by_vcd_api_version( env.VCD_API_VERSION_TO_USE) if rde_version == RuntimeRDEVersion.RDE_1_X.value: modified_spec = _update_cluster_apply_spec_for_1_0( sample_apply_spec, properties) elif rde_version == RuntimeRDEVersion.RDE_2_X.value: modified_spec = _update_cluster_apply_spec_for_2_1( sample_apply_spec, properties) else: raise Exception("Invalid RDE version") # write modified spec to the apply spec file with open(apply_spec_file_path, 'w') as f: f.write(yaml.dump(modified_spec))
def rde_exists(rde_name, logger=NULL_LOGGER): try: cloudapi_client: CloudApiClient = \ pyvcloud_utils.get_cloudapi_client_from_vcd_client( CLIENT, logger_debug=logger, logger_wire=SERVER_CLOUDAPI_WIRE_LOGGER) # To avoid cyclic import from container_service_extension.rde.common.entity_service import \ DefEntityService entity_svc = DefEntityService(cloudapi_client) rde_version = rde_utils.get_runtime_rde_version_by_vcd_api_version( CLIENT.get_api_version()) entity = \ entity_svc.get_native_rde_by_name_and_rde_version( rde_name, rde_version) return bool(entity) except Exception as e: logger.warning(f"Exception occured when checking if rde exists: {e}") return False
def delete_rde(cluster_name, logger=NULL_LOGGER): """Delete defined entity with the given name. NOTE: RDE names are not unique. This function deletes all occurances """ try: cloudapi_client: CloudApiClient = \ pyvcloud_utils.get_cloudapi_client_from_vcd_client( CLIENT, logger_debug=logger, logger_wire=SERVER_CLOUDAPI_WIRE_LOGGER) # noqa: E501 from container_service_extension.rde.common.entity_service import DefEntityService # noqa: E501 entity_svc = DefEntityService(cloudapi_client) for cluster_rde in \ entity_svc.list_all_native_rde_by_name_and_rde_version( cluster_name, rde_utils.get_runtime_rde_version_by_vcd_api_version(CLIENT.get_api_version())): # noqa: E501 entity_svc.resolve_entity(cluster_rde.id, cluster_rde.entityType) entity_svc.delete_entity(cluster_rde.id) except cse_exceptions.DefEntityServiceError as e: PYTEST_LOGGER.error(f"Failed to delete RDE: {e}") pass
def add_additional_details_to_config( config: Dict, vcd_host: str, vcd_username: str, vcd_password: str, verify_ssl: bool, is_legacy_mode: bool, is_mqtt_exchange: bool, log_wire: bool, log_wire_file: str ): """Update config dict with computed key-value pairs. :param dict config: :param str vcd_host: :param str vcd_username: :param str vcd_password: :param bool verify_ssl: :param bool is_legacy_mode: :param bool is_mqtt_exchange: :param bool log_wire: :param str log_wire_file: :return: the updated config file :rtype: dict """ # Compute common supported api versions by the CSE server and vCD sysadmin_client = None try: sysadmin_client = Client( vcd_host, verify_ssl_certs=verify_ssl, log_file=log_wire_file, log_requests=log_wire, log_headers=log_wire, log_bodies=log_wire ) sysadmin_client.set_credentials( BasicLoginCredentials( vcd_username, SYSTEM_ORG_NAME, vcd_password ) ) vcd_supported_api_versions = \ set(sysadmin_client.get_supported_versions_list()) cse_supported_api_versions = set(SUPPORTED_VCD_API_VERSIONS) common_supported_api_versions = \ list(cse_supported_api_versions.intersection(vcd_supported_api_versions)) # noqa: E501 common_supported_api_versions.sort() if is_legacy_mode: common_supported_api_versions = \ [x for x in common_supported_api_versions if VCDApiVersion(x) < VcdApiVersionObj.VERSION_35.value] else: common_supported_api_versions = \ [x for x in common_supported_api_versions if VCDApiVersion(x) >= VcdApiVersionObj.VERSION_35.value] config['service']['supported_api_versions'] = \ common_supported_api_versions finally: if sysadmin_client: sysadmin_client.logout() # Convert legacy_mode flag in service_section to corresponding # feature flags if 'feature_flags' not in config: config['feature_flags'] = {} config['feature_flags']['legacy_api'] = str_to_bool(is_legacy_mode) config['feature_flags']['non_legacy_api'] = \ not str_to_bool(is_legacy_mode) # Compute the default api version as the max supported version # Also compute the RDE version in use max_vcd_api_version_supported: str = get_max_api_version(config['service']['supported_api_versions']) # noqa: E501 config['service']['default_api_version'] = max_vcd_api_version_supported config['service']['rde_version_in_use'] = semantic_version.Version( rde_utils.get_runtime_rde_version_by_vcd_api_version( max_vcd_api_version_supported ) ) # Update the config dict with telemetry specific key value pairs update_with_telemetry_settings( config_dict=config, vcd_host=vcd_host, vcd_username=vcd_username, vcd_password=vcd_password, verify_ssl=verify_ssl, is_mqtt_exchange=is_mqtt_exchange ) return config
def apply(ctx, cluster_config_file_path, generate_sample_config, k8_runtime, output, org, cluster_id): # noqa: E501 CLIENT_LOGGER.debug(f'Executing command: {ctx.command_path}') try: console_message_printer = utils.ConsoleMessagePrinter() if cluster_config_file_path and (generate_sample_config or output or k8_runtime): # noqa: E501 console_message_printer.general_no_color(ctx.get_help()) msg = "-s/-o/-n/-t/-k flag can't be used together with CLUSTER_CONFIG_FILE_PATH" # noqa: E501 CLIENT_LOGGER.error(msg) raise Exception(msg) if not cluster_config_file_path and not generate_sample_config: console_message_printer.general_no_color(ctx.get_help()) msg = "No option chosen/invalid option" CLIENT_LOGGER.error(msg) raise Exception(msg) client = ctx.obj['client'] if generate_sample_config: if not k8_runtime: console_message_printer.general_no_color(ctx.get_help()) msg = "with option --sample you must specify either of options: --native or --tkg-s" # noqa: E501 if utils.is_environment_variable_enabled(cli_constants.ENV_CSE_TKG_PLUS_ENABLED): # noqa: E501 msg += " or --tkg-plus" CLIENT_LOGGER.error(msg) raise Exception(msg) elif k8_runtime == shared_constants.ClusterEntityKind.TKG_PLUS.value \ and not utils.is_environment_variable_enabled(cli_constants.ENV_CSE_TKG_PLUS_ENABLED): # noqa: E501 raise Exception(f"{shared_constants.ClusterEntityKind.TKG_PLUS.value} not enabled") # noqa: E501 else: # since apply command is not exposed when CSE server is not # running, it is safe to get the server_rde_version from # VCD API version as VCD API version will be the supported by # CSE server. server_rde_version = \ def_utils.get_runtime_rde_version_by_vcd_api_version( client.get_api_version()) sample_cluster_config = \ client_sample_generator.get_sample_cluster_configuration( output=output, k8_runtime=k8_runtime, server_rde_in_use=server_rde_version) console_message_printer.general_no_color(sample_cluster_config) return with open(cluster_config_file_path) as f: cluster_config_map = yaml.safe_load(f) or {} k8_runtime = cluster_config_map.get('kind') if not k8_runtime: raise Exception("Cluster kind missing from the spec.") if client_utils.is_cli_for_tkg_s_only(): if k8_runtime in [shared_constants.ClusterEntityKind.NATIVE.value, shared_constants.ClusterEntityKind.TKG_PLUS.value]: # noqa: E501 # Cannot run the command as cse cli is enabled only for native raise CseServerNotRunningError() k8_runtime = shared_constants.ClusterEntityKind.TKG_S.value org_name = None if k8_runtime == shared_constants.ClusterEntityKind.TKG_S.value: org_name = org if not org: org_name = ctx.obj['profiles'].get('org_in_use') cluster = Cluster(client, k8_runtime=cluster_config_map.get('kind')) result = cluster.apply(cluster_config_map, cluster_id=cluster_id, org=org_name) stdout(result, ctx) CLIENT_LOGGER.debug(result) except Exception as e: stderr(e, ctx) CLIENT_LOGGER.error(str(e), exc_info=True)
def test_0040_vcd_cse_cluster_apply( cluster_apply_param: CLUSTER_APPLY_TEST_PARAM): # noqa: E501 """Test 'vcd cse cluster create ...' command for various cse users. Test cluster creation from different persona's- sys_admin, org_admin and k8_author. Created clusters will remain in the system for further command tests - list, resize and delete. :param config: cse config file for vcd configuration :param test_runner_username: parameterized persona to run tests with different users """ print(f"Running cluster create operation for {cluster_apply_param.user}") exit_code = 0 if cluster_apply_param.expected_phase == 'UPDATE:FAILED': # Validation failure during cluster update will fail the command # execution before task is generated. exit_code = 2 expect_failure = "FAILED" in cluster_apply_param.expected_phase cmd_list = [ testutils.CMD_BINDER( cmd=f"cse cluster apply {env.APPLY_SPEC_PATH} ", exit_code=exit_code, validate_output_func=_follow_apply_output( expect_failure=expect_failure), # noqa: E501 test_user=cluster_apply_param.user) ] testutils.execute_commands(cmd_list, logger=PYTEST_LOGGER) created_cluster_name = cluster_apply_param.cluster_name rollback = cluster_apply_param.rollback if "CREATE" in cluster_apply_param.expected_phase: if "SUCCEEDED" in cluster_apply_param.expected_phase: assert env.vapp_exists(created_cluster_name, vdc_href=env.TEST_VDC_HREF), \ f"Expected VApp to be present for cluster {created_cluster_name}" # noqa: E501 assert env.rde_exists(created_cluster_name), \ f"Expected RDE to be present for cluster {created_cluster_name}" # noqa: E501 assert _get_cluster_phase(created_cluster_name, cluster_apply_param.user) == 'CREATE:SUCCEEDED', \ "Expected RDE phase to be 'CREATE:SUCCEEDED'" # noqa: E501 if "FAILED" in cluster_apply_param.expected_phase: if rollback: assert not env.vapp_exists(created_cluster_name, vdc_href=env.TEST_VDC_HREF), \ f"Expected VApp to be present for cluster {created_cluster_name}" # noqa: E501 assert not env.rde_exists(created_cluster_name), \ f"Expected RDE to be present for cluster {created_cluster_name}" # noqa: E501 else: # During failure, cannot garauntee vapp creation assert env.rde_exists(created_cluster_name), \ f"Expected RDE for the cluster {created_cluster_name} to be present" # noqa: E501 assert _get_cluster_phase(created_cluster_name, cluster_apply_param.user) == 'CREATE:FAILED', \ "Expected RDE phase to be 'CREATE:FAILED'" # noqa: E501 if "UPDATE" in cluster_apply_param.expected_phase: if "SUCCEEDED" in cluster_apply_param.expected_phase: cmd_list = [ testutils.CMD_BINDER( cmd=f"cse cluster info {created_cluster_name}", # noqa exit_code=0, validate_output_func=testutils. generate_validate_node_count_func( # noqa: E501 expected_nodes=cluster_apply_param. worker_count, # noqa: E501 rde_version=get_runtime_rde_version_by_vcd_api_version( env.VCD_API_VERSION_TO_USE), # noqa: E501 logger=PYTEST_LOGGER), # noqa: E501 test_user=cluster_apply_param.user) ] testutils.execute_commands(cmd_list, logger=PYTEST_LOGGER) # common for both succeeded and failed conditions assert _get_cluster_phase(created_cluster_name, cluster_apply_param.user) == cluster_apply_param.expected_phase, \ f"Expected RDE phase to be {cluster_apply_param.expected_phase}" # noqa: E501 # logout user env.CLI_RUNNER.invoke(vcd, env.USER_LOGOUT_CMD, catch_exceptions=False)
def _load_def_schema(self, msg_update_callback=utils.NullPrinter()): """Load cluster interface and cluster entity type to global context. If defined entity framework is supported by vCD api version, load defined entity interface and defined entity type registered during server install :param utils.ConsoleMessagePrinter msg_update_callback: """ sysadmin_client = None try: sysadmin_client = vcd_utils.get_sys_admin_client() logger_wire = logger.NULL_LOGGER if utils.str_to_bool( utils.str_to_bool(self.config['service'].get( 'log_wire', False))): # noqa: E501 logger_wire = logger.SERVER_CLOUDAPI_WIRE_LOGGER cloudapi_client = \ vcd_utils.get_cloudapi_client_from_vcd_client(sysadmin_client, logger.SERVER_LOGGER, # noqa: E501 logger_wire) raise_error_if_def_not_supported(cloudapi_client) # set the RDE version used max_vcd_api_version_supported = \ max([float(x) for x in self.config['service']['supported_api_versions']]) # noqa: E501 self.config['service']['rde_version_in_use'] = \ def_utils.get_runtime_rde_version_by_vcd_api_version(max_vcd_api_version_supported) # noqa: E501 server_rde_version = server_utils.get_rde_version_in_use() msg_update_callback.general( f"Using RDE version: {server_rde_version}") # noqa: E501 schema_svc = def_schema_svc.DefSchemaService(cloudapi_client) def_metadata_dict: dict = def_utils.get_rde_metadata( server_rde_version) # noqa: E501 entity_type: common_models.DefEntityType = \ def_metadata_dict[def_constants.RDEMetadataKey.ENTITY_TYPE] # noqa: E501 interfaces: List[common_models.DefInterface] = \ def_metadata_dict[def_constants.RDEMetadataKey.INTERFACES] # noqa: E501 for interface in interfaces: # TODO change _kubernetesInterface to an array once additional # interface for CSE is added. self._kubernetesInterface = \ schema_svc.get_interface(interface.get_id()) self._nativeEntityType = \ schema_svc.get_entity_type(entity_type.get_id()) msg = f"Successfully loaded defined entity schema " \ f"{entity_type.get_id()} to global context" msg_update_callback.general(msg) logger.SERVER_LOGGER.debug(msg) except cse_exception.DefNotSupportedException: msg = "Skipping initialization of defined entity type" \ " and defined entity interface" msg_update_callback.info(msg) logger.SERVER_LOGGER.debug(msg) except cse_exception.DefSchemaServiceError as e: msg = f"Error while loading defined entity schema: {e.error_message}" # noqa: E501 msg_update_callback.error(msg) logger.SERVER_LOGGER.debug(msg) raise except Exception as e: msg = f"Failed to load defined entity schema to global context: {str(e)}" # noqa: E501 msg_update_callback.error(msg) logger.SERVER_LOGGER.error(msg) raise finally: if sysadmin_client: sysadmin_client.logout()