diff --git a/junit5/pom.xml b/junit5/pom.xml index 295549fc..1863c833 100644 --- a/junit5/pom.xml +++ b/junit5/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 @@ -44,5 +45,4 @@ - \ No newline at end of file diff --git a/junit5/src/main/java/cz/xtf/junit5/extensions/OpenShiftRecorderService.java b/junit5/src/main/java/cz/xtf/junit5/extensions/OpenShiftRecorderService.java index c925d9a6..3bcf20e9 100644 --- a/junit5/src/main/java/cz/xtf/junit5/extensions/OpenShiftRecorderService.java +++ b/junit5/src/main/java/cz/xtf/junit5/extensions/OpenShiftRecorderService.java @@ -16,6 +16,7 @@ import cz.xtf.core.openshift.OpenShifts; import cz.xtf.junit5.annotations.OpenShiftRecorder; import cz.xtf.junit5.config.JUnitConfig; +import cz.xtf.junit5.extensions.helpers.CustomResourceHelper; import cz.xtf.junit5.extensions.helpers.EventsFilterBuilder; import cz.xtf.junit5.extensions.helpers.ResourcesFilterBuilder; import cz.xtf.junit5.extensions.helpers.ResourcesPrinterHelper; @@ -32,6 +33,10 @@ import io.fabric8.openshift.api.model.DeploymentConfig; import io.fabric8.openshift.api.model.ImageStream; import io.fabric8.openshift.api.model.Route; +import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup; +import io.fabric8.openshift.api.model.operatorhub.v1alpha1.ClusterServiceVersion; +import io.fabric8.openshift.api.model.operatorhub.v1alpha1.InstallPlan; +import io.fabric8.openshift.api.model.operatorhub.v1alpha1.Subscription; /** * Record OpenShift isolated state relative to a test. @@ -88,6 +93,15 @@ public class OpenShiftRecorderService { private static final String IS_FILTER_BUILDS = "IS_FILTER_BUILDS"; private static final String EVENT_FILTER_BUILDS = "EVENT_FILTER_BUILDS"; + private CustomResourceHelper customResourceHelper; + + private CustomResourceHelper getCustomResourceHelper() { + if (customResourceHelper == null) { + customResourceHelper = new CustomResourceHelper(); + } + return customResourceHelper; + } + /** * Initialize filters by collecting information OCP resources which are relevant for the current test execution * context (e.g.: called by a {@link org.junit.jupiter.api.extension.BeforeAllCallback#beforeAll(ExtensionContext)} @@ -213,6 +227,10 @@ public void recordState(ExtensionContext context) throws IOException { !isMasterAndBuildNamespaceSame() ? getFilter(context, BUILD_FILTER_MASTER) : null); saveEvents(context, getFilter(context, EVENT_FILTER_MASTER), !isMasterAndBuildNamespaceSame() ? getFilter(context, EVENT_FILTER_BUILDS) : null); + saveClusterServiceVersions(context); + saveInstallPlans(context); + saveOperatorGroups(context); + saveSubscriptions(context); } private boolean isFilterInitializationComplete(ExtensionContext context) { @@ -521,6 +539,39 @@ protected void saveBuildLogs(ExtensionContext context, ResourcesFilterBuilder printer = ResourcesPrinterHelper + .forClusterServiceVersion(logPath)) { + getCustomResourceHelper().getClusterServiceVersionClient().list().getItems().stream() + .forEach(printer::row); + } + } + + protected void saveInstallPlans(ExtensionContext context) throws IOException { + final Path logPath = Paths.get(attachmentsDir(), dirNameForTest(context), "installPlans.log"); + try (final ResourcesPrinterHelper printer = ResourcesPrinterHelper.forInstallPlan(logPath)) { + getCustomResourceHelper().getInstallPlanClient().list().getItems().stream() + .forEach(printer::row); + } + } + + protected void saveOperatorGroups(ExtensionContext context) throws IOException { + final Path logPath = Paths.get(attachmentsDir(), dirNameForTest(context), "operatorGroups.log"); + try (final ResourcesPrinterHelper printer = ResourcesPrinterHelper.forOperatorGroup(logPath)) { + getCustomResourceHelper().getOperatorGroupClient().list().getItems().stream() + .forEach(printer::row); + } + } + + protected void saveSubscriptions(ExtensionContext context) throws IOException { + final Path logPath = Paths.get(attachmentsDir(), dirNameForTest(context), "subscriptions.log"); + try (final ResourcesPrinterHelper printer = ResourcesPrinterHelper.forSubscription(logPath)) { + getCustomResourceHelper().getSubscriptionClient().list().getItems().stream() + .forEach(printer::row); + } + } + private String attachmentsDir() { return JUnitConfig.recordDir() != null ? JUnitConfig.recordDir() : System.getProperty("user.dir"); } diff --git a/junit5/src/main/java/cz/xtf/junit5/extensions/helpers/CustomResourceHelper.java b/junit5/src/main/java/cz/xtf/junit5/extensions/helpers/CustomResourceHelper.java new file mode 100644 index 00000000..dfdbae45 --- /dev/null +++ b/junit5/src/main/java/cz/xtf/junit5/extensions/helpers/CustomResourceHelper.java @@ -0,0 +1,86 @@ +package cz.xtf.junit5.extensions.helpers; + +import cz.xtf.core.openshift.OpenShifts; +import io.fabric8.kubernetes.client.dsl.MixedOperation; +import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; +import io.fabric8.kubernetes.client.dsl.Resource; +import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext; +import io.fabric8.openshift.api.model.operatorhub.v1.DoneableOperatorGroup; +import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup; +import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroupList; +import io.fabric8.openshift.api.model.operatorhub.v1alpha1.ClusterServiceVersion; +import io.fabric8.openshift.api.model.operatorhub.v1alpha1.ClusterServiceVersionList; +import io.fabric8.openshift.api.model.operatorhub.v1alpha1.DoneableClusterServiceVersion; +import io.fabric8.openshift.api.model.operatorhub.v1alpha1.DoneableInstallPlan; +import io.fabric8.openshift.api.model.operatorhub.v1alpha1.DoneableSubscription; +import io.fabric8.openshift.api.model.operatorhub.v1alpha1.InstallPlan; +import io.fabric8.openshift.api.model.operatorhub.v1alpha1.InstallPlanList; +import io.fabric8.openshift.api.model.operatorhub.v1alpha1.Subscription; +import io.fabric8.openshift.api.model.operatorhub.v1alpha1.SubscriptionList; + +/** + *

This class provides the clients used to interact with some of the APIs of the Operator Lifecycle Manager (OLM)

+ *

For example it provides the client to ineract with ClusterServiceVersion

+ */ +public class CustomResourceHelper { + + public static final String OPERATORS_COREOS_COM = "operators.coreos.com"; + + public NonNamespaceOperation> getClusterServiceVersionClient() { + CustomResourceDefinitionContext clusterserviceversionsContext = new CustomResourceDefinitionContext.Builder() + .withGroup(OPERATORS_COREOS_COM).withVersion("v1alpha1").withScope("Namespaced") + .withName("clusterserviceversions.operators.coreos.com").withPlural("clusterserviceversions") + .withKind("ClusterServiceVersion").build(); + + NonNamespaceOperation> client = OpenShifts + .admin().customResources(clusterserviceversionsContext, ClusterServiceVersion.class, + ClusterServiceVersionList.class, DoneableClusterServiceVersion.class); + client = ((MixedOperation>) client) + .inNamespace(OpenShifts.master().getNamespace()); + return client; + } + + public NonNamespaceOperation> getInstallPlanClient() { + CustomResourceDefinitionContext installplansContext = new CustomResourceDefinitionContext.Builder() + .withGroup(OPERATORS_COREOS_COM).withVersion("v1alpha1").withScope("Namespaced") + .withName("installplans.operators.coreos.com").withPlural("installplans").withKind("InstallPlan") + .build(); + + NonNamespaceOperation> client = OpenShifts + .admin().customResources(installplansContext, InstallPlan.class, InstallPlanList.class, + DoneableInstallPlan.class); + client = ((MixedOperation>) client) + .inNamespace(OpenShifts.master().getNamespace()); + + return client; + } + + public NonNamespaceOperation> getOperatorGroupClient() { + CustomResourceDefinitionContext operatorgroupsContext = new CustomResourceDefinitionContext.Builder() + .withGroup(OPERATORS_COREOS_COM).withVersion("v1").withScope("Namespaced") + .withName("operatorgroups.operators.coreos.com").withPlural("operatorgroups").withKind("OperatorGroup") + .build(); + + NonNamespaceOperation> client = OpenShifts + .admin().customResources(operatorgroupsContext, OperatorGroup.class, OperatorGroupList.class, + DoneableOperatorGroup.class); + client = ((MixedOperation>) client) + .inNamespace(OpenShifts.master().getNamespace()); + + return client; + } + + public NonNamespaceOperation> getSubscriptionClient() { + CustomResourceDefinitionContext subscriptionsContext = new CustomResourceDefinitionContext.Builder() + .withGroup(OPERATORS_COREOS_COM).withVersion("v1alpha1").withScope("Namespaced") + .withName("subscriptions.operators.coreos.com").withPlural("subscriptions").withKind("Subscription") + .build(); + + NonNamespaceOperation> client = OpenShifts + .admin().customResources(subscriptionsContext, Subscription.class, SubscriptionList.class, + DoneableSubscription.class); + client = ((MixedOperation>) client) + .inNamespace(OpenShifts.master().getNamespace()); + return client; + } +} diff --git a/junit5/src/main/java/cz/xtf/junit5/extensions/helpers/ResourcesPrinterHelper.java b/junit5/src/main/java/cz/xtf/junit5/extensions/helpers/ResourcesPrinterHelper.java index d08f2cf4..f6bdd2c7 100644 --- a/junit5/src/main/java/cz/xtf/junit5/extensions/helpers/ResourcesPrinterHelper.java +++ b/junit5/src/main/java/cz/xtf/junit5/extensions/helpers/ResourcesPrinterHelper.java @@ -10,6 +10,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.function.Function; +import java.util.stream.Collectors; import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ContainerStatus; @@ -23,6 +24,10 @@ import io.fabric8.openshift.api.model.DeploymentConfig; import io.fabric8.openshift.api.model.ImageStream; import io.fabric8.openshift.api.model.Route; +import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup; +import io.fabric8.openshift.api.model.operatorhub.v1alpha1.ClusterServiceVersion; +import io.fabric8.openshift.api.model.operatorhub.v1alpha1.InstallPlan; +import io.fabric8.openshift.api.model.operatorhub.v1alpha1.Subscription; public class ResourcesPrinterHelper implements AutoCloseable { private final Path file; @@ -189,6 +194,72 @@ private static LinkedHashMap getServicesCols(Service service) { return map; } + public static ResourcesPrinterHelper forClusterServiceVersion(Path filePath) { + return new ResourcesPrinterHelper<>(filePath, + ResourcesPrinterHelper::getClusterServiceVersionCols); + } + + private static LinkedHashMap getClusterServiceVersionCols(ClusterServiceVersion csv) { + LinkedHashMap map = new LinkedHashMap<>(5); + map.put("NAME", csv.getMetadata().getName()); + map.put("CREATED", csv.getMetadata().getCreationTimestamp()); + map.put("PHASE", csv.getStatus().getPhase()); + map.put("REASON", csv.getStatus().getReason()); + map.put("MESSAGE", csv.getStatus().getMessage()); + return map; + } + + public static ResourcesPrinterHelper forInstallPlan(Path filePath) { + return new ResourcesPrinterHelper<>(filePath, + ResourcesPrinterHelper::getInstallPlanCols); + } + + private static LinkedHashMap getInstallPlanCols(InstallPlan ip) { + LinkedHashMap map = new LinkedHashMap<>(6); + map.put("NAME", ip.getMetadata().getName()); + map.put("CREATED", ip.getMetadata().getCreationTimestamp()); + map.put("PHASE", ip.getStatus().getPhase()); + map.put("CATALOG SOURCES", ip.getStatus().getCatalogSources().toString()); + map.put("CSVS", ip.getSpec().getClusterServiceVersionNames().toString()); + map.put("CONDITIONS", ip.getStatus().getConditions() + .stream() + .filter(cond -> "True".equalsIgnoreCase(cond.getStatus())) + .map(cond -> cond.getType()) + .collect(Collectors.joining(",", "[", "]"))); + return map; + } + + public static ResourcesPrinterHelper forOperatorGroup(Path filePath) { + return new ResourcesPrinterHelper<>(filePath, + ResourcesPrinterHelper::getOperatorGroupCols); + } + + private static LinkedHashMap getOperatorGroupCols(OperatorGroup og) { + LinkedHashMap map = new LinkedHashMap<>(3); + map.put("NAME", og.getMetadata().getName()); + map.put("TARGET NAMESPACE", og.getSpec().getTargetNamespaces().toString()); + map.put("NAMESPACES", og.getStatus().getNamespaces().toString()); + return map; + } + + public static ResourcesPrinterHelper forSubscription(Path filePath) { + return new ResourcesPrinterHelper<>(filePath, + ResourcesPrinterHelper::getSubscriptionCols); + } + + private static LinkedHashMap getSubscriptionCols(Subscription subscription) { + LinkedHashMap map = new LinkedHashMap<>(8); + map.put("NAME", subscription.getMetadata().getName()); + map.put("SOURCE", subscription.getSpec().getSource()); + map.put("CHANNEL", subscription.getSpec().getChannel()); + map.put("STARTING CSV", subscription.getSpec().getStartingCSV()); + map.put("INSTALLED CSV", subscription.getStatus().getInstalledCSV()); + map.put("CURRENT CSV", subscription.getStatus().getCurrentCSV()); + map.put("STATE", subscription.getStatus().getState()); + map.put("REASON", subscription.getStatus().getReason()); + return map; + } + public void row(X resource) { row(resourceToCols.apply(resource)); }