Skip to content

Commit

Permalink
Add initial implementation of ResourceManager (#17)
Browse files Browse the repository at this point in the history
* Add initial implementation of ResourceManager

Signed-off-by: David Kornel <[email protected]>
  • Loading branch information
kornys authored Feb 27, 2024
1 parent 9954773 commit 37e2c1d
Show file tree
Hide file tree
Showing 34 changed files with 1,153 additions and 155 deletions.
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@ target/
*.iml

### Mac OS ###
**.DS_Store
**.DS_Store

## Frame specific files
**/*.kubeconfig
*.env
config.yaml
26 changes: 26 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
<maven.javadoc.version>3.4.1</maven.javadoc.version>
<maven.assembly.version>3.4.2</maven.assembly.version>
<maven.plugin.plugin.version>3.9.0</maven.plugin.plugin.version>
<junit.jupiter.version>5.10.2</junit.jupiter.version>
</properties>

<dependencyManagement>
Expand All @@ -101,6 +102,31 @@
<artifactId>openshift-client-api</artifactId>
<version>${fabric8.version}</version>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>openshift-client</artifactId>
<version>${fabric8.version}</version>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client</artifactId>
<version>${fabric8.version}</version>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-model</artifactId>
<version>${fabric8.version}</version>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>generator-annotations</artifactId>
<version>${fabric8.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down
16 changes: 16 additions & 0 deletions test-frame-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,21 @@
<groupId>io.fabric8</groupId>
<artifactId>openshift-client-api</artifactId>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>openshift-client</artifactId>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client</artifactId>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-model</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -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)));
}
}
Original file line number Diff line number Diff line change
@@ -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";

}
Original file line number Diff line number Diff line change
@@ -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<String, String> VALUES = new HashMap<>();
private static final Map<String, Object> 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> T getOrDefault(String var, Function<String, T> 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<String, Object> 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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<T extends HasMetadata, L extends KubernetesResourceList<T>, M extends Resource<T>> extends ResourceType<T, L, M> {
public interface NamespacedResourceType<T extends HasMetadata> extends ResourceType<T> {

/**
* 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<T, L, M> getClient();
MixedOperation<?, ?, ?> getClient();

/**
* Creates specific {@link T} resource in Namespace specified by user
Expand Down
Loading

0 comments on commit 37e2c1d

Please sign in to comment.