github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/types/types.go (about)

     1  // Copyright 2019-2024 The Inspektor Gadget authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package types
    16  
    17  import (
    18  	"encoding/json"
    19  	"fmt"
    20  	"time"
    21  
    22  	"github.com/inspektor-gadget/inspektor-gadget/pkg/columns"
    23  )
    24  
    25  type EventType string
    26  
    27  var node string
    28  
    29  func init() {
    30  	// Register column templates
    31  	columns.MustRegisterTemplate("timestamp", "width:35,maxWidth:35,hide")
    32  	columns.MustRegisterTemplate("node", "width:30,ellipsis:middle")
    33  	columns.MustRegisterTemplate("namespace", "width:30")
    34  	columns.MustRegisterTemplate("pod", "width:30,ellipsis:middle")
    35  	columns.MustRegisterTemplate("container", "width:30")
    36  	columns.MustRegisterTemplate("containerImageName", "width:30")
    37  	columns.MustRegisterTemplate("containerImageDigest", "width:30")
    38  	columns.MustRegisterTemplate("comm", "maxWidth:16")
    39  	columns.MustRegisterTemplate("pid", "minWidth:7")
    40  	columns.MustRegisterTemplate("uid", "minWidth:8")
    41  	columns.MustRegisterTemplate("gid", "minWidth:8")
    42  	columns.MustRegisterTemplate("ns", "width:12,hide")
    43  
    44  	// For IPs (IPv4+IPv6):
    45  	// Min: XXX.XXX.XXX.XXX (IPv4) = 15
    46  	// Max: 0000:0000:0000:0000:0000:ffff:XXX.XXX.XXX.XXX (IPv4-mapped IPv6 address) = 45
    47  	columns.MustRegisterTemplate("ipaddr", "minWidth:15,maxWidth:45")
    48  	columns.MustRegisterTemplate("ipport", "minWidth:type")
    49  	// Assume type width for ipport is 5 characters long. Delimiter is 1. Add that to ipaddr template
    50  	columns.MustRegisterTemplate("ipaddrport", "minWidth:22,width:40,maxWidth:52")
    51  	columns.MustRegisterTemplate("ipversion", "width:2,fixed")
    52  
    53  	// For system calls as the longest is sched_rr_get_interval_time64 with 28
    54  	// characters:
    55  	// https://gist.github.com/alban/aa664b3c46aaf24aeb69caae29a01ae5
    56  	// But there is a lot of system calls which name is below 18 characters.
    57  	columns.MustRegisterTemplate("syscall", "width:18,maxWidth:28")
    58  }
    59  
    60  func Init(nodeName string) {
    61  	node = nodeName
    62  }
    63  
    64  type Time int64
    65  
    66  func (t Time) String() string {
    67  	// Don't use time.RFC3339Nano because we prefer to keep the trailing
    68  	// zeros for alignment
    69  	return time.Unix(0, int64(t)).Format("2006-01-02T15:04:05.000000000Z07:00")
    70  }
    71  
    72  type EndpointKind string
    73  
    74  const (
    75  	EndpointKindPod     EndpointKind = "pod"
    76  	EndpointKindService EndpointKind = "svc"
    77  	EndpointKindRaw     EndpointKind = "raw"
    78  )
    79  
    80  type RuntimeName string
    81  
    82  func (r RuntimeName) String() string {
    83  	return string(r)
    84  }
    85  
    86  const (
    87  	RuntimeNameDocker     RuntimeName = "docker"
    88  	RuntimeNameContainerd RuntimeName = "containerd"
    89  	RuntimeNameCrio       RuntimeName = "cri-o"
    90  	RuntimeNamePodman     RuntimeName = "podman"
    91  	RuntimeNameUnknown    RuntimeName = "unknown"
    92  )
    93  
    94  func String2RuntimeName(name string) RuntimeName {
    95  	switch name {
    96  	case string(RuntimeNameDocker):
    97  		return RuntimeNameDocker
    98  	case string(RuntimeNameContainerd):
    99  		return RuntimeNameContainerd
   100  	case string(RuntimeNameCrio):
   101  		return RuntimeNameCrio
   102  	case string(RuntimeNamePodman):
   103  		return RuntimeNamePodman
   104  	}
   105  	return RuntimeNameUnknown
   106  }
   107  
   108  type Container interface {
   109  	K8sMetadata() *BasicK8sMetadata
   110  	RuntimeMetadata() *BasicRuntimeMetadata
   111  	UsesHostNetwork() bool
   112  }
   113  
   114  type BasicRuntimeMetadata struct {
   115  	// RuntimeName is the name of the container runtime. It is useful to distinguish
   116  	// who is the "owner" of each container in a list of containers collected
   117  	// from multiple runtimes.
   118  	RuntimeName RuntimeName `json:"runtimeName,omitempty" column:"runtimeName,width:19,fixed,hide"`
   119  
   120  	// ContainerID is the container ContainerID without the container runtime prefix. For
   121  	// instance, without the "cri-o://" for CRI-O.
   122  	ContainerID string `json:"containerId,omitempty" column:"containerId,width:13,maxWidth:64,hide"`
   123  
   124  	// ContainerName is the container name. In the case the container runtime
   125  	// response with multiple containers, ContainerName contains only the first element.
   126  	ContainerName string `json:"containerName,omitempty" column:"containerName,template:container"`
   127  
   128  	// ContainerImageName is the name of the container image where the event comes from
   129  	// i.e. docker.io/library/busybox:latest
   130  	// Sometimes the image name is not provided by the runtime (i.e. Docker), then ContainerImageName
   131  	// is the imageID
   132  	// i.e. sha256:6e38f40d628db3002f5617342c8872c935de530d867d0f709a2fbda1a302a562
   133  	// OR
   134  	// i.e. 6e38f40d628d, when truncated
   135  	ContainerImageName string `json:"containerImageName,omitempty" column:"containerImageName,hide"`
   136  
   137  	// ContainerImageDigest is the (repo) digest of the container image where the event comes from
   138  	// containerd: events from both initial and new containers are enriched
   139  	// crio: events from initial containers are enriched
   140  	ContainerImageDigest string `json:"containerImageDigest,omitempty" column:"containerImageDigest,hide"`
   141  }
   142  
   143  func (b *BasicRuntimeMetadata) IsEnriched() bool {
   144  	return b.RuntimeName != RuntimeNameUnknown && b.RuntimeName != "" && b.ContainerID != "" && b.ContainerName != "" && b.ContainerImageName != "" && b.ContainerImageDigest != ""
   145  }
   146  
   147  type BasicK8sMetadata struct {
   148  	Namespace     string            `json:"namespace,omitempty" column:"namespace,template:namespace"`
   149  	PodName       string            `json:"podName,omitempty" column:"pod,template:pod"`
   150  	PodLabels     map[string]string `json:"podLabels,omitempty" column:"labels,hide"`
   151  	ContainerName string            `json:"containerName,omitempty" column:"container,template:container"`
   152  }
   153  
   154  func (b *BasicK8sMetadata) IsEnriched() bool {
   155  	return b.Namespace != "" && b.PodName != "" && b.ContainerName != "" && b.PodLabels != nil
   156  }
   157  
   158  type K8sMetadata struct {
   159  	Node string `json:"node,omitempty" column:"node,template:node"`
   160  
   161  	BasicK8sMetadata `json:",inline"`
   162  
   163  	// HostNetwork is true if the container uses the host network namespace
   164  	HostNetwork bool `json:"hostNetwork,omitempty" column:"hostnetwork,hide"`
   165  }
   166  
   167  type CommonData struct {
   168  	// Runtime contains the container runtime metadata of the container
   169  	// that generated the event
   170  	Runtime BasicRuntimeMetadata `json:"runtime,omitempty" column:"runtime" columnTags:"runtime"`
   171  
   172  	// K8s contains the Kubernetes metadata of the object that generated the
   173  	// event
   174  	K8s K8sMetadata `json:"k8s,omitempty" column:"k8s" columnTags:"kubernetes"`
   175  }
   176  
   177  func (c *CommonData) SetNode(node string) {
   178  	c.K8s.Node = node
   179  }
   180  
   181  func (c *CommonData) SetPodMetadata(container Container) {
   182  	k8s := container.K8sMetadata()
   183  	runtime := container.RuntimeMetadata()
   184  
   185  	c.K8s.PodName = k8s.PodName
   186  	c.K8s.Namespace = k8s.Namespace
   187  	c.K8s.PodLabels = k8s.PodLabels
   188  
   189  	// All containers in the same pod share the same container runtime
   190  	c.Runtime.RuntimeName = runtime.RuntimeName
   191  }
   192  
   193  func (c *CommonData) SetContainerMetadata(container Container) {
   194  	k8s := container.K8sMetadata()
   195  	runtime := container.RuntimeMetadata()
   196  
   197  	c.K8s.ContainerName = k8s.ContainerName
   198  	c.K8s.PodName = k8s.PodName
   199  	c.K8s.Namespace = k8s.Namespace
   200  	c.K8s.PodLabels = k8s.PodLabels
   201  
   202  	c.Runtime.RuntimeName = runtime.RuntimeName
   203  	c.Runtime.ContainerName = runtime.ContainerName
   204  	c.Runtime.ContainerID = runtime.ContainerID
   205  	c.Runtime.ContainerImageName = runtime.ContainerImageName
   206  	c.Runtime.ContainerImageDigest = runtime.ContainerImageDigest
   207  }
   208  
   209  func (c *CommonData) GetNode() string {
   210  	return c.K8s.Node
   211  }
   212  
   213  func (c *CommonData) GetPod() string {
   214  	return c.K8s.PodName
   215  }
   216  
   217  func (c *CommonData) GetNamespace() string {
   218  	return c.K8s.Namespace
   219  }
   220  
   221  func (c *CommonData) GetContainer() string {
   222  	return c.K8s.ContainerName
   223  }
   224  
   225  func (c *CommonData) GetContainerImageName() string {
   226  	return c.Runtime.ContainerImageName
   227  }
   228  
   229  type L3Endpoint struct {
   230  	// Addr is filled by the gadget
   231  	Addr    string `json:"addr,omitempty" column:"addr,hide,template:ipaddr"`
   232  	Version uint8  `json:"version,omitempty" column:"v,hide,template:ipversion"`
   233  
   234  	// Namespace, Name, Kind and PodLabels get populated by the KubeIPResolver operator
   235  	Namespace string            `json:"namespace,omitempty" column:"ns,template:namespace,hide"`
   236  	Name      string            `json:"podname,omitempty" column:"name,hide"`
   237  	Kind      EndpointKind      `json:"kind,omitempty" column:"kind,hide"`
   238  	PodLabels map[string]string `json:"podlabels,omitempty" column:"podLabels,hide"`
   239  }
   240  
   241  func (e *L3Endpoint) String() string {
   242  	switch e.Kind {
   243  	case EndpointKindPod:
   244  		return "p/" + e.Namespace + "/" + e.Name
   245  	case EndpointKindService:
   246  		return "s/" + e.Namespace + "/" + e.Name
   247  	case EndpointKindRaw:
   248  		return "r/" + e.Addr
   249  	default:
   250  		if e.Version == 6 {
   251  			return "[" + e.Addr + "]"
   252  		}
   253  		return e.Addr
   254  	}
   255  }
   256  
   257  type L4Endpoint struct {
   258  	L3Endpoint
   259  	// Port and Proto are filled by the gadget
   260  	Port  uint16 `json:"port" column:"port,hide,template:ipport"`
   261  	Proto uint16 `json:"proto,omitempty" column:"proto,hide,width:4"`
   262  }
   263  
   264  func (e *L4Endpoint) String() string {
   265  	return e.L3Endpoint.String() + ":" + fmt.Sprint(e.Port)
   266  }
   267  
   268  func MustAddVirtualL4EndpointColumn[Event any](
   269  	cols *columns.Columns[Event],
   270  	attr columns.Attributes,
   271  	getEndpoint func(*Event) L4Endpoint,
   272  ) {
   273  	cols.MustAddColumn(
   274  		attr,
   275  		func(e *Event) any {
   276  			endpoint := getEndpoint(e)
   277  			return endpoint.String()
   278  		},
   279  	)
   280  }
   281  
   282  func MustAddVirtualL3EndpointColumn[Event any](
   283  	cols *columns.Columns[Event],
   284  	attr columns.Attributes,
   285  	getEndpoint func(*Event) L3Endpoint,
   286  ) {
   287  	cols.MustAddColumn(
   288  		attr,
   289  		func(e *Event) any {
   290  			endpoint := getEndpoint(e)
   291  			return endpoint.String()
   292  		},
   293  	)
   294  }
   295  
   296  const (
   297  	// Indicates a generic event produced by a gadget. Gadgets extend
   298  	// the base event to contain the specific data the gadget provides
   299  	NORMAL EventType = "normal"
   300  
   301  	// Event is an error message
   302  	ERR EventType = "err"
   303  
   304  	// Event is a warning message
   305  	WARN EventType = "warn"
   306  
   307  	// Event is a debug message
   308  	DEBUG EventType = "debug"
   309  
   310  	// Event is a info message
   311  	INFO EventType = "info"
   312  
   313  	// Indicates the tracer in the node is now is able to produce events
   314  	READY EventType = "ready"
   315  )
   316  
   317  type Event struct {
   318  	CommonData
   319  
   320  	// Timestamp in nanoseconds since January 1, 1970 UTC. An int64 is big
   321  	// enough to represent time between the year 1678 and 2262.
   322  	Timestamp Time `json:"timestamp,omitempty" column:"timestamp,template:timestamp,stringer"`
   323  
   324  	// Type indicates the kind of this event
   325  	Type EventType `json:"type"`
   326  
   327  	// Message when Type is ERR, WARN, DEBUG or INFO
   328  	Message string `json:"message,omitempty"`
   329  }
   330  
   331  // GetBaseEvent is needed to implement commonutils.BaseElement and
   332  // snapshot.SnapshotEvent interfaces.
   333  func (e Event) GetBaseEvent() *Event {
   334  	return &e
   335  }
   336  
   337  func (e *Event) GetType() EventType {
   338  	return e.Type
   339  }
   340  
   341  func (e *Event) GetMessage() string {
   342  	return e.Message
   343  }
   344  
   345  func Err(msg string) Event {
   346  	return Event{
   347  		CommonData: CommonData{
   348  			K8s: K8sMetadata{
   349  				Node: node,
   350  			},
   351  		},
   352  		Type:    ERR,
   353  		Message: msg,
   354  	}
   355  }
   356  
   357  func Warn(msg string) Event {
   358  	return Event{
   359  		CommonData: CommonData{
   360  			K8s: K8sMetadata{
   361  				Node: node,
   362  			},
   363  		},
   364  		Type:    WARN,
   365  		Message: msg,
   366  	}
   367  }
   368  
   369  func Debug(msg string) Event {
   370  	return Event{
   371  		CommonData: CommonData{
   372  			K8s: K8sMetadata{
   373  				Node: node,
   374  			},
   375  		},
   376  		Type:    DEBUG,
   377  		Message: msg,
   378  	}
   379  }
   380  
   381  func Info(msg string) Event {
   382  	return Event{
   383  		CommonData: CommonData{
   384  			K8s: K8sMetadata{
   385  				Node: node,
   386  			},
   387  		},
   388  		Type:    INFO,
   389  		Message: msg,
   390  	}
   391  }
   392  
   393  func EventString(i interface{}) string {
   394  	b, err := json.Marshal(i)
   395  	if err != nil {
   396  		return fmt.Sprintf("error marshaling event: %s\n", err)
   397  	}
   398  	return string(b)
   399  }
   400  
   401  type WithMountNsID struct {
   402  	MountNsID uint64 `json:"mountnsid,omitempty" column:"mntns,template:ns"`
   403  }
   404  
   405  func (e *WithMountNsID) GetMountNSID() uint64 {
   406  	return e.MountNsID
   407  }
   408  
   409  type WithNetNsID struct {
   410  	NetNsID uint64 `json:"netnsid,omitempty" column:"netns,template:ns"`
   411  }
   412  
   413  func (e *WithNetNsID) GetNetNSID() uint64 {
   414  	return e.NetNsID
   415  }