From 39bad1a22f48b4bf76bd5d506b1ff85d7ceba8b6 Mon Sep 17 00:00:00 2001
From: Peter Somogyvari <peter.somogyvari@accenture.com>
Date: Sat, 20 Mar 2021 13:52:38 -0700
Subject: [PATCH] feat(test-tooling): pruneDockerResources() observability #694

Primary change
-----------------------

Adds request and response definitions to
the pruneDockerResources() method to
allow callers to control the log levels
and also to get a complete report of the
pruning processes' outcome from the
returned object instead of just returning
with `void`.

Miscellaneous changes
----------------------------------

Significantly improved the documentation
for the utility method in question.

Fixes #694

Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
---
 .../src/main/typescript/common/containers.ts  | 74 ++++++++++++++++---
 .../src/main/typescript/public-api.ts         |  6 +-
 2 files changed, 69 insertions(+), 11 deletions(-)

diff --git a/packages/cactus-test-tooling/src/main/typescript/common/containers.ts b/packages/cactus-test-tooling/src/main/typescript/common/containers.ts
index 14827bb0af1..78ded092aa7 100644
--- a/packages/cactus-test-tooling/src/main/typescript/common/containers.ts
+++ b/packages/cactus-test-tooling/src/main/typescript/common/containers.ts
@@ -6,7 +6,30 @@ import Dockerode from "dockerode";
 import tar from "tar-stream";
 import fs from "fs-extra";
 import { Streams } from "../common/streams";
-import { Checks, Strings } from "@hyperledger/cactus-common";
+import { Checks, LoggerProvider, Strings } from "@hyperledger/cactus-common";
+import { LogLevelDesc } from "loglevel";
+
+export interface IPruneDockerResourcesRequest {
+  logLevel?: LogLevelDesc;
+}
+
+/**
+ * Contains a combined report of the resource pruning performed
+ * by the similarly named utility method of the `Containers` class.
+ * All the properties are optional because the method does a best
+ * effort algorithm with the pruning meaning that all failures are
+ * ignored in favor of continuing with trying to prune other
+ * resources, meaning that all four pruning categories (container, volume, network, image)
+ * are attempted regardless of how many of them succeed or fail.
+ * Based on the above, it is never known for sure if the response object
+ * will contain all, some or none of it's properties at all.
+ */
+export interface IPruneDockerResourcesResponse {
+  containers?: Dockerode.PruneContainersInfo;
+  images?: Dockerode.PruneImagesInfo;
+  networks?: Dockerode.PruneNetworksInfo;
+  volumes?: Dockerode.PruneVolumesInfo;
+}
 
 export interface IPushFileFromFsOptions {
   /**
@@ -374,27 +397,58 @@ export class Containers {
     } while (!reachable);
   }
 
-  public static async pruneDockerResources(): Promise<void> {
+  /**
+   * Attempts to prune all docker resources that are unused on the current
+   * docker host in the following order:
+   * 1. Containers
+   * 2. Volumes
+   * 3. Images
+   * 4. Networks
+   *
+   * @returns A complete rundown of how each pruning process worked out
+   * where the properties pertaining to the pruning processes are `undefined`
+   * if they failed.
+   */
+  public static async pruneDockerResources(
+    req?: IPruneDockerResourcesRequest,
+  ): Promise<IPruneDockerResourcesResponse> {
+    const fnTag = `Containers#pruneDockerResources()`;
+    const level = req?.logLevel || "INFO";
+    const log = LoggerProvider.getOrCreate({ level, label: fnTag });
     const docker = new Dockerode();
+    let containers;
+    let volumes;
+    let images;
+    let networks;
     try {
-      await docker.pruneContainers();
+      containers = await docker.pruneContainers();
     } catch (ex) {
-      console.warn(`Failed to prune docker containers: `, ex);
+      log.warn(`Failed to prune docker containers: `, ex);
     }
     try {
-      await docker.pruneVolumes();
+      volumes = await docker.pruneVolumes();
     } catch (ex) {
-      console.warn(`Failed to prune docker volumes: `, ex);
+      log.warn(`Failed to prune docker volumes: `, ex);
     }
     try {
-      await docker.pruneImages();
+      images = await docker.pruneImages();
     } catch (ex) {
-      console.warn(`Failed to prune docker images: `, ex);
+      log.warn(`Failed to prune docker images: `, ex);
     }
     try {
-      await docker.pruneNetworks();
+      networks = await docker.pruneNetworks();
     } catch (ex) {
-      console.warn(`Failed to prune docker networks: `, ex);
+      log.warn(`Failed to prune docker networks: `, ex);
     }
+
+    const response: IPruneDockerResourcesResponse = {
+      containers,
+      images,
+      networks,
+      volumes,
+    };
+
+    log.debug(`Finished pruning all docker resources. Outcome: %o`, response);
+    return response;
   }
 }
diff --git a/packages/cactus-test-tooling/src/main/typescript/public-api.ts b/packages/cactus-test-tooling/src/main/typescript/public-api.ts
index 7322f17e03a..f3a13ea3b61 100755
--- a/packages/cactus-test-tooling/src/main/typescript/public-api.ts
+++ b/packages/cactus-test-tooling/src/main/typescript/public-api.ts
@@ -25,7 +25,11 @@ export {
 export { ICordappJarFile } from "./corda/cordapp-jar-file";
 
 export * from "./quorum/i-quorum-genesis-options";
-export { Containers } from "./common/containers";
+export {
+  Containers,
+  IPruneDockerResourcesRequest,
+  IPruneDockerResourcesResponse,
+} from "./common/containers";
 
 export {
   HttpEchoContainer,