Skip to content

Commit

Permalink
Run blackhole command in a separate pod with hostnetwork
Browse files Browse the repository at this point in the history
Signed-off-by: Marc Sluiter <[email protected]>
  • Loading branch information
slintes committed Jul 3, 2024
1 parent 005f193 commit 3033614
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 120 deletions.
16 changes: 5 additions & 11 deletions e2e/self_node_remediation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,22 +391,18 @@ func createSNR(node *v1.Node, remediationStrategy v1alpha1.RemediationStrategyTy
}

func getBootTime(node *v1.Node) (*time.Time, error) {
bootTimeCommand := []string{"uptime", "-s"}
var bootTime time.Time
var bootTime *time.Time
EventuallyWithOffset(1, func() error {
ctx, cancel := context.WithTimeout(context.Background(), nodeExecTimeout)
defer cancel()
bootTimeString, err := utils.ExecCommandOnNode(k8sClient, bootTimeCommand, node, ctx)
if err != nil {
return err
}
bootTime, err = time.Parse("2006-01-02 15:04:05", bootTimeString)
var err error
bootTime, err = utils.GetBootTime(ctx, k8sClientSet, node.GetName(), testNamespace)
if err != nil {
return err
}
return nil
}, 15*time.Minute, 10*time.Second).ShouldNot(HaveOccurred(), "Could not get boot time on target node")
return &bootTime, nil
return bootTime, nil
}

func checkNoExecuteTaintRemoved(node *v1.Node) {
Expand Down Expand Up @@ -464,8 +460,6 @@ func killApiConnection(node *v1.Node, apiIPs []string, withReconnect bool) {
script += composeScript(reconnectCommand, apiIPs)
}

command := []string{"/bin/bash", "-c", script}

var ctx context.Context
var cancel context.CancelFunc
if withReconnect {
Expand All @@ -474,7 +468,7 @@ func killApiConnection(node *v1.Node, apiIPs []string, withReconnect bool) {
ctx, cancel = context.WithTimeout(context.Background(), nodeExecTimeout)
}
defer cancel()
_, err := utils.ExecCommandOnNode(k8sClient, command, node, ctx)
_, err := utils.RunCommandInCluster(ctx, k8sClientSet, node.GetName(), testNamespace, script)

if withReconnect {
//in case the sleep didn't work
Expand Down
174 changes: 174 additions & 0 deletions e2e/utils/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package utils

import (
"bytes"
"context"
"fmt"
"os"
ctrl "sigs.k8s.io/controller-runtime"
"strings"
"time"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/tools/remotecommand"
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client/config"
)

var (
log = ctrl.Log.WithName("testutils")
)

// GetBootTime gets the boot time of the given node by running a pod on it executing uptime command
func GetBootTime(ctx context.Context, c *kubernetes.Clientset, nodeName string, ns string) (*time.Time, error) {
output, err := RunCommandInCluster(ctx, c, nodeName, ns, "microdnf install procps -y >/dev/null 2>&1 && uptime -s")
if err != nil {
return nil, err
}

bootTime, err := time.Parse("2006-01-02 15:04:05", output)
if err != nil {
return nil, err
}

return &bootTime, nil
}

// RunCommandInCluster runs a command in a pod in the cluster and returns the output
func RunCommandInCluster(ctx context.Context, c *kubernetes.Clientset, nodeName string, ns string, command string) (string, error) {

// create a pod and wait that it's running
pod := getPod(nodeName)
pod, err := c.CoreV1().Pods(ns).Create(ctx, pod, metav1.CreateOptions{})
if err != nil {
return "", err
}

err = waitForCondition(c, pod, corev1.PodReady, corev1.ConditionTrue, time.Minute)
if err != nil {
return "", err
}

log.Info("helper pod is running, going to execute command")
cmd := []string{"sh", "-c", command}
bytes, err := waitForPodOutput(c, pod, cmd)
if err != nil {
return "", err
}
return strings.TrimSpace(string(bytes)), nil
}

func waitForPodOutput(c *kubernetes.Clientset, pod *corev1.Pod, command []string) ([]byte, error) {
var out []byte
if err := wait.PollImmediate(15*time.Second, time.Minute, func() (done bool, err error) {
out, err = execCommandOnPod(c, pod, command)
if err != nil {
return false, err
}

return len(out) != 0, nil
}); err != nil {
return nil, err
}

return out, nil
}

// execCommandOnPod runs command in the pod and returns buffer output
func execCommandOnPod(c *kubernetes.Clientset, pod *corev1.Pod, command []string) ([]byte, error) {
var outputBuf bytes.Buffer
var errorBuf bytes.Buffer

req := c.CoreV1().RESTClient().
Post().
Namespace(pod.Namespace).
Resource("pods").
Name(pod.Name).
SubResource("exec").
VersionedParams(&corev1.PodExecOptions{
Container: pod.Spec.Containers[0].Name,
Command: command,
Stdin: true,
Stdout: true,
Stderr: true,
TTY: true,
}, scheme.ParameterCodec)

cfg, err := config.GetConfig()
if err != nil {
return nil, err
}

exec, err := remotecommand.NewSPDYExecutor(cfg, "POST", req.URL())
if err != nil {
return nil, err
}

err = exec.Stream(remotecommand.StreamOptions{
Stdin: os.Stdin,
Stdout: &outputBuf,
Stderr: &errorBuf,
Tty: true,
})
if err != nil {
return nil, fmt.Errorf("failed to run command %v: error: %v, outputStream %s; errorStream %s", command, err, outputBuf.String(), errorBuf.String())
}

if errorBuf.Len() != 0 {
return nil, fmt.Errorf("failed to run command %v: output %s; error %s", command, outputBuf.String(), errorBuf.String())
}

return outputBuf.Bytes(), nil
}

// waitForCondition waits until the pod will have specified condition type with the expected status
func waitForCondition(c *kubernetes.Clientset, pod *corev1.Pod, conditionType corev1.PodConditionType, conditionStatus corev1.ConditionStatus, timeout time.Duration) error {
return wait.PollImmediate(time.Second, timeout, func() (bool, error) {
updatedPod := &corev1.Pod{}
var err error
if updatedPod, err = c.CoreV1().Pods(pod.Namespace).Get(context.TODO(), pod.Name, metav1.GetOptions{}); err != nil {
return false, nil
}
for _, c := range updatedPod.Status.Conditions {
if c.Type == conditionType && c.Status == conditionStatus {
return true, nil
}
}
return false, nil
})
}

func getPod(nodeName string) *corev1.Pod {
return &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "nhc-test-",
Labels: map[string]string{
"test": "",
},
},
Spec: corev1.PodSpec{
NodeName: nodeName,
HostNetwork: true,
HostPID: true,
SecurityContext: &corev1.PodSecurityContext{
RunAsUser: pointer.Int64(0),
RunAsGroup: pointer.Int64(0),
},
RestartPolicy: corev1.RestartPolicyNever,
Containers: []corev1.Container{
{
Name: "test",
Image: "registry.access.redhat.com/ubi8/ubi-minimal",
SecurityContext: &corev1.SecurityContext{
Privileged: pointer.Bool(true),
},
Command: []string{"sleep", "2m"},
},
},
},
}
}
109 changes: 0 additions & 109 deletions e2e/utils/node.go

This file was deleted.

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ require (
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
github.com/mitchellh/copystructure v1.1.2 // indirect
github.com/mitchellh/reflectwalk v1.0.1 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
Expand Down
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
Expand All @@ -65,6 +67,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
Expand Down Expand Up @@ -177,6 +181,7 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
Expand Down Expand Up @@ -222,6 +227,8 @@ github.com/mitchellh/copystructure v1.1.2 h1:Th2TIvG1+6ma3e/0/bopBKohOTY7s4dA8V2
github.com/mitchellh/copystructure v1.1.2/go.mod h1:EBArHfARyrSWO/+Wyr9zwEkc6XMFB9XyNgFNmRkZZU4=
github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE=
github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand Down

0 comments on commit 3033614

Please sign in to comment.