diff --git a/operator/pom.xml b/operator/pom.xml index 5858395e01c..3816f0008b9 100644 --- a/operator/pom.xml +++ b/operator/pom.xml @@ -231,14 +231,36 @@ java package + + oracle.kubernetes.operator.helpers.CrdHelper + + ${project.basedir}/../kubernetes/crd/domain-crd.yaml + + + + + test-python-scripts + test + + exec + + + ${skip.unit.tests} + python + src/test/python + + ${project.basedir}/src/main/resources/scripts + sample-domain1 + + + -B + -m + unittest + discover + + - - oracle.kubernetes.operator.helpers.CrdHelper - - ${project.basedir}/../kubernetes/crd/domain-crd.yaml - - diff --git a/operator/src/main/java/oracle/kubernetes/operator/helpers/JobHelper.java b/operator/src/main/java/oracle/kubernetes/operator/helpers/JobHelper.java index 81c1f05bd6e..8f527c4a336 100644 --- a/operator/src/main/java/oracle/kubernetes/operator/helpers/JobHelper.java +++ b/operator/src/main/java/oracle/kubernetes/operator/helpers/JobHelper.java @@ -314,7 +314,6 @@ List getConfiguredEnvVars(TuningParameters tuningParameters) { Long.toString(getDomain().getWDTSetServerGroupsTimeoutMillis())); } - String dataHome = getDataHome(); if (dataHome != null && !dataHome.isEmpty()) { addEnvVar(vars, ServerEnvVars.DATA_HOME, dataHome); diff --git a/operator/src/main/java/oracle/kubernetes/operator/helpers/PodStepContext.java b/operator/src/main/java/oracle/kubernetes/operator/helpers/PodStepContext.java index 3e534414f76..c7bcbf27b31 100644 --- a/operator/src/main/java/oracle/kubernetes/operator/helpers/PodStepContext.java +++ b/operator/src/main/java/oracle/kubernetes/operator/helpers/PodStepContext.java @@ -61,6 +61,7 @@ import oracle.kubernetes.operator.work.Step; import oracle.kubernetes.weblogic.domain.model.Domain; import oracle.kubernetes.weblogic.domain.model.DomainStatus; +import oracle.kubernetes.weblogic.domain.model.IntrospectorJobEnvVars; import oracle.kubernetes.weblogic.domain.model.ServerEnvVars; import oracle.kubernetes.weblogic.domain.model.ServerSpec; import oracle.kubernetes.weblogic.domain.model.Shutdown; @@ -631,6 +632,11 @@ private void updateEnv(List env) { updateEnvForShutdown(env); updateEnvForStartupMode(env); defineConfigOverride(env); + updateEnvWithDomainSourceType(env); + } + + private void updateEnvWithDomainSourceType(List env) { + addDefaultEnvVarIfMissing(env, IntrospectorJobEnvVars.DOMAIN_SOURCE_TYPE, getDomainHomeSourceType().toString()); } private void updateEnvForShutdown(List env) { diff --git a/operator/src/main/resources/scripts/introspectDomain.py b/operator/src/main/resources/scripts/introspectDomain.py index aec9b2c3bad..f54faa823a6 100644 --- a/operator/src/main/resources/scripts/introspectDomain.py +++ b/operator/src/main/resources/scripts/introspectDomain.py @@ -767,6 +767,10 @@ def addNetworkAccessPoint(self, server, nap, is_server_template): nap_protocol = getNAPProtocol(nap, server, self.env.getDomain(), is_server_template) if istio_enabled == 'true': + name = nap.getName() + if name.startswith('http-') or name.startswith('tcp-') or name.startswith('tls-') or name.startswith('https-'): + # skip istio ports already defined by WDT filtering for MII + return http_protocol = [ 'http' ] https_protocol = ['https','admin'] tcp_protocol = [ 't3', 'snmp', 'ldap', 'cluster-broadcast', 'iiop', 'sip'] @@ -1606,10 +1610,11 @@ def introspect(self): tg = TopologyGenerator(self.env) if tg.validate(): - SitConfigGenerator(self.env).generate() + DOMAIN_SOURCE_TYPE = self.env.getEnvOrDef("DOMAIN_SOURCE_TYPE", None) + if DOMAIN_SOURCE_TYPE != "FromModel": + SitConfigGenerator(self.env).generate() BootPropertiesGenerator(self.env).generate() UserConfigAndKeyGenerator(self.env).generate() - DOMAIN_SOURCE_TYPE = self.env.getEnvOrDef("DOMAIN_SOURCE_TYPE", None) if DOMAIN_SOURCE_TYPE == "FromModel": trace("cfgmap write primordial_domain") diff --git a/operator/src/main/resources/scripts/livenessProbe.sh b/operator/src/main/resources/scripts/livenessProbe.sh index 66d52641652..fd0b4f5ba1c 100755 --- a/operator/src/main/resources/scripts/livenessProbe.sh +++ b/operator/src/main/resources/scripts/livenessProbe.sh @@ -102,9 +102,11 @@ if [ $? != 0 ]; then exit $RETVAL fi -copySitCfgWhileRunning /weblogic-operator/introspector ${DOMAIN_HOME}/optconfig 'Sit-Cfg-CFG--' -copySitCfgWhileRunning /weblogic-operator/introspector ${DOMAIN_HOME}/optconfig/jms 'Sit-Cfg-JMS--' -copySitCfgWhileRunning /weblogic-operator/introspector ${DOMAIN_HOME}/optconfig/jdbc 'Sit-Cfg-JDBC--' -copySitCfgWhileRunning /weblogic-operator/introspector ${DOMAIN_HOME}/optconfig/diagnostics 'Sit-Cfg-WLDF--' +if [ ${DOMAIN_SOURCE_TYPE} != "FromModel" ]; then + copySitCfgWhileRunning /weblogic-operator/introspector ${DOMAIN_HOME}/optconfig 'Sit-Cfg-CFG--' + copySitCfgWhileRunning /weblogic-operator/introspector ${DOMAIN_HOME}/optconfig/jms 'Sit-Cfg-JMS--' + copySitCfgWhileRunning /weblogic-operator/introspector ${DOMAIN_HOME}/optconfig/jdbc 'Sit-Cfg-JDBC--' + copySitCfgWhileRunning /weblogic-operator/introspector ${DOMAIN_HOME}/optconfig/diagnostics 'Sit-Cfg-WLDF--' +fi exit 0 diff --git a/operator/src/main/resources/scripts/model-filters.json b/operator/src/main/resources/scripts/model-filters.json index 0b55aa179ab..dff0b7ed97e 100644 --- a/operator/src/main/resources/scripts/model-filters.json +++ b/operator/src/main/resources/scripts/model-filters.json @@ -7,5 +7,9 @@ "discover": [ ], "update": [ + { "name": "update_mii_filter", "path": "/u01/wdt/weblogic-deploy/lib/model_wdt_mii_filter.py" } + ], + "validate": [ + { "name": "validate_mii_filter", "path": "/u01/wdt/weblogic-deploy/lib/model_wdt_mii_filter.py" } ] } \ No newline at end of file diff --git a/operator/src/main/resources/scripts/modelInImage.sh b/operator/src/main/resources/scripts/modelInImage.sh index 632ec986db7..5c9c70fd1bc 100755 --- a/operator/src/main/resources/scripts/modelInImage.sh +++ b/operator/src/main/resources/scripts/modelInImage.sh @@ -37,6 +37,7 @@ WDT_OUTPUT="/tmp/wdt_output.log" WDT_BINDIR="${WDT_ROOT}/bin" WDT_FILTER_JSON="/weblogic-operator/scripts/model-filters.json" WDT_CREATE_FILTER="/weblogic-operator/scripts/model-wdt-create-filter.py" +WDT_MII_FILTER="/weblogic-operator/scripts/model_wdt_mii_filter.py" UPDATE_RCUPWD_FLAG="" WLSDEPLOY_PROPERTIES="${WLSDEPLOY_PROPERTIES} -Djava.security.egd=file:/dev/./urandom" ARCHIVE_ZIP_CHANGED=0 @@ -319,9 +320,9 @@ function createWLDomain() { fi # copy the filter related files to the wdt lib - - cp ${WDT_FILTER_JSON} ${WDT_ROOT}/lib/model_filters.json - cp ${WDT_CREATE_FILTER} ${WDT_ROOT}/lib + cp ${WDT_FILTER_JSON} ${WDT_ROOT}/lib/model_filters.json || logSevereAndExit ${WDT_FILTER_JSON} + cp ${WDT_CREATE_FILTER} ${WDT_ROOT}/lib || logSevereAndExit ${WDT_CREATE_FILTER} + cp ${WDT_MII_FILTER} ${WDT_ROOT}/lib || logSevereAndExit ${WDT_MII_FILTER} # check to see if any model including changed (or first model in image deploy) # if yes. then run create domain again @@ -793,8 +794,14 @@ function generateMergedModel() { export __WLSDEPLOY_STORE_MODEL__="${NEW_MERGED_MODEL}" - ${WDT_BINDIR}/validateModel.sh -oracle_home ${ORACLE_HOME} ${model_list} \ - ${archive_list} ${variable_list} -domain_type ${WDT_DOMAIN_TYPE} > ${WDT_OUTPUT} 2>&1 + local wdtArgs="" + wdtArgs+=" -oracle_home ${ORACLE_HOME}" + wdtArgs+=" ${model_list} ${archive_list} ${variable_list}" + wdtArgs+=" -domain_type ${WDT_DOMAIN_TYPE}" + + trace "About to call '${WDT_BINDIR}/validateModel.sh ${wdtArgs}'." + + ${WDT_BINDIR}/validateModel.sh ${wdtArgs} > ${WDT_OUTPUT} 2>&1 ret=$? if [ $ret -ne 0 ]; then trace SEVERE "Model in Image: the WDT validate model tool detected an error with the fully merged model:" @@ -917,8 +924,16 @@ function wdtUpdateModelDomain() { # make sure wdt create write out the merged model to a file in the root of the domain export __WLSDEPLOY_STORE_MODEL__=1 - ${WDT_BINDIR}/updateDomain.sh -oracle_home ${ORACLE_HOME} -domain_home ${DOMAIN_HOME} $model_list \ - ${archive_list} ${variable_list} -domain_type ${WDT_DOMAIN_TYPE} ${UPDATE_RCUPWD_FLAG} > ${WDT_OUTPUT} 2>&1 + local wdtArgs="" + wdtArgs+=" -oracle_home ${ORACLE_HOME}" + wdtArgs+=" -domain_home ${DOMAIN_HOME}" + wdtArgs+=" ${model_list} ${archive_list} ${variable_list}" + wdtArgs+=" -domain_type ${WDT_DOMAIN_TYPE}" + wdtArgs+=" ${UPDATE_RCUPWD_FLAG}" + + trace "About to call '${WDT_BINDIR}/updateDomain.sh ${wdtArgs}'." + + ${WDT_BINDIR}/updateDomain.sh ${wdtArgs} > ${WDT_OUTPUT} 2>&1 ret=$? if [ $ret -ne 0 ]; then @@ -1271,3 +1286,8 @@ function stop_trap() { function cleanup_mii() { rm -f /tmp/*.md5 /tmp/*.gz /tmp/*.ini /tmp/*.json } + +function logSevereAndExit() { + trace SEVERE "cp '$1' failed" + exitOrLoop +} diff --git a/operator/src/main/resources/scripts/model_wdt_mii_filter.py b/operator/src/main/resources/scripts/model_wdt_mii_filter.py new file mode 100644 index 00000000000..7cecd6985ac --- /dev/null +++ b/operator/src/main/resources/scripts/model_wdt_mii_filter.py @@ -0,0 +1,598 @@ +# Copyright (c) 2018, 2021, Oracle and/or its affiliates. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. +# +# ------------ +# Description: +# ------------ +# This is a model-in-image WDT filter for overriding WLS configuration, it +# replaces 'situational configuration overrides'. +# +# This code is used by the operator during introspection for MII to manipulate +# the domain model. It generates domain configuration information that's +# useful for running the domain, setting up its networking, and for overriding +# specific parts of its configuration so that it can run in k8s. +# +# For more details, see the Model Filters description in the WebLogic Deploy +# Tooling in Github. +# +# --------------------- +# Prerequisites/Inputs: +# --------------------- +# +# A domain model as a Jython dictionary. +# +# The following env vars are required: +# DOMAIN_UID - completely unique id for this domain +# DOMAIN_HOME - path for the domain configuration +# LOG_HOME - path to override WebLogic server log locations +# CREDENTIALS_SECRET_NAME - name of secret containing credentials +# +# The following env vars are optional: +# ACCESS_LOG_IN_LOG_HOME - HTTP access log files will be written to +# the logHome directory. +# DATA_HOME - in-pod location for data storage of default and custom file +# stores. +# CREDENTIALS_SECRET_PATH - directory path to secret containing credentials +# +# --------------------------------- +# Result +# --------------------------------- +# +# The configuration overrides are directly modified in the domain model and +# include listen addresses, log file locations, etc. The WebLogic Deploy +# Tooling will then generate/update the domain with the appropriate +# configuration. +# + + +import inspect +import os +import sys + +tmp_callerframerecord = inspect.stack()[0] # 0 represents this line # 1 represents line at caller +tmp_info = inspect.getframeinfo(tmp_callerframerecord[0]) +tmp_scriptdir=os.path.dirname(tmp_info[0]) +sys.path.append(tmp_scriptdir) + +env = None + +class OfflineWlstEnv(object): + + def open(self, model): + + self.model = model + # before doing anything, get each env var and verify it exists + + self.DOMAIN_UID = self.getEnv('DOMAIN_UID') + self.DOMAIN_HOME = self.getEnv('DOMAIN_HOME') + self.LOG_HOME = self.getEnv('LOG_HOME') + self.ACCESS_LOG_IN_LOG_HOME = self.getEnvOrDef('ACCESS_LOG_IN_LOG_HOME', 'true') + self.DATA_HOME = self.getEnvOrDef('DATA_HOME', "") + self.CREDENTIALS_SECRET_NAME = self.getEnv('CREDENTIALS_SECRET_NAME') + + # initialize globals + self.CREDENTIALS_SECRET_PATH = self.getEnvOrDef('CREDENTIALS_SECRET_PATH', '/weblogic-operator/secrets') + self.TOPOLOGY_YAML_PATH = '/weblogic-operator/introspectormii/topology.yaml' + self.DOMAIN_NAME = None + + if model and 'topology' in model: + self.DOMAIN_NAME = model['topology']['Name'] + + if self.DOMAIN_NAME is None and os.path.exists(self.TOPOLOGY_YAML_PATH): + self.readDomainNameFromTopologyYaml(self.TOPOLOGY_YAML_PATH) + + def readDomainNameFromTopologyYaml(self, path): + file = open(path, 'r') + content = file.readlines() + file.close() + # access line containing domain name and strip leading and trailing spaces + line = content[2].strip() + # create key-value pair (e.g. name="sample-domain1") + (key, val) = line.split() + if key == 'name:': + # strip leading and trailing double quotes from value + self.DOMAIN_NAME = val.strip('"') + + def getDomainName(self): + return self.DOMAIN_NAME + + def getDomainUID(self): + return self.DOMAIN_UID + + def getDomainHome(self): + return self.DOMAIN_HOME + + def getDomainLogHome(self): + return self.LOG_HOME + + def getDataHome(self): + return self.DATA_HOME + + def isAccessLogInLogHome(self): + return self.ACCESS_LOG_IN_LOG_HOME == 'true' + + def readFile(self, path): + file = open(path, 'r') + contents = file.read() + file.close() + return contents + + def getEnv(self, name): + val = os.getenv(name) + if val is None or val == "null": + print("SEVERE: Env var %s not set." % name) + sys.exit(1) + return val + + def getEnvOrDef(self, name, deflt): + val = os.getenv(name) + if val == None or val == "null" or len(val) == 0: + return deflt + return val + + def toDNS1123Legal(self, address): + return address.lower().replace('_','-') + + def getModel(self): + return self.model + + def wlsVersionEarlierThan(self, version): + # unconventional import within function definition for unit testing + from weblogic.management.configuration import LegalHelper + return LegalHelper.versionEarlierThan("14.1.2.0", version) + +class SecretManager(object): + + def __init__(self, env): + self.env = env + + def readCredentialsSecret(self, key): + path = self.env.CREDENTIALS_SECRET_PATH + '/' + key + return self.env.readFile(path) + + +def filter_model(model): + if model is not None: + if getOfflineWlstEnv() is None: + initOfflineWlstEnv(model) + + initSecretManager(env) + + if model and 'resources' in model: + customizeCustomFileStores(model) + + if model and 'topology' in model: + topology = model['topology'] + customizeNodeManagerCreds(topology) + customizeDomainLogPath(topology) + if 'Server' in topology: + customizeServers(model) + + if 'ServerTemplate' in topology: + customizeServerTemplates(model) + + +def initOfflineWlstEnv(model): + global env + env = OfflineWlstEnv() + env.open(model) + + +def getOfflineWlstEnv(): + if env is not None: + return env + return None + + +def setOfflineWlstEnv(offlineWlstEnv): + env = offlineWlstEnv + +def initSecretManager(env): + global secret_manager + secret_manager = SecretManager(env) + +def customizeServerTemplates(model): + topology = model['topology'] + if 'ServerTemplate' not in topology: + return + + serverTemplates = topology['ServerTemplate'] + template_names = serverTemplates.keys() + if template_names is not None: + for template_name in template_names: + template = serverTemplates[template_name] + cluster_name = getClusterNameOrNone(template) + if cluster_name is not None: + customizeServerTemplate(topology, template) + + +def customizeServerTemplate(topology, template): + server_name_prefix = getServerNamePrefix(topology, template) + domain_uid = env.getDomainUID() + customizeLog(server_name_prefix + "${id}", template) + customizeAccessLog(server_name_prefix + "${id}", template) + customizeDefaultFileStore(template) + listen_address=env.toDNS1123Legal(domain_uid + "-" + server_name_prefix + "${id}") + setServerListenAddress(template, listen_address) + customizeNetworkAccessPoints(template, listen_address) + customizeManagedIstioNetworkAccessPoint(template, listen_address) + + +def getServerNamePrefix(topology, template): + server_name_prefix = None + cluster_name = getClusterNameOrNone(template) + if cluster_name is not None: + cluster = getClusterOrNone(topology, cluster_name) + if cluster is not None: + dynamicServer = getDynamicServerOrNone(cluster) + if dynamicServer is not None: + server_name_prefix = getDynamicServerPropertyOrNone(dynamicServer, 'ServerNamePrefix') + + return server_name_prefix + + +def customizeNodeManagerCreds(topology): + username = getSecretManager().readCredentialsSecret('username') + pwd = getSecretManager().readCredentialsSecret('password') + + if not ('SecurityConfiguration' in topology): + topology['SecurityConfiguration'] = {} + + topology['SecurityConfiguration']['NodeManagerUsername'] = username + topology['SecurityConfiguration']['NodeManagerPasswordEncrypted'] = pwd + + +def customizeDomainLogPath(topology): + customizeLog(env.getDomainName(), topology) + + +def customizeLog(name, topologyOrServer): + if name is None: + # domain name is req'd to create domain log configuration. + # Missing domain name indicates our model is a fragment + return + + logs_dir = env.getDomainLogHome() + if logs_dir is None or len(logs_dir) == 0: + return + + if 'Log' not in topologyOrServer: + topologyOrServer['Log'] = {} + + topologyOrServer['Log']['FileName'] = logs_dir + "/" + name + ".log" + + +def customizeCustomFileStores(model): + customizeFileStores(model['resources']) + + +def customizeFileStores(resources): + data_dir = env.getDataHome() + if data_dir is None or len(data_dir) == 0: + # do not override if dataHome not specified or empty ("") + return + + if 'FileStore' not in resources: + return + + filestores = resources['FileStore'] + names = filestores.keys() + for name in names: + filestore = filestores[name] + customizeFileStore(filestore, data_dir) + + +def customizeFileStore(filestore, data_dir): + filestore['Directory'] = data_dir + + +def customizeServers(model): + if 'Server' not in model['topology']: + return + + servers = model['topology']['Server'] + names = servers.keys() + for name in names: + server = servers[name] + customizeServer(server, name) + + +def customizeServer(server, name): + listen_address=env.toDNS1123Legal(env.getDomainUID() + "-" + name) + customizeLog(name, server) + customizeAccessLog(name, server) + customizeDefaultFileStore(server) + setServerListenAddress(server, listen_address) + customizeNetworkAccessPoints(server,listen_address) + customizeServerIstioNetworkAccessPoint(server, listen_address) + + +def getAdministrationPort(server, topology): + port = 0 + if 'AdministrationPort' in server: + port = int(server['AdministrationPort']) + if port == 0 and 'AdministrationPort' in topology: + port = int(topology['AdministrationPort']) + return port + + +def isAdministrationPortEnabledForServer(server, topology): + administrationPortEnabled = False + if 'AdministrationPortEnabled' in server: + administrationPortEnabled = server['AdministrationPortEnabled'] == 'true' + else: + administrationPortEnabled = isAdministrationPortEnabledForDomain(topology) + return administrationPortEnabled + + +def isAdministrationPortEnabledForDomain(topology): + administrationPortEnabled = False + + if 'AdministrationPortEnabled' in topology: + administrationPortEnabled = topology['AdministrationPortEnabled'] == 'true' + else: + # AdministrationPortEnabled is not explicitly set so going with the default + # Starting with 14.1.2.0, the domain's AdministrationPortEnabled default is derived from the domain's SecureMode + administrationPortEnabled = isSecureModeEnabledForDomain(topology) + return administrationPortEnabled + + +# Derive the default value for SecureMode of a domain +def isSecureModeEnabledForDomain(topology): + secureModeEnabled = False + if 'SecurityConfiguration' in topology and 'SecureMode' in topology['SecurityConfiguration'] and 'SecureModeEnabled' in topology['SecurityConfiguration']['SecureMode']: + secureModeEnabled = topology['SecurityConfiguration']['SecureMode']['SecureModeEnabled'] == 'true' + else: + is_production_mode_enabled = False + if 'ProductionModeEnabled' in topology: + is_production_mode_enabled = topology['ProductionModeEnabled'] == 'true' + secureModeEnabled = is_production_mode_enabled and not env.wlsVersionEarlierThan("14.1.2.0") + return secureModeEnabled + + +def getSSLOrNone(server): + if 'SSL' not in server: + return None + + return server['SSL'] + + +def _writeIstioNAP(name, server, listen_address, listen_port, protocol, http_enabled="true"): + + if 'NetworkAccessPoint' not in server: + server['NetworkAccessPoint'] = {} + + naps = server['NetworkAccessPoint'] + if name not in naps: + naps[name] = {} + + nap = naps[name] + nap['Protocol'] = protocol + nap['ListenAddress'] = '127.0.0.1' + nap['PublicAddress'] = '%s.%s' % (listen_address, env.getEnvOrDef("ISTIO_POD_NAMESPACE", "default")) + nap['ListenPort'] = listen_port + nap['HttpEnabledForThisProtocol'] = http_enabled + nap['TunnelingEnabled'] = 'false' + nap['OutboundEnabled'] = 'true' + nap['Enabled'] = 'true' + + +def customizeServerIstioNetworkAccessPoint(server, listen_address): + istio_enabled = env.getEnvOrDef("ISTIO_ENABLED", "false") + if istio_enabled == 'false': + return + istio_readiness_port = env.getEnvOrDef("ISTIO_READINESS_PORT", None) + if istio_readiness_port is None: + return + admin_server_port = server['ListenPort'] + # readiness probe + _writeIstioNAP(name='http-probe', server=server, listen_address=listen_address, + listen_port=istio_readiness_port, protocol='http', http_enabled="true") + + # Generate NAP for each protocols + _writeIstioNAP(name='tcp-ldap', server=server, listen_address=listen_address, + listen_port=admin_server_port, protocol='ldap') + + _writeIstioNAP(name='tcp-default', server=server, listen_address=listen_address, + listen_port=admin_server_port, protocol='t3') + + _writeIstioNAP(name='http-default', server=server, listen_address=listen_address, + listen_port=admin_server_port, protocol='http') + + _writeIstioNAP(name='tcp-snmp', server=server, listen_address=listen_address, + listen_port=admin_server_port, protocol='snmp') + + _writeIstioNAP(name='tcp-cbt', server=server, listen_address=listen_address, + listen_port=admin_server_port, protocol='CLUSTER-BROADCAST') + + _writeIstioNAP(name='tcp-iiop', server=server, listen_address=listen_address, + listen_port=admin_server_port, protocol='iiop') + + ssl = getSSLOrNone(server) + ssl_listen_port = None + model = env.getModel() + if ssl is not None and 'Enabled' in ssl and ssl['Enabled'] == 'true': + ssl_listen_port = ssl['ListenPort'] + elif ssl is None and isSecureModeEnabledForDomain(model['topology']): + ssl_listen_port = "7002" + + if ssl_listen_port is not None: + _writeIstioNAP(name='https-secure', server=server, listen_address=listen_address, + listen_port=ssl_listen_port, protocol='https', http_enabled="true") + + _writeIstioNAP(name='tls-ldaps', server=server, listen_address=listen_address, + listen_port=ssl_listen_port, protocol='ldaps') + + _writeIstioNAP(name='tls-default', server=server, listen_address=listen_address, + listen_port=ssl_listen_port, protocol='t3s') + + _writeIstioNAP(name='tls-cbts', server=server, listen_address=listen_address, + listen_port=ssl_listen_port, protocol='CLUSTER-BROADCAST-SECURE') + + _writeIstioNAP(name='tls-iiops', server=server, listen_address=listen_address, + listen_port=ssl_listen_port, protocol='iiops') + + if isAdministrationPortEnabledForServer(server, model['topology']): + _writeIstioNAP(name='https-admin', server=server, listen_address=listen_address, + listen_port=getAdministrationPort(server, model['topology']), protocol='https', http_enabled="true") + + +def customizeManagedIstioNetworkAccessPoint(template, listen_address): + istio_enabled = env.getEnvOrDef("ISTIO_ENABLED", "false") + if istio_enabled == 'false': + return + istio_readiness_port = env.getEnvOrDef("ISTIO_READINESS_PORT", None) + if istio_readiness_port is None: + return + listen_port = template['ListenPort'] + # readiness probe + _writeIstioNAP(name='http-probe', server=template, listen_address=listen_address, + listen_port=istio_readiness_port, protocol='http', http_enabled="true") + + # Generate NAP for each protocols + _writeIstioNAP(name='tcp-ldap', server=template, listen_address=listen_address, + listen_port=listen_port, protocol='ldap') + + _writeIstioNAP(name='tcp-default', server=template, listen_address=listen_address, + listen_port=listen_port, protocol='t3') + + _writeIstioNAP(name='http-default', server=template, listen_address=listen_address, + listen_port=listen_port, protocol='http') + + _writeIstioNAP(name='tcp-snmp', server=template, listen_address=listen_address, + listen_port=listen_port, protocol='snmp') + + _writeIstioNAP(name='tcp-cbt', server=template, listen_address=listen_address, + listen_port=listen_port, protocol='CLUSTER-BROADCAST') + + _writeIstioNAP(name='tcp-iiop', server=template, listen_address=listen_address, + listen_port=listen_port, protocol='iiop') + + ssl = getSSLOrNone(template) + ssl_listen_port = None + model = env.getModel() + if ssl is not None and 'Enabled' in ssl and ssl['Enabled'] == 'true': + ssl_listen_port = ssl['ListenPort'] + elif ssl is None and isSecureModeEnabledForDomain(model['topology']): + ssl_listen_port = "7002" + + if ssl_listen_port is not None: + _writeIstioNAP(name='https-secure', server=template, listen_address=listen_address, + listen_port=ssl_listen_port, protocol='https', http_enabled="true") + + _writeIstioNAP(name='tls-ldaps', server=template, listen_address=listen_address, + listen_port=ssl_listen_port, protocol='ldaps') + + _writeIstioNAP(name='tls-default', server=template, listen_address=listen_address, + listen_port=ssl_listen_port, protocol='t3s') + + _writeIstioNAP(name='tls-cbts', server=template, listen_address=listen_address, + listen_port=ssl_listen_port, protocol='CLUSTER-BROADCAST-SECURE') + + _writeIstioNAP(name='tls-iiops', server=template, listen_address=listen_address, + listen_port=ssl_listen_port, protocol='iiops') + + +def customizeNetworkAccessPoints(server, listen_address): + if 'NetworkAccessPoint' not in server: + return + + naps = server['NetworkAccessPoint'] + nap_names = naps.keys() + for nap_name in nap_names: + nap = naps[nap_name] + customizeNetworkAccessPoint(nap, listen_address) + + +def customizeNetworkAccessPoint(nap, listen_address): + istio_enabled = env.getEnvOrDef("ISTIO_ENABLED", "false") + + if 'ListenAddress' in nap: + original_listen_address = nap['ListenAddress'] + if len(original_listen_address) > 0: + if istio_enabled == 'true': + nap['ListenAddress'] = '127.0.0.1' + else: + nap['ListenAddress'] = listen_address + + +def setServerListenAddress(serverOrTemplate, listen_address): + serverOrTemplate['ListenAddress'] = listen_address + + +def customizeDefaultFileStore(server): + data_dir = env.getDataHome() + if data_dir is None or len(data_dir) == 0: + # do not override if dataHome not specified or empty ("") + return + + if 'DefaultFileStore' not in server: + server['DefaultFileStore'] = {} + + server['DefaultFileStore']['Directory'] = data_dir + + +def customizeAccessLog(name, server): + # do not customize if LOG_HOME is not set + logs_dir = env.getDomainLogHome() + if logs_dir is None or len(logs_dir) == 0: + return + + # customize only if ACCESS_LOG_IN_LOG_HOME is 'true' + if env.isAccessLogInLogHome(): + if 'WebServer' not in server: + server['WebServer'] = {} + + web_server = server['WebServer'] + if 'WebServerLog' not in web_server: + web_server['WebServerLog'] = {} + + web_server_log = web_server['WebServerLog'] + if 'FileName' not in web_server_log: + web_server_log['FileName'] = {} + + web_server_log['FileName'] = logs_dir + "/" + name + "_access.log" + + +def getLogOrNone(config): + if 'Log' not in config: + return None + + return config['Log'] + + +def getClusterNameOrNone(serverOrTemplate): + if 'Cluster' not in serverOrTemplate: + return None + + return serverOrTemplate['Cluster'] + + +def getClusterOrNone(topology, name): + if 'Cluster' not in topology: + return + + clusters = topology['Cluster'] + + if name in clusters: + return clusters[name] + + return None + + +def getDynamicServerOrNone(cluster): + if 'DynamicServers' not in cluster: + return None + + return cluster['DynamicServers'] + + +def getDynamicServerPropertyOrNone(dynamicServer, name): + if name not in dynamicServer: + return None + + return dynamicServer[name] + + +def getSecretManager(): + return secret_manager diff --git a/operator/src/main/resources/scripts/startNodeManager.sh b/operator/src/main/resources/scripts/startNodeManager.sh index bb7f547fedf..a39937c3002 100644 --- a/operator/src/main/resources/scripts/startNodeManager.sh +++ b/operator/src/main/resources/scripts/startNodeManager.sh @@ -241,13 +241,20 @@ if [ ! "${SERVER_NAME}" = "introspector" ]; then [ ! $? -eq 0 ] && trace SEVERE "Could not remove stale file '$wl_state_file'." && exit 1 fi + if [ ${DOMAIN_SOURCE_TYPE} == "FromModel" ]; then + # Domain source type is 'FromModel' (MII) then disable Situation config override for WebLogic. + failBootOnErrorOption="" + else + failBootOnErrorOption="-Dweblogic.SituationalConfig.failBootOnError=${FAIL_BOOT_ON_SITUATIONAL_CONFIG_ERROR}" + fi + cat < ${wl_props_file} # Server startup properties AutoRestart=true RestartMax=2 RestartInterval=3600 NMHostName=${SERVICE_NAME} -Arguments=${USER_MEM_ARGS} -Dweblogic.SituationalConfig.failBootOnError=${FAIL_BOOT_ON_SITUATIONAL_CONFIG_ERROR} ${serverOutOption} ${JAVA_OPTIONS} +Arguments=${USER_MEM_ARGS} ${failBootOnErrorOption} ${serverOutOption} ${JAVA_OPTIONS} EOF diff --git a/operator/src/main/resources/scripts/startServer.sh b/operator/src/main/resources/scripts/startServer.sh index cf1b54819b6..e4925005c3b 100755 --- a/operator/src/main/resources/scripts/startServer.sh +++ b/operator/src/main/resources/scripts/startServer.sh @@ -102,8 +102,12 @@ function startWLS() { FAIL_BOOT_ON_SITUATIONAL_CONFIG_ERROR=${FAIL_BOOT_ON_SITUATIONAL_CONFIG_ERROR:-true} SERVER_OUT_MONITOR_INTERVAL=${SERVER_OUT_MONITOR_INTERVAL:-3} - if [ ${FAIL_BOOT_ON_SITUATIONAL_CONFIG_ERROR} == 'true' ] ; then - ${SCRIPTPATH}/monitorLog.sh ${SERVER_OUT_FILE} ${SERVER_OUT_MONITOR_INTERVAL} & + if [ ${DOMAIN_SOURCE_TYPE} != "FromModel" ]; then + # If Domain source type is not FromModel (MII) then monitor server logs for invalid + # Situational config override files. + if [ ${FAIL_BOOT_ON_SITUATIONAL_CONFIG_ERROR} == 'true' ] ; then + ${SCRIPTPATH}/monitorLog.sh ${SERVER_OUT_FILE} ${SERVER_OUT_MONITOR_INTERVAL} & + fi fi } @@ -174,7 +178,7 @@ traceDirs before DOMAIN_HOME LOG_HOME DATA_HOME traceTiming "POD '${SERVICE_NAME}' MII UNZIP START" -if [ -f /weblogic-operator/introspector/domainzip.secure ]; then +if [ ${DOMAIN_SOURCE_TYPE} == "FromModel" ]; then prepareMIIServer if [ $? -ne 0 ] ; then trace SEVERE "Domain Source Type is FromModel, unable to start the server, check other error messages in the log" @@ -281,10 +285,13 @@ createFolder ${DOMAIN_HOME}/servers/${SERVER_NAME}/security copyIfChanged /weblogic-operator/introspector/boot.properties \ ${DOMAIN_HOME}/servers/${SERVER_NAME}/security/boot.properties -copySitCfgWhileBooting /weblogic-operator/introspector ${DOMAIN_HOME}/optconfig 'Sit-Cfg-CFG--' -copySitCfgWhileBooting /weblogic-operator/introspector ${DOMAIN_HOME}/optconfig/jms 'Sit-Cfg-JMS--' -copySitCfgWhileBooting /weblogic-operator/introspector ${DOMAIN_HOME}/optconfig/jdbc 'Sit-Cfg-JDBC--' -copySitCfgWhileBooting /weblogic-operator/introspector ${DOMAIN_HOME}/optconfig/diagnostics 'Sit-Cfg-WLDF--' +if [ ${DOMAIN_SOURCE_TYPE} != "FromModel" ]; then + trace "Copying situational configuration files from operator cm to ${DOMAIN_HOME}/optconfig directory" + copySitCfgWhileBooting /weblogic-operator/introspector ${DOMAIN_HOME}/optconfig 'Sit-Cfg-CFG--' + copySitCfgWhileBooting /weblogic-operator/introspector ${DOMAIN_HOME}/optconfig/jms 'Sit-Cfg-JMS--' + copySitCfgWhileBooting /weblogic-operator/introspector ${DOMAIN_HOME}/optconfig/jdbc 'Sit-Cfg-JDBC--' + copySitCfgWhileBooting /weblogic-operator/introspector ${DOMAIN_HOME}/optconfig/diagnostics 'Sit-Cfg-WLDF--' +fi # # Start WLS diff --git a/operator/src/test/python/__init__.py b/operator/src/test/python/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/operator/src/test/python/test_wdt_mii_filter.py b/operator/src/test/python/test_wdt_mii_filter.py new file mode 100644 index 00000000000..c376dbc2a9f --- /dev/null +++ b/operator/src/test/python/test_wdt_mii_filter.py @@ -0,0 +1,257 @@ +import ast +import os +import unittest +#import yaml + +import model_wdt_mii_filter + + +class WdtUpdateFilterCase(unittest.TestCase): + + ISTIO_NAP_NAMES = ['tcp-cbt', 'tcp-ldap', 'tcp-iiop', 'tcp-snmp', 'http-probe', 'http-default', 'tcp-default'] + + def setUp(self): + self.initialize_environment_variables() + + + def initialize_environment_variables(self): + os.environ['DOMAIN_UID'] = 'sample-domain1' + os.environ['DOMAIN_HOME'] = '/u01/domains/sample-domain1' + os.environ['LOG_HOME'] = '/u01/logs/sample-domain1' + os.environ[ + 'CREDENTIALS_SECRET_NAME'] = 'sample-domain1-weblogic-credentials' + os.environ['DOMAIN_SOURCE_TYPE'] = 'FromModel' + os.environ['DATA_HOME'] = '/u01/datahome' + + def initialize_istio_naps(self): + istio_naps = {} + + self.add_istio_nap_to_dict(istio_naps, name='http-probe', protocol='http', http_enabled="true") + self.add_istio_nap_to_dict(istio_naps, name='tcp-ldap', protocol='ldap', http_enabled="false") + + + def add_istio_nap_to_dict(self, istio_naps, name, protocol, http_enabled): + if name in istio_naps: + return + + istio_naps.setdefault(name, {}) + listen_address=self.env.toDNS1123Legal(self.env.getDomainUID() + "-" + name) + nap = istio_naps[name] + nap['Protocol'] = protocol + nap['ListenAddres'] = '127.0.0.1' + nap['PublicAddress'] = '%s.%s' % (listen_address, self.env.getEnvOrDef("ISTIO_POD_NAMESPACE", "default")) + nap['ListenPort'] = self.env.getEnvOrDef("ISTIO_READINESS_PORT", None) + nap['HttpEnabledForThisProtocol'] = http_enabled + nap['TunnelingEnabled'] = 'false' + nap['OutboundEnabled'] = 'false' + nap['Enabled'] = 'true' + nap['TwoWaySslEnabled'] = 'false' + nap['ClientCertificateEnforced'] = 'false' + + def getModel(self): + # Load model as dictionary + file = open(r'../resources/model.dynamic_cluster_dict.txt') + contents = file.read() + model = ast.literal_eval(contents) + file.close() + + # Setup mock environment + mock_env= MockOfflineWlstEnv() + mock_env.open(model) + model_wdt_mii_filter.env = mock_env + + return model + + def getStaticModel(self): + # Load model as dictionary + file = open(r'../resources/model.static_cluster_dict.txt') + contents = file.read() + model = ast.literal_eval(contents) + file.close() + + # Setup mock environment + mock_env= MockOfflineWlstEnv() + mock_env.open(model) + model_wdt_mii_filter.env = mock_env + + return model + + def writeModelAsDict(self, model, file_path): + f = open(file_path,"w") + f.write( str(model) ) + f.close() + + def getServerTemplate(self, model): + template_name = 'cluster-1-template' + topology = model['topology'] + server_template = topology['ServerTemplate'][template_name] + return server_template + + + def test_get_server_name_prefix(self): + model = self.getModel() + + server_template = self.getServerTemplate(model) + server_name_prefix = model_wdt_mii_filter.getServerNamePrefix(model['topology'], server_template) + self.assertEqual('managed-server', server_name_prefix, "Expected server name prefix to be \'managed-server\'") + + + def test_customize_admin_server_static_cluster(self): + model = self.getStaticModel() + + server_name = 'admin-server' + server = model['topology']['Server'][server_name] + model_wdt_mii_filter.customizeServer(server, server_name) + listen_address = server['ListenAddress'] + self.assertEqual('sample-domain1-admin-server', listen_address, "Expected listen address to be \'sample-domain1-admin-server\'") + + def test_customize_log_in_server_template(self): + model = self.getModel() + + server_template = self.getServerTemplate(model) + model_wdt_mii_filter.customizeLog("managed-server${id}", server_template) + template_log_filename = server_template['Log']['FileName'] + self.assertEqual('/u01/logs/sample-domain1/managed-server${id}.log', template_log_filename, "Expected listen address to be \'/u01/logs/sample-domain1/managed-server${id}.log\'") + + def test_customize_access_log_in_server_template(self): + model = self.getModel() + + server_template = self.getServerTemplate(model) + model_wdt_mii_filter.customizeAccessLog("managed-server${id}", server_template) + template_access_log = server_template['WebServer']['WebServerLog']['FileName'] + self.assertEqual('/u01/logs/sample-domain1/managed-server${id}_access.log', template_access_log, "Expected listen address to be \'/u01/logs/sample-domain1/managed-server${id}.log\'") + + + def test_customize_default_filestore_in_server_template(self): + model = self.getModel() + + server_template = self.getServerTemplate(model) + model_wdt_mii_filter.customizeDefaultFileStore(server_template) + default_filestore = server_template['DefaultFileStore']['Directory'] + self.assertEqual('/u01/datahome', default_filestore, "Expected default file store directory to be \'/u01/datahome\'") + + + def test_customize_network_access_points_in_server_template(self): + model = self.getModel() + + server_template = self.getServerTemplate(model) + model_wdt_mii_filter.customizeNetworkAccessPoints(server_template, 'sample-domain1-managed-server${id}') + nap_listen_address = model['topology']['ServerTemplate']['cluster-1-template']['NetworkAccessPoint']['T3Channel']['ListenAddress'] + self.assertEqual('sample-domain1-managed-server${id}', nap_listen_address, "Expected nap listen address to be \'sample-domain1-managed-server${id}\'") + + def test_customize_istio_enabled_network_access_points_in_server_template(self): + try: + os.environ['ISTIO_ENABLED'] = 'true' + model = self.getModel() + + server_template = self.getServerTemplate(model) + model_wdt_mii_filter.customizeNetworkAccessPoints(server_template, 'sample-domain1-managed-server${id}') + nap_listen_address = model['topology']['ServerTemplate']['cluster-1-template']['NetworkAccessPoint']['T3Channel']['ListenAddress'] + self.assertEqual('127.0.0.1', nap_listen_address, "Expected nap listen address to be \'127.0.0.1\'") + finally: + del os.environ['ISTIO_ENABLED'] + + def test_customize_managed_istio_network_access_point_in_server_template(self): + try: + os.environ['ISTIO_ENABLED'] = 'true' + os.environ['ISTIO_READINESS_PORT'] = '8088' + model = self.getModel() + + template_name = 'cluster-1-template' + server_template = self.getServerTemplate(model) + model_wdt_mii_filter.customizeManagedIstioNetworkAccessPoint(server_template, 'sample-domain1-managed-server${id}') + naps = server_template.get('NetworkAccessPoint') + self.assertGreater(len(naps), 1) + names = list(naps.keys()) + names.remove('T3Channel') + for name in names: + self.assertIn(name, WdtUpdateFilterCase.ISTIO_NAP_NAMES) + finally: + del os.environ['ISTIO_ENABLED'] + del os.environ['ISTIO_READINESS_PORT'] + + + def test_customizeServerTemplates(self): + model = self.getModel() + + model_wdt_mii_filter.customizeServerTemplates(model) + listen_address = model['topology']['ServerTemplate']['cluster-1-template']['ListenAddress'] + self.assertEqual('sample-domain1-managed-server${id}', listen_address, "Expected listen address to be \'sample-domain1-managed-server${id}\'") + + def test_customizeServerTemplate(self): + model = self.getModel() + topology = model['topology'] + template_name = 'cluster-1-template' + + serverTemplate = topology['ServerTemplate'][template_name] + model_wdt_mii_filter.customizeServerTemplate(topology, serverTemplate) + + # verify custom log in server template + template_log_filename = serverTemplate['Log']['FileName'] + self.assertEqual('/u01/logs/sample-domain1/managed-server${id}.log', template_log_filename, "Expected listen address to be \'/u01/logs/sample-domain1/managed-server${id}.log\'") + + # verify custom access log in server template + template_access_log = serverTemplate['WebServer']['WebServerLog']['FileName'] + self.assertEqual('/u01/logs/sample-domain1/managed-server${id}_access.log', template_access_log, "Expected listen address to be \'/u01/logs/sample-domain1/managed-server${id}.log\'") + + # verify listen address in server template + listen_address = model['topology']['ServerTemplate'][template_name]['ListenAddress'] + self.assertEqual('sample-domain1-managed-server${id}', listen_address, "Expected listen address to be \'sample-domain1-managed-server${id}\'") + + def test_getClusterOrNone_returns_none(self): + model = self.getModel() + cluster = model_wdt_mii_filter.getClusterOrNone(model, "cluster-2") + self.assertIsNone(cluster, "Did not expect to find cluster named \'cluster-2\'") + + def test_customize_node_manager_creds(self): + model = self.getModel() + model_wdt_mii_filter.initSecretManager(model_wdt_mii_filter.getOfflineWlstEnv()) + model_wdt_mii_filter.customizeNodeManagerCreds(model['topology']) + self.assertEqual(MockOfflineWlstEnv.WLS_CRED_USERNAME, model['topology']['SecurityConfiguration']['NodeManagerUsername'], "Expected node manager username to be \'" + MockOfflineWlstEnv.WLS_CRED_USERNAME + "\'") + self.assertEqual(MockOfflineWlstEnv.WLS_CRED_PASSWORD, model['topology']['SecurityConfiguration']['NodeManagerPasswordEncrypted'], "Expected node manager password to be \'" + MockOfflineWlstEnv.WLS_CRED_PASSWORD + "\'") + + def test_customizeDomainLogPath(self): + model = self.getModel() + model_wdt_mii_filter.customizeDomainLogPath(model['topology']) + self.assertEqual('/u01/logs/sample-domain1/sample-domain1.log', model['topology']['Log']['FileName'], "Expected domain log file name to be \'/u01/logs/sample-domain1/sample-domain1.log\'") + + def test_customizeLog_whenNoNameProvided(self): + model = self.getModel() + model_wdt_mii_filter.customizeLog(None, model['topology']) + self.assertNotIn('Log', model['topology'], "Did not expect \'Log\' to be configured") + + def test_customizeCustomFileStores(self): + model = self.getModel() + model_wdt_mii_filter.customizeCustomFileStores(model) + self.assertEqual('/u01/datahome', model['resources']['FileStore']['FileStore-0']['Directory'], "Expected custom filestore directory \'/u01/datahome\'") + + def test_customizeServers(self): + model = self.getModel() + model_wdt_mii_filter.customizeServers(model) + self.assertEqual('sample-domain1-admin-server', model['topology']['Server']['admin-server']['ListenAddress'], "Expected server listen address to be \'sample-domain1-admin-server\'") + + def test_readDomainNameFromTopologyYaml(self): + model = self.getModel() + model_wdt_mii_filter.env.readDomainNameFromTopologyYaml('../resources/topology.yaml') + domain_name = model_wdt_mii_filter.env.getDomainName() + self.assertEqual('wls-domain1', domain_name, "Expected domain name to be \'wls-domain1\'") + +class MockOfflineWlstEnv(model_wdt_mii_filter.OfflineWlstEnv): + + WLS_CRED_USERNAME = 'weblogic' + WLS_CRED_PASSWORD = 'password' + + def __init__(self): + model_wdt_mii_filter.OfflineWlstEnv.__init__(self) + + def encrypt(self, cleartext): + return cleartext + + def readFile(self, path): + if path.endswith('username'): + return self.WLS_CRED_USERNAME + + return self.WLS_CRED_PASSWORD + +if __name__ == '__main__': + unittest.main() diff --git a/operator/src/test/resources/model.dynamic_cluster_dict.txt b/operator/src/test/resources/model.dynamic_cluster_dict.txt new file mode 100644 index 00000000000..1937c634979 --- /dev/null +++ b/operator/src/test/resources/model.dynamic_cluster_dict.txt @@ -0,0 +1 @@ +{'appDeployments': {'Application': {'myapp': {'SourcePath': 'wlsdeploy/applications/myapp-v1', 'ModuleType': 'ear', 'Target': 'cluster-1'}}}, 'domainInfo': {'AdminUserName': 'weblogic', 'ServerStartMode': 'dev', 'AdminPassword': 'welcome1'}, 'resources': {'FileStore': {'FileStore-0': {'Directory': '/u01/oracle/customFileStore/', 'Target': 'cluster-1'}}}, 'topology': {'Cluster': {'cluster-1': {'DynamicServers': {'MinDynamicClusterSize': '0', 'CalculatedListenPorts': False, 'MaxDynamicClusterSize': '5', 'ServerNamePrefix': 'managed-server', 'DynamicClusterSize': '5', 'ServerTemplate': 'cluster-1-template'}}}, 'AdminServerName': 'admin-server', 'Server': {'admin-server': {'ListenPort': 7001}}, 'ServerTemplate': {'cluster-1-template': {'NetworkAccessPoint': {'T3Channel': {'PublicAddress': 'admin-server-public-service', 'PublicPort': 9003, 'ListenPort': 8003, 'ListenAddress': 'admin-server-service'}}, 'Cluster': 'cluster-1', 'ListenPort': 8001}}, 'Name': 'sample-domain1'}} \ No newline at end of file diff --git a/operator/src/test/resources/model.static_cluster_dict.txt b/operator/src/test/resources/model.static_cluster_dict.txt new file mode 100644 index 00000000000..037efecac23 --- /dev/null +++ b/operator/src/test/resources/model.static_cluster_dict.txt @@ -0,0 +1 @@ +{'appDeployments': {'Application': {'myapp': {'SourcePath': 'wlsdeploy/applications/myapp-v1', 'ModuleType': 'ear', 'Target': 'cluster-2'}}}, 'domainInfo': {'AdminUserName': 'weblogic', 'ServerStartMode': 'dev', 'AdminPassword': 'welcome1'}, 'resources': {'FileStore': {'FileStore-0': {'Directory': '/u01/oracle/customFileStore/', 'Target': 'cluster-2'}}}, 'topology': {'Cluster': {'cluster-2': None}, 'AdminServerName': 'admin-server', 'Name': 'sample-domain1', 'Server': {'config-cluster-server1': {'Cluster': 'cluster-2', 'ListenPort': '8001'}, 'config-cluster-server2': {'Cluster': 'cluster-2', 'ListenPort': '8001'}, 'standalone-managed': {'ListenPort': '8001'}, 'admin-server': {'ListenPort': 7001}}}} \ No newline at end of file diff --git a/operator/src/test/resources/topology.yaml b/operator/src/test/resources/topology.yaml new file mode 100644 index 00000000000..5cfa30c41d3 --- /dev/null +++ b/operator/src/test/resources/topology.yaml @@ -0,0 +1,24 @@ +domainValid: true +domain: + name: "wls-domain1" + adminServerName: "admin-server" + configuredClusters: + - name: "cluster-1" + dynamicServersConfig: + name: "NO_NAME_0" + serverTemplateName: "cluster-1-template" + calculatedListenPorts: 0 + serverNamePrefix: "managed-server" + dynamicClusterSize: 5 + maxDynamicClusterSize: 5 + minDynamicClusterSize: 1 + serverTemplates: + - name: "cluster-1-template" + listenPort: 8001 + listenAddress: "mii-dynamic-update-cluster-1-template" + clusterName: "cluster-1" + servers: + - name: "admin-server" + listenPort: 7001 + listenAddress: "mii-dynamic-update-admin-server" +