From 8de7d5deead799a170bcfe519ae2a7c919f7991e Mon Sep 17 00:00:00 2001 From: David Zuber Date: Sun, 17 May 2020 09:29:30 +0100 Subject: [PATCH] Add -mode flag and update to 1.18.2 --- CHANGELOG.md | 6 ++++ README.md | 36 +++++++++++++++---- kind-config.yaml | 4 +-- kubedoom.go | 75 ++++++++++++++++++++++++++++++++-------- manifest/deployment.yaml | 2 +- 5 files changed, 98 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e94d08..501f1d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 0.4.0 + +* New image storadev/kubedoom:0.4.0 +* New `-mode` flag to switch between killing pods or namespaces. +* Update kubernetes to 1.18.2 + # 0.3.0 * New image storadev/kubedoom:0.3.0 diff --git a/README.md b/README.md index c855771..ca1a11f 100644 --- a/README.md +++ b/README.md @@ -13,18 +13,19 @@ which was forked from psdoom. ## Usage -Run `storaxdev/kubedoom:0.3.0` locally: +Run `storaxdev/kubedoom:0.4.0` locally: ```console -$ docker run -p5900:5900 \ +$ docker run -p5901:5900 \ + --net=host \ -v ~/.kube:/root/.kube \ --rm -it --name kubedoom \ - storaxdev/kubedoom:0.3.0 + storaxdev/kubedoom:0.4.0 ``` -Now start a VNC viewer and connect to `localhost:5900`. The password is `1234`: +Now start a VNC viewer and connect to `localhost:5901`. The password is `1234`: ```console -$ vncviewer viewer localhost +$ vncviewer viewer localhost:5901 ``` You should now see DOOM! Now if you want to get the job done quickly enter the cheat `idspispopd` and walk through the wall on your right. You should be @@ -32,6 +33,21 @@ greeted by your pods as little pink monsters. Press `CTRL` to fire. If the pistol is not your thing, cheat with `idkfa` and press `5` for a nice surprise. Pause the game with `ESC`. +### Killing namespaces + +Kubedoom now also supports killing namespaces [in case you have too many of +them](https://github.com/storax/kubedoom/issues/5). Simply set the `-mode` flag +to `namespaces`: + +```console +$ docker run -p5901:5900 \ + --net=host \ + -v ~/.kube:/root/.kube \ + --rm -it --name kubedoom \ + storaxdev/kubedoom:0.4.0 \ + -mode namespaces +``` + ### Running Kubedoom inside Kubernetes See the example in the `/manifest` directory. You can quickly test it using @@ -41,7 +57,7 @@ example config from this repository: ```console $ kind create cluster --config kind-config.yaml Creating cluster "kind" ... - ✓ Ensuring node image (kindest/node:v1.18.0) đŸ–ŧ + ✓ Ensuring node image (kindest/node:v1.18.2) đŸ–ŧ ✓ Preparing nodes đŸ“Ļ đŸ“Ļ ✓ Writing configuration 📜 ✓ Starting control-plane đŸ•šī¸ @@ -68,5 +84,11 @@ deployment.apps/kubedoom created serviceaccount/kubedoom created clusterrolebinding.rbac.authorization.k8s.io/kubedoom created ``` + +To connect run: +```console +$ vncviewer viewer localhost:5900 +``` + Kubedoom requires a service account with permissions to list all pods and delete -them and uses kubectl 1.18.1. +them and uses kubectl 1.18.2. diff --git a/kind-config.yaml b/kind-config.yaml index d917e53..7d16c0b 100644 --- a/kind-config.yaml +++ b/kind-config.yaml @@ -2,9 +2,9 @@ kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane - image: kindest/node:v1.18.0@sha256:0e20578828edd939d25eb98496a685c76c98d54084932f76069f886ec315d694 + image: kindest/node:v1.18.2@sha256:7b27a6d0f2517ff88ba444025beae41491b016bc6af573ba467b70c5e8e0d85f - role: worker - image: kindest/node:v1.18.0@sha256:0e20578828edd939d25eb98496a685c76c98d54084932f76069f886ec315d694 + image: kindest/node:v1.18.2@sha256:7b27a6d0f2517ff88ba444025beae41491b016bc6af573ba467b70c5e8e0d85f extraPortMappings: - containerPort: 5900 hostPort: 5900 diff --git a/kubedoom.go b/kubedoom.go index 0f9c78c..f0d3758 100644 --- a/kubedoom.go +++ b/kubedoom.go @@ -1,13 +1,14 @@ package main import ( + "flag" "log" "net" "os" "os/exec" + "strconv" "strings" "time" - "strconv" ) func hash(input string) int32 { @@ -16,7 +17,7 @@ func hash(input string) int32 { for _, char := range input { hash = ((hash << 5) + hash + int32(char)) } - if (hash < 0) { + if hash < 0 { hash = 0 - hash } return hash @@ -55,7 +56,15 @@ func startCmd(cmdstring string) { } } -func getPods() []string { +type Mode interface { + getEntities() []string + deleteEntity(string) +} + +type podmode struct { +} + +func (m podmode) getEntities() []string { args := []string{"kubectl", "get", "pods", "-A", "-o", "go-template", "--template={{range .items}}{{.metadata.namespace}}/{{.metadata.name}} {{end}}"} output := outputCmd(args) outputstr := strings.TrimSpace(output) @@ -63,7 +72,31 @@ func getPods() []string { return pods } -func socketLoop(listener net.Listener) { +func (m podmode) deleteEntity(entity string) { + log.Printf("Pod to kill: %v", entity) + podparts := strings.Split(entity, "/") + cmd := exec.Command("/usr/bin/kubectl", "delete", "pod", "-n", podparts[0], podparts[1]) + go cmd.Run() +} + +type nsmode struct { +} + +func (m nsmode) getEntities() []string { + args := []string{"kubectl", "get", "namespaces", "-o", "go-template", "--template={{range .items}}{{.metadata.name}} {{end}}"} + output := outputCmd(args) + outputstr := strings.TrimSpace(output) + namespaces := strings.Split(outputstr, " ") + return namespaces +} + +func (m nsmode) deleteEntity(entity string) { + log.Printf("Namespace to kill: %v", entity) + cmd := exec.Command("/usr/bin/kubectl", "delete", "namespace", entity) + go cmd.Run() +} + +func socketLoop(listener net.Listener, mode Mode) { for true { conn, err := listener.Accept() if err != nil { @@ -78,11 +111,11 @@ func socketLoop(listener net.Listener) { } bytes = bytes[0:n] strbytes := strings.TrimSpace(string(bytes)) - pods := getPods() + entities := mode.getEntities() if strbytes == "list" { - for _, pod := range pods { - padding := strings.Repeat("\n", 255 - len(pod)) - _, err = conn.Write([]byte(pod + padding)) + for _, entity := range entities { + padding := strings.Repeat("\n", 255-len(entity)) + _, err = conn.Write([]byte(entity + padding)) if err != nil { log.Fatal("Could not write to socker file") } @@ -95,12 +128,9 @@ func socketLoop(listener net.Listener) { if err != nil { log.Fatal("Could not parse kill hash") } - for _, pod := range pods { - if (hash(pod) == int32(killhash)) { - log.Printf("Pod to kill: %v", pod) - podparts := strings.Split(pod, "/") - cmd := exec.Command("/usr/bin/kubectl", "delete", "pod", "-n", podparts[0], podparts[1]) - go cmd.Run() + for _, entity := range entities { + if hash(entity) == int32(killhash) { + mode.deleteEntity(entity) break } } @@ -112,6 +142,21 @@ func socketLoop(listener net.Listener) { } func main() { + var modeFlag string + flag.StringVar(&modeFlag, "mode", "pods", "What to kill pods|namespaces") + + flag.Parse() + + var mode Mode + switch modeFlag { + case "pods": + mode = podmode{} + case "namespaces": + mode = nsmode{} + default: + log.Fatalf("Mode should be pods or namespaces") + } + listener, err := net.Listen("unix", "/dockerdoom.socket") if err != nil { log.Fatalf("Could not create socket file") @@ -125,5 +170,5 @@ func main() { log.Print("Trying to start DOOM ...") startCmd("/usr/bin/env DISPLAY=:99 /usr/local/games/psdoom -warp -E1M1") - socketLoop(listener) + socketLoop(listener, mode) } diff --git a/manifest/deployment.yaml b/manifest/deployment.yaml index a1fcb18..22bcb17 100644 --- a/manifest/deployment.yaml +++ b/manifest/deployment.yaml @@ -18,7 +18,7 @@ spec: hostNetwork: true serviceAccountName: kubedoom containers: - - image: storaxdev/kubedoom:0.3.0 + - image: storaxdev/kubedoom:0.4.0 name: kubedoom ports: - containerPort: 5900