From d83cc1b06de1c8016297f7c76e92d1339400be25 Mon Sep 17 00:00:00 2001 From: David Zuber Date: Sun, 1 Sep 2019 20:43:02 +0100 Subject: [PATCH] Implement hashing in go and add README --- Dockerfile | 29 ++++++-- README.md | 61 +++++++++++++++++ dockerdoom/trunk/src/pr_process.c | 2 +- kind-config.yaml | 2 +- kubedoom.go | 106 ++++++++++++++---------------- manifest/deployment.yaml | 2 +- manifest/service.yaml | 15 ----- 7 files changed, 134 insertions(+), 83 deletions(-) create mode 100644 README.md delete mode 100644 manifest/service.yaml diff --git a/Dockerfile b/Dockerfile index dc5e4c5..c32f585 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,23 +10,38 @@ RUN apt-get update FROM ubuntu AS ubuntu-deps # Install dependencies -RUN apt-get install -y -o APT::Install-Suggests=0 --no-install-recommends git wget ca-certificates -RUN git clone https://github.com/GideonRed/dockerdoom.git +RUN apt-get install -y \ + -o APT::Install-Suggests=0 \ + --no-install-recommends \ + wget ca-certificates RUN wget http://distro.ibiblio.org/pub/linux/distributions/slitaz/sources/packages/d/doom1.wad -RUN wget -O /usr/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/linux/amd64/kubectl && chmod +x /usr/bin/kubectl +RUN wget -O /usr/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/linux/amd64/kubectl \ + && chmod +x /usr/bin/kubectl FROM ubuntu AS ubuntu-build ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get install -y -o APT::Install-Suggests=0 --no-install-recommends build-essential libsdl-mixer1.2-dev libsdl-net1.2-dev gcc +RUN apt-get install -y \ + -o APT::Install-Suggests=0 \ + --no-install-recommends \ + build-essential \ + libsdl-mixer1.2-dev \ + libsdl-net1.2-dev \ + gcc # Setup doom -COPY --from=ubuntu-deps /dockerdoom /dockerdoom +ADD /dockerdoom /dockerdoom RUN cd /dockerdoom/trunk && ./configure --enable-static && make && make install FROM ubuntu -RUN apt-get install -y -o APT::Install-Suggests=0 --no-install-recommends libsdl-mixer1.2 libsdl-net1.2 x11vnc xvfb netcat-openbsd - +RUN apt-get install -y \ + -o APT::Install-Suggests=0 \ + --no-install-recommends \ + libsdl-mixer1.2 \ + libsdl-net1.2 \ + x11vnc \ + xvfb \ + netcat-openbsd WORKDIR /root/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..c55208f --- /dev/null +++ b/README.md @@ -0,0 +1,61 @@ +# Kube DOOM +## Kill Kubernetes pods using Id's Doom! + +The next level of chaos engineering is here! Kill pods inside your Kubernetes +cluster by shooting them in Doom! + +This is a fork of the excellent +[gideonred/dockerdoomd](https://github.com/gideonred/dockerdoomd) using a +slightly modified Doom, forked from https://github.com/gideonred/dockerdoom, +which was forked from psdoom. + +## Usage + +Run the `storaxdev/kubedoom:0.1.0` docker image inside your cluster and expose +port 5900. Then connect with a VNC viewer to it. + +You can quickly test it using [kind](https://github.com/kubernetes-sigs/kind). +Create a cluster with the example config from this repository: + +```console +$ kind create cluster --config kind-config.yaml +Creating cluster "kind" ... + ✓ Ensuring node image (kindest/node:v1.15.0) đŸ–ŧ + ✓ Preparing nodes đŸ“ĻđŸ“Ļ + ✓ Creating kubeadm config 📜 + ✓ Starting control-plane đŸ•šī¸ + ✓ Installing CNI 🔌 + ✓ Installing StorageClass 💾 + ✓ Joining worker nodes 🚜 +Cluster creation complete. You can now use the cluster with: + +export KUBECONFIG="$(kind get kubeconfig-path --name="kind")" +kubectl cluster-info +``` + +This will spin up a 2 node cluster inside docker, with port 5900 exposed from +the worker node. Then run kubedoom inside the cluster by applying the manifest +provided in this repository: + +```console +$ export KUBECONFIG="$(kind get kubeconfig-path --name="kind")" +$ kubectl apply -f manifest/ +namespace/kubedoom created +deployment.apps/kubedoom created +serviceaccount/kubedoom created +clusterrolebinding.rbac.authorization.k8s.io/kubedoom created +``` + +Now start a VNC viewer and connect to `localhost:5900`. The password is `1234`: +```console +$ vncviewer viewer localhost +``` + +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 +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`. + +Kubedoom requires a service account with permissions to list all pods and delete +them and uses kubectl 1.15.3. diff --git a/dockerdoom/trunk/src/pr_process.c b/dockerdoom/trunk/src/pr_process.c index 7db0204..78e3d50 100644 --- a/dockerdoom/trunk/src/pr_process.c +++ b/dockerdoom/trunk/src/pr_process.c @@ -137,8 +137,8 @@ void pr_check(void) { while (fgets(buf, 255, f)) { int read_fields = sscanf(buf, "%s\n", namebuf); if (read_fields == 1 && namebuf) { - fprintf(stderr, "Demon: %s\n", namebuf); pid = hash(namebuf); + fprintf(stderr, "Demon: %s, %d\n", namebuf, pid); demon = true; add_to_pid_list(pid, namebuf, demon); } diff --git a/kind-config.yaml b/kind-config.yaml index 867416f..7e646ed 100644 --- a/kind-config.yaml +++ b/kind-config.yaml @@ -6,4 +6,4 @@ nodes: extraPortMappings: - containerPort: 5900 hostPort: 5900 - listenAddress: "127.0.0.1" # Optional, defaults to "0.0.0.0" + listenAddress: "127.0.0.1" diff --git a/kubedoom.go b/kubedoom.go index f88d6fc..0f9c78c 100644 --- a/kubedoom.go +++ b/kubedoom.go @@ -1,18 +1,27 @@ package main -//TODO: Make your container die if you die - import ( - "flag" - //"fmt" "log" "net" "os" "os/exec" "strings" "time" + "strconv" ) +func hash(input string) int32 { + var hash int32 + hash = 5381 + for _, char := range input { + hash = ((hash << 5) + hash + int32(char)) + } + if (hash < 0) { + hash = 0 - hash + } + return hash +} + func runCmd(cmdstring string) { parts := strings.Split(cmdstring, " ") cmd := exec.Command(parts[0], parts[1:len(parts)]...) @@ -38,6 +47,7 @@ func startCmd(cmdstring string) { parts := strings.Split(cmdstring, " ") cmd := exec.Command(parts[0], parts[1:len(parts)]...) cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin err := cmd.Start() if err != nil { @@ -45,70 +55,55 @@ func startCmd(cmdstring string) { } } -func startCmdSilent(cmdstring string) { - parts := strings.Split(cmdstring, " ") - cmd := exec.Command(parts[0], parts[1:len(parts)]...) - cmd.Stdin = os.Stdin - err := cmd.Start() - if err != nil { - log.Fatalf("The following command failed: \"%v\"\n", cmdstring) - } +func getPods() []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) + pods := strings.Split(outputstr, " ") + return pods } func socketLoop(listener net.Listener) { - log.Print("Socket loop") for true { - log.Print("accept?") conn, err := listener.Accept() - log.Print("accept!") if err != nil { panic(err) } stop := false for !stop { bytes := make([]byte, 40960) - log.Print("Reading") n, err := conn.Read(bytes) if err != nil { stop = true } - log.Print("got suff") bytes = bytes[0:n] strbytes := strings.TrimSpace(string(bytes)) - log.Printf("Received: '%s'", strbytes) + pods := getPods() if strbytes == "list" { - // output := outputCmd(fmt.Sprintf("%v ps -q", dockerBinary)) - args := []string{"kubectl", "get", "pods", "-A", "-o", "go-template", "--template={{range .items}}{{.metadata.namespace}}/{{.metadata.name}} {{end}}"} - output := outputCmd(args) - log.Printf("output: '%s'", output) - _, err = conn.Write([]byte(output)) - if err != nil { - log.Fatal("Could not write to socker file") + for _, pod := range pods { + padding := strings.Repeat("\n", 255 - len(pod)) + _, err = conn.Write([]byte(pod + padding)) + if err != nil { + log.Fatal("Could not write to socker file") + } } - //cmd := exec.Command("/usr/bin/docker", "inspect", "-f", "{{.Name}}", "`docker", "ps", "-q`") - // outputstr := strings.TrimSpace(output) - // pods := strings.Split(outputstr, "\n") - // for _, pod := range pods { - // log.Print(pod) - // _, err = conn.Write([]byte(pod + " ")) - // if err != nil { - // log.Fatal("Could not write to socker file") - // } - // time.Sleep(time.Duration(200) * time.Millisecond) - // } conn.Close() stop = true } else if strings.HasPrefix(strbytes, "kill ") { - log.Printf("killcommand: '%s'", strbytes) - // parts := strings.Split(strbytes, " ") - // pod := strings.TrimSpace(parts[1]) - // podparts := strings.Split(pod, "/") - // namespace := podparts[0] - - // podname := podparts[1] - // log.Printf("Pod to kill: %s // %s", namespace, podname) - // cmd := exec.Command(dockerBinary, "rm", "-f", docker_id) - // go cmd.Run() + parts := strings.Split(strbytes, " ") + killhash, err := strconv.ParseInt(parts[1], 10, 32) + 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() + break + } + } conn.Close() stop = true } @@ -117,23 +112,18 @@ func socketLoop(listener net.Listener) { } func main() { - var asciiDisplay bool - flag.BoolVar(&asciiDisplay, "asciiDisplay", false, "Don't use fancy vnc, throw DOOM straightup on my terminal screen") - flag.Parse() - listener, err := net.Listen("unix", "/dockerdoom.socket") if err != nil { log.Fatalf("Could not create socket file") } - if !asciiDisplay { - log.Print("Create virtual display") - startCmd("/usr/bin/Xvfb :99 -ac -screen 0 640x480x24") - time.Sleep(time.Duration(2) * time.Second) - startCmd("x11vnc -geometry 640x480 -forever -usepw -display :99") - log.Print("You can now connect to it with a VNC viewer at port 5900") - } + log.Print("Create virtual display") + startCmd("/usr/bin/Xvfb :99 -ac -screen 0 640x480x24") + time.Sleep(time.Duration(2) * time.Second) + startCmd("x11vnc -geometry 640x480 -forever -usepw -display :99") + log.Print("You can now connect to it with a VNC viewer at port 5900") + log.Print("Trying to start DOOM ...") - startCmdSilent("/usr/bin/env DISPLAY=:99 /usr/local/games/psdoom -warp -E1M1") + startCmd("/usr/bin/env DISPLAY=:99 /usr/local/games/psdoom -warp -E1M1") socketLoop(listener) } diff --git a/manifest/deployment.yaml b/manifest/deployment.yaml index e403659..4ee3b6a 100644 --- a/manifest/deployment.yaml +++ b/manifest/deployment.yaml @@ -18,7 +18,7 @@ spec: hostNetwork: true serviceAccountName: kubedoom containers: - - image: kubedoom:0.1.2 + - image: storaxdev/kubedoom:0.1.0 name: kubedoom ports: - containerPort: 5900 diff --git a/manifest/service.yaml b/manifest/service.yaml deleted file mode 100644 index 192cbcf..0000000 --- a/manifest/service.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# apiVersion: v1 -# kind: Service -# metadata: -# labels: -# app: kubedoom -# name: kubedoom -# namespace: kubedoom -# spec: -# type: NodePort -# ports: -# - name: vnc -# port: 5900 -# targetPort: vnc -# selector: -# app: kubedoom