Skip to content

Commit f4b782f

Browse files
rakillenddsharpe
authored andcommitted
Remove curly brace properties, allow @@prop in lists (#516)
* JIRA WDT-377 Remove curly brace check for variable substitution * JIRA WDT-377 Replace curly brace validation with @@prop:key@@ checks * JIRA WDT-377 Updated copyrights * JIRA WDT-377 Allow @@prop in model lists * JIRA WDT-377 Log missing variables based on -method; revised system test to expect warning for missing variable file * JIRA WDT-377 revised system test to expect warning for missing variable file
1 parent e21dcf2 commit f4b782f

File tree

8 files changed

+97
-133
lines changed

8 files changed

+97
-133
lines changed

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

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Copyright (c) 2017, 2019, Oracle Corporation and/or its affiliates. All rights reserved.
2+
Copyright (c) 2017, 2020, Oracle Corporation and/or its affiliates. All rights reserved.
33
Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
44
"""
55
import re
@@ -10,8 +10,6 @@
1010
divider_string = '-----------------------------------------------'
1111

1212
_class_name = "validation_utils"
13-
_variable_pattern = re.compile('\$\{[\w.-]+\}')
14-
_property_pattern = re.compile('@@PROP:[\w.-]+@@')
1513
_path_token_pattern = re.compile('@@[\w._]+@@')
1614

1715

@@ -107,27 +105,6 @@ def get_properties(value):
107105
return rtnval
108106

109107

110-
def extract_substitution_tokens(tokenized_value):
111-
"""
112-
Returns a Python list containing the substitution variable expressions found in the
113-
tokenized_value argument
114-
115-
:param tokenized_value:
116-
:return:
117-
"""
118-
tokens = re.findall(_property_pattern, str(tokenized_value))
119-
if tokens is None:
120-
# tokenized_value didn't contain any variable expressions, so
121-
# return an empty list
122-
return []
123-
else:
124-
# tokenized_value contained at least 1 variable expressions, so
125-
# create a map of all the tokens and return the keys from that
126-
map_entry = {}
127-
map(map_entry.__setitem__, tokens, [])
128-
return map_entry.keys()
129-
130-
131108
def is_compatible_data_type(expected_data_type, actual_data_type):
132109
"""
133110
Returns boolean value indicating whether the actual_data_type argument is compatible

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

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Copyright (c) 2017, 2019, Oracle Corporation and/or its affiliates. All rights reserved.
2+
Copyright (c) 2017, 2020, Oracle Corporation and/or its affiliates. All rights reserved.
33
Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
44
"""
55
import os
@@ -236,14 +236,8 @@ def __validate_model_file(self, model_dict, variables_map, archive_file_name):
236236
if self._model_file_name is not None:
237237
self._logger.info('WLSDPLY-05003', self._model_file_name, class_name=_class_name, method_name=_method_name)
238238

239-
try:
240-
self._variable_properties = variables_map
241-
variables.substitute(model_dict, self._variable_properties, self._model_context)
242-
except VariableException, ve:
243-
ex = exception_helper.create_validate_exception('WLSDPLY-20004', 'validateModel',
244-
ve.getLocalizedMessage(), error=ve)
245-
self._logger.throwing(ex, class_name=_class_name, method_name=_method_name)
246-
raise ex
239+
self._variable_properties = variables_map
240+
# don't substitute model here, it should be validated with variables intact
247241

248242
if archive_file_name is not None:
249243
self._logger.info('WLSDPLY-05005', archive_file_name, class_name=_class_name, method_name=_method_name)
@@ -394,7 +388,7 @@ def __validate_model_section(self, model_section_key, model_dict, valid_section_
394388

395389
model_folder_path = model_section_key + ":/"
396390

397-
if '${' in section_dict_key:
391+
if variables.has_variables(section_dict_key):
398392
self._report_unsupported_variable_usage(section_dict_key, model_folder_path)
399393

400394
self._logger.finer('WLSDPLY-05011', section_dict_key, section_dict_value,
@@ -474,7 +468,7 @@ def __validate_section_folder(self, model_node, validation_location):
474468

475469
for name in model_node:
476470
expanded_name = name
477-
if '${' in name:
471+
if variables.has_variables(name):
478472
expanded_name = self.__validate_variable_substitution(name, model_folder_path)
479473

480474
self._logger.finest('2 expanded_name={0}', expanded_name,
@@ -503,7 +497,7 @@ def __validate_section_folder(self, model_node, validation_location):
503497

504498
for name in model_node:
505499
expanded_name = name
506-
if '${' in name:
500+
if variables.has_variables(name):
507501
self._report_unsupported_variable_usage(name, model_folder_path)
508502

509503
self._logger.finest('3 expanded_name={0}', expanded_name,
@@ -566,7 +560,7 @@ def __process_model_node(self, model_node, validation_location):
566560
method_name=_method_name)
567561

568562
for key, value in model_node.iteritems():
569-
if '${' in key:
563+
if variables.has_variables(key):
570564
self._report_unsupported_variable_usage(key, model_folder_path)
571565

572566
self._logger.finer('5 key={0}', key,
@@ -673,10 +667,10 @@ def __validate_attribute(self, attribute_name, attribute_value, valid_attr_infos
673667
model_folder_path, str(validation_location),
674668
class_name=_class_name, method_name=_method_name)
675669

676-
if '${' in attribute_name:
670+
if variables.has_variables(attribute_name):
677671
self._report_unsupported_variable_usage(attribute_name, model_folder_path)
678672

679-
if '${' in str(attribute_value):
673+
if variables.has_variables(str(attribute_value)):
680674
attribute_value = self.__validate_variable_substitution(attribute_value, model_folder_path)
681675

682676
if attribute_name in valid_attr_infos:
@@ -720,10 +714,10 @@ def __validate_property(self, property_name, property_value, valid_prop_infos, m
720714
self._logger.entering(property_name, property_value, str(valid_prop_infos), model_folder_path,
721715
class_name=_class_name, method_name=_method_name)
722716

723-
if '${' in property_name:
717+
if variables.has_variables(property_name):
724718
property_name = self.__validate_variable_substitution(property_name, model_folder_path)
725719

726-
if '${' in str(property_value):
720+
if variables.has_variables(str(property_value)):
727721
property_value = self.__validate_variable_substitution(property_value, model_folder_path)
728722

729723
if property_name in valid_prop_infos:
@@ -750,9 +744,8 @@ def __validate_variable_substitution(self, tokenized_value, model_folder_path):
750744

751745
if not isinstance(untokenized_value, dict):
752746
# Extract the variable substitution variables from tokenized_value
753-
tokens = validation_utils.extract_substitution_tokens(tokenized_value)
754-
for token in tokens:
755-
property_name = token[2:len(token)-1]
747+
matches = variables.get_variable_matches(tokenized_value)
748+
for token, property_name in matches:
756749
property_value = None
757750
if property_name in self._variable_properties:
758751
property_value = self._variable_properties[property_name]
@@ -761,13 +754,18 @@ def __validate_variable_substitution(self, tokenized_value, model_folder_path):
761754
else:
762755
# FIXME(mwooten) - the cla_utils should be fixing all windows paths to use forward slashes already
763756
# assuming that the value is not None
757+
758+
logger_method = self._logger.info
759+
if self._model_context.get_validation_method() == 'strict':
760+
logger_method = self._logger.warning
761+
764762
variables_file_name = self._model_context.get_variable_file()
765763
if variables_file_name is None:
766-
self._logger.warning('WLSDPLY-05021', model_folder_path, property_name,
767-
class_name=_class_name, method_name=_method_name)
764+
logger_method('WLSDPLY-05021', model_folder_path, property_name,
765+
class_name=_class_name, method_name=_method_name)
768766
else:
769-
self._logger.warning('WLSDPLY-05022', model_folder_path, property_name, variables_file_name,
770-
class_name=_class_name, method_name=_method_name)
767+
logger_method('WLSDPLY-05022', model_folder_path, property_name, variables_file_name,
768+
class_name=_class_name, method_name=_method_name)
771769

772770
self._logger.exiting(class_name=_class_name, method_name=_method_name, result=untokenized_value)
773771
return untokenized_value
@@ -882,7 +880,7 @@ def __validate_server_group_targeting_limits(self, attribute_key, attribute_valu
882880
self._logger.severe('WLSDPLY-05033', key, model_folder_path, str(type(key)),
883881
class_name=_class_name, method_name=__method_name)
884882
else:
885-
if '${' in key:
883+
if variables.has_variables(key):
886884
self._report_unsupported_variable_usage(key, model_folder_path)
887885

888886
if isinstance(value, basestring) and MODEL_LIST_DELIMITER in value:
@@ -904,7 +902,7 @@ def _validate_single_server_group_target_limits_value(self, key, value, model_fo
904902
_method_name = '_validate_single_server_group_target_limits_value'
905903

906904
if type(value) is str:
907-
if '${' in str(value):
905+
if variables.has_variables(str(value)):
908906
self._report_unsupported_variable_usage(str(value), model_folder_path)
909907
else:
910908
self._logger.severe('WLSDPLY-05035', key, str(value), model_folder_path, str(type(value)),
@@ -922,7 +920,7 @@ def __validate_wlsroles_section(self, attribute_value):
922920

923921
def _report_unsupported_variable_usage(self, tokenized_value, model_folder_path):
924922
_method_name = '_report_unsupported_variable_usage'
925-
tokens = validation_utils.extract_substitution_tokens(tokenized_value)
923+
tokens = variables.get_variable_names(tokenized_value)
926924
for token in tokens:
927925
self._logger.severe('WLSDPLY-05030', model_folder_path, token,
928926
class_name=_class_name, method_name=_method_name)

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

Lines changed: 52 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Copyright (c) 2017, 2019, Oracle Corporation and/or its affiliates. All rights reserved.
2+
Copyright (c) 2017, 2020, Oracle Corporation and/or its affiliates. All rights reserved.
33
Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
44
"""
55
import os
@@ -23,9 +23,8 @@
2323

2424
_class_name = "variables"
2525
_logger = platform_logger.PlatformLogger('wlsdeploy.variables')
26-
_variable_pattern = re.compile("\\$\\{[\w.-]+\\}")
2726
_file_variable_pattern = re.compile("@@FILE:[\w.\\\/:-]+@@")
28-
_property_pattern = re.compile("@@PROP:[\w.-]+@@")
27+
_property_pattern = re.compile("(@@PROP:([\\w.-]+)@@)")
2928
_file_nested_variable_pattern = re.compile("@@FILE:@@[\w]+@@[\w.\\\/:-]+@@")
3029

3130

@@ -153,17 +152,10 @@ def get_variable_names(text):
153152
:return: a list of variable names
154153
"""
155154
names = []
156-
if '${' in text:
157-
tokens = _variable_pattern.findall(text)
158-
if tokens is not None:
159-
for token in tokens:
160-
names.append(token[2:-1])
161-
162155
if '@@' in text:
163-
tokens = _property_pattern.findall(text)
164-
if tokens:
165-
for token in tokens:
166-
names.append(token[7:-2])
156+
matches = _property_pattern.findall(text)
157+
for token, key in matches:
158+
names.append(key)
167159

168160
return names
169161

@@ -201,6 +193,13 @@ def _process_node(nodes, variables, model_context):
201193

202194
if isinstance(value, dict):
203195
_process_node(value, variables, model_context)
196+
197+
elif isinstance(value, list):
198+
for member in value:
199+
if type(member) in [str, unicode]:
200+
index = value.index(member)
201+
value[index] = _substitute(member, variables, model_context)
202+
204203
elif type(value) in [str, unicode]:
205204
nodes[key] = _substitute(value, variables, model_context)
206205

@@ -215,40 +214,25 @@ def _substitute(text, variables, model_context):
215214
"""
216215
method_name = '_substitute'
217216

218-
if '${' in text:
219-
tokens = _variable_pattern.findall(text)
220-
if tokens:
221-
for token in tokens:
222-
key = token[2:-1]
223-
# for ${key} variables, leave them in place if not defined.
224-
# there are cases where WebLogic allows ${key} values, such as server templates.
225-
# ${key} substitution is deprecated, so log if replacement occurs.
226-
if key in variables:
227-
value = variables[key]
228-
text = text.replace(token, value)
229-
_logger.info('WLSDPLY-01735', token, key, method_name=method_name, class_name=_class_name)
230-
231217
# skip lookups for text with no @@
232218
if '@@' in text:
233219

234220
# do properties first, to cover the case @@FILE:/dir/@@PROP:name@@.txt@@
235-
tokens = _property_pattern.findall(text)
236-
if tokens:
237-
for token in tokens:
238-
key = token[7:-2]
239-
# for @@PROP:key@@ variables, throw an exception if key is not found.
240-
if key not in variables:
241-
if model_context.get_validation_method() == 'strict':
242-
_logger.severe('WLSDPLY-01732', key, class_name=_class_name, method_name=method_name)
243-
ex = exception_helper.create_variable_exception('WLSDPLY-01732', key)
244-
_logger.throwing(ex, class_name=_class_name, method_name=method_name)
245-
raise ex
246-
else:
247-
_logger.info('WLSDPLY-01732', key, class_name=_class_name, method_name=method_name)
248-
continue
249-
250-
value = variables[key]
251-
text = text.replace(token, value)
221+
matches = _property_pattern.findall(text)
222+
for token, key in matches:
223+
# log, or throw an exception if key is not found.
224+
if key not in variables:
225+
if model_context.get_validation_method() == 'strict':
226+
_logger.severe('WLSDPLY-01732', key, class_name=_class_name, method_name=method_name)
227+
ex = exception_helper.create_variable_exception('WLSDPLY-01732', key)
228+
_logger.throwing(ex, class_name=_class_name, method_name=method_name)
229+
raise ex
230+
else:
231+
_logger.info('WLSDPLY-01732', key, class_name=_class_name, method_name=method_name)
232+
continue
233+
234+
value = variables[key]
235+
text = text.replace(token, value)
252236

253237
tokens = _file_variable_pattern.findall(text)
254238
if tokens:
@@ -306,16 +290,33 @@ def substitute_key(text, variables):
306290
"""
307291
Substitute any @@PROP values in the text and return.
308292
If the corresponding variable is not found, leave the @@PROP value in place.
309-
The deprecated ${} notation is not resolved.
310293
:param text: the text to be evaluated
311294
:param variables: the variable map
312295
:return: the substituted text value
313296
"""
314-
tokens = _property_pattern.findall(text)
315-
if tokens:
316-
for token in tokens:
317-
key = token[7:-2]
318-
if key in variables:
319-
value = variables[key]
320-
text = text.replace(token, value)
297+
matches = _property_pattern.findall(text)
298+
for token, key in matches:
299+
if key in variables:
300+
value = variables[key]
301+
text = text.replace(token, value)
321302
return text
303+
304+
305+
def has_variables(text):
306+
"""
307+
Determine if the specified text contains any variable references.
308+
:param text: the text to be evaluated
309+
:return: True if the text contains variable references, False otherwise
310+
"""
311+
matches = _property_pattern.findall(text)
312+
return len(matches) > 0
313+
314+
315+
def get_variable_matches(text):
316+
"""
317+
Return a list containing a tuple for each property key in the specified text.
318+
Each tuple contains the full expression (@@PROP:<key>@@) and just the key (<key>).
319+
:param text: the text to be evaluated
320+
:return: a list of tuples
321+
"""
322+
return _property_pattern.findall(text)

core/src/test/python/variables_test.py

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Copyright (c) 2017, 2019, Oracle Corporation and/or its affiliates. All rights reserved.
2+
Copyright (c) 2017, 2020, Oracle Corporation and/or its affiliates. All rights reserved.
33
Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
44
"""
55
import unittest
@@ -47,17 +47,6 @@ def testSubstituteJson(self):
4747
self.assertEqual(True, 'myCluster' in model['topology']['Cluster'])
4848
self.assertEqual(True, 's3' in model['topology']['Server'])
4949

50-
def testVariableNotFound(self):
51-
"""
52-
For ${key} substitution, no replacement is done, and no error is reported, if variable not found.
53-
${key} substitution is deprecated.
54-
"""
55-
model = FileToPython(self._resources_dir + '/variables-test.json', self._use_ordering).parse()
56-
model['topology']['Name'] = '${bad.variable}'
57-
variable_map = variables.load_variables(self._variables_file)
58-
variables.substitute(model, variable_map, self.model_context)
59-
self.assertEqual(model['topology']['Name'], '${bad.variable}')
60-
6150
def testPropertyNotFound(self):
6251
"""
6352
For @@PROP:key@@ substitution, an exception is thrown if variable not found.
@@ -79,7 +68,7 @@ def testFileVariable(self):
7968
self.assertEqual(model['domainInfo']['AdminUserName'], 'file-variable-value')
8069

8170
def testFileVariableWithVariable(self):
82-
model = {'domainInfo': {'AdminUserName': '@@FILE:${variable_dir}/' + self._file_variable_name + '@@'}}
71+
model = {'domainInfo': {'AdminUserName': '@@FILE:@@PROP:variable_dir@@/' + self._file_variable_name + '@@'}}
8372
variables.substitute(model, {'variable_dir': self._resources_dir}, self.model_context)
8473
self.assertEqual(model['domainInfo']['AdminUserName'], 'file-variable-value')
8574

0 commit comments

Comments
 (0)