Skip to content

Commit acf206b

Browse files
committed
chore/inspektor_gadget: Add upgrade action
This change adds upgrade action to allow users to upgrade Inspektor Gadget. It aligns gadget version with Inspektor Gadget version to ensure compatibility. Also, we setup the grpcruntime at runtime to ensure lastest kubeconfig is used Signed-off-by: Qasim Sarfraz <[email protected]>
1 parent 7c80b0e commit acf206b

File tree

11 files changed

+220
-81
lines changed

11 files changed

+220
-81
lines changed

docs/inspektor-gadget-usage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ Can you observe system calls for the pod my-pod in the default namespace for few
6767

6868
## Prerequisites
6969

70-
- A kubeconfig file that has access to the AKS cluster. You will need to restart the MCP server if you change the kubeconfig file.
70+
- A kubeconfig file that has access to the AKS cluster.
7171
- The tool requires Inspektor Gadget to be installed in the cluster. If you are running with `--access-level=readwrite` or more, the MCP server will automatically
7272
install Inspektor Gadget (action `deploy` ) in the cluster otherwise you can follow the steps to install it manually: [Inspektor Gadget Installation](https://learn.microsoft.com/en-us/troubleshoot/azure/azure-kubernetes/logs/capture-system-insights-from-aks#how-to-install-inspektor-gadget-in-an-aks-cluster) or
7373
use the official Helm chart: [Inspektor Gadget Helm Chart](https://inspektor-gadget.io/docs/latest/reference/install-kubernetes#installation-with-the-helm-chart):

internal/components/inspektorgadget/const.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ const (
66
deployAction = "deploy"
77
// undeployAction is the action to remove Inspektor Gadget from the cluster
88
undeployAction = "undeploy"
9+
// upgradeAction is the action to upgrade Inspektor Gadget in the cluster
10+
upgradeAction = "upgrade"
911
// isDeployedAction is the action to check if Inspektor Gadget is deployed
1012
isDeployedAction = "is_deployed"
1113
)

internal/components/inspektorgadget/gadgetmanager.go

Lines changed: 62 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
gadgetcontext "github.com/inspektor-gadget/inspektor-gadget/pkg/gadget-context"
1616
"github.com/inspektor-gadget/inspektor-gadget/pkg/operators"
1717
"github.com/inspektor-gadget/inspektor-gadget/pkg/operators/simple"
18-
"github.com/inspektor-gadget/inspektor-gadget/pkg/runtime"
1918
grpcruntime "github.com/inspektor-gadget/inspektor-gadget/pkg/runtime/grpc"
2019
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2120
"k8s.io/cli-runtime/pkg/genericclioptions"
@@ -40,8 +39,8 @@ type GadgetManager interface {
4039
ListGadgets(ctx context.Context) ([]*GadgetInstance, error)
4140
// IsDeployed checks if the Inspektor Gadget is deployed in the environment
4241
IsDeployed(ctx context.Context) (bool, string, error)
43-
// Close closes the gadget manager and releases any resources
44-
Close() error
42+
// GetVersion retrieves the of Inpektor Gadget installed in the cluster
43+
GetVersion() (string, error)
4544
}
4645

4746
// GadgetInstance represents a running gadget instance
@@ -60,26 +59,11 @@ func init() {
6059
}
6160

6261
// NewGadgetManager creates a new instance of GadgetManager
63-
func NewGadgetManager() (GadgetManager, error) {
64-
rt := grpcruntime.New(grpcruntime.WithConnectUsingK8SProxy)
65-
if err := rt.Init(nil); err != nil {
66-
return nil, fmt.Errorf("initializing gadget runtime: %w", err)
67-
}
68-
69-
restConfig, err := KubernetesFlags.ToRESTConfig()
70-
if err != nil {
71-
return nil, fmt.Errorf("creating REST config: %w", err)
72-
}
73-
rt.SetRestConfig(restConfig)
74-
75-
return &manager{
76-
runtime: rt,
77-
}, nil
62+
func NewGadgetManager() GadgetManager {
63+
return &manager{}
7864
}
7965

80-
type manager struct {
81-
runtime runtime.Runtime
82-
}
66+
type manager struct{}
8367

8468
// RunGadget runs a gadget with the specified image and parameters for a given duration
8569
func (g *manager) RunGadget(ctx context.Context, image string, params map[string]string, duration time.Duration) (string, error) {
@@ -96,7 +80,12 @@ func (g *manager) RunGadget(ctx context.Context, image string, params map[string
9680
gadgetcontext.WithTimeout(duration),
9781
)
9882

99-
if err := g.runtime.RunGadget(gadgetCtx, g.runtime.ParamDescs().ToParams(), params); err != nil {
83+
rt, err := getRuntime()
84+
if err != nil {
85+
return "", fmt.Errorf("getting runtime: %w", err)
86+
}
87+
88+
if err := rt.RunGadget(gadgetCtx, rt.ParamDescs().ToParams(), params); err != nil {
10089
return "", fmt.Errorf("running gadget: %w", err)
10190
}
10291

@@ -155,10 +144,14 @@ func (g *manager) StartGadget(ctx context.Context, image string, params map[stri
155144
image,
156145
)
157146

158-
p := g.runtime.ParamDescs().ToParams()
147+
rt, err := getRuntime()
148+
if err != nil {
149+
return "", fmt.Errorf("getting runtime: %w", err)
150+
}
151+
p := rt.ParamDescs().ToParams()
159152

160153
newID := make([]byte, 16)
161-
_, err := rand.Read(newID)
154+
_, err = rand.Read(newID)
162155
if err != nil {
163156
return "", fmt.Errorf("generating new gadget ID: %w", err)
164157
}
@@ -175,7 +168,7 @@ func (g *manager) StartGadget(ctx context.Context, image string, params map[stri
175168
if err = p.Set(grpcruntime.ParamTags, strings.Join(append(tags, "createdBy=aks-mcp"), ",")); err != nil {
176169
return "", fmt.Errorf("setting gadget tags: %w", err)
177170
}
178-
if err := g.runtime.RunGadget(gadgetCtx, p, params); err != nil {
171+
if err = rt.RunGadget(gadgetCtx, p, params); err != nil {
179172
return "", fmt.Errorf("running gadget: %w", err)
180173
}
181174

@@ -184,7 +177,12 @@ func (g *manager) StartGadget(ctx context.Context, image string, params map[stri
184177

185178
// StopGadget stops a running gadget by its ID
186179
func (g *manager) StopGadget(ctx context.Context, id string) error {
187-
if err := g.runtime.(*grpcruntime.Runtime).RemoveGadgetInstance(ctx, g.runtime.ParamDescs().ToParams(), id); err != nil {
180+
rt, err := getRuntime()
181+
if err != nil {
182+
return fmt.Errorf("getting runtime: %w", err)
183+
}
184+
185+
if err = rt.RemoveGadgetInstance(ctx, rt.ParamDescs().ToParams(), id); err != nil {
188186
return fmt.Errorf("stopping to gadget: %w", err)
189187
}
190188
return nil
@@ -210,7 +208,12 @@ func (g *manager) GetResults(ctx context.Context, id string) (string, error) {
210208
gadgetcontext.WithTimeout(time.Second),
211209
)
212210

213-
if err := g.runtime.RunGadget(gadgetCtx, g.runtime.ParamDescs().ToParams(), map[string]string{}); err != nil {
211+
rt, err := getRuntime()
212+
if err != nil {
213+
return "", fmt.Errorf("getting runtime: %w", err)
214+
}
215+
216+
if err = rt.RunGadget(gadgetCtx, rt.ParamDescs().ToParams(), map[string]string{}); err != nil {
214217
return "", fmt.Errorf("attaching to gadget: %w", err)
215218
}
216219

@@ -219,7 +222,12 @@ func (g *manager) GetResults(ctx context.Context, id string) (string, error) {
219222

220223
// ListGadgets lists all running gadgets and returns their instances
221224
func (g *manager) ListGadgets(ctx context.Context) ([]*GadgetInstance, error) {
222-
instances, err := g.runtime.(*grpcruntime.Runtime).GetGadgetInstances(ctx, g.runtime.ParamDescs().ToParams())
225+
rt, err := getRuntime()
226+
if err != nil {
227+
return nil, fmt.Errorf("getting runtime: %w", err)
228+
}
229+
230+
instances, err := rt.GetGadgetInstances(ctx, rt.ParamDescs().ToParams())
223231
if err != nil {
224232
return nil, fmt.Errorf("listing gadgets: %w", err)
225233
}
@@ -267,10 +275,31 @@ func (g *manager) IsDeployed(ctx context.Context) (bool, string, error) {
267275
return true, namespaces[0], nil
268276
}
269277

270-
// Close closes the gadget manager and releases any resources
271-
func (g *manager) Close() error {
272-
if g.runtime != nil {
273-
return g.runtime.Close()
278+
func (g *manager) GetVersion() (string, error) {
279+
rt, err := getRuntime()
280+
if err != nil {
281+
return "", fmt.Errorf("getting runtime: %w", err)
274282
}
275-
return nil
283+
284+
info, err := rt.GetInfo()
285+
if err != nil {
286+
return "", fmt.Errorf("getting info: %w", err)
287+
}
288+
return info.ServerVersion, nil
289+
}
290+
291+
// getRuntime sets up a runtime, ensuring we always use the latest kubeconfig
292+
func getRuntime() (*grpcruntime.Runtime, error) {
293+
rt := grpcruntime.New(grpcruntime.WithConnectUsingK8SProxy)
294+
if err := rt.Init(nil); err != nil {
295+
return nil, fmt.Errorf("initializing gadget runtime: %w", err)
296+
}
297+
298+
restConfig, err := KubernetesFlags.ToRESTConfig()
299+
if err != nil {
300+
return nil, fmt.Errorf("creating REST config: %w", err)
301+
}
302+
rt.SetRestConfig(restConfig)
303+
304+
return rt, nil
276305
}

internal/components/inspektorgadget/gadgets.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@ type Gadget struct {
1919
ParamsFunc func(filterParams map[string]interface{}, gadgetParams map[string]string)
2020
}
2121

22+
func (g *Gadget) getImage(version string) string {
23+
return fmt.Sprintf("%s:%s", g.Image, gadgetVersionFor(version))
24+
}
25+
2226
var gadgets = []Gadget{
2327
{
2428
Name: observeDNS,
25-
Image: "ghcr.io/inspektor-gadget/gadget/trace_dns:latest",
29+
Image: "ghcr.io/inspektor-gadget/gadget/trace_dns",
2630
Description: "Observes DNS queries in the cluster",
2731
Params: map[string]interface{}{
2832
"name": map[string]interface{}{
@@ -75,7 +79,7 @@ var gadgets = []Gadget{
7579
},
7680
{
7781
Name: observeTCP,
78-
Image: "ghcr.io/inspektor-gadget/gadget/trace_tcp:latest",
82+
Image: "ghcr.io/inspektor-gadget/gadget/trace_tcp",
7983
Description: "Observes TCP traffic in the cluster",
8084
Params: map[string]interface{}{
8185
"source_port": map[string]interface{}{
@@ -121,7 +125,7 @@ var gadgets = []Gadget{
121125
},
122126
{
123127
Name: observeFileOpen,
124-
Image: "ghcr.io/inspektor-gadget/gadget/trace_open:latest",
128+
Image: "ghcr.io/inspektor-gadget/gadget/trace_open",
125129
Description: "Observes file open operations in the cluster",
126130
Params: map[string]interface{}{
127131
"path": map[string]interface{}{
@@ -152,7 +156,7 @@ var gadgets = []Gadget{
152156
},
153157
{
154158
Name: observeProcessExecution,
155-
Image: "ghcr.io/inspektor-gadget/gadget/trace_exec:latest",
159+
Image: "ghcr.io/inspektor-gadget/gadget/trace_exec",
156160
Description: "Observes process execution in the cluster",
157161
Params: map[string]interface{}{
158162
"command": map[string]interface{}{
@@ -172,7 +176,7 @@ var gadgets = []Gadget{
172176
},
173177
{
174178
Name: observeSignal,
175-
Image: "ghcr.io/inspektor-gadget/gadget/trace_signal:latest",
179+
Image: "ghcr.io/inspektor-gadget/gadget/trace_signal",
176180
Description: "Traces signals sent to containers in the cluster",
177181
Params: map[string]interface{}{
178182
"signal": map[string]interface{}{
@@ -193,7 +197,7 @@ var gadgets = []Gadget{
193197
},
194198
{
195199
Name: observeSystemCalls,
196-
Image: "ghcr.io/inspektor-gadget/gadget/traceloop:latest",
200+
Image: "ghcr.io/inspektor-gadget/gadget/traceloop",
197201
Description: "Observes system calls in the cluster",
198202
Params: map[string]interface{}{
199203
"syscall": map[string]interface{}{
@@ -215,7 +219,7 @@ var gadgets = []Gadget{
215219
},
216220
{
217221
Name: topFile,
218-
Image: "ghcr.io/inspektor-gadget/gadget/top_file:latest",
222+
Image: "ghcr.io/inspektor-gadget/gadget/top_file",
219223
Description: "Shows top files by read/write operations",
220224
Params: map[string]interface{}{
221225
"max_entries": map[string]interface{}{
@@ -240,7 +244,7 @@ var gadgets = []Gadget{
240244
},
241245
{
242246
Name: topTCP,
243-
Image: "ghcr.io/inspektor-gadget/gadget/top_tcp:latest",
247+
Image: "ghcr.io/inspektor-gadget/gadget/top_tcp",
244248
Description: "Shows top TCP connections by traffic volume",
245249
Params: map[string]interface{}{
246250
"max_entries": map[string]interface{}{

internal/components/inspektorgadget/gadgets_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package inspektorgadget
22

3-
import "testing"
3+
import (
4+
"strings"
5+
"testing"
6+
)
47

58
func TestGadgets(t *testing.T) {
69
for _, gadget := range gadgets {
@@ -10,6 +13,9 @@ func TestGadgets(t *testing.T) {
1013
if gadget.Image == "" {
1114
t.Errorf("Gadget image is empty for %s", gadget.Name)
1215
}
16+
if gadget.Image != "" && strings.Contains(gadget.Image, ":") {
17+
t.Errorf("Gadget image %s should not contain a version tag", gadget.Image)
18+
}
1319
if gadget.Description == "" {
1420
t.Errorf("Gadget description is empty for %s", gadget.Name)
1521
}

0 commit comments

Comments
 (0)