Skip to content

Commit 7c32434

Browse files
committed
Implement online attribute filter; pass model context for use by internal filters
1 parent 9f31bef commit 7c32434

File tree

5 files changed

+184
-23
lines changed

5 files changed

+184
-23
lines changed

core/src/main/python/validate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def __perform_model_file_validation(model_file_name, model_context):
122122
# substitute variables before filtering
123123
variables.substitute(model_dictionary, variable_map, model_context)
124124
# apply filters to merged model
125-
if filter_helper.apply_filters(model_dictionary, "validate"):
125+
if filter_helper.apply_filters(model_dictionary, "validate", model_context):
126126
# persist model after filtering
127127
cla_helper.persist_model(model_context, model_dictionary)
128128

core/src/main/python/wlsdeploy/tool/util/filter_helper.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,26 @@
2222
}
2323

2424

25-
def apply_filters(model, tool_type, model_context=None):
25+
def apply_filters(model, tool_type, model_context):
2626
"""
2727
Apply any filters configured for the specified tool type to the specified model.
2828
:param model: the model to be filtered
2929
:param tool_type: the name of the filter tool type
30-
:param model_context: optional, used to find target filters
30+
:param model_context: used to find target filters
3131
:return: True if any filter was applied, False otherwise
3232
:raises: BundleAwareException of the specified type: if an error occurs
3333
"""
3434
_method_name = 'apply_filters'
35-
global __filter_file_location
3635

37-
__filter_file_location = path_utils.find_config_path('model_filters.json')
36+
__filter_file_location = None
3837
filter_applied = False
3938

4039
try:
4140
filters_dictionary = {}
4241

4342
# if target specified in model context, use the filters from target config
4443
if model_context and model_context.get_target():
44+
__filter_file_location = model_context.get_target_configuration_file()
4545
filters_dictionary = model_context.get_target_configuration().get_model_filters()
4646
target_path = os.path.join('targets', model_context.get_target())
4747

@@ -53,15 +53,18 @@ def apply_filters(model, tool_type, model_context=None):
5353
filter_path = target_path + filter_path.replace(TARGET_CONFIG_TOKEN, '')
5454
current_filter['path'] = path_utils.find_config_path(filter_path)
5555

56-
elif os.path.isfile(__filter_file_location):
57-
filters_dictionary = FileToPython(__filter_file_location).parse()
5856
else:
59-
__logger.info('WLSDPLY-20017', __filter_file_location, class_name=__class_name, method_name=_method_name)
57+
__filter_file_location = path_utils.find_config_path('model_filters.json')
58+
if os.path.isfile(__filter_file_location):
59+
filters_dictionary = FileToPython(__filter_file_location).parse()
60+
else:
61+
__logger.info('WLSDPLY-20017', __filter_file_location, class_name=__class_name,
62+
method_name=_method_name)
6063

6164
if tool_type in filters_dictionary:
6265
filter_list = filters_dictionary[tool_type]
6366
for filter in filter_list:
64-
filter_applied = _apply_filter(model, filter) or filter_applied
67+
filter_applied = _apply_filter(model, filter, model_context, __filter_file_location) or filter_applied
6568
else:
6669
__logger.info('WLSDPLY-20016', tool_type, __filter_file_location, class_name=__class_name,
6770
method_name=_method_name)
@@ -72,34 +75,39 @@ def apply_filters(model, tool_type, model_context=None):
7275
return filter_applied
7376

7477

75-
def _apply_filter(model, the_filter):
78+
def _apply_filter(model, the_filter, model_context, filter_file_location):
7679
"""
7780
Apply the specified filter to the specified model.
7881
:param model: the model to be filtered
7982
:param the_filter: a dictionary containing the filter parameters
83+
:param model_context: may be used by internal (ID) filters
84+
:param filter_file_location: used for logging
8085
:return: True if the specified filter was applied, False otherwise
8186
:raises: BundleAwareException of the specified type: if an error occurs
8287
"""
8388
_method_name = '_apply_filter'
84-
global __filter_file_location
8589

8690
id = dictionary_utils.get_element(the_filter, 'id')
8791
if id is not None:
88-
return _apply_id_filter(model, id)
92+
__logger.info('WLSDPLY-20034', id, class_name=__class_name, method_name=_method_name)
93+
return _apply_id_filter(model, id, model_context)
8994

9095
path = dictionary_utils.get_element(the_filter, 'path')
9196
if path is not None:
97+
name = dictionary_utils.get_element(the_filter, 'name')
98+
__logger.info('WLSDPLY-20035', name, class_name=__class_name, method_name=_method_name)
9299
return _apply_path_filter(model, path)
93100

94-
__logger.severe('WLSDPLY-20019', str(__filter_file_location), class_name=__class_name, method_name=_method_name)
101+
__logger.severe('WLSDPLY-20019', str(filter_file_location), class_name=__class_name, method_name=_method_name)
95102
return False
96103

97104

98-
def _apply_id_filter(model, id):
105+
def _apply_id_filter(model, id, model_context):
99106
"""
100107
Apply the specified ID filter to the specified model.
101108
:param model: the model to be filtered
102109
:param id: the ID of the filter to be applied
110+
:param model_context: may be used by filters
103111
:return: True if the specified filter was applied, False otherwise
104112
:raises: BundleAwareException of the specified type: if an error occurs
105113
"""
@@ -110,7 +118,7 @@ def _apply_id_filter(model, id):
110118
__logger.severe('WLSDPLY-20020', str(id), class_name=__class_name, method_name=_method_name)
111119
return False
112120
else:
113-
filter_method(model)
121+
filter_method(model, model_context)
114122
return True
115123

116124

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Copyright (c) 2021, Oracle and/or its affiliates.
2+
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
3+
4+
from wlsdeploy.aliases.aliases import Aliases
5+
from wlsdeploy.aliases.location_context import LocationContext
6+
from wlsdeploy.aliases.model_constants import DOMAIN_INFO
7+
from wlsdeploy.aliases.model_constants import RESOURCES
8+
from wlsdeploy.aliases.model_constants import TOPOLOGY
9+
from wlsdeploy.logging.platform_logger import PlatformLogger
10+
11+
_class_name = 'ModelTraverse'
12+
13+
14+
class ModelTraverse:
15+
"""
16+
This class traverses all model folders and attributes.
17+
Sub-classes can override specific methods to avoid re-implementing the recursive traversal.
18+
"""
19+
def __init__(self, model_context, wlst_mode, exception_type):
20+
self._aliases = Aliases(model_context=model_context, wlst_mode=wlst_mode, exception_type=exception_type)
21+
self._logger = PlatformLogger('wlsdeploy.model_traverse')
22+
23+
def traverse_model(self, root_dict):
24+
section_names = [DOMAIN_INFO, TOPOLOGY, RESOURCES]
25+
for section_name in section_names:
26+
self.traverse_section(section_name, root_dict,
27+
self._aliases.get_model_section_top_level_folder_names(section_name))
28+
29+
def traverse_section(self, model_section_key, model_dict, valid_section_folders):
30+
if model_section_key not in model_dict.keys():
31+
return
32+
33+
# only specific top-level sections have attributes
34+
attribute_location = self._aliases.get_model_section_attribute_location(model_section_key)
35+
valid_attr_infos = []
36+
37+
if attribute_location is not None:
38+
valid_attr_infos = self._aliases.get_model_attribute_names_and_types(attribute_location)
39+
40+
model_section_dict = model_dict[model_section_key]
41+
for section_dict_key, section_dict_value in model_section_dict.iteritems():
42+
# section_dict_key is the name of a folder or attribute in the section.
43+
44+
if section_dict_key in valid_attr_infos:
45+
# section_dict_key is the name of an attribute in the section
46+
self.traverse_attribute(model_section_dict, section_dict_key, attribute_location)
47+
48+
elif section_dict_key in valid_section_folders:
49+
# section_dict_key is a folder under the model section
50+
51+
# Append section_dict_key to location context
52+
model_location = LocationContext()
53+
model_location.append_location(section_dict_key)
54+
55+
# Call self.traverse_folder() passing in section_dict_value as the model_node to process
56+
self.traverse_folder(section_dict_value, model_location)
57+
58+
def traverse_folder(self, model_node, model_location):
59+
"""
60+
Traverse a folder that may have named sub-folders (such as Server), artificial named sub-folders (such
61+
as a security provider type), or its own sub-folders and attributes (such as .
62+
"""
63+
64+
# avoid checking folder type if is_artificial_type_folder
65+
is_multiple = not self._aliases.is_artificial_type_folder(model_location) and \
66+
(self._aliases.supports_multiple_mbean_instances(model_location) or
67+
self._aliases.requires_artificial_type_subfolder_handling(model_location))
68+
69+
if is_multiple:
70+
for name in model_node:
71+
expanded_name = name
72+
new_location = LocationContext(model_location)
73+
name_token = self._aliases.get_name_token(new_location)
74+
if name_token is not None:
75+
new_location.add_name_token(name_token, expanded_name)
76+
value_dict = model_node[name]
77+
self.traverse_node(value_dict, new_location)
78+
else:
79+
name_token = self._aliases.get_name_token(model_location)
80+
if name_token is not None:
81+
name = model_location.get_name_for_token(name_token)
82+
if name is None:
83+
name = '%s-0' % name_token
84+
model_location.add_name_token(name_token, name)
85+
self.traverse_node(model_node, model_location)
86+
87+
def traverse_node(self, model_node, model_location):
88+
"""
89+
Traverse a node that contains only attributes, non-named sub-folders, and artificial type folders.
90+
"""
91+
valid_folder_keys = self._aliases.get_model_subfolder_names(model_location)
92+
valid_attr_infos = self._aliases.get_model_attribute_names_and_types(model_location)
93+
94+
for key, value in model_node.iteritems():
95+
if key in valid_folder_keys:
96+
new_location = LocationContext(model_location).append_location(key)
97+
self.traverse_folder(value, new_location)
98+
99+
elif key in valid_attr_infos:
100+
self.traverse_attribute(model_node, key, model_location)
101+
102+
else:
103+
self.unrecognized_field(model_node, key, model_location)
104+
105+
def traverse_attribute(self, model_dict, attribute_name, model_location):
106+
"""
107+
Called for each attribute that is encountered in the model.
108+
"""
109+
pass
110+
111+
def unrecognized_field(self, model_dict, key, model_location):
112+
"""
113+
Called if a key in a model dictionary is not recognized as an attribute or a sub-folder.
114+
This can happen if:
115+
- the key is the name of a custom security provider, usually a full Java class name
116+
- the key is an attribute that is not applicable for the current WLS version or offline/online status
117+
- the field is not a valid attribute or folder name
118+
"""
119+
pass

core/src/main/python/wlsdeploy/tool/util/filters/wko_filter.py

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,64 @@
66
# ------------
77
# WDT filters to prepare a model for use with WKO, using the createDomain or prepareModel tools.
88
# These operations can be invoked as a single call, or independently of each other.
9+
from wlsdeploy.aliases.validation_codes import ValidationCodes
10+
from wlsdeploy.aliases.wlst_modes import WlstModes
11+
from wlsdeploy.exception.expection_types import ExceptionType
12+
from wlsdeploy.tool.util.filters.model_traverse import ModelTraverse
913

10-
def filter_model(model):
14+
15+
def filter_model(model, model_context):
1116
"""
1217
Perform the following operations on the specified model:
1318
- Remove any online-only attributes
1419
- Check if servers in a cluster have different ports
1520
:param model: the model to be filtered
21+
:param model_context: used by nested filters
1622
"""
17-
filter_online_attributes(model)
18-
check_clustered_server_ports(model)
23+
filter_online_attributes(model, model_context)
24+
check_clustered_server_ports(model, model_context)
1925

2026

21-
def filter_online_attributes(model):
27+
def filter_online_attributes(model, model_context):
2228
"""
2329
Remove any online-only attributes from the specified model.
2430
:param model: the model to be filtered
31+
:param model_context: used to configure aliases
2532
"""
26-
print("\n\nFILTER ONLINE ATTRIBUTES")
33+
online_filter = OnlineAttributeFilter(model_context, ExceptionType.PREPARE)
34+
online_filter.traverse_model(model)
2735

2836

29-
def check_clustered_server_ports(model):
37+
def check_clustered_server_ports(model, model_context):
3038
"""
3139
Set the CalculatedListenPorts attribute to false for dynamic clusters in the specified model.
3240
Warn if servers in a static cluster have different ports in the specified model.
3341
:param model: the model to be filtered
42+
:param model_context: unused, passed by filter_helper if called independently
43+
"""
44+
print("CHECK_CLUSTERED SERVER PORTS")
45+
46+
47+
class OnlineAttributeFilter(ModelTraverse):
3448
"""
35-
print("\n\nCHECK_CLUSTERED SERVER PORTS")
49+
Traverse the model and remove any online-only attributes.
50+
"""
51+
_class_name = 'OnlineAttributeFilter'
52+
53+
def __init__(self, model_context, exception_type):
54+
# use OFFLINE regardless of tool configuration
55+
ModelTraverse.__init__(self, model_context, WlstModes.OFFLINE, exception_type)
56+
57+
# Override
58+
def unrecognized_field(self, model_dict, key, model_location):
59+
"""
60+
If the attribute name has status ValidationCodes.VERSION_INVALID, it is a valid attribute sometimes,
61+
but not for offline mode in this WLS version.
62+
"""
63+
_method_name = 'unrecognized_field'
64+
65+
result, message = self._aliases.is_valid_model_attribute_name(model_location, key)
66+
if result == ValidationCodes.VERSION_INVALID:
67+
path = self._aliases.get_model_folder_path(model_location)
68+
self._logger.info('WLSDPLY-20033', key, path, class_name=self._class_name, method_name=_method_name)
69+
del model_dict[key]

core/src/main/python/wlsdeploy/util/cla_helper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ def load_model(program_name, model_context, aliases, filter_type, wlst_mode):
243243
clean_up_temp_files()
244244
tool_exit.end(model_context, CommandLineArgUtil.PROG_ERROR_EXIT_CODE)
245245

246-
filter_helper.apply_filters(model_dictionary, filter_type)
246+
filter_helper.apply_filters(model_dictionary, filter_type, model_context)
247247

248248
persist_model(model_context, model_dictionary)
249249

0 commit comments

Comments
 (0)