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 }