github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadget-context/run.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 gadgetcontext
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"sort"
    21  
    22  	"github.com/inspektor-gadget/inspektor-gadget/pkg/gadget-service/api"
    23  	apihelpers "github.com/inspektor-gadget/inspektor-gadget/pkg/gadget-service/api-helpers"
    24  	"github.com/inspektor-gadget/inspektor-gadget/pkg/operators"
    25  )
    26  
    27  func (c *GadgetContext) initAndPrepareOperators(paramValues api.ParamValues) ([]operators.DataOperatorInstance, error) {
    28  	log := c.Logger()
    29  
    30  	ops := c.DataOperators()
    31  
    32  	// Sort dataOperators based on their priority
    33  	sort.Slice(ops, func(i, j int) bool {
    34  		return ops[i].Priority() < ops[j].Priority()
    35  	})
    36  
    37  	params := make([]*api.Param, 0)
    38  
    39  	dataOperatorInstances := make([]operators.DataOperatorInstance, 0, len(ops))
    40  	for _, op := range ops {
    41  		log.Debugf("initializing data op %q", op.Name())
    42  		opParamPrefix := fmt.Sprintf("operator.%s", op.Name())
    43  
    44  		// Lazily initialize operator
    45  		// TODO: global params should be filled out from a config file or such; maybe it's a better idea not to
    46  		// lazily initialize operators at all, but just hand over the config. The "lazy" stuff could then be done
    47  		// if the operator is instantiated and needs to do work
    48  		err := op.Init(apihelpers.ToParamDescs(op.GlobalParams()).ToParams())
    49  		if err != nil {
    50  			return nil, fmt.Errorf("initializing operator %q: %w", op.Name(), err)
    51  		}
    52  
    53  		// Get and fill params
    54  		instanceParams := op.InstanceParams().AddPrefix(opParamPrefix)
    55  		opParamValues := paramValues.ExtractPrefixedValues(opParamPrefix)
    56  
    57  		err = apihelpers.Validate(instanceParams, opParamValues)
    58  		if err != nil {
    59  			return nil, fmt.Errorf("validating params for operator %q: %w", op.Name(), err)
    60  		}
    61  
    62  		opInst, err := op.InstantiateDataOperator(c, opParamValues)
    63  		if err != nil {
    64  			return nil, fmt.Errorf("instantiating operator %q: %w", op.Name(), err)
    65  		}
    66  		if opInst == nil {
    67  			log.Debugf("> skipped %s", op.Name())
    68  			continue
    69  		}
    70  		dataOperatorInstances = append(dataOperatorInstances, opInst)
    71  
    72  		// Add instance params only if operator was actually instantiated (i.e., activated)
    73  		params = append(params, instanceParams...)
    74  	}
    75  
    76  	for _, opInst := range dataOperatorInstances {
    77  		log.Debugf("preparing op %q", opInst.Name())
    78  		opParamPrefix := fmt.Sprintf("operator.%s", opInst.Name())
    79  
    80  		// Second pass params; this time the operator had the chance to prepare itself based on DataSources, etc.
    81  		// this mainly is postponed to read default values that might differ from before; this second pass is
    82  		// what is handed over to the remote end
    83  		if extra, ok := opInst.(operators.DataOperatorExtraParams); ok {
    84  			pd := extra.ExtraParams(c)
    85  			params = append(params, pd.AddPrefix(opParamPrefix)...)
    86  		}
    87  	}
    88  
    89  	c.SetParams(params)
    90  
    91  	return dataOperatorInstances, nil
    92  }
    93  
    94  func (c *GadgetContext) run(dataOperatorInstances []operators.DataOperatorInstance) error {
    95  	log := c.Logger()
    96  
    97  	for _, opInst := range dataOperatorInstances {
    98  		preStart, ok := opInst.(operators.PreStart)
    99  		if !ok {
   100  			continue
   101  		}
   102  		log.Debugf("pre-starting op %q", opInst.Name())
   103  		err := preStart.PreStart(c)
   104  		if err != nil {
   105  			c.cancel()
   106  			return fmt.Errorf("pre-starting operator %q: %w", opInst.Name(), err)
   107  		}
   108  	}
   109  
   110  	ctx := c.Context()
   111  	if c.timeout > 0 {
   112  		newContext, cancel := context.WithTimeout(ctx, c.timeout)
   113  		defer cancel()
   114  		ctx = newContext
   115  	}
   116  
   117  	for _, opInst := range dataOperatorInstances {
   118  		log.Debugf("starting op %q", opInst.Name())
   119  		err := opInst.Start(c)
   120  		if err != nil {
   121  			c.cancel()
   122  			return fmt.Errorf("starting operator %q: %w", opInst.Name(), err)
   123  		}
   124  	}
   125  
   126  	log.Debugf("running...")
   127  
   128  	<-ctx.Done()
   129  
   130  	// Stop/DeInit in reverse order
   131  	for i := len(dataOperatorInstances) - 1; i >= 0; i-- {
   132  		opInst := dataOperatorInstances[i]
   133  		log.Debugf("stopping op %q", opInst.Name())
   134  		err := opInst.Stop(c)
   135  		if err != nil {
   136  			log.Errorf("stopping operator %q: %v", opInst.Name(), err)
   137  		}
   138  	}
   139  
   140  	// Stop/DeInit in reverse order
   141  	for i := len(dataOperatorInstances) - 1; i >= 0; i-- {
   142  		opInst := dataOperatorInstances[i]
   143  		postStop, ok := opInst.(operators.PostStop)
   144  		if !ok {
   145  			continue
   146  		}
   147  		log.Debugf("post-stopping op %q", opInst.Name())
   148  		err := postStop.PostStop(c)
   149  		if err != nil {
   150  			log.Errorf("post-stopping operator %q: %v", opInst.Name(), err)
   151  		}
   152  	}
   153  	return nil
   154  }
   155  
   156  func (c *GadgetContext) PrepareGadgetInfo(paramValues api.ParamValues) error {
   157  	_, err := c.initAndPrepareOperators(paramValues)
   158  	return err
   159  }
   160  
   161  func (c *GadgetContext) Run(paramValues api.ParamValues) error {
   162  	dataOperatorInstances, err := c.initAndPrepareOperators(paramValues)
   163  	if err != nil {
   164  		c.cancel()
   165  		return fmt.Errorf("initializing and preparing operators: %w", err)
   166  	}
   167  	return c.run(dataOperatorInstances)
   168  }