-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
4 changed files
with
150 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
coverage | ||
brownie-ns-list.tmp.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#!/bin/bash | ||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
# This script is invoked from the periodic CI pipeline. It will fetch the list of children | ||
# namespaces from the kubernetes and pass that list into the node app. The node app will determine | ||
# whether the namespace is old and should be removed or it hasn't been aged yet and should be | ||
# kept in the cluster. If the "--dry-run" parameter is "false" then old namespaces will be removed. | ||
# The actual removal of namespace is delegeated to | ||
# ../k8s-deployer/scripts/k8s-manage-namespace.sh | ||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
K8S_NAMESPACE=$1 | ||
BROWNIE_TIMEOUT=$2 | ||
DRY_RUN=$3 | ||
|
||
if [ "${DRY_RUN}" == "" ]; then DRY_RUN="true"; fi | ||
|
||
usage="Example: $0 my-parent-namespace 3days" | ||
if [ "${K8S_NAMESPACE}" == "" ]; | ||
then | ||
echo "Missing 1st parameter namespace" | ||
echo $usage | ||
exit 1 | ||
fi | ||
|
||
if [ "${BROWNIE_TIMEOUT}" == "" ]; | ||
then | ||
echo "Missing 2nd parameter namespace retention period" | ||
echo $usage | ||
exit 1 | ||
fi | ||
|
||
LOG_FILE="./brownie-ns-list.tmp.json" | ||
|
||
kubectl get ns -l "${K8S_NAMESPACE}.tree.hnc.x-k8s.io/depth=1" -ojson | jq '.items' > $LOG_FILE | ||
|
||
node dist/src/k8ns/index.js --dry-run $DRY_RUN --ns-file $LOG_FILE --retention-period $BROWNIE_TIMEOUT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import * as fs from "fs" | ||
|
||
import { Config as BrownieConfig } from "../config.js" | ||
import { logger } from "../logger.js" | ||
|
||
export const HNC_PARENT_ANNOTATION = "hnc.x-k8s.io/subnamespace-of" | ||
export interface ChildNamespace { | ||
metadata: { | ||
creationTimestamp: string, | ||
name: string, | ||
annotations: Array<string> | ||
} | ||
} | ||
|
||
export class Config { | ||
constructor( | ||
readonly dryRun: boolean, | ||
readonly nsList: Array<ChildNamespace>, | ||
readonly retentionMinutes: number, | ||
) {} | ||
} | ||
|
||
export const loadConfig = (params: Map<string, string>): Config => { | ||
const dryRunRaw = params.get(BrownieConfig.PARAM_DRY_RUN) | ||
const nsDataFile = params.get("--ns-file") | ||
const retentionRaw = params.get(BrownieConfig.PARAM_RETENTION_PERIOD) | ||
|
||
const nsListRaw = fs.readFileSync(`${ nsDataFile }`).toString("utf-8") | ||
let nsList: Array<ChildNamespace> = null | ||
try { | ||
nsList = JSON.parse(nsListRaw) | ||
} catch (e) { | ||
logger.warn("loadConfig(): Could not parse the list of namespaces:\n%s", nsListRaw) | ||
throw new Error(`Unable to parse raw list of namespaces in '${ nsDataFile }'`, { cause: e }) | ||
} | ||
|
||
return new Config( | ||
"false" !== dryRunRaw.toLowerCase(), | ||
nsList, | ||
BrownieConfig.parseRetention(retentionRaw) | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import * as Shell from "node:child_process" | ||
|
||
import { logger } from "../logger.js" | ||
import * as Core from "./core.js" | ||
|
||
const main = async () => { | ||
const params = new Map<string, string>() | ||
|
||
let deletedCount = 0 | ||
for (let i = 2; i < process.argv.length; i+=2) { | ||
params.set(process.argv[i], process.argv[i + 1]) | ||
} | ||
const config = Core.loadConfig(params) | ||
if (config.nsList.length == 0) { | ||
logger.debug("There are no namespaces to delete") | ||
return | ||
} | ||
|
||
logger.info("Analysing the list of %s namespaces", config.nsList.length) | ||
|
||
for (let ns of config.nsList) { | ||
logger.info("") | ||
|
||
if (!ns.metadata.creationTimestamp) { | ||
logger.info("Namespace '%s' does not have 'creationTimestamp' information. Skipping...", ns.metadata.name) | ||
continue | ||
} | ||
|
||
const nsName = ns.metadata.name | ||
const ageInMinutes = (new Date().getTime() - Date.parse(ns.metadata.creationTimestamp)) / 60_000 | ||
logger.info("Namespace '%s' was created at: %s. It is %s minutes old", nsName, ns.metadata.creationTimestamp, ageInMinutes.toFixed(2)) | ||
if (ageInMinutes < config.retentionMinutes) { | ||
logger.info("Namespace '%s' hasn't aged enough. Will be cleaned after %s minutes", nsName, (config.retentionMinutes - ageInMinutes).toFixed(2)) | ||
continue | ||
} | ||
|
||
const parentNsName = ns.metadata.annotations[Core.HNC_PARENT_ANNOTATION] | ||
if (!parentNsName) { | ||
logger.warn("The child namespace '%s', does not have '%s' annotation. It might be misconfigured, hence need to be dealt with manually. Skipping...", nsName, Core.HNC_PARENT_ANNOTATION) | ||
continue | ||
} | ||
|
||
logger.info("Deleting namespace '%s' under '%s'", nsName, parentNsName) | ||
if (config.dryRun) { | ||
|
||
logger.info("Namespace '%s > %s' has NOT been deleted (dry run mode).", parentNsName, nsName) | ||
deletedCount++ | ||
|
||
} else { | ||
|
||
try { | ||
|
||
const script = "../k8s-deployer/scripts/k8s-manage-namespace.sh" | ||
const scriptParams = [ parentNsName, "delete", nsName, 120 ] | ||
Shell.spawnSync(script, scriptParams, { stdio: [ 'inherit', 'inherit', 'inherit' ] }) | ||
deletedCount++ | ||
|
||
} catch (e) { | ||
logger.error("Unable to delete namespace %s > %s. Error: %s", parentNsName, nsName, e.message) | ||
if (e.cause) logger.error(e.cause) | ||
if (e.stack) logger.error("Stack:\n%s", e.stack) | ||
} | ||
} | ||
} | ||
} | ||
|
||
main() | ||
.catch(e => { | ||
logger.error("Message: %s", e.message) | ||
if (e.cause) logger.error(e.cause) | ||
if (e.stack) logger.error("Stack:\n%s", e.stack) | ||
}) |