Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dns-chaos): Adding containerd support for dns-chaos #577

Merged
merged 1 commit into from
Oct 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion chaoslib/litmus/http-chaos/helper/http-helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func prepareK8sHttpChaos(experimentsDetails *experimentTypes.ExperimentDetails,
return err
}
// extract out the pid of the target container
targetPID, err := common.GetPID(experimentsDetails.ContainerRuntime, containerID, experimentsDetails.SocketPath)
targetPID, err := common.GetPauseAndSandboxPID(experimentsDetails.ContainerRuntime, containerID, experimentsDetails.SocketPath)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion chaoslib/litmus/network-chaos/helper/netem.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func preparePodNetworkChaos(experimentsDetails *experimentTypes.ExperimentDetail
return err
}
// extract out the pid of the target container
targetPID, err := common.GetPID(experimentsDetails.ContainerRuntime, containerID, experimentsDetails.SocketPath)
targetPID, err := common.GetPauseAndSandboxPID(experimentsDetails.ContainerRuntime, containerID, experimentsDetails.SocketPath)
if err != nil {
return err
}
Expand Down
3 changes: 2 additions & 1 deletion chaoslib/litmus/pod-dns-chaos/helper/dnschaos.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,11 @@ func Helper(clients clients.ClientSets) {
//preparePodDNSChaos contains the preparation steps before chaos injection
func preparePodDNSChaos(experimentsDetails *experimentTypes.ExperimentDetails, clients clients.ClientSets, eventsDetails *types.EventDetails, chaosDetails *types.ChaosDetails, resultDetails *types.ResultDetails) error {

containerID, err := common.GetRuntimeBasedContainerID(experimentsDetails.ContainerRuntime, experimentsDetails.SocketPath, experimentsDetails.TargetPods, experimentsDetails.AppNS, experimentsDetails.TargetContainer, clients)
containerID, err := common.GetContainerID(experimentsDetails.AppNS, experimentsDetails.TargetPods, experimentsDetails.TargetContainer, clients)
if err != nil {
return err
}

// extract out the pid of the target container
pid, err := common.GetPID(experimentsDetails.ContainerRuntime, containerID, experimentsDetails.SocketPath)
if err != nil {
Expand Down
89 changes: 1 addition & 88 deletions chaoslib/litmus/stress-chaos/helper/stress-helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package helper
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"io"
"os"
Expand Down Expand Up @@ -99,7 +98,7 @@ func prepareStressChaos(experimentsDetails *experimentTypes.ExperimentDetails, c
return err
}
// extract out the pid of the target container
targetPID, err := getPID(experimentsDetails, containerID)
targetPID, err := common.GetPID(experimentsDetails.ContainerRuntime, containerID, experimentsDetails.SocketPath)
if err != nil {
return err
}
Expand Down Expand Up @@ -287,51 +286,6 @@ func prepareStressor(experimentDetails *experimentTypes.ExperimentDetails) []str
return stressArgs
}

//getPID extract out the PID of the target container
func getPID(experimentDetails *experimentTypes.ExperimentDetails, containerID string) (int, error) {
var PID int

switch experimentDetails.ContainerRuntime {
case "docker":
host := "unix://" + experimentDetails.SocketPath
// deriving pid from the inspect out of target container
out, err := exec.Command("sudo", "docker", "--host", host, "inspect", containerID).CombinedOutput()
if err != nil {
log.Error(fmt.Sprintf("[docker]: Failed to run docker inspect: %s", string(out)))
return 0, err
}

// parsing data from the json output of inspect command
PID, err = parsePIDFromJSON(out, experimentDetails.ContainerRuntime)
if err != nil {
log.Error(fmt.Sprintf("[docker]: Failed to parse json from docker inspect output: %s", string(out)))
return 0, err
}

case "containerd", "crio":
// deriving pid from the inspect out of target container
endpoint := "unix://" + experimentDetails.SocketPath
out, err := exec.Command("sudo", "crictl", "-i", endpoint, "-r", endpoint, "inspect", containerID).CombinedOutput()
if err != nil {
log.Error(fmt.Sprintf("[cri]: Failed to run crictl: %s", string(out)))
return 0, err
}

// parsing data from the json output of inspect command
PID, err = parsePIDFromJSON(out, experimentDetails.ContainerRuntime)
if err != nil {
log.Errorf(fmt.Sprintf("[cri]: Failed to parse json from crictl output: %s", string(out)))
return 0, err
}
default:
return 0, errors.Errorf("%v container runtime not suported", experimentDetails.ContainerRuntime)
}

log.Info(fmt.Sprintf("[Info]: Container ID=%s has process PID=%d", containerID, PID))

return PID, nil
}

//pidPath will get the pid path of the container
func pidPath(pid int) cgroups.Path {
processPath := "/proc/" + strconv.Itoa(pid) + "/cgroup"
Expand Down Expand Up @@ -454,47 +408,6 @@ func findValidCgroup(path cgroups.Path, target string) (string, error) {
return "", errors.Errorf("never found valid cgroup for %s", target)
}

//parsePIDFromJSON extract the pid from the json output
func parsePIDFromJSON(j []byte, runtime string) (int, error) {
var pid int
switch runtime {
case "docker":
// in docker, pid is present inside state.pid attribute of inspect output
var resp []common.DockerInspectResponse
if err := json.Unmarshal(j, &resp); err != nil {
return 0, err
}
pid = resp[0].State.PID
case "containerd":
var resp common.CrictlInspectResponse
if err := json.Unmarshal(j, &resp); err != nil {
return 0, err
}
pid = resp.Info.PID

case "crio":
var info common.InfoDetails
if err := json.Unmarshal(j, &info); err != nil {
return 0, err
}
pid = info.PID
if pid == 0 {
var resp common.CrictlInspectResponse
if err := json.Unmarshal(j, &resp); err != nil {
return 0, err
}
pid = resp.Info.PID
}
default:
return 0, errors.Errorf("[cri]: No supported container runtime, runtime: %v", runtime)
}
if pid == 0 {
return 0, errors.Errorf("[cri]: No running target container found, pid: %d", pid)
}

return pid, nil
}

//getENV fetches all the env variables from the runner pod
func getENV(experimentDetails *experimentTypes.ExperimentDetails) {
experimentDetails.ExperimentName = types.Getenv("EXPERIMENT_NAME", "")
Expand Down
160 changes: 92 additions & 68 deletions pkg/utils/common/pid.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,91 +50,115 @@ type StateDetails struct {
PID int `json:"pid"`
}

//GetPID extract out the PID of the target container
func GetPID(runtime, containerID, socketPath string) (int, error) {
var PID int
func getDockerPID(containerID, socketPath string) (int, error) {
host := "unix://" + socketPath
// deriving pid from the inspect out of target container
out, err := exec.Command("sudo", "docker", "--host", host, "inspect", containerID).CombinedOutput()
if err != nil {
log.Error(fmt.Sprintf("[docker]: Failed to run docker inspect: %s", string(out)))
return 0, err
}
// in docker, pid is present inside state.pid attribute of inspect output
var resp []DockerInspectResponse
if err := json.Unmarshal(out, &resp); err != nil {
return 0, err
}
pid := resp[0].State.PID
return pid, nil
}

switch runtime {
case "docker":
host := "unix://" + socketPath
// deriving pid from the inspect out of target container
out, err := exec.Command("sudo", "docker", "--host", host, "inspect", containerID).CombinedOutput()
if err != nil {
log.Error(fmt.Sprintf("[docker]: Failed to run docker inspect: %s", string(out)))
return 0, err
}
// parsing data from the json output of inspect command
PID, err = parsePIDFromJSON(out, runtime)
if err != nil {
log.Error(fmt.Sprintf("[docker]: Failed to parse json from docker inspect output: %s", string(out)))
return 0, err
}
case "containerd", "crio":
// deriving pid from the inspect out of target container
endpoint := "unix://" + socketPath
out, err := exec.Command("sudo", "crictl", "-i", endpoint, "-r", endpoint, "inspect", containerID).CombinedOutput()
if err != nil {
log.Error(fmt.Sprintf("[cri]: Failed to run crictl: %s", string(out)))
return 0, err
}
// parsing data from the json output of inspect command
PID, err = parsePIDFromJSON(out, runtime)
if err != nil {
log.Errorf(fmt.Sprintf("[cri]: Failed to parse json from crictl output: %s", string(out)))
return 0, err
func getContainerdSandboxPID(containerID, socketPath string) (int, error) {
var pid int
endpoint := "unix://" + socketPath
out, err := exec.Command("sudo", "crictl", "-i", endpoint, "-r", endpoint, "inspect", containerID).CombinedOutput()
if err != nil {
log.Error(fmt.Sprintf("[cri]: Failed to run crictl: %s", string(out)))
return 0, err
}
var resp CrictlInspectResponse
if err := json.Unmarshal(out, &resp); err != nil {
return 0, err
}
for _, namespace := range resp.Info.RuntimeSpec.Linux.Namespaces {
if namespace.Type == "network" {
value := strings.Split(namespace.Path, "/")[2]
pid, _ = strconv.Atoi(value)
}
default:
return 0, errors.Errorf("%v container runtime not suported", runtime)
}
return pid, nil
}

log.Info(fmt.Sprintf("[Info]: Container ID=%s has process PID=%d", containerID, PID))
func getContainerdPID(containerID, socketPath string) (int, error) {
var pid int
endpoint := "unix://" + socketPath
out, err := exec.Command("sudo", "crictl", "-i", endpoint, "-r", endpoint, "inspect", containerID).CombinedOutput()
ispeakc0de marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
log.Error(fmt.Sprintf("[cri]: Failed to run crictl: %s", string(out)))
return 0, err
}
var resp CrictlInspectResponse
if err := json.Unmarshal(out, &resp); err != nil {
return 0, err
}
pid = resp.Info.PID
if pid == 0 {
return 0, errors.Errorf("[cri]: No running target container found, pid: %d", pid)
}
return pid, nil
}

return PID, nil
func getCRIOPID(containerID, socketPath string) (int, error) {
var pid int
endpoint := "unix://" + socketPath
out, err := exec.Command("sudo", "crictl", "-i", endpoint, "-r", endpoint, "inspect", containerID).CombinedOutput()
if err != nil {
log.Error(fmt.Sprintf("[cri]: Failed to run crictl: %s", string(out)))
return 0, err
}
var info InfoDetails
if err := json.Unmarshal(out, &info); err != nil {
return 0, err
}
pid = info.PID
if pid == 0 {
var resp CrictlInspectResponse
if err := json.Unmarshal(out, &resp); err != nil {
return 0, err
}
pid = resp.Info.PID
}
return pid, nil
}

//parsePIDFromJSON extract the pid from the json output
func parsePIDFromJSON(j []byte, runtime string) (int, error) {
//GetPauseAndSandboxPID extract out the PID of the target container
func GetPauseAndSandboxPID(runtime, containerID, socketPath string) (int, error) {
var pid int
// namespaces are present inside `info.runtimeSpec.linux.namespaces` of inspect output
// linux namespace of type network contains pid, in the form of `/proc/<pid>/ns/net`

switch runtime {
case "docker":
// in docker, pid is present inside state.pid attribute of inspect output
var resp []DockerInspectResponse
if err := json.Unmarshal(j, &resp); err != nil {
return 0, err
}
pid = resp[0].State.PID
pid, err = getDockerPID(containerID, socketPath)
case "containerd":
var resp CrictlInspectResponse
if err := json.Unmarshal(j, &resp); err != nil {
return 0, err
}
for _, namespace := range resp.Info.RuntimeSpec.Linux.Namespaces {
if namespace.Type == "network" {
value := strings.Split(namespace.Path, "/")[2]
pid, _ = strconv.Atoi(value)
}
}
pid, err = getContainerdSandboxPID(containerID, socketPath)
case "crio":
var info InfoDetails
if err := json.Unmarshal(j, &info); err != nil {
return 0, err
}
pid = info.PID
if pid == 0 {
var resp CrictlInspectResponse
if err := json.Unmarshal(j, &resp); err != nil {
return 0, err
}
pid = resp.Info.PID
}
pid, err = getCRIOPID(containerID, socketPath)
default:
return 0, errors.Errorf("[cri]: unsupported container runtime, runtime: %v", runtime)
return 0, errors.Errorf("%v container runtime not suported", runtime)
}
if err != nil {
return 0, err
}

if pid == 0 {
return 0, errors.Errorf("[cri]: No running target container found, pid: %d", pid)
}

log.Info(fmt.Sprintf("[Info]: Container ID=%s has process PID=%d", containerID, pid))
return pid, nil
}

func GetPID(runtime, containerID, socketPath string) (int, error) {
if runtime == "containerd" {
return getContainerdPID(containerID, socketPath)
}
return GetPauseAndSandboxPID(runtime, containerID, socketPath)
}