Skip to content

Commit 7aa9399

Browse files
jshum2479ddsharpe
authored andcommitted
Allow late binding of file and properties for command line validation (#443)
* introduced lax validation for command line validation tool to allow late binding of @@file@@ and @@prop@@ values in the model.
1 parent e6cdd51 commit 7aa9399

File tree

12 files changed

+148
-33
lines changed

12 files changed

+148
-33
lines changed

Jenkinsfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@ pipeline {
3737
}
3838
}
3939
}
40-
}
40+
}

core/src/main/python/create.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def __process_args(args):
106106
__process_rcu_args(optional_arg_map, domain_type, domain_typedef)
107107
__process_encryption_args(optional_arg_map)
108108
__process_opss_args(optional_arg_map)
109-
109+
110110
combined_arg_map = optional_arg_map.copy()
111111
combined_arg_map.update(required_arg_map)
112112
model_context = ModelContext(_program_name, combined_arg_map)

core/src/main/python/validate.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@
4646
CommandLineArgUtil.TARGET_MODE_SWITCH,
4747
CommandLineArgUtil.ATTRIBUTES_ONLY_SWITCH,
4848
CommandLineArgUtil.FOLDERS_ONLY_SWITCH,
49-
CommandLineArgUtil.RECURSIVE_SWITCH
49+
CommandLineArgUtil.RECURSIVE_SWITCH,
50+
CommandLineArgUtil.VALIDATION_METHOD
5051
]
5152

5253

@@ -247,6 +248,7 @@ def main(args):
247248
cla_helper.clean_up_temp_files()
248249
sys.exit(CommandLineArgUtil.PROG_WARNING_EXIT_CODE)
249250

251+
250252
except ValidateException, ve:
251253
__logger.severe('WLSDPLY-20000', _program_name, ve.getLocalizedMessage(), error=ve,
252254
class_name=_class_name, method_name=_method_name)

core/src/main/python/wlsdeploy/aliases/model_constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
FOREIGN_SERVER = 'ForeignServer'
112112
GROUP = 'Group'
113113
GROUP_PARAMS = 'GroupParams'
114+
GLOBAL_VARIABLE_SUBSTITUTION = 'VariableSubstitution'
114115
HARVESTED_TYPE = 'HarvestedType'
115116
HARVESTER = 'Harvester'
116117
HEAP_DUMP_ACTION = 'HeapDumpAction'

core/src/main/python/wlsdeploy/tool/validate/validation_results.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
from wlsdeploy.util import model
1515
from wlsdeploy.tool.validate import validation_utils
16+
from wlsdeploy.aliases import model_constants
1617

1718

1819
class ValidationResults(object):
@@ -27,7 +28,8 @@ def __init__(self):
2728
'%s Section' % model.get_model_domain_info_key(): None,
2829
'%s Section' % model.get_model_topology_key(): None,
2930
'%s Section' % model.get_model_deployments_key(): None,
30-
'%s Section' % model.get_model_resources_key(): None
31+
'%s Section' % model.get_model_resources_key(): None,
32+
'%s Section' % model_constants.GLOBAL_VARIABLE_SUBSTITUTION: None
3133
}
3234

3335
def __str__(self):

core/src/main/python/wlsdeploy/tool/validate/validator.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
_TOPOLOGY_VALIDATION_AREA = validation_utils.format_message('WLSDPLY-05001', model_constants.TOPOLOGY)
4545
_RESOURCES_VALIDATION_AREA = validation_utils.format_message('WLSDPLY-05001', model_constants.RESOURCES)
4646
_APP_DEPLOYMENTS_VALIDATION_AREA = validation_utils.format_message('WLSDPLY-05001', model_constants.APP_DEPLOYMENTS)
47+
_GLOBAL_LEVEL_VARAIBLE_SUBSTITUTE = validation_utils.format_message('WLSDPLY-05001',
48+
model_constants.GLOBAL_VARIABLE_SUBSTITUTION)
4749

4850

4951
class Validator(object):
@@ -239,8 +241,11 @@ def __validate_model_file(self, model_dict, variables_file_name, archive_file_na
239241
if variables_file_name is not None:
240242
self._logger.info('WLSDPLY-05004', variables_file_name, class_name=_class_name, method_name=_method_name)
241243
self._variable_properties = variables.load_variables(variables_file_name)
244+
validation_result = ValidationResult(_GLOBAL_LEVEL_VARAIBLE_SUBSTITUTE)
245+
validation_result = variables.substitute(model_dict, self._variable_properties, self._model_context,
246+
validation_result)
242247

243-
variables.substitute(model_dict, self._variable_properties, self._model_context)
248+
self._validation_results.set_validation_result(validation_result)
244249
except VariableException, ve:
245250
ex = exception_helper.create_validate_exception('WLSDPLY-20004', 'validateModel',
246251
ve.getLocalizedMessage(), error=ve)

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class CommandLineArgUtil(object):
6464
ATTRIBUTES_ONLY_SWITCH = '-attributes_only'
6565
FOLDERS_ONLY_SWITCH = '-folders_only'
6666
RECURSIVE_SWITCH = '-recursive'
67+
VALIDATION_METHOD = '-method'
6768
# overrides for the variable injector
6869
VARIABLE_INJECTOR_FILE_SWITCH = '-variable_injector_file'
6970
VARIABLE_KEYWORDS_FILE_SWITCH = '-variable_keywords_file'
@@ -280,6 +281,15 @@ def process_args(self, args, for_domain_create=False):
280281
ex = self._get_out_of_args_exception(key)
281282
self._logger.throwing(ex, class_name=self._class_name, method_name=method_name)
282283
raise ex
284+
elif self.is_validate_method_key(key):
285+
idx += 1
286+
if idx < args_len:
287+
context = self._validate_validate_method_arg(args[idx])
288+
self._add_arg(key, context)
289+
else:
290+
ex = self._get_out_of_args_exception(key)
291+
self._logger.throwing(ex, class_name=self._class_name, method_name=method_name)
292+
raise ex
283293
elif self.is_variable_file_key(key):
284294
idx += 1
285295
if idx < args_len:
@@ -757,6 +767,24 @@ def _validate_previous_model_file_arg(self, value):
757767
raise ex
758768
return model.getAbsolutePath()
759769

770+
def is_validate_method_key(self, key):
771+
return self.VALIDATION_METHOD == key
772+
773+
def _validate_validate_method_arg(self, value):
774+
method_name = '_validate_validate_method_arg'
775+
776+
if value is None or len(value) == 0:
777+
ex = exception_helper.create_cla_exception('WLSDPLY-20029')
778+
ex.setExitCode(self.ARG_VALIDATION_ERROR_EXIT_CODE)
779+
self._logger.throwing(ex, class_name=self._class_name, method_name=method_name)
780+
raise ex
781+
elif value.lower() != 'strict' and value.lower() != 'lax':
782+
ex = exception_helper.create_cla_exception('WLSDPLY-20030', value, "strict, or lax")
783+
ex.setExitCode(self.ARG_VALIDATION_ERROR_EXIT_CODE)
784+
self._logger.throwing(ex, class_name=self._class_name, method_name=method_name)
785+
raise ex
786+
return value
787+
760788
def get_print_usage_key(self):
761789
return self.PRINT_USAGE_SWITCH
762790

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ def __init__(self, program_name, arg_map):
6363
self._folders_only = False
6464
self._opss_wallet_passphrase = None
6565
self._opss_wallet = None
66+
self._validation_method = None
6667

6768
if CommandLineArgUtil.ORACLE_HOME_SWITCH in arg_map:
6869
self._oracle_home = arg_map[CommandLineArgUtil.ORACLE_HOME_SWITCH]
@@ -153,6 +154,9 @@ def __init__(self, program_name, arg_map):
153154
if CommandLineArgUtil.OPSS_WALLET_SWITCH in arg_map:
154155
self._opss_wallet = arg_map[CommandLineArgUtil.OPSS_WALLET_SWITCH]
155156

157+
if CommandLineArgUtil.VALIDATION_METHOD in arg_map:
158+
self._validation_method = arg_map[CommandLineArgUtil.VALIDATION_METHOD]
159+
156160
if CommandLineArgUtil.TARGET_VERSION_SWITCH in arg_map:
157161
self._wl_version = arg_map[CommandLineArgUtil.TARGET_VERSION_SWITCH]
158162

@@ -287,6 +291,14 @@ def get_opss_wallet_passphrase(self):
287291
"""
288292
return self._opss_wallet_passphrase
289293

294+
def get_validation_method(self):
295+
"""
296+
Get the validation method.
297+
:return: the validation method
298+
"""
299+
if self._validation_method is None:
300+
self._validation_method = 'strict'
301+
return self._validation_method
290302

291303
def get_archive_file(self):
292304
"""

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

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -134,17 +134,18 @@ def get_variable_names(text):
134134
return names
135135

136136

137-
def substitute(dictionary, variables, model_context):
137+
def substitute(dictionary, variables, model_context, validation_result=None):
138138
"""
139139
Substitute fields in the specified dictionary with variable values.
140140
:param dictionary: the dictionary in which to substitute variables
141141
:param variables: a dictionary of variables for substitution
142142
:param model_context: used to resolve variables in file paths
143143
"""
144-
_process_node(dictionary, variables, model_context)
144+
_process_node(dictionary, variables, model_context, validation_result)
145+
return validation_result
145146

146147

147-
def _process_node(nodes, variables, model_context):
148+
def _process_node(nodes, variables, model_context, validation_result):
148149
"""
149150
Process variables in the node.
150151
:param nodes: the dictionary to process
@@ -160,18 +161,18 @@ def _process_node(nodes, variables, model_context):
160161
value = nodes[key]
161162

162163
# if the key changes with substitution, remove old key and map value to new key
163-
new_key = _substitute(key, variables, model_context)
164+
new_key = _substitute(key, variables, model_context, validation_result)
164165
if new_key is not key:
165166
nodes.pop(key)
166167
nodes[new_key] = value
167168

168169
if isinstance(value, dict):
169-
_process_node(value, variables, model_context)
170+
_process_node(value, variables, model_context, validation_result)
170171
elif type(value) is str:
171-
nodes[key] = _substitute(value, variables, model_context)
172+
nodes[key] = _substitute(value, variables, model_context, validation_result)
172173

173174

174-
def _substitute(text, variables, model_context):
175+
def _substitute(text, variables, model_context, validation_result):
175176
"""
176177
Substitute the variable placeholders with the variable value.
177178
:param text: the text to process for variable placeholders
@@ -204,17 +205,25 @@ def _substitute(text, variables, model_context):
204205
key = token[7:-2]
205206
# for @@PROP:key@@ variables, throw an exception if key is not found.
206207
if key not in variables:
207-
ex = exception_helper.create_variable_exception('WLSDPLY-01732', key)
208-
_logger.throwing(ex, class_name=_class_name, method_name=method_name)
209-
raise ex
208+
if model_context.get_validation_method() == 'strict':
209+
if validation_result:
210+
validation_result.add_error('WLSDPLY-01732', key)
211+
ex = exception_helper.create_variable_exception('WLSDPLY-01732', key)
212+
_logger.throwing(ex, class_name=_class_name, method_name=method_name)
213+
raise ex
214+
else:
215+
if validation_result:
216+
validation_result.add_info('WLSDPLY-01732', key)
217+
continue
218+
210219
value = variables[key]
211220
text = text.replace(token, value)
212221

213222
tokens = _file_variable_pattern.findall(text)
214223
if tokens:
215224
for token in tokens:
216225
path = token[7:-2]
217-
value = _read_value_from_file(path)
226+
value = _read_value_from_file(path, model_context, validation_result)
218227
text = text.replace(token, value)
219228

220229
# special case for @@FILE:@@ORACLE_HOME@@/dir/name.txt@@
@@ -223,13 +232,13 @@ def _substitute(text, variables, model_context):
223232
for token in tokens:
224233
path = token[7:-2]
225234
path = model_context.replace_token_string(path)
226-
value = _read_value_from_file(path)
235+
value = _read_value_from_file(path, model_context, validation_result)
227236
text = text.replace(token, value)
228237

229238
return text
230239

231240

232-
def _read_value_from_file(file_path):
241+
def _read_value_from_file(file_path, model_context, validation_result):
233242
"""
234243
Read a single text value from the first line in the specified file.
235244
:param file_path: the file from which to read the value
@@ -243,9 +252,18 @@ def _read_value_from_file(file_path):
243252
line = file_reader.readLine()
244253
file_reader.close()
245254
except IOException, e:
246-
ex = exception_helper.create_variable_exception('WLSDPLY-01733', file_path, e.getLocalizedMessage(), error=e)
247-
_logger.throwing(ex, class_name=_class_name, method_name=method_name)
248-
raise ex
255+
if model_context.get_validation_method() == 'strict':
256+
if validation_result:
257+
validation_result.add_error('WLSDPLY-01733', file_path, e.getLocalizedMessage())
258+
ex = exception_helper.create_variable_exception('WLSDPLY-01733', file_path, e.getLocalizedMessage(), error=e)
259+
_logger.throwing(ex, class_name=_class_name, method_name=method_name)
260+
raise ex
261+
else:
262+
if validation_result:
263+
validation_result.add_info('WLSDPLY-01733', file_path, e.getLocalizedMessage())
264+
_logger.info('WLSDPLY-01733', file_path, e.getLocalizedMessage(), error=e,
265+
class_name=_class_name, method_name=method_name)
266+
line = ''
249267

250268
if line is None:
251269
ex = exception_helper.create_variable_exception('WLSDPLY-01734', file_path)

core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,6 +1446,8 @@ WLSDPLY-20025=For {0}, specify the {1} or {2} argument, but not both
14461446
WLSDPLY-20026={0} failed to find a model file in archive {1}, and {2} argument not specified
14471447
WLSDPLY-20027=Enter the OPSS wallet passphrase
14481448
WLSDPLY-20028=Failed to read the OPSS wallet passphrase input from the user: {0}
1449+
WLSDPLY-20029=Specified validation method to use was empty or null
1450+
WLSDPLY-20030=Specified validation method {0} is invalid, must be one of: {1}
14491451

14501452
# Common messages used for tool exit and clean-up
14511453
WLSDPLY-21000={0} Messages:

installer/src/main/bin/validateModel.cmd

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,61 @@
1515
@rem This script uses the following command-line arguments directly, the rest
1616
@rem of the arguments are passed down to the underlying python program:
1717
@rem
18-
@rem - -oracle_home The directory of the existing Oracle Home to use.
19-
@rem This directory must exist and it is the caller^'s
20-
@rem responsibility to verify that it does. This
21-
@rem argument is required.
18+
@rem - -oracle_home The directory of the existing Oracle Home to use.
19+
@rem This directory must exist and it is the caller^'s
20+
@rem responsibility to verify that it does. This
21+
@rem argument is required.
2222
@rem
23-
@rem - -domain_type The type of domain to create. This argument is
24-
@rem is optional. If not specified, it defaults to WLS.
23+
@rem - -wlst_path The path to the Oracle Home product directory under
24+
@rem which to find the wlst.cmd script. This is only
25+
@rem needed for pre-12.2.1 upper stack products like SOA.
2526
@rem
26-
@rem - -wlst_path The path to the Oracle Home product directory under
27-
@rem which to find the wlst.cmd script. This is only
28-
@rem needed for pre-12.2.1 upper stack products like SOA.
27+
@rem For example, for SOA 12.1.3, -wlst_path should be
28+
@rem specified as %ORACLE_HOME%\soa
2929
@rem
30-
@rem For example, for SOA 12.1.3, -wlst_path should be
31-
@rem specified as %ORACLE_HOME%\soa
30+
@rem - -domain_type The type of domain (e.g., WLS, JRF).
31+
@rem Used to locate wlst.cmd if -wlst_path not specified
32+
@rem
33+
@rem The following arguments are passed down to the underlying python program:
34+
@rem
35+
@rem - -print_usage Specify the context for printing out the model structure.
36+
@rem By default, the specified folder attributes and subfolder
37+
@rem names are printed. Use one of the optional control
38+
@rem switches to customize the behavior. Note that the
39+
@rem control switches are mutually exclusive.
40+
@rem
41+
@rem - -model_file The location of the model file to use if not using
42+
@rem the -print_usage functionality. This can also be specified as a
43+
@rem comma-separated list of model locations, where each successive model layers
44+
@rem on top of the previous ones. If not specified, the tool will look for the
45+
@rem model in the archive. If the model is not found, validation will only
46+
@rem validate the artifacts provided.
47+
@rem
48+
@rem - -variable_file The location of the property file containing
49+
@rem the variable values for all variables used in
50+
@rem the model if not using the -print_usage functionality.
51+
@rem If the variable file is not provided, validation will
52+
@rem only validate the artifacts provided.
53+
@rem
54+
@rem - -archive_file The path to the archive file to use if not using the
55+
@rem -print_usage functionality. If the archive file is
56+
@rem not provided, validation will only validate the
57+
@rem artifacts provided.
58+
@rem
59+
@rem - -target_version The target version of WebLogic Server the tool
60+
@rem should use to validate the model content. This
61+
@rem version number can be different than the version
62+
@rem being used to run the tool. If not specified, the
63+
@rem tool will validate against the version being used
64+
@rem to run the tool.
65+
@rem
66+
@rem - -target_mode The target WLST mode that the tool should use to
67+
@rem validate the model content. The only valid values
68+
@rem are online or offline. If not specified, the tool
69+
@rem defaults to WLST offline mode.
70+
@rem
71+
@rem - -method The validation method to apply. Options: lax, strict.
72+
@rem The lax method will skip validation of external model references like @@FILE@@
3273
@rem
3374
@rem This script uses the following variables:
3475
@rem

installer/src/main/bin/validateModel.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,12 @@ usage() {
5858
echo " [-target_mode <target_mode>]"
5959
echo " [-domain_type <domain_type>]"
6060
echo " [-wlst_path <wlst_path>]"
61+
echo " [-method <method>]"
6162
echo ""
6263
echo " where:"
6364
echo " oracle_home - the existing Oracle Home directory for the domain"
6465
echo ""
65-
echo " context - specify the context for printing out the model structure."
66+
echo " print_usage - specify the context for printing out the model structure."
6667
echo " By default, the specified folder attributes and subfolder"
6768
echo " names are printed. Use one of the optional control"
6869
echo " switches to customize the behavior. Note that the"
@@ -104,6 +105,9 @@ usage() {
104105
echo " wlst_path - the Oracle Home subdirectory of the wlst.cmd"
105106
echo " script to use (e.g., <ORACLE_HOME>/soa)"
106107
echo ""
108+
echo " method - the validation method to apply. Options: lax, strict. "
109+
echo " The lax method will skip validation of external model references like @@FILE@@"
110+
echo ""
107111
}
108112

109113
umask 27

0 commit comments

Comments
 (0)