Skip to content

Commit

Permalink
Merge pull request #94 from snprajwal/add-sk
Browse files Browse the repository at this point in the history
feat: display sockets in process tree
  • Loading branch information
rst0git authored Aug 14, 2023
2 parents a699e2d + 4ff6bb7 commit 3d698f3
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 4 deletions.
28 changes: 24 additions & 4 deletions checkpointctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ var (
psTreeCmd bool
psTreeEnv bool
files bool
sockets bool
showAll bool
)

Expand Down Expand Up @@ -127,6 +128,12 @@ func setupInspect() *cobra.Command {
false,
"Display the open file descriptors for processes in the container checkpoint",
)
flags.BoolVar(
&sockets,
"sockets",
false,
"Display the open sockets for processes in the container checkpoint",
)
flags.BoolVar(
&showAll,
"all",
Expand All @@ -150,6 +157,7 @@ func inspect(cmd *cobra.Command, args []string) error {
psTreeCmd = true
psTreeEnv = true
files = true
sockets = true
}

requiredFiles := []string{metadata.SpecDumpFile, metadata.ConfigDumpFile}
Expand All @@ -170,12 +178,24 @@ func inspect(cmd *cobra.Command, args []string) error {
psTree = true
requiredFiles = append(
requiredFiles,
// Unpack files.img, fs-*.img, ids-*.img, fdinfo-*.img
filepath.Join(metadata.CheckpointDirectory, "files.img"),
// fs-*.img
filepath.Join(metadata.CheckpointDirectory, "fs-"),
// ids-*.img
filepath.Join(metadata.CheckpointDirectory, "ids-"),
// fdinfo-*.img
filepath.Join(metadata.CheckpointDirectory, "fdinfo-"),
)
}

if sockets {
// Enable displaying process tree, even if it is not passed.
// This is necessary to attach the sockets to the processes
// that opened them and display this in the tree.
psTree = true
requiredFiles = append(
requiredFiles,
// Unpack files.img, ids-*.img, fdinfo-*.img
filepath.Join(metadata.CheckpointDirectory, "files.img"),
filepath.Join(metadata.CheckpointDirectory, "ids-"),
filepath.Join(metadata.CheckpointDirectory, "fdinfo-"),
)
}
Expand All @@ -195,8 +215,8 @@ func inspect(cmd *cobra.Command, args []string) error {
if psTree {
requiredFiles = append(
requiredFiles,
// Unpack pstree.img, core-*.img
filepath.Join(metadata.CheckpointDirectory, "pstree.img"),
// core-*.img
filepath.Join(metadata.CheckpointDirectory, "core-"),
)
}
Expand Down
26 changes: 26 additions & 0 deletions test/checkpointctl.bats
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,32 @@ function teardown() {
[[ ${lines[0]} == *"failed to get file descriptors"* ]]
}

@test "Run checkpointctl inspect with tar file and --sockets" {
cp data/config.dump \
data/spec.dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
cp test-imgs/pstree.img \
test-imgs/core-*.img \
test-imgs/files.img \
test-imgs/ids-*.img \
test-imgs/fdinfo-*.img "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl inspect "$TEST_TMP_DIR2"/test.tar --sockets
[ "$status" -eq 0 ]
}

@test "Run checkpointctl inspect with tar file and --sockets and missing files.img" {
cp data/config.dump \
data/spec.dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
cp test-imgs/pstree.img \
test-imgs/core-*.img "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl inspect "$TEST_TMP_DIR2"/test.tar --sockets
[ "$status" -eq 1 ]
[[ ${lines[0]} == *"failed to get sockets"* ]]
}

@test "Run checkpointctl inspect with tar file and --ps-tree and valid PID" {
cp data/config.dump \
data/spec.dump "$TEST_TMP_DIR1"
Expand Down
58 changes: 58 additions & 0 deletions tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ func renderTreeView(tasks []task) error {
addFdsToTree(tree, fds)
}

if sockets {
c := crit.New(nil, nil, filepath.Join(task.outputDir, "checkpoint"), false, false)
fds, err := c.ExploreSk()
if err != nil {
return fmt.Errorf("failed to get sockets: %w", err)
}

addSkToTree(tree, fds)
}

if mounts {
addMountsToTree(tree, info.specDump)
}
Expand Down Expand Up @@ -181,6 +191,54 @@ func addFdsToTree(tree treeprint.Tree, fds []*crit.Fd) {
}
}

func addSkToTree(tree treeprint.Tree, sks []*crit.Sk) {
var node treeprint.Tree
for _, sk := range sks {
node = tree.FindByMeta(sk.PId)
// If FindByMeta returns nil, then the node with
// the PID has been pruned while building the tree.
// Hence, skip all associated sockets.
if node == nil {
continue
}

nodeSubtree := node.AddBranch("Open sockets")
var data string
var protocol string
for _, socket := range sk.Sockets {
protocol = socket.Protocol
switch socket.FdType {
case "UNIXSK":
// UNIX sockets do not have a protocol assigned.
// Hence, the meta value for the socket is just
// the socket type.
protocol = fmt.Sprintf("UNIX (%s)", socket.Type)
data = socket.SrcAddr
if len(data) == 0 {
// Use an abstract socket address
data = "@"
}
case "INETSK":
if protocol == "TCP" {
protocol = fmt.Sprintf("%s (%s)", socket.Protocol, socket.State)
}
data = fmt.Sprintf(
"%s:%d -> %s:%d (↑ %s ↓ %s)",
socket.SrcAddr, socket.SrcPort,
socket.DestAddr, socket.DestPort,
socket.SendBuf, socket.RecvBuf,
)
case "PACKETSK":
data = fmt.Sprintf("↑ %s ↓ %s", socket.SendBuf, socket.RecvBuf)
case "NETLINKSK":
data = fmt.Sprintf("↑ %s ↓ %s", socket.SendBuf, socket.RecvBuf)
}

nodeSubtree.AddMetaBranch(protocol, data)
}
}
}

// Recursively updates the Comm field of the psTree struct with the command line arguments
// from process memory pages
func updatePsTreeCommToCmdline(checkpointOutputDir string, psTree *crit.PsTree) error {
Expand Down

0 comments on commit 3d698f3

Please sign in to comment.