diff --git a/core/src/main/python/deploy.py b/core/src/main/python/deploy.py index 7b1f3e124..6faf4516e 100644 --- a/core/src/main/python/deploy.py +++ b/core/src/main/python/deploy.py @@ -41,12 +41,12 @@ __required_arguments = [ CommandLineArgUtil.ORACLE_HOME_SWITCH, - CommandLineArgUtil.DOMAIN_HOME_SWITCH, CommandLineArgUtil.MODEL_FILE_SWITCH ] __optional_arguments = [ # Used by shell script to locate WLST + CommandLineArgUtil.DOMAIN_HOME_SWITCH, CommandLineArgUtil.DOMAIN_TYPE_SWITCH, CommandLineArgUtil.ARCHIVE_FILE_SWITCH, CommandLineArgUtil.VARIABLE_FILE_SWITCH, @@ -61,7 +61,8 @@ CommandLineArgUtil.PASSPHRASE_ENV_SWITCH, CommandLineArgUtil.OUTPUT_DIR_SWITCH, CommandLineArgUtil.DISCARD_CURRENT_EDIT_SWITCH, - CommandLineArgUtil.CANCEL_CHANGES_IF_RESTART_REQ_SWITCH + CommandLineArgUtil.CANCEL_CHANGES_IF_RESTART_REQ_SWITCH, + CommandLineArgUtil.REMOTE_SWITCH ] @@ -72,6 +73,7 @@ def __process_args(args): :raises CLAException: if an error occurs while validating and processing the command-line arguments """ global __wlst_mode + _method_name = '__process_args' cla_util = CommandLineArgUtil(_program_name, __required_arguments, __optional_arguments) cla_util.set_allow_multiple_models(True) @@ -80,6 +82,7 @@ def __process_args(args): cla_helper.validate_optional_archive(_program_name, argument_map) cla_helper.validate_required_model(_program_name, argument_map) cla_helper.validate_variable_file_exists(_program_name, argument_map) + cla_helper.validate_if_domain_home_required(_program_name, argument_map) __wlst_mode = cla_helper.process_online_args(argument_map) cla_helper.process_encryption_args(argument_map) @@ -124,6 +127,10 @@ def __deploy_online(model, model_context, aliases): __logger.info("WLSDPLY-09005", admin_url, timeout, method_name=_method_name, class_name=_class_name) __wlst_helper.connect(admin_user, admin_pwd, admin_url, timeout) + + model_context.set_domain_home_name_if_remote(__wlst_helper.get_domain_home_online(), + __wlst_helper.get_domain_name_online()) + deployer_utils.ensure_no_uncommitted_changes_or_edit_sessions(skip_edit_session_check) __wlst_helper.edit() __logger.fine("WLSDPLY-09019", edit_lock_acquire_timeout, edit_lock_release_timeout, edit_lock_exclusive) diff --git a/core/src/main/python/discover.py b/core/src/main/python/discover.py index 147de111b..7464a6610 100644 --- a/core/src/main/python/discover.py +++ b/core/src/main/python/discover.py @@ -67,12 +67,12 @@ __required_arguments = [ CommandLineArgUtil.ORACLE_HOME_SWITCH, - CommandLineArgUtil.DOMAIN_HOME_SWITCH, CommandLineArgUtil.MODEL_FILE_SWITCH ] __optional_arguments = [ # Used by shell script to locate WLST + CommandLineArgUtil.DOMAIN_HOME_SWITCH, CommandLineArgUtil.ARCHIVE_FILE_SWITCH, CommandLineArgUtil.SKIP_ARCHIVE_FILE_SWITCH, CommandLineArgUtil.DOMAIN_TYPE_SWITCH, @@ -102,6 +102,7 @@ def __process_args(args): argument_map = cla_util.process_args(args, TOOL_TYPE_DISCOVER) __wlst_mode = cla_helper.process_online_args(argument_map) + cla_helper.validate_if_domain_home_required(_program_name, argument_map) target_configuration_helper.process_target_arguments(argument_map) __process_model_arg(argument_map) __process_archive_filename_arg(argument_map) @@ -356,6 +357,10 @@ def __connect_to_domain(model_context, helper): try: helper.connect(model_context.get_admin_user(), model_context.get_admin_password(), model_context.get_admin_url(), model_context.get_model_config().get_connect_timeout()) + + model_context.set_domain_home_name_if_remote(helper.get_domain_home_online(), + helper.get_domain_name_online()) + except PyWLSTException, wlst_ex: ex = exception_helper.create_discover_exception('WLSDPLY-06001', model_context.get_admin_url(), model_context.get_admin_user(), diff --git a/core/src/main/python/update.py b/core/src/main/python/update.py index 4b7b9d85b..04e070397 100644 --- a/core/src/main/python/update.py +++ b/core/src/main/python/update.py @@ -31,6 +31,8 @@ from wlsdeploy.util.exit_code import ExitCode from wlsdeploy.util.model import Model from wlsdeploy.util.weblogic_helper import WebLogicHelper +from wlsdeploy.tool.validate.validator import Validator +from oracle.weblogic.deploy.validate import ValidateException wlst_helper.wlst_functions = globals() @@ -44,12 +46,12 @@ __required_arguments = [ CommandLineArgUtil.ORACLE_HOME_SWITCH, - CommandLineArgUtil.DOMAIN_HOME_SWITCH, CommandLineArgUtil.MODEL_FILE_SWITCH ] __optional_arguments = [ # Used by shell script to locate WLST + CommandLineArgUtil.DOMAIN_HOME_SWITCH, CommandLineArgUtil.DOMAIN_TYPE_SWITCH, CommandLineArgUtil.ARCHIVE_FILE_SWITCH, CommandLineArgUtil.VARIABLE_FILE_SWITCH, @@ -66,6 +68,7 @@ CommandLineArgUtil.OUTPUT_DIR_SWITCH, CommandLineArgUtil.UPDATE_RCU_SCHEMA_PASS_SWITCH, CommandLineArgUtil.DISCARD_CURRENT_EDIT_SWITCH, + CommandLineArgUtil.REMOTE_SWITCH, CommandLineArgUtil.WAIT_FOR_EDIT_LOCK_SWITCH ] @@ -85,6 +88,7 @@ def __process_args(args): cla_helper.validate_optional_archive(_program_name, argument_map) cla_helper.validate_required_model(_program_name, argument_map) cla_helper.validate_variable_file_exists(_program_name, argument_map) + cla_helper.validate_if_domain_home_required(_program_name, argument_map) __wlst_mode = cla_helper.process_online_args(argument_map) cla_helper.process_encryption_args(argument_map) @@ -130,7 +134,18 @@ def __update_online(model, model_context, aliases): __logger.info("WLSDPLY-09005", admin_url, timeout, method_name=_method_name, class_name=_class_name) try: + + if model_context.is_remote(): + model_validator = Validator(model_context, aliases, logger=__logger, wlst_mode=WlstModes.ONLINE) + model_validator.validate_in_tool_mode(model.get_model(), None, + model_context.get_archive_file_name()) + __wlst_helper.connect(admin_user, admin_pwd, admin_url, timeout) + + # -remote does not have domain home set, so get it from online wlst after connect + model_context.set_domain_home_name_if_remote(__wlst_helper.get_domain_home_online(), + __wlst_helper.get_domain_name_online()) + deployer_utils.ensure_no_uncommitted_changes_or_edit_sessions(skip_edit_session_check) __wlst_helper.edit() __logger.fine("WLSDPLY-09019", edit_lock_acquire_timeout, edit_lock_release_timeout, edit_lock_exclusive) @@ -138,6 +153,8 @@ def __update_online(model, model_context, aliases): exclusive=edit_lock_exclusive) if model_context.is_discard_current_edit(): deployer_utils.discard_current_edit() + except ValidateException, ve: + raise ve except BundleAwareException, ex: raise ex diff --git a/core/src/main/python/validate.py b/core/src/main/python/validate.py index 741a038f1..3ae4a0af8 100644 --- a/core/src/main/python/validate.py +++ b/core/src/main/python/validate.py @@ -47,6 +47,7 @@ ] __optional_arguments = [ + CommandLineArgUtil.REMOTE_SWITCH, CommandLineArgUtil.DOMAIN_TYPE_SWITCH, # Used by shell script to locate WLST CommandLineArgUtil.MODEL_FILE_SWITCH, CommandLineArgUtil.ARCHIVE_FILE_SWITCH, diff --git a/core/src/main/python/wlsdeploy/tool/deploy/applications_deployer.py b/core/src/main/python/wlsdeploy/tool/deploy/applications_deployer.py index 12c92c84b..75897566f 100644 --- a/core/src/main/python/wlsdeploy/tool/deploy/applications_deployer.py +++ b/core/src/main/python/wlsdeploy/tool/deploy/applications_deployer.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2017, 2022, Oracle Corporation and/or its affiliates. +Copyright (c) 2017, 2023, Oracle Corporation and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. """ import copy @@ -63,11 +63,19 @@ class docstring """ def __init__(self, model, model_context, aliases, wlst_mode=WlstModes.OFFLINE, base_location=LocationContext()): + _method_name = '__init__' Deployer.__init__(self, model, model_context, aliases, wlst_mode) self._class_name = 'ApplicationDeployer' self._base_location = base_location self._parent_dict, self._parent_name, self._parent_type = self.__get_parent_by_location(self._base_location) self.version_helper = ApplicationsVersionHelper(model_context, self.archive_helper) + try: + self.upload_temporary_dir = FileUtils.createTempDirectory("wdt-uploadtemp").getAbsolutePath() + except (IOException), e: + ex = exception_helper.create_deploy_exception('WLSDPLY-09340', e.getLocalizedMessage(), error=e) + self.logger.throwing(ex, class_name=self._class_name, method_name=_method_name) + raise ex + def deploy(self): """ @@ -90,63 +98,75 @@ def __add_shared_libraries(self): self.logger.entering(self._parent_name, self._parent_type, class_name=self._class_name, method_name=_method_name) shared_libraries = dictionary_utils.get_dictionary_element(self._parent_dict, LIBRARY) - if len(shared_libraries) == 0: - self.logger.finer('WLSDPLY-09300', self._parent_type, self._parent_name, - class_name=self._class_name, method_name=_method_name) + if len(shared_libraries) != 0: + root_path = self.aliases.get_wlst_subfolders_path(self._base_location) + shared_library_location = LocationContext(self._base_location).append_location(LIBRARY) + shared_library_token = self.aliases.get_name_token(shared_library_location) + + for shared_library_name in shared_libraries: + existing_shared_libraries = deployer_utils.get_existing_object_list(shared_library_location, self.aliases) + + if model_helper.is_delete_name(shared_library_name): + self.__delete_versioned_library_or_application(existing_shared_libraries, shared_library_name, 'lib') + continue + else: + self.logger.info('WLSDPLY-09608', LIBRARY, shared_library_name, self._parent_type, self._parent_name, + class_name=self._class_name, method_name=_method_name) + + # + # In WLST offline mode, the shared library name must match the fully qualified name, including + # the spec and implementation versions from the deployment descriptor. Since we want to allow + # users to not tie the model to a specific release when deploy shared libraries shipped with + # WebLogic, we have to go compute the required name and change the name in the model prior to + # making changes to the domain. + # + shared_library = \ + copy.deepcopy(dictionary_utils.get_dictionary_element(shared_libraries, shared_library_name)) + shlib_source_path = dictionary_utils.get_element(shared_library, SOURCE_PATH) + if string_utils.is_empty(shlib_source_path): + ex = exception_helper.create_deploy_exception('WLSDPLY-09302', LIBRARY, shared_library_name, + SOURCE_PATH) + self.logger.throwing(ex, class_name=self._class_name, method_name=_method_name) + raise ex + + self.__extract_app_shlib_source_path(shared_library_name, shlib_source_path) + + library_name = \ + self.version_helper.get_library_versioned_name(shlib_source_path, shared_library_name) + quoted_library_name = self.wlst_helper.get_quoted_name_for_wlst(library_name) + shared_library_location.add_name_token(shared_library_token, quoted_library_name) + + self.wlst_helper.cd(root_path) + deployer_utils.create_and_cd(shared_library_location, existing_shared_libraries, self.aliases) + self.set_attributes(shared_library_location, shared_library) + shared_library_location.remove_name_token(shared_library_token) + self.logger.exiting(class_name=self._class_name, method_name=_method_name) return - root_path = self.aliases.get_wlst_subfolders_path(self._base_location) - shared_library_location = LocationContext(self._base_location).append_location(LIBRARY) - shared_library_token = self.aliases.get_name_token(shared_library_location) + self.logger.finer('WLSDPLY-09300', self._parent_type, self._parent_name, + class_name=self._class_name, method_name=_method_name) - for shared_library_name in shared_libraries: - existing_shared_libraries = deployer_utils.get_existing_object_list(shared_library_location, self.aliases) + def __extract_app_shlib_source_path(self, app_library_name, source_path): + _method_name = '__extract_app_shlib_source_path' - if model_helper.is_delete_name(shared_library_name): - if self.__verify_delete_versioned_app(shared_library_name, existing_shared_libraries, type='lib'): - location = LocationContext() - location.append_location(model_constants.LIBRARY) - existing_names = deployer_utils.get_existing_object_list(location, self.aliases) - deployer_utils.delete_named_element(location, shared_library_name, existing_names, self.aliases) - continue + if deployer_utils.is_path_into_archive(source_path): + if self.archive_helper is not None: + self.__extract_source_path_from_archive(source_path, LIBRARY, app_library_name) else: - self.logger.info('WLSDPLY-09608', LIBRARY, shared_library_name, self._parent_type, self._parent_name, - class_name=self._class_name, method_name=_method_name) - - # - # In WLST offline mode, the shared library name must match the fully qualified name, including - # the spec and implementation versions from the deployment descriptor. Since we want to allow - # users to not tie the model to a specific release when deploy shared libraries shipped with - # WebLogic, we have to go compute the required name and change the name in the model prior to - # making changes to the domain. - # - shared_library = \ - copy.deepcopy(dictionary_utils.get_dictionary_element(shared_libraries, shared_library_name)) - shlib_source_path = dictionary_utils.get_element(shared_library, SOURCE_PATH) - if string_utils.is_empty(shlib_source_path): - ex = exception_helper.create_deploy_exception('WLSDPLY-09302', LIBRARY, shared_library_name, - SOURCE_PATH) + ex = exception_helper.create_deploy_exception('WLSDPLY-09303', LIBRARY, app_library_name) self.logger.throwing(ex, class_name=self._class_name, method_name=_method_name) raise ex - if deployer_utils.is_path_into_archive(shlib_source_path): - if self.archive_helper is not None: - self.__extract_source_path_from_archive(shlib_source_path, LIBRARY, shared_library_name) - else: - ex = exception_helper.create_deploy_exception('WLSDPLY-09303', LIBRARY, shared_library_name) - self.logger.throwing(ex, class_name=self._class_name, method_name=_method_name) - raise ex - - library_name = \ - self.version_helper.get_library_versioned_name(shlib_source_path, shared_library_name) - quoted_library_name = self.wlst_helper.get_quoted_name_for_wlst(library_name) - shared_library_location.add_name_token(shared_library_token, quoted_library_name) + def __delete_versioned_library_or_application(self, existing_applib_list, app_name, app_type): + if self.__verify_delete_versioned_app(app_name, existing_applib_list, type=app_type): + location = LocationContext() + if app_type == 'lib': + location.append_location(model_constants.LIBRARY) + else: + location.append_location(model_constants.APPLICATION) + existing_names = deployer_utils.get_existing_object_list(location, self.aliases) + deployer_utils.delete_named_element(location, app_name, existing_names, self.aliases) - self.wlst_helper.cd(root_path) - deployer_utils.create_and_cd(shared_library_location, existing_shared_libraries, self.aliases) - self.set_attributes(shared_library_location, shared_library) - shared_library_location.remove_name_token(shared_library_token) - self.logger.exiting(class_name=self._class_name, method_name=_method_name) def __add_applications(self): """ @@ -158,71 +178,61 @@ def __add_applications(self): class_name=self._class_name, method_name=_method_name) applications = dictionary_utils.get_dictionary_element(self._parent_dict, APPLICATION) - if len(applications) == 0: - self.logger.finer('WLSDPLY-09304', self._parent_type, self._parent_name, - class_name=self._class_name, method_name=_method_name) - return - - root_path = self.aliases.get_wlst_subfolders_path(self._base_location) - application_location = LocationContext(self._base_location).append_location(APPLICATION) - application_token = self.aliases.get_name_token(application_location) + if len(applications) != 0: + root_path = self.aliases.get_wlst_subfolders_path(self._base_location) + application_location = LocationContext(self._base_location).append_location(APPLICATION) + application_token = self.aliases.get_name_token(application_location) - for application_name in applications: - existing_applications = deployer_utils.get_existing_object_list(application_location, self.aliases) + for application_name in applications: + existing_applications = deployer_utils.get_existing_object_list(application_location, self.aliases) - if model_helper.is_delete_name(application_name): - if self.__verify_delete_versioned_app(application_name, existing_applications, type='app'): - location = LocationContext() - location.append_location(model_constants.APPLICATION) - existing_names = deployer_utils.get_existing_object_list(location, self.aliases) - deployer_utils.delete_named_element(location, application_name, existing_names, self.aliases) - continue - else: - self.logger.info('WLSDPLY-09301', APPLICATION, application_name, self._parent_type, self._parent_name, - class_name=self._class_name, method_name=_method_name) + if model_helper.is_delete_name(application_name): + self.__delete_versioned_library_or_application(existing_applications, application_name, 'app') + continue + else: + self.logger.info('WLSDPLY-09301', APPLICATION, application_name, self._parent_type, self._parent_name, + class_name=self._class_name, method_name=_method_name) - application = \ - copy.deepcopy(dictionary_utils.get_dictionary_element(applications, application_name)) + application = \ + copy.deepcopy(dictionary_utils.get_dictionary_element(applications, application_name)) - app_source_path = dictionary_utils.get_element(application, SOURCE_PATH) - if string_utils.is_empty(app_source_path): - ex = exception_helper.create_deploy_exception('WLSDPLY-09302', APPLICATION, application_name, - SOURCE_PATH) - self.logger.throwing(ex, class_name=self._class_name, method_name=_method_name) - raise ex - - if deployer_utils.is_path_into_archive(app_source_path): - if self.archive_helper is not None: - self.__extract_source_path_from_archive(app_source_path, APPLICATION, application_name) - else: - ex = exception_helper.create_deploy_exception('WLSDPLY-09303', APPLICATION, application_name) + app_source_path = dictionary_utils.get_element(application, SOURCE_PATH) + if string_utils.is_empty(app_source_path): + ex = exception_helper.create_deploy_exception('WLSDPLY-09302', APPLICATION, application_name, + SOURCE_PATH) self.logger.throwing(ex, class_name=self._class_name, method_name=_method_name) raise ex - module_type = dictionary_utils.get_element(application, MODULE_TYPE) + self.__extract_app_shlib_source_path(application_name, app_source_path) - application_name = \ - self.version_helper.get_application_versioned_name(app_source_path, application_name, - module_type=module_type) + module_type = dictionary_utils.get_element(application, MODULE_TYPE) - quoted_application_name = self.wlst_helper.get_quoted_name_for_wlst(application_name) + application_name = \ + self.version_helper.get_application_versioned_name(app_source_path, application_name, + module_type=module_type) - application_location.add_name_token(application_token, quoted_application_name) + quoted_application_name = self.wlst_helper.get_quoted_name_for_wlst(application_name) - self.wlst_helper.cd(root_path) - deployer_utils.create_and_cd(application_location, existing_applications, self.aliases) + application_location.add_name_token(application_token, quoted_application_name) - self._set_attributes_and_add_subfolders(application_location, application) + self.wlst_helper.cd(root_path) + deployer_utils.create_and_cd(application_location, existing_applications, self.aliases) - application_location.remove_name_token(application_token) - self.__substitute_appmodule_token(app_source_path, module_type) + self._set_attributes_and_add_subfolders(application_location, application) - if app_source_path.startswith(WLSDeployArchive.ARCHIVE_STRUCT_APPS_TARGET_DIR): - plan_dir = dictionary_utils.get_element(application, PLAN_DIR) - plan_path = dictionary_utils.get_element(application, PLAN_PATH) - self._fix_plan_file(plan_dir, plan_path) + application_location.remove_name_token(application_token) + self.__substitute_appmodule_token(app_source_path, module_type) - self.logger.exiting(class_name=self._class_name, method_name=_method_name) + if app_source_path.startswith(WLSDeployArchive.ARCHIVE_STRUCT_APPS_TARGET_DIR): + plan_dir = dictionary_utils.get_element(application, PLAN_DIR) + plan_path = dictionary_utils.get_element(application, PLAN_PATH) + self._fix_plan_file(plan_dir, plan_path) + + self.logger.exiting(class_name=self._class_name, method_name=_method_name) + return + + self.logger.finer('WLSDPLY-09304', self._parent_type, self._parent_name, + class_name=self._class_name, method_name=_method_name) def __substitute_appmodule_token(self, path, module_type): # we need to substitute any token in the app module xml file @@ -433,6 +443,11 @@ def __get_parent_dict_and_name_for_resource_group(self, location, parent_dict, p return parent_dict[RESOURCE_GROUP][rg_name], rg_name def __get_existing_apps(self, base_location): + """ + Getting the details of existing applications including hash values of the app and plan. + :param base_location: location context + :return: dictionary containing the details about the existing applications + """ _method_name = '__get_existing_apps' self.logger.entering(str_helper.to_string(base_location), class_name=self._class_name, method_name=_method_name) @@ -478,18 +493,31 @@ def __get_existing_apps(self, base_location): deployment_order = attributes_map['DeploymentOrder'] - app_hash = self.__get_file_hash(absolute_sourcepath) - if absolute_planpath is not None: - plan_hash = self.__get_file_hash(absolute_planpath) - else: - plan_hash = None + app_hash, plan_hash = self.__get_app_and_plan_hash(absolute_planpath, absolute_sourcepath) _update_ref_dictionary(ref_dictionary, app, absolute_sourcepath, app_hash, config_targets, absolute_plan_path=absolute_planpath, deploy_order=deployment_order, plan_hash=plan_hash) return ref_dictionary + def __get_app_and_plan_hash(self, absolute_planpath, absolute_sourcepath): + if self.model_context.is_remote(): + app_hash = None + plan_hash = None + else: + app_hash = self.__get_file_hash(absolute_sourcepath) + if absolute_planpath is not None: + plan_hash = self.__get_file_hash(absolute_planpath) + else: + plan_hash = None + return app_hash, plan_hash + def __get_library_references(self, base_location): + """ + Getting shared library referenced + :param base_location: location context + :return: dictonary of the library referenced details. + """ _method_name = '__get_library_references' self.logger.entering(str_helper.to_string(base_location), class_name=self._class_name, method_name=_method_name) @@ -515,51 +543,52 @@ def __get_library_references(self, base_location): for lib in libs: if lib in internal_skip_list: continue - self.wlst_helper.domain_runtime() - self.wlst_helper.cd(library_runtime_path + lib) - runtime_attributes = self.wlst_helper.lsa() - - lib_location = LocationContext(location).add_name_token(token_name, lib) - wlst_attributes_path = self.aliases.get_wlst_attributes_path(lib_location) - self.wlst_helper.server_config() - self.wlst_helper.cd(wlst_attributes_path) - config_attributes = self.wlst_helper.lsa() - config_targets = self.__get_config_targets() - - # There are case in application where absolute source path is not set but sourepath is - # if source path is not absolute then we need to add the domain path - - absolute_source_path = config_attributes[ABSOLUTE_SOURCE_PATH] - if absolute_source_path is None: - absolute_source_path = config_attributes['SourcePath'] - - if absolute_source_path is not None and not os.path.isabs(absolute_source_path): - absolute_source_path = self.model_context.get_domain_home() + '/' + absolute_source_path - - deployment_order = config_attributes[DEPLOYMENT_ORDER] - lib_hash = self.__get_file_hash(absolute_source_path) - - if string_utils.to_boolean(runtime_attributes['Referenced']) is True: - referenced_path = library_runtime_path + lib + '/ReferencingRuntimes/' - self.wlst_helper.domain_runtime() - referenced_by = self.wlst_helper.get_existing_object_list(referenced_path) - self.wlst_helper.cd(referenced_path) - for app_ref in referenced_by: - # TODO(rpatrick) - what if it is partitioned? - ref_attrs = self.wlst_helper.lsa(app_ref) - app_type = ref_attrs['Type'] - app_id = None - if app_type == 'ApplicationRuntime' and 'ApplicationName' in ref_attrs: - app_id = ref_attrs['ApplicationName'] - if app_type == 'WebAppComponentRuntime' and 'ApplicationIdentifier' in ref_attrs: - app_id = ref_attrs['ApplicationIdentifier'] - - _update_ref_dictionary(existing_libraries, lib, absolute_source_path, lib_hash, config_targets, - deploy_order=deployment_order, app_name=app_id) - else: - _update_ref_dictionary(existing_libraries, lib, absolute_source_path, lib_hash, config_targets) + self.__get_library_reference_attributes(existing_libraries, lib, library_runtime_path, location, + token_name) return existing_libraries + def __get_library_reference_attributes(self, existing_libraries, lib, library_runtime_path, location, token_name): + self.wlst_helper.domain_runtime() + self.wlst_helper.cd(library_runtime_path + lib) + runtime_attributes = self.wlst_helper.lsa() + lib_location = LocationContext(location).add_name_token(token_name, lib) + wlst_attributes_path = self.aliases.get_wlst_attributes_path(lib_location) + self.wlst_helper.server_config() + self.wlst_helper.cd(wlst_attributes_path) + config_attributes = self.wlst_helper.lsa() + config_targets = self.__get_config_targets() + # There are case in application where absolute source path is not set but sourepath is + # if source path is not absolute then we need to add the domain path + absolute_source_path = config_attributes[ABSOLUTE_SOURCE_PATH] + if absolute_source_path is None: + absolute_source_path = config_attributes['SourcePath'] + if absolute_source_path is not None and not os.path.isabs(absolute_source_path): + absolute_source_path = self.model_context.get_domain_home() + '/' + absolute_source_path + deployment_order = config_attributes[DEPLOYMENT_ORDER] + if self.model_context.is_remote(): + lib_hash = None + else: + lib_hash = self.__get_file_hash(absolute_source_path) + if string_utils.to_boolean(runtime_attributes['Referenced']) is True: + referenced_path = library_runtime_path + lib + '/ReferencingRuntimes/' + self.wlst_helper.domain_runtime() + referenced_by = self.wlst_helper.get_existing_object_list(referenced_path) + self.wlst_helper.cd(referenced_path) + for app_ref in referenced_by: + # TODO(rpatrick) - what if it is partitioned? + ref_attrs = self.wlst_helper.lsa(app_ref) + app_type = ref_attrs['Type'] + app_id = None + if app_type == 'ApplicationRuntime' and 'ApplicationName' in ref_attrs: + app_id = ref_attrs['ApplicationName'] + if app_type == 'WebAppComponentRuntime' and 'ApplicationIdentifier' in ref_attrs: + app_id = ref_attrs['ApplicationIdentifier'] + + _update_ref_dictionary(existing_libraries, lib, absolute_source_path, lib_hash, config_targets, + deploy_order=deployment_order, app_name=app_id) + else: + _update_ref_dictionary(existing_libraries, lib, absolute_source_path, lib_hash, config_targets) + def __build_library_deploy_strategy(self, location, model_libs, existing_lib_refs, stop_app_list, update_library_list): """ @@ -581,13 +610,7 @@ def __build_library_deploy_strategy(self, location, model_libs, existing_lib_ref self.model_context.replace_tokens(LIBRARY, lib, param, lib_dict) if model_helper.is_delete_name(lib): - if self.__verify_delete_versioned_app(lib, existing_libs, 'lib'): - lib_name = model_helper.get_delete_item_name(lib) - if lib_name in existing_libs: - model_libs.pop(lib) - update_library_list.append(lib_name) - else: - model_libs.pop(lib) + self.__update_delete_library_in_model(existing_libs, lib, model_libs, update_library_list) continue # determine the versioned name of the library from the library's MANIFEST @@ -627,38 +650,61 @@ def __build_library_deploy_strategy(self, location, model_libs, existing_lib_ref existing_lib_targets_set, model_targets_set) continue - # user libraries - model_lib_hash = self.__get_hash(model_src_path) - existing_lib_hash = self.__get_file_hash(existing_src_path) - if model_lib_hash != existing_lib_hash: - # - # updated library and add referencing apps to the stop list - # - # The target needs to be set to the union to avoid changing - # target in subsequent deploy affecting existing referencing apps. - # - union_targets_set = existing_lib_targets_set.union(model_targets_set) - lib_dict['Target'] = ','.join(union_targets_set) - # For update case, the sparse model may be just changing targets, therefore without sourcepath - if lib_dict['SourcePath'] is None and existing_src_path is not None: - lib_dict['SourcePath'] = existing_src_path - - if versioned_name not in update_library_list: - update_library_list.append(versioned_name) - else: - # If the hashes match, assume that the library did not change so there is no need - # to redeploy them ot the referencing applications unless the targets are different. - if existing_lib_targets_set.issuperset(model_targets_set): - self.__remove_lib_from_deployment(model_libs, lib) - else: - # Adjust the targets to only the new targets so that existing apps on - # already targeted servers are not impacted. - adjusted_set = model_targets_set.difference(existing_lib_targets_set) - adjusted_targets = ','.join(adjusted_set) - lib_dict['Target'] = adjusted_targets - # For update case, the sparse model may be just changing targets, therefore without sourcepath - if lib_dict['SourcePath'] is None and existing_src_path is not None: - lib_dict['SourcePath'] = existing_src_path + # always update if remote + if self.model_context.is_remote(): + update_library_list.append(versioned_name) + continue + + # based on the hash value of the existing source path and the new one in the archive + # setup how the library should be deployed or redeployed. + self._update_library_build_strategy_based_on_hashes(existing_lib_targets_set, existing_src_path, + lib, lib_dict, model_libs, model_src_path, + model_targets_set, update_library_list, + versioned_name) + + def _update_library_build_strategy_based_on_hashes(self, existing_lib_targets_set, existing_src_path, lib, lib_dict, + model_libs, model_src_path, model_targets_set, + update_library_list, versioned_name): + model_lib_hash = self.__get_hash(model_src_path) + existing_lib_hash = self.__get_file_hash(existing_src_path) + if model_lib_hash != existing_lib_hash: + # + # updated library and add referencing apps to the stop list + # + # The target needs to be set to the union to avoid changing + # target in subsequent deploy affecting existing referencing apps. + # + union_targets_set = existing_lib_targets_set.union(model_targets_set) + lib_dict['Target'] = ','.join(union_targets_set) + # For update case, the sparse model may be just changing targets, therefore without sourcepath + if lib_dict['SourcePath'] is None and existing_src_path is not None: + lib_dict['SourcePath'] = existing_src_path + + if versioned_name not in update_library_list: + update_library_list.append(versioned_name) + else: + # If the hashes match, assume that the library did not change so there is no need + # to redeploy them ot the referencing applications unless the targets are different. + if existing_lib_targets_set.issuperset(model_targets_set): + self.__remove_lib_from_deployment(model_libs, lib) + else: + # Adjust the targets to only the new targets so that existing apps on + # already targeted servers are not impacted. + adjusted_set = model_targets_set.difference(existing_lib_targets_set) + adjusted_targets = ','.join(adjusted_set) + lib_dict['Target'] = adjusted_targets + # For update case, the sparse model may be just changing targets, therefore without sourcepath + if lib_dict['SourcePath'] is None and existing_src_path is not None: + lib_dict['SourcePath'] = existing_src_path + + def __update_delete_library_in_model(self, existing_libs, lib, model_libs, update_library_list): + if self.__verify_delete_versioned_app(lib, existing_libs, 'lib'): + lib_name = model_helper.get_delete_item_name(lib) + if lib_name in existing_libs: + model_libs.pop(lib) + update_library_list.append(lib_name) + else: + model_libs.pop(lib) def __shouldCheckForTargetChange(self, src_path, model_src_path): # If the existing running app's source path (always absolute from runtime mbean) = the model's source path. @@ -730,56 +776,79 @@ def __build_app_deploy_strategy(self, location, model_apps, existing_app_refs, s if model_src_path is None and src_path is not None: model_src_path = src_path - model_src_hash = self.__get_hash(model_src_path) - model_plan_hash = self.__get_hash(dictionary_utils.get_element(app_dict, PLAN_PATH)) - - existing_src_hash = self.__get_file_hash(src_path) - existing_plan_hash = self.__get_file_hash(plan_path) existing_app_targets = dictionary_utils.get_element(existing_app_ref, 'target') existing_app_targets_set = Set(existing_app_targets) - if model_src_hash == existing_src_hash: - if model_plan_hash == existing_plan_hash: - if self.__shouldCheckForTargetChange(src_path, model_src_path): - # If model hashes match existing hashes, the application did not change. - # Unless targets were added, there's no need to redeploy. - # If it is an absolute path, there is nothing to compare so assume redeploy - model_targets = dictionary_utils.get_element(app_dict, TARGET) - model_targets_list = alias_utils.create_list(model_targets, 'WLSDPLY-08000') - model_targets_set = Set(model_targets_list) - - if existing_app_targets_set == model_targets_set and len(existing_app_targets_set) > 0: - # redeploy the app if everything is the same - self.logger.info('WLSDPLY-09336', src_path, - class_name=self._class_name, method_name=_method_name) - self.__append_to_stop_and_undeploy_apps(versioned_name, stop_and_undeploy_app_list - , existing_app_targets_set) - elif len(existing_app_targets_set) == 0 and len(model_targets_set) == 0: - self.__remove_app_from_deployment(model_apps, app, "emptyset") - elif existing_app_targets_set.issuperset(model_targets_set): - self.__remove_app_from_deployment(model_apps, app, "superset") - else: - # Adjust the targets to only the new targets so that existing apps on - # already targeted servers are not impacted. - adjusted_set = model_targets_set.difference(existing_app_targets_set) - adjusted_targets = ','.join(adjusted_set) - app_dict['Target'] = adjusted_targets - - # For update case, the sparse model may be just changing targets, therefore without sourcepath - - if app_dict['SourcePath'] is None and src_path is not None: - app_dict['SourcePath'] = src_path - else: - # same hash but different path, so redeploy it - self.__append_to_stop_and_undeploy_apps(versioned_name, stop_and_undeploy_app_list - , existing_app_targets_set) - else: - # updated deployment plan - self.__append_to_stop_and_undeploy_apps(versioned_name, stop_and_undeploy_app_list - , existing_app_targets_set) - else: - # updated app + + # always update if remote + if self.model_context.is_remote(): self.__append_to_stop_and_undeploy_apps(versioned_name, stop_and_undeploy_app_list , existing_app_targets_set) + continue + + # based on the hash value of existing app and the new one in the archive + # set up how the app should be deployed or redeployed + self.__update_app_build_strartegy_based_on_hashes(app, app_dict, existing_app_targets_set, + model_apps, model_src_path, plan_path, src_path, + stop_and_undeploy_app_list, versioned_name) + + def __update_app_build_strartegy_based_on_hashes(self, app, app_dict, existing_app_targets_set, model_apps, + model_src_path, plan_path, src_path, stop_and_undeploy_app_list, + versioned_name): + model_src_hash = self.__get_hash(model_src_path) + model_plan_hash = self.__get_hash(dictionary_utils.get_element(app_dict, PLAN_PATH)) + existing_src_hash = self.__get_file_hash(src_path) + existing_plan_hash = self.__get_file_hash(plan_path) + if model_src_hash == existing_src_hash: + if model_plan_hash == existing_plan_hash: + if self.__shouldCheckForTargetChange(src_path, model_src_path): + self._update_app_deploy_strategy_for_target_changes(app, app_dict, + existing_app_targets_set, model_apps, + src_path, stop_and_undeploy_app_list, + versioned_name) + else: + # same hash but different path, so redeploy it + self.__append_to_stop_and_undeploy_apps(versioned_name, stop_and_undeploy_app_list + , existing_app_targets_set) + else: + # updated deployment plan + self.__append_to_stop_and_undeploy_apps(versioned_name, stop_and_undeploy_app_list + , existing_app_targets_set) + else: + # updated app + self.__append_to_stop_and_undeploy_apps(versioned_name, stop_and_undeploy_app_list + , existing_app_targets_set) + + def _update_app_deploy_strategy_for_target_changes(self, app, app_dict, existing_app_targets_set, + model_apps, src_path, stop_and_undeploy_app_list, versioned_name): + + _method_name = '_update_app_deploy_strategy_for_target_changes' + # If model hashes match existing hashes, the application did not change. + # Unless targets were added, there's no need to redeploy. + # If it is an absolute path, there is nothing to compare so assume redeploy + model_targets = dictionary_utils.get_element(app_dict, TARGET) + model_targets_list = alias_utils.create_list(model_targets, 'WLSDPLY-08000') + model_targets_set = Set(model_targets_list) + if existing_app_targets_set == model_targets_set and len(existing_app_targets_set) > 0: + # redeploy the app if everything is the same + self.logger.info('WLSDPLY-09336', src_path, + class_name=self._class_name, method_name=_method_name) + self.__append_to_stop_and_undeploy_apps(versioned_name, stop_and_undeploy_app_list + , existing_app_targets_set) + elif len(existing_app_targets_set) == 0 and len(model_targets_set) == 0: + self.__remove_app_from_deployment(model_apps, app, "emptyset") + elif existing_app_targets_set.issuperset(model_targets_set): + self.__remove_app_from_deployment(model_apps, app, "superset") + else: + # Adjust the targets to only the new targets so that existing apps on + # already targeted servers are not impacted. + adjusted_set = model_targets_set.difference(existing_app_targets_set) + adjusted_targets = ','.join(adjusted_set) + app_dict['Target'] = adjusted_targets + + # For update case, the sparse model may be just changing targets, therefore without sourcepath + + if app_dict['SourcePath'] is None and src_path is not None: + app_dict['SourcePath'] = src_path def __remove_delete_targets(self, model_dict, existing_ref): """ @@ -982,12 +1051,11 @@ def __deploy_model_libraries(self, model_libs, lib_location): targets = dictionary_utils.get_element(lib_dict, TARGET) stage_mode = dictionary_utils.get_element(lib_dict, STAGE_MODE) options, sub_module_targets = _get_deploy_options(model_libs, lib_name, library_module='true', - application_version_helper=self.version_helper) - for uses_path_tokens_attribute_name in uses_path_tokens_attribute_names: - if uses_path_tokens_attribute_name in lib_dict: - path = lib_dict[uses_path_tokens_attribute_name] - if deployer_utils.is_path_into_archive(path): - self.__extract_source_path_from_archive(path, LIBRARY, lib_name) + application_version_helper=self.version_helper, + is_remote=self.model_context.is_remote()) + + src_path = self._get_source_path_fo_delooy_library(lib_dict, lib_name, src_path, + uses_path_tokens_attribute_names) location.add_name_token(token_name, lib_name) resource_group_template_name, resource_group_name, partition_name = \ @@ -997,6 +1065,20 @@ def __deploy_model_libraries(self, model_libs, lib_location): resource_group_template=resource_group_template_name, options=options) location.remove_name_token(token_name) + def _get_source_path_fo_delooy_library(self, lib_dict, lib_name, src_path, uses_path_tokens_attribute_names): + for uses_path_tokens_attribute_name in uses_path_tokens_attribute_names: + if uses_path_tokens_attribute_name in lib_dict: + path = lib_dict[uses_path_tokens_attribute_name] + if deployer_utils.is_path_into_archive(path): + self.__extract_source_path_from_archive(path, LIBRARY, lib_name, + is_remote=self.model_context.is_remote(), + upload_remote_directory=self.upload_temporary_dir) + # if it is remote app deployment src path is the local absolute location and the + # app archive will be uploaded to the admin server's upload directory + if self.model_context.is_remote(): + src_path = self.upload_temporary_dir + '/' + src_path + return src_path + def __deploy_model_applications(self, model_apps, app_location, deployed_applist): if model_apps is not None: uses_path_tokens_attribute_names = self.__get_uses_path_tokens_attribute_names(app_location) @@ -1011,14 +1093,13 @@ def __deploy_model_applications(self, model_apps, app_location, deployed_applist stage_mode = dictionary_utils.get_element(app_dict, STAGE_MODE) targets = dictionary_utils.get_element(app_dict, TARGET) options, sub_module_targets = _get_deploy_options(model_apps, app_name, library_module='false', - application_version_helper=self.version_helper) + application_version_helper=self.version_helper, + is_remote=self.model_context.is_remote()) # any attribute with 'uses_path_tokens' may be in the archive (such as SourcePath) - for uses_path_tokens_attribute_name in uses_path_tokens_attribute_names: - if uses_path_tokens_attribute_name in app_dict: - path = app_dict[uses_path_tokens_attribute_name] - if deployer_utils.is_path_into_archive(path): - self.__extract_source_path_from_archive(path, APPLICATION, app_name) + path, src_path = self._get_source_path_for_deploy_application(app_dict, app_name, src_path, + uses_path_tokens_attribute_names) + location.add_name_token(token_name, app_name) resource_group_template_name, resource_group_name, partition_name = \ self.__get_mt_names_from_location(location) @@ -1036,6 +1117,19 @@ def __deploy_model_applications(self, model_apps, app_location, deployed_applist deployed_applist.append(new_app_name) self.__substitute_appmodule_token(path, module_type) + def _get_source_path_for_deploy_application(self, app_dict, app_name, src_path, uses_path_tokens_attribute_names): + for uses_path_tokens_attribute_name in uses_path_tokens_attribute_names: + if uses_path_tokens_attribute_name in app_dict: + path = app_dict[uses_path_tokens_attribute_name] + if deployer_utils.is_path_into_archive(path): + self.__extract_source_path_from_archive(path, APPLICATION, app_name, + is_remote=self.model_context.is_remote(), + upload_remote_directory=self.upload_temporary_dir) + # if it is remote app deployment src path is the local absolute location and the + # app archive will be uploaded to the admin server's upload directory + if self.model_context.is_remote(): + src_path = self.upload_temporary_dir + '/' + src_path + return path, src_path def __get_mt_names_from_location(self, app_location): dummy_location = LocationContext() @@ -1141,7 +1235,8 @@ def __deploy_app_online(self, application_name, source_path, targets, stage_mode self.wlst_helper.deploy_application(application_name, *args, **kwargs) return application_name - def __extract_source_path_from_archive(self, source_path, model_type, model_name): + def __extract_source_path_from_archive(self, source_path, model_type, model_name, is_remote=False, + upload_remote_directory=None): """ Extract contents from the archive set for the specified source path. The contents may be a single file, or a directory with exploded content. @@ -1152,10 +1247,18 @@ def __extract_source_path_from_archive(self, source_path, model_type, model_name _method_name = '__extract_source_path_from_archive' # source path may be may be a single file (jar, war, etc.) if self.archive_helper.contains_file(source_path): - self.archive_helper.extract_file(source_path) + if is_remote: + self.archive_helper.extract_file(source_path, upload_remote_directory, False) + else: + self.archive_helper.extract_file(source_path) # source path may be exploded directory in archive elif self.archive_helper.contains_path(source_path): + # exploded format cannot be used for remote upload + if is_remote: + ex = exception_helper.create_deploy_exception('WLSDPLY-09341', model_name, source_path) + self.logger.throwing(ex, class_name=self._class_name, method_name=_method_name) + raise ex self.archive_helper.extract_directory(source_path) else: @@ -1248,7 +1351,7 @@ def __start_all_apps(self, deployed_app_list, base_location): self.__start_app(app) -def _get_deploy_options(model_apps, app_name, library_module, application_version_helper): +def _get_deploy_options(model_apps, app_name, library_module, application_version_helper, is_remote=False): """ Get the deploy command options. :param model_apps: the apps dictionary @@ -1278,11 +1381,22 @@ def _get_deploy_options(model_apps, app_name, library_module, application_versio if library_module == 'true': deploy_options['libraryModule'] = 'true' + if is_remote: + deploy_options['upload'] = 'true' + if len(deploy_options) == 0: deploy_options = None module_type = dictionary_utils.get_element(app, MODULE_TYPE) sub_module_targets = '' + sub_module_targets = _set_sub_deployments_for_app_module(app, application_version_helper, module_type, + sub_module_targets) + + + return deploy_options, sub_module_targets + + +def _set_sub_deployments_for_app_module(app, application_version_helper, module_type, sub_module_targets): if application_version_helper.is_module_type_app_module(module_type): sub_deployments = dictionary_utils.get_element(app, SUB_DEPLOYMENT) if sub_deployments is not None: @@ -1292,10 +1406,9 @@ def _get_deploy_options(model_apps, app_name, library_module, application_versio name = sub_deployment target = sub_deployments[name][TARGET] sub_module_targets += '%s@%s' % (name, target) + return sub_module_targets - return deploy_options, sub_module_targets - def _find_deployorder_list(apps_dict, ordered_list, order): """ Get the deployment order for the apps diff --git a/core/src/main/python/wlsdeploy/tool/discover/domain_info_discoverer.py b/core/src/main/python/wlsdeploy/tool/discover/domain_info_discoverer.py index 4c35bde50..72b066ef8 100644 --- a/core/src/main/python/wlsdeploy/tool/discover/domain_info_discoverer.py +++ b/core/src/main/python/wlsdeploy/tool/discover/domain_info_discoverer.py @@ -129,7 +129,7 @@ def get_user_env_scripts(self): _logger.finer('WLSDPLY-06423', domain_bin, class_name=_class_name, method_name=_method_name) for entry in file_list: if self._model_context.is_remote(): - new_source_name = archive_file.getDomainBinScriptArchivePath(entry) + new_source_name = WLSDeployArchive.getDomainBinScriptArchivePath(entry) self.add_to_remote_map(entry, new_source_name, WLSDeployArchive.ArchiveEntryType.DOMAIN_BIN.name()) else: diff --git a/core/src/main/python/wlsdeploy/tool/util/archive_helper.py b/core/src/main/python/wlsdeploy/tool/util/archive_helper.py index caaf80c95..624324e83 100644 --- a/core/src/main/python/wlsdeploy/tool/util/archive_helper.py +++ b/core/src/main/python/wlsdeploy/tool/util/archive_helper.py @@ -129,7 +129,34 @@ def contains_file_or_path(self, path): self.__logger.exiting(class_name=self.__class_name, method_name=_method_name, result=result) return result - def extract_file(self, path, location=None): + def is_path_forbidden_for_remote_update(self, path): + """ + Check that the provided path in the archive is forbidden for remote domain update + :param path: the path to test + :return: True, if the path is forbidden for remote update. False otherwise + :raises: BundleAwareException of the appropriate type: if an error occurs + """ + _method_name = 'is_path_forbidden_for_remote_update' + self.__logger.entering(path, class_name=self.__class_name, method_name=_method_name) + + result = False + for archive_file in self.__archive_files: + try: + if archive_file.containsFileOrPath(path): + if (not path.startswith(WLSDeployArchive.ARCHIVE_SHLIBS_TARGET_DIR) and + not path.startswith(WLSDeployArchive.ARCHIVE_APPS_TARGET_DIR)): + result = True + break + except (IllegalArgumentException), e: + ex = exception_helper.create_exception(self.__exception_type, "WLSDPLY-19309", path, + self.__archive_files_text, e.getLocalizedMessage(), error=e) + self.__logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) + raise ex + + self.__logger.exiting(class_name=self.__class_name, method_name=_method_name, result=result) + return result + + def extract_file(self, path, location=None, strip_leading_path=True): """ Extract the specified file from the archive into the specified directory, or into Domain Home. :param path: the path into the archive @@ -146,7 +173,7 @@ def extract_file(self, path, location=None): result = archive_file.extractFile(path, self.__domain_home) else: extract_location = FileUtils.getCanonicalFile(File(location)) - result = archive_file.extractFile(path, extract_location, True) + result = archive_file.extractFile(path, extract_location, strip_leading_path) except (IllegalArgumentException, WLSDeployArchiveIOException), e: ex = exception_helper.create_exception(self.__exception_type, "WLSDPLY-19303", path, self.__archive_files_text, e.getLocalizedMessage(), error=e) diff --git a/core/src/main/python/wlsdeploy/tool/util/wlst_helper.py b/core/src/main/python/wlsdeploy/tool/util/wlst_helper.py index b0d098139..fb270f856 100644 --- a/core/src/main/python/wlsdeploy/tool/util/wlst_helper.py +++ b/core/src/main/python/wlsdeploy/tool/util/wlst_helper.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2019, 2022, Oracle Corporation and/or its affiliates. +Copyright (c) 2019, 2023, Oracle Corporation and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. """ @@ -1361,6 +1361,45 @@ def server_config(self): raise pwe self.__logger.exiting(class_name=self.__class_name, method_name=_method_name) + def get_domain_name_online(self): + """ + Get the domain name online. + :raises Exception for the specified tool type: if a WLST error occurs + """ + _method_name = 'get_domain_name_online' + self.__logger.entering(class_name=self.__class_name, method_name=_method_name) + try: + self.server_config() + self.cd('/') + name = self.get('Name') + except self.__load_global('WLSTException'), e: + pwe = exception_helper.create_exception(self.__exception_type, 'WLSDPLY-00065', + _format_exception(e), error=e) + self.__logger.throwing(class_name=self.__class_name, method_name=_method_name, error=pwe) + raise pwe + self.__logger.exiting(class_name=self.__class_name, method_name=_method_name) + return name + + + def get_domain_home_online(self): + """ + Get the domain name online. + :raises Exception for the specified tool type: if a WLST error occurs + """ + _method_name = 'get_domain_home_online' + self.__logger.entering(class_name=self.__class_name, method_name=_method_name) + try: + self.server_config() + self.cd('/') + result = self.get('RootDirectory') + except self.__load_global('WLSTException'), e: + pwe = exception_helper.create_exception(self.__exception_type, 'WLSDPLY-00065', + _format_exception(e), error=e) + self.__logger.throwing(class_name=self.__class_name, method_name=_method_name, error=pwe) + raise pwe + self.__logger.exiting(class_name=self.__class_name, method_name=_method_name) + return result + def domain_runtime(self): """ Change to the domainRuntime MBean tree. diff --git a/core/src/main/python/wlsdeploy/tool/validate/validator.py b/core/src/main/python/wlsdeploy/tool/validate/validator.py index 098863038..5d872cbb6 100644 --- a/core/src/main/python/wlsdeploy/tool/validate/validator.py +++ b/core/src/main/python/wlsdeploy/tool/validate/validator.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2017, 2022, Oracle Corporation and/or its affiliates. +Copyright (c) 2017, 2023, Oracle Corporation and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. """ import os @@ -838,6 +838,15 @@ def __validate_single_path_in_archive(self, path, attribute_name, model_folder_p if not archive_has_file: log_method('WLSDPLY-05024', attribute_name, model_folder_path, path, self._archive_file_name, class_name=_class_name, method_name=_method_name) + + # If this is validating for remote use + # check to see if it is a path into the archive + # and the path is not applications/libraries then flag as error + + if self._model_context.is_remote() and self._archive_helper.is_path_forbidden_for_remote_update(path): + log_method('WLSDPLY-19313', attribute_name, model_folder_path, path, + class_name=_class_name, method_name=_method_name) + elif not self._model_context.is_remote() and not self._model_context.skip_archive(): log_method('WLSDPLY-05025', attribute_name, model_folder_path, path, class_name=_class_name, method_name=_method_name) diff --git a/core/src/main/python/wlsdeploy/util/cla_helper.py b/core/src/main/python/wlsdeploy/util/cla_helper.py index 3af184fcb..183e860db 100644 --- a/core/src/main/python/wlsdeploy/util/cla_helper.py +++ b/core/src/main/python/wlsdeploy/util/cla_helper.py @@ -31,6 +31,7 @@ from wlsdeploy.util.cla_utils import CommandLineArgUtil from wlsdeploy.util.exit_code import ExitCode from wlsdeploy.util.model_translator import FileToPython +from wlsdeploy.exception.exception_helper import create_cla_exception __logger = PlatformLogger('wlsdeploy.util') @@ -121,6 +122,16 @@ def validate_variable_file_exists(program_name, argument_map): argument_map[CommandLineArgUtil.VARIABLE_FILE_SWITCH] = ",".join(result_files) +def validate_if_domain_home_required(program_name, argument_map): + method_name = 'validate_if_remote_options' + if CommandLineArgUtil.REMOTE_SWITCH not in argument_map and \ + CommandLineArgUtil.DOMAIN_HOME_SWITCH not in argument_map: + ex = create_cla_exception(ExitCode.USAGE_ERROR, 'WLSDPLY-20005', + program_name, CommandLineArgUtil.DOMAIN_HOME_SWITCH) + __logger.throwing(ex, class_name=_class_name, method_name=method_name) + raise ex + + def process_encryption_args(optional_arg_map): """ If the user is using model encryption, get the passphrase from stdin, and put it in the argument map. diff --git a/core/src/main/python/wlsdeploy/util/cla_utils.py b/core/src/main/python/wlsdeploy/util/cla_utils.py index ca11b9c60..8e1d043e3 100644 --- a/core/src/main/python/wlsdeploy/util/cla_utils.py +++ b/core/src/main/python/wlsdeploy/util/cla_utils.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2017, 2022, Oracle Corporation and/or its affiliates. +Copyright (c) 2017, 2023, Oracle Corporation and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. Module that handles command-line argument parsing and common validation. @@ -176,6 +176,9 @@ def process_args(self, args, tool_type=TOOL_TYPE_DEFAULT, trailing_arg_count=0): args = self._check_trailing_arguments(args, trailing_arg_count) args_len = len(args) + is_remote = False + if CommandLineArgUtil.REMOTE_SWITCH in args: + is_remote = True idx = 1 while idx < args_len: @@ -201,7 +204,10 @@ def process_args(self, args, tool_type=TOOL_TYPE_DEFAULT, trailing_arg_count=0): elif tool_type == TOOL_TYPE_DISCOVER: full_path = value else: - full_path = validate_domain_home_arg(value) + if is_remote: + full_path = value + else: + full_path = validate_domain_home_arg(value) self._add_arg(key, full_path, True) elif self.is_domain_parent_key(key): value, idx = self._get_arg_value(args, idx) diff --git a/core/src/main/python/wlsdeploy/util/model_context.py b/core/src/main/python/wlsdeploy/util/model_context.py index 5cf4fc0fb..48ca1e2bc 100644 --- a/core/src/main/python/wlsdeploy/util/model_context.py +++ b/core/src/main/python/wlsdeploy/util/model_context.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2017, 2022, Oracle Corporation and/or its affiliates. +Copyright (c) 2017, 2023, Oracle Corporation and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. """ @@ -405,6 +405,13 @@ def get_domain_name(self): """ return self._domain_name + def set_domain_name(self, domain_name): + """ + Set the domain name when online + :param domain_name: the domain name + """ + self._domain_name = domain_name + def set_domain_home(self, domain_home): """ This method is a hack to allow create to add the domain home after reading the domain name from the model. @@ -415,6 +422,11 @@ def set_domain_home(self, domain_home): self._domain_home = domain_home self._domain_name = os.path.basename(self._domain_home) + def set_domain_home_name_if_remote(self, domain_home, domain_name): + if self.is_remote(): + self.set_domain_home(domain_home) + self.set_domain_name(domain_name) + def get_domain_parent_dir(self): """ Get the domain parent directory diff --git a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties index f74f89e42..5405578ce 100644 --- a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties +++ b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties @@ -1182,6 +1182,8 @@ WLSDPLY-09338=Removing {0} from model deployment because the running application the targets in the model. WLSDPLY-09339=Removing {0} from model deployment because the running application's has no target and \ also no targets in the model. +WLSDPLY-09340=Cannot create temporary directory for uploading applications for remote deployment; {0} +WLSDPLY-09341=Cannot deploy application {0}, SourcePath {1} with '-remote' option because it is in exploded format # wlsdeploy/tool/deploy/common_resources_deployer.py WLSDPLY-09400=ResourceGroup was specified in the test file but are not supported in WebLogic Server version {0} @@ -1586,6 +1588,8 @@ WLSDPLY-19309=Unable to extract from domain bin {0} from archive file {1}: {2} WLSDPLY-19310=Unable to extract user custom files from archive file {0} to domain directory {1}: {2} WLSDPLY-19311=Unable to remove domain bin scripts from archive file{0}: {1} WLSDPLY-19312=Unable to copy file {0} to {1}: {2} +WLSDPLY-19313=Attribute {0} in model location {1} references path {2} specified in the model is not suitable for \ + remote domain update, the path cannot be deployed remotely. # wlsdeploy/tool/util/topology_helper.py WLSDPLY-19400=Creating placeholder for server template {0} diff --git a/core/src/test/python/validation_test.py b/core/src/test/python/validation_test.py index 678f651da..af0a293d8 100644 --- a/core/src/test/python/validation_test.py +++ b/core/src/test/python/validation_test.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2017, 2022, Oracle Corporation and/or its affiliates. +Copyright (c) 2017, 2023, Oracle Corporation and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. """ import unittest @@ -151,6 +151,52 @@ def testYamlModelValidation(self): self.assertNotEqual(return_code, Validator.ReturnCode.STOP) + def testYamlModelValidationWithRemoteOption(self): + """ + Parse and validate a YAML model with '-remote' option, should fail with path error. + """ + + _model_file = self._resources_dir + '/simple-model2.yaml' + _archive_file = self._resources_dir + "/SingleAppDomain.zip" + _method_name = 'testYamlModelValidation' + + mw_home = os.environ['MW_HOME'] + args_map = { + '-oracle_home': mw_home, + '-model_file': _model_file, + '-archive_file': _archive_file + } + + model_context = ModelContext('ValidationTestCase', args_map) + aliases = Aliases(model_context, wls_version=self._wls_version) + model_context._remote = True + try: + model_dictionary = FileToPython(model_context.get_model_file()).parse() + model_validator = Validator(model_context, aliases, wlst_mode=WlstModes.ONLINE) + return_code = model_validator.validate_in_tool_mode(model_dictionary, + model_context.get_variable_file(), + model_context.get_archive_file_name()) + + summary_handler = WLSDeployLogEndHandler.getSummaryHandler() + self.assertNotEqual(summary_handler, None, "Summary Handler is None") + self.assertEqual(summary_handler.getMaximumMessageLevel(), Level.SEVERE, "No SEVERE messages found") + # 2 messages complaining about the path of these + # domainBin: [ 'wlsdeploy/domainBin/setUserOverrides.sh' ] + # domainLibraries: [ 'wlsdeploy/domainLibraries/fake.jar' ] + self.assertEqual(summary_handler.getMessageCount(Level.SEVERE), 2, "Number of SEVERE messages do not match") + self._logger.info('The Validator.validate_in_tool_mode() call returned {0}', + Validator.ReturnCode.from_value(return_code), + class_name=self._class_name, method_name=_method_name) + except TranslateException, te: + return_code = Validator.ReturnCode.STOP + self._logger.severe('WLSDPLY-20009', + self._program_name, + model_context.get_model_file(), + te.getLocalizedMessage(), error=te, + class_name=self._class_name, method_name=_method_name) + + self.assertEqual(return_code, Validator.ReturnCode.STOP) + def testWLSRolesValidation(self): """ Run the validation portion of the WLSRoles helper and check for expected results. diff --git a/core/src/test/resources/SingleAppDomain.zip b/core/src/test/resources/SingleAppDomain.zip index 0214cb1a6..0f603b0d0 100644 Binary files a/core/src/test/resources/SingleAppDomain.zip and b/core/src/test/resources/SingleAppDomain.zip differ diff --git a/core/src/test/resources/simple-model2.yaml b/core/src/test/resources/simple-model2.yaml new file mode 100644 index 000000000..cd2c7fc4c --- /dev/null +++ b/core/src/test/resources/simple-model2.yaml @@ -0,0 +1,105 @@ +# Copyright (c) 2023, Oracle Corporation and/or its affiliates. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + +domainInfo: + # The DOMAIN_TYPE field is for reference only. The actual type of domain created is controlled by + # the -domain_type parameter passed to the createDomain shell script. + AdminUserName: 'weblogic' + AdminPassword: 'welcome1' + ServerStartMode: 'prod' + domainBin: [ 'wlsdeploy/domainBin/setUserOverrides.sh' ] + domainLibraries: [ 'wlsdeploy/domainLibraries/fake.jar' ] + + +topology: + Name: simple_domain + Cluster: + mycluster: + MulticastTTL: -1 + Server: + AdminServer: + ListenAddress: 127.0.0.1 + ListenPort: 7001 + s1: + ListenAddress: 127.0.0.1 + ListenPort: 8001 + Cluster: mycluster + s2: + ListenAddress: 127.0.0.1 + ListenPort: 8101 + Cluster: mycluster +resources: + JDBCSystemResource: + Generic1: + # This is just a test sample to validate lists of value processing + Target: + - mycluster + - AdminServer + JdbcResource: + JDBCDataSourceParams: + JNDIName: [ jdbc/generic1, jdbc/special1 ] + GlobalTransactionsProtocol: TwoPhaseCommit + JDBCDriverParams: + DriverName: oracle.jdbc.xa.client.OracleXADataSource + URL: 'jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=slc05til.us.oracle.com)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=orcl.us.oracle.com)))' + PasswordEncrypted: welcome1 + Properties: + user: + Value: jshum + oracle.net.CONNECT_TIMEOUT: + Value: '5000' + oracle.jdbc.ReadTimeout: + Value: '30000' + oracle.net.ssl_version: + # this float should convert to string + Value: 1.2 + JDBCConnectionPoolParams: + InitialCapacity: 3 + MaxCapacity: 15 + TestTableName: SQL ISVALID + TestConnectionsOnReserve: true + Generic2: + Target: mycluster + JdbcResource: + JDBCDataSourceParams: + JNDIName: [ + jdbc/generic2, + jdbc/special2 + ] + GlobalTransactionsProtocol: TwoPhaseCommit + JDBCDriverParams: + DriverName: oracle.jdbc.xa.client.OracleXADataSource + URL : 'jdbc:oracle:thin:@//den00chv.us.oracle.com:1521/PDBORCL' + PasswordEncrypted: welcome1 + Properties: + user: + Value: jshum + oracle.net.CONNECT_TIMEOUT: + Value: '5000' + oracle.jdbc.ReadTimeout: + Value: '30000' + oracle.net.ssl_version: + # this float string should convert to string + Value: '1.2' + JDBCConnectionPoolParams: + InitialCapacity: 3 + MaxCapacity: 15 # This is a comment + TestTableName: SQL ISVALID # This is a comment + TestConnectionsOnReserve: true # This is a comment + +# This is a comment +appDeployments: + Application: + # Quote needed because of hyphen in string + 'get-listen-address-app': + SourcePath: 'wlsdeploy/applications/get-listen-address-app.war' + Target: mycluster + ModuleType: war + StagingMode: nostage + PlanStagingMode: nostage + simpleear : + SourcePath: wlsdeploy/applications/simpleear.ear + Target: mycluster + ModuleType: ear + StagingMode: nostage + PlanStagingMode : nostage diff --git a/installer/src/main/bin/deployApps.cmd b/installer/src/main/bin/deployApps.cmd index e78395aa7..724a29179 100644 --- a/installer/src/main/bin/deployApps.cmd +++ b/installer/src/main/bin/deployApps.cmd @@ -71,7 +71,7 @@ if "%SHOW_USAGE%" == "false" ( ECHO. ECHO Usage: %SCRIPT_NAME% [-help] [-use_encryption] ECHO [-oracle_home ^] -ECHO -domain_home ^ +ECHO [-domain_home ^] ECHO -model_file ^ ECHO [-archive_file ^] ECHO [-variable_file ^] @@ -86,6 +86,7 @@ ECHO [-output_dir ^] ECHO [-admin_url ^ ECHO -admin_user ^ ECHO -admin_pass_env ^ ^| -admin_pass_file ^ +ECHO [-remote] ECHO ] ECHO. ECHO where: @@ -94,7 +95,7 @@ ECHO This argument is required unless the ORACLE_HOME ECHO environment variable is set. ECHO. ECHO domain_home - the domain home directory. This argument is -ECHO required. +ECHO required if -remote option is not specified. ECHO. ECHO model_file - the location of the model file to use. This can also ECHO be specified as a comma-separated list of model diff --git a/installer/src/main/bin/deployApps.sh b/installer/src/main/bin/deployApps.sh index d4053e868..d67e4e76b 100644 --- a/installer/src/main/bin/deployApps.sh +++ b/installer/src/main/bin/deployApps.sh @@ -32,7 +32,7 @@ usage() { echo "" echo "Usage: $1 [-help] [-use_encryption]" echo " [-oracle_home ]" - echo " -domain_home " + echo " [-domain_home ]" echo " -model_file " echo " [-archive_file ]" echo " [-variable_file ]" @@ -47,6 +47,7 @@ usage() { echo " [-admin_url " echo " -admin_user " echo " -admin_pass_env | -admin_pass_file " + echo " [-remote]" echo " ]" echo "" echo " where:" @@ -55,7 +56,7 @@ usage() { echo " environment variable is set." echo "" echo " domain_home - the domain home directory. This argument is" - echo " required." + echo " required if -remote option is not specified" echo "" echo " model_file - the location of the model file to use. This can also" echo " be specified as a comma-separated list of model" diff --git a/installer/src/main/bin/discoverDomain.cmd b/installer/src/main/bin/discoverDomain.cmd index 2d4be15a1..3f2b1704c 100644 --- a/installer/src/main/bin/discoverDomain.cmd +++ b/installer/src/main/bin/discoverDomain.cmd @@ -71,7 +71,7 @@ if "%SHOW_USAGE%" == "false" ( :usage ECHO. ECHO Usage: %SCRIPT_NAME% [-oracle_home ^] -ECHO -domain_home ^ +ECHO [-domain_home ^] ECHO -model_file ^ ECHO ^<-archive_file ^ ^| -skip_archive ^| -remote ^> ECHO [-variable_file ^] @@ -91,7 +91,8 @@ ECHO oracle_home - the existing Oracle Home directory for the domain ECHO This argument is required unless the ORACLE_HOME ECHO environment variable is set. ECHO. -ECHO domain_home - the domain home directory. This argument is required. +ECHO domain_home - the domain home directory. This argument is +ECHO required if -remote option is not specified. ECHO. ECHO model_file - the location to write the model file. This argument ECHO is required. diff --git a/installer/src/main/bin/discoverDomain.sh b/installer/src/main/bin/discoverDomain.sh index 0a2867a73..20cf50c34 100644 --- a/installer/src/main/bin/discoverDomain.sh +++ b/installer/src/main/bin/discoverDomain.sh @@ -34,7 +34,7 @@ usage() { echo "" echo "Usage: $1 [-help]" echo " [-oracle_home ]" - echo " -domain_home " + echo " [-domain_home ]" echo " -model_file " echo " <-archive_file | -skip_archive | -remote>" echo " [-variable_file ]" @@ -54,7 +54,8 @@ usage() { echo " This argument is required unless the ORACLE_HOME" echo " environment variable is set." echo "" - echo " domain_home - the domain home directory. This argument is required." + echo " domain_home - the domain home directory. This argument is" + echo " required if -remote option is not specified" echo "" echo " model_file - the location of the model file to use. This argument" echo " is required." diff --git a/installer/src/main/bin/updateDomain.cmd b/installer/src/main/bin/updateDomain.cmd index 394f76698..d3ce3e8d4 100644 --- a/installer/src/main/bin/updateDomain.cmd +++ b/installer/src/main/bin/updateDomain.cmd @@ -71,7 +71,7 @@ if "%SHOW_USAGE%" == "false" ( ECHO. ECHO Usage: %SCRIPT_NAME% [-help] [-use_encryption] ECHO [-oracle_home ^] -ECHO -domain_home ^ +ECHO [-domain_home ^] ECHO -model_file ^ ECHO [-archive_file ^] ECHO [-variable_file ^] @@ -85,6 +85,7 @@ ECHO [-output_dir ^] ECHO [-admin_url ^ ECHO -admin_user ^ ECHO -admin_pass_env ^ ^| -admin_pass_file ^ +ECHO [-remote] ECHO ] ECHO. ECHO where: @@ -93,7 +94,7 @@ ECHO This argument is required unless the ORACLE_HOME ECHO environment variable is set. ECHO. ECHO domain_home - the domain home directory. This argument is -ECHO required. +ECHO required if -remote option is not specified. ECHO. ECHO model_file - the location of the model file to use. This can also ECHO be specified as a comma-separated list of model diff --git a/installer/src/main/bin/updateDomain.sh b/installer/src/main/bin/updateDomain.sh index 42955d5c0..7627fcb26 100644 --- a/installer/src/main/bin/updateDomain.sh +++ b/installer/src/main/bin/updateDomain.sh @@ -32,7 +32,7 @@ usage() { echo "" echo "Usage: $1 [-help] [-use_encryption]" echo " [-oracle_home ]" - echo " -domain_home " + echo " [-domain_home ]" echo " -model_file " echo " [-archive_file ]" echo " [-variable_file ]" @@ -47,6 +47,7 @@ usage() { echo " [-admin_url " echo " -admin_user " echo " -admin_pass_env | -admin_pass_file " + echo " [-remote]" echo " ]" echo "" echo " where:" @@ -55,7 +56,7 @@ usage() { echo " environment variable is set." echo "" echo " domain_home - the domain home directory. This argument is" - echo " required." + echo " required if -remote option is not specified" echo "" echo " model_file - the location of the model file to use. This can also" echo " be specified as a comma-separated list of model" diff --git a/integration-tests/system-test/src/test/java/oracle/weblogic/deploy/integration/ITWdt.java b/integration-tests/system-test/src/test/java/oracle/weblogic/deploy/integration/ITWdt.java index 65477bf18..ca028b4c1 100644 --- a/integration-tests/system-test/src/test/java/oracle/weblogic/deploy/integration/ITWdt.java +++ b/integration-tests/system-test/src/test/java/oracle/weblogic/deploy/integration/ITWdt.java @@ -19,6 +19,8 @@ import java.util.List; import java.util.Map; import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import oracle.weblogic.deploy.integration.annotations.IntegrationTest; import oracle.weblogic.deploy.integration.annotations.TestingLogger; @@ -965,6 +967,34 @@ void test30OnlineUpdateApp(TestInfo testInfo) throws Exception { assertTrue(result.stdout().contains("<__start_app> "), "Update does not contains expected message WLSDPLY-09313"); + cmd = "echo welcome1 | " + + updateDomainScript + + " -oracle_home " + mwhome_12213 + + " -domain_home " + domainParentDir + FS + domainDir + + " -model_file " + model + + " -remote" + + " -archive_file " + getUpdatedSampleArchiveFile() + + " -admin_url t3://localhost:7001 -admin_user weblogic"; + result = Runner.run(cmd, getTestMethodEnvironment(testInfo), out); + + assertEquals(0, result.exitValue(), "Unexpected return code for remote updating domain with new archive"); + + Path sourcePyfile = Paths.get(getResourcePath() + FS + SAMPLE_MODEL_FILE_PREFIX + "-chk-srcpath.py"); + Path testPyFile = getTestOutputPath(testInfo).resolve(SAMPLE_MODEL_FILE_PREFIX + "-chk-srcpath.py"); + Files.copy(sourcePyfile, testPyFile, StandardCopyOption.REPLACE_EXISTING); + cmd = mwhome_12213 + "/oracle_common/common/bin/wlst.sh " + testPyFile + " " + domainParentDir + FS + + domainDir; + result = Runner.run(cmd, getTestMethodEnvironment(testInfo), out); + assertEquals(0, result.exitValue(), "Unexpected return code for running wlst to find app sourcepath"); + Pattern pattern = Pattern.compile("SRCPATH=(.*)"); + Matcher matcher = pattern.matcher(result.stdout()); + String srcPath = "Unknown"; + if (matcher.find()) { + srcPath = matcher.group(1); + } + assertTrue(srcPath.equals("servers/admin-server/upload/simple-app/app/simple-app.war"), + "App SourcePath returned " + srcPath + " does not match the expected value"); + stopAdminServer(domainHome); } } else { diff --git a/integration-tests/system-test/src/test/resources/simple-topology-chk-srcpath.py b/integration-tests/system-test/src/test/resources/simple-topology-chk-srcpath.py new file mode 100644 index 000000000..c340f0e90 --- /dev/null +++ b/integration-tests/system-test/src/test/resources/simple-topology-chk-srcpath.py @@ -0,0 +1,9 @@ +""" +Copyright (c) 2022, Oracle Corporation and/or its affiliates. +Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. +""" +import sys +readDomain(sys.argv[1]) +cd('AppDeployment/simple-app') +print('SRCPATH=' + get('SourcePath')) +exit()