Skip to content

Commit dc26790

Browse files
committed
Handle situations when we cannot collect or list particular resource(s)
Signed-off-by: Lukas Kral <lukywill16@gmail.com>
1 parent 2309a59 commit dc26790

File tree

2 files changed

+69
-13
lines changed

2 files changed

+69
-13
lines changed

test-frame-log-collector/src/main/java/io/skodjob/testframe/LogCollector.java

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.Arrays;
2222
import java.util.Collections;
2323
import java.util.List;
24+
import java.util.function.Supplier;
2425

2526
/**
2627
* LogCollector class containing all methods used for logs and YAML collection.
@@ -188,10 +189,14 @@ public void collectClusterWideResourcesToFolder(boolean logPerFile, String folde
188189
if (logPerFile) {
189190
collectClusterWideResourcesPerFile(clusterWideFolderPath, resourceType);
190191
} else {
191-
String yaml = kubeCmdClient.getClusterWideResourcesAsYaml(resourceType);
192+
String yaml = executeCollectionCall(
193+
String.format("collect descriptions of type: %s", resourceType),
194+
() -> kubeCmdClient.getClusterWideResourcesAsYaml(resourceType)
195+
);
192196
String resFileName = LogCollectorUtils.getYamlFileNameForResource(resourceType);
193197
String filePath = LogCollectorUtils
194198
.getFullPathForFolderPathAndFileName(clusterWideFolderPath, resFileName);
199+
195200
writeDataToFile(filePath, yaml);
196201
}
197202
});
@@ -210,9 +215,12 @@ public void collectClusterWideResourcesToFolder(boolean logPerFile, String folde
210215
*/
211216
public void collectLogsFromPodsInNamespace(String namespaceName, String namespaceFolderPath) {
212217
LOGGER.info("Collecting logs from all Pods in Namespace: {}", namespaceName);
213-
List<Pod> pods = kubeClient.listPods(namespaceName);
218+
List<Pod> pods = executeCollectionCall(
219+
String.format("list Pods in Namespace: %s", namespaceName),
220+
() -> kubeClient.listPods(namespaceName)
221+
);
214222

215-
if (!pods.isEmpty()) {
223+
if (pods != null && !pods.isEmpty()) {
216224
String podsFolderPath = createResourceDirectoryInNamespaceDir(namespaceFolderPath, CollectorConstants.POD);
217225

218226
pods.forEach(pod -> {
@@ -262,7 +270,10 @@ private void collectLogsFromPodContainer(
262270
String podName,
263271
String containerName
264272
) {
265-
String containerLog = kubeCmdClient.inNamespace(namespaceName).logs(podName, containerName);
273+
String containerLog = executeCollectionCall(
274+
String.format("collect logs from Pod:%s", podName),
275+
() -> kubeCmdClient.inNamespace(namespaceName).logs(podName, containerName)
276+
);
266277
String podConLogFileName = LogCollectorUtils.getLogFileNameForPodContainer(podName, containerName);
267278
String filePath = LogCollectorUtils.getFullPathForFolderPathAndFileName(podsFolderPath, podConLogFileName);
268279

@@ -277,7 +288,10 @@ private void collectLogsFromPodContainer(
277288
* @param podName name of Pod from which the description should be collected
278289
*/
279290
private void collectPodDescription(String namespaceName, String podsFolderPath, String podName) {
280-
String podDesc = kubeCmdClient.inNamespace(namespaceName).describe(CollectorConstants.POD, podName);
291+
String podDesc = executeCollectionCall(
292+
String.format("collect description of Pod:%s", podName),
293+
() -> kubeCmdClient.inNamespace(namespaceName).describe(CollectorConstants.POD, podName)
294+
);
281295
String podDescFileName = LogCollectorUtils.getLogFileNameForPodDescription(podName);
282296
String filePath = LogCollectorUtils.getFullPathForFolderPathAndFileName(podsFolderPath, podDescFileName);
283297

@@ -296,7 +310,10 @@ private void collectClusterWideResourcesPerFile(String clusterWideFolderPath,Str
296310
String fullFolderPath = createResourceDirectoryInNamespaceDir(clusterWideFolderPath, resourceType);
297311

298312
resources.forEach(resourceName -> {
299-
String yaml = kubeCmdClient.getClusterWideResourceAsYaml(resourceType, resourceName);
313+
String yaml = executeCollectionCall(
314+
String.format("collect YAML description for %s:%s", resourceType, resourceName),
315+
() -> kubeCmdClient.getClusterWideResourceAsYaml(resourceType, resourceName)
316+
);
300317

301318
String resFileName = LogCollectorUtils.getYamlFileNameForResource(resourceName);
302319
String fileName = LogCollectorUtils.getFullPathForFolderPathAndFileName(fullFolderPath, resFileName);
@@ -313,7 +330,10 @@ private void collectClusterWideResourcesPerFile(String clusterWideFolderPath,Str
313330
*/
314331
public void collectEventsFromNamespace(String namespaceName, String namespaceFolderPath) {
315332
LOGGER.info("Collecting events from Namespace: {}", namespaceName);
316-
String events = kubeCmdClient.inNamespace(namespaceName).getEvents();
333+
String events = executeCollectionCall(
334+
String.format("collect %s from %s", CollectorConstants.EVENTS, namespaceName),
335+
() -> kubeCmdClient.inNamespace(namespaceName).getEvents()
336+
);
317337
String eventsFileName = LogCollectorUtils.getLogFileNameForResource(CollectorConstants.EVENTS);
318338
String fileName = LogCollectorUtils.getFullPathForFolderPathAndFileName(namespaceFolderPath, eventsFileName);
319339

@@ -349,13 +369,19 @@ private void collectDescriptionOfResourceInNamespace(
349369
String resourceType
350370
) {
351371
LOGGER.info("Collecting YAMLs of {} from Namespace: {}", resourceType, namespaceName);
352-
List<String> resources = kubeCmdClient.inNamespace(namespaceName).list(resourceType);
372+
List<String> resources = executeCollectionCall(
373+
String.format("list resources of type: %s in Namespace: %s", resourceType, namespaceName),
374+
() -> kubeCmdClient.inNamespace(namespaceName).list(resourceType)
375+
);
353376

354377
if (resources != null && !resources.isEmpty()) {
355378
String fullFolderPath = createResourceDirectoryInNamespaceDir(namespaceFolderPath, resourceType);
356379

357380
resources.forEach(resourceName -> {
358-
String yaml = kubeCmdClient.inNamespace(namespaceName).getResourceAsYaml(resourceType, resourceName);
381+
String yaml = executeCollectionCall(
382+
String.format("collect YAML description for %s:%s", resourceType, resourceName),
383+
() -> kubeCmdClient.inNamespace(namespaceName).getResourceAsYaml(resourceType, resourceName)
384+
);
359385

360386
String resFileName = LogCollectorUtils.getYamlFileNameForResource(resourceName);
361387
String fileName = LogCollectorUtils.getFullPathForFolderPathAndFileName(fullFolderPath, resFileName);
@@ -433,4 +459,24 @@ private void writeDataToFile(String fullFilePath, String data) {
433459
}
434460
}
435461
}
462+
463+
/**
464+
* Method for executing the collection (or list) call, which handles the exceptions when the resource is not found
465+
* (or was removed during the process). That way the LogCollector will continue with collection of other resources.
466+
*
467+
* @param errorOperationMessage message for the operation that is being executed, for error logging
468+
* @param executeCall Supplier with the lambda method for collection of the data
469+
*
470+
* @return result of the execution of the method -> YAML descriptions, logs, or lists of resources
471+
*
472+
* @param <T> type of the return value -> same as the return type of the executed call
473+
*/
474+
private <T> T executeCollectionCall(String errorOperationMessage, Supplier<T> executeCall) {
475+
try {
476+
return executeCall.get();
477+
} catch (Exception e) {
478+
LOGGER.warn("Failed to {}, due to: {}", errorOperationMessage, e.getMessage());
479+
return null;
480+
}
481+
}
436482
}

test-frame-log-collector/src/test/java/io/skodjob/testframe/LogCollectorIT.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import io.fabric8.kubernetes.api.model.Pod;
1616
import io.fabric8.kubernetes.api.model.PodBuilder;
1717
import io.fabric8.kubernetes.client.KubernetesClient;
18+
import io.fabric8.kubernetes.client.KubernetesClientException;
1819
import io.fabric8.kubernetes.client.dsl.FilterWatchListDeletable;
1920
import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
2021
import io.fabric8.kubernetes.client.dsl.Resource;
@@ -42,10 +43,7 @@
4243
import java.util.Map;
4344
import java.util.Objects;
4445

45-
import static org.junit.jupiter.api.Assertions.assertFalse;
46-
import static org.junit.jupiter.api.Assertions.assertNotNull;
47-
import static org.junit.jupiter.api.Assertions.assertThrows;
48-
import static org.junit.jupiter.api.Assertions.assertTrue;
46+
import static org.junit.jupiter.api.Assertions.*;
4947
import static org.mockito.ArgumentMatchers.anyString;
5048
import static org.mockito.Mockito.any;
5149
import static org.mockito.Mockito.eq;
@@ -380,6 +378,18 @@ void testCannotWriteToFiles() {
380378
}
381379
}
382380

381+
@Test
382+
void testExceptionDuringResourceCollection() {
383+
String namespaceName = "my-namespace";
384+
mockNamespaces(namespaceName);
385+
mockSecrets(namespaceName, "my-secret");
386+
387+
when(mockClient.listPods(any())).thenThrow(new KubernetesClientException("Failed to obtain the resource"));
388+
when(mockCmdClient.getResourceAsYaml(any(), any())).thenThrow(new KubernetesClientException("Failed to get description of resource"));
389+
390+
assertDoesNotThrow(() -> logCollector.collectFromNamespace(namespaceName));
391+
}
392+
383393
@AfterEach
384394
void cleanAndUpdate() {
385395
reset(mockCmdClient, mockClient);

0 commit comments

Comments
 (0)