github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/datasource/compat/wrapper.go (about) 1 // Copyright 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 compat 16 17 import ( 18 "fmt" 19 20 "github.com/inspektor-gadget/inspektor-gadget/pkg/datasource" 21 "github.com/inspektor-gadget/inspektor-gadget/pkg/environment" 22 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadget-service/api" 23 "github.com/inspektor-gadget/inspektor-gadget/pkg/operators" 24 "github.com/inspektor-gadget/inspektor-gadget/pkg/types" 25 ) 26 27 const ( 28 MntNsIdType = "type:gadget_mntns_id" 29 NetNsIdType = "type:gadget_netns_id" 30 NetNsIdFallback = "name:netns" 31 ) 32 33 type EventWrapperBase struct { 34 ds datasource.DataSource 35 MntnsidAccessor datasource.FieldAccessor 36 NetnsidAccessor datasource.FieldAccessor 37 nodeAccessor datasource.FieldAccessor 38 namespaceAccessor datasource.FieldAccessor 39 podnameAccessor datasource.FieldAccessor 40 containernameAccessorK8s datasource.FieldAccessor 41 containernameAccessor datasource.FieldAccessor 42 runtimenameAccessor datasource.FieldAccessor 43 containeridAccessor datasource.FieldAccessor 44 containerimagenameAccessor datasource.FieldAccessor 45 containerimagedigestAccessor datasource.FieldAccessor 46 hostNetworkAccessor datasource.FieldAccessor 47 } 48 49 type ( 50 MntNsEnrichFunc func(event operators.ContainerInfoFromMountNSID) 51 NetNsEnrichFunc func(event operators.ContainerInfoFromNetNSID) 52 ) 53 54 // GetEventWrappers checks for data sources containing refererences to mntns/netns that we could enrich data for 55 func GetEventWrappers(gadgetCtx operators.GadgetContext) (map[datasource.DataSource]*EventWrapperBase, error) { 56 res := make(map[datasource.DataSource]*EventWrapperBase) 57 for _, ds := range gadgetCtx.GetDataSources() { 58 mntnsFields := ds.GetFieldsWithTag(MntNsIdType) 59 netnsFields := ds.GetFieldsWithTag(NetNsIdType, NetNsIdFallback) 60 if len(mntnsFields) == 0 && len(netnsFields) == 0 { 61 continue 62 } 63 64 gadgetCtx.Logger().Debugf("found DataSource with mntns/netns fields: %q", ds.Name()) 65 66 var err error 67 68 var mntnsField datasource.FieldAccessor 69 var netnsField datasource.FieldAccessor 70 71 for _, f := range mntnsFields { 72 gadgetCtx.Logger().Debugf("using mntns enrichment") 73 mntnsField = f 74 // We only support one of those per DataSource for now 75 break 76 } 77 for _, f := range netnsFields { 78 gadgetCtx.Logger().Debugf("using netns enrichment") 79 netnsField = f 80 // We only support one of those per DataSource for now 81 break 82 } 83 84 accessors, err := WrapAccessors(ds, mntnsField, netnsField) 85 if err != nil { 86 return nil, fmt.Errorf("registering accessors: %w", err) 87 } 88 res[ds] = accessors 89 } 90 return res, nil 91 } 92 93 func Subscribe( 94 eventWrappers map[datasource.DataSource]*EventWrapperBase, 95 mntNsEnrichFunc MntNsEnrichFunc, 96 netNsEnrichFunc NetNsEnrichFunc, 97 priority int, 98 ) { 99 for ds, wrapper := range eventWrappers { 100 wr := EventWrapper{ 101 EventWrapperBase: wrapper, 102 } 103 ds.Subscribe(func(ds datasource.DataSource, data datasource.Data) error { 104 wr.Data = data 105 if wrapper.MntnsidAccessor != nil { 106 mntNsEnrichFunc(&wr) 107 } 108 if wrapper.NetnsidAccessor != nil { 109 netNsEnrichFunc(&wr) 110 } 111 return nil 112 }, priority) 113 } 114 } 115 116 func WrapAccessors(source datasource.DataSource, mntnsidAccessor datasource.FieldAccessor, netnsidAccessor datasource.FieldAccessor) (*EventWrapperBase, error) { 117 ev := &EventWrapperBase{ 118 ds: source, 119 MntnsidAccessor: mntnsidAccessor, 120 NetnsidAccessor: netnsidAccessor, 121 } 122 123 k8s, err := source.AddField("k8s", datasource.WithFlags(datasource.FieldFlagEmpty)) 124 if err != nil { 125 return nil, err 126 } 127 128 ev.nodeAccessor, err = k8s.AddSubField("node", datasource.WithTags("kubernetes")) 129 if err != nil { 130 return nil, err 131 } 132 ev.namespaceAccessor, err = k8s.AddSubField("namespace", datasource.WithTags("kubernetes"), datasource.WithAnnotations(map[string]string{ 133 "columns.template": "namespace", 134 }), datasource.WithOrder(-30)) 135 if err != nil { 136 return nil, err 137 } 138 ev.podnameAccessor, err = k8s.AddSubField("pod", datasource.WithTags("kubernetes"), datasource.WithAnnotations(map[string]string{ 139 "columns.template": "pod", 140 }), datasource.WithOrder(-29)) 141 if err != nil { 142 return nil, err 143 } 144 ev.containernameAccessorK8s, err = k8s.AddSubField("container", datasource.WithTags("kubernetes"), datasource.WithAnnotations(map[string]string{ 145 "columns.template": "container", 146 }), datasource.WithOrder(-28)) 147 if err != nil { 148 return nil, err 149 } 150 ev.hostNetworkAccessor, err = k8s.AddSubField( 151 "hostnetwork", 152 datasource.WithTags("kubernetes"), 153 datasource.WithKind(api.Kind_Bool), 154 datasource.WithFlags(datasource.FieldFlagHidden), 155 datasource.WithOrder(-27), 156 ) 157 if err != nil { 158 return nil, err 159 } 160 161 // TODO: Instead of just hiding fields, we can skip adding them in the first place (integration tests don't like 162 // that right now, though) 163 if environment.Environment != environment.Kubernetes { 164 k8s.SetHidden(true, true) 165 } 166 167 runtime, err := source.AddField("runtime", datasource.WithFlags(datasource.FieldFlagEmpty)) 168 if err != nil { 169 return nil, err 170 } 171 ev.containernameAccessor, err = runtime.AddSubField( 172 "containerName", 173 datasource.WithAnnotations(map[string]string{ 174 "columns.template": "container", 175 }), 176 datasource.WithOrder(-26), 177 ) 178 if err != nil { 179 return nil, err 180 } 181 ev.runtimenameAccessor, err = runtime.AddSubField( 182 "runtimeName", 183 datasource.WithAnnotations(map[string]string{ 184 "columns.width": "19", 185 "columns.fixed": "true", 186 }), 187 datasource.WithFlags(datasource.FieldFlagHidden), 188 datasource.WithOrder(-25), 189 ) 190 if err != nil { 191 return nil, err 192 } 193 ev.containeridAccessor, err = runtime.AddSubField( 194 "containerId", 195 datasource.WithAnnotations(map[string]string{ 196 "columns.width": "13", 197 "columns.maxWidth": "64", 198 }), 199 datasource.WithFlags(datasource.FieldFlagHidden), 200 datasource.WithOrder(-24)) 201 if err != nil { 202 return nil, err 203 } 204 ev.containerimagenameAccessor, err = runtime.AddSubField( 205 "containerImageName", 206 datasource.WithFlags(datasource.FieldFlagHidden), 207 datasource.WithOrder(-23), 208 ) 209 if err != nil { 210 return nil, err 211 } 212 ev.containerimagedigestAccessor, err = runtime.AddSubField( 213 "containerImageDigest", 214 datasource.WithFlags(datasource.FieldFlagHidden), 215 datasource.WithOrder(-22), 216 ) 217 if err != nil { 218 return nil, err 219 } 220 221 // TODO: Instead of just hiding fields, we can skip adding them in the first place (integration tests don't like 222 // that right now, though) 223 if environment.Environment == environment.Kubernetes { 224 runtime.SetHidden(true, true) 225 } 226 227 return ev, nil 228 } 229 230 type EventWrapper struct { 231 *EventWrapperBase 232 Data datasource.Data 233 } 234 235 func getUint64(accessor datasource.FieldAccessor, data datasource.Data) uint64 { 236 d := accessor.Get(data) 237 switch len(d) { 238 case 4: 239 return uint64(accessor.Uint32(data)) 240 case 8: 241 return accessor.Uint64(data) 242 } 243 return 0 244 } 245 246 func (ev *EventWrapper) GetMountNSID() uint64 { 247 return getUint64(ev.MntnsidAccessor, ev.Data) 248 } 249 250 func (ev *EventWrapper) GetNetNSID() uint64 { 251 return getUint64(ev.NetnsidAccessor, ev.Data) 252 } 253 254 func (ev *EventWrapper) SetPodMetadata(container types.Container) { 255 k8s := container.K8sMetadata() 256 if k8s != nil { 257 if ev.namespaceAccessor.IsRequested() { 258 ev.namespaceAccessor.Set(ev.Data, []byte(k8s.Namespace)) 259 } 260 if ev.podnameAccessor.IsRequested() { 261 ev.podnameAccessor.Set(ev.Data, []byte(k8s.PodName)) 262 } 263 if ev.containernameAccessor.IsRequested() { 264 ev.containernameAccessorK8s.Set(ev.Data, []byte(k8s.ContainerName)) 265 } 266 if ev.hostNetworkAccessor.IsRequested() { 267 ev.hostNetworkAccessor.Set(ev.Data, make([]byte, 1)) 268 if container.UsesHostNetwork() { 269 ev.hostNetworkAccessor.PutInt8(ev.Data, 1) 270 } 271 } 272 } 273 rt := container.RuntimeMetadata() 274 if rt != nil { 275 if ev.containernameAccessor.IsRequested() { 276 ev.containernameAccessor.Set(ev.Data, []byte(rt.ContainerName)) 277 } 278 if ev.runtimenameAccessor.IsRequested() { 279 ev.runtimenameAccessor.Set(ev.Data, []byte(rt.RuntimeName)) 280 } 281 if ev.containeridAccessor.IsRequested() { 282 ev.containeridAccessor.Set(ev.Data, []byte(rt.ContainerID)) 283 } 284 if ev.containerimagenameAccessor.IsRequested() { 285 ev.containerimagenameAccessor.Set(ev.Data, []byte(rt.ContainerImageName)) 286 } 287 if ev.containerimagedigestAccessor.IsRequested() { 288 ev.containerimagedigestAccessor.Set(ev.Data, []byte(rt.ContainerImageDigest)) 289 } 290 } 291 } 292 293 func (ev *EventWrapper) SetContainerMetadata(container types.Container) { 294 ev.SetPodMetadata(container) 295 } 296 297 func (ev *EventWrapper) SetNode(node string) { 298 ev.nodeAccessor.Set(ev.Data, []byte(node)) 299 }