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  }