From 37e2c1dc8aa3b0ee550b53106319c185d4af4554 Mon Sep 17 00:00:00 2001 From: David Kornel Date: Tue, 27 Feb 2024 11:48:05 +0100 Subject: [PATCH] Add initial implementation of ResourceManager (#17) * Add initial implementation of ResourceManager Signed-off-by: David Kornel --- .gitignore | 7 +- pom.xml | 26 ++ test-frame-common/pom.xml | 16 ++ .../io/skodjob/testframe/LoggerUtils.java | 27 ++ .../skodjob/testframe/TestFrameConstants.java | 16 ++ .../io/skodjob/testframe/TestFrameEnv.java | 97 +++++++ .../skodjob/testframe/clients/KubeClient.java | 130 ++++++++- .../interfaces/NamespacedResourceType.java | 10 +- .../testframe/interfaces/ResourceType.java | 21 +- .../testframe/interfaces/ThrowableRunner.java | 10 + .../listeners/ResourceManagerExtension.java | 39 +++ .../TestVisualSeparatorExtension.java | 32 +++ .../resources/ResourceCondition.java | 40 +++ .../testframe/resources/ResourceItem.java | 30 ++ .../testframe/resources/ResourceManager.java | 257 ++++++++++++++++++ .../testframe/utils/TestFrameUtils.java | 99 +++++++ .../java/io/skodjob/testframe/wait/Wait.java | 72 +++++ .../resources/ClusterRoleBindingResource.java | 21 +- .../resources/ClusterRoleResource.java | 21 +- .../resources/ConfigMapResource.java | 33 ++- .../CustomResourceDefinitionResource.java | 22 +- .../resources/DeploymentResource.java | 21 +- .../testframe/resources/JobResource.java | 21 +- .../testframe/resources/LeaseResource.java | 21 +- .../resources/NamespaceResource.java | 21 +- .../resources/NetworkPolicyResource.java | 22 +- .../resources/RoleBindingResource.java | 21 +- .../testframe/resources/RoleResource.java | 23 +- .../testframe/resources/SecretResource.java | 23 +- .../resources/ServiceAccountResource.java | 23 +- .../testframe/resources/ServiceResource.java | 23 +- ...alidatingWebhookConfigurationResource.java | 21 +- .../resources/OperatorGroupResource.java | 21 +- .../resources/SubscriptionResource.java | 21 +- 34 files changed, 1153 insertions(+), 155 deletions(-) create mode 100644 test-frame-common/src/main/java/io/skodjob/testframe/LoggerUtils.java create mode 100644 test-frame-common/src/main/java/io/skodjob/testframe/TestFrameConstants.java create mode 100644 test-frame-common/src/main/java/io/skodjob/testframe/TestFrameEnv.java create mode 100644 test-frame-common/src/main/java/io/skodjob/testframe/interfaces/ThrowableRunner.java create mode 100644 test-frame-common/src/main/java/io/skodjob/testframe/listeners/ResourceManagerExtension.java create mode 100644 test-frame-common/src/main/java/io/skodjob/testframe/listeners/TestVisualSeparatorExtension.java create mode 100644 test-frame-common/src/main/java/io/skodjob/testframe/resources/ResourceCondition.java create mode 100644 test-frame-common/src/main/java/io/skodjob/testframe/resources/ResourceItem.java create mode 100644 test-frame-common/src/main/java/io/skodjob/testframe/resources/ResourceManager.java create mode 100644 test-frame-common/src/main/java/io/skodjob/testframe/utils/TestFrameUtils.java diff --git a/.gitignore b/.gitignore index 5ffdec9..22342a5 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,9 @@ target/ *.iml ### Mac OS ### -**.DS_Store \ No newline at end of file +**.DS_Store + +## Frame specific files +**/*.kubeconfig +*.env +config.yaml \ No newline at end of file diff --git a/pom.xml b/pom.xml index d01fe6f..4385e13 100644 --- a/pom.xml +++ b/pom.xml @@ -82,6 +82,7 @@ 3.4.1 3.4.2 3.9.0 + 5.10.2 @@ -101,6 +102,31 @@ openshift-client-api ${fabric8.version} + + io.fabric8 + openshift-client + ${fabric8.version} + + + io.fabric8 + kubernetes-client + ${fabric8.version} + + + io.fabric8 + kubernetes-model + ${fabric8.version} + + + io.fabric8 + generator-annotations + ${fabric8.version} + + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + diff --git a/test-frame-common/pom.xml b/test-frame-common/pom.xml index 3c8dc54..7f65cb8 100644 --- a/test-frame-common/pom.xml +++ b/test-frame-common/pom.xml @@ -69,5 +69,21 @@ io.fabric8 openshift-client-api + + io.fabric8 + openshift-client + + + io.fabric8 + kubernetes-client + + + io.fabric8 + kubernetes-model + + + org.junit.jupiter + junit-jupiter-api + \ No newline at end of file diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/LoggerUtils.java b/test-frame-common/src/main/java/io/skodjob/testframe/LoggerUtils.java new file mode 100644 index 0000000..fcc34ad --- /dev/null +++ b/test-frame-common/src/main/java/io/skodjob/testframe/LoggerUtils.java @@ -0,0 +1,27 @@ +/* + * Copyright Skodjob authors. + * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html). + */ +package io.skodjob.testframe; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; + +public class LoggerUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(LoggerUtils.class); + static final String SEPARATOR_CHAR = "#"; + + public static final String RESOURCE_LOGGER_PATTERN = "{} {}/{}"; + public static final String RESOURCE_WITH_NAMESPACE_LOGGER_PATTERN = "{} {}/{} in {}"; + + public static void logSeparator() { + logSeparator(SEPARATOR_CHAR, 76); + } + + public static void logSeparator(String delimiterChar, int length) { + LOGGER.info(String.join("", Collections.nCopies(length, delimiterChar))); + } +} diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/TestFrameConstants.java b/test-frame-common/src/main/java/io/skodjob/testframe/TestFrameConstants.java new file mode 100644 index 0000000..3f9198c --- /dev/null +++ b/test-frame-common/src/main/java/io/skodjob/testframe/TestFrameConstants.java @@ -0,0 +1,16 @@ +package io.skodjob.testframe; + +import java.time.Duration; + +public class TestFrameConstants { + private TestFrameConstants() { + } + public static final long GLOBAL_POLL_INTERVAL_LONG = Duration.ofSeconds(15).toMillis(); + public static final long GLOBAL_POLL_INTERVAL_MEDIUM = Duration.ofSeconds(10).toMillis(); + public static final long GLOBAL_POLL_INTERVAL_SHORT = Duration.ofSeconds(5).toMillis(); + public static final long GLOBAL_POLL_INTERVAL_1_SEC = Duration.ofSeconds(1).toMillis(); + public static final long GLOBAL_TIMEOUT = Duration.ofMinutes(10).toMillis(); + public static final String OPENSHIFT_CLIENT = "oc"; + public static final String KUBERNETES_CLIENT = "kubectl"; + +} diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/TestFrameEnv.java b/test-frame-common/src/main/java/io/skodjob/testframe/TestFrameEnv.java new file mode 100644 index 0000000..ec12345 --- /dev/null +++ b/test-frame-common/src/main/java/io/skodjob/testframe/TestFrameEnv.java @@ -0,0 +1,97 @@ +/* + * Copyright Skodjob authors. + * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html). + */ +package io.skodjob.testframe; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.yaml.snakeyaml.Yaml; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; + +/** + * Class which holds environment variables for system tests. + */ +public class TestFrameEnv { + + private static final Logger LOGGER = LoggerFactory.getLogger(TestFrameEnv.class); + private static final Map VALUES = new HashMap<>(); + private static final Map YAML_DATA = loadConfigurationFile(); + public static final String USER_PATH = System.getProperty("user.dir"); + + private static final String CONFIG_FILE_PATH_ENV = "ENV_FILE"; + private static final String CLIENT_TYPE_ENV = "CLIENT_TYPE"; + private static final String USERNAME_ENV = "KUBE_USERNAME"; + private static final String PASSWORD_ENV = "KUBE_PASSWORD"; + private static final String TOKEN_ENV = "KUBE_TOKEN"; + private static final String URL_ENV = "KUBE_URL"; + + /** + * Set values + */ + public static final String CLIENT_TYPE = getOrDefault(CLIENT_TYPE_ENV, TestFrameConstants.KUBERNETES_CLIENT); + public static final String KUBE_USERNAME = getOrDefault(USERNAME_ENV, null); + public static final String KUBE_PASSWORD = getOrDefault(PASSWORD_ENV, null); + public static final String KUBE_TOKEN = getOrDefault(TOKEN_ENV, null); + public static final String KUBE_URL = getOrDefault(URL_ENV, null); + + private TestFrameEnv() { + } + + static { + String debugFormat = "{}: {}"; + LoggerUtils.logSeparator("-", 30); + LOGGER.info("Used environment variables:"); + VALUES.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .forEach(entry -> { + if (!Objects.equals(entry.getValue(), "null")) { + LOGGER.info(debugFormat, entry.getKey(), entry.getValue()); + } + }); + LoggerUtils.logSeparator("-", 30); + } + + public static void print() { + } + + private static String getOrDefault(String varName, String defaultValue) { + return getOrDefault(varName, String::toString, defaultValue); + } + + private static T getOrDefault(String var, Function converter, T defaultValue) { + String value = System.getenv(var) != null ? + System.getenv(var) : + (Objects.requireNonNull(YAML_DATA).get(var) != null ? + YAML_DATA.get(var).toString() : + null); + T returnValue = defaultValue; + if (value != null) { + returnValue = converter.apply(value); + } + VALUES.put(var, String.valueOf(returnValue)); + return returnValue; + } + + private static Map loadConfigurationFile() { + String config = System.getenv().getOrDefault(CONFIG_FILE_PATH_ENV, + Paths.get(System.getProperty("user.dir"), "config.yaml").toAbsolutePath().toString()); + Yaml yaml = new Yaml(); + try { + File yamlFile = new File(config).getAbsoluteFile(); + return yaml.load(new FileInputStream(yamlFile)); + } catch (IOException ex) { + LOGGER.info("Yaml configuration not provider or not exists"); + return Collections.emptyMap(); + } + } +} diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/clients/KubeClient.java b/test-frame-common/src/main/java/io/skodjob/testframe/clients/KubeClient.java index 8edb3f8..6a1c54d 100644 --- a/test-frame-common/src/main/java/io/skodjob/testframe/clients/KubeClient.java +++ b/test-frame-common/src/main/java/io/skodjob/testframe/clients/KubeClient.java @@ -5,24 +5,27 @@ package io.skodjob.testframe.clients; import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.ConfigBuilder; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientBuilder; import io.fabric8.openshift.client.OpenShiftClient; +import io.skodjob.testframe.TestFrameConstants; +import io.skodjob.testframe.TestFrameEnv; +import io.skodjob.testframe.executor.Exec; + +import java.util.Arrays; public class KubeClient { private KubernetesClient client; - private static KubeClient kubeClient; + private String kubeconfigPath; - private KubeClient() { - this.client = new KubernetesClientBuilder().withConfig(Config.autoConfigure(System.getenv().getOrDefault("TEST_CLUSTER_CONTEXT", null))).build(); - } + public KubeClient() { + Config config = getConfig(); - public static KubeClient getInstance() { - if (kubeClient == null) { - kubeClient = new KubeClient(); - } - return kubeClient; + this.client = new KubernetesClientBuilder() + .withConfig(config) + .build(); } public KubernetesClient getClient() { @@ -32,4 +35,113 @@ public KubernetesClient getClient() { public OpenShiftClient getOpenShiftClient() { return client.adapt(OpenShiftClient.class); } + + public String getKubeconfigPath() { + return kubeconfigPath; + } + + private Config getConfig() { + if (TestFrameEnv.KUBE_USERNAME != null + && TestFrameEnv.KUBE_PASSWORD != null + && TestFrameEnv.KUBE_URL != null) { + kubeconfigPath = createLocalKubeconfig(); + return new ConfigBuilder() + .withUsername(TestFrameEnv.KUBE_USERNAME) + .withPassword(TestFrameEnv.KUBE_PASSWORD) + .withMasterUrl(TestFrameEnv.KUBE_URL) + .withDisableHostnameVerification(true) + .withTrustCerts(true) + .build(); + } else if (TestFrameEnv.KUBE_URL != null + && TestFrameEnv.KUBE_TOKEN != null) { + kubeconfigPath = createLocalKubeconfig(); + return new ConfigBuilder() + .withOauthToken(TestFrameEnv.KUBE_TOKEN) + .withMasterUrl(TestFrameEnv.KUBE_URL) + .withDisableHostnameVerification(true) + .withTrustCerts(true) + .build(); + } else { + return Config.autoConfigure(System.getenv() + .getOrDefault("KUBE_CONTEXT", null)); + } + } + + private String createLocalKubeconfig() { + try { + if (TestFrameEnv.CLIENT_TYPE.equals(TestFrameConstants.OPENSHIFT_CLIENT)) { + if (TestFrameEnv.KUBE_URL != null && TestFrameEnv.KUBE_TOKEN != null) { + createLocalOcKubeconfig(TestFrameEnv.KUBE_TOKEN, TestFrameEnv.KUBE_URL); + } else { + createLocalOcKubeconfig(TestFrameEnv.KUBE_USERNAME, TestFrameEnv.KUBE_PASSWORD, TestFrameEnv.KUBE_URL); + } + } else { + if (TestFrameEnv.KUBE_URL != null && TestFrameEnv.KUBE_TOKEN != null) { + createLocalKubectlContext(TestFrameEnv.KUBE_TOKEN, TestFrameEnv.KUBE_URL); + } else { + createLocalKubectlContext(TestFrameEnv.KUBE_USERNAME, TestFrameEnv.KUBE_PASSWORD, TestFrameEnv.KUBE_URL); + } + } + return TestFrameEnv.USER_PATH + "/test.kubeconfig"; + } catch (Exception ex) { + return null; + } + } + + private void createLocalOcKubeconfig(String username, String password, String apiUrl) { + Exec.exec(null, Arrays.asList("oc", "login", + "-u", username, + "-p", password, + "--insecure-skip-tls-verify", + "--kubeconfig", TestFrameEnv.USER_PATH + "/test.kubeconfig", + apiUrl), 0, false, true); + } + + private void createLocalOcKubeconfig(String token, String apiUrl) { + Exec.exec(null, Arrays.asList("oc", "login", "--token", token, + "--insecure-skip-tls-verify", + "--kubeconfig", TestFrameEnv.USER_PATH + "/test.kubeconfig", + apiUrl), 0, false, true); + } + + private void createLocalKubectlContext(String username, String password, String apiUrl) { + + Exec.exec(null, Arrays.asList("kubectl", "config", + "set-credentials", "test-user", + "--username", username, + "--password", password, + "--kubeconfig", TestFrameEnv.USER_PATH + "/test.kubeconfig"), + 0, false, true); + buildKubectlContext(apiUrl); + + } + + private void createLocalKubectlContext(String token, String apiUrl) { + Exec.exec(null, Arrays.asList("kubectl", "config", + "set-credentials", "test-user", + "--token", token, + "--kubeconfig", TestFrameEnv.USER_PATH + "/test.kubeconfig"), + 0, false, true); + buildKubectlContext(apiUrl); + + } + + private void buildKubectlContext(String apiUrl) { + Exec.exec(null, Arrays.asList("kubectl", "config", + "set-cluster", "test-cluster", + "--insecure-skip-tls-verify=true", "--server", apiUrl, + "--kubeconfig", TestFrameEnv.USER_PATH + "/test.kubeconfig"), + 0, false, true); + Exec.exec(null, Arrays.asList("kubectl", "config", + "set-context", "test-context", + "--user", "test-user", + "--cluster", "test-cluster", + "--namespace", "default", + "--kubeconfig", TestFrameEnv.USER_PATH + "/test.kubeconfig"), + 0, false, true); + Exec.exec(null, Arrays.asList("kubectl", "config", + "use-context", "test-context", + "--kubeconfig", TestFrameEnv.USER_PATH + "/test.kubeconfig"), + 0, false, true); + } } \ No newline at end of file diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/interfaces/NamespacedResourceType.java b/test-frame-common/src/main/java/io/skodjob/testframe/interfaces/NamespacedResourceType.java index 3cb394b..aa94d1a 100644 --- a/test-frame-common/src/main/java/io/skodjob/testframe/interfaces/NamespacedResourceType.java +++ b/test-frame-common/src/main/java/io/skodjob/testframe/interfaces/NamespacedResourceType.java @@ -5,19 +5,17 @@ package io.skodjob.testframe.interfaces; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.api.model.KubernetesResourceList; import io.fabric8.kubernetes.client.dsl.MixedOperation; -import io.fabric8.kubernetes.client.dsl.Resource; import java.util.function.Consumer; -public interface NamespacedResourceType, M extends Resource> extends ResourceType { +public interface NamespacedResourceType extends ResourceType { /** - * Returns client for resource {@link T} - * @return client of a MixedOperation<{@link T}, {@link L}, Resource<{@link T}>> resource + * Get specific {@link T} client for resoruce + * @return specific client */ - MixedOperation getClient(); + MixedOperation getClient(); /** * Creates specific {@link T} resource in Namespace specified by user diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/interfaces/ResourceType.java b/test-frame-common/src/main/java/io/skodjob/testframe/interfaces/ResourceType.java index a114de1..b5f57d8 100644 --- a/test-frame-common/src/main/java/io/skodjob/testframe/interfaces/ResourceType.java +++ b/test-frame-common/src/main/java/io/skodjob/testframe/interfaces/ResourceType.java @@ -5,27 +5,28 @@ package io.skodjob.testframe.interfaces; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.api.model.KubernetesResourceList; -import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition; -import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionList; -import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; -import io.fabric8.kubernetes.client.dsl.Resource; import java.util.function.Consumer; /** * Class for encapsulating methods related to {@link T} resource. * @param resource type - * @param resource's list */ -public interface ResourceType, M extends Resource> { +public interface ResourceType { /** - * Returns client for resource {@link T} - * @return client of a MixedOperation<{@link T}, {@link L}, Resource<{@link T}>> resource + * Get specific client for resoruce + * @return specific client */ - NonNamespaceOperation getClient(); + NonNamespaceOperation getClient(); + + + /** + * Kind of api resource + * @return kind name + */ + String getKind(); /** * Creates specific {@link T} resource diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/interfaces/ThrowableRunner.java b/test-frame-common/src/main/java/io/skodjob/testframe/interfaces/ThrowableRunner.java new file mode 100644 index 0000000..57fc565 --- /dev/null +++ b/test-frame-common/src/main/java/io/skodjob/testframe/interfaces/ThrowableRunner.java @@ -0,0 +1,10 @@ +/* + * Copyright Skodjob authors. + * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html). + */ +package io.skodjob.testframe.interfaces; + +@FunctionalInterface +public interface ThrowableRunner { + void run() throws Exception; +} diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/listeners/ResourceManagerExtension.java b/test-frame-common/src/main/java/io/skodjob/testframe/listeners/ResourceManagerExtension.java new file mode 100644 index 0000000..dd63118 --- /dev/null +++ b/test-frame-common/src/main/java/io/skodjob/testframe/listeners/ResourceManagerExtension.java @@ -0,0 +1,39 @@ +/* + * Copyright Skodjob authors. + * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html). + */ +package io.skodjob.testframe.listeners; + +import io.skodjob.testframe.resources.ResourceManager; +import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +/** + * jUnit5 specific class which listening on test callbacks + */ +public class ResourceManagerExtension implements BeforeAllCallback, BeforeEachCallback, AfterAllCallback, AfterEachCallback { + + @Override + public void beforeAll(ExtensionContext extensionContext) throws Exception { + ResourceManager.getInstance(); + ResourceManager.setTestContext(extensionContext); + } + + @Override + public void beforeEach(ExtensionContext extensionContext) throws Exception { + ResourceManager.setTestContext(extensionContext); + } + + @Override + public void afterAll(ExtensionContext extensionContext) throws Exception { + ResourceManager.setTestContext(extensionContext); + } + + @Override + public void afterEach(ExtensionContext extensionContext) throws Exception { + ResourceManager.setTestContext(extensionContext); + } +} diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/listeners/TestVisualSeparatorExtension.java b/test-frame-common/src/main/java/io/skodjob/testframe/listeners/TestVisualSeparatorExtension.java new file mode 100644 index 0000000..3806df4 --- /dev/null +++ b/test-frame-common/src/main/java/io/skodjob/testframe/listeners/TestVisualSeparatorExtension.java @@ -0,0 +1,32 @@ +/* + * Copyright Skodjob authors. + * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html). + */ +package io.skodjob.testframe.listeners; + +import io.skodjob.testframe.LoggerUtils; +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * jUnit5 specific class which listening on test callbacks + */ +public class TestVisualSeparatorExtension implements BeforeEachCallback, AfterEachCallback { + Logger LOGGER = LoggerFactory.getLogger(TestVisualSeparatorExtension.class); + @Override + public void beforeEach(ExtensionContext extensionContext) throws Exception { + LoggerUtils.logSeparator(); + LOGGER.info(String.format("%s.%s-STARTED", extensionContext.getRequiredTestClass().getName(), + extensionContext.getDisplayName().replace("()", ""))); + } + + @Override + public void afterEach(ExtensionContext extensionContext) throws Exception { + LOGGER.info(String.format("%s.%s-FINISHED", extensionContext.getRequiredTestClass().getName(), + extensionContext.getDisplayName().replace("()", ""))); + LoggerUtils.logSeparator(); + } +} diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/resources/ResourceCondition.java b/test-frame-common/src/main/java/io/skodjob/testframe/resources/ResourceCondition.java new file mode 100644 index 0000000..7c3b654 --- /dev/null +++ b/test-frame-common/src/main/java/io/skodjob/testframe/resources/ResourceCondition.java @@ -0,0 +1,40 @@ +/* + * Copyright Skodjob authors. + * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html). + */ + +package io.skodjob.testframe.resources; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.KubernetesResourceList; +import io.fabric8.kubernetes.client.dsl.Resource; +import io.skodjob.testframe.interfaces.ResourceType; + +import java.util.Objects; +import java.util.function.Predicate; + +public class ResourceCondition { + private final Predicate predicate; + private final String conditionName; + + public ResourceCondition(Predicate predicate, String conditionName) { + this.predicate = predicate; + this.conditionName = conditionName; + } + + public String getConditionName() { + return conditionName; + } + + public Predicate getPredicate() { + return predicate; + } + + public static ResourceCondition readiness(ResourceType type) { + return new ResourceCondition<>(type::waitForReadiness, "readiness"); + } + + public static ResourceCondition deletion() { + return new ResourceCondition<>(Objects::isNull, "deletion"); + } +} diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/resources/ResourceItem.java b/test-frame-common/src/main/java/io/skodjob/testframe/resources/ResourceItem.java new file mode 100644 index 0000000..eefe7a8 --- /dev/null +++ b/test-frame-common/src/main/java/io/skodjob/testframe/resources/ResourceItem.java @@ -0,0 +1,30 @@ +/* + * Copyright Skodjob authors. + * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html). + */ +package io.skodjob.testframe.resources; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.skodjob.testframe.interfaces.ThrowableRunner; + +public final class ResourceItem { + + ThrowableRunner throwableRunner; + T resource; + + public ResourceItem(ThrowableRunner throwableRunner, T resource) { + this.throwableRunner = throwableRunner; + this.resource = resource; + } + + public ResourceItem(ThrowableRunner throwableRunner) { + this.throwableRunner = throwableRunner; + } + + public ThrowableRunner getThrowableRunner() { + return throwableRunner; + } + public T getResource() { + return resource; + } +} diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/resources/ResourceManager.java b/test-frame-common/src/main/java/io/skodjob/testframe/resources/ResourceManager.java new file mode 100644 index 0000000..778cf68 --- /dev/null +++ b/test-frame-common/src/main/java/io/skodjob/testframe/resources/ResourceManager.java @@ -0,0 +1,257 @@ +/* + * Copyright Skodjob authors. + * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html). + */ +package io.skodjob.testframe.resources; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.skodjob.testframe.LoggerUtils; +import io.skodjob.testframe.TestFrameConstants; +import io.skodjob.testframe.TestFrameEnv; +import io.skodjob.testframe.clients.KubeClient; +import io.skodjob.testframe.clients.cmdClient.KubeCmdClient; +import io.skodjob.testframe.clients.cmdClient.Kubectl; +import io.skodjob.testframe.clients.cmdClient.Oc; +import io.skodjob.testframe.interfaces.ResourceType; +import io.skodjob.testframe.wait.Wait; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Stack; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ResourceManager { + private static final Logger LOGGER = LoggerFactory.getLogger(ResourceManager.class); + + private static ResourceManager instance; + private static KubeClient client; + private static KubeCmdClient kubeCmdClient; + + private static ThreadLocal testContext = new ThreadLocal<>(); + + private static final Map> STORED_RESOURCES = new LinkedHashMap<>(); + + public static synchronized ResourceManager getInstance() { + if (instance == null) { + instance = new ResourceManager(); + client = new KubeClient(); + if (TestFrameEnv.CLIENT_TYPE.equals(TestFrameConstants.KUBERNETES_CLIENT)) { + kubeCmdClient = new Kubectl(); + } else { + kubeCmdClient = new Oc(client.getKubeconfigPath()); + } + } + return instance; + } + + public static KubeClient getKubeClient() { + return client; + } + + public static KubeCmdClient getKubeCmdClient() { + return kubeCmdClient; + } + + private ResourceType[] resourceTypes; + + public static void setTestContext(ExtensionContext context) { + testContext.set(context); + } + + public static ExtensionContext getTestContext() { + return testContext.get(); + } + + public final void setResourceTypes(ResourceType... types) { + this.resourceTypes = types; + } + + public final void pushToStack(ResourceItem item) { + synchronized (this) { + STORED_RESOURCES.computeIfAbsent(getTestContext().getDisplayName(), k -> new Stack<>()); + STORED_RESOURCES.get(getTestContext().getDisplayName()).push(item); + } + } + + public final void pushToStack(T resource) { + synchronized (this) { + STORED_RESOURCES.computeIfAbsent(getTestContext().getDisplayName(), k -> new Stack<>()); + STORED_RESOURCES.get(getTestContext().getDisplayName()).push( + new ResourceItem( + () -> deleteResource(resource), + resource + )); + } + } + + @SafeVarargs + public final void createResourceWithoutWait(T... resources) { + createResource(false, resources); + } + + @SafeVarargs + public final void createResourceWithWait(T... resources) { + createResource(true, resources); + } + + @SafeVarargs + private void createResource(boolean waitReady, T... resources) { + for (T resource : resources) { + ResourceType type = findResourceType(resource); + pushToStack(resource); + + if (resource.getMetadata().getNamespace() == null) { + LOGGER.info(LoggerUtils.RESOURCE_LOGGER_PATTERN, + "Creating", resource.getKind(), resource.getMetadata().getName()); + } else { + LOGGER.info(LoggerUtils.RESOURCE_WITH_NAMESPACE_LOGGER_PATTERN, + "Creating", resource.getKind(), resource.getMetadata().getName(), resource.getMetadata().getNamespace()); + } + + if (type == null) { + // Generic create for any resource + client.getClient().resource(resource).create(); + if (waitReady) { + assertTrue(waitResourceCondition(resource, new ResourceCondition<>(p -> { + try { + return client.getClient().resource(resource).isReady(); + } catch (Exception ex) { + return client.getClient().resource(resource) != null; + } + }, "ready")), + String.format("Timed out waiting for %s/%s in %s to be ready", resource.getKind(), resource.getMetadata().getName(), resource.getMetadata().getNamespace())); + } + } else { + // Create for typed resource implementing ResourceType + type.create(resource); + if (waitReady) { + assertTrue(waitResourceCondition(resource, ResourceCondition.readiness(type)), + String.format("Timed out waiting for %s/%s in %s to be ready", resource.getKind(), resource.getMetadata().getName(), resource.getMetadata().getNamespace())); + } + } + } + } + + @SafeVarargs + public final void deleteResource(T... resources) { + for (T resource : resources) { + ResourceType type = findResourceType(resource); + if (resource.getMetadata().getNamespace() == null) { + LOGGER.info(LoggerUtils.RESOURCE_LOGGER_PATTERN, + "Deleting", resource.getKind(), resource.getMetadata().getName()); + } else { + LOGGER.info(LoggerUtils.RESOURCE_WITH_NAMESPACE_LOGGER_PATTERN, + "Deleting", resource.getKind(), resource.getMetadata().getName(), resource.getMetadata().getNamespace()); + } + try { + if (type == null) { + client.getClient().resource(resource).delete(); + assertTrue(waitResourceCondition(resource, ResourceCondition.deletion()), + String.format("Timed out deleting %s/%s in %s", resource.getKind(), resource.getMetadata().getName(), resource.getMetadata().getNamespace())); + } else { + type.delete(resource.getMetadata().getName()); + assertTrue(waitResourceCondition(resource, ResourceCondition.deletion()), + String.format("Timed out deleting %s/%s in %s", resource.getKind(), resource.getMetadata().getName(), resource.getMetadata().getNamespace())); + } + } catch (Exception e) { + if (resource.getMetadata().getNamespace() == null) { + LOGGER.error(LoggerUtils.RESOURCE_LOGGER_PATTERN, "Deleting", resource.getKind(), resource.getMetadata().getName(), e); + } else { + LOGGER.error(LoggerUtils.RESOURCE_WITH_NAMESPACE_LOGGER_PATTERN, "Deleting", resource.getKind(), resource.getMetadata().getName(), resource.getMetadata().getNamespace(), e); + } + } + } + } + + @SafeVarargs + public final void updateResource(T... resources) { + for (T resource : resources) { + if (resource.getMetadata().getNamespace() == null) { + LOGGER.info(LoggerUtils.RESOURCE_LOGGER_PATTERN, + "Updating", resource.getKind(), resource.getMetadata().getName()); + } else { + LOGGER.info(LoggerUtils.RESOURCE_WITH_NAMESPACE_LOGGER_PATTERN, + "Updating", resource.getKind(), resource.getMetadata().getName(), resource.getMetadata().getNamespace()); + } + ResourceType type = findResourceType(resource); + if (type != null) { + type.update(resource); + } else { + client.getClient().resource(resource).update(); + } + } + } + + public final boolean waitResourceCondition(T resource, ResourceCondition condition) { + assertNotNull(resource); + assertNotNull(resource.getMetadata()); + assertNotNull(resource.getMetadata().getName()); + + ResourceType type = findResourceType(resource); + boolean[] resourceReady = new boolean[1]; + + Wait.until(String.format("Resource condition: %s to be fulfilled for resource %s/%s", condition.getConditionName(), resource.getKind(), resource.getMetadata().getName()), + TestFrameConstants.GLOBAL_POLL_INTERVAL_MEDIUM, TestFrameConstants.GLOBAL_TIMEOUT, + () -> { + T res = getKubeClient().getClient().resource(resource).get(); + resourceReady[0] = condition.getPredicate().test(res); + if (!resourceReady[0]) { + if (type == null) { + client.getClient().resource(resource).delete(); + } else { + type.delete(res.getMetadata().getName()); + } + } + return resourceReady[0]; + }); + + return resourceReady[0]; + } + + public void deleteResources() { + LoggerUtils.logSeparator(); + if (!STORED_RESOURCES.containsKey(getTestContext().getDisplayName()) || STORED_RESOURCES.get(getTestContext().getDisplayName()).isEmpty()) { + LOGGER.info("In context {} is everything deleted", getTestContext().getDisplayName()); + } else { + LOGGER.info("Deleting all resources for {}", getTestContext().getDisplayName()); + } + + // if stack is created for specific test suite or test case + AtomicInteger numberOfResources = STORED_RESOURCES.get(getTestContext().getDisplayName()) != null ? + new AtomicInteger(STORED_RESOURCES.get(getTestContext().getDisplayName()).size()) : + // stack has no elements + new AtomicInteger(0); + while (STORED_RESOURCES.containsKey(getTestContext().getDisplayName()) && numberOfResources.get() > 0) { + Stack s = STORED_RESOURCES.get(getTestContext().getDisplayName()); + + while (!s.isEmpty()) { + ResourceItem resourceItem = s.pop(); + + try { + resourceItem.getThrowableRunner().run(); + } catch (Exception e) { + e.printStackTrace(); + } + numberOfResources.decrementAndGet(); + } + } + STORED_RESOURCES.remove(getTestContext().getDisplayName()); + LoggerUtils.logSeparator(); + } + + private ResourceType findResourceType(T resource) { + // other no conflicting types + for (ResourceType type : resourceTypes) { + if (type.getKind().equals(resource.getKind())) { + return (ResourceType) type; + } + } + return null; + } +} diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/utils/TestFrameUtils.java b/test-frame-common/src/main/java/io/skodjob/testframe/utils/TestFrameUtils.java new file mode 100644 index 0000000..88d36d5 --- /dev/null +++ b/test-frame-common/src/main/java/io/skodjob/testframe/utils/TestFrameUtils.java @@ -0,0 +1,99 @@ +/* + * Copyright Skodjob authors. + * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html). + */ +package io.skodjob.testframe.utils; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import io.skodjob.testframe.wait.WaitException; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.time.Duration; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.BooleanSupplier; + +@SuppressWarnings({"checkstyle:ClassFanOutComplexity"}) +public final class TestFrameUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(TestFrameUtils.class); + + /** + * Default timeout for asynchronous tests. + */ + public static final int DEFAULT_TIMEOUT_DURATION = 30; + + /** + * Default timeout unit for asynchronous tests. + */ + public static final TimeUnit DEFAULT_TIMEOUT_UNIT = TimeUnit.SECONDS; + + private TestFrameUtils() { + // All static methods + } + + public static InputStream getFileFromResourceAsStream(String fileName) { + + // The class loader that loaded the class + ClassLoader classLoader = TestFrameUtils.class.getClassLoader(); + InputStream inputStream = classLoader.getResourceAsStream(fileName); + + // the stream holding the file content + if (inputStream == null) { + throw new IllegalArgumentException("file not found! " + fileName); + } else { + return inputStream; + } + + } + + public static T configFromYaml(String yamlFile, Class c) { + ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); + try { + return mapper.readValue(yamlFile, c); + } catch (InvalidFormatException e) { + throw new IllegalArgumentException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Repeat command n-times + * + * @param retry count of remaining retries + * @param fn request function + * @return The value from the first successful call to the callable + */ + public static T runUntilPass(int retry, Callable fn) { + for (int i = 0; i < retry; i++) { + try { + LOGGER.debug("Running Callable, attempt: {}", i); + return fn.call(); + } catch (Exception | Error ex) { + LOGGER.warn("Callable failed: {}", ex.getMessage()); + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + throw new IllegalStateException(String.format("Callable did not pass in %s attempts", retry)); + } +} diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/wait/Wait.java b/test-frame-common/src/main/java/io/skodjob/testframe/wait/Wait.java index b690215..803ae93 100644 --- a/test-frame-common/src/main/java/io/skodjob/testframe/wait/Wait.java +++ b/test-frame-common/src/main/java/io/skodjob/testframe/wait/Wait.java @@ -4,12 +4,24 @@ */ package io.skodjob.testframe.wait; +import io.skodjob.testframe.LoggerUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.PrintWriter; import java.io.StringWriter; import java.time.Duration; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.function.BooleanSupplier; public class Wait { + private static final Logger LOGGER = LoggerFactory.getLogger(Wait.class); /** * For every poll (happening once each {@code pollIntervalMs}) checks if supplier {@code ready} is true. @@ -99,4 +111,64 @@ public static void until(String description, long pollIntervalMs, long timeoutMs } } } + + private static final ExecutorService EXECUTOR = Executors.newCachedThreadPool(new ThreadFactory() { + final ThreadFactory defaultThreadFactory = Executors.defaultThreadFactory(); + + @Override + public Thread newThread(Runnable r) { + Thread result = defaultThreadFactory.newThread(r); + result.setDaemon(true); + return result; + } + }); + + /** + * For every poll (happening once each {@code pollIntervalMs}) checks if supplier {@code ready} is true. + * If yes, the wait is closed. Otherwise, waits another {@code pollIntervalMs} and tries again. + * Once the wait timeout (specified by {@code timeoutMs} is reached and supplier wasn't true until that time, + * runs the {@code onTimeout} (f.e. print of logs, showing the actual value that was checked inside {@code ready}), + * and finally throws {@link WaitException}. + * + * @param description information about on what we are waiting + * @param pollIntervalMs poll interval in milliseconds + * @param timeoutMs timeout specified in milliseconds + * @param ready {@link BooleanSupplier} containing code, which should be executed each poll, verifying readiness + * of the particular thing + */ + public static CompletableFuture untilAsync(String description, long pollIntervalMs, long timeoutMs, BooleanSupplier ready) { + LOGGER.info("Waiting for {}", description); + long deadline = System.currentTimeMillis() + timeoutMs; + CompletableFuture future = new CompletableFuture<>(); + Executor delayed = CompletableFuture.delayedExecutor(pollIntervalMs, TimeUnit.MILLISECONDS, EXECUTOR); + Runnable r = new Runnable() { + @Override + public void run() { + boolean result; + try { + result = ready.getAsBoolean(); + } catch (Exception e) { + future.completeExceptionally(e); + return; + } + long timeLeft = deadline - System.currentTimeMillis(); + if (!future.isDone()) { + if (!result) { + if (timeLeft >= 0) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("{} not ready, will try again ({}ms till timeout)", description, timeLeft); + } + delayed.execute(this); + } else { + future.completeExceptionally(new TimeoutException(String.format("Waiting for %s timeout %s exceeded", description, timeoutMs))); + } + } else { + future.complete(null); + } + } + } + }; + r.run(); + return future; + } } diff --git a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ClusterRoleBindingResource.java b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ClusterRoleBindingResource.java index 2be0e7c..969bc8c 100644 --- a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ClusterRoleBindingResource.java +++ b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ClusterRoleBindingResource.java @@ -8,29 +8,36 @@ import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingList; import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.ResourceType; import java.util.function.Consumer; -public class ClusterRoleBindingResource implements ResourceType> { +public class ClusterRoleBindingResource implements ResourceType { private final NonNamespaceOperation> client; public ClusterRoleBindingResource() { - this.client = KubeClient.getInstance().getClient().rbac().clusterRoleBindings(); + this.client = ResourceManager.getKubeClient().getClient().rbac().clusterRoleBindings(); } /** - * Returns client for resource {@link ClusterRoleBinding} - * - * @return client of a MixedOperation<{@link ClusterRoleBinding}, {@link ClusterRoleBindingList}, Resource<{@link ClusterRoleBinding}>> resource + * Get specific client for resoruce + * @return specific client */ @Override - public NonNamespaceOperation> getClient() { + public NonNamespaceOperation getClient() { return client; } + /** + * Kind of api resource + * @return kind name + */ + @Override + public String getKind() { + return "ClusterRoleBinding"; + } + /** * Creates specific {@link ClusterRoleBinding} resource * diff --git a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ClusterRoleResource.java b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ClusterRoleResource.java index 8ba63d7..e773323 100644 --- a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ClusterRoleResource.java +++ b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ClusterRoleResource.java @@ -8,26 +8,33 @@ import io.fabric8.kubernetes.api.model.rbac.ClusterRoleList; import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.ResourceType; import java.util.function.Consumer; -public class ClusterRoleResource implements ResourceType> { +public class ClusterRoleResource implements ResourceType { private final NonNamespaceOperation> client; public ClusterRoleResource() { - this.client = KubeClient.getInstance().getClient().rbac().clusterRoles(); + this.client = ResourceManager.getKubeClient().getClient().rbac().clusterRoles(); } /** - * Returns client for resource {@link ClusterRole} - * - * @return client of a MixedOperation<{@link ClusterRole}, {@link ClusterRoleList}, Resource<{@link ClusterRole}>> resource + * Kind of api resource + * @return kind name + */ + @Override + public String getKind() { + return "ClusterRole"; + } + + /** + * Get specific client for resoruce + * @return specific client */ @Override - public NonNamespaceOperation> getClient() { + public NonNamespaceOperation getClient() { return client; } diff --git a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ConfigMapResource.java b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ConfigMapResource.java index 3a17989..f449f85 100644 --- a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ConfigMapResource.java +++ b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ConfigMapResource.java @@ -8,16 +8,33 @@ import io.fabric8.kubernetes.api.model.ConfigMapList; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.NamespacedResourceType; import java.util.function.Consumer; -public class ConfigMapResource implements NamespacedResourceType> { +public class ConfigMapResource implements NamespacedResourceType { private final MixedOperation> client; public ConfigMapResource() { - this.client = KubeClient.getInstance().getClient().configMaps(); + this.client = ResourceManager.getKubeClient().getClient().configMaps(); + } + + /** + * Kind of api resource + * @return kind name + */ + @Override + public String getKind() { + return "ConfigMap"; + } + + /** + * Get specific client for resoruce + * @return specific client + */ + @Override + public MixedOperation getClient() { + return client; } /** @@ -68,16 +85,6 @@ public void replaceInNamespace(String namespaceName, String resourceName, Consum updateInNamespace(namespaceName, toBeUpdated); } - /** - * Returns client for resource {@link ConfigMap} - * - * @return client of a MixedOperation<{@link ConfigMap}, {@link ConfigMapList}, Resource<{@link ConfigMap}>> resource - */ - @Override - public MixedOperation> getClient() { - return client; - } - /** * Creates specific {@link ConfigMap} resource * diff --git a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/CustomResourceDefinitionResource.java b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/CustomResourceDefinitionResource.java index f7ccd0a..f9608d5 100644 --- a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/CustomResourceDefinitionResource.java +++ b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/CustomResourceDefinitionResource.java @@ -8,25 +8,33 @@ import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionList; import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.ResourceType; import java.util.function.Consumer; -public class CustomResourceDefinitionResource implements ResourceType> { +public class CustomResourceDefinitionResource implements ResourceType { private final NonNamespaceOperation> client; public CustomResourceDefinitionResource() { - this.client = KubeClient.getInstance().getClient().apiextensions().v1().customResourceDefinitions(); + this.client = ResourceManager.getKubeClient().getClient().apiextensions().v1().customResourceDefinitions(); } + /** - * Returns client for resource {@link CustomResourceDefinition} - * - * @return client of a MixedOperation<{@link CustomResourceDefinition}, {@link CustomResourceDefinitionList}, Resource<{@link CustomResourceDefinition}>> resource + * Kind of api resource + * @return kind name + */ + @Override + public String getKind() { + return "CustomResourceDefinition"; + } + + /** + * Get specific client for resoruce + * @return specific client */ @Override - public NonNamespaceOperation> getClient() { + public NonNamespaceOperation getClient() { return client; } diff --git a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/DeploymentResource.java b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/DeploymentResource.java index 70719ad..4bde6b2 100644 --- a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/DeploymentResource.java +++ b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/DeploymentResource.java @@ -8,26 +8,33 @@ import io.fabric8.kubernetes.api.model.apps.DeploymentList; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.RollableScalableResource; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.NamespacedResourceType; import java.util.function.Consumer; -public class DeploymentResource implements NamespacedResourceType> { +public class DeploymentResource implements NamespacedResourceType { private final MixedOperation> client; public DeploymentResource() { - this.client = KubeClient.getInstance().getClient().apps().deployments(); + this.client = ResourceManager.getKubeClient().getClient().apps().deployments(); } /** - * Returns client for resource {@link Deployment} - * - * @return client of a MixedOperation<{@link Deployment}, {@link L}, Resource<{@link Deployment}>> resource + * Kind of api resource + * @return kind name + */ + @Override + public String getKind() { + return "Deployment"; + } + + /** + * Get specific client for resoruce + * @return specific client */ @Override - public MixedOperation> getClient() { + public MixedOperation getClient() { return client; } diff --git a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/JobResource.java b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/JobResource.java index e3e19bf..6e23c76 100644 --- a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/JobResource.java +++ b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/JobResource.java @@ -8,26 +8,33 @@ import io.fabric8.kubernetes.api.model.batch.v1.JobList; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.ScalableResource; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.NamespacedResourceType; import java.util.function.Consumer; -public class JobResource implements NamespacedResourceType> { +public class JobResource implements NamespacedResourceType { private final MixedOperation> client; public JobResource() { - this.client = KubeClient.getInstance().getClient().batch().v1().jobs(); + this.client = ResourceManager.getKubeClient().getClient().batch().v1().jobs(); } /** - * Returns client for resource {@link Job} - * - * @return client of a MixedOperation<{@link Job}, {@link JobList}, Resource<{@link Job}>> resource + * Kind of api resource + * @return kind name + */ + @Override + public String getKind() { + return "Job"; + } + + /** + * Get specific client for resoruce + * @return specific client */ @Override - public MixedOperation> getClient() { + public MixedOperation getClient() { return client; } diff --git a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/LeaseResource.java b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/LeaseResource.java index e4a3217..53545d4 100644 --- a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/LeaseResource.java +++ b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/LeaseResource.java @@ -8,26 +8,33 @@ import io.fabric8.kubernetes.api.model.coordination.v1.LeaseList; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.NamespacedResourceType; import java.util.function.Consumer; -public class LeaseResource implements NamespacedResourceType> { +public class LeaseResource implements NamespacedResourceType { private MixedOperation> client; public LeaseResource() { - this.client = KubeClient.getInstance().getClient().leases(); + this.client = ResourceManager.getKubeClient().getClient().leases(); } /** - * Returns client for resource {@link Lease} - * - * @return client of a MixedOperation<{@link Lease}, {@link LeaseList}, Resource<{@link Lease}>> resource + * Kind of api resource + * @return kind name + */ + @Override + public String getKind() { + return "Lease"; + } + + /** + * Get specific client for resoruce + * @return specific client */ @Override - public MixedOperation> getClient() { + public MixedOperation getClient() { return client; } diff --git a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/NamespaceResource.java b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/NamespaceResource.java index 011190e..2c3cdf6 100644 --- a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/NamespaceResource.java +++ b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/NamespaceResource.java @@ -9,26 +9,33 @@ import io.fabric8.kubernetes.api.model.Namespace; import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.ResourceType; import java.util.function.Consumer; -public class NamespaceResource implements ResourceType> { +public class NamespaceResource implements ResourceType { private final NonNamespaceOperation> client; public NamespaceResource() { - this.client = KubeClient.getInstance().getClient().namespaces(); + this.client = ResourceManager.getKubeClient().getClient().namespaces(); } /** - * Returns client for resource {@link Namespace} - * - * @return client of a MixedOperation<{@link Namespace}, {@link NamespaceList}, Resource<{@link Namespace}>> resource + * Kind of api resource + * @return kind name + */ + @Override + public String getKind() { + return "Namespace"; + } + + /** + * Get specific client for resoruce + * @return specific client */ @Override - public NonNamespaceOperation> getClient() { + public NonNamespaceOperation getClient() { return client; } diff --git a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/NetworkPolicyResource.java b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/NetworkPolicyResource.java index 981727e..7efc810 100644 --- a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/NetworkPolicyResource.java +++ b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/NetworkPolicyResource.java @@ -8,25 +8,33 @@ import io.fabric8.kubernetes.api.model.networking.v1.NetworkPolicyList; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.NamespacedResourceType; import java.util.function.Consumer; -public class NetworkPolicyResource implements NamespacedResourceType> { +public class NetworkPolicyResource implements NamespacedResourceType { private final MixedOperation> client; public NetworkPolicyResource() { - this.client = KubeClient.getInstance().getClient().network().networkPolicies(); + this.client = ResourceManager.getKubeClient().getClient().network().networkPolicies(); } + /** - * Returns client for resource {@link NetworkPolicy} - * - * @return client of a MixedOperation<{@link NetworkPolicy}, {@link NetworkPolicyList}, Resource<{@link NetworkPolicy}>> resource + * Kind of api resource + * @return kind name + */ + @Override + public String getKind() { + return "NetworkPolicy"; + } + + /** + * Get specific client for resoruce + * @return specific client */ @Override - public MixedOperation> getClient() { + public MixedOperation getClient() { return client; } diff --git a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/RoleBindingResource.java b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/RoleBindingResource.java index 8779762..5ef88f7 100644 --- a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/RoleBindingResource.java +++ b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/RoleBindingResource.java @@ -8,26 +8,33 @@ import io.fabric8.kubernetes.api.model.rbac.RoleBindingList; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.NamespacedResourceType; import java.util.function.Consumer; -public class RoleBindingResource implements NamespacedResourceType> { +public class RoleBindingResource implements NamespacedResourceType { private final MixedOperation> client; public RoleBindingResource() { - this.client = KubeClient.getInstance().getClient().rbac().roleBindings(); + this.client = ResourceManager.getKubeClient().getClient().rbac().roleBindings(); } /** - * Returns client for resource {@link RoleBinding} - * - * @return client of a MixedOperation<{@link RoleBinding}, {@link RoleBindingList}, Resource<{@link RoleBinding}>> resource + * Kind of api resource + * @return kind name + */ + @Override + public String getKind() { + return "RoleBinding"; + } + + /** + * Get specific client for resoruce + * @return specific client */ @Override - public MixedOperation> getClient() { + public MixedOperation getClient() { return client; } diff --git a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/RoleResource.java b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/RoleResource.java index 497d6bb..51dfe8d 100644 --- a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/RoleResource.java +++ b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/RoleResource.java @@ -8,27 +8,25 @@ import io.fabric8.kubernetes.api.model.rbac.RoleList; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.NamespacedResourceType; import java.util.function.Consumer; -public class RoleResource implements NamespacedResourceType> { +public class RoleResource implements NamespacedResourceType { private final MixedOperation> client; public RoleResource() { - this.client = KubeClient.getInstance().getClient().rbac().roles(); + this.client = ResourceManager.getKubeClient().getClient().rbac().roles(); } /** - * Returns client for resource {@link Role} - * - * @return client of a MixedOperation<{@link Role}, {@link RoleList}, Resource<{@link Role}>> resource + * Kind of api resource + * @return kind name */ @Override - public MixedOperation> getClient() { - return client; + public String getKind() { + return "Role"; } /** @@ -41,6 +39,15 @@ public void create(Role resource) { client.resource(resource).create(); } + /** + * Get specific client for resoruce + * @return specific client + */ + @Override + public MixedOperation getClient() { + return client; + } + /** * Updates specific {@link Role} resource * diff --git a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/SecretResource.java b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/SecretResource.java index a642f5b..cd60dc6 100644 --- a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/SecretResource.java +++ b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/SecretResource.java @@ -8,27 +8,25 @@ import io.fabric8.kubernetes.api.model.SecretList; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.NamespacedResourceType; import java.util.function.Consumer; -public class SecretResource implements NamespacedResourceType> { +public class SecretResource implements NamespacedResourceType { private final MixedOperation> client; public SecretResource() { - this.client = KubeClient.getInstance().getClient().secrets(); + this.client = ResourceManager.getKubeClient().getClient().secrets(); } /** - * Returns client for resource {@link Secret} - * - * @return client of a MixedOperation<{@link Secret}, {@link SecretList}, Resource<{@link Secret}>> resource + * Kind of api resource + * @return kind name */ @Override - public MixedOperation> getClient() { - return client; + public String getKind() { + return "Secret"; } /** @@ -41,6 +39,15 @@ public void create(Secret resource) { client.resource(resource).create(); } + /** + * Get specific client for resoruce + * @return specific client + */ + @Override + public MixedOperation getClient() { + return client; + } + /** * Creates specific {@link Secret} resource in specified namespace * diff --git a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ServiceAccountResource.java b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ServiceAccountResource.java index 62de8bb..0369347 100644 --- a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ServiceAccountResource.java +++ b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ServiceAccountResource.java @@ -8,27 +8,25 @@ import io.fabric8.kubernetes.api.model.ServiceAccountList; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.NamespacedResourceType; import java.util.function.Consumer; -public class ServiceAccountResource implements NamespacedResourceType> { +public class ServiceAccountResource implements NamespacedResourceType { private final MixedOperation> client; public ServiceAccountResource() { - this.client = KubeClient.getInstance().getClient().serviceAccounts(); + this.client = ResourceManager.getKubeClient().getClient().serviceAccounts(); } /** - * Returns client for resource {@link ServiceAccount} - * - * @return client of a MixedOperation<{@link ServiceAccount}, {@link ServiceAccountList}, Resource<{@link ServiceAccount}>> resource + * Kind of api resource + * @return kind name */ @Override - public MixedOperation> getClient() { - return client; + public String getKind() { + return "ServiceAccount"; } /** @@ -41,6 +39,15 @@ public void create(ServiceAccount resource) { client.resource(resource).create(); } + /** + * Get specific client for resoruce + * @return specific client + */ + @Override + public MixedOperation getClient() { + return client; + } + /** * Updates specific {@link ServiceAccount} resource * diff --git a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ServiceResource.java b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ServiceResource.java index 1fadadc..6912b6f 100644 --- a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ServiceResource.java +++ b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ServiceResource.java @@ -7,27 +7,25 @@ import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.ServiceList; import io.fabric8.kubernetes.client.dsl.MixedOperation; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.NamespacedResourceType; import java.util.function.Consumer; -public class ServiceResource implements NamespacedResourceType> { +public class ServiceResource implements NamespacedResourceType { private final MixedOperation> client; public ServiceResource() { - this.client = KubeClient.getInstance().getClient().services(); + this.client = ResourceManager.getKubeClient().getClient().services(); } /** - * Returns client for resource {@link Service} - * - * @return client of a MixedOperation<{@link Service}, {@link ServiceList}, Resource<{@link Service}>> resource + * Kind of api resource + * @return kind name */ @Override - public MixedOperation> getClient() { - return client; + public String getKind() { + return "Service"; } /** @@ -40,6 +38,15 @@ public void create(Service resource) { client.resource(resource).create(); } + /** + * Get specific client for resoruce + * @return specific client + */ + @Override + public MixedOperation getClient() { + return client; + } + /** * Updates specific {@link Service} resource * diff --git a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ValidatingWebhookConfigurationResource.java b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ValidatingWebhookConfigurationResource.java index defcb26..5af8e1d 100644 --- a/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ValidatingWebhookConfigurationResource.java +++ b/test-frame-kubernetes/src/main/java/io/skodjob/testframe/resources/ValidatingWebhookConfigurationResource.java @@ -8,27 +8,34 @@ import io.fabric8.kubernetes.api.model.admissionregistration.v1.ValidatingWebhookConfigurationList; import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.ResourceType; import java.util.function.Consumer; -public class ValidatingWebhookConfigurationResource implements ResourceType> { +public class ValidatingWebhookConfigurationResource implements ResourceType { private final NonNamespaceOperation> client; public ValidatingWebhookConfigurationResource() { - this.client = KubeClient.getInstance().getClient().admissionRegistration().v1().validatingWebhookConfigurations(); + this.client = ResourceManager.getKubeClient().getClient().admissionRegistration().v1().validatingWebhookConfigurations(); } /** - * Returns client for resource {@link ValidatingWebhookConfiguration} - * - * @return client of a MixedOperation<{@link ValidatingWebhookConfiguration}, {@link ValidatingWebhookConfigurationList}, Resource<{@link ValidatingWebhookConfiguration}>> resource + * Kind of api resource + * @return kind name + */ + @Override + public String getKind() { + return "ValidatingWebhookConfiguration"; + } + + /** + * Get specific client for resoruce + * @return specific client */ @Override - public NonNamespaceOperation> getClient() { + public NonNamespaceOperation getClient() { return client; } diff --git a/test-frame-openshift/src/main/java/io/skodjob/testframe/resources/OperatorGroupResource.java b/test-frame-openshift/src/main/java/io/skodjob/testframe/resources/OperatorGroupResource.java index c502b64..4865153 100644 --- a/test-frame-openshift/src/main/java/io/skodjob/testframe/resources/OperatorGroupResource.java +++ b/test-frame-openshift/src/main/java/io/skodjob/testframe/resources/OperatorGroupResource.java @@ -8,26 +8,33 @@ import io.fabric8.kubernetes.client.dsl.Resource; import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroup; import io.fabric8.openshift.api.model.operatorhub.v1.OperatorGroupList; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.NamespacedResourceType; import java.util.function.Consumer; -public class OperatorGroupResource implements NamespacedResourceType> { +public class OperatorGroupResource implements NamespacedResourceType { private final MixedOperation> client; public OperatorGroupResource() { - this.client = KubeClient.getInstance().getOpenShiftClient().operatorHub().operatorGroups(); + this.client = ResourceManager.getKubeClient().getOpenShiftClient().operatorHub().operatorGroups(); } /** - * Returns client for resource {@link OperatorGroup} - * - * @return client of a MixedOperation<{@link OperatorGroup}, {@link OperatorGroupList}, Resource<{@link OperatorGroup}>> resource + * Kind of api resource + * @return kind name + */ + @Override + public String getKind() { + return "OperatorGroup"; + } + + /** + * Get specific client for resoruce + * @return specific client */ @Override - public MixedOperation> getClient() { + public MixedOperation getClient() { return client; } diff --git a/test-frame-openshift/src/main/java/io/skodjob/testframe/resources/SubscriptionResource.java b/test-frame-openshift/src/main/java/io/skodjob/testframe/resources/SubscriptionResource.java index 34c0628..7040375 100644 --- a/test-frame-openshift/src/main/java/io/skodjob/testframe/resources/SubscriptionResource.java +++ b/test-frame-openshift/src/main/java/io/skodjob/testframe/resources/SubscriptionResource.java @@ -8,26 +8,33 @@ import io.fabric8.kubernetes.client.dsl.Resource; import io.fabric8.openshift.api.model.operatorhub.v1alpha1.Subscription; import io.fabric8.openshift.api.model.operatorhub.v1alpha1.SubscriptionList; -import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.interfaces.NamespacedResourceType; import java.util.function.Consumer; -public class SubscriptionResource implements NamespacedResourceType> { +public class SubscriptionResource implements NamespacedResourceType { private final MixedOperation> client; public SubscriptionResource() { - this.client = KubeClient.getInstance().getOpenShiftClient().operatorHub().subscriptions(); + this.client = ResourceManager.getKubeClient().getOpenShiftClient().operatorHub().subscriptions(); } /** - * Returns client for resource {@link Subscription} - * - * @return client of a MixedOperation<{@link Subscription}, {@link SubscriptionList}, Resource<{@link Subscription}>> resource + * Kind of api resource + * @return kind name + */ + @Override + public String getKind() { + return "Subscription"; + } + + /** + * Get specific client for resoruce + * @return specific client */ @Override - public MixedOperation> getClient() { + public MixedOperation getClient() { return client; }