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 }