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 }