feat: netstat pod support
talosctl netstat -k show all host and non-hostnetwork pods sockets/connections. talosctl netstat namespace/pod shows sockets/connections of a specific pod + autocompletes in the shell. Signed-off-by: Nico Berlee <nico.berlee@on2it.net> Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
This commit is contained in:
parent
52e857f55e
commit
0af8fe2fb5
@ -608,6 +608,7 @@ message ContainerInfo {
|
||||
string status = 5;
|
||||
string pod_id = 6;
|
||||
string name = 7;
|
||||
string network_namespace = 8;
|
||||
}
|
||||
|
||||
// The messages message containing the requested containers.
|
||||
@ -1223,6 +1224,12 @@ message NetstatRequest {
|
||||
bool raw6 = 8;
|
||||
}
|
||||
L4proto l4proto = 3;
|
||||
message NetNS {
|
||||
bool hostnetwork = 1;
|
||||
repeated string netns = 2;
|
||||
bool allnetns = 3;
|
||||
}
|
||||
NetNS netns = 4;
|
||||
}
|
||||
|
||||
message ConnectRecord {
|
||||
@ -1268,6 +1275,7 @@ message ConnectRecord {
|
||||
string name = 2;
|
||||
}
|
||||
Process process = 17;
|
||||
string netns = 18;
|
||||
}
|
||||
|
||||
message Netstat {
|
||||
|
@ -12,9 +12,11 @@ import (
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
criconstants "github.com/containerd/containerd/pkg/cri/constants"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/siderolabs/talos/pkg/cli"
|
||||
"github.com/siderolabs/talos/pkg/machinery/api/common"
|
||||
"github.com/siderolabs/talos/pkg/machinery/api/machine"
|
||||
"github.com/siderolabs/talos/pkg/machinery/client"
|
||||
)
|
||||
@ -26,6 +28,7 @@ var netstatCmdFlags struct {
|
||||
timers bool
|
||||
listening bool
|
||||
all bool
|
||||
pods bool
|
||||
tcp bool
|
||||
udp bool
|
||||
udplite bool
|
||||
@ -34,26 +37,102 @@ var netstatCmdFlags struct {
|
||||
ipv6 bool
|
||||
}
|
||||
|
||||
// netstatCmd represents the ls command.
|
||||
type netstat struct {
|
||||
client *client.Client
|
||||
NodeNetNSPods map[string]map[string]string
|
||||
}
|
||||
|
||||
// netstatCmd represents the netstat command.
|
||||
var netstatCmd = &cobra.Command{
|
||||
Use: "netstat",
|
||||
Aliases: []string{"ss"},
|
||||
Short: "Retrieve a socket listing of connections",
|
||||
Long: ``,
|
||||
Args: cobra.NoArgs,
|
||||
Short: "Show network connections and sockets",
|
||||
Long: `Show network connections and sockets.
|
||||
|
||||
You can pass an optional argument to view a specific pod's connections.
|
||||
To do this, format the argument as "namespace/pod".
|
||||
Note that only pods with a pod network namespace are allowed.
|
||||
If you don't pass an argument, the command will show host connections.`,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
if len(args) > 0 {
|
||||
return nil, cobra.ShellCompDirectiveError | cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
var podList []string
|
||||
|
||||
if WithClient(func(ctx context.Context, c *client.Client) error {
|
||||
n := netstat{
|
||||
NodeNetNSPods: make(map[string]map[string]string),
|
||||
client: c,
|
||||
}
|
||||
|
||||
err := n.getPodNetNsFromNode(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, netNsPods := range n.NodeNetNSPods {
|
||||
for _, podName := range netNsPods {
|
||||
podList = append(podList, podName)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}) != nil {
|
||||
return nil, cobra.ShellCompDirectiveError | cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
return podList, cobra.ShellCompDirectiveNoFileComp
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return WithClient(func(ctx context.Context, c *client.Client) error {
|
||||
req := netstatFlagsToRequest()
|
||||
req := netstatFlagsToRequest()
|
||||
|
||||
return WithClient(func(ctx context.Context, c *client.Client) (err error) {
|
||||
if netstatCmdFlags.pods && len(args) > 0 {
|
||||
return fmt.Errorf("cannot use --pods and specify a pod")
|
||||
}
|
||||
|
||||
findThePod := len(args) > 0
|
||||
|
||||
n := netstat{
|
||||
client: c,
|
||||
}
|
||||
|
||||
n.NodeNetNSPods = make(map[string]map[string]string)
|
||||
|
||||
if findThePod || netstatCmdFlags.pods {
|
||||
err = n.getPodNetNsFromNode(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if findThePod {
|
||||
var foundNode, foundNetNs string
|
||||
|
||||
foundNode, foundNetNs = n.findPodNetNs(args[0])
|
||||
|
||||
if foundNetNs == "" {
|
||||
cli.Fatalf("pod %s not found", args[0])
|
||||
}
|
||||
|
||||
ctx = client.WithNode(ctx, foundNode)
|
||||
|
||||
req.Netns.Netns = []string{foundNetNs}
|
||||
req.Netns.Hostnetwork = false
|
||||
}
|
||||
|
||||
response, err := c.Netstat(ctx, req)
|
||||
if err != nil {
|
||||
if response == nil {
|
||||
return fmt.Errorf("error getting netstat: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
cli.Warning("%s", err)
|
||||
}
|
||||
|
||||
err = printNetstat(response)
|
||||
err = n.printNetstat(response)
|
||||
|
||||
return err
|
||||
})
|
||||
@ -76,6 +155,10 @@ func netstatFlagsToRequest() *machine.NetstatRequest {
|
||||
Raw: netstatCmdFlags.raw,
|
||||
Raw6: netstatCmdFlags.raw,
|
||||
},
|
||||
Netns: &machine.NetstatRequest_NetNS{
|
||||
Allnetns: netstatCmdFlags.pods,
|
||||
Hostnetwork: true,
|
||||
},
|
||||
}
|
||||
|
||||
switch {
|
||||
@ -122,37 +205,61 @@ func netstatFlagsToRequest() *machine.NetstatRequest {
|
||||
return &req
|
||||
}
|
||||
|
||||
func (n *netstat) getPodNetNsFromNode(ctx context.Context) (err error) {
|
||||
resp, err := n.client.Containers(ctx, criconstants.K8sContainerdNamespace, common.ContainerDriver_CRI)
|
||||
if err != nil {
|
||||
cli.Warning("error getting containers: %v", err)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
for _, msg := range resp.Messages {
|
||||
for _, p := range msg.Containers {
|
||||
if p.NetworkNamespace == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if p.Pid == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if p.Id != p.PodId {
|
||||
continue
|
||||
}
|
||||
|
||||
if n.NodeNetNSPods[msg.Metadata.Hostname] == nil {
|
||||
n.NodeNetNSPods[msg.Metadata.Hostname] = make(map[string]string)
|
||||
}
|
||||
|
||||
n.NodeNetNSPods[msg.Metadata.Hostname][p.NetworkNamespace] = p.Id
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *netstat) findPodNetNs(findNamespaceAndPod string) (string, string) {
|
||||
var foundNetNs, foundNode string
|
||||
|
||||
for node, netNSPods := range n.NodeNetNSPods {
|
||||
for NetNs, podName := range netNSPods {
|
||||
if podName == strings.ToLower(findNamespaceAndPod) {
|
||||
foundNetNs = NetNs
|
||||
foundNode = node
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return foundNode, foundNetNs
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func printNetstat(response *machine.NetstatResponse) error {
|
||||
func (n *netstat) printNetstat(response *machine.NetstatResponse) error {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
|
||||
node := ""
|
||||
|
||||
labels := strings.Join(
|
||||
[]string{
|
||||
"Proto",
|
||||
"Recv-Q",
|
||||
"Send-Q",
|
||||
"Local Address",
|
||||
"Foreign Address",
|
||||
"State",
|
||||
}, "\t")
|
||||
|
||||
if netstatCmdFlags.extend {
|
||||
labels += "\t" + strings.Join(
|
||||
[]string{
|
||||
"Uid",
|
||||
"Inode",
|
||||
}, "\t")
|
||||
}
|
||||
|
||||
if netstatCmdFlags.pid {
|
||||
labels += "\t" + "PID/Program name"
|
||||
}
|
||||
|
||||
if netstatCmdFlags.timers {
|
||||
labels += "\t" + "Timer"
|
||||
}
|
||||
|
||||
for i, message := range response.Messages {
|
||||
if message.Metadata != nil && message.Metadata.Hostname != "" {
|
||||
node = message.Metadata.Hostname
|
||||
@ -164,6 +271,8 @@ func printNetstat(response *machine.NetstatResponse) error {
|
||||
|
||||
for j, record := range message.Connectrecord {
|
||||
if i == 0 && j == 0 {
|
||||
labels := netstatSummaryLabels()
|
||||
|
||||
if node != "" {
|
||||
fmt.Fprintln(w, "NODE\t"+labels)
|
||||
} else {
|
||||
@ -210,6 +319,18 @@ func printNetstat(response *machine.NetstatResponse) error {
|
||||
}
|
||||
}
|
||||
|
||||
if netstatCmdFlags.pods {
|
||||
if record.Netns == "" || node == "" || n.NodeNetNSPods[node] == nil {
|
||||
args = append(args, []interface{}{
|
||||
"-",
|
||||
}...)
|
||||
} else {
|
||||
args = append(args, []interface{}{
|
||||
n.NodeNetNSPods[node][record.Netns],
|
||||
}...)
|
||||
}
|
||||
}
|
||||
|
||||
if netstatCmdFlags.timers {
|
||||
timerwhen := strconv.FormatFloat(float64(record.Timerwhen)/100, 'f', 2, 64)
|
||||
|
||||
@ -228,6 +349,40 @@ func printNetstat(response *machine.NetstatResponse) error {
|
||||
return w.Flush()
|
||||
}
|
||||
|
||||
func netstatSummaryLabels() (labels string) {
|
||||
labels = strings.Join(
|
||||
[]string{
|
||||
"Proto",
|
||||
"Recv-Q",
|
||||
"Send-Q",
|
||||
"Local Address",
|
||||
"Foreign Address",
|
||||
"State",
|
||||
}, "\t")
|
||||
|
||||
if netstatCmdFlags.extend {
|
||||
labels += "\t" + strings.Join(
|
||||
[]string{
|
||||
"Uid",
|
||||
"Inode",
|
||||
}, "\t")
|
||||
}
|
||||
|
||||
if netstatCmdFlags.pid {
|
||||
labels += "\t" + "PID/Program name"
|
||||
}
|
||||
|
||||
if netstatCmdFlags.pods {
|
||||
labels += "\t" + "Pod"
|
||||
}
|
||||
|
||||
if netstatCmdFlags.timers {
|
||||
labels += "\t" + "Timer"
|
||||
}
|
||||
|
||||
return labels
|
||||
}
|
||||
|
||||
func wildcardIfZero(num uint32) string {
|
||||
if num == 0 {
|
||||
return "*"
|
||||
@ -244,12 +399,13 @@ func init() {
|
||||
netstatCmd.Flags().BoolVarP(&netstatCmdFlags.timers, "timers", "o", false, "display timers")
|
||||
netstatCmd.Flags().BoolVarP(&netstatCmdFlags.listening, "listening", "l", false, "display listening server sockets")
|
||||
netstatCmd.Flags().BoolVarP(&netstatCmdFlags.all, "all", "a", false, "display all sockets states (default: connected)")
|
||||
netstatCmd.Flags().BoolVarP(&netstatCmdFlags.pods, "pods", "k", false, "show sockets used by Kubernetes pods")
|
||||
netstatCmd.Flags().BoolVarP(&netstatCmdFlags.tcp, "tcp", "t", false, "display only TCP sockets")
|
||||
netstatCmd.Flags().BoolVarP(&netstatCmdFlags.udp, "udp", "u", false, "display only UDP sockets")
|
||||
netstatCmd.Flags().BoolVarP(&netstatCmdFlags.udplite, "udplite", "U", false, "display only UDPLite sockets")
|
||||
netstatCmd.Flags().BoolVarP(&netstatCmdFlags.raw, "raw", "w", false, "display only RAW sockets")
|
||||
netstatCmd.Flags().BoolVarP(&netstatCmdFlags.ipv4, "ipv4", "4", false, "display only ipv4 sockets")
|
||||
netstatCmd.Flags().BoolVarP(&netstatCmdFlags.ipv4, "ipv6", "6", false, "display only ipv6 sockets")
|
||||
netstatCmd.Flags().BoolVarP(&netstatCmdFlags.ipv6, "ipv6", "6", false, "display only ipv6 sockets")
|
||||
|
||||
addCommand(netstatCmd)
|
||||
}
|
||||
|
2
go.mod
2
go.mod
@ -75,7 +75,7 @@ require (
|
||||
github.com/mdlayher/genetlink v1.3.1
|
||||
github.com/mdlayher/netlink v1.7.1
|
||||
github.com/mdlayher/netx v0.0.0-20220422152302-c711c2f8512f
|
||||
github.com/nberlee/go-netstat v0.0.0-20230319161348-19cc338ee40a
|
||||
github.com/nberlee/go-netstat v0.1.1
|
||||
github.com/opencontainers/image-spec v1.1.0-rc2
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
|
||||
github.com/packethost/packngo v0.29.0
|
||||
|
4
go.sum
4
go.sum
@ -975,8 +975,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/nberlee/go-netstat v0.0.0-20230319161348-19cc338ee40a h1:1p1sNvJOlkfWnZ01BuPF+SVHaVe/VXlMxLgnGTgPH+I=
|
||||
github.com/nberlee/go-netstat v0.0.0-20230319161348-19cc338ee40a/go.mod h1:GvDCRLsUKMRN1wULkt7tpnDmjSIE6YGf5zeVq+mBO64=
|
||||
github.com/nberlee/go-netstat v0.1.1 h1:8QlXkUT8pr5wJKVRgn2186+lPxbum0BkuEwbSOtHrSE=
|
||||
github.com/nberlee/go-netstat v0.1.1/go.mod h1:GvDCRLsUKMRN1wULkt7tpnDmjSIE6YGf5zeVq+mBO64=
|
||||
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840=
|
||||
|
@ -129,7 +129,7 @@ This allows to distinguish between containers with the same name.
|
||||
[notes.netstat]
|
||||
title = "talosctl netstat"
|
||||
description="""\
|
||||
Talos API was extended to support retrieving a list of network connections (sockets) from the node.
|
||||
Talos API was extended to support retrieving a list of network connections (sockets) from the node and pods.
|
||||
`talosctl netstat` command was added to retrieve the list of network connections.
|
||||
"""
|
||||
|
||||
|
@ -1438,13 +1438,14 @@ func (s *Server) Containers(ctx context.Context, in *machine.ContainersRequest)
|
||||
for _, pod := range pods {
|
||||
for _, container := range pod.Containers {
|
||||
container := &machine.ContainerInfo{
|
||||
Namespace: in.Namespace,
|
||||
Id: container.Display,
|
||||
PodId: pod.Name,
|
||||
Name: container.Name,
|
||||
Image: container.Image,
|
||||
Pid: container.Pid,
|
||||
Status: container.Status,
|
||||
Namespace: in.Namespace,
|
||||
Id: container.Display,
|
||||
PodId: pod.Name,
|
||||
Name: container.Name,
|
||||
Image: container.Image,
|
||||
Pid: container.Pid,
|
||||
Status: container.Status,
|
||||
NetworkNamespace: container.NetworkNamespace,
|
||||
}
|
||||
containers = append(containers, container)
|
||||
}
|
||||
@ -2345,15 +2346,18 @@ func (s *Server) Netstat(ctx context.Context, req *machine.NetstatRequest) (*mac
|
||||
}
|
||||
|
||||
features := netstat.EnableFeatures{
|
||||
TCP: req.L4Proto.Tcp,
|
||||
TCP6: req.L4Proto.Tcp6,
|
||||
UDP: req.L4Proto.Udp,
|
||||
UDP6: req.L4Proto.Udp6,
|
||||
UDPLite: req.L4Proto.Udplite,
|
||||
UDPLite6: req.L4Proto.Udplite6,
|
||||
Raw: req.L4Proto.Raw,
|
||||
Raw6: req.L4Proto.Raw6,
|
||||
PID: req.Feature.Pid,
|
||||
TCP: req.L4Proto.Tcp,
|
||||
TCP6: req.L4Proto.Tcp6,
|
||||
UDP: req.L4Proto.Udp,
|
||||
UDP6: req.L4Proto.Udp6,
|
||||
UDPLite: req.L4Proto.Udplite,
|
||||
UDPLite6: req.L4Proto.Udplite6,
|
||||
Raw: req.L4Proto.Raw,
|
||||
Raw6: req.L4Proto.Raw6,
|
||||
PID: req.Feature.Pid,
|
||||
NoHostNetwork: !req.Netns.Hostnetwork,
|
||||
AllNetNs: req.Netns.Allnetns,
|
||||
NetNsName: req.Netns.Netns,
|
||||
}
|
||||
|
||||
var fn netstat.AcceptFn
|
||||
@ -2363,11 +2367,11 @@ func (s *Server) Netstat(ctx context.Context, req *machine.NetstatRequest) (*mac
|
||||
fn = func(*netstat.SockTabEntry) bool { return true }
|
||||
case machine.NetstatRequest_LISTENING:
|
||||
fn = func(s *netstat.SockTabEntry) bool {
|
||||
return s.State == netstat.Listen
|
||||
return s.RemoteEndpoint.IP.IsUnspecified() && s.RemoteEndpoint.Port == 0
|
||||
}
|
||||
case machine.NetstatRequest_CONNECTED:
|
||||
fn = func(s *netstat.SockTabEntry) bool {
|
||||
return s.State != netstat.Listen
|
||||
return !s.RemoteEndpoint.IP.IsUnspecified() && s.RemoteEndpoint.Port != 0
|
||||
}
|
||||
}
|
||||
|
||||
@ -2397,6 +2401,7 @@ func (s *Server) Netstat(ctx context.Context, req *machine.NetstatRequest) (*mac
|
||||
Ref: entry.Ref,
|
||||
Pointer: entry.Pointer,
|
||||
Process: &machine.ConnectRecord_Process{},
|
||||
Netns: entry.NetNS,
|
||||
}
|
||||
if entry.Process != nil {
|
||||
records[i].Process = &machine.ConnectRecord_Process{
|
||||
|
@ -7,12 +7,14 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/siderolabs/talos/internal/integration/base"
|
||||
)
|
||||
|
||||
// NetstatSuite verifies etcd command.
|
||||
// NetstatSuite verifies etcd command and coredns container.
|
||||
type NetstatSuite struct {
|
||||
base.CLISuite
|
||||
}
|
||||
@ -28,6 +30,14 @@ func (suite *NetstatSuite) TestListening() {
|
||||
base.StdoutShouldMatch(regexp.MustCompile(`:::50000.+LISTEN.+/apid`)))
|
||||
}
|
||||
|
||||
// TestContainers verifies that containers are listed.
|
||||
func (suite *NetstatSuite) TestContainers() {
|
||||
nodes := suite.DiscoverNodeInternalIPs(context.TODO())
|
||||
|
||||
suite.RunCLI([]string{"netstat", "--listening", "--programs", "--udp", "--ipv6", "--pods", "--nodes", strings.Join(nodes, ",")},
|
||||
base.StdoutShouldMatch(regexp.MustCompile(`:::53\s+:::\*.+/coredns\s+kube-system/coredns-`)))
|
||||
}
|
||||
|
||||
func init() {
|
||||
allSuites = append(allSuites, new(NetstatSuite))
|
||||
}
|
||||
|
@ -25,19 +25,20 @@ import (
|
||||
type Container struct {
|
||||
Inspector Inspector
|
||||
|
||||
Display string // Friendly Name
|
||||
Name string // container name
|
||||
ID string // container sha/id
|
||||
Digest string // Container Digest
|
||||
Image string
|
||||
PodName string
|
||||
Sandbox string
|
||||
Status string // Running state of container
|
||||
RestartCount string
|
||||
LogPath string
|
||||
Metrics *ContainerMetrics
|
||||
Pid uint32
|
||||
IsPodSandbox bool // real container or just pod sandbox
|
||||
Display string // Friendly Name
|
||||
Name string // container name
|
||||
ID string // container sha/id
|
||||
Digest string // Container Digest
|
||||
Image string
|
||||
PodName string
|
||||
Sandbox string
|
||||
Status string // Running state of container
|
||||
RestartCount string
|
||||
LogPath string
|
||||
Metrics *ContainerMetrics
|
||||
Pid uint32
|
||||
IsPodSandbox bool // real container or just pod sandbox
|
||||
NetworkNamespace string
|
||||
}
|
||||
|
||||
// ContainerMetrics represents container cgroup stats.
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
@ -184,6 +185,7 @@ func findContainer(cntID string, containers []*runtimeapi.Container) (*runtimeap
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// nolint: gocyclo
|
||||
func (i *inspector) buildPod(sandbox *runtimeapi.PodSandbox) (*ctrs.Pod, error) {
|
||||
sandboxStatus, sandboxInfo, err := i.client.PodSandboxStatus(i.ctx, sandbox.Id)
|
||||
if err != nil {
|
||||
@ -210,7 +212,7 @@ func (i *inspector) buildPod(sandbox *runtimeapi.PodSandbox) (*ctrs.Pod, error)
|
||||
}
|
||||
|
||||
if info, ok := sandboxInfo["info"]; ok {
|
||||
var verboseInfo map[string]interface{}
|
||||
var verboseInfo map[string]any
|
||||
|
||||
if err := json.Unmarshal([]byte(info), &verboseInfo); err == nil {
|
||||
if pid, ok := verboseInfo["pid"]; ok {
|
||||
@ -225,6 +227,22 @@ func (i *inspector) buildPod(sandbox *runtimeapi.PodSandbox) (*ctrs.Pod, error)
|
||||
pod.Containers[0].Digest = digest
|
||||
}
|
||||
}
|
||||
|
||||
if runtimeSpec, ok := verboseInfo["runtimeSpec"].(map[string]any); ok {
|
||||
if linuxSpec, ok := runtimeSpec["linux"].(map[string]any); ok {
|
||||
if namespaces, ok := linuxSpec["namespaces"].([]any); ok {
|
||||
for _, n := range namespaces {
|
||||
if nt, ok := n.(map[string]any); ok && nt["type"] == "network" {
|
||||
if netnsPath, ok := nt["path"].(string); ok {
|
||||
pod.Containers[0].NetworkNamespace = path.Base(netnsPath)
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3749,6 +3749,13 @@ func (m *ContainerInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if len(m.NetworkNamespace) > 0 {
|
||||
i -= len(m.NetworkNamespace)
|
||||
copy(dAtA[i:], m.NetworkNamespace)
|
||||
i = encodeVarint(dAtA, i, uint64(len(m.NetworkNamespace)))
|
||||
i--
|
||||
dAtA[i] = 0x42
|
||||
}
|
||||
if len(m.Name) > 0 {
|
||||
i -= len(m.Name)
|
||||
copy(dAtA[i:], m.Name)
|
||||
@ -9124,6 +9131,68 @@ func (m *NetstatRequest_L4Proto) MarshalToSizedBufferVT(dAtA []byte) (int, error
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *NetstatRequest_NetNS) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
size := m.SizeVT()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *NetstatRequest_NetNS) MarshalToVT(dAtA []byte) (int, error) {
|
||||
size := m.SizeVT()
|
||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *NetstatRequest_NetNS) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
if m == nil {
|
||||
return 0, nil
|
||||
}
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.unknownFields != nil {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if m.Allnetns {
|
||||
i--
|
||||
if m.Allnetns {
|
||||
dAtA[i] = 1
|
||||
} else {
|
||||
dAtA[i] = 0
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x18
|
||||
}
|
||||
if len(m.Netns) > 0 {
|
||||
for iNdEx := len(m.Netns) - 1; iNdEx >= 0; iNdEx-- {
|
||||
i -= len(m.Netns[iNdEx])
|
||||
copy(dAtA[i:], m.Netns[iNdEx])
|
||||
i = encodeVarint(dAtA, i, uint64(len(m.Netns[iNdEx])))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
}
|
||||
if m.Hostnetwork {
|
||||
i--
|
||||
if m.Hostnetwork {
|
||||
dAtA[i] = 1
|
||||
} else {
|
||||
dAtA[i] = 0
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x8
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *NetstatRequest) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
@ -9154,6 +9223,16 @@ func (m *NetstatRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if m.Netns != nil {
|
||||
size, err := m.Netns.MarshalToSizedBufferVT(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarint(dAtA, i, uint64(size))
|
||||
i--
|
||||
dAtA[i] = 0x22
|
||||
}
|
||||
if m.L4Proto != nil {
|
||||
size, err := m.L4Proto.MarshalToSizedBufferVT(dAtA[:i])
|
||||
if err != nil {
|
||||
@ -9257,6 +9336,15 @@ func (m *ConnectRecord) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if len(m.Netns) > 0 {
|
||||
i -= len(m.Netns)
|
||||
copy(dAtA[i:], m.Netns)
|
||||
i = encodeVarint(dAtA, i, uint64(len(m.Netns)))
|
||||
i--
|
||||
dAtA[i] = 0x1
|
||||
i--
|
||||
dAtA[i] = 0x92
|
||||
}
|
||||
if m.Process != nil {
|
||||
size, err := m.Process.MarshalToSizedBufferVT(dAtA[:i])
|
||||
if err != nil {
|
||||
@ -11196,6 +11284,10 @@ func (m *ContainerInfo) SizeVT() (n int) {
|
||||
if l > 0 {
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
l = len(m.NetworkNamespace)
|
||||
if l > 0 {
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
@ -13310,6 +13402,28 @@ func (m *NetstatRequest_L4Proto) SizeVT() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *NetstatRequest_NetNS) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.Hostnetwork {
|
||||
n += 2
|
||||
}
|
||||
if len(m.Netns) > 0 {
|
||||
for _, s := range m.Netns {
|
||||
l = len(s)
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
}
|
||||
if m.Allnetns {
|
||||
n += 2
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *NetstatRequest) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
@ -13327,6 +13441,10 @@ func (m *NetstatRequest) SizeVT() (n int) {
|
||||
l = m.L4Proto.SizeVT()
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
if m.Netns != nil {
|
||||
l = m.Netns.SizeVT()
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
@ -13409,6 +13527,10 @@ func (m *ConnectRecord) SizeVT() (n int) {
|
||||
l = m.Process.SizeVT()
|
||||
n += 2 + l + sov(uint64(l))
|
||||
}
|
||||
l = len(m.Netns)
|
||||
if l > 0 {
|
||||
n += 2 + l + sov(uint64(l))
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
@ -21834,6 +21956,38 @@ func (m *ContainerInfo) UnmarshalVT(dAtA []byte) error {
|
||||
}
|
||||
m.Name = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 8:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field NetworkNamespace", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.NetworkNamespace = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
@ -33961,6 +34115,129 @@ func (m *NetstatRequest_L4Proto) UnmarshalVT(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *NetstatRequest_NetNS) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: NetstatRequest_NetNS: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: NetstatRequest_NetNS: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Hostnetwork", wireType)
|
||||
}
|
||||
var v int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
v |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
m.Hostnetwork = bool(v != 0)
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Netns", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Netns = append(m.Netns, string(dAtA[iNdEx:postIndex]))
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Allnetns", wireType)
|
||||
}
|
||||
var v int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
v |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
m.Allnetns = bool(v != 0)
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *NetstatRequest) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
@ -34081,6 +34358,42 @@ func (m *NetstatRequest) UnmarshalVT(dAtA []byte) error {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 4:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Netns", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.Netns == nil {
|
||||
m.Netns = &NetstatRequest_NetNS{}
|
||||
}
|
||||
if err := m.Netns.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
@ -34613,6 +34926,38 @@ func (m *ConnectRecord) UnmarshalVT(dAtA []byte) error {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 18:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Netns", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Netns = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
|
@ -308,6 +308,7 @@ description: Talos gRPC API reference.
|
||||
- [NetstatRequest](#machine.NetstatRequest)
|
||||
- [NetstatRequest.Feature](#machine.NetstatRequest.Feature)
|
||||
- [NetstatRequest.L4proto](#machine.NetstatRequest.L4proto)
|
||||
- [NetstatRequest.NetNS](#machine.NetstatRequest.NetNS)
|
||||
- [NetstatResponse](#machine.NetstatResponse)
|
||||
- [NetworkConfig](#machine.NetworkConfig)
|
||||
- [NetworkDeviceConfig](#machine.NetworkDeviceConfig)
|
||||
@ -4012,6 +4013,7 @@ ConfigValidationErrorEvent is reported when config validation has failed.
|
||||
| ref | [uint64](#uint64) | | |
|
||||
| pointer | [uint64](#uint64) | | |
|
||||
| process | [ConnectRecord.Process](#machine.ConnectRecord.Process) | | |
|
||||
| netns | [string](#string) | | |
|
||||
|
||||
|
||||
|
||||
@ -4065,6 +4067,7 @@ The messages message containing the requested containers.
|
||||
| status | [string](#string) | | |
|
||||
| pod_id | [string](#string) | | |
|
||||
| name | [string](#string) | | |
|
||||
| network_namespace | [string](#string) | | |
|
||||
|
||||
|
||||
|
||||
@ -5356,6 +5359,7 @@ The messages message containing the requested df stats.
|
||||
| filter | [NetstatRequest.Filter](#machine.NetstatRequest.Filter) | | |
|
||||
| feature | [NetstatRequest.Feature](#machine.NetstatRequest.Feature) | | |
|
||||
| l4proto | [NetstatRequest.L4proto](#machine.NetstatRequest.L4proto) | | |
|
||||
| netns | [NetstatRequest.NetNS](#machine.NetstatRequest.NetNS) | | |
|
||||
|
||||
|
||||
|
||||
@ -5399,6 +5403,23 @@ The messages message containing the requested df stats.
|
||||
|
||||
|
||||
|
||||
<a name="machine.NetstatRequest.NetNS"></a>
|
||||
|
||||
### NetstatRequest.NetNS
|
||||
|
||||
|
||||
|
||||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| hostnetwork | [bool](#bool) | | |
|
||||
| netns | [string](#string) | repeated | |
|
||||
| allnetns | [bool](#bool) | | |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="machine.NetstatResponse"></a>
|
||||
|
||||
### NetstatResponse
|
||||
|
@ -2103,7 +2103,16 @@ talosctl mounts [flags]
|
||||
|
||||
## talosctl netstat
|
||||
|
||||
Retrieve a socket listing of connections
|
||||
Show network connections and sockets
|
||||
|
||||
### Synopsis
|
||||
|
||||
Show network connections and sockets.
|
||||
|
||||
You can pass an optional argument to view a specific pod's connections.
|
||||
To do this, format the argument as "namespace/pod".
|
||||
Note that only pods with a pod network namespace are allowed.
|
||||
If you don't pass an argument, the command will show host connections.
|
||||
|
||||
```
|
||||
talosctl netstat [flags]
|
||||
@ -2118,6 +2127,7 @@ talosctl netstat [flags]
|
||||
-4, --ipv4 display only ipv4 sockets
|
||||
-6, --ipv6 display only ipv6 sockets
|
||||
-l, --listening display listening server sockets
|
||||
-k, --pods show sockets used by Kubernetes pods
|
||||
-p, --programs show process using socket
|
||||
-w, --raw display only RAW sockets
|
||||
-t, --tcp display only TCP sockets
|
||||
@ -2809,7 +2819,7 @@ A CLI for out-of-band management of Kubernetes nodes created by Talos
|
||||
* [talosctl memory](#talosctl-memory) - Show memory usage
|
||||
* [talosctl meta](#talosctl-meta) - Write and delete keys in the META partition
|
||||
* [talosctl mounts](#talosctl-mounts) - List mounts
|
||||
* [talosctl netstat](#talosctl-netstat) - Retrieve a socket listing of connections
|
||||
* [talosctl netstat](#talosctl-netstat) - Show network connections and sockets
|
||||
* [talosctl patch](#talosctl-patch) - Update field(s) of a resource using a JSON patch.
|
||||
* [talosctl pcap](#talosctl-pcap) - Capture the network packets from the node.
|
||||
* [talosctl processes](#talosctl-processes) - List running processes
|
||||
|
Loading…
Reference in New Issue
Block a user