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

     1  // Copyright 2022-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  /*
    16  Package gadgetcontext handles initializing gadgets and installed operators before
    17  handing them over to a specified runtime.
    18  */
    19  package gadgetcontext
    20  
    21  import (
    22  	"context"
    23  	"encoding/binary"
    24  	"fmt"
    25  	"maps"
    26  	"slices"
    27  	"sync"
    28  	"time"
    29  
    30  	"github.com/inspektor-gadget/inspektor-gadget/pkg/datasource"
    31  	"github.com/inspektor-gadget/inspektor-gadget/pkg/gadget-service/api"
    32  	"github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets"
    33  	"github.com/inspektor-gadget/inspektor-gadget/pkg/logger"
    34  	"github.com/inspektor-gadget/inspektor-gadget/pkg/operators"
    35  	"github.com/inspektor-gadget/inspektor-gadget/pkg/params"
    36  	"github.com/inspektor-gadget/inspektor-gadget/pkg/parser"
    37  	"github.com/inspektor-gadget/inspektor-gadget/pkg/runtime"
    38  )
    39  
    40  // GadgetContext handles running gadgets by the gadget interface; it orchestrates the whole lifecycle of the gadget
    41  // instance and communicates with gadget and runtime.
    42  type GadgetContext struct {
    43  	ctx                      context.Context
    44  	cancel                   context.CancelFunc
    45  	id                       string
    46  	gadget                   gadgets.GadgetDesc
    47  	gadgetParams             *params.Params
    48  	args                     []string
    49  	runtime                  runtime.Runtime
    50  	runtimeParams            *params.Params
    51  	parser                   parser.Parser
    52  	operators                operators.Operators
    53  	operatorsParamCollection params.Collection
    54  	logger                   logger.Logger
    55  	result                   []byte
    56  	resultError              error
    57  	timeout                  time.Duration
    58  
    59  	lock             sync.Mutex
    60  	dataSources      map[string]datasource.DataSource
    61  	dataOperators    []operators.DataOperator
    62  	vars             map[string]any
    63  	params           []*api.Param
    64  	prepareCallbacks []func()
    65  	loaded           bool
    66  	imageName        string
    67  	metadata         []byte
    68  }
    69  
    70  func NewBuiltIn(
    71  	ctx context.Context,
    72  	id string,
    73  	runtime runtime.Runtime,
    74  	runtimeParams *params.Params,
    75  	gadget gadgets.GadgetDesc,
    76  	gadgetParams *params.Params,
    77  	args []string,
    78  	operatorsParamCollection params.Collection,
    79  	parser parser.Parser,
    80  	logger logger.Logger,
    81  	timeout time.Duration,
    82  ) *GadgetContext {
    83  	gCtx, cancel := context.WithCancel(ctx)
    84  
    85  	return &GadgetContext{
    86  		ctx:                      gCtx,
    87  		cancel:                   cancel,
    88  		id:                       id,
    89  		runtime:                  runtime,
    90  		runtimeParams:            runtimeParams,
    91  		gadget:                   gadget,
    92  		gadgetParams:             gadgetParams,
    93  		args:                     args,
    94  		parser:                   parser,
    95  		logger:                   logger,
    96  		operators:                operators.GetOperatorsForGadget(gadget),
    97  		operatorsParamCollection: operatorsParamCollection,
    98  		timeout:                  timeout,
    99  
   100  		dataSources: make(map[string]datasource.DataSource),
   101  		vars:        make(map[string]any),
   102  	}
   103  }
   104  
   105  func New(
   106  	ctx context.Context,
   107  	imageName string,
   108  	options ...Option,
   109  ) *GadgetContext {
   110  	gCtx, cancel := context.WithCancel(ctx)
   111  	gadgetContext := &GadgetContext{
   112  		ctx:    gCtx,
   113  		cancel: cancel,
   114  		args:   []string{},
   115  		logger: logger.DefaultLogger(),
   116  
   117  		imageName:   imageName,
   118  		dataSources: make(map[string]datasource.DataSource),
   119  		vars:        make(map[string]any),
   120  		// dataOperators: operators.GetDataOperators(),
   121  	}
   122  	for _, option := range options {
   123  		option(gadgetContext)
   124  	}
   125  	return gadgetContext
   126  }
   127  
   128  func (c *GadgetContext) ID() string {
   129  	return c.id
   130  }
   131  
   132  func (c *GadgetContext) Context() context.Context {
   133  	return c.ctx
   134  }
   135  
   136  func (c *GadgetContext) Cancel() {
   137  	c.cancel()
   138  }
   139  
   140  func (c *GadgetContext) Parser() parser.Parser {
   141  	return c.parser
   142  }
   143  
   144  func (c *GadgetContext) Runtime() runtime.Runtime {
   145  	return c.runtime
   146  }
   147  
   148  func (c *GadgetContext) RuntimeParams() *params.Params {
   149  	return c.runtimeParams
   150  }
   151  
   152  func (c *GadgetContext) GadgetDesc() gadgets.GadgetDesc {
   153  	return c.gadget
   154  }
   155  
   156  func (c *GadgetContext) Operators() operators.Operators {
   157  	return c.operators
   158  }
   159  
   160  func (c *GadgetContext) Logger() logger.Logger {
   161  	return c.logger
   162  }
   163  
   164  func (c *GadgetContext) GadgetParams() *params.Params {
   165  	return c.gadgetParams
   166  }
   167  
   168  func (c *GadgetContext) Args() []string {
   169  	return c.args
   170  }
   171  
   172  func (c *GadgetContext) OperatorsParamCollection() params.Collection {
   173  	return c.operatorsParamCollection
   174  }
   175  
   176  func (c *GadgetContext) Timeout() time.Duration {
   177  	return c.timeout
   178  }
   179  
   180  func (c *GadgetContext) ImageName() string {
   181  	return c.imageName
   182  }
   183  
   184  func (c *GadgetContext) DataOperators() []operators.DataOperator {
   185  	return slices.Clone(c.dataOperators)
   186  }
   187  
   188  func (c *GadgetContext) RegisterDataSource(t datasource.Type, name string) (datasource.DataSource, error) {
   189  	c.lock.Lock()
   190  	defer c.lock.Unlock()
   191  	ds := datasource.New(t, name)
   192  	c.dataSources[name] = ds
   193  	return ds, nil
   194  }
   195  
   196  func (c *GadgetContext) GetDataSources() map[string]datasource.DataSource {
   197  	c.lock.Lock()
   198  	defer c.lock.Unlock()
   199  	return maps.Clone(c.dataSources)
   200  }
   201  
   202  func (c *GadgetContext) SetVar(varName string, value any) {
   203  	c.vars[varName] = value
   204  }
   205  
   206  func (c *GadgetContext) GetVar(varName string) (any, bool) {
   207  	res, ok := c.vars[varName]
   208  	return res, ok
   209  }
   210  
   211  func (c *GadgetContext) GetVars() map[string]any {
   212  	return maps.Clone(c.vars)
   213  }
   214  
   215  func (c *GadgetContext) Params() []*api.Param {
   216  	return slices.Clone(c.params)
   217  }
   218  
   219  func (c *GadgetContext) SetParams(params []*api.Param) {
   220  	for _, p := range params {
   221  		c.params = append(c.params, p)
   222  	}
   223  }
   224  
   225  func (c *GadgetContext) SetMetadata(m []byte) {
   226  	c.metadata = m
   227  }
   228  
   229  func (c *GadgetContext) SerializeGadgetInfo() (*api.GadgetInfo, error) {
   230  	gi := &api.GadgetInfo{
   231  		Name:      "",
   232  		ImageName: c.ImageName(),
   233  		Metadata:  c.metadata,
   234  		Params:    c.params,
   235  	}
   236  
   237  	for _, ds := range c.GetDataSources() {
   238  		di := &api.DataSource{
   239  			Id:          0,
   240  			Name:        ds.Name(),
   241  			Fields:      ds.Fields(),
   242  			Tags:        ds.Tags(),
   243  			Annotations: ds.Annotations(),
   244  		}
   245  		if ds.ByteOrder() == binary.BigEndian {
   246  			di.Flags |= api.DataSourceFlagsBigEndian
   247  		}
   248  		gi.DataSources = append(gi.DataSources, di)
   249  	}
   250  
   251  	return gi, nil
   252  }
   253  
   254  func (c *GadgetContext) LoadGadgetInfo(info *api.GadgetInfo, paramValues api.ParamValues, run bool) error {
   255  	c.lock.Lock()
   256  	if c.loaded {
   257  		// TODO: verify that info matches what we previously loaded
   258  		c.lock.Unlock()
   259  		return nil
   260  	}
   261  
   262  	c.dataSources = make(map[string]datasource.DataSource)
   263  	for _, inds := range info.DataSources {
   264  		ds, err := datasource.NewFromAPI(inds)
   265  		if err != nil {
   266  			c.lock.Unlock()
   267  			return fmt.Errorf("creating DataSource from API: %w", err)
   268  		}
   269  		c.dataSources[inds.Name] = ds
   270  	}
   271  	c.params = info.Params
   272  	c.loaded = true
   273  	c.lock.Unlock()
   274  
   275  	c.Logger().Debug("loaded gadget info")
   276  
   277  	// After loading gadget info, start local operators as well
   278  	localOperators, err := c.initAndPrepareOperators(paramValues)
   279  	if err != nil {
   280  		return fmt.Errorf("initializing local operators: %w", err)
   281  	}
   282  
   283  	if run {
   284  		go c.run(localOperators)
   285  	}
   286  
   287  	return nil
   288  }
   289  
   290  func WithTimeoutOrCancel(ctx context.Context, timeout time.Duration) (context.Context, context.CancelFunc) {
   291  	if timeout == 0 {
   292  		return context.WithCancel(ctx)
   293  	}
   294  	return context.WithTimeout(ctx, timeout)
   295  }
   296  
   297  func WaitForTimeoutOrDone(c gadgets.GadgetContext) {
   298  	ctx, cancel := WithTimeoutOrCancel(c.Context(), c.Timeout())
   299  	defer cancel()
   300  	<-ctx.Done()
   301  }