Skip to content

Commit

Permalink
[Deployable] Add restart method
Browse files Browse the repository at this point in the history
  • Loading branch information
avano committed Apr 11, 2023
1 parent 939e865 commit e3550bd
Show file tree
Hide file tree
Showing 55 changed files with 468 additions and 274 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -534,4 +534,14 @@ public void addGroupsToSecurityContext(SecurityContextConstraints scc, String...
public String getServiceAccountRef(String serviceAccountName) {
return "system:serviceaccount:" + get().getNamespace() + ":" + serviceAccountName;
}

public boolean hasLabels(Pod pod, Map<String, String> expectedLabels) {
final Map<String, String> labels = pod.getMetadata().getLabels();
for (Map.Entry<String, String> expected : expectedLabels.entrySet()) {
if (!labels.containsKey(expected.getKey()) || !labels.get(expected.getKey()).equals(expected.getValue())) {
return false;
}
}
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,11 @@ default void afterAll(ExtensionContext extensionContext) throws Exception {
closeResources();
undeploy();
}

default void restart() {
closeResources();
undeploy();
deploy();
openResources();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,47 @@

import org.junit.jupiter.api.extension.ExtensionContext;

import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.dsl.PodResource;
import io.fabric8.kubernetes.client.dsl.Readiable;

public interface OpenshiftDeployable extends Deployable {
void create();

boolean isReady();
default boolean isReady() {
final List<PodResource<Pod>> servicePods = servicePods();
return servicePods != null && servicePods.size() > 0 && servicePods.stream().allMatch(Readiable::isReady);
}

boolean isDeployed();

default long waitTime() {
return 300_000;
}

default PodResource<Pod> servicePod() {
return servicePods().size() > 0 ? servicePods().get(0) : null;
}

default List<PodResource<Pod>> servicePods() {
try {
return OpenshiftClient.get().pods().list().getItems().stream()
.filter(podSelector())
.map(p -> OpenshiftClient.get().pods().withName(p.getMetadata().getName()))
.collect(Collectors.toList());
} catch (KubernetesClientException kce) {
// Just in case of some transient error
return null;
}
}

Predicate<Pod> podSelector();

@Override
default void deploy() {
final int retries = 60;
Expand All @@ -35,4 +65,13 @@ default void afterAll(ExtensionContext extensionContext) throws Exception {
OpenshiftClient.deleteNamespace();
}
}

@Override
default void restart() {
closeResources();
servicePod().delete();
WaitUtils.waitFor(() -> servicePods().stream().allMatch(p -> p.isReady() && !p.get().isMarkedForDeletion()),
"Restart: Waiting until the service is restarted");
openResources();
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
package software.tnb.common.deployment;

import software.tnb.common.config.OpenshiftConfiguration;
import software.tnb.common.openshift.OpenshiftClient;

import java.util.Map;
import java.util.function.Predicate;

import io.fabric8.kubernetes.api.model.Pod;

/**
* Resource that has a name.
*/
public interface WithName {
String name();

default Predicate<Pod> podSelector() {
return p -> OpenshiftClient.get().hasLabels(p, Map.of(OpenshiftConfiguration.openshiftDeploymentLabel(), name()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package software.tnb.common.service;

public interface Restartable {
void restart();
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@

import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;

import cz.xtf.core.openshift.OpenShiftWaiters;
import cz.xtf.core.openshift.helpers.ResourceFunctions;
import io.fabric8.kubernetes.api.model.ContainerPort;
import io.fabric8.kubernetes.api.model.ContainerPortBuilder;
import io.fabric8.kubernetes.api.model.IntOrString;
Expand All @@ -28,6 +28,7 @@
import io.fabric8.kubernetes.api.model.VolumeBuilder;
import io.fabric8.kubernetes.api.model.VolumeMountBuilder;
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
import io.fabric8.kubernetes.client.dsl.PodResource;

@AutoService(LocalStack.class)
public class OpenshiftLocalStack extends LocalStack implements OpenshiftDeployable, WithName, WithInClusterHostname, WithExternalHostname {
Expand Down Expand Up @@ -135,16 +136,19 @@ public void create() {

@Override
public boolean isReady() {
List<Pod> pods = OpenshiftClient.get().getLabeledPods(OpenshiftConfiguration.openshiftDeploymentLabel(), name());
if (ResourceFunctions.areExactlyNPodsReady(1).apply(pods)) {
return OpenshiftClient.get().getLogs(pods.get(0)).contains("Ready.");
}
return false;
final PodResource<Pod> pod = servicePod();
return pod != null && pod.isReady() && OpenshiftClient.get().getLogs(pod.get()).contains("Ready.");
}

@Override
public boolean isDeployed() {
return OpenshiftClient.get().getLabeledPods(OpenshiftConfiguration.openshiftDeploymentLabel(), name()).size() != 0;
return OpenshiftClient.get().apps().deployments().withLabel(OpenshiftConfiguration.openshiftDeploymentLabel(), name()).list()
.getItems().size() > 0;
}

@Override
public Predicate<Pod> podSelector() {
return WithName.super.podSelector();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,28 @@
import software.tnb.common.openshift.OpenshiftClient;
import software.tnb.common.utils.IOUtils;
import software.tnb.common.utils.NetworkUtils;
import software.tnb.common.utils.WaitUtils;

import org.junit.jupiter.api.extension.ExtensionContext;

import com.google.auto.service.AutoService;

import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;

import cz.xtf.core.openshift.OpenShiftWaiters;
import cz.xtf.core.openshift.helpers.ResourceFunctions;
import io.fabric8.kubernetes.api.model.ContainerPort;
import io.fabric8.kubernetes.api.model.ContainerPortBuilder;
import io.fabric8.kubernetes.api.model.EnvVar;
import io.fabric8.kubernetes.api.model.IntOrString;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.ServiceBuilder;
import io.fabric8.kubernetes.api.model.ServicePortBuilder;
import io.fabric8.kubernetes.api.model.ServiceSpecBuilder;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
import io.fabric8.kubernetes.client.PortForward;
import io.fabric8.kubernetes.client.dsl.PodResource;
import software.amazon.awssdk.services.s3.S3Client;

@AutoService(Minio.class)
Expand Down Expand Up @@ -106,8 +108,7 @@ public void undeploy() {
OpenshiftClient.get().services().withName(name()).delete();
OpenshiftClient.get().apps().deployments().withName(name()).delete();
OpenshiftClient.get().persistentVolumeClaims().withName(name()).delete();
OpenShiftWaiters.get(OpenshiftClient.get(), () -> false).areNoPodsPresent(OpenshiftConfiguration.openshiftDeploymentLabel(), name())
.timeout(120_000).waitFor();
WaitUtils.waitFor(() -> servicePod() == null, "Waiting until the pod is removed");
}

@Override
Expand All @@ -119,16 +120,15 @@ public void openResources() {

@Override
public void closeResources() {
client = null;
IOUtils.closeQuietly(portForward);
NetworkUtils.releasePort(localPort);
}

@Override
public boolean isReady() {
return ResourceFunctions.areExactlyNPodsReady(1)
.apply(OpenshiftClient.get().getLabeledPods(OpenshiftConfiguration.openshiftDeploymentLabel(), name()))
&& OpenshiftClient.get().getLogs(OpenshiftClient.get().getAnyPod(OpenshiftConfiguration.openshiftDeploymentLabel(), name()))
.contains("1 Online, 0 Offline.");
final PodResource<Pod> pod = servicePod();
return pod != null && pod.isReady() && OpenshiftClient.get().getLogs(pod.get()).contains("1 Online, 0 Offline.");
}

@Override
Expand All @@ -137,6 +137,11 @@ public boolean isDeployed() {
return deployment != null && !deployment.isMarkedForDeletion();
}

@Override
public Predicate<Pod> podSelector() {
return WithName.super.podSelector();
}

@Override
public void beforeAll(ExtensionContext extensionContext) throws Exception {
OpenshiftDeployable.super.beforeAll(extensionContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import cz.xtf.core.openshift.helpers.ResourceParsers;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.client.dsl.PodResource;
import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext;
import io.fabric8.openshift.client.internal.readiness.OpenShiftReadiness;
import okhttp3.Request;

@AutoService(Cryostat.class)
Expand All @@ -43,8 +44,7 @@ public class OpenshiftCryostat extends Cryostat implements ReusableOpenshiftDepl
public void undeploy() {
try {
OpenshiftClient.get().customResource(CRYOSTAT_CTX).delete(OpenshiftClient.get().getNamespace(), APP_NAME, true);
WaitUtils.waitFor(() -> OpenshiftClient.get().getLabeledPods(Map.of("kind", "cryostat", "app", APP_NAME))
.isEmpty(), "Waiting until Cryostat pods are deleted");
WaitUtils.waitFor(() -> servicePod() == null, "Waiting until the pod is removed");
deleteSubscription(() -> OpenshiftClient.get().getLabeledPods("control-plane", "controller-manager")
.stream().noneMatch(p -> p.getMetadata().getName().contains("cryostat")));
} catch (IOException e) {
Expand Down Expand Up @@ -85,10 +85,9 @@ public void create() {

@Override
public boolean isReady() {
final List<Pod> labeledPods = OpenshiftClient.get().getLabeledPods(Map.of("kind", "cryostat", "app", APP_NAME));
final PodResource<Pod> pod = servicePod();
try {
return labeledPods.size() > 0
&& labeledPods.stream().allMatch(OpenShiftReadiness::isPodReady)
return pod != null && pod.isReady()
&& HTTPUtils.trustAllSslClient().newCall(new Request.Builder().get().url(String.format("https://%s/health"
, OpenshiftClient.get().getRoute(APP_NAME).getSpec().getHost())).build()).execute().isSuccessful();
} catch (IOException e) {
Expand All @@ -105,6 +104,11 @@ public boolean isDeployed() {
&& ((List) OpenshiftClient.get().customResource(CRYOSTAT_CTX).list().get("items")).size() == 1;
}

@Override
public Predicate<Pod> podSelector() {
return p -> OpenshiftClient.get().hasLabels(p, Map.of("kind", "cryostat", "app", APP_NAME));
}

@Override
public String connectionUrl() {
return String.format("https://%s", OpenshiftClient.get().getRoute(APP_NAME).getSpec().getHost());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public void openResources() {

@Override
public void closeResources() {
validation = null;
if (session != null) {
session.close();
session = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import software.tnb.common.openshift.OpenshiftClient;
import software.tnb.common.utils.IOUtils;
import software.tnb.common.utils.NetworkUtils;
import software.tnb.common.utils.WaitUtils;
import software.tnb.db.cassandra.service.Cassandra;

import com.datastax.oss.driver.api.core.CqlSession;
Expand All @@ -17,17 +18,16 @@

import java.net.InetSocketAddress;
import java.time.Duration;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import cz.xtf.core.openshift.OpenShiftWaiters;
import cz.xtf.core.openshift.helpers.ResourceFunctions;
import io.fabric8.kubernetes.api.model.EnvVar;
import io.fabric8.kubernetes.api.model.IntOrString;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.ServiceBuilder;
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
import io.fabric8.kubernetes.client.LocalPortForward;
import io.fabric8.kubernetes.client.dsl.PodResource;

@AutoService(Cassandra.class)
public class OpenshiftCassandra extends Cassandra implements OpenshiftDeployable, WithName, WithInClusterHostname, WithExternalHostname {
Expand Down Expand Up @@ -122,8 +122,7 @@ public String host() {
public void undeploy() {
OpenshiftClient.get().services().withName(name()).delete();
OpenshiftClient.get().apps().deployments().withName(name()).delete();
OpenShiftWaiters.get(OpenshiftClient.get(), () -> false)
.areNoPodsPresent(OpenshiftConfiguration.openshiftDeploymentLabel(), name()).timeout(120_000).waitFor();
WaitUtils.waitFor(() -> servicePod() == null, "Waiting until the pod is removed");
}

@Override
Expand All @@ -147,6 +146,7 @@ public void openResources() {

@Override
public void closeResources() {
validation = null;
if (session != null) {
session.close();
session = null;
Expand All @@ -157,16 +157,22 @@ public void closeResources() {

@Override
public boolean isReady() {
List<Pod> pods = OpenshiftClient.get().getLabeledPods(OpenshiftConfiguration.openshiftDeploymentLabel(), name());
if (ResourceFunctions.areExactlyNPodsReady(1).apply(pods)) {
return OpenshiftClient.get().getLogs(pods.get(0)).contains("Startup complete");
final PodResource<Pod> pod = servicePod();
if (pod.isReady()) {
return OpenshiftClient.get().getLogs(pod.get()).contains("Startup complete");
}
return false;
}

@Override
public boolean isDeployed() {
return OpenshiftClient.get().getLabeledPods(OpenshiftConfiguration.openshiftDeploymentLabel(), name()).size() > 0;
return OpenshiftClient.get().apps().deployments().withLabel(OpenshiftConfiguration.openshiftDeploymentLabel(), name()).list()
.getItems().size() > 0;
}

@Override
public Predicate<Pod> podSelector() {
return WithName.super.podSelector();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ public abstract class Cassandra implements Service, WithDockerImage {

public static final int CASSANDRA_PORT = 9042;

private CassandraValidation validation;
private CassandraAccount account;
protected CassandraValidation validation;

public String defaultImage() {
// official library image required hacks in openshift, bitnami works out of the box
Expand Down
Loading

0 comments on commit e3550bd

Please sign in to comment.