Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
bf23126
add support of model diff tool
Apr 10, 2020
8eefe36
Merge branch 'master' into model_diff
Apr 10, 2020
a9b50f1
update parameter
Apr 10, 2020
1cda1de
Fix various delete problem
Apr 10, 2020
9bf66f0
add message properties and command file for windows
Apr 13, 2020
1c4b54f
update exception
Apr 13, 2020
15db52b
add topology section
Apr 13, 2020
a720e77
Merge branch 'master' into model_diff
Apr 13, 2020
5c84886
merge from master
Apr 13, 2020
9d7ab02
grab from master
Apr 13, 2020
009d666
fix script name
Apr 13, 2020
767398b
Fix command line parameter
Apr 13, 2020
356b197
Fix merging problems
Apr 13, 2020
586e03f
correct spellings
Apr 13, 2020
a86b642
Experiment to use alias tree to figure out folder or attribute
Apr 14, 2020
96364f0
add validation
Apr 14, 2020
6c5751c
add message for validation
Apr 14, 2020
fe911e6
Use alias methods to check for folder or attributes
Apr 14, 2020
a383a5c
use for loop to prevent infinite loop
Apr 14, 2020
1903478
correct logic
Apr 14, 2020
e549d31
update method and add CompareException
Apr 14, 2020
e5b36ed
copyrights update
Apr 14, 2020
98a42fd
change wordings
Apr 14, 2020
81bf16a
removed operator specific logic
Apr 15, 2020
7ed9eeb
Add documentations
Apr 15, 2020
f412d72
Fix file writing issues
Apr 15, 2020
8574498
Fix file writing for results
Apr 15, 2020
a76b31b
remove unused var
Apr 15, 2020
7f39a51
add support of variable substitution
Apr 15, 2020
4e60c98
update doc
Apr 15, 2020
8749ba6
fix script error
Apr 16, 2020
402487f
update wordings and script
Apr 16, 2020
088c208
handle deleting top level tree
Apr 16, 2020
63eac89
fix code error
Apr 16, 2020
5ba6071
Add unit test for model diff
Apr 20, 2020
3b51492
Add parsing to catch error
Apr 21, 2020
d38ad40
Add translate error check
Apr 21, 2020
40c4e47
Add more tests for model_diff
Apr 21, 2020
22f25db
Add CreateException
Apr 21, 2020
15d27a1
minor refactor
Apr 21, 2020
fe0584a
update exception handling
Apr 21, 2020
d68eee5
update exception in test
Apr 21, 2020
49f1521
change to use true or false for dictionary check
Apr 22, 2020
c99fd03
update doc
Apr 22, 2020
7d285ad
rename model_diff to compare_model
Apr 22, 2020
9fd4957
renamed file and update test
Apr 22, 2020
9c15a87
change test to use new temporary directory each time
Apr 22, 2020
b68e3dd
update unit test
Apr 22, 2020
e87e991
doc updates
Apr 22, 2020
5087ee8
doc edit
Apr 22, 2020
8fd738c
adding messages for identical model
Apr 22, 2020
ed093a1
doc update
Apr 22, 2020
860ec84
doc update
Apr 22, 2020
41e4f9d
Merge branch 'master' into model_diff
ddsharpe Apr 22, 2020
1020256
Merge branch 'master' into model_diff
ddsharpe Apr 22, 2020
7fb4eea
Merge branch 'master' into model_diff
ddsharpe Apr 22, 2020
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix various delete problem
  • Loading branch information
Johnny Shum committed Apr 10, 2020
commit 1cda1de072a3cdd106cb365d09f6cd61b2ff9726
221 changes: 180 additions & 41 deletions core/src/main/python/model_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
from java.lang import System
from wlsdeploy.util.model_translator import FileToPython
#from wlsdeploy.yaml.yaml_translator import PythonToYaml
from oracle.weblogic.deploy.util import CLAException
from wlsdeploy.logging.platform_logger import PlatformLogger
from wlsdeploy.tool.util import model_context_helper
from wlsdeploy.util import cla_helper
from wlsdeploy.util.cla_utils import CommandLineArgUtil

UNSAFE_ONLINE_UPDATE=0
SAFE_ONLINE_UPDATE=1
Expand All @@ -26,6 +31,38 @@
SECURITY_INFO_UPDATED=4
RCU_PASSWORD_CHANGED=5

_program_name = 'compareModel'
_class_name = 'model_diff'
__logger = PlatformLogger('wlsdeploy.model_diff')

__required_arguments = [
CommandLineArgUtil.ORACLE_HOME_SWITCH
]

__optional_arguments = [
CommandLineArgUtil.COMPARE_MODEL_OUTPUT_DIR_SWITCH
]

def __process_args(args):
"""
Process the command-line arguments.
:param args: the command-line arguments list
:raises CLAException: if an error occurs while validating and processing the command-line arguments
"""
_method_name = '__process_args'

cla_util = CommandLineArgUtil(_program_name, __required_arguments, __optional_arguments)
required_arg_map, optional_arg_map = cla_util.process_args(args, trailing_arg_count=2)

cla_helper.verify_required_args_present(_program_name, __required_arguments, required_arg_map)

combined_arg_map = optional_arg_map.copy()
combined_arg_map.update(required_arg_map)

return model_context_helper.create_context(_program_name, combined_arg_map)



# The following class is borrowed directly from the WDT project's yaml_tranlator.py
class PythonToYaml:
"""
Expand Down Expand Up @@ -116,10 +153,12 @@ def __init__(self, current_dict, past_dict):
self.past_dict = past_dict
self.set_current = sets.Set()
self.set_past = sets.Set()
for item in self.current_dict.keys():
self.set_current.add(item)
for item in self.past_dict.keys():
self.set_past.add(item)
if self.current_dict and len(self.current_dict.keys()) > 0:
for item in self.current_dict.keys():
self.set_current.add(item)
if self.past_dict and len(self.past_dict.keys()) > 0:
for item in self.past_dict.keys():
self.set_past.add(item)
self.intersect = self.set_current.intersection(self.set_past)

def added(self):
Expand Down Expand Up @@ -149,6 +188,7 @@ def print_diff(self,s, category):

def recursive_changed_detail(self, key, token, root):
debug("DEBUG: Entering recursive_changed_detail key=%s token=%s root=%s", key, token, root)

a=ModelDiffer(self.current_dict[key], self.past_dict[key])
diff=a.changed()
added=a.added()
Expand Down Expand Up @@ -214,6 +254,7 @@ def calculate_changed_model(self):
added = self.added()
removed = self.removed()

#
# Call recursive for each key
#
for s in changed:
Expand All @@ -231,20 +272,68 @@ def calculate_changed_model(self):
self._add_results(all_added)
# Should not have delete

# Top level ? delete all resources, all appDeployments?
# Clean up previous delete first
for x in all_removed:
all_removed.remove(x)

# Top level: delete all resources, all appDeployments

for s in removed:
token = s
self.recursive_changed_detail(s,token, s)
self._add_results(all_removed, True)

def _add_results(self, ar_changes, is_delete=False):
"""
Update the final diffed dictionary with the changes
Update the differences in the final model dictionary with the changes
:param ar_changes: Array of changes in delimited format
"""
# The ar_changes is the keys of changes in the piped format
# 'resources|JDBCSystemResource|Generic2|JdbcResource|JDBCConnectionPoolParams|TestConnectionsOnReserve
#
# Now change it to python dictionrary

allowable_deletes = [ 'appDeployments|Application' ,
'appDeployments|Library',
'resources|CoherenceClusterSystemResource',
'resources|FileStore',
'resources|ForeignJNDIProvider',
'resources|JDBCStore',
'resources|JDBCSystemResource',
'resources|JMSBridgeDestination',
'resources|JMSServer',
'resources|JMSSystemResource',
'resources|JoltConnectionPool',
'resources|MailSession',
'resources|MessagingBridge',
'resources|ODLConfiguration',
'resources|Partition',
'resources|PartitionWorkManager',
'resources|PathService',
'resources|ResourceGroup',
'resources|ResourceGroupTemplate',
'resources|ResourceManagement',
'resources|SAFAgent',
'resources|SelfTuning',
'resources|ShutdownClass',
'resources|SingletonService',
'resources|StartupClass',
'resources|WLDFSystemResource',
'resources|WebAppContainer',
'resources|WTCServer' ]

for item in ar_changes:
print 'DEBUG: item is ' + item
found_in_allowable_delete = False
if is_delete:
print 'DEBUG: ' + item
for allowable_delete in allowable_deletes:
if item.startswith(allowable_delete):
found_in_allowable_delete = True
if not found_in_allowable_delete:
compare_warnings.add('INFO: Model Path: ' + str(item)
+ ' does not exist in current model but exists in previous model')
continue

splitted=item.split('|',1)
n=len(splitted)
result=dict()
Expand Down Expand Up @@ -273,43 +362,51 @@ def _add_results(self, ar_changes, is_delete=False):
for k in walked:
leaf = leaf[k]
value_tree=value_tree[k]

#
# walk the current dictionary and set the value
# doesn't work in delete case
#
leaf[splitted[0]] = value_tree[splitted[0]]
if value_tree:
leaf[splitted[0]] = value_tree[splitted[0]]
else:
leaf[splitted[0]] = None

self.merge_dictionaries(self.final_changed_model, result)

allowable_deletes = [ 'appDeployments|Application' ,
'appDeployments|Library',
'resources|JDBCSystemResource',
'resources|JMSSystemResource',
'resources|JMSServer' ]
# if it is a deletion then go back and update with '!'

if is_delete:
found_in_allowable_delete = False
print 'DELETING ' + item
for allowable_delete in allowable_deletes:
if item.startswith(allowable_delete):
found_in_allowable_delete = True
split_delete = item.split('|')
allowable_delete_length = len(allowable_delete.split('|'))
split_delete_length = len(split_delete)
debug("DEBUG: deleting %s from the model ", item)

if split_delete_length == allowable_delete_length + 1:
app_key = split_delete[split_delete_length - 1]
debug("DEBUG: deleting %s from the model ", item)
pointer_dict = self.final_changed_model
for k_item in allowable_delete.split('|'):
pointer_dict = pointer_dict[k_item]
del pointer_dict[app_key]
pointer_dict['!' + app_key] = dict()
else:
print 'WARNING: Cannot delete attribute: ' + str(item) + ' will not reflected in differences'

if not found_in_allowable_delete:
print 'WARNING: Cannot delete attribute: ' + str(item) + ' will not reflected in differences'



# Deleting attributes
pointer_dict = self.final_changed_model
split_delete = item.split('|')
app_key = split_delete[-1]
parent_key = split_delete[-2]
for k_item in split_delete:
if k_item == parent_key:
break
pointer_dict = pointer_dict[k_item]
del pointer_dict[parent_key][app_key]
# Deleting entire tree
if split_delete_length == allowable_delete_length:
pointer_dict[parent_key][ '!' + app_key] = dict()
else:
compare_warnings.add('INFO: Model Path: ' + str(item)
+ ' does not exist in current model but exists in previous model')

def merge_dictionaries(self, dictionary, new_dictionary):
"""
Expand Down Expand Up @@ -444,9 +541,10 @@ class ModelFileDiffer:
"""
This is the main driver for the caller. It compares two model files whether they are json or yaml format.
"""
def __init__(self, current_dict, past_dict):
def __init__(self, current_dict, past_dict, output_dir=None):
self.current_dict_file = current_dict
self.past_dict_file = past_dict
self.output_dir = output_dir

def get_dictionary(self, file):
"""
Expand Down Expand Up @@ -549,14 +647,18 @@ def compare(self):
obj = ModelDiffer(current_dict, past_dict)
obj.calculate_changed_model()
net_diff = obj.get_final_changed_model()
fh = open('/tmp/diffed_model.json', 'w')
self.write_dictionary_to_json_file(net_diff, fh)
#print all_added
fh.close()
fh = open('/tmp/diffed_model.yaml', 'w')
pty = PythonToYaml()
pty._write_dictionary_to_yaml_file(net_diff, fh)
fh.close()
if self.output_dir:
fh = open(self.output_dir + '/diffed_model.json', 'w')
self.write_dictionary_to_json_file(net_diff, fh)
fh.close()
fh = open(self.output_dir + '/diffed_model.yaml', 'w')
pty = PythonToYaml()
pty._write_dictionary_to_yaml_file(net_diff, fh)
fh.close()
else:
pty = PythonToYaml()
pty._write_dictionary_to_yaml_file(net_diff, sys.stdout)

return obj.is_safe_diff(net_diff)

def debug(format_string, *arguments):
Expand All @@ -565,19 +667,55 @@ def debug(format_string, *arguments):
:param format_string: python formatted string
:param arguments:
"""
if os.environ.has_key('DEBUG_INTROSPECT_JOB'):
if os.environ.has_key('DEBUG_COMPARE_MODEL_TOOL'):
print format_string % (arguments)

def main():
"""
The main entry point for the discoverDomain tool.
:param args: the command-line arguments
"""
_method_name = 'main'

__logger.entering(class_name=_class_name, method_name=_method_name)
for index, arg in enumerate(sys.argv):
__logger.finer('sys.argv[{0}] = {1}', str(index), str(arg), class_name=_class_name, method_name=_method_name)

_outputdir = None

try:
obj = ModelFileDiffer(sys.argv[3], sys.argv[4])
rc=obj.compare()
rcfh = open('/tmp/model_diff_rc', 'w')
rcfh.write(",".join(map(str,changed_items)))
rcfh.close()
System.exit(0)
model_context = __process_args(sys.argv)
_outputdir = model_context.get_compare_model_output_dir()
except CLAException, ex:
exit_code = ex.getExitCode()
if exit_code != CommandLineArgUtil.HELP_EXIT_CODE:
__logger.severe('WLSDPLY-20008', _program_name, ex.getLocalizedMessage(), error=ex,
class_name=_class_name, method_name=_method_name)
cla_helper.clean_up_temp_files()
sys.exit(exit_code)

try:
model1 = model_context.get_trailing_argument(0)
model2 = model_context.get_trailing_argument(1)
obj = ModelFileDiffer(model1, model2, _outputdir)
obj.compare()
if _outputdir:
rcfh = open(_outputdir + '/model_diff_rc', 'w')
rcfh.write(",".join(map(str,changed_items)))
rcfh.close()
if len(compare_warnings) > 0:
rcfh = open(_outputdir + '/model_diff_stdout', 'w')
for line in compare_warnings:
rcfh.write(line.replace('|', "-->"))
rcfh.close()
else:
if len(compare_warnings) > 0:
print ""
print ""
for line in compare_warnings:
print line.replace('|', "-->")

System.exit(0)
except:
exc_type, exc_obj, exc_tb = sys.exc_info()
eeString = traceback.format_exception(exc_type, exc_obj, exc_tb)
Expand All @@ -589,6 +727,7 @@ def main():
all_added = []
all_removed = []
changed_items = []
compare_warnings = sets.Set()
main()


8 changes: 4 additions & 4 deletions core/src/main/python/wlsdeploy/util/cla_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ class CommandLineArgUtil(object):
# For compare models tool

COMPARE_MODEL_OUTPUT_DIR_SWITCH = "-compare_models_output_dir"
SILENT_SWITCH = '-silent'

# arguments that are true if specified, false if not
BOOLEAN_SWITCHES = [
Expand Down Expand Up @@ -292,6 +291,10 @@ def process_args(self, args, tool_type=TOOL_TYPE_DEFAULT, trailing_arg_count=0):
self._add_arg(key, full_path, True)
elif self.is_boolean_switch(key):
self._add_arg(key, True)
elif self.is_compare_model_output_dir_switch(key):
value, idx = self._get_arg_value(args, idx, key)
full_path = self._validate_compare_model_output_dir_arg(value)
self._add_arg(key, full_path, True)
else:
ex = exception_helper.create_cla_exception('WLSDPLY-01601', self._program_name, key)
ex.setExitCode(self.USAGE_ERROR_EXIT_CODE)
Expand Down Expand Up @@ -978,9 +981,6 @@ def is_rollback_if_restart_required_key(self, key):
def is_compare_model_output_dir_switch(self, key):
return self.COMPARE_MODEL_OUTPUT_DIR_SWITCH == key

def is_silent_switch(self, key):
return self.SILENT_SWITCH == key

def _validate_compare_model_output_dir_arg(self, value):
method_name = '_validate_compare_model_output_dir_arg'
try:
Expand Down
11 changes: 11 additions & 0 deletions core/src/main/python/wlsdeploy/util/model_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def __init__(self, program_name, arg_map):
self._validation_method = None
self._rollback_if_restart_required = None
self._domain_resource_file = None
self._compare_model_output_dir = None
self._trailing_args = []

if CommandLineArgUtil.ORACLE_HOME_SWITCH in arg_map:
Expand Down Expand Up @@ -188,6 +189,9 @@ def __init__(self, program_name, arg_map):
else:
self._wlst_mode = WlstModes.OFFLINE

if CommandLineArgUtil.COMPARE_MODEL_OUTPUT_DIR_SWITCH in arg_map:
self._compare_model_output_dir = arg_map[CommandLineArgUtil.COMPARE_MODEL_OUTPUT_DIR_SWITCH]

if self._wl_version is None:
self._wl_version = self._wls_helper.get_actual_weblogic_version()

Expand Down Expand Up @@ -453,6 +457,13 @@ def is_using_encryption(self):
"""
return self._use_encryption

def get_compare_model_output_dir(self):
"""
Get the compare model output directory
:return: compare model output directory
"""
return self._compare_model_output_dir

def get_target_wls_version(self):
"""
Get the target WebLogic version.
Expand Down
Loading