Skip to content

Commit 593cf4f

Browse files
committed
Support CRD subresources
1 parent 546b4a1 commit 593cf4f

File tree

7 files changed

+144
-26
lines changed

7 files changed

+144
-26
lines changed

model/src/main/java/oracle/kubernetes/weblogic/domain/v2/DomainSpec.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,16 @@ public DomainSpec withDomainHomeInImage(boolean domainHomeInImage) {
388388
return this;
389389
}
390390

391+
/**
392+
* The desired number of running managed servers in each WebLogic cluster that is not explicitly
393+
* configured in clusters.
394+
*
395+
* @return replicas
396+
*/
397+
public Integer getReplicas() {
398+
return this.replicas;
399+
}
400+
391401
/**
392402
* The desired number of running managed servers in each WebLogic cluster that is not explicitly
393403
* configured in clusters.

model/src/main/java/oracle/kubernetes/weblogic/domain/v2/DomainStatus.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.util.ArrayList;
1010
import java.util.List;
1111
import javax.validation.Valid;
12+
import oracle.kubernetes.json.Range;
1213
import org.apache.commons.lang3.builder.EqualsBuilder;
1314
import org.apache.commons.lang3.builder.HashCodeBuilder;
1415
import org.apache.commons.lang3.builder.ToStringBuilder;
@@ -46,6 +47,14 @@ public class DomainStatus {
4647
@Expose
4748
private DateTime startTime;
4849

50+
/**
51+
* The number of running managed servers in the WebLogic cluster if there is only one cluster in
52+
* the domain and where the cluster does not explicitly configure its replicas in a cluster
53+
* specification.
54+
*/
55+
@Range(minimum = 0)
56+
private Integer replicas;
57+
4958
/**
5059
* Current service state of domain.
5160
*
@@ -133,6 +142,41 @@ public DomainStatus withReason(String reason) {
133142
return this;
134143
}
135144

145+
/**
146+
* The number of running managed servers in the WebLogic cluster if there is only one cluster in
147+
* the domain and where the cluster does not explicitly configure its replicas in a cluster
148+
* specification.
149+
*
150+
* @param replicas replicas
151+
*/
152+
public void setReplicas(Integer replicas) {
153+
this.replicas = replicas;
154+
}
155+
156+
/**
157+
* The number of running managed servers in the WebLogic cluster if there is only one cluster in
158+
* the domain and where the cluster does not explicitly configure its replicas in a cluster
159+
* specification.
160+
*
161+
* @return replicas
162+
*/
163+
public Integer getReplicas() {
164+
return this.replicas;
165+
}
166+
167+
/**
168+
* The number of running managed servers in the WebLogic cluster if there is only one cluster in
169+
* the domain and where the cluster does not explicitly configure its replicas in a cluster
170+
* specification.
171+
*
172+
* @param replicas replicas
173+
* @return this
174+
*/
175+
public DomainStatus withReplicas(Integer replicas) {
176+
this.replicas = replicas;
177+
return this;
178+
}
179+
136180
/**
137181
* Status of WebLogic servers in this domain.
138182
*

operator/src/main/java/oracle/kubernetes/operator/DomainStatusUpdater.java

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import io.kubernetes.client.models.V1Pod;
99
import java.util.ArrayList;
1010
import java.util.Collection;
11+
import java.util.HashMap;
1112
import java.util.List;
1213
import java.util.ListIterator;
1314
import java.util.Map;
@@ -30,8 +31,10 @@
3031
import oracle.kubernetes.operator.work.NextAction;
3132
import oracle.kubernetes.operator.work.Packet;
3233
import oracle.kubernetes.operator.work.Step;
34+
import oracle.kubernetes.weblogic.domain.v2.Cluster;
3335
import oracle.kubernetes.weblogic.domain.v2.Domain;
3436
import oracle.kubernetes.weblogic.domain.v2.DomainCondition;
37+
import oracle.kubernetes.weblogic.domain.v2.DomainSpec;
3538
import oracle.kubernetes.weblogic.domain.v2.DomainStatus;
3639
import oracle.kubernetes.weblogic.domain.v2.ServerHealth;
3740
import oracle.kubernetes.weblogic.domain.v2.ServerStatus;
@@ -160,17 +163,27 @@ public NextAction apply(Packet packet) {
160163
serverStatuses.put(serverName, ss);
161164
}
162165
}
166+
167+
Map<String, Integer> clusterCounts = new HashMap<>();
163168
for (Map.Entry<String, ServerKubernetesObjects> entry : info.getServers().entrySet()) {
164169
String serverName = entry.getKey();
165170
if (!serverStatuses.containsKey(serverName)) {
166171
V1Pod pod = entry.getValue().getPod().get();
167172
if (pod != null) {
173+
String clusterName =
174+
pod.getMetadata().getLabels().get(LabelConstants.CLUSTERNAME_LABEL);
175+
if (clusterName != null) {
176+
clusterCounts.compute(
177+
clusterName,
178+
(key, value) -> {
179+
return (value == null) ? 1 : value + 1;
180+
});
181+
}
168182
ServerStatus ss =
169183
new ServerStatus()
170184
.withState(
171185
serverState.getOrDefault(serverName, WebLogicConstants.SHUTDOWN_STATE))
172-
.withClusterName(
173-
pod.getMetadata().getLabels().get(LabelConstants.CLUSTERNAME_LABEL))
186+
.withClusterName(clusterName)
174187
.withNodeName(pod.getSpec().getNodeName())
175188
.withServerName(serverName)
176189
.withHealth(serverHealth.get(serverName));
@@ -189,6 +202,37 @@ public NextAction apply(Packet packet) {
189202
madeChange = true;
190203
}
191204

205+
// Check if we should set top-level replicas value
206+
DomainSpec spec = dom.getSpec();
207+
if (spec.getReplicas() != null) {
208+
int replicas = -1;
209+
for (Map.Entry<String, Integer> entry : clusterCounts.entrySet()) {
210+
// Does this cluster specify an explicit value for replicas?
211+
String clusterName = entry.getKey();
212+
for (Cluster c : spec.getClusters()) {
213+
if (clusterName.equals(c.getClusterName())) {
214+
if (c.getReplicas() == null) {
215+
// There is no explicit replicas for for this cluster
216+
if (replicas == -1) {
217+
replicas = entry.getValue();
218+
} else {
219+
replicas = Math.min(replicas, entry.getValue());
220+
}
221+
}
222+
break;
223+
}
224+
}
225+
}
226+
227+
if (replicas != -1) {
228+
Integer current = status.getReplicas();
229+
if (current == null || current.intValue() != replicas) {
230+
status.setReplicas(replicas);
231+
madeChange = true;
232+
}
233+
}
234+
}
235+
192236
// Now, we'll build the conditions.
193237
// Possible condition types are Progressing, Available, and Failed
194238
// Each condition is either True, False, or Unknown

operator/src/main/java/oracle/kubernetes/operator/Main.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ private static void begin() {
206206
version = HealthCheckHelper.performK8sVersionCheck();
207207

208208
runSteps(
209-
CRDHelper.createDomainCRDStep(new StartNamespacesStep(targetNamespaces)),
209+
CRDHelper.createDomainCRDStep(version, new StartNamespacesStep(targetNamespaces)),
210210
Main::completeBegin);
211211
} catch (Throwable e) {
212212
LOGGER.warning(MessageKeys.EXCEPTION, e);

operator/src/main/java/oracle/kubernetes/operator/helpers/CRDHelper.java

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.google.gson.JsonElement;
1111
import io.kubernetes.client.models.*;
1212
import java.util.Collections;
13+
import java.util.HashMap;
1314
import oracle.kubernetes.json.SchemaGenerator;
1415
import oracle.kubernetes.operator.KubernetesConstants;
1516
import oracle.kubernetes.operator.LabelConstants;
@@ -37,16 +38,16 @@ private CRDHelper() {}
3738
* @param next Next step
3839
* @return Step for creating Domain custom resource definition
3940
*/
40-
public static Step createDomainCRDStep(Step next) {
41-
return new CRDStep(next);
41+
public static Step createDomainCRDStep(KubernetesVersion version, Step next) {
42+
return new CRDStep(version, next);
4243
}
4344

4445
static class CRDStep extends Step {
4546
CRDContext context;
4647

47-
CRDStep(Step next) {
48+
CRDStep(KubernetesVersion version, Step next) {
4849
super(next);
49-
context = new CRDContext(this);
50+
context = new CRDContext(version, this);
5051
}
5152

5253
@Override
@@ -58,18 +59,20 @@ public NextAction apply(Packet packet) {
5859
static class CRDContext {
5960
private final Step conflictStep;
6061
private final V1beta1CustomResourceDefinition model;
62+
private final KubernetesVersion version;
6163

62-
CRDContext(Step conflictStep) {
64+
CRDContext(KubernetesVersion version, Step conflictStep) {
65+
this.version = version;
6366
this.conflictStep = conflictStep;
64-
this.model = createModel();
67+
this.model = createModel(version);
6568
}
6669

67-
static V1beta1CustomResourceDefinition createModel() {
70+
static V1beta1CustomResourceDefinition createModel(KubernetesVersion version) {
6871
return new V1beta1CustomResourceDefinition()
6972
.apiVersion("apiextensions.k8s.io/v1beta1")
7073
.kind("CustomResourceDefinition")
7174
.metadata(createMetadata())
72-
.spec(createSpec());
75+
.spec(createSpec(version));
7376
}
7477

7578
static V1ObjectMeta createMetadata() {
@@ -78,13 +81,24 @@ static V1ObjectMeta createMetadata() {
7881
.putLabelsItem(LabelConstants.RESOURCE_VERSION_LABEL, DEFAULT_OPERATOR_VERSION);
7982
}
8083

81-
static V1beta1CustomResourceDefinitionSpec createSpec() {
82-
return new V1beta1CustomResourceDefinitionSpec()
83-
.group(KubernetesConstants.DOMAIN_GROUP)
84-
.version(KubernetesConstants.DOMAIN_VERSION)
85-
.scope("Namespaced")
86-
.names(getCRDNames())
87-
.validation(createSchemaValidation());
84+
static V1beta1CustomResourceDefinitionSpec createSpec(KubernetesVersion version) {
85+
V1beta1CustomResourceDefinitionSpec spec =
86+
new V1beta1CustomResourceDefinitionSpec()
87+
.group(KubernetesConstants.DOMAIN_GROUP)
88+
.version(KubernetesConstants.DOMAIN_VERSION)
89+
.scope("Namespaced")
90+
.names(getCRDNames())
91+
.validation(createSchemaValidation());
92+
if (version.isCRDSubresourcesSupported()) {
93+
spec.setSubresources(
94+
new V1beta1CustomResourceSubresources()
95+
.scale(
96+
new V1beta1CustomResourceSubresourceScale()
97+
.specReplicasPath(".spec.replicas")
98+
.statusReplicasPath(".status.replicas"))
99+
.status(new HashMap<String, Object>()));
100+
}
101+
return spec;
88102
}
89103

90104
static V1beta1CustomResourceDefinitionNames getCRDNames() {

operator/src/main/java/oracle/kubernetes/operator/helpers/KubernetesVersion.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ boolean isRulesReviewSupported() {
111111
return this.major > 1 || (this.major == 1 && this.minor >= 8);
112112
}
113113

114+
boolean isCRDSubresourcesSupported() {
115+
return this.major > 1 || (this.major == 1 && this.minor >= 10);
116+
}
117+
114118
@Override
115119
public boolean equals(Object o) {
116120
return this == o || o instanceof KubernetesVersion && equals((KubernetesVersion) o);

operator/src/test/java/oracle/kubernetes/operator/helpers/CRDHelperTest.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import org.junit.Test;
3030

3131
public class CRDHelperTest {
32+
private static final KubernetesVersion KUBERNETES_VERSION = new KubernetesVersion(1, 10);
33+
3234
private final V1beta1CustomResourceDefinition defaultCRD = defineDefaultCRD();
3335
private RetryStrategyStub retryStrategy = createStrictStub(RetryStrategyStub.class);
3436

@@ -37,7 +39,7 @@ public class CRDHelperTest {
3739
private List<LogRecord> logRecords = new ArrayList<>();
3840

3941
private V1beta1CustomResourceDefinition defineDefaultCRD() {
40-
return CRDHelper.CRDContext.createModel();
42+
return CRDHelper.CRDContext.createModel(KUBERNETES_VERSION);
4143
}
4244

4345
private V1beta1CustomResourceDefinition defineCRD(String version, String operatorVersion) {
@@ -89,7 +91,7 @@ public void whenUnableToReadCRD_reportFailure() {
8991
testSupport.addRetryStrategy(retryStrategy);
9092
expectReadCRD().failingWithStatus(401);
9193

92-
Step scriptCRDStep = CRDHelper.createDomainCRDStep(null);
94+
Step scriptCRDStep = CRDHelper.createDomainCRDStep(KUBERNETES_VERSION, null);
9395
testSupport.runSteps(scriptCRDStep);
9496

9597
testSupport.verifyCompletionThrowable(ApiException.class);
@@ -100,7 +102,7 @@ public void whenNoCRD_createIt() {
100102
expectReadCRD().failingWithStatus(HttpURLConnection.HTTP_NOT_FOUND);
101103
expectSuccessfulCreateCRD(defaultCRD);
102104

103-
testSupport.runSteps(CRDHelper.createDomainCRDStep(null));
105+
testSupport.runSteps(CRDHelper.createDomainCRDStep(KUBERNETES_VERSION, null));
104106

105107
assertThat(logRecords, containsInfo(CREATING_CRD));
106108
}
@@ -111,7 +113,7 @@ public void whenNoCRD_retryOnFailure() {
111113
expectReadCRD().failingWithStatus(HttpURLConnection.HTTP_NOT_FOUND);
112114
expectCreateCRD(defaultCRD).failingWithStatus(401);
113115

114-
Step scriptCRDStep = CRDHelper.createDomainCRDStep(null);
116+
Step scriptCRDStep = CRDHelper.createDomainCRDStep(KUBERNETES_VERSION, null);
115117
testSupport.runSteps(scriptCRDStep);
116118

117119
testSupport.verifyCompletionThrowable(ApiException.class);
@@ -122,15 +124,15 @@ public void whenNoCRD_retryOnFailure() {
122124
public void whenMatchingCRDExists_noop() {
123125
expectReadCRD().returning(defaultCRD);
124126

125-
testSupport.runSteps(CRDHelper.createDomainCRDStep(null));
127+
testSupport.runSteps(CRDHelper.createDomainCRDStep(KUBERNETES_VERSION, null));
126128
}
127129

128130
@Test
129131
public void whenExistingCRDHasOldVersion_replaceIt() {
130132
expectReadCRD().returning(defineCRD("v1", OPERATOR_V1));
131133
expectSuccessfulReplaceCRD(defaultCRD);
132134

133-
testSupport.runSteps(CRDHelper.createDomainCRDStep(null));
135+
testSupport.runSteps(CRDHelper.createDomainCRDStep(KUBERNETES_VERSION, null));
134136

135137
assertThat(logRecords, containsInfo(CREATING_CRD));
136138
}
@@ -139,7 +141,7 @@ public void whenExistingCRDHasOldVersion_replaceIt() {
139141
public void whenExistingCRDHasFutureVersion_dontReplaceIt() {
140142
expectReadCRD().returning(defineCRD("v4", "operator-v4"));
141143

142-
testSupport.runSteps(CRDHelper.createDomainCRDStep(null));
144+
testSupport.runSteps(CRDHelper.createDomainCRDStep(KUBERNETES_VERSION, null));
143145
}
144146

145147
@Test
@@ -148,7 +150,7 @@ public void whenReplaceFails_scheduleRetry() {
148150
expectReadCRD().returning(defineCRD("v1", OPERATOR_V1));
149151
expectReplaceCRD(defaultCRD).failingWithStatus(401);
150152

151-
Step scriptCRDStep = CRDHelper.createDomainCRDStep(null);
153+
Step scriptCRDStep = CRDHelper.createDomainCRDStep(KUBERNETES_VERSION, null);
152154
testSupport.runSteps(scriptCRDStep);
153155

154156
testSupport.verifyCompletionThrowable(ApiException.class);

0 commit comments

Comments
 (0)