From 2c0cbbdaf06c6dbe79bec047608bb97327aecb0b Mon Sep 17 00:00:00 2001 From: David Kornel Date: Tue, 4 Jun 2024 08:40:49 +0200 Subject: [PATCH] Add collecting of cluster wide resources (#93) Signed-off-by: David Kornel --- .../clients/cmdClient/BaseCmdKubeClient.java | 37 ++++++ .../clients/cmdClient/KubeCmdClient.java | 25 ++++ test-frame-log-collector/README.md | 39 +++++- .../skodjob/testframe/CollectorConstants.java | 5 + .../io/skodjob/testframe/LogCollector.java | 117 ++++++++++++++---- .../testframe/LogCollectorBuilder.java | 90 ++++++++++++-- .../testframe/LogCollectorBuilderTest.java | 5 +- .../io/skodjob/testframe/LogCollectorIT.java | 28 ++--- .../test/integration/LogCollectorIT.java | 22 +++- 9 files changed, 307 insertions(+), 61 deletions(-) diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/clients/cmdClient/BaseCmdKubeClient.java b/test-frame-common/src/main/java/io/skodjob/testframe/clients/cmdClient/BaseCmdKubeClient.java index a8798c4..857cca9 100644 --- a/test-frame-common/src/main/java/io/skodjob/testframe/clients/cmdClient/BaseCmdKubeClient.java +++ b/test-frame-common/src/main/java/io/skodjob/testframe/clients/cmdClient/BaseCmdKubeClient.java @@ -482,6 +482,20 @@ public List list(String resourceType) { .filter(s -> !s.trim().isEmpty()).collect(Collectors.toList()); } + /** + * Lists cluster wide resources of a certain type. + * + * @param resourceType The type of the resource. + * @return A list of resource names. + */ + @Override + public List listClusterWide(String resourceType) { + return Arrays.stream(Exec.exec(command(List.of(GET, resourceType, + "-o", "jsonpath={range .items[*]}{.metadata.name} "))) + .out().trim().split(" +")) + .filter(s -> !s.trim().isEmpty()).collect(Collectors.toList()); + } + /** * Retrieves a resource as JSON. * @@ -517,6 +531,29 @@ public String getResourcesAsYaml(String resourceType) { return Exec.exec(namespacedCommand(GET, resourceType, "-o", "yaml")).out(); } + /** + * Retrieves a cluster wide resource as YAML. + * + * @param resourceType The type of the resource. + * @param resourceName The name of the resource. + * @return The resource as YAML. + */ + @Override + public String getClusterWideResourceAsYaml(String resourceType, String resourceName) { + return Exec.exec(command(List.of(GET, resourceType, resourceName, "-o", "yaml"))).out(); + } + + /** + * Retrieves resources as YAML. + * + * @param resourceType The type of the resource. + * @return The resources as YAML. + */ + @Override + public String getClusterWideResourcesAsYaml(String resourceType) { + return Exec.exec(command(List.of(GET, resourceType, "-o", "yaml"))).out(); + } + /** * Creates a resource from a template and applies it. * diff --git a/test-frame-common/src/main/java/io/skodjob/testframe/clients/cmdClient/KubeCmdClient.java b/test-frame-common/src/main/java/io/skodjob/testframe/clients/cmdClient/KubeCmdClient.java index c2b3a14..3af2fc7 100644 --- a/test-frame-common/src/main/java/io/skodjob/testframe/clients/cmdClient/KubeCmdClient.java +++ b/test-frame-common/src/main/java/io/skodjob/testframe/clients/cmdClient/KubeCmdClient.java @@ -286,6 +286,14 @@ default K delete(String... files) { */ List list(String resourceType); + /** + * Retrieves a list of cluster wide resources by type. + * + * @param resourceType The type of the resources. + * @return The list of resources. + */ + List listClusterWide(String resourceType); + /** * Retrieves the YAML content of a resource by type and name. * @@ -303,6 +311,23 @@ default K delete(String... files) { */ String getResourcesAsYaml(String resourceType); + /** + * Retrieves the YAML content of a cluster wide resource by type and name. + * + * @param resourceType The type of the resource. + * @param resourceName The name of the resource. + * @return The YAML content of the resource. + */ + String getClusterWideResourceAsYaml(String resourceType, String resourceName); + + /** + * Retrieves the YAML content of cluster wide resources by type. + * + * @param resourceType The type of the resources. + * @return The YAML content of the resources. + */ + String getClusterWideResourcesAsYaml(String resourceType); + /** * Creates a resource from a template and applies it. * diff --git a/test-frame-log-collector/README.md b/test-frame-log-collector/README.md index 4e4065d..da3d56f 100644 --- a/test-frame-log-collector/README.md +++ b/test-frame-log-collector/README.md @@ -40,7 +40,7 @@ import io.skodjob.testframe.LogCollector; import io.skodjob.testframe.LogCollectorBuilder; LogCollector logCollector = new LogCollectorBuilder() - .withResources("secret", "deployment", "my-custom-resource") + .withNamespacedResources("secret", "deployment", "my-custom-resource") .withRootFolderPath("/path/to/logs/folder") .build(); ``` @@ -66,7 +66,7 @@ import io.skodjob.testframe.LogCollector; import io.skodjob.testframe.LogCollectorBuilder; LogCollector logCollector = new LogCollectorBuilder() - .withResources("secret", "deployment", "my-custom-resource") + .withNamespacedResources("secret", "deployment", "my-custom-resource") .withRootFolderPath("/path/to/logs/folder") .build(); @@ -92,7 +92,7 @@ import io.skodjob.testframe.LogCollector; import io.skodjob.testframe.LogCollectorBuilder; LogCollector logCollector = new LogCollectorBuilder() - .withResources("secret", "deployment", "my-custom-resource") + .withNamespacedResources("secret", "deployment", "my-custom-resource") .withRootFolderPath("/path/to/logs/folder") .build(); @@ -127,17 +127,46 @@ import io.skodjob.testframe.LogCollector; import io.skodjob.testframe.LogCollectorBuilder; LogCollector logCollector = new LogCollectorBuilder() - .withResources("secret", "deployment", "my-custom-resource") + .withNamespacedResources("secret", "deployment", "my-custom-resource") .withRootFolderPath("/path/to/logs/folder") .build(); public static void collectFromNamespaces() { logCollector.collectFromNamespacesWithLabels(new LabelSelectorBuilder() - .withMatchLabels(Map.of("my-label", "my-value")) + .withMatchLabels(Map.of("my-label", "my-value")) ); } ``` +#### 4. Collect cluster wide resource lists + +Collect cluster wide resource lists yaml like `nodes`, `pvs`: + +```java +import io.fabric8.kubernetes.api.model.LabelSelectorBuilder; +import io.skodjob.testframe.LogCollector; +import io.skodjob.testframe.LogCollectorBuilder; + +LogCollector logCollector = new LogCollectorBuilder() + .withClusterWideResources("nodes", "pvs") + .withRootFolderPath("/path/to/logs/folder") + .build(); + +public static void collectClusterWideRes() { + logCollector.collectClusterWideResources(); +} +``` +the logs path will then look like this: +```bash +/path/to/logs/folder +└── cluster-wide-resources + ├── nodes + │ ├── node1.yaml + │ └── node2.yaml + └── pvs + ├── pv1.yaml + └── pv2.yaml +``` The tree path will look similarly to above examples, there will be folders for Namespaces matching the specified labels. ### Specifying additional folder path diff --git a/test-frame-log-collector/src/main/java/io/skodjob/testframe/CollectorConstants.java b/test-frame-log-collector/src/main/java/io/skodjob/testframe/CollectorConstants.java index 1d4bba0..fa4c679 100644 --- a/test-frame-log-collector/src/main/java/io/skodjob/testframe/CollectorConstants.java +++ b/test-frame-log-collector/src/main/java/io/skodjob/testframe/CollectorConstants.java @@ -32,4 +32,9 @@ public interface CollectorConstants { * Prefix for description files */ String DESCRIBE = "describe"; + + /** + * Cluster wide resources folder name + */ + String CLUSTER_WIDE_FOLDER = "cluster-wide-resources"; } diff --git a/test-frame-log-collector/src/main/java/io/skodjob/testframe/LogCollector.java b/test-frame-log-collector/src/main/java/io/skodjob/testframe/LogCollector.java index 44470ff..687e44c 100644 --- a/test-frame-log-collector/src/main/java/io/skodjob/testframe/LogCollector.java +++ b/test-frame-log-collector/src/main/java/io/skodjob/testframe/LogCollector.java @@ -10,7 +10,6 @@ import io.skodjob.testframe.clients.KubeClient; import io.skodjob.testframe.clients.cmdClient.KubeCmdClient; import io.skodjob.testframe.clients.cmdClient.Kubectl; -import io.skodjob.testframe.resources.KubeResourceManager; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -27,10 +26,11 @@ * LogCollector class containing all methods used for logs and YAML collection. */ public class LogCollector { - private static final Logger LOGGER = LogManager.getLogger(KubeResourceManager.class); - protected final List resources; + private static final Logger LOGGER = LogManager.getLogger(LogCollector.class); + protected final List namespacedResources; + protected final List clusterWideResources; protected String rootFolderPath; - private KubeCmdClient kubeCmdClient = new Kubectl(); + private KubeCmdClient kubeCmdClient = new Kubectl(); private KubeClient kubeClient = new KubeClient(); /** @@ -39,33 +39,24 @@ public class LogCollector { * @param builder {@link LogCollectorBuilder} with configuration for {@link LogCollector} */ public LogCollector(LogCollectorBuilder builder) { - this.resources = builder.getResources() == null ? Collections.emptyList() : builder.getResources(); + this.namespacedResources = builder.getNamespacedResources() == null ? + Collections.emptyList() : builder.getNamespacedResources(); + this.clusterWideResources = builder.getClusterWideResources() == null ? + Collections.emptyList() : builder.getClusterWideResources(); if (builder.getRootFolderPath() == null) { throw new RuntimeException("rootFolderPath should be filled, but it's empty"); } - this.rootFolderPath = builder.getRootFolderPath(); - } + if (builder.getKubeClient() != null) { + this.kubeClient = builder.getKubeClient(); + } - /** - * Sets {@link KubeClient} for the LogCollector. - * Mainly for testing purposes (to mock the client). - * - * @param kubeClient {@link KubeClient} - usually mocked. - */ - /* test */ public void setKubeClient(KubeClient kubeClient) { - this.kubeClient = kubeClient; - } + if (builder.getKubeCmdClient() != null) { + this.kubeCmdClient = builder.getKubeCmdClient(); + } - /** - * Sets {@link KubeCmdClient} for the LogCollector. - * Mainly for testing purposes (to mock the client). - * - * @param kubeCmdClient {@link KubeCmdClient} - usually mocked. - */ - /* test */ public void setKubeCmdClient(KubeCmdClient kubeCmdClient) { - this.kubeCmdClient = kubeCmdClient; + this.rootFolderPath = builder.getRootFolderPath(); } /** @@ -129,6 +120,24 @@ public void collectFromNamespace(String namespaceName) { collectFromNamespaceToFolder(namespaceName, null); } + /** + * Method that collects YAML of cluster wide resources + * {@link #rootFolderPath}. + */ + public void collectClusterWideResources() { + collectClusterWideResources(true); + } + + /** + * Method that collects YAML of cluster wide resources + * {@link #rootFolderPath}. + * + * @param logPerResource flag enables cluster wide resource per file + */ + public void collectClusterWideResources(boolean logPerResource) { + collectClusterWideResourcesToFolder(logPerResource, null); + } + /** * Method that collects all logs and YAML files from specified Namespace, collected into * {@link #rootFolderPath} with {@param folderPath}. @@ -151,6 +160,43 @@ public void collectFromNamespaceToFolder(String namespaceName, String folderPath } } + /** + * Method that collects YAML of cluster wide resources + * {@link #rootFolderPath} with {@param folderPath}. + * + * @param folderPath folder path for the log collection + */ + public void collectClusterWideResourcesToFolder(String folderPath) { + collectClusterWideResourcesToFolder(true, folderPath); + } + + /** + * Method that collects YAML of cluster wide resources + * {@link #rootFolderPath} with {@param folderPath}. + * + * @param logPerFile flag enables cluster wide resource per file + * @param folderPath folder path for the log collection + */ + public void collectClusterWideResourcesToFolder(boolean logPerFile, String folderPath) { + clusterWideResources.forEach(resourceType -> { + LOGGER.info("Collecting YAMLs of {}", resourceType); + + String clusterWideFolderPath = createNamespaceDirectory(CollectorConstants.CLUSTER_WIDE_FOLDER, + LogCollectorUtils.getFolderPath(rootFolderPath, folderPath)); + createLogDirOnPath(clusterWideFolderPath); + + if (logPerFile) { + collectClusterWideResourcesPerFile(clusterWideFolderPath, resourceType); + } else { + String yaml = kubeCmdClient.getClusterWideResourcesAsYaml(resourceType); + String resFileName = LogCollectorUtils.getYamlFileNameForResource(resourceType); + String filePath = LogCollectorUtils + .getFullPathForFolderPathAndFileName(clusterWideFolderPath, resFileName); + writeDataToFile(filePath, yaml); + } + }); + } + /** * Method for collecting logs from all Pods (and their containers) in specified Namespace. * At the start, it creates a folder in the Namespace dir for the `pod` resource. @@ -238,6 +284,27 @@ private void collectPodDescription(String namespaceName, String podsFolderPath, writeDataToFile(filePath, podDesc); } + /** + * Collect cluster wide resource per file + * + * @param clusterWideFolderPath root path of cluster wide resource + * @param resourceType resource kind for collect + */ + private void collectClusterWideResourcesPerFile(String clusterWideFolderPath,String resourceType) { + List resources = kubeCmdClient.listClusterWide(resourceType); + if (resources != null && !resources.isEmpty()) { + String fullFolderPath = createResourceDirectoryInNamespaceDir(clusterWideFolderPath, resourceType); + + resources.forEach(resourceName -> { + String yaml = kubeCmdClient.getClusterWideResourceAsYaml(resourceType, resourceName); + + String resFileName = LogCollectorUtils.getYamlFileNameForResource(resourceName); + String fileName = LogCollectorUtils.getFullPathForFolderPathAndFileName(fullFolderPath, resFileName); + writeDataToFile(fileName, yaml); + }); + } + } + /** * Method that collects all Events (kubectl get events) from Namespace * @@ -261,7 +328,7 @@ public void collectEventsFromNamespace(String namespaceName, String namespaceFol * @param namespaceFolderPath path to Namespace folder where the resource directories will be created */ private void collectResourcesDescInNamespace(String namespaceName, String namespaceFolderPath) { - resources.forEach(resource -> + namespacedResources.forEach(resource -> collectDescriptionOfResourceInNamespace(namespaceName, namespaceFolderPath, resource)); } diff --git a/test-frame-log-collector/src/main/java/io/skodjob/testframe/LogCollectorBuilder.java b/test-frame-log-collector/src/main/java/io/skodjob/testframe/LogCollectorBuilder.java index 46446c2..9ad78f2 100644 --- a/test-frame-log-collector/src/main/java/io/skodjob/testframe/LogCollectorBuilder.java +++ b/test-frame-log-collector/src/main/java/io/skodjob/testframe/LogCollectorBuilder.java @@ -4,6 +4,10 @@ */ package io.skodjob.testframe; +import io.skodjob.testframe.clients.KubeClient; +import io.skodjob.testframe.clients.cmdClient.KubeCmdClient; + +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -14,7 +18,10 @@ public class LogCollectorBuilder { private String rootFolderPath; - private List resources; + private List namespacedResources; + private List clusterWideResources; + private KubeClient kubeClient; + private KubeCmdClient kubeCmdClient; /** * Constructor for creating {@link LogCollectorBuilder} with parameters from @@ -24,7 +31,8 @@ public class LogCollectorBuilder { */ public LogCollectorBuilder(LogCollector logCollector) { this.rootFolderPath = logCollector.rootFolderPath; - this.resources = logCollector.resources; + this.namespacedResources = logCollector.namespacedResources; + this.clusterWideResources = logCollector.clusterWideResources; } /** @@ -47,14 +55,15 @@ public LogCollectorBuilder withRootFolderPath(String rootFolderPath) { } /** - * Method for setting the resources, which YAML descriptions should be collected as part of the log collection + * Method for setting the namespaced resources, which YAML + * descriptions should be collected as part of the log collection * * @param resources array of resources * * @return {@link LogCollectorBuilder} object */ - public LogCollectorBuilder withResources(String... resources) { - this.resources = Arrays.stream(resources).toList() + public LogCollectorBuilder withNamespacedResources(String... resources) { + this.namespacedResources = Arrays.stream(resources).toList() .stream() .filter(resource -> !resource.equals(CollectorConstants.POD) && !resource.equals(CollectorConstants.PODS)) .collect(Collectors.toList()); @@ -62,6 +71,42 @@ public LogCollectorBuilder withResources(String... resources) { return this; } + /** + * Method for setting the cluster wide resources, which YAML + * descriptions should be collected as part of the log collection + * + * @param resources array of resources + * + * @return {@link LogCollectorBuilder} object + */ + public LogCollectorBuilder withClusterWideResources(String... resources) { + this.clusterWideResources = new ArrayList<>(Arrays.stream(resources).toList()); + + return this; + } + + /** + * Setter for kubeClient + * + * @param kubeClient kubeClientInstance + * @return {@link LogCollectorBuilder} object + */ + public LogCollectorBuilder withKubeClient(KubeClient kubeClient) { + this.kubeClient = kubeClient; + return this; + } + + /** + * Setter for kubeCmdClient + * + * @param kubeCmdClient kubeClientInstance + * @return {@link LogCollectorBuilder} object + */ + public LogCollectorBuilder withKubeCmdClient(KubeCmdClient kubeCmdClient) { + this.kubeCmdClient = kubeCmdClient; + return this; + } + /** * Getter returning currently configured {@link #rootFolderPath} * @@ -72,12 +117,39 @@ public String getRootFolderPath() { } /** - * Getter returning currently configured {@link #resources} in {@link List} object + * Getter returning currently configured {@link #namespacedResources} in {@link List} object + * + * @return {@link #namespacedResources} + */ + public List getNamespacedResources() { + return this.namespacedResources; + } + + /** + * Getter returning currently configured {@link #clusterWideResources} in {@link List} object + * + * @return {@link #clusterWideResources} + */ + public List getClusterWideResources() { + return this.clusterWideResources; + } + + /** + * Getter for kubeClient + * + * @return {@link #kubeClient} + */ + public KubeClient getKubeClient() { + return this.kubeClient; + } + + /** + * Getter for kubeCmdClient * - * @return {@link #resources} + * @return {@link #kubeCmdClient} */ - public List getResources() { - return this.resources; + public KubeCmdClient getKubeCmdClient() { + return this.kubeCmdClient; } /** diff --git a/test-frame-log-collector/src/test/java/io/skodjob/testframe/LogCollectorBuilderTest.java b/test-frame-log-collector/src/test/java/io/skodjob/testframe/LogCollectorBuilderTest.java index 3d4d423..546e5ac 100644 --- a/test-frame-log-collector/src/test/java/io/skodjob/testframe/LogCollectorBuilderTest.java +++ b/test-frame-log-collector/src/test/java/io/skodjob/testframe/LogCollectorBuilderTest.java @@ -3,7 +3,6 @@ import io.skodjob.testframe.annotations.TestVisualSeparator; import org.junit.jupiter.api.Test; -import java.io.IOException; import java.util.Collections; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -15,9 +14,9 @@ public class LogCollectorBuilderTest { @Test void testPassingPodAndPodsAsResourcesToLogCollectorBuilder() { LogCollectorBuilder logCollectorBuilder = new LogCollectorBuilder() - .withResources("pod", "pods"); + .withNamespacedResources("pod", "pods"); - assertEquals(Collections.emptyList(), logCollectorBuilder.getResources()); + assertEquals(Collections.emptyList(), logCollectorBuilder.getNamespacedResources()); } @Test diff --git a/test-frame-log-collector/src/test/java/io/skodjob/testframe/LogCollectorIT.java b/test-frame-log-collector/src/test/java/io/skodjob/testframe/LogCollectorIT.java index 554efc6..9783f96 100644 --- a/test-frame-log-collector/src/test/java/io/skodjob/testframe/LogCollectorIT.java +++ b/test-frame-log-collector/src/test/java/io/skodjob/testframe/LogCollectorIT.java @@ -78,8 +78,10 @@ public void setup() { mockNamespaceOperation = mock(NonNamespaceOperation.class); logCollector = new LogCollectorBuilder() - .withResources(SECRET, DEPLOYMENT, CONFIG_MAP) + .withNamespacedResources(SECRET, DEPLOYMENT, CONFIG_MAP) .withRootFolderPath(pathToRoot) + .withKubeCmdClient(mockCmdClient) + .withKubeClient(mockClient) .build(); } @@ -91,10 +93,9 @@ public void setRootPathForCollector() { logCollector = new LogCollectorBuilder(logCollector) .withRootFolderPath(getFolderPathForTest()) + .withKubeCmdClient(mockCmdClient) + .withKubeClient(mockClient) .build(); - - logCollector.setKubeCmdClient(mockCmdClient); - logCollector.setKubeClient(mockClient); } /** @@ -258,12 +259,11 @@ void testCollectFromNonExistentNamespace() { void testChangingCustomResources() throws IOException { LogCollector localLogCollector = new LogCollectorBuilder() .withRootFolderPath(getFolderPathForTest()) - .withResources(SECRET) + .withNamespacedResources(SECRET) + .withKubeClient(mockClient) + .withKubeCmdClient(mockCmdClient) .build(); - localLogCollector.setKubeClient(mockClient); - localLogCollector.setKubeCmdClient(mockCmdClient); - String namespaceName = "my-namespace"; String[] secretNames = new String[]{"secret1", "secret2"}; String[] deploymentNames = new String[]{"deployment1", "deployment2"}; @@ -292,12 +292,11 @@ void testChangingCustomResources() throws IOException { localLogCollector = new LogCollectorBuilder(localLogCollector) .withRootFolderPath(getFolderPathForTest()) - .withResources(CONFIG_MAP, DEPLOYMENT) + .withNamespacedResources(CONFIG_MAP, DEPLOYMENT) + .withKubeClient(mockClient) + .withKubeCmdClient(mockCmdClient) .build(); - localLogCollector.setKubeClient(mockClient); - localLogCollector.setKubeCmdClient(mockCmdClient); - localLogCollector.collectFromNamespace(namespaceName); rootFolder = Paths.get(getFolderPathForTest()).toFile(); @@ -343,11 +342,10 @@ void testCollectingWithEmptyListOfCustomResources() { LogCollector localLogCollector = new LogCollectorBuilder() .withRootFolderPath(getFolderPathForTest()) + .withKubeClient(mockClient) + .withKubeCmdClient(mockCmdClient) .build(); - localLogCollector.setKubeClient(mockClient); - localLogCollector.setKubeCmdClient(mockCmdClient); - mockNamespaces(namespaceName); mockEvents(); mockSecrets(namespaceName, secretNames); diff --git a/test-frame-test-examples/src/test/java/io/skodjob/testframe/test/integration/LogCollectorIT.java b/test-frame-test-examples/src/test/java/io/skodjob/testframe/test/integration/LogCollectorIT.java index 7183383..b1a7721 100644 --- a/test-frame-test-examples/src/test/java/io/skodjob/testframe/test/integration/LogCollectorIT.java +++ b/test-frame-test-examples/src/test/java/io/skodjob/testframe/test/integration/LogCollectorIT.java @@ -6,6 +6,7 @@ import io.fabric8.kubernetes.api.model.*; import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; +import io.skodjob.testframe.CollectorConstants; import io.skodjob.testframe.LogCollector; import io.skodjob.testframe.LogCollectorBuilder; import io.skodjob.testframe.LogCollectorUtils; @@ -35,7 +36,8 @@ public class LogCollectorIT extends AbstractIT { private final String folderRoot = "/tmp/log-collector-examples"; private final String[] resourcesToBeCollected = new String[] {"secret", "configmap", "deployment"}; private final LogCollector logCollector = new LogCollectorBuilder() - .withResources(resourcesToBeCollected) + .withNamespacedResources(resourcesToBeCollected) + .withClusterWideResources("nodes") .withRootFolderPath(folderRoot) .build(); @@ -144,6 +146,8 @@ void testCollectFromMultipleNamespacesWithDifferentResources() { ); logCollector.collectFromNamespacesToFolder(List.of(namespaceName1, namespaceName2), folderPath); + logCollector.collectClusterWideResourcesToFolder(folderPath); + logCollector.collectClusterWideResourcesToFolder(false, folderPath); List podNames = KubeResourceManager.getKubeClient() .listPods(namespaceName1).stream().map(pod -> pod.getMetadata().getName()).toList(); @@ -157,9 +161,12 @@ void testCollectFromMultipleNamespacesWithDifferentResources() { File[] namespaceFolders = rootFolder.listFiles(); assertNotNull(namespaceFolders); - assertEquals(2, namespaceFolders.length); + assertEquals(3, namespaceFolders.length); - Arrays.stream(namespaceFolders).forEach(namespaceFolder -> { + assertTrue(rootFolder.toPath() + .resolve(CollectorConstants.CLUSTER_WIDE_FOLDER).resolve("nodes.yaml").toFile().exists()); + + Arrays.stream(namespaceFolders).filter(File::isDirectory).forEach(namespaceFolder -> { List namespaceFolderFiles = Arrays.asList(Objects.requireNonNull(namespaceFolder.listFiles())); List namespaceFolderFileNames = namespaceFolderFiles.stream().map(File::getName).toList(); @@ -200,7 +207,7 @@ void testCollectFromMultipleNamespacesWithDifferentResources() { secretNames.forEach( secret -> assertTrue(secretFolderFileNames.contains(LogCollectorUtils.getYamlFileNameForResource(secret))) ); - } else { + } else if (namespaceFolder.getName().equals(namespaceName2)) { assertFalse(namespaceFolderFileNames.contains("pod")); assertFalse(namespaceFolderFileNames.contains("deployment")); assertTrue(namespaceFolderFileNames.contains("configmap")); @@ -211,6 +218,13 @@ void testCollectFromMultipleNamespacesWithDifferentResources() { List configMapFolderFileNames = configMapFolderFiles.stream().map(File::getName).toList(); assertTrue(configMapFolderFileNames.contains(LogCollectorUtils.getYamlFileNameForResource(configMapName))); + } else if (namespaceFolder.getName().equals(CollectorConstants.CLUSTER_WIDE_FOLDER)) { + int countOfNodes = KubeResourceManager.getKubeClient().getClient().nodes().list().getItems().size(); + int countOfFiles = Objects.requireNonNull( + Arrays.stream(Objects.requireNonNull(namespaceFolder.listFiles())) + .filter(file -> file.getName().equals("nodes")).toList() + .stream().findFirst().get().listFiles()).length; + assertEquals(countOfNodes, countOfFiles); } }); }