Skip to content

OWLS-80960 - Allow replicas count to drop below min dynamic cluster size #1627

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/domains/Domain.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@
"description": "The name of this cluster. Required",
"type": "string"
},
"allowReplicasBelowMinDynClusterSize": {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this also be a global setting? On the one hand, it's extra work and I'm not sure if the extra work is worth it at this time. On the other hand, there's precedent where 'replicas' itself is both global and per-cluster.

One way to handle this would be check-in 'as-is' and file a JIRA to add a global setting...

Copy link
Member Author

@alai8 alai8 May 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed OWLS-81769

"description": "If true (the default), then the number of replicas is allowed to drop below the minimum dynamic cluster size configured in the WebLogic domain home configuration. Otherwise, the operator will ensure that the number of replicas is not less than the minimum dynamic cluster setting. This setting applies to dynamic clusters only.",
"type": "boolean"
},
"serverPod": {
"description": "Configuration affecting server pods.",
"$ref": "#/definitions/ServerPod"
Expand Down
1 change: 1 addition & 0 deletions docs/domains/Domain.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ An element representing a cluster in the domain configuration.

| Name | Type | Description |
| --- | --- | --- |
| `allowReplicasBelowMinDynClusterSize` | Boolean | If true (the default), then the number of replicas is allowed to drop below the minimum dynamic cluster size configured in the WebLogic domain home configuration. Otherwise, the operator will ensure that the number of replicas is not less than the minimum dynamic cluster setting. This setting applies to dynamic clusters only. |
| `clusterName` | string | The name of this cluster. Required |
| `clusterService` | [Kubernetes Resource](#kubernetes-resource) | Customization affecting ClusterIP Kubernetes services for the WebLogic cluster. |
| `maxUnavailable` | number | The maximum number of cluster members that can be temporarily unavailable. Defaults to 1. |
Expand Down
4 changes: 4 additions & 0 deletions docs/domains/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1029,6 +1029,10 @@
"description": "The name of this cluster. Required",
"type": "string"
},
"allowReplicasBelowMinDynClusterSize": {
Copy link
Contributor

@rosemarymarano rosemarymarano May 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If true (the default), the number -> If true (the default), then the number
that the number of replicas is not below the minimum dynamic cluster -> that the number of replicas is not less than the minimum dynamic cluster setting. OR ->
that the number of replicas is not less than the configured minimum dynamic cluster size.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

"description": "If true (the default), then the number of replicas is allowed to drop below the minimum dynamic cluster size configured in the WebLogic domain home configuration. Otherwise, the operator will ensure that the number of replicas is not less than the minimum dynamic cluster setting. This setting applies to dynamic clusters only.",
"type": "boolean"
},
"serverPod": {
"description": "Configuration affecting server pods.",
"$ref": "#/definitions/ServerPod"
Expand Down
8 changes: 8 additions & 0 deletions kubernetes/crd/domain-crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5478,6 +5478,14 @@ spec:
clusterName:
description: The name of this cluster. Required
type: string
allowReplicasBelowMinDynClusterSize:
description: If true (the default), then the number of replicas
is allowed to drop below the minimum dynamic cluster size
configured in the WebLogic domain home configuration. Otherwise,
the operator will ensure that the number of replicas is not
less than the minimum dynamic cluster setting. This setting
applies to dynamic clusters only.
type: boolean
serverPod:
description: Configuration affecting server pods.
type: object
Expand Down
8 changes: 8 additions & 0 deletions kubernetes/crd/domain-v1beta1-crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5367,6 +5367,14 @@ spec:
clusterName:
description: The name of this cluster. Required
type: string
allowReplicasBelowMinDynClusterSize:
description: If true (the default), then the number of replicas
is allowed to drop below the minimum dynamic cluster size configured
in the WebLogic domain home configuration. Otherwise, the operator
will ensure that the number of replicas is not less than the
minimum dynamic cluster setting. This setting applies to dynamic
clusters only.
type: boolean
serverPod:
description: Configuration affecting server pods.
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public interface KubernetesConstants {

boolean DEFAULT_HTTP_ACCESS_LOG_IN_LOG_HOME = true;
boolean DEFAULT_INCLUDE_SERVER_OUT_IN_POD_LOG = true;
boolean DEFAULT_ALLOW_REPLICAS_BELOW_MIN_DYN_CLUSTER_SIZE = true;

String CONTAINER_NAME = "weblogic-server";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,10 +246,11 @@ private void logIfReplicasLessThanClusterServersMin(WlsClusterConfig clusterConf
private boolean lessThanMinConfiguredClusterSize(WlsClusterConfig clusterConfig) {
if (clusterConfig != null) {
String clusterName = clusterConfig.getClusterName();
int configMinClusterSize
= clusterConfig.getMinDynamicClusterSize();
return clusterConfig.hasDynamicServers()
&& domain.getReplicaCount(clusterName) < configMinClusterSize;
if (clusterConfig.hasDynamicServers()
&& !domain.isAllowReplicasBelowMinDynClusterSize(clusterName)) {
int configMinClusterSize = clusterConfig.getMinDynamicClusterSize();
return domain.getReplicaCount(clusterName) < configMinClusterSize;
}
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,6 @@ ClusterConfigurator withLivenessProbeSettings(
ClusterConfigurator withToleration(V1Toleration toleration);

ClusterConfigurator withPrecreateServerService(boolean precreateServerService);

ClusterConfigurator withAllowReplicasBelowDynClusterSize(boolean allowReplicasBelowDynClusterSize);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@ public interface EffectiveConfigurationFactory {
boolean isShuttingDown();

List<String> getAdminServerChannelNames();

boolean isAllowReplicasBelowMinDynClusterSize(String clusterName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package oracle.kubernetes.weblogic.domain.model;

import java.util.Map;
import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

Expand All @@ -12,6 +13,7 @@
import oracle.kubernetes.json.Description;
import oracle.kubernetes.json.EnumClass;
import oracle.kubernetes.json.Range;
import oracle.kubernetes.operator.KubernetesConstants;
import oracle.kubernetes.operator.ServerStartPolicy;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
Expand Down Expand Up @@ -57,6 +59,15 @@ public class Cluster extends BaseConfiguration implements Comparable<Cluster> {
@Expose
private KubernetesResource clusterService = new KubernetesResource();

/** Whether to allow the number of replicas to drop below the minimum dynamic cluster
* size configured in the WebLogic domain home configuration. Default is true. */
@Description("If true (the default), then the number of replicas is allowed to drop below the "
+ "minimum dynamic cluster size configured in the WebLogic domain home configuration. "
+ "Otherwise, the operator will ensure that the number of replicas is not less than "
+ "the minimum dynamic cluster setting. This setting applies to dynamic clusters only."
)
private Boolean allowReplicasBelowMinDynClusterSize;

protected Cluster getConfiguration() {
Cluster configuration = new Cluster();
configuration.fillInFrom(this);
Expand Down Expand Up @@ -85,6 +96,22 @@ public void setReplicas(Integer replicas) {
this.replicas = replicas;
}

/**
* Whether to allow number of replicas to drop below the minimum dynamic cluster size configured
* in the WebLogic domain home configuration.
*
* @return whether to allow number of replicas to drop below the minimum dynamic cluster size
* configured in the WebLogic domain home configuration.
*/
public boolean isAllowReplicasBelowMinDynClusterSize() {
return Optional.ofNullable(allowReplicasBelowMinDynClusterSize)
.orElse(KubernetesConstants.DEFAULT_ALLOW_REPLICAS_BELOW_MIN_DYN_CLUSTER_SIZE);
}

public void setAllowReplicasBelowMinDynClusterSize(boolean value) {
allowReplicasBelowMinDynClusterSize = value;
}

@Nullable
@Override
public String getServerStartPolicy() {
Expand Down Expand Up @@ -145,6 +172,7 @@ public String toString() {
.append("serverStartPolicy", serverStartPolicy)
.append("clusterService", clusterService)
.append("maxUnavailable", maxUnavailable)
.append("allowReplicasBelowMinDynClusterSize", allowReplicasBelowMinDynClusterSize)
.toString();
}

Expand All @@ -167,6 +195,7 @@ public boolean equals(Object o) {
.append(serverStartPolicy, cluster.serverStartPolicy)
.append(clusterService, cluster.clusterService)
.append(maxUnavailable, cluster.maxUnavailable)
.append(allowReplicasBelowMinDynClusterSize, cluster.allowReplicasBelowMinDynClusterSize)
.isEquals();
}

Expand All @@ -179,6 +208,7 @@ public int hashCode() {
.append(serverStartPolicy)
.append(clusterService)
.append(maxUnavailable)
.append(allowReplicasBelowMinDynClusterSize)
.toHashCode();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,19 @@ public int getMinAvailable(String clusterName) {
return Math.max(getReplicaCount(clusterName) - getMaxUnavailable(clusterName), 0);
}

/**
* Returns whether the specified cluster is allowed to have replica count below the minimum
* dynamic cluster size configured in WebLogic domain configuration.
*
* @param clusterName the name of the cluster
* @return whether the specified cluster is allowed to have replica count below the minimum
* dynamic cluster size configured in WebLogic domain configuration
*/
public boolean isAllowReplicasBelowMinDynClusterSize(String clusterName) {
return getEffectiveConfigurationFactory().isAllowReplicasBelowMinDynClusterSize(clusterName);
}


/**
* DomainSpec is a description of a domain.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,12 @@ public ClusterConfigurator withNodeName(String nodeName) {
return this;
}

@Override
public ClusterConfigurator withAllowReplicasBelowDynClusterSize(boolean allowReplicasBelowDynClusterSize) {
cluster.setAllowReplicasBelowMinDynClusterSize(allowReplicasBelowDynClusterSize);
return this;
}

@Override
public ClusterConfigurator withSchedulerName(String schedulerName) {
getDomainSpec().setSchedulerName(schedulerName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,10 @@ private boolean hasMaxUnavailable(Cluster cluster) {
return cluster != null && cluster.getMaxUnavailable() != null;
}

private boolean isAllowReplicasBelowDynClusterSizeFor(Cluster cluster) {
return cluster.isAllowReplicasBelowMinDynClusterSize();
}

public AdminServer getAdminServer() {
return adminServer;
}
Expand Down Expand Up @@ -907,6 +911,11 @@ public List<String> getAdminServerChannelNames() {
return adminServer != null ? adminServer.getChannelNames() : Collections.emptyList();
}

@Override
public boolean isAllowReplicasBelowMinDynClusterSize(String clusterName) {
return isAllowReplicasBelowDynClusterSizeFor(getCluster(clusterName));
}

private Cluster getOrCreateCluster(String clusterName) {
Cluster cluster = getCluster(clusterName);
if (cluster != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,15 @@ private void addWlsCluster(String clusterName, String... serverNames) {
configSupport.addWlsCluster(clusterName, serverNames);
}

private void addDynamicWlsCluster(String clusterName,
int minDynamicClusterSize,
int maxDynamicClusterSize,
String... serverNames) {
configSupport.addDynamicWlsCluster(clusterName, serverNames);
configSupport.getWlsCluster(clusterName).getDynamicServersConfig().setMinDynamicClusterSize(minDynamicClusterSize);
configSupport.getWlsCluster(clusterName).getDynamicServersConfig().setMaxDynamicClusterSize(maxDynamicClusterSize);
}

@Test
public void whenStartPolicyUndefined_startServers() {
invokeStepWithConfiguredServer();
Expand Down Expand Up @@ -541,6 +550,44 @@ public void whenClusterStartupDefinedWithPreCreateServerService_allServersDown_a
assertThat(getServers(), empty());
}

@Test
public void whenReplicasLessThanMinDynClusterSize_setReplicaCountToMinClusterSize() {
startNoServers();
setCluster1Replicas(0);
setCluster1AllowReplicasBelowMinDynClusterSize(false);

addDynamicWlsCluster("cluster1", 2, 5,"ms1", "ms2", "ms3", "ms4", "ms5");

invokeStep();

assertThat(2, equalTo(domain.getReplicaCount("cluster1")));
}

@Test
public void whenReplicasLessThanMinDynClusterSize_allowBelowMin_doNotChangeReplicaCount() {
startNoServers();
setCluster1Replicas(0);

addDynamicWlsCluster("cluster1", 2, 5,"ms1", "ms2", "ms3", "ms4", "ms5");

invokeStep();

assertThat(0, equalTo(domain.getReplicaCount("cluster1")));
}

@Test
public void whenReplicasMoreThanMinDynClusterSize_doNotChangeReplicaCount() {
startNoServers();
setCluster1Replicas(3);
setCluster1AllowReplicasBelowMinDynClusterSize(false);

addDynamicWlsCluster("cluster1", 2, 5,"ms1", "ms2", "ms3", "ms4", "ms5");

invokeStep();

assertThat(3, equalTo(domain.getReplicaCount("cluster1")));
}

private void assertStoppingServers(Step step, String... servers) {
assertThat(((ServerDownIteratorStep) step).getServersToStop(), containsInAnyOrder(servers));
}
Expand Down Expand Up @@ -569,7 +616,11 @@ private void setDefaultReplicas(int replicas) {
}

private void setCluster1Replicas(int replicas) {
configureCluster("cluster1").withReplicas(replicas);
configurator.configureCluster("cluster1").withReplicas(replicas);
}

private void setCluster1AllowReplicasBelowMinDynClusterSize(boolean allowReplicasBelowMinDynClusterSize) {
configurator.configureCluster("cluster1").withAllowReplicasBelowDynClusterSize(allowReplicasBelowMinDynClusterSize);
}

private void configureServers(String... serverNames) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.junit.Test;

import static oracle.kubernetes.operator.KubernetesConstants.ALWAYS_IMAGEPULLPOLICY;
import static oracle.kubernetes.operator.KubernetesConstants.DEFAULT_ALLOW_REPLICAS_BELOW_MIN_DYN_CLUSTER_SIZE;
import static oracle.kubernetes.operator.KubernetesConstants.DEFAULT_IMAGE;
import static oracle.kubernetes.operator.KubernetesConstants.IFNOTPRESENT_IMAGEPULLPOLICY;
import static oracle.kubernetes.operator.KubernetesConstants.LATEST_IMAGE_SUFFIX;
Expand All @@ -28,7 +29,7 @@
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.junit.Assert.assertThat;
import static org.hamcrest.junit.MatcherAssert.assertThat;

public abstract class DomainTestBase {
protected static final String CLUSTER_NAME = "cluster1";
Expand Down Expand Up @@ -318,6 +319,21 @@ public void afterMaxUnavailableSetForCluster_canReadIt() {
assertThat(domain.getMaxUnavailable("cluster1"), equalTo(5));
}

@Test
public void afterAllowReplicasBelowMinDynamicClusterSizeSetForCluster_canReadIt() {
configureCluster("cluster1").withAllowReplicasBelowDynClusterSize(false);

assertThat(domain.isAllowReplicasBelowMinDynClusterSize("cluster1"), equalTo(false));
}

@Test
public void whenNotSpecified_allowReplicasBelowMinDynamicClusterSizeHasDefault() {
configureCluster("cluster1");

assertThat(domain.isAllowReplicasBelowMinDynClusterSize("cluster1"),
equalTo(DEFAULT_ALLOW_REPLICAS_BELOW_MIN_DYN_CLUSTER_SIZE));
}

@Test
public void whenBothClusterAndServerStateSpecified_managedServerUsesServerState() {
configureServer(SERVER1).withDesiredState("STAND-BY");
Expand Down