Skip to content

Commit adcd59b

Browse files
authored
Perform checks for compatibility with WKO targets (#1389)
* Check dynamic cluster server name prefixes in target filter * Ensure admin server is included in model for wko3 targets * Validate server templates in dynamic clusters
1 parent ea5725d commit adcd59b

File tree

13 files changed

+301
-21
lines changed

13 files changed

+301
-21
lines changed

core/src/main/python/wlsdeploy/tool/prepare/model_preparer.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2021, 2022, Oracle and/or its affiliates.
1+
# Copyright (c) 2021, 2023, Oracle and/or its affiliates.
22
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
33

44
import os
@@ -163,17 +163,12 @@ def __walk_attribute(self, model_dict, attribute_name, attribute_location):
163163

164164
self._logger.exiting(class_name=_class_name, method_name=_method_name)
165165

166-
def fix_property_secrets(self):
166+
def fix_property_secrets(self, original_variables):
167167
# Just in case the credential cache has @@PROP in the model's attribute value,
168168
# we use the original variable file to resolve it,
169169
# so that the generated json/script files have the resolved property value(s) instead of the @@PROP token.
170170
# it's possible that the variable file is not specified, or does not exist yet.
171171

172-
original_variables = {}
173-
variable_file = self.model_context.get_variable_file()
174-
if variable_file is not None and os.path.exists(variable_file):
175-
original_variables = variables.load_variables(variable_file)
176-
177172
credential_caches = self.credential_injector.get_variable_cache()
178173
for key in credential_caches:
179174
if variables.is_variable_string(credential_caches[key]):
@@ -359,14 +354,20 @@ def prepare_models(self):
359354
self._clean_variable_files(merged_model_dictionary)
360355
self._clean_archive_files()
361356

362-
# use a merged, substituted, filtered model to get domain name and create additional target output.
363-
full_model_dictionary = cla_helper.load_model(_program_name, self.model_context, self._aliases,
364-
"discover", WlstModes.OFFLINE)
357+
# resolve variables in the model AFTER the clean and filter has been done,
358+
# but before generating output files.
359+
360+
variable_map = {}
361+
variable_file = self.model_context.get_variable_file()
362+
if variable_file is not None and os.path.exists(variable_file):
363+
variable_map = variables.load_variables(variable_file)
364+
365+
variables.substitute(merged_model_dictionary, variable_map, self.model_context)
365366

366367
# correct any secret values that point to @@PROP values
367-
self.fix_property_secrets()
368+
self.fix_property_secrets(variable_map)
368369

369-
target_configuration_helper.generate_all_output_files(Model(full_model_dictionary), self._aliases,
370+
target_configuration_helper.generate_all_output_files(Model(merged_model_dictionary), self._aliases,
370371
self.credential_injector, self.model_context,
371372
ExceptionType.PREPARE)
372373

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Copyright (c) 2017, 2022, Oracle and/or its affiliates.
2+
Copyright (c) 2017, 2023 Oracle and/or its affiliates.
33
Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
44
"""
55
import imp
@@ -23,6 +23,7 @@
2323
'k8s_filter': wko_filter.filter_model,
2424
'vz_filter': wko_filter.filter_model_for_vz,
2525
'wko_filter': wko_filter.filter_model_for_wko,
26+
'wko3_filter': wko_filter.filter_model_for_wko3,
2627

2728
# individual filters for custom target environments
2829
'online_attributes_filter': wko_filter.filter_online_attributes,

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

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2021, 2022, Oracle and/or its affiliates.
1+
# Copyright (c) 2021, 2023, Oracle and/or its affiliates.
22
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
33
#
44
# ------------
@@ -7,14 +7,17 @@
77
# WDT filters to prepare a model for use a target environment, using the createDomain or prepareModel tools.
88
# These operations can be invoked as a single call, or independently of each other.
99
from oracle.weblogic.deploy.util import PyRealBoolean
10+
from oracle.weblogic.deploy.util import PyOrderedDict
1011
from wlsdeploy.aliases import alias_utils
12+
from wlsdeploy.aliases.model_constants import ADMIN_SERVER_NAME
1113
from wlsdeploy.aliases.model_constants import AUTO_MIGRATION_ENABLED
1214
from wlsdeploy.aliases.model_constants import CALCULATED_LISTEN_PORTS
1315
from wlsdeploy.aliases.model_constants import CANDIDATE_MACHINE
1416
from wlsdeploy.aliases.model_constants import CANDIDATE_MACHINES_FOR_MIGRATABLE_SERVER
1517
from wlsdeploy.aliases.model_constants import CLUSTER
1618
from wlsdeploy.aliases.model_constants import CLUSTER_MESSAGING_MODE
1719
from wlsdeploy.aliases.model_constants import DATABASE_LESS_LEASING_BASIS
20+
from wlsdeploy.aliases.model_constants import DEFAULT_ADMIN_SERVER_NAME
1821
from wlsdeploy.aliases.model_constants import DYNAMIC_SERVERS
1922
from wlsdeploy.aliases.model_constants import LISTEN_PORT
2023
from wlsdeploy.aliases.model_constants import MACHINE
@@ -31,6 +34,7 @@
3134
from wlsdeploy.aliases.model_constants import RESOURCE_MANAGER
3235
from wlsdeploy.aliases.model_constants import SECURITY_CONFIGURATION
3336
from wlsdeploy.aliases.model_constants import SERVER
37+
from wlsdeploy.aliases.model_constants import SERVER_NAME_PREFIX
3438
from wlsdeploy.aliases.model_constants import SERVER_START
3539
from wlsdeploy.aliases.model_constants import SERVER_TEMPLATE
3640
from wlsdeploy.aliases.model_constants import TOPOLOGY
@@ -45,6 +49,8 @@
4549
from wlsdeploy.util import dictionary_utils
4650
import wlsdeploy.util.unicode_helper as str_helper
4751

52+
FIX_PREFIX_TEMPLATE = '-- FIX PREFIX %s --'
53+
4854
_class_name = 'wko_filter'
4955
_logger = PlatformLogger('wlsdeploy.tool.util')
5056

@@ -61,6 +67,7 @@ def filter_model(model, model_context):
6167
filter_resources(model, model_context)
6268
filter_online_attributes(model, model_context)
6369
check_clustered_server_ports(model, model_context)
70+
check_dynamic_cluster_prefixes(model, model_context)
6471

6572

6673
def filter_model_for_wko(model, model_context):
@@ -73,6 +80,17 @@ def filter_model_for_wko(model, model_context):
7380
filter_model(model, model_context)
7481

7582

83+
def filter_model_for_wko3(model, model_context):
84+
"""
85+
Perform filtering operations on the specified model to prepare for WKO deployment.
86+
Currently matches the general k8s target filtering.
87+
:param model: the model to be filtered
88+
:param model_context: used by nested filters
89+
"""
90+
filter_model(model, model_context)
91+
check_admin_server_defined(model, model_context)
92+
93+
7694
def filter_model_for_vz(model, model_context):
7795
"""
7896
Perform filtering operations on the specified model to prepare for Verrazzano deployment.
@@ -143,6 +161,71 @@ def check_clustered_server_ports(model, _model_context):
143161
server_port_map[server_cluster] = {"firstServer": server_name, "serverPort": server_port_text}
144162

145163

164+
def check_dynamic_cluster_prefixes(model, _model_context):
165+
"""
166+
All Dynamic Clusters must have a DynamicServers section with the ServerNamePrefix field explicitly declared.
167+
Ensure each cluster uses a unique value for this field.
168+
:param model: the model to be updated
169+
:param _model_context: unused, passed by filter_helper if called independently
170+
:return:
171+
"""
172+
_method_name = 'check_dynamic_cluster_prefixes'
173+
174+
server_name_prefixes = []
175+
topology_folder = dictionary_utils.get_dictionary_element(model, TOPOLOGY)
176+
clusters_folder = dictionary_utils.get_dictionary_element(topology_folder, CLUSTER)
177+
for cluster_name, cluster_fields in clusters_folder.items():
178+
dynamic_folder = dictionary_utils.get_element(cluster_fields, DYNAMIC_SERVERS)
179+
if dynamic_folder:
180+
server_name_prefix = dictionary_utils.get_element(dynamic_folder, SERVER_NAME_PREFIX)
181+
182+
if not server_name_prefix:
183+
_logger.warning('WLSDPLY-20204', cluster_name, SERVER_NAME_PREFIX, class_name=_class_name,
184+
method_name=_method_name)
185+
server_name_prefix = _get_unused_prefix(server_name_prefixes)
186+
dynamic_folder[SERVER_NAME_PREFIX] = server_name_prefix
187+
188+
elif server_name_prefix in server_name_prefixes:
189+
_logger.warning('WLSDPLY-20205', SERVER_NAME_PREFIX, server_name_prefix, class_name=_class_name,
190+
method_name=_method_name)
191+
server_name_prefix = _get_unused_prefix(server_name_prefixes)
192+
dynamic_folder[SERVER_NAME_PREFIX] = server_name_prefix
193+
194+
server_name_prefixes.append(server_name_prefix)
195+
196+
197+
def check_admin_server_defined(model, _model_context):
198+
"""
199+
Ensure that the AdminServerName attribute is set, and that the server is defined.
200+
This is required by WKO 3.0, and not by 4.0 and later.
201+
:param model: the model to be filtered
202+
:param _model_context: unused, passed by filter_helper if called independently
203+
"""
204+
_method_name = 'check_admin_server_defined'
205+
206+
topology_folder = dictionary_utils.get_element(model, TOPOLOGY)
207+
if topology_folder is None:
208+
# for cases with multiple models, avoid adding topology and admin server for
209+
# models with only resources, applications, etc.
210+
return
211+
212+
admin_server_name = dictionary_utils.get_element(topology_folder, ADMIN_SERVER_NAME)
213+
if not admin_server_name:
214+
admin_server_name = DEFAULT_ADMIN_SERVER_NAME
215+
_logger.info('WLSDPLY-20206', ADMIN_SERVER_NAME, admin_server_name, class_name=_class_name,
216+
method_name=_method_name)
217+
topology_folder[ADMIN_SERVER_NAME] = admin_server_name
218+
219+
servers_folder = dictionary_utils.get_element(topology_folder, SERVER)
220+
if servers_folder is None:
221+
servers_folder = PyOrderedDict()
222+
topology_folder[SERVER] = servers_folder
223+
224+
if admin_server_name not in servers_folder:
225+
_logger.info('WLSDPLY-20207', SERVER, admin_server_name, class_name=_class_name, method_name=_method_name)
226+
servers_folder[admin_server_name] = PyOrderedDict()
227+
228+
146229
def filter_topology(model, _model_context):
147230
"""
148231
Remove elements from the topology section of the model that are not relevant in a Kubernetes environment.
@@ -201,6 +284,18 @@ def filter_resources(model, _model_context):
201284
del resources[delete_key]
202285

203286

287+
def _get_unused_prefix(used_prefixes):
288+
"""
289+
Find a recognizable, unused prefix that can be used in the filtered model.
290+
:param used_prefixes: prefixes that have already been used in the model
291+
:return: an unused prefix
292+
"""
293+
i = 1
294+
while FIX_PREFIX_TEMPLATE % i in used_prefixes:
295+
i += 1
296+
return FIX_PREFIX_TEMPLATE % i
297+
298+
204299
class OnlineAttributeFilter(ModelTraverse):
205300
"""
206301
Traverse the model and remove any online-only attributes.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""
2+
Copyright (c) 2023, Oracle and/or its affiliates.
3+
Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
4+
"""
5+
from wlsdeploy.aliases.model_constants import CLUSTER
6+
from wlsdeploy.aliases.model_constants import DYNAMIC_SERVERS
7+
from wlsdeploy.aliases.model_constants import SERVER_TEMPLATE
8+
from wlsdeploy.aliases.model_constants import TOPOLOGY
9+
from wlsdeploy.logging.platform_logger import PlatformLogger
10+
from wlsdeploy.util import dictionary_utils
11+
12+
13+
class ContentValidator(object):
14+
"""
15+
Class for validating consistency and compatibility of model folders and attributes.
16+
These checks are done after alias folder and attribute checks.
17+
The model may be a partial model from a multiple-model configuration.
18+
19+
Dynamic clusters is currently the only validation.
20+
Other non-alias validations might fit here (RcuDbInfo?).
21+
"""
22+
_class_name = 'ContentValidator'
23+
_logger = PlatformLogger('wlsdeploy.validate')
24+
25+
def __init__(self, model_context):
26+
self._model_context = model_context
27+
28+
def validate_model(self, model_dict):
29+
"""
30+
Validate the contents of the specified model.
31+
:param model_dict: A Python dictionary of the model to be validated
32+
:raises ValidationException: if problems occur during validation
33+
"""
34+
_method_name = 'validate_model'
35+
36+
self.validate_dynamic_clusters(model_dict)
37+
38+
def validate_dynamic_clusters(self, model_dict):
39+
"""
40+
Validate that dynamic clusters have a unique server template.
41+
:param model_dict: A Python dictionary of the model to be validated
42+
:raises ValidationException: if problems occur during validation
43+
"""
44+
_method_name = 'validate_dynamic_clusters'
45+
46+
server_templates = []
47+
topology_folder = dictionary_utils.get_dictionary_element(model_dict, TOPOLOGY)
48+
clusters_folder = dictionary_utils.get_dictionary_element(topology_folder, CLUSTER)
49+
for cluster_name, cluster_fields in clusters_folder.items():
50+
dynamic_folder = dictionary_utils.get_element(cluster_fields, DYNAMIC_SERVERS)
51+
if dynamic_folder:
52+
server_template = dictionary_utils.get_element(dynamic_folder, SERVER_TEMPLATE)
53+
54+
if not server_template:
55+
self._logger.warning('WLSDPLY-05200', cluster_name, SERVER_TEMPLATE,
56+
class_name=self._class_name, method_name=_method_name)
57+
58+
elif server_template in server_templates:
59+
self._logger.warning('WLSDPLY-05201', cluster_name, SERVER_TEMPLATE, server_template,
60+
class_name=self._class_name, method_name=_method_name)
61+
62+
else:
63+
server_templates.append(server_template)

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from wlsdeploy.tool.create import wlsroles_helper
2222
from wlsdeploy.tool.util.archive_helper import ArchiveHelper
2323
from wlsdeploy.tool.validate import validation_utils
24+
from wlsdeploy.tool.validate.content_validator import ContentValidator
2425
from wlsdeploy.tool.validate.crd_sections_validator import CrdSectionsValidator
2526
from wlsdeploy.tool.validate.validator_logger import ValidatorLogger
2627
from wlsdeploy.util import dictionary_utils
@@ -265,6 +266,9 @@ def __validate_model_file(self, model_dict, variables_map, archive_file_name):
265266
k8s_validator = CrdSectionsValidator(self._model_context)
266267
k8s_validator.validate_model(model_dict)
267268

269+
content_validator = ContentValidator(self._model_context)
270+
content_validator.validate_model(model_dict)
271+
268272
self._logger.exiting(class_name=_class_name, method_name=_method_name)
269273

270274
def load_variables(self, variables_file_name):

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,10 @@ WLSDPLY-05043=Model location {0} does not match any of the {1} folder options
549549
# wlsdeploy/tool/validate/crd_sections_validator.py
550550
WLSDPLY-05090=Model folder {0} is not supported, will be skipped
551551

552+
# wlsdeploy/tool/validate/content_validator.py
553+
WLSDPLY-05200=Dynamic cluster "{0}" does not have a {1} value, which will prevent the domain from starting
554+
WLSDPLY-05201=Dynamic cluster "{0}" {1} "{2}" is used by another cluster, which is not allowed
555+
552556
# wlsdeploy/tools/validate/validation_utils.py
553557
WLSDPLY-05300=NOT USED
554558

@@ -1771,6 +1775,10 @@ WLSDPLY-20036={0} encountered an unexpected runtime exception. Stacktrace: {1}
17711775
WLSDPLY-20201=Unsupported attribute {0} at location {1} removed from model
17721776
WLSDPLY-20202=Changing {0} to false for {1} "{2}"
17731777
WLSDPLY-20203={0} entries "{1}" and "{2}" in {3} "{4}" have different {5} values: {6} and {7}
1778+
WLSDPLY-20204=Dynamic cluster "{0}" does not specify {1}, which will cause deployment to fail
1779+
WLSDPLY-20205=The {0} value "{1}" is used by multiple dynamic clusters, which will cause deployment to fail
1780+
WLSDPLY-20206=Adding {0} value "{1}" to model for WKO 3 compatibility
1781+
WLSDPLY-20207=Adding {0} "{1}" to model for WKO 3 compatibility
17741782

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

core/src/main/targetconfigs/wko-dii/target.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"model_filters" : {
33
"discover": [
4-
{ "id": "wko_filter" }
4+
{ "id": "wko3_filter" }
55
]
66
},
77
"variable_injectors" : {"PORT": {},"HOST": {},"URL": {}},

core/src/main/targetconfigs/wko-pv/target.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"model_filters" : {
33
"discover": [
4-
{ "id": "wko_filter" }
4+
{ "id": "wko3_filter" }
55
]
66
},
77
"variable_injectors" : {"PORT": {},"HOST": {},"URL": {}},

core/src/main/targetconfigs/wko/target.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"model_filters" : {
33
"discover": [
44
{ "name": "wko_prep", "path": "@@TARGET_CONFIG_DIR@@/wko_operator_filter.py" },
5-
{ "id": "wko_filter" }
5+
{ "id": "wko3_filter" }
66
]
77
},
88
"variable_injectors" : {"PORT": {},"HOST": {},"URL": {}},

0 commit comments

Comments
 (0)