diff --git a/documentation/domains/Domain.json b/documentation/domains/Domain.json index 6e8f0592e09..f3ca364afd3 100644 --- a/documentation/domains/Domain.json +++ b/documentation/domains/Domain.json @@ -618,6 +618,10 @@ "x-kubernetes-preserve-unknown-fields": "true", "description": "The configuration for the WebLogic Monitoring Exporter. If WebLogic Server instances are already running and have the monitoring exporter sidecar container, then changes to this field will be propagated to the exporter without requiring the restart of the WebLogic Server instances.", "$ref": "#/definitions/Map" + }, + "port": { + "description": "The port exposed by the WebLogic Monitoring Exporter running in the sidecar container. Defaults to 8080. The port value must not conflict with a port used by any WebLogic Server instance, including the ports of built-in channels or network access points (NAPs).", + "type": "number" } } }, diff --git a/documentation/domains/Domain.md b/documentation/domains/Domain.md index a725ca93190..ff2a2ef36a2 100644 --- a/documentation/domains/Domain.md +++ b/documentation/domains/Domain.md @@ -119,6 +119,7 @@ The current status of the operation of the WebLogic domain. Updated automaticall | `configuration` | Map | The configuration for the WebLogic Monitoring Exporter. If WebLogic Server instances are already running and have the monitoring exporter sidecar container, then changes to this field will be propagated to the exporter without requiring the restart of the WebLogic Server instances. | | `image` | string | The WebLogic Monitoring Exporter sidecar container image name. Defaults to ghcr.io/oracle/weblogic-monitoring-exporter:2.0.2 | | `imagePullPolicy` | string | The image pull policy for the WebLogic Monitoring Exporter sidecar container image. Legal values are Always, Never, and IfNotPresent. Defaults to Always if image ends in :latest; IfNotPresent, otherwise. | +| `port` | number | The port exposed by the WebLogic Monitoring Exporter running in the sidecar container. Defaults to 8080. The port value must not conflict with a port used by any WebLogic Server instance, including the ports of built-in channels or network access points (NAPs). | ### Server Pod diff --git a/documentation/domains/index.html b/documentation/domains/index.html index 40697bb9d4b..6634c70976c 100644 --- a/documentation/domains/index.html +++ b/documentation/domains/index.html @@ -1539,6 +1539,10 @@ "x-kubernetes-preserve-unknown-fields": "true", "description": "The configuration for the WebLogic Monitoring Exporter. If WebLogic Server instances are already running and have the monitoring exporter sidecar container, then changes to this field will be propagated to the exporter without requiring the restart of the WebLogic Server instances.", "$ref": "#/definitions/Map" + }, + "port": { + "description": "The port exposed by the WebLogic Monitoring Exporter running in the sidecar container. Defaults to 8080 unless that port value is in use by a channel or network access point (NAP) of the WebLogic Server instance, in which case the next higher available port is selected. If a port value is specified then it must not conflict with a port used by the WebLogic Server instance.", + "type": "number" } } }, diff --git a/kubernetes/crd/domain-crd.yaml b/kubernetes/crd/domain-crd.yaml index 40e2d5e510a..838b81c43de 100644 --- a/kubernetes/crd/domain-crd.yaml +++ b/kubernetes/crd/domain-crd.yaml @@ -5,7 +5,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - weblogic.sha256: e091b25f525f2d1a6b90729dcee23d63ead5beb23660912acebf921d1c0499a7 + weblogic.sha256: d1191a10f1c4843d11c897002f731292c9f580c6670a84e1ee8b5916e21f0a62 name: domains.weblogic.oracle spec: group: weblogic.oracle @@ -59,6 +59,13 @@ spec: restart of the WebLogic Server instances. type: object x-kubernetes-preserve-unknown-fields: true + port: + description: The port exposed by the WebLogic Monitoring Exporter + running in the sidecar container. Defaults to 8080. The port + value must not conflict with a port used by any WebLogic Server + instance, including the ports of built-in channels or network + access points (NAPs). + type: number type: object configuration: description: Models and overrides affecting the WebLogic domain configuration. diff --git a/operator/src/main/java/oracle/kubernetes/operator/helpers/DomainValidationSteps.java b/operator/src/main/java/oracle/kubernetes/operator/helpers/DomainValidationSteps.java index d90566f9760..fc02dab3667 100644 --- a/operator/src/main/java/oracle/kubernetes/operator/helpers/DomainValidationSteps.java +++ b/operator/src/main/java/oracle/kubernetes/operator/helpers/DomainValidationSteps.java @@ -25,7 +25,10 @@ import oracle.kubernetes.operator.logging.LoggingFactory; import oracle.kubernetes.operator.logging.MessageKeys; import oracle.kubernetes.operator.steps.DefaultResponseStep; +import oracle.kubernetes.operator.wlsconfig.WlsClusterConfig; import oracle.kubernetes.operator.wlsconfig.WlsDomainConfig; +import oracle.kubernetes.operator.wlsconfig.WlsDynamicServersConfig; +import oracle.kubernetes.operator.wlsconfig.WlsServerConfig; import oracle.kubernetes.operator.work.NextAction; import oracle.kubernetes.operator.work.Packet; import oracle.kubernetes.operator.work.Step; @@ -192,6 +195,16 @@ private void validate(DomainPresenceInfo info, WlsDomainConfig wlsDomainConfig) // in the WebLogic domain domainSpec.getManagedServers().forEach( s -> warnIfServerDoesNotExist(wlsDomainConfig, s.getServerName(), info)); + + // log warning if monitoring exporter port is specified and it conflicts with a server port + Optional.ofNullable(domainSpec.getMonitoringExporterPort()).ifPresent(port -> { + wlsDomainConfig.getServerConfigs().values() + .forEach(server -> warnIfMonitoringExporterPortConflicts(port, server, info)); + wlsDomainConfig.getClusterConfigs().values() + .forEach(cluster -> Optional.ofNullable(cluster.getDynamicServersConfig()) + .map(WlsDynamicServersConfig::getServerTemplate) + .ifPresent(template -> warnIfMonitoringExporterPortConflicts(port, cluster, template, info))); + }); } private void warnIfClusterDoesNotExist(WlsDomainConfig domainConfig, @@ -208,6 +221,43 @@ private void warnIfServerDoesNotExist(WlsDomainConfig domainConfig, } } + private void warnIfMonitoringExporterPortConflicts( + Integer port, WlsServerConfig serverConfig, DomainPresenceInfo info) { + warnIfMonitoringExporterPortConflicts(port, null, serverConfig, info); + } + + private void warnIfMonitoringExporterPortConflicts( + Integer port, WlsClusterConfig cluster, WlsServerConfig serverConfig, DomainPresenceInfo info) { + + if (port.equals(serverConfig.getListenPort())) { + logAndAddValidationWarningExporter(port, cluster, serverConfig, serverConfig.getListenPort(), info); + } + if (port.equals(serverConfig.getSslListenPort())) { + logAndAddValidationWarningExporter(port, cluster, serverConfig, serverConfig.getSslListenPort(), info); + } + if (port.equals(serverConfig.getAdminPort())) { + logAndAddValidationWarningExporter(port, cluster, serverConfig, serverConfig.getAdminPort(), info); + } + Optional.ofNullable(serverConfig.getNetworkAccessPoints()).ifPresent(naps -> naps.forEach(nap -> { + if (port.equals(nap.getListenPort())) { + logAndAddValidationWarningExporter(port, cluster, serverConfig, nap.getListenPort(), info); + } + })); + } + + private void logAndAddValidationWarningExporter( + Integer port, WlsClusterConfig cluster, WlsServerConfig serverConfig, + Integer conflictPort, DomainPresenceInfo info) { + if (cluster != null) { + logAndAddValidationWarning(info, MessageKeys.MONITORING_EXPORTER_CONFLICT_DYNAMIC_CLUSTER, + // Note: Using Integer.toString because default logger behavior formats with commas, e.g. "7,001" + Integer.toString(port), cluster.getClusterName(), Integer.toString(conflictPort)); + } else { + logAndAddValidationWarning(info, MessageKeys.MONITORING_EXPORTER_CONFLICT_SERVER, + Integer.toString(port), serverConfig.getName(), Integer.toString(conflictPort)); + } + } + @Override public NextAction apply(Packet packet) { DomainPresenceInfo info = packet.getSpi(DomainPresenceInfo.class); 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 e18b3af8b5c..d5b0e4de9f2 100644 --- a/operator/src/main/java/oracle/kubernetes/operator/helpers/PodStepContext.java +++ b/operator/src/main/java/oracle/kubernetes/operator/helpers/PodStepContext.java @@ -155,7 +155,8 @@ private Step getConflictStep() { } ExporterContext createExporterContext() { - return useSidecar() ? new SidecarExporterContext() : new WebAppExporterContext(); + return useSidecar() + ? new SidecarExporterContext(getMonitoringExporterSpecification()) : new WebAppExporterContext(); } // Use the monitoring exporter sidecar if an exporter configuration is part of the domain. @@ -219,6 +220,10 @@ Integer getAsPort() { .getLocalAdminProtocolChannelPort(); } + MonitoringExporterSpecification getMonitoringExporterSpecification() { + return getDomain().getMonitoringExporterSpecification(); + } + /** * Check if the server is listening on a secure port. NOTE: If the targeted server is a managed * server, this method is overridden to check if the managed server has a secure listen port rather @@ -1295,11 +1300,10 @@ void addContainer(List containers) { } class SidecarExporterContext extends ExporterContext { - private static final int DEBUG_PORT = 30055; private final int metricsPort; - public SidecarExporterContext() { - metricsPort = MonitoringExporterSpecification.getRestPort(scan); + public SidecarExporterContext(MonitoringExporterSpecification specification) { + metricsPort = specification.getRestPort(); } @Override @@ -1328,8 +1332,12 @@ private V1Container createMonitoringExporterContainer() { .image(getDomain().getMonitoringExporterImage()) .imagePullPolicy(getDomain().getMonitoringExporterImagePullPolicy()) .addEnvItem(new V1EnvVar().name("JAVA_OPTS").value(createJavaOptions())) - .addPortsItem(new V1ContainerPort().name("metrics").protocol("TCP").containerPort(getPort())) - .addPortsItem(new V1ContainerPort().name("debugger").protocol("TCP").containerPort(DEBUG_PORT)); + .addPortsItem(new V1ContainerPort() + .name(getMetricsPortName()).protocol("TCP").containerPort(getPort())); + } + + private String getMetricsPortName() { + return getDomain().isIstioEnabled() ? "http-metrics" : "metrics"; } private String createJavaOptions() { @@ -1342,13 +1350,8 @@ private String createJavaOptions() { if (metricsPort != DEFAULT_EXPORTER_SIDECAR_PORT) { args.add("-DEXPORTER_PORT=" + metricsPort); } - args.add(getDebugOption()); return String.join(" ", args); } - - private String getDebugOption() { - return "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:" + DEBUG_PORT; - } } } diff --git a/operator/src/main/java/oracle/kubernetes/operator/helpers/ServiceHelper.java b/operator/src/main/java/oracle/kubernetes/operator/helpers/ServiceHelper.java index 77cce5d10b8..918976ac492 100644 --- a/operator/src/main/java/oracle/kubernetes/operator/helpers/ServiceHelper.java +++ b/operator/src/main/java/oracle/kubernetes/operator/helpers/ServiceHelper.java @@ -42,7 +42,6 @@ import oracle.kubernetes.weblogic.domain.model.Channel; import oracle.kubernetes.weblogic.domain.model.ClusterSpec; import oracle.kubernetes.weblogic.domain.model.Domain; -import oracle.kubernetes.weblogic.domain.model.MonitoringExporterSpecification; import oracle.kubernetes.weblogic.domain.model.ServerSpec; import org.apache.commons.lang3.builder.EqualsBuilder; @@ -62,7 +61,6 @@ import static oracle.kubernetes.operator.logging.MessageKeys.MANAGED_SERVICE_CREATED; import static oracle.kubernetes.operator.logging.MessageKeys.MANAGED_SERVICE_EXISTS; import static oracle.kubernetes.operator.logging.MessageKeys.MANAGED_SERVICE_REPLACED; -import static oracle.kubernetes.weblogic.domain.model.MonitoringExporterSpecification.EXPORTER_PORT_NAME; public class ServiceHelper { public static final String CLUSTER_IP_TYPE = "ClusterIP"; @@ -420,9 +418,15 @@ void addServicePorts(List ports, WlsServerConfig serverConfig) { addServicePortIfNeeded(ports, "default-admin", serverConfig.getAdminPort()); } - if (getDomain().getMonitoringExporterConfiguration() != null) { - addServicePortIfNeeded(ports, EXPORTER_PORT_NAME, MonitoringExporterSpecification.getRestPort(serverConfig)); - } + Optional.ofNullable(getDomain().getMonitoringExporterSpecification()).ifPresent(specification -> { + if (specification.getConfiguration() != null) { + addServicePortIfNeeded(ports, getMetricsPortName(), specification.getRestPort()); + } + }); + } + + private String getMetricsPortName() { + return getDomain().isIstioEnabled() ? "http-metrics" : "metrics"; } List getNetworkAccessPoints(@Nonnull WlsServerConfig config) { diff --git a/operator/src/main/java/oracle/kubernetes/operator/logging/MessageKeys.java b/operator/src/main/java/oracle/kubernetes/operator/logging/MessageKeys.java index 6269c9ecfdb..b73ee66d0c7 100644 --- a/operator/src/main/java/oracle/kubernetes/operator/logging/MessageKeys.java +++ b/operator/src/main/java/oracle/kubernetes/operator/logging/MessageKeys.java @@ -168,6 +168,8 @@ public class MessageKeys { public static final String DUPLICATE_COMMON_MOUNT_PATH_FOUND = "WLSDO-0024"; public static final String DUPLICATE_COMMON_MOUNT_VOLUME_FOUND = "WLSDO-0025"; public static final String COMMON_MOUNT_VOLUME_NAME_NOT_DEFINED = "WLSDO-0026"; + public static final String MONITORING_EXPORTER_CONFLICT_SERVER = "WLSDO-0027"; + public static final String MONITORING_EXPORTER_CONFLICT_DYNAMIC_CLUSTER = "WLSDO-0028"; private MessageKeys() { } diff --git a/operator/src/main/java/oracle/kubernetes/operator/steps/MonitoringExporterSteps.java b/operator/src/main/java/oracle/kubernetes/operator/steps/MonitoringExporterSteps.java index 04bb0fad04a..7d8c81c62a1 100644 --- a/operator/src/main/java/oracle/kubernetes/operator/steps/MonitoringExporterSteps.java +++ b/operator/src/main/java/oracle/kubernetes/operator/steps/MonitoringExporterSteps.java @@ -35,7 +35,6 @@ import static oracle.kubernetes.operator.ProcessingConstants.SERVER_NAME; import static oracle.kubernetes.operator.steps.HttpRequestProcessing.createRequestStep; -import static oracle.kubernetes.weblogic.domain.model.MonitoringExporterSpecification.EXPORTER_PORT_NAME; public class MonitoringExporterSteps { @@ -235,9 +234,11 @@ public NextAction apply(Packet packet) { } private static class ExporterRequestProcessing extends HttpRequestProcessing { + private final DomainPresenceInfo info; ExporterRequestProcessing(Packet packet) { super(packet, getServerService(packet), getServerPod(packet)); + info = packet.getSpi(DomainPresenceInfo.class); } private static V1Service getServerService(Packet packet) { @@ -269,7 +270,15 @@ private List getServicePorts() { } private boolean isExporterPort(V1ServicePort servicePort) { - return EXPORTER_PORT_NAME.equals(servicePort.getName()); + return getMetricsPortName().equals(servicePort.getName()); + } + + Domain getDomain() { + return info.getDomain(); + } + + private String getMetricsPortName() { + return getDomain().isIstioEnabled() ? "http-metrics" : "metrics"; } private HttpRequest createConfigurationQueryRequest() { diff --git a/operator/src/main/java/oracle/kubernetes/operator/wlsconfig/WlsDynamicServersConfig.java b/operator/src/main/java/oracle/kubernetes/operator/wlsconfig/WlsDynamicServersConfig.java index 551d06ed13e..04c8cccc4b5 100644 --- a/operator/src/main/java/oracle/kubernetes/operator/wlsconfig/WlsDynamicServersConfig.java +++ b/operator/src/main/java/oracle/kubernetes/operator/wlsconfig/WlsDynamicServersConfig.java @@ -269,6 +269,10 @@ public WlsServerConfig getServerTemplate() { return serverTemplate; } + public void setServerTemplate(WlsServerConfig serverTemplate) { + this.serverTemplate = serverTemplate; + } + public String getName() { return this.name; } diff --git a/operator/src/main/java/oracle/kubernetes/weblogic/domain/DomainConfigurator.java b/operator/src/main/java/oracle/kubernetes/weblogic/domain/DomainConfigurator.java index 353cbef9b1b..3b2be760b1a 100644 --- a/operator/src/main/java/oracle/kubernetes/weblogic/domain/DomainConfigurator.java +++ b/operator/src/main/java/oracle/kubernetes/weblogic/domain/DomainConfigurator.java @@ -303,6 +303,8 @@ protected DomainSpec getDomainSpec() { public abstract DomainConfigurator withMonitoringExporterImage(String imageName); + public abstract DomainConfigurator withMonitoringExporterPort(Integer port); + /** * Adds a default server configuration to the domain, if not already present. * diff --git a/operator/src/main/java/oracle/kubernetes/weblogic/domain/model/Domain.java b/operator/src/main/java/oracle/kubernetes/weblogic/domain/model/Domain.java index c88263e515c..94de97bdf4b 100644 --- a/operator/src/main/java/oracle/kubernetes/weblogic/domain/model/Domain.java +++ b/operator/src/main/java/oracle/kubernetes/weblogic/domain/model/Domain.java @@ -274,6 +274,10 @@ public MonitoringExporterConfiguration getMonitoringExporterConfiguration() { return spec.getMonitoringExporterConfiguration(); } + public MonitoringExporterSpecification getMonitoringExporterSpecification() { + return spec.getMonitoringExporterSpecification(); + } + public String getMonitoringExporterImage() { return spec.getMonitoringExporterImage(); } diff --git a/operator/src/main/java/oracle/kubernetes/weblogic/domain/model/DomainCommonConfigurator.java b/operator/src/main/java/oracle/kubernetes/weblogic/domain/model/DomainCommonConfigurator.java index 1076c28e3d4..774fb8c9444 100644 --- a/operator/src/main/java/oracle/kubernetes/weblogic/domain/model/DomainCommonConfigurator.java +++ b/operator/src/main/java/oracle/kubernetes/weblogic/domain/model/DomainCommonConfigurator.java @@ -176,6 +176,12 @@ public DomainConfigurator withMonitoringExporterImage(String imageName) { return this; } + @Override + public DomainConfigurator withMonitoringExporterPort(Integer port) { + getDomainSpec().setMonitoringExporterPort(port); + return this; + } + private AdminServer getOrCreateAdminServer() { return getDomainSpec().getOrCreateAdminServer(); } diff --git a/operator/src/main/java/oracle/kubernetes/weblogic/domain/model/DomainSpec.java b/operator/src/main/java/oracle/kubernetes/weblogic/domain/model/DomainSpec.java index baf809fa836..93ef4d95125 100644 --- a/operator/src/main/java/oracle/kubernetes/weblogic/domain/model/DomainSpec.java +++ b/operator/src/main/java/oracle/kubernetes/weblogic/domain/model/DomainSpec.java @@ -321,6 +321,10 @@ public class DomainSpec extends BaseConfiguration { + "have the exporter sidecar or not, as appropriate. See https://github.com/oracle/weblogic-monitoring-exporter.") private MonitoringExporterSpecification monitoringExporter; + public MonitoringExporterSpecification getMonitoringExporterSpecification() { + return monitoringExporter; + } + MonitoringExporterConfiguration getMonitoringExporterConfiguration() { return Optional.ofNullable(monitoringExporter).map(MonitoringExporterSpecification::getConfiguration).orElse(null); } @@ -341,6 +345,10 @@ String getMonitoringExporterImagePullPolicy() { return monitoringExporter == null ? null : monitoringExporter.getImagePullPolicy(); } + public Integer getMonitoringExporterPort() { + return monitoringExporter == null ? null : monitoringExporter.getPort(); + } + /** * Specifies the image for the monitoring exporter sidecar. * @param imageName the name of the docker image @@ -361,6 +369,16 @@ public void setMonitoringExporterImagePullPolicy(String pullPolicy) { monitoringExporter.setImagePullPolicy(pullPolicy); } + /** + * Specifies the port for the exporter sidecar. + * @param port port number + */ + public void setMonitoringExporterPort(Integer port) { + assert monitoringExporter != null : "May not set exporter port without configuration"; + + monitoringExporter.setPort(port); + } + /** * The configuration for the admin server. * diff --git a/operator/src/main/java/oracle/kubernetes/weblogic/domain/model/MonitoringExporterSpecification.java b/operator/src/main/java/oracle/kubernetes/weblogic/domain/model/MonitoringExporterSpecification.java index 8ef0836792b..5ba11b96fa0 100644 --- a/operator/src/main/java/oracle/kubernetes/weblogic/domain/model/MonitoringExporterSpecification.java +++ b/operator/src/main/java/oracle/kubernetes/weblogic/domain/model/MonitoringExporterSpecification.java @@ -3,11 +3,8 @@ package oracle.kubernetes.weblogic.domain.model; -import java.util.HashSet; import java.util.Map; import java.util.Optional; -import java.util.Set; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import com.google.gson.Gson; @@ -16,7 +13,6 @@ import oracle.kubernetes.json.PreserveUnknown; import oracle.kubernetes.operator.ImagePullPolicy; import oracle.kubernetes.operator.helpers.KubernetesUtils; -import oracle.kubernetes.operator.wlsconfig.WlsServerConfig; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.ToStringBuilder; @@ -27,7 +23,6 @@ public class MonitoringExporterSpecification { - public static final String EXPORTER_PORT_NAME = "exporter"; @Description("The configuration for the WebLogic Monitoring Exporter. If WebLogic Server instances " + "are already running and have the monitoring exporter sidecar container, then changes to this field will " + "be propagated to the exporter without requiring the restart of the WebLogic Server instances.") @@ -49,30 +44,21 @@ public class MonitoringExporterSpecification { @EnumClass(ImagePullPolicy.class) private String imagePullPolicy; + @Description( + "The port exposed by the WebLogic Monitoring Exporter running in the sidecar container. " + + "Defaults to 8080. The port value must not conflict with a port used by any WebLogic Server " + + "instance, including the ports of built-in channels or network access points (NAPs).") + private Integer port; + /** - * Computes the REST port for the specified server. This port will be used by the + * Computes the REST port. This port will be used by the * metrics exporter to query runtime data. - * @param serverConfig the configuration for a server */ - public static int getRestPort(WlsServerConfig serverConfig) { - int restPort = DEFAULT_EXPORTER_SIDECAR_PORT; - final Set webLogicPorts = getWebLogicPorts(serverConfig); - while (webLogicPorts.contains(restPort)) { - restPort++; - } - return restPort; - } - - @Nonnull - private static Set getWebLogicPorts(WlsServerConfig serverConfig) { - final Set ports = new HashSet<>(); - Optional.ofNullable(serverConfig.getListenPort()).ifPresent(ports::add); - Optional.ofNullable(serverConfig.getSslListenPort()).ifPresent(ports::add); - Optional.ofNullable(serverConfig.getAdminPort()).ifPresent(ports::add); - return ports; + public int getRestPort() { + return Optional.ofNullable(port).orElse(DEFAULT_EXPORTER_SIDECAR_PORT); } - MonitoringExporterConfiguration getConfiguration() { + public MonitoringExporterConfiguration getConfiguration() { return Optional.ofNullable(configuration).map(this::toJson).map(this::toConfiguration).orElse(null); } @@ -108,12 +94,21 @@ void setImagePullPolicy(@Nullable String imagePullPolicy) { this.imagePullPolicy = imagePullPolicy; } + Integer getPort() { + return port; + } + + void setPort(Integer port) { + this.port = port; + } + @Override public String toString() { return new ToStringBuilder(this) .append("configuration", configuration) .append("image", image) .append("imagePullPolicy", imagePullPolicy) + .append("port", port) .toString(); } @@ -128,6 +123,7 @@ private boolean equals(MonitoringExporterSpecification that) { .append(configuration, that.configuration) .append(image, that.image) .append(imagePullPolicy, that.imagePullPolicy) + .append(port, that.port) .isEquals(); } @@ -137,6 +133,7 @@ public int hashCode() { .append(configuration) .append(image) .append(imagePullPolicy) + .append(port) .toHashCode(); } } diff --git a/operator/src/main/resources/Operator.properties b/operator/src/main/resources/Operator.properties index b63e1e3f61d..87d432e3c77 100644 --- a/operator/src/main/resources/Operator.properties +++ b/operator/src/main/resources/Operator.properties @@ -177,6 +177,8 @@ WLSDO-0024=More than one item under ''spec.commonMountVolumes'' in the domain re WLSDO-0025=More than one item under ''spec.commonMountVolumes'' in the domain resource has same DNS-1123 name ''{0}''. WLSDO-0026=An item under ''spec.commonMountVolumes'' in the domain resource does not have a name. A name is required for \ the common mount volumes defined under ''spec.commonMountVolumes''. +WLSDO-0027=The Monitoring Exporter port ''{0}'' specified by ''spec.monitoringExporter.port'' conflicts with WebLogic Server instance ''{1}'' port ''{2}'' +WLSDO-0028=The Monitoring Exporter port ''{0}'' specified by ''spec.monitoringExporter.port'' conflicts with Cluster ''{1}'' dynamic server template port ''{2}'' oneEnvVar=variable multipleEnvVars=variables diff --git a/operator/src/test/java/oracle/kubernetes/operator/helpers/DomainValidationStepTest.java b/operator/src/test/java/oracle/kubernetes/operator/helpers/DomainValidationStepTest.java index 668588121ec..73a6526a523 100644 --- a/operator/src/test/java/oracle/kubernetes/operator/helpers/DomainValidationStepTest.java +++ b/operator/src/test/java/oracle/kubernetes/operator/helpers/DomainValidationStepTest.java @@ -27,9 +27,12 @@ import oracle.kubernetes.operator.logging.LoggingFactory; import oracle.kubernetes.operator.logging.MessageKeys; import oracle.kubernetes.operator.utils.WlsDomainConfigSupport; +import oracle.kubernetes.operator.wlsconfig.WlsDomainConfig; import oracle.kubernetes.operator.work.Step; import oracle.kubernetes.operator.work.TerminalStep; import oracle.kubernetes.utils.TestUtils; +import oracle.kubernetes.weblogic.domain.DomainConfigurator; +import oracle.kubernetes.weblogic.domain.DomainConfiguratorFactory; import oracle.kubernetes.weblogic.domain.model.Cluster; import oracle.kubernetes.weblogic.domain.model.Configuration; import oracle.kubernetes.weblogic.domain.model.ConfigurationConstants; @@ -51,6 +54,8 @@ import static oracle.kubernetes.operator.helpers.KubernetesTestSupport.DOMAIN; import static oracle.kubernetes.operator.helpers.ServiceHelperTestBase.NS; import static oracle.kubernetes.operator.logging.MessageKeys.DOMAIN_VALIDATION_FAILED; +import static oracle.kubernetes.operator.logging.MessageKeys.MONITORING_EXPORTER_CONFLICT_DYNAMIC_CLUSTER; +import static oracle.kubernetes.operator.logging.MessageKeys.MONITORING_EXPORTER_CONFLICT_SERVER; import static oracle.kubernetes.operator.logging.MessageKeys.NO_CLUSTER_IN_DOMAIN; import static oracle.kubernetes.operator.logging.MessageKeys.NO_MANAGED_SERVER_IN_DOMAIN; import static oracle.kubernetes.utils.LogMatcher.containsSevere; @@ -74,6 +79,15 @@ public class DomainValidationStepTest { private static final String TEST_SECRET_PREFIX = "TEST_SECRET"; private static final String TEST_CONFIGMAP_PREFIX = "TEST_CM"; + private static final String ADMIN_SERVER = "admin-server"; + private static final String MANAGED_SERVER1 = "managed-server1"; + private static final String DYNAMIC_CLUSTER_NAME = "dyn-cluster-1"; + private static final String SERVER_TEMPLATE_NAME = "server-template"; + private static final String DOMAIN_NAME = "domain"; + private static final int ADMIN_SERVER_PORT_NUM = 7001; + private static final int MANAGED_SERVER1_PORT_NUM = 8001; + private static final int SERVER_TEMPLATE_PORT_NUM = 9001; + private final Domain domain = DomainProcessorTestSetup.createTestDomain(); private final DomainPresenceInfo info = new DomainPresenceInfo(domain); private final TerminalStep terminalStep = new TerminalStep(); @@ -81,7 +95,14 @@ public class DomainValidationStepTest { private final List mementos = new ArrayList<>(); private final List logRecords = new ArrayList<>(); private TestUtils.ConsoleHandlerMemento consoleControl; - private final WlsDomainConfigSupport configSupport = new WlsDomainConfigSupport("mydomain"); + private final WlsDomainConfig domainConfig = + new WlsDomainConfigSupport(DOMAIN_NAME) + .withAdminServerName(ADMIN_SERVER) + .withWlsServer(ADMIN_SERVER, ADMIN_SERVER_PORT_NUM) + .withWlsServer(MANAGED_SERVER1, MANAGED_SERVER1_PORT_NUM) + .withDynamicWlsCluster(DYNAMIC_CLUSTER_NAME, SERVER_TEMPLATE_NAME, SERVER_TEMPLATE_PORT_NUM) + .createDomainConfig(); + private final Map> domainEventObjects = new ConcurrentHashMap<>(); private final Map nsEventObjects = new ConcurrentHashMap<>(); @@ -91,7 +112,8 @@ public class DomainValidationStepTest { @BeforeEach public void setUp() throws Exception { consoleControl = TestUtils.silenceOperatorLogger().collectLogMessages(logRecords, DOMAIN_VALIDATION_FAILED, - NO_CLUSTER_IN_DOMAIN, NO_MANAGED_SERVER_IN_DOMAIN); + NO_CLUSTER_IN_DOMAIN, NO_MANAGED_SERVER_IN_DOMAIN, + MONITORING_EXPORTER_CONFLICT_DYNAMIC_CLUSTER, MONITORING_EXPORTER_CONFLICT_SERVER); mementos.add(consoleControl); mementos.add(testSupport.install()); @@ -340,7 +362,7 @@ private V1ConfigMap createConfigMap(String cm) { @Test public void whenClusterDoesNotExistInDomain_logWarning() { domain.getSpec().withCluster(createCluster("no-such-cluster")); - testSupport.addToPacket(DOMAIN_TOPOLOGY, configSupport.createDomainConfig()); + testSupport.addToPacket(DOMAIN_TOPOLOGY, domainConfig); testSupport.runSteps(topologyValidationStep); @@ -352,7 +374,7 @@ public void whenClusterDoesNotExistInDomain_logWarning() { @Test public void whenServerDoesNotExistInDomain_logWarning() { domain.getSpec().getManagedServers().add(new ManagedServer().withServerName("no-such-server")); - testSupport.addToPacket(DOMAIN_TOPOLOGY, configSupport.createDomainConfig()); + testSupport.addToPacket(DOMAIN_TOPOLOGY, domainConfig); testSupport.runSteps(topologyValidationStep); @@ -361,11 +383,64 @@ public void whenServerDoesNotExistInDomain_logWarning() { stringContainsInOrder("Managed Server", "no-such-server", "does not exist")); } + private DomainConfigurator configureDomain(Domain domain) { + return DomainConfiguratorFactory.forDomain(domain); + } + + @Test + public void whenMonitoringExporterPortConflictsWithAdminServerPort_logWarningAndGenerateEvent() { + configureDomain(domain).withMonitoringExporterConfiguration("queries:\n").withMonitoringExporterPort(7001); + testSupport.addToPacket(DOMAIN_TOPOLOGY, domainConfig); + + testSupport.runSteps(topologyValidationStep); + + assertThat(logRecords, containsWarning(MessageKeys.MONITORING_EXPORTER_CONFLICT_SERVER)); + assertThat(info.getValidationWarningsAsString(), + stringContainsInOrder(Integer.toString(7001), ADMIN_SERVER, Integer.toString(ADMIN_SERVER_PORT_NUM))); + + assertContainsEventWithFormattedMessage( + getFormattedMessage(MONITORING_EXPORTER_CONFLICT_SERVER, + Integer.toString(7001), ADMIN_SERVER, Integer.toString(ADMIN_SERVER_PORT_NUM))); + } + + @Test + public void whenMonitoringExporterPortConflictsWithManagedServerPort_logWarningAndGenerateEvent() { + configureDomain(domain).withMonitoringExporterConfiguration("queries:\n").withMonitoringExporterPort(8001); + testSupport.addToPacket(DOMAIN_TOPOLOGY, domainConfig); + + testSupport.runSteps(topologyValidationStep); + + assertThat(logRecords, containsWarning(MessageKeys.MONITORING_EXPORTER_CONFLICT_SERVER)); + assertThat(info.getValidationWarningsAsString(), + stringContainsInOrder(Integer.toString(8001), MANAGED_SERVER1, Integer.toString(MANAGED_SERVER1_PORT_NUM))); + + assertContainsEventWithFormattedMessage( + getFormattedMessage(MONITORING_EXPORTER_CONFLICT_SERVER, + Integer.toString(8001), MANAGED_SERVER1, Integer.toString(MANAGED_SERVER1_PORT_NUM))); + } + + @Test + public void whenMonitoringExporterPortConflictsWithClusterServerTemplatePort_logWarningAndGenerateEvent() { + configureDomain(domain).withMonitoringExporterConfiguration("queries:\n").withMonitoringExporterPort(9001); + testSupport.addToPacket(DOMAIN_TOPOLOGY, domainConfig); + + testSupport.runSteps(topologyValidationStep); + + assertThat(logRecords, containsWarning(MessageKeys.MONITORING_EXPORTER_CONFLICT_DYNAMIC_CLUSTER)); + assertThat(info.getValidationWarningsAsString(), + stringContainsInOrder(Integer.toString(9001), DYNAMIC_CLUSTER_NAME, + Integer.toString(SERVER_TEMPLATE_PORT_NUM))); + + assertContainsEventWithFormattedMessage( + getFormattedMessage(MONITORING_EXPORTER_CONFLICT_DYNAMIC_CLUSTER, + Integer.toString(9001), DYNAMIC_CLUSTER_NAME, Integer.toString(SERVER_TEMPLATE_PORT_NUM))); + } + @Test public void whenServerDoesNotExistInDomain_createEvent() { consoleControl.ignoreMessage(NO_MANAGED_SERVER_IN_DOMAIN); domain.getSpec().getManagedServers().add(new ManagedServer().withServerName("no-such-server")); - testSupport.addToPacket(DOMAIN_TOPOLOGY, configSupport.createDomainConfig()); + testSupport.addToPacket(DOMAIN_TOPOLOGY, domainConfig); testSupport.runSteps(topologyValidationStep); @@ -376,7 +451,7 @@ public void whenServerDoesNotExistInDomain_createEvent() { public void whenClusterDoesNotExistInDomain_createEvent() { consoleControl.ignoreMessage(NO_CLUSTER_IN_DOMAIN); domain.getSpec().withCluster(createCluster("no-such-cluster")); - testSupport.addToPacket(DOMAIN_TOPOLOGY, configSupport.createDomainConfig()); + testSupport.addToPacket(DOMAIN_TOPOLOGY, domainConfig); testSupport.runSteps(topologyValidationStep); @@ -389,7 +464,7 @@ public void whenBothServerAndClusterDoNotExistInDomain_createEventWithBothWarnin consoleControl.ignoreMessage(NO_CLUSTER_IN_DOMAIN); domain.getSpec().getManagedServers().add(new ManagedServer().withServerName("no-such-server")); domain.getSpec().withCluster(createCluster("no-such-cluster")); - testSupport.addToPacket(DOMAIN_TOPOLOGY, configSupport.createDomainConfig()); + testSupport.addToPacket(DOMAIN_TOPOLOGY, domainConfig); testSupport.runSteps(topologyValidationStep); @@ -402,7 +477,7 @@ public void whenIsExplicitRecheck_doNotCreateEvent() { consoleControl.ignoreMessage(NO_CLUSTER_IN_DOMAIN); setExplicitRecheck(); domain.getSpec().withCluster(createCluster("no-such-cluster")); - testSupport.addToPacket(DOMAIN_TOPOLOGY, configSupport.createDomainConfig()); + testSupport.addToPacket(DOMAIN_TOPOLOGY, domainConfig); testSupport.runSteps(topologyValidationStep); diff --git a/operator/src/test/java/oracle/kubernetes/operator/helpers/ManagerServerServiceHelperTest.java b/operator/src/test/java/oracle/kubernetes/operator/helpers/ManagerServerServiceHelperTest.java index dd275dd6cde..056b03d51bb 100644 --- a/operator/src/test/java/oracle/kubernetes/operator/helpers/ManagerServerServiceHelperTest.java +++ b/operator/src/test/java/oracle/kubernetes/operator/helpers/ManagerServerServiceHelperTest.java @@ -11,7 +11,6 @@ import static oracle.kubernetes.operator.logging.MessageKeys.MANAGED_SERVICE_CREATED; import static oracle.kubernetes.operator.logging.MessageKeys.MANAGED_SERVICE_EXISTS; import static oracle.kubernetes.operator.logging.MessageKeys.MANAGED_SERVICE_REPLACED; -import static oracle.kubernetes.weblogic.domain.model.MonitoringExporterSpecification.EXPORTER_PORT_NAME; import static org.hamcrest.junit.MatcherAssert.assertThat; public class ManagerServerServiceHelperTest extends ServiceHelperTest { @@ -66,6 +65,24 @@ void whenDomainHasMonitoringExporterConfiguration_serviceHasExporterPort() { V1Service service = createService(); - assertThat(service, containsPort(EXPORTER_PORT_NAME, DEFAULT_EXPORTER_SIDECAR_PORT)); + assertThat(service, containsPort("metrics", DEFAULT_EXPORTER_SIDECAR_PORT)); + } + + @Test + void whenDomainHasMonitoringExporterConfigurationWithPort_serviceHasExporterPort() { + configureDomain().withMonitoringExporterConfiguration("queries:\n").withMonitoringExporterPort(300); + + V1Service service = createService(); + + assertThat(service, containsPort("metrics", 300)); + } + + @Test + void whenDomainHasMonitoringExporterConfigurationAndIstio_serviceHasExporterPort() { + configureDomain().withMonitoringExporterConfiguration("queries:\n").withIstio(); + + V1Service service = createService(); + + assertThat(service, containsPort("http-metrics", DEFAULT_EXPORTER_SIDECAR_PORT)); } } diff --git a/operator/src/test/java/oracle/kubernetes/operator/helpers/PodHelperTestBase.java b/operator/src/test/java/oracle/kubernetes/operator/helpers/PodHelperTestBase.java index 057c76c3f3b..1b84eb36003 100644 --- a/operator/src/test/java/oracle/kubernetes/operator/helpers/PodHelperTestBase.java +++ b/operator/src/test/java/oracle/kubernetes/operator/helpers/PodHelperTestBase.java @@ -375,8 +375,8 @@ public void whenPodCreatedWithAdminNap_prometheusAnnotationsSpecifyPlainTextPort hasEntry("prometheus.io/scrape", "true"))); } - protected void defineExporterConfiguration() { - configureDomain() + protected DomainConfigurator defineExporterConfiguration() { + return configureDomain() .withMonitoringExporterConfiguration(NOOP_EXPORTER_CONFIG) .withMonitoringExporterImage(EXPORTER_IMAGE); } @@ -439,53 +439,36 @@ void whenExporterContainerCreated_hasMetricsPortsItem() { assertThat(metricsPort.getContainerPort(), equalTo(DEFAULT_EXPORTER_SIDECAR_PORT)); } - private V1ContainerPort getExporterContainerPort(@Nonnull String name) { - return Optional.ofNullable(getExporterContainer().getPorts()).orElse(Collections.emptyList()).stream() - .filter(p -> name.equals(p.getName())).findFirst().orElse(null); - } - @Test - void whenExporterContainerCreated_hasDebugPortsItem() { - defineExporterConfiguration(); + void whenExporterContainerCreatedWithPort_hasMetricsPortsItem() { + defineExporterConfiguration().withMonitoringExporterPort(300); - V1ContainerPort metricsPort = getExporterContainerPort("debugger"); + V1ContainerPort metricsPort = getExporterContainerPort("metrics"); assertThat(metricsPort, notNullValue()); assertThat(metricsPort.getProtocol(), equalTo("TCP")); - assertThat(metricsPort.getContainerPort(), equalTo(30055)); + assertThat(metricsPort.getContainerPort(), equalTo(300)); } @Test - void whenExporterContainerCreated_specifyOperatorDomain() { - defineExporterConfiguration(); + void whenExporterContainerCreatedAndIstioEnabled_hasMetricsPortsItem() { + defineExporterConfiguration().withIstio(); - assertThat(getExporterContainer(), hasJavaOption("-DDOMAIN=" + getDomain().getDomainUid())); + V1ContainerPort metricsPort = getExporterContainerPort("http-metrics"); + assertThat(metricsPort, notNullValue()); + assertThat(metricsPort.getProtocol(), equalTo("TCP")); + assertThat(metricsPort.getContainerPort(), equalTo(DEFAULT_EXPORTER_SIDECAR_PORT)); } - @Test - void whenDefaultMonitorPortUsedByServer_relocateIt() { - getServerTopology().setListenPort(8080); - getServerTopology().setSslListenPort(8081); - getServerTopology().setAdminPort(8082); - defineExporterConfiguration(); - - assertThat(getExporterContainer(), hasJavaOption("-DEXPORTER_PORT=8083")); + private V1ContainerPort getExporterContainerPort(@Nonnull String name) { + return Optional.ofNullable(getExporterContainer().getPorts()).orElse(Collections.emptyList()).stream() + .filter(p -> name.equals(p.getName())).findFirst().orElse(null); } @Test - public void whenDefaultMonitorPortUsedByServer_hasPrometheusAnnotations() { - getServerTopology().setListenPort(8080); - getServerTopology().setSslListenPort(8081); - getServerTopology().setAdminPort(8082); + void whenExporterContainerCreated_specifyOperatorDomain() { defineExporterConfiguration(); - assertThat( - getCreatedPod().getMetadata().getAnnotations(), - allOf( - hasEntry("prometheus.io/port", "8083"), - hasEntry("prometheus.io/path", "/metrics"), - hasEntry("prometheus.io/scrape", "true"))); - - assertThat(getExporterContainer().getPorts().get(0).getContainerPort(), equalTo(8083)); + assertThat(getExporterContainer(), hasJavaOption("-DDOMAIN=" + getDomain().getDomainUid())); } abstract void setServerPort(int port); diff --git a/operator/src/test/java/oracle/kubernetes/operator/steps/MonitoringExporterStepsTest.java b/operator/src/test/java/oracle/kubernetes/operator/steps/MonitoringExporterStepsTest.java index 8256c541dbf..c79828b9e62 100644 --- a/operator/src/test/java/oracle/kubernetes/operator/steps/MonitoringExporterStepsTest.java +++ b/operator/src/test/java/oracle/kubernetes/operator/steps/MonitoringExporterStepsTest.java @@ -51,7 +51,6 @@ import static oracle.kubernetes.operator.ProcessingConstants.SERVER_NAME; import static oracle.kubernetes.operator.helpers.LegalNames.toPodName; import static oracle.kubernetes.operator.helpers.LegalNames.toServerServiceName; -import static oracle.kubernetes.weblogic.domain.model.MonitoringExporterSpecification.EXPORTER_PORT_NAME; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; @@ -150,13 +149,13 @@ private V1PodStatus setReady(V1PodStatus status) { private V1Container createExporterSidecar() { return new V1Container() .name(EXPORTER_CONTAINER_NAME) - .addPortsItem(new V1ContainerPort().name(EXPORTER_PORT_NAME).containerPort(EXPORTER_PORT)); + .addPortsItem(new V1ContainerPort().name("metrics").containerPort(EXPORTER_PORT)); } private V1Service createServerService(String serverName) { return new V1Service() .metadata(new V1ObjectMeta().namespace(NS).name(toServerServiceName(DOMAIN_NAME, serverName))) - .spec(new V1ServiceSpec().addPortsItem(new V1ServicePort().name(EXPORTER_PORT_NAME).port(EXPORTER_PORT))); + .spec(new V1ServiceSpec().addPortsItem(new V1ServicePort().name("metrics").port(EXPORTER_PORT))); } @AfterEach diff --git a/operator/src/test/java/oracle/kubernetes/operator/utils/WlsDomainConfigSupport.java b/operator/src/test/java/oracle/kubernetes/operator/utils/WlsDomainConfigSupport.java index 97678848bf3..5c5b0f85ff1 100644 --- a/operator/src/test/java/oracle/kubernetes/operator/utils/WlsDomainConfigSupport.java +++ b/operator/src/test/java/oracle/kubernetes/operator/utils/WlsDomainConfigSupport.java @@ -47,6 +47,11 @@ public WlsDomainConfigSupport withDynamicWlsCluster(String clusterName, String.. return this; } + public WlsDomainConfigSupport withDynamicWlsCluster(String clusterName, String serverTemplateName, Integer port) { + addDynamicWlsCluster(clusterName, serverTemplateName, port); + return this; + } + public WlsDomainConfigSupport withAdminServerName(String adminServerName) { setAdminServerName(adminServerName); return this; @@ -162,6 +167,18 @@ public void addDynamicWlsCluster(String clusterName, String... serverNames) { wlsClusters.put(clusterName, builder.build()); } + /** + * Adds a dynamic WLS cluster to the configuration with the server template. + * + * @param clusterName the name of the cluster + * @param serverTemplateName the names of the server template + * @param port the default listen port + */ + public void addDynamicWlsCluster(String clusterName, String serverTemplateName, int port) { + ClusterConfigBuilder builder = new DynamicClusterConfigBuilder(clusterName, serverTemplateName, port); + wlsClusters.put(clusterName, builder.build()); + } + /** * Creates a domain configuration, based on the defined servers and clusters. * @@ -227,14 +244,22 @@ WlsClusterConfig build() { } static class DynamicClusterConfigBuilder extends ClusterConfigBuilder { + private WlsServerConfig serverTemplate; + DynamicClusterConfigBuilder(String name) { + this(name, null, 0); + } + + DynamicClusterConfigBuilder(String name, String serverTemplateName, int port) { super(name); + serverTemplate = new WlsServerConfig(serverTemplateName, null, port); } WlsClusterConfig build() { WlsDynamicServersConfig wlsDynamicServersConfig = new WlsDynamicServersConfig(); wlsDynamicServersConfig.setServerConfigs(serverConfigs); wlsDynamicServersConfig.setDynamicClusterSize(serverConfigs.size()); + wlsDynamicServersConfig.setServerTemplate(serverTemplate); WlsClusterConfig wlsClusterConfig = new WlsClusterConfig(getName(), wlsDynamicServersConfig); return wlsClusterConfig; }