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 45ab3321e75..dfc21170ef9 100644 --- a/operator/src/main/java/oracle/kubernetes/operator/helpers/ServiceHelper.java +++ b/operator/src/main/java/oracle/kubernetes/operator/helpers/ServiceHelper.java @@ -4,16 +4,19 @@ package oracle.kubernetes.operator.helpers; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import javax.annotation.Nonnull; import io.kubernetes.client.openapi.models.V1DeleteOptions; import io.kubernetes.client.openapi.models.V1ObjectMeta; import io.kubernetes.client.openapi.models.V1Service; +import io.kubernetes.client.openapi.models.V1ServiceList; import io.kubernetes.client.openapi.models.V1ServicePort; import io.kubernetes.client.openapi.models.V1ServiceSpec; import io.kubernetes.client.openapi.models.V1Status; @@ -24,7 +27,9 @@ import oracle.kubernetes.operator.calls.UnrecoverableErrorBuilder; import oracle.kubernetes.operator.logging.LoggingFacade; import oracle.kubernetes.operator.logging.LoggingFactory; +import oracle.kubernetes.operator.steps.ActionResponseStep; import oracle.kubernetes.operator.steps.DefaultResponseStep; +import oracle.kubernetes.operator.steps.DeleteServiceListStep; import oracle.kubernetes.operator.wlsconfig.NetworkAccessPoint; import oracle.kubernetes.operator.wlsconfig.WlsClusterConfig; import oracle.kubernetes.operator.wlsconfig.WlsDomainConfig; @@ -40,7 +45,10 @@ import oracle.kubernetes.weblogic.domain.model.ServerSpec; import org.apache.commons.lang3.builder.EqualsBuilder; +import static oracle.kubernetes.operator.LabelConstants.forDomainUidSelector; +import static oracle.kubernetes.operator.LabelConstants.getCreatedbyOperatorSelector; import static oracle.kubernetes.operator.helpers.KubernetesUtils.getDomainUidLabel; +import static oracle.kubernetes.operator.helpers.OperatorServiceType.EXTERNAL; import static oracle.kubernetes.operator.logging.MessageKeys.ADMIN_SERVICE_CREATED; import static oracle.kubernetes.operator.logging.MessageKeys.ADMIN_SERVICE_EXISTS; import static oracle.kubernetes.operator.logging.MessageKeys.ADMIN_SERVICE_REPLACED; @@ -527,10 +535,29 @@ private Step createNewService(Step next) { protected abstract String getServiceCreatedMessageKey(); private Step deleteAndReplaceService(Step next) { - V1DeleteOptions deleteOptions = new V1DeleteOptions(); + if (serviceType == EXTERNAL) { + return deleteAndReplaceNodePortService(); + } else { + V1DeleteOptions deleteOptions = new V1DeleteOptions(); + return new CallBuilder() + .deleteServiceAsync( + createServiceName(), getNamespace(), getDomainUid(), deleteOptions, new DeleteServiceResponse(next)); + } + } + + private Step deleteAndReplaceNodePortService() { return new CallBuilder() - .deleteServiceAsync( - createServiceName(), getNamespace(), getDomainUid(), deleteOptions, new DeleteServiceResponse(next)); + .withLabelSelectors(forDomainUidSelector(info.getDomainUid()), getCreatedbyOperatorSelector()) + .listServiceAsync( + getNamespace(), + new ActionResponseStep() { + public Step createSuccessStep(V1ServiceList result, Step next) { + Collection c = Optional.ofNullable(result).map(list -> list.getItems().stream() + .filter(s -> isNodePortType(s)) + .collect(Collectors.toList())).orElse(new ArrayList<>()); + return new DeleteServiceListStep(c, createReplacementService(next)); + } + }); } private Step createReplacementService(Step next) { @@ -798,7 +825,7 @@ private static class ExternalServiceStepContext extends ServiceStepContext { private final String adminServerName; ExternalServiceStepContext(Step conflictStep, Packet packet) { - super(conflictStep, packet, OperatorServiceType.EXTERNAL); + super(conflictStep, packet, EXTERNAL); adminServerName = (String) packet.get(ProcessingConstants.SERVER_NAME); } diff --git a/operator/src/main/java/oracle/kubernetes/operator/steps/DeleteServiceListStep.java b/operator/src/main/java/oracle/kubernetes/operator/steps/DeleteServiceListStep.java index 56298bae316..e83635dfeac 100644 --- a/operator/src/main/java/oracle/kubernetes/operator/steps/DeleteServiceListStep.java +++ b/operator/src/main/java/oracle/kubernetes/operator/steps/DeleteServiceListStep.java @@ -19,7 +19,7 @@ */ public class DeleteServiceListStep extends AbstractListStep { - DeleteServiceListStep(Collection c, Step next) { + public DeleteServiceListStep(Collection c, Step next) { super(c, next); } diff --git a/operator/src/test/java/oracle/kubernetes/operator/helpers/ServiceHelperTest.java b/operator/src/test/java/oracle/kubernetes/operator/helpers/ServiceHelperTest.java index f1c1a7f0fb0..db5991ba82a 100644 --- a/operator/src/test/java/oracle/kubernetes/operator/helpers/ServiceHelperTest.java +++ b/operator/src/test/java/oracle/kubernetes/operator/helpers/ServiceHelperTest.java @@ -19,9 +19,11 @@ import javax.annotation.Nonnull; import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.models.V1ObjectMeta; import io.kubernetes.client.openapi.models.V1OwnerReference; import io.kubernetes.client.openapi.models.V1Service; import io.kubernetes.client.openapi.models.V1ServicePort; +import io.kubernetes.client.openapi.models.V1ServiceSpec; import oracle.kubernetes.operator.KubernetesConstants; import oracle.kubernetes.operator.LabelConstants; import oracle.kubernetes.operator.calls.FailureStatusSourceException; @@ -76,6 +78,7 @@ import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.is; @@ -121,6 +124,8 @@ public class ServiceHelperTest extends ServiceHelperTestBase { private static final int NAP_PORT_1 = 7100; private static final int NAP_PORT_2 = 37100; private static final int NAP_PORT_3 = 37200; + public static final String STRANDED = "Stranded"; + public static final String NODE_PORT = "NodePort"; private final TerminalStep terminalStep = new TerminalStep(); @Parameter public String testType; @Parameter(1) @@ -399,11 +404,20 @@ public void whenConfiguredSslListenPortChanged_replaceService() { private void verifyServiceReplaced(Runnable configurationMutator) { recordInitialService(); + if (testFacade instanceof ExternalServiceTestFacade) { + recordStrandedService(); + } configurationMutator.run(); runServiceHelper(); assertThat(logRecords, containsInfo(testFacade.getServiceReplacedLogMessage())); + assertThat(getStrandedService(), empty()); + } + + private List getStrandedService() { + ArrayList svcList = (ArrayList)testSupport.getResources(SERVICE); + return svcList.stream().filter(s -> s.getMetadata().getName().equals(STRANDED)).collect(Collectors.toList()); } private void configureNewLabel() { @@ -436,6 +450,16 @@ private void recordInitialService() { testFacade.recordService(domainPresenceInfo, originalService); } + private void recordStrandedService() { + Map labels = new HashMap<>(); + labels.put(LabelConstants.DOMAINUID_LABEL, UID); + labels.put(LabelConstants.CREATEDBYOPERATOR_LABEL, "true"); + V1Service strandedService = new V1Service().metadata(new V1ObjectMeta().name(STRANDED).namespace(NS) + .labels(labels)).spec(new V1ServiceSpec().type(NODE_PORT)); + testSupport.defineResources(strandedService); + testFacade.recordService(domainPresenceInfo, strandedService); + } + @Test public void whenServiceLabelAdded_dontReplaceService() { verifyServiceNotReplaced(this::addNewLabel);