Skip to content

Commit 13da69a

Browse files
lennyphanankedia
andauthored
OWLS-102910: WKO 4.0 bug: Cluster condition last transition time is diffferent in ClusterStatus of Domain Resource and not updated on ClusterResource resource (#3531)
* Cluster condition last transition time is different in ClusterStatus of Domain Resource and not updated on ClusterResource resource Co-authored-by: Anil Kedia <[email protected]>
1 parent 1f34733 commit 13da69a

File tree

13 files changed

+153
-28
lines changed

13 files changed

+153
-28
lines changed

integration-tests/src/test/java/oracle/weblogic/kubernetes/ItDiagnosticsCompleteAvailableCondition.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ void testCompleteAvailableConditionWithIfNeeded() {
161161
* Test domain status condition with serverStartPolicy set to AdminOnly.
162162
* Verify the following conditions are generated:
163163
* type: Completed, status: true
164-
* type: Available, status: false
164+
* type: Available, status: true
165165
* Verify no Failed type condition generated.
166166
*/
167167
@Test
@@ -195,7 +195,7 @@ void testCompleteAvailableConditionWithAdminOnly() {
195195
DOMAIN_STATUS_CONDITION_COMPLETED_TYPE, "True");
196196
// verify the condition Available type has status True
197197
checkDomainStatusConditionTypeHasExpectedStatus(domainUid, domainNamespace1,
198-
DOMAIN_STATUS_CONDITION_AVAILABLE_TYPE, "False");
198+
DOMAIN_STATUS_CONDITION_AVAILABLE_TYPE, "True");
199199
// verify there is no status condition type Failed
200200
verifyDomainStatusConditionTypeDoesNotExist(domainUid, domainNamespace1, DOMAIN_STATUS_CONDITION_FAILED_TYPE);
201201
} finally {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,7 @@ private Packet createPacket() {
10121012
ProcessingConstants.DOMAIN_COMPONENT_NAME,
10131013
Component.createFor(delegate.getKubernetesVersion()));
10141014
packet.put(LoggingFilter.LOGGING_FILTER_PACKET_KEY, loggingFilter);
1015+
packet.put(ProcessingConstants.SKIP_STATUS_UPDATE_IF_SSI_NOT_RECORDED, Boolean.TRUE);
10151016
return packet;
10161017
}
10171018

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

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
import static oracle.kubernetes.operator.ProcessingConstants.MII_DYNAMIC_UPDATE_RESTART_REQUIRED;
8888
import static oracle.kubernetes.operator.ProcessingConstants.SERVER_HEALTH_MAP;
8989
import static oracle.kubernetes.operator.ProcessingConstants.SERVER_STATE_MAP;
90+
import static oracle.kubernetes.operator.ProcessingConstants.SKIP_STATUS_UPDATE_IF_SSI_NOT_RECORDED;
9091
import static oracle.kubernetes.operator.WebLogicConstants.RUNNING_STATE;
9192
import static oracle.kubernetes.operator.WebLogicConstants.SHUTDOWN_STATE;
9293
import static oracle.kubernetes.operator.WebLogicConstants.SHUTTING_DOWN_STATE;
@@ -569,6 +570,20 @@ DomainStatusUpdaterContext createContext(Packet packet) {
569570
void modifyStatus(DomainStatus domainStatus) { // no-op; modification happens in the context itself.
570571
}
571572

573+
@Override
574+
public NextAction apply(Packet packet) {
575+
return shouldSkipDomainStatusUpdate(packet)
576+
? doNext(getNext().getNext(), packet) : super.apply(packet);
577+
}
578+
579+
private boolean shouldSkipDomainStatusUpdate(Packet packet) {
580+
boolean domainRecheckOrScheduledStatusUpdate =
581+
(Boolean) packet.getOrDefault(SKIP_STATUS_UPDATE_IF_SSI_NOT_RECORDED, Boolean.FALSE);
582+
DomainPresenceInfo info = packet.getSpi(DomainPresenceInfo.class);
583+
return (domainRecheckOrScheduledStatusUpdate)
584+
&& info.getServerStartupInfo() == null;
585+
}
586+
572587
static class StatusUpdateContext extends DomainStatusUpdaterContext {
573588
private final WlsDomainConfig config;
574589
private final Set<String> expectedRunningServers;
@@ -824,10 +839,20 @@ private boolean isUnavailable(@Nonnull ClusterCheck clusterCheck) {
824839
}
825840

826841
private boolean noApplicationServersReady() {
827-
return getInfo().getServerStartupInfo().stream()
828-
.map(DomainPresenceInfo.ServerInfo::getName)
829-
.filter(this::isApplicationServer)
830-
.noneMatch(StatusUpdateContext.this::isServerReady);
842+
return isAdminOnlyDomain() && getInfo().getAdminServerName() != null
843+
? isServerNotReady(getInfo().getAdminServerName()) : noManagedServersReady();
844+
}
845+
846+
private boolean noManagedServersReady() {
847+
return getServerStartupInfos()
848+
.stream()
849+
.map(DomainPresenceInfo.ServerInfo::getName)
850+
.filter(this::isApplicationServer)
851+
.noneMatch(StatusUpdateContext.this::isServerReady);
852+
}
853+
854+
private Collection<DomainPresenceInfo.ServerStartupInfo> getServerStartupInfos() {
855+
return Optional.ofNullable(getInfo().getServerStartupInfo()).orElse(Collections.emptyList());
831856
}
832857

833858
// when the domain start policy is ADMIN_ONLY, the admin server is considered to be an application server.

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ public interface MakeRightDomainOperation extends PacketComponent {
3636
*/
3737
MakeRightDomainOperation withEventData(EventData eventData);
3838

39+
/**
40+
* Specifies that the current MakeRightOperation may skip updating the DomainStatus if the
41+
* DomainPresenceInfo.ServerStartupInfo value has not yet been constructed..
42+
*/
43+
default MakeRightDomainOperation skipUpdateDomainStatusIfNeeded() {
44+
return this;
45+
}
46+
3947
MakeRightDomainOperation interrupt();
4048

4149
/**

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,5 @@ public interface ProcessingConstants {
6464

6565
String SHUTDOWN_WITH_HTTP_SUCCEEDED = "SHUTDOWN_WITH_HTTP_SUCCEEDED";
6666
String DOMAIN_INTROSPECTION_COMPLETE = "Domain introspection complete";
67+
String SKIP_STATUS_UPDATE_IF_SSI_NOT_RECORDED = "skipStatusUpdateIfSSINotRecorded";
6768
}

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -779,10 +779,10 @@ private boolean hasMatchingServer(Map.Entry<String, ServerKubernetesObjects> e,
779779
/**
780780
* Server startup info.
781781
*
782-
* @return Server startup info
782+
* @return Server startup info or null if the current value is not set.
783783
*/
784784
public Collection<ServerStartupInfo> getServerStartupInfo() {
785-
return Optional.ofNullable(serverStartupInfo.get()).orElse(Collections.emptyList());
785+
return serverStartupInfo.get();
786786
}
787787

788788
/**
@@ -843,7 +843,9 @@ long getNumDeadlineIncreases() {
843843

844844
@Nonnull
845845
private Set<String> getExpectedRunningManagedServers() {
846-
return getServerStartupInfo().stream().map(ServerStartupInfo::getServerName).collect(Collectors.toSet());
846+
return Optional.ofNullable(getServerStartupInfo()).orElse(Collections.emptySet()).stream()
847+
.map(ServerStartupInfo::getServerName)
848+
.collect(Collectors.toSet());
847849
}
848850

849851
public Map<String, Step.StepAndPacket> getServersToRoll() {

operator/src/main/java/oracle/kubernetes/operator/makeright/MakeRightDomainOperationImpl.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ public class MakeRightDomainOperationImpl implements MakeRightDomainOperation {
7070
private boolean inspectionRun;
7171
private EventHelper.EventData eventData;
7272

73-
7473
/**
7574
* Create the operation.
7675
*
@@ -207,6 +206,9 @@ public Packet createPacket() {
207206
Component.createFor(delegate.getKubernetesVersion(),
208207
PodAwaiterStepFactory.class, delegate.getPodAwaiterStepFactory(getNamespace()),
209208
JobAwaiterStepFactory.class, delegate.getJobAwaiterStepFactory(getNamespace())));
209+
if (!wasStartedFromEvent()) {
210+
packet.put(ProcessingConstants.SKIP_STATUS_UPDATE_IF_SSI_NOT_RECORDED, Boolean.TRUE);
211+
}
210212
return packet;
211213
}
212214

@@ -224,7 +226,9 @@ public Step createSteps() {
224226

225227
result.add(Optional.ofNullable(eventData).map(EventHelper::createEventStep).orElse(null));
226228
result.add(new DomainProcessorImpl.PopulatePacketServerMapsStep());
227-
result.add(createStatusInitializationStep());
229+
if (wasStartedFromEvent()) {
230+
result.add(createStatusInitializationStep());
231+
}
228232
if (deleting || domainHasDeletionTimestamp()) {
229233
result.add(new StartPlanStep(liveInfo, createDomainDownPlan()));
230234
} else {

operator/src/main/java/oracle/kubernetes/operator/steps/ManagedServersUpStep.java

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ static class ServersUpStepFactory {
198198
final WlsDomainConfig domainTopology;
199199
final DomainResource domain;
200200
final DomainPresenceInfo info;
201-
List<ServerStartupInfo> startupInfos;
201+
List<ServerStartupInfo> startupInfos = new ArrayList<>();
202202
List<ServerShutdownInfo> shutdownInfos = new ArrayList<>();
203203
final Collection<String> servers = new ArrayList<>();
204204
final Collection<String> preCreateServers = new ArrayList<>();
@@ -270,10 +270,8 @@ private Step createNextStep(Step next) {
270270
}
271271

272272
Collection<ServerStartupInfo> getStartupInfos() {
273-
if (startupInfos != null) {
274-
startupInfos.sort(
275-
comparing((ServerStartupInfo sinfo) -> OperatorUtils.getSortingString(sinfo.getServerName())));
276-
}
273+
startupInfos.sort(
274+
comparing((ServerStartupInfo sinfo) -> OperatorUtils.getSortingString(sinfo.getServerName())));
277275
return startupInfos;
278276
}
279277

@@ -286,9 +284,6 @@ Collection<String> getServers() {
286284
}
287285

288286
private void addStartupInfo(ServerStartupInfo startupInfo) {
289-
if (startupInfos == null) {
290-
startupInfos = new ArrayList<>();
291-
}
292287
startupInfos.add(startupInfo);
293288
}
294289

operator/src/test/java/oracle/kubernetes/operator/DomainProcessorTest.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@
130130
import static oracle.kubernetes.operator.WebLogicConstants.SHUTDOWN_STATE;
131131
import static oracle.kubernetes.operator.WebLogicConstants.SUSPENDING_STATE;
132132
import static oracle.kubernetes.operator.helpers.AffinityHelper.getDefaultAntiAffinity;
133+
import static oracle.kubernetes.operator.helpers.EventHelper.EventItem.DOMAIN_CHANGED;
133134
import static oracle.kubernetes.operator.helpers.KubernetesTestSupport.CONFIG_MAP;
134135
import static oracle.kubernetes.operator.helpers.KubernetesTestSupport.DOMAIN;
135136
import static oracle.kubernetes.operator.helpers.KubernetesTestSupport.JOB;
@@ -350,7 +351,7 @@ void whenCachedDomainIsNewerThanSpecifiedDomain_dontRunMakeRightWhenStartedFromE
350351
cachedDomain.getMetadata().setCreationTimestamp(laterThan(newDomain));
351352

352353
processor.createMakeRightOperation(newInfo)
353-
.withEventData(new EventHelper.EventData(EventHelper.EventItem.DOMAIN_CHANGED))
354+
.withEventData(new EventHelper.EventData(DOMAIN_CHANGED))
354355
.execute();
355356

356357
assertThat(testSupport.getNumItemsRun(), equalTo(0));
@@ -526,7 +527,7 @@ void whenMakeRightRunFailsEarly_populateAvailableAndCompletedConditions() {
526527
domainConfigurator.configureCluster(newInfo, CLUSTER).withReplicas(MIN_REPLICAS);
527528
testSupport.failOnResource(SECRET, null, NS, KubernetesConstants.HTTP_BAD_REQUEST);
528529

529-
processor.createMakeRightOperation(newInfo).execute();
530+
processor.createMakeRightOperation(newInfo).withEventData(new EventHelper.EventData(DOMAIN_CHANGED)).execute();
530531

531532
DomainResource updatedDomain = testSupport.getResourceWithName(DOMAIN, UID);
532533
assertThat(updatedDomain, hasCondition(AVAILABLE).withStatus("False"));
@@ -2218,7 +2219,8 @@ private boolean isServerInactive(DomainPresenceInfo info, String serverName) {
22182219
void whenDomainIsNotValid_dontBringUpServers() {
22192220
defineDuplicateServerNames();
22202221

2221-
processor.createMakeRightOperation(originalInfo).withExplicitRecheck().execute();
2222+
processor.createMakeRightOperation(originalInfo)
2223+
.withEventData(new EventHelper.EventData(DOMAIN_CHANGED)).withExplicitRecheck().execute();
22222224

22232225
assertServerPodAndServiceNotPresent(originalInfo, ADMIN_NAME);
22242226
for (String serverName : MANAGED_SERVER_NAMES) {
@@ -2235,7 +2237,8 @@ private void assertServerPodAndServiceNotPresent(DomainPresenceInfo info, String
22352237
void whenDomainIsNotValid_updateStatus() {
22362238
defineDuplicateServerNames();
22372239

2238-
processor.createMakeRightOperation(originalInfo).withExplicitRecheck().execute();
2240+
processor.createMakeRightOperation(originalInfo)
2241+
.withEventData(new EventHelper.EventData(DOMAIN_CHANGED)).withExplicitRecheck().execute();
22392242

22402243
DomainResource updatedDomain = testSupport.getResourceWithName(DOMAIN, UID);
22412244
assertThat(getStatusReason(updatedDomain), equalTo("DomainInvalid"));

operator/src/test/java/oracle/kubernetes/operator/DomainStatusUpdateTestBase.java

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
import static oracle.kubernetes.operator.ProcessingConstants.MII_DYNAMIC_UPDATE_RESTART_REQUIRED;
8282
import static oracle.kubernetes.operator.ProcessingConstants.SERVER_HEALTH_MAP;
8383
import static oracle.kubernetes.operator.ProcessingConstants.SERVER_STATE_MAP;
84+
import static oracle.kubernetes.operator.ProcessingConstants.SKIP_STATUS_UPDATE_IF_SSI_NOT_RECORDED;
8485
import static oracle.kubernetes.operator.WebLogicConstants.RUNNING_STATE;
8586
import static oracle.kubernetes.operator.WebLogicConstants.SHUTDOWN_STATE;
8687
import static oracle.kubernetes.operator.WebLogicConstants.SHUTTING_DOWN_STATE;
@@ -416,7 +417,7 @@ private void deleteServerPodsInCluster() {
416417
info.setServerPod("server1", null);
417418
info.setServerPod("server2", null);
418419
info.setServerPod("server3", null);
419-
info.setServerStartupInfo(null);
420+
info.setServerStartupInfo(Collections.emptyList());
420421
}
421422

422423
@Test
@@ -1222,6 +1223,24 @@ void whenNoServersInAClusterAreRunning_domainIsNotAvailable() {
12221223
assertThat(getRecordedDomain(), hasCondition(AVAILABLE).withStatus(FALSE));
12231224
}
12241225

1226+
@Test
1227+
void whenServersInAClusterAreNotInRunningState_clusterIsNotAvailableAndNotCompleted() {
1228+
defineScenario()
1229+
.withCluster("cluster1", "ms1", "ms2")
1230+
.withServersReachingState(STARTING_STATE, "ms1", "ms2").build();
1231+
1232+
updateDomainStatus();
1233+
1234+
ClusterStatus clusterStatus = getClusterStatus();
1235+
assertThat(clusterStatus.getConditions().size(), equalTo(2));
1236+
ClusterCondition condition = clusterStatus.getConditions().get(0);
1237+
assertThat(condition.getType(), equalTo(ClusterConditionType.AVAILABLE));
1238+
assertThat(condition.getStatus(), equalTo(FALSE));
1239+
condition = clusterStatus.getConditions().get(1);
1240+
assertThat(condition.getType(), equalTo(ClusterConditionType.COMPLETED));
1241+
assertThat(condition.getStatus(), equalTo(FALSE));
1242+
}
1243+
12251244
@Test
12261245
void withServersShuttingDown_domainIsNotCompleted() {
12271246
defineScenario().withServers("server1").withServersReachingState(SHUTTING_DOWN_STATE, "server1").build();
@@ -1610,6 +1629,17 @@ void whenAdminOnlyAndAdminServerIsNotReady_availableIsFalse() {
16101629
assertThat(getRecordedDomain(), hasCondition(AVAILABLE).withStatus(FALSE));
16111630
}
16121631

1632+
@Test
1633+
void whenAdminOnlyAndAdminServerNameNotSetInDomainPresenceInfo_availableIsFalse() {
1634+
info.setAdminServerName(null);
1635+
configureDomain().withDefaultServerStartPolicy(ServerStartPolicy.ADMIN_ONLY);
1636+
defineScenario().withServersReachingState(STARTING_STATE, "admin").build();
1637+
1638+
updateDomainStatus();
1639+
1640+
assertThat(getRecordedDomain(), hasCondition(AVAILABLE).withStatus(FALSE));
1641+
}
1642+
16131643
@Test
16141644
void whenAdminOnly_completedIsTrue() {
16151645
configureDomain().withDefaultServerStartPolicy(ServerStartPolicy.ADMIN_ONLY);
@@ -1644,6 +1674,50 @@ void whenAdminOnlyAndAManagedServersShuttingDown_completedIsFalse() {
16441674
assertThat(getRecordedDomain(), hasCondition(COMPLETED).withStatus(FALSE));
16451675
}
16461676

1677+
@Test
1678+
void whenDomainRecheckOrScheduledStatusUpdateAndSSINotConstructed_verifyDomainStatusNotUpdated() {
1679+
configureDomain().configureCluster(info, "cluster1").withReplicas(2).withMaxUnavailable(1);
1680+
ScenarioBuilder scenarioBuilder = defineScenario();
1681+
scenarioBuilder.withCluster("cluster1", "server1", "server2")
1682+
.withServersReachingState(STARTING_STATE, "server1", "server2")
1683+
.build();
1684+
info.getReferencedClusters().forEach(testSupport::defineResources);
1685+
1686+
updateDomainStatus();
1687+
1688+
assertThat(getRecordedDomain(), hasCondition(COMPLETED).withStatus(FALSE));
1689+
1690+
scenarioBuilder.withServersReachingState(RUNNING_STATE, "server1", "server2").build();
1691+
testSupport.addToPacket(SKIP_STATUS_UPDATE_IF_SSI_NOT_RECORDED, Boolean.TRUE);
1692+
info.setServerStartupInfo(null);
1693+
1694+
updateDomainStatus();
1695+
1696+
assertThat(getRecordedDomain(), hasCondition(COMPLETED).withStatus(FALSE));
1697+
}
1698+
1699+
@Test
1700+
void whenDomainRecheckOrScheduleStatusUpdateAndAdminOnly_availableIsTrue() {
1701+
configureDomain().withDefaultServerStartPolicy(ServerStartPolicy.ADMIN_ONLY);
1702+
defineScenario().build();
1703+
1704+
testSupport.addToPacket(SKIP_STATUS_UPDATE_IF_SSI_NOT_RECORDED, Boolean.TRUE);
1705+
updateDomainStatus();
1706+
1707+
assertThat(getRecordedDomain(), hasCondition(AVAILABLE).withStatus(TRUE));
1708+
}
1709+
1710+
@Test
1711+
void whenDomainRecheckOrScheduleStatusUpdateAndAdminOnlyAndAdminServerIsNotReady_availableIsFalse() {
1712+
configureDomain().withDefaultServerStartPolicy(ServerStartPolicy.ADMIN_ONLY);
1713+
defineScenario().withServersReachingState(STARTING_STATE, "admin").build();
1714+
1715+
testSupport.addToPacket(SKIP_STATUS_UPDATE_IF_SSI_NOT_RECORDED, Boolean.TRUE);
1716+
updateDomainStatus();
1717+
1718+
assertThat(getRecordedDomain(), hasCondition(AVAILABLE).withStatus(FALSE));
1719+
}
1720+
16471721
@SuppressWarnings("SameParameterValue")
16481722
private ScenarioBuilder defineScenario() {
16491723
return new ScenarioBuilder();
@@ -1752,6 +1826,7 @@ void build() {
17521826
@Nonnull
17531827
private List<DomainPresenceInfo.ServerStartupInfo> createServerStartupInfo(WlsDomainConfig domainConfig) {
17541828
return domainConfig.getAllServers().stream()
1829+
.filter(c -> !isAdminServer(c))
17551830
.filter(this::isLive)
17561831
.map(config -> new DomainPresenceInfo.ServerStartupInfo(config, "", null))
17571832
.collect(Collectors.toList());
@@ -1761,6 +1836,10 @@ private boolean isLive(WlsServerConfig serverConfig) {
17611836
return !nonStartedServers.contains(serverConfig.getName());
17621837
}
17631838

1839+
private boolean isAdminServer(WlsServerConfig serverConfig) {
1840+
return ADMIN.equals(serverConfig.getName());
1841+
}
1842+
17641843
private Map<String,String> createStateMap() {
17651844
Map<String,String> result = new HashMap<>();
17661845
result.put(ADMIN, RUNNING_STATE);

0 commit comments

Comments
 (0)