From 1ba403e87884c53ec30f524292ac9ce4e4e4bfda Mon Sep 17 00:00:00 2001 From: Beilei Huang <41132767+bravebeaver@users.noreply.github.com> Date: Thu, 22 Sep 2022 20:21:23 +1200 Subject: [PATCH 01/27] add gadget top block-io --- cmd/aks-periscope/aks-periscope.go | 1 + pkg/collector/inspecktor_blockio_collector.go | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 pkg/collector/inspecktor_blockio_collector.go diff --git a/cmd/aks-periscope/aks-periscope.go b/cmd/aks-periscope/aks-periscope.go index 70acb343..0a68cbe8 100644 --- a/cmd/aks-periscope/aks-periscope.go +++ b/cmd/aks-periscope/aks-periscope.go @@ -98,6 +98,7 @@ func run(osIdentifier utils.OSIdentifier, knownFilePaths *utils.KnownFilePaths, collector.NewSystemLogsCollector(osIdentifier, runtimeInfo), collector.NewSystemPerfCollector(config, runtimeInfo), collector.NewWindowsLogsCollector(osIdentifier, runtimeInfo, knownFilePaths, fileSystem, 10*time.Second, 20*time.Minute), + collector.NewInspektorGadgetBlockIOCollector(config, runtimeInfo), } collectorGrp := new(sync.WaitGroup) diff --git a/pkg/collector/inspecktor_blockio_collector.go b/pkg/collector/inspecktor_blockio_collector.go new file mode 100644 index 00000000..304a93c0 --- /dev/null +++ b/pkg/collector/inspecktor_blockio_collector.go @@ -0,0 +1,50 @@ +package collector + +import ( + "github.com/Azure/aks-periscope/pkg/interfaces" + "github.com/Azure/aks-periscope/pkg/utils" + + restclient "k8s.io/client-go/rest" +) + +// InspektorGadgetBlockIOCollector defines a InspektorGadget Top BlockIO Collector struct +type InspektorGadgetBlockIOCollector struct { + data map[string]string + kubeconfig *restclient.Config + commandRunner *utils.KubeCommandRunner + runtimeInfo *utils.RuntimeInfo +} + +// NewInspektorGadgetBlockIOCollector is a constructor. +func NewInspektorGadgetBlockIOCollector(config *restclient.Config, runtimeInfo *utils.RuntimeInfo) *InspektorGadgetBlockIOCollector { + return &InspektorGadgetBlockIOCollector{ + data: make(map[string]string), + kubeconfig: config, + commandRunner: utils.NewKubeCommandRunner(config), + runtimeInfo: runtimeInfo, + } +} + +func (collector *InspektorGadgetBlockIOCollector) GetName() string { + return "inspektorgadget-block_io" +} + +func (collector *InspektorGadgetBlockIOCollector) CheckSupported() error { + // TODO check whether gadget plugin is installed, for now assume so + return nil +} + +// Collect implements the interface method +func (collector *InspektorGadgetBlockIOCollector) Collect() error { + output, err := utils.RunCommandOnHost("kubectl-gadget", "top", "block-io") + if err != nil { + return err + } + + collector.data["block-io"] = output + return nil +} + +func (collector *InspektorGadgetBlockIOCollector) GetData() map[string]interfaces.DataValue { + return utils.ToDataValueMap(collector.data) +} From ddf3e76eb16edb8ab0019da3dc9d828b8cf6163a Mon Sep 17 00:00:00 2001 From: Beilei Huang <41132767+bravebeaver@users.noreply.github.com> Date: Tue, 27 Sep 2022 10:47:28 +1300 Subject: [PATCH 02/27] create trace using client-go and stream result --- cmd/aks-periscope/aks-periscope.go | 2 +- pkg/collector/inspecktor_blockio_collector.go | 50 -------- .../inspecktor_trace_dns_collector.go | 121 ++++++++++++++++++ .../inspektor-gadget/biolatency.yaml | 9 ++ .../inspektor-gadget/biotop-trace.yaml | 18 +++ .../inspektor-gadget/dns-trace.yaml | 12 ++ .../inspektor-gadget/filetop-trace.yaml | 9 ++ 7 files changed, 170 insertions(+), 51 deletions(-) delete mode 100644 pkg/collector/inspecktor_blockio_collector.go create mode 100644 pkg/collector/inspecktor_trace_dns_collector.go create mode 100644 pkg/test/resources/tools-resources/inspektor-gadget/biolatency.yaml create mode 100644 pkg/test/resources/tools-resources/inspektor-gadget/biotop-trace.yaml create mode 100644 pkg/test/resources/tools-resources/inspektor-gadget/dns-trace.yaml create mode 100644 pkg/test/resources/tools-resources/inspektor-gadget/filetop-trace.yaml diff --git a/cmd/aks-periscope/aks-periscope.go b/cmd/aks-periscope/aks-periscope.go index 0a68cbe8..31db7248 100644 --- a/cmd/aks-periscope/aks-periscope.go +++ b/cmd/aks-periscope/aks-periscope.go @@ -98,7 +98,7 @@ func run(osIdentifier utils.OSIdentifier, knownFilePaths *utils.KnownFilePaths, collector.NewSystemLogsCollector(osIdentifier, runtimeInfo), collector.NewSystemPerfCollector(config, runtimeInfo), collector.NewWindowsLogsCollector(osIdentifier, runtimeInfo, knownFilePaths, fileSystem, 10*time.Second, 20*time.Minute), - collector.NewInspektorGadgetBlockIOCollector(config, runtimeInfo), + collector.NewInspektorGadgetDNSTraceCollector(config, runtimeInfo), } collectorGrp := new(sync.WaitGroup) diff --git a/pkg/collector/inspecktor_blockio_collector.go b/pkg/collector/inspecktor_blockio_collector.go deleted file mode 100644 index 304a93c0..00000000 --- a/pkg/collector/inspecktor_blockio_collector.go +++ /dev/null @@ -1,50 +0,0 @@ -package collector - -import ( - "github.com/Azure/aks-periscope/pkg/interfaces" - "github.com/Azure/aks-periscope/pkg/utils" - - restclient "k8s.io/client-go/rest" -) - -// InspektorGadgetBlockIOCollector defines a InspektorGadget Top BlockIO Collector struct -type InspektorGadgetBlockIOCollector struct { - data map[string]string - kubeconfig *restclient.Config - commandRunner *utils.KubeCommandRunner - runtimeInfo *utils.RuntimeInfo -} - -// NewInspektorGadgetBlockIOCollector is a constructor. -func NewInspektorGadgetBlockIOCollector(config *restclient.Config, runtimeInfo *utils.RuntimeInfo) *InspektorGadgetBlockIOCollector { - return &InspektorGadgetBlockIOCollector{ - data: make(map[string]string), - kubeconfig: config, - commandRunner: utils.NewKubeCommandRunner(config), - runtimeInfo: runtimeInfo, - } -} - -func (collector *InspektorGadgetBlockIOCollector) GetName() string { - return "inspektorgadget-block_io" -} - -func (collector *InspektorGadgetBlockIOCollector) CheckSupported() error { - // TODO check whether gadget plugin is installed, for now assume so - return nil -} - -// Collect implements the interface method -func (collector *InspektorGadgetBlockIOCollector) Collect() error { - output, err := utils.RunCommandOnHost("kubectl-gadget", "top", "block-io") - if err != nil { - return err - } - - collector.data["block-io"] = output - return nil -} - -func (collector *InspektorGadgetBlockIOCollector) GetData() map[string]interfaces.DataValue { - return utils.ToDataValueMap(collector.data) -} diff --git a/pkg/collector/inspecktor_trace_dns_collector.go b/pkg/collector/inspecktor_trace_dns_collector.go new file mode 100644 index 00000000..17741cc7 --- /dev/null +++ b/pkg/collector/inspecktor_trace_dns_collector.go @@ -0,0 +1,121 @@ +package collector + +import ( + "context" + "fmt" + "math/rand" + "time" + + "github.com/Azure/aks-periscope/pkg/interfaces" + "github.com/Azure/aks-periscope/pkg/utils" + gadgetv1alpha1 "github.com/kinvolk/inspektor-gadget/pkg/apis/gadget/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes" + restclient "k8s.io/client-go/rest" + runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" +) + +const ( + GadgetOperation = "gadget.kinvolk.io/operation" +) + +// InspektorGadgetDNSTraceCollector defines a InspektorGadget Trace DNS Collector struct +type InspektorGadgetDNSTraceCollector struct { + data map[string]string + kubeconfig *restclient.Config + commandRunner *utils.KubeCommandRunner + runtimeInfo *utils.RuntimeInfo +} + +// NewInspektorGadgetDNSTraceCollector is a constructor. +func NewInspektorGadgetDNSTraceCollector(config *restclient.Config, runtimeInfo *utils.RuntimeInfo) *InspektorGadgetDNSTraceCollector { + rand.Seed(time.Now().UnixNano()) + return &InspektorGadgetDNSTraceCollector{ + data: make(map[string]string), + kubeconfig: config, + commandRunner: utils.NewKubeCommandRunner(config), + runtimeInfo: runtimeInfo, + } +} + +func (collector *InspektorGadgetDNSTraceCollector) GetName() string { + return "inspektorgadget-dnstrace" +} + +func (collector *InspektorGadgetDNSTraceCollector) CheckSupported() error { + clientset, err := kubernetes.NewForConfig(collector.kubeconfig) + + opts := metav1.ListOptions{LabelSelector: "k8s-app=gadget"} + pods, err := clientset.CoreV1().Pods("gadget").List(context.TODO(), opts) + if err != nil { + return err + } + + if len(pods.Items) == 0 { + return fmt.Errorf("no gadget pods found. Inspektor gadget not deployed properly") + } + + return nil +} + +// Collect implements the interface method +func (collector *InspektorGadgetDNSTraceCollector) Collect() error { + + gadgetScheme := runtime.NewScheme() + + err := gadgetv1alpha1.AddToScheme(gadgetScheme) + if err != nil { + return fmt.Errorf("could not add gadget scheme: %w", err) + } + + gadgetClient, err := runtimeclient.New(collector.kubeconfig, runtimeclient.Options{ + Scheme: gadgetScheme, + }) + if err != nil { + return fmt.Errorf("could not create rest client for gadgets: %w", err) + } + + // Create a dns gadget. + gadgetName := fmt.Sprintf("dns-%s", randomPodID()) + trace := &gadgetv1alpha1.Trace{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "gadget", + Annotations: map[string]string{ + GadgetOperation: string(gadgetv1alpha1.OperationStart), + }, + Name: gadgetName, + }, + Spec: gadgetv1alpha1.TraceSpec{ + Node: collector.runtimeInfo.HostNodeName, + Gadget: "dns", + RunMode: gadgetv1alpha1.RunModeManual, + OutputMode: gadgetv1alpha1.TraceOutputModeStream, + }, + } + err = gadgetClient.Create(context.TODO(), trace) + if err != nil { + return fmt.Errorf("could not create dns trace %s: %w", gadgetName, err) + } + //collect output + output, err := utils.RunCommandOnHost("./bin/gadgettracermanager", "-call", "receive-stream", "-tracerid", fmt.Sprintf("trace_%s_%s", "gadget", gadgetName)) + if err != nil { + return err + } + collector.data[fmt.Sprintf("dns-trace-%s", gadgetName)] = output + + return nil +} + +func (collector *InspektorGadgetDNSTraceCollector) GetData() map[string]interfaces.DataValue { + return utils.ToDataValueMap(collector.data) +} + +func randomPodID() string { + output := make([]byte, 5) + allowedCharacters := "0123456789abcdefghijklmnopqrstuvwxyz" + for i := range output { + output[i] = allowedCharacters[rand.Int31n(int32(len(allowedCharacters)))] + } + return string(output) +} diff --git a/pkg/test/resources/tools-resources/inspektor-gadget/biolatency.yaml b/pkg/test/resources/tools-resources/inspektor-gadget/biolatency.yaml new file mode 100644 index 00000000..369e6583 --- /dev/null +++ b/pkg/test/resources/tools-resources/inspektor-gadget/biolatency.yaml @@ -0,0 +1,9 @@ +apiVersion: gadget.kinvolk.io/v1alpha1 +kind: Trace +metadata: + name: biolatency + namespace: gadget +spec: + gadget: biolatency + runMode: Manual + outputMode: Status \ No newline at end of file diff --git a/pkg/test/resources/tools-resources/inspektor-gadget/biotop-trace.yaml b/pkg/test/resources/tools-resources/inspektor-gadget/biotop-trace.yaml new file mode 100644 index 00000000..4989885e --- /dev/null +++ b/pkg/test/resources/tools-resources/inspektor-gadget/biotop-trace.yaml @@ -0,0 +1,18 @@ +apiVersion: gadget.kinvolk.io/v1alpha1 +kind: Trace +metadata: + name: biotop-f + namespace: gadget + labels: + gadgetName: biotop + namespace: demo + outputMode: Stream +spec: + gadget: biotop + runMode: Manual + outputMode: Stream + node: aks-agentpool-14358782-vmss000002 + parameters: + interval: "1" + max_rows: "20" + sort_by: all \ No newline at end of file diff --git a/pkg/test/resources/tools-resources/inspektor-gadget/dns-trace.yaml b/pkg/test/resources/tools-resources/inspektor-gadget/dns-trace.yaml new file mode 100644 index 00000000..aa5e8880 --- /dev/null +++ b/pkg/test/resources/tools-resources/inspektor-gadget/dns-trace.yaml @@ -0,0 +1,12 @@ +apiVersion: gadget.kinvolk.io/v1alpha1 +kind: Trace +metadata: + name: dns-k9ptr + namespace: gadget + annotations: + gadget.kinvolk.io/operation: start +spec: + node: aks-agentpool-14358782-vmss000000 + gadget: dns + outputMode: Stream + runMode: Manual \ No newline at end of file diff --git a/pkg/test/resources/tools-resources/inspektor-gadget/filetop-trace.yaml b/pkg/test/resources/tools-resources/inspektor-gadget/filetop-trace.yaml new file mode 100644 index 00000000..b3e54d3d --- /dev/null +++ b/pkg/test/resources/tools-resources/inspektor-gadget/filetop-trace.yaml @@ -0,0 +1,9 @@ +apiVersion: gadget.kinvolk.io/v1alpha1 +kind: Trace +metadata: + name: filetop + namespace: gadget +spec: + gadget: filetop + runMode: Manual + outputMode: Stream \ No newline at end of file From 5f53de6928598fe271f35c447c3aae4dee372edd Mon Sep 17 00:00:00 2001 From: Beilei Huang <41132767+bravebeaver@users.noreply.github.com> Date: Wed, 28 Sep 2022 11:50:31 +1300 Subject: [PATCH 03/27] check existence of trace crd rather than pod. more reliable way to see whether ig is supported --- deployment/base/cluster-role.yaml | 3 +++ .../inspecktor_trace_dns_collector.go | 18 ++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/deployment/base/cluster-role.yaml b/deployment/base/cluster-role.yaml index 192e7db7..28c98d78 100644 --- a/deployment/base/cluster-role.yaml +++ b/deployment/base/cluster-role.yaml @@ -27,3 +27,6 @@ rules: - apiGroups: ["admissionregistration.k8s.io"] resources: ["mutatingwebhookconfigurations", "validatingwebhookconfigurations"] verbs: ["get", "list"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["mutatingwebhookconfigurations", "validatingwebhookconfigurations"] + verbs: ["get", "list"] diff --git a/pkg/collector/inspecktor_trace_dns_collector.go b/pkg/collector/inspecktor_trace_dns_collector.go index 17741cc7..6fd30213 100644 --- a/pkg/collector/inspecktor_trace_dns_collector.go +++ b/pkg/collector/inspecktor_trace_dns_collector.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math/rand" + "strings" "time" "github.com/Azure/aks-periscope/pkg/interfaces" @@ -11,7 +12,6 @@ import ( gadgetv1alpha1 "github.com/kinvolk/inspektor-gadget/pkg/apis/gadget/v1alpha1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes" restclient "k8s.io/client-go/rest" runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -44,19 +44,17 @@ func (collector *InspektorGadgetDNSTraceCollector) GetName() string { } func (collector *InspektorGadgetDNSTraceCollector) CheckSupported() error { - clientset, err := kubernetes.NewForConfig(collector.kubeconfig) - - opts := metav1.ListOptions{LabelSelector: "k8s-app=gadget"} - pods, err := clientset.CoreV1().Pods("gadget").List(context.TODO(), opts) + crds, err := collector.commandRunner.GetCRDUnstructuredList() if err != nil { - return err + return fmt.Errorf("error listing CRDs in cluster") } - if len(pods.Items) == 0 { - return fmt.Errorf("no gadget pods found. Inspektor gadget not deployed properly") + for _, crd := range crds.Items { + if strings.Contains(crd.GetName(), "traces.gadget.kinvolk.io") { + return nil + } } - - return nil + return fmt.Errorf("does not contain gadget crd") } // Collect implements the interface method From b03c937a44f0fe4c5f05f98f842cfc6fd862a88b Mon Sep 17 00:00:00 2001 From: Beilei Huang <41132767+bravebeaver@users.noreply.github.com> Date: Wed, 28 Sep 2022 16:24:19 +1300 Subject: [PATCH 04/27] allow periscope to run exec on pods --- deployment/base/cluster-role.yaml | 5 +- .../inspecktor_trace_dns_collector.go | 68 ++++++++++++++++++- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/deployment/base/cluster-role.yaml b/deployment/base/cluster-role.yaml index 28c98d78..7c0f1312 100644 --- a/deployment/base/cluster-role.yaml +++ b/deployment/base/cluster-role.yaml @@ -10,7 +10,7 @@ rules: resources: ["secrets"] verbs: ["list"] - apiGroups: [""] - resources: ["pods/portforward"] + resources: ["pods/portforward", "pods/exec"] verbs: ["create"] - apiGroups: ["aks-periscope.azure.github.com"] resources: ["diagnostics"] @@ -21,6 +21,9 @@ rules: - apiGroups: ["access.smi-spec.io", "specs.smi-spec.io", "split.smi-spec.io"] resources: ["*"] verbs: ["get", "list", "watch"] +- apiGroups: ["gadget.kinvolk.io"] + resources: ["*"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] - apiGroups: ["config.openservicemesh.io"] resources: ["meshconfigs"] verbs: ["get", "list"] diff --git a/pkg/collector/inspecktor_trace_dns_collector.go b/pkg/collector/inspecktor_trace_dns_collector.go index 6fd30213..513415eb 100644 --- a/pkg/collector/inspecktor_trace_dns_collector.go +++ b/pkg/collector/inspecktor_trace_dns_collector.go @@ -1,8 +1,10 @@ package collector import ( + "bytes" "context" "fmt" + "log" "math/rand" "strings" "time" @@ -10,9 +12,13 @@ import ( "github.com/Azure/aks-periscope/pkg/interfaces" "github.com/Azure/aks-periscope/pkg/utils" gadgetv1alpha1 "github.com/kinvolk/inspektor-gadget/pkg/apis/gadget/v1alpha1" + "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/scheme" restclient "k8s.io/client-go/rest" + "k8s.io/client-go/tools/remotecommand" runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -95,12 +101,12 @@ func (collector *InspektorGadgetDNSTraceCollector) Collect() error { if err != nil { return fmt.Errorf("could not create dns trace %s: %w", gadgetName, err) } + //collect output - output, err := utils.RunCommandOnHost("./bin/gadgettracermanager", "-call", "receive-stream", "-tracerid", fmt.Sprintf("trace_%s_%s", "gadget", gadgetName)) + err = collector.runTraceCommandOnPod(gadgetName) if err != nil { return err } - collector.data[fmt.Sprintf("dns-trace-%s", gadgetName)] = output return nil } @@ -117,3 +123,61 @@ func randomPodID() string { } return string(output) } + +func (collector *InspektorGadgetDNSTraceCollector) runTraceCommandOnPod(gadgetName string) error { + // Creates the clientset + clientset, err := kubernetes.NewForConfig(collector.kubeconfig) + if err != nil { + return fmt.Errorf("getting access to K8S failed: %w", err) + } + + gadgetPods, err := clientset.CoreV1().Pods("gadget").List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return fmt.Errorf("could not list gadget pods: %w", err) + } + var command = []string{"./bin/gadgettracermanager", "-call", "receive-stream", "-tracerid", fmt.Sprintf("trace_gadget_%s", gadgetName)} + + for _, podName := range gadgetPods.Items { + request := clientset.CoreV1().RESTClient().Post(). + Resource("pods"). + Name(podName.Name). + Namespace("gadget"). + SubResource("exec"). + VersionedParams(&v1.PodExecOptions{ + Stdin: false, + Stdout: true, + Stderr: true, + TTY: false, + Command: command, + }, scheme.ParameterCodec) + + stdout := new(bytes.Buffer) + stderr := new(bytes.Buffer) + streamOptions := remotecommand.StreamOptions{ + Stdout: stdout, + Stderr: stderr, + } + + exec, err := remotecommand.NewSPDYExecutor(collector.kubeconfig, "POST", request.URL()) + log.Printf("\tPost request to DNS trace stream : %s ", request.URL()) + if err != nil { + return fmt.Errorf("could not create SPDY executor: %w", err) + } + + err = exec.Stream(streamOptions) + if err != nil { + result := strings.TrimSpace(stdout.String()) + "\n" + strings.TrimSpace(stderr.String()) + result = strings.TrimSpace(result) + collector.data[fmt.Sprintf("dns-trace-%s-%s", gadgetName, podName)] = result + return fmt.Errorf("error reading stream: %w", err) + } + result := strings.TrimSpace(stdout.String()) + "\n" + strings.TrimSpace(stderr.String()) + result = strings.TrimSpace(result) + log.Printf("\tObtain DNS trace stream : %s ", result) + + collector.data[fmt.Sprintf("dns-trace-%s-%s", gadgetName, podName)] = result + log.Printf("\tupdated collector data") + } + + return nil +} From 7f0c785a1a50e47fa271523f3f0810518486d3b1 Mon Sep 17 00:00:00 2001 From: Beilei Huang <41132767+bravebeaver@users.noreply.github.com> Date: Wed, 28 Sep 2022 20:05:02 +1300 Subject: [PATCH 05/27] collect stream and delete pod --- .../inspecktor_trace_dns_collector.go | 75 +++++++++++-------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/pkg/collector/inspecktor_trace_dns_collector.go b/pkg/collector/inspecktor_trace_dns_collector.go index 513415eb..17d23365 100644 --- a/pkg/collector/inspecktor_trace_dns_collector.go +++ b/pkg/collector/inspecktor_trace_dns_collector.go @@ -103,8 +103,9 @@ func (collector *InspektorGadgetDNSTraceCollector) Collect() error { } //collect output - err = collector.runTraceCommandOnPod(gadgetName) + err = collector.runTraceCommandOnPod(gadgetName, gadgetClient, trace) if err != nil { + log.Printf("\t could not run trace : %s ", err) return err } @@ -124,7 +125,7 @@ func randomPodID() string { return string(output) } -func (collector *InspektorGadgetDNSTraceCollector) runTraceCommandOnPod(gadgetName string) error { +func (collector *InspektorGadgetDNSTraceCollector) runTraceCommandOnPod(gadgetName string, gadgetClient runtimeclient.Client, trace *gadgetv1alpha1.Trace) error { // Creates the clientset clientset, err := kubernetes.NewForConfig(collector.kubeconfig) if err != nil { @@ -137,19 +138,7 @@ func (collector *InspektorGadgetDNSTraceCollector) runTraceCommandOnPod(gadgetNa } var command = []string{"./bin/gadgettracermanager", "-call", "receive-stream", "-tracerid", fmt.Sprintf("trace_gadget_%s", gadgetName)} - for _, podName := range gadgetPods.Items { - request := clientset.CoreV1().RESTClient().Post(). - Resource("pods"). - Name(podName.Name). - Namespace("gadget"). - SubResource("exec"). - VersionedParams(&v1.PodExecOptions{ - Stdin: false, - Stdout: true, - Stderr: true, - TTY: false, - Command: command, - }, scheme.ParameterCodec) + for _, pod := range gadgetPods.Items { stdout := new(bytes.Buffer) stderr := new(bytes.Buffer) @@ -158,26 +147,48 @@ func (collector *InspektorGadgetDNSTraceCollector) runTraceCommandOnPod(gadgetNa Stderr: stderr, } - exec, err := remotecommand.NewSPDYExecutor(collector.kubeconfig, "POST", request.URL()) - log.Printf("\tPost request to DNS trace stream : %s ", request.URL()) - if err != nil { - return fmt.Errorf("could not create SPDY executor: %w", err) - } - - err = exec.Stream(streamOptions) - if err != nil { + go func(podName string) { + request := clientset.CoreV1().RESTClient().Post(). + Resource("pods"). + Name(podName). + Namespace("gadget"). + SubResource("exec"). + VersionedParams(&v1.PodExecOptions{ + Stdin: false, + Stdout: true, + Stderr: true, + TTY: false, + Command: command, + }, scheme.ParameterCodec) + //TODO start streaming when trace is started + log.Printf("\tPost request to DNS trace stream : %s ", request.URL()) + exec, err := remotecommand.NewSPDYExecutor(collector.kubeconfig, "POST", request.URL()) + + if err != nil { + log.Printf("\tError creating SPDYExecutor for pod exec %q: %s", podName, err) + collector.data[fmt.Sprintf("dns-trace-%s-%s", gadgetName, podName)] = fmt.Sprintf("could not create SPDY executor: %v", err) + return + } + err = exec.Stream(streamOptions) + if err != nil { + result := strings.TrimSpace(stdout.String()) + "\n" + strings.TrimSpace(stderr.String()) + result = strings.TrimSpace(result) + collector.data[fmt.Sprintf("dns-trace-%s-%s", gadgetName, podName)] = "try a different pod" + log.Printf("\tObtain DNS trace stream erred: %s, %s. Try a different pod ", podName, result) + return + } + log.Printf("\tCollecting DNS trace stream from pod %s", podName) result := strings.TrimSpace(stdout.String()) + "\n" + strings.TrimSpace(stderr.String()) result = strings.TrimSpace(result) collector.data[fmt.Sprintf("dns-trace-%s-%s", gadgetName, podName)] = result - return fmt.Errorf("error reading stream: %w", err) - } - result := strings.TrimSpace(stdout.String()) + "\n" + strings.TrimSpace(stderr.String()) - result = strings.TrimSpace(result) - log.Printf("\tObtain DNS trace stream : %s ", result) - - collector.data[fmt.Sprintf("dns-trace-%s-%s", gadgetName, podName)] = result - log.Printf("\tupdated collector data") + log.Printf("\tCollected DNS trace stream from pod %s", podName) + }(pod.Name) + } + log.Printf("\twait for 10 seconds to stop collection dns trace") + time.Sleep(10 * time.Second) + err = gadgetClient.Delete(context.TODO(), trace) + if err != nil { + log.Printf("could not stop trace %s: %w", trace.Name, err) } - return nil } From b8c0befa0befb772116b34fb3c22e427f743cba3 Mon Sep 17 00:00:00 2001 From: Beilei Huang <41132767+bravebeaver@users.noreply.github.com> Date: Wed, 28 Sep 2022 21:40:51 +1300 Subject: [PATCH 06/27] wait and wait --- pkg/collector/inspecktor_trace_dns_collector.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pkg/collector/inspecktor_trace_dns_collector.go b/pkg/collector/inspecktor_trace_dns_collector.go index 17d23365..c3b445f4 100644 --- a/pkg/collector/inspecktor_trace_dns_collector.go +++ b/pkg/collector/inspecktor_trace_dns_collector.go @@ -7,6 +7,7 @@ import ( "log" "math/rand" "strings" + "sync" "time" "github.com/Azure/aks-periscope/pkg/interfaces" @@ -138,6 +139,7 @@ func (collector *InspektorGadgetDNSTraceCollector) runTraceCommandOnPod(gadgetNa } var command = []string{"./bin/gadgettracermanager", "-call", "receive-stream", "-tracerid", fmt.Sprintf("trace_gadget_%s", gadgetName)} + collectorGrp := new(sync.WaitGroup) for _, pod := range gadgetPods.Items { stdout := new(bytes.Buffer) @@ -146,8 +148,10 @@ func (collector *InspektorGadgetDNSTraceCollector) runTraceCommandOnPod(gadgetNa Stdout: stdout, Stderr: stderr, } + collectorGrp.Add(1) go func(podName string) { + defer collectorGrp.Done() request := clientset.CoreV1().RESTClient().Post(). Resource("pods"). Name(podName). @@ -166,21 +170,19 @@ func (collector *InspektorGadgetDNSTraceCollector) runTraceCommandOnPod(gadgetNa if err != nil { log.Printf("\tError creating SPDYExecutor for pod exec %q: %s", podName, err) - collector.data[fmt.Sprintf("dns-trace-%s-%s", gadgetName, podName)] = fmt.Sprintf("could not create SPDY executor: %v", err) return } err = exec.Stream(streamOptions) if err != nil { result := strings.TrimSpace(stdout.String()) + "\n" + strings.TrimSpace(stderr.String()) result = strings.TrimSpace(result) - collector.data[fmt.Sprintf("dns-trace-%s-%s", gadgetName, podName)] = "try a different pod" log.Printf("\tObtain DNS trace stream erred: %s, %s. Try a different pod ", podName, result) return } log.Printf("\tCollecting DNS trace stream from pod %s", podName) result := strings.TrimSpace(stdout.String()) + "\n" + strings.TrimSpace(stderr.String()) result = strings.TrimSpace(result) - collector.data[fmt.Sprintf("dns-trace-%s-%s", gadgetName, podName)] = result + collector.data[fmt.Sprintf("dns-trace-%s", podName)] = result log.Printf("\tCollected DNS trace stream from pod %s", podName) }(pod.Name) } @@ -188,7 +190,8 @@ func (collector *InspektorGadgetDNSTraceCollector) runTraceCommandOnPod(gadgetNa time.Sleep(10 * time.Second) err = gadgetClient.Delete(context.TODO(), trace) if err != nil { - log.Printf("could not stop trace %s: %w", trace.Name, err) + log.Printf("could not stop trace %s: %v", trace.Name, err) } + collectorGrp.Wait() return nil } From 1aa75b26dbd8b5f2f62c74a4f2f35220c806b265 Mon Sep 17 00:00:00 2001 From: Beilei Huang <41132767+bravebeaver@users.noreply.github.com> Date: Thu, 29 Sep 2022 18:38:45 +1300 Subject: [PATCH 07/27] dns needs a bit more time to collect --- .../inspecktor_trace_dns_collector.go | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/pkg/collector/inspecktor_trace_dns_collector.go b/pkg/collector/inspecktor_trace_dns_collector.go index c3b445f4..df34b74c 100644 --- a/pkg/collector/inspecktor_trace_dns_collector.go +++ b/pkg/collector/inspecktor_trace_dns_collector.go @@ -140,18 +140,20 @@ func (collector *InspektorGadgetDNSTraceCollector) runTraceCommandOnPod(gadgetNa var command = []string{"./bin/gadgettracermanager", "-call", "receive-stream", "-tracerid", fmt.Sprintf("trace_gadget_%s", gadgetName)} collectorGrp := new(sync.WaitGroup) + for _, pod := range gadgetPods.Items { - stdout := new(bytes.Buffer) - stderr := new(bytes.Buffer) - streamOptions := remotecommand.StreamOptions{ - Stdout: stdout, - Stderr: stderr, - } collectorGrp.Add(1) - go func(podName string) { defer collectorGrp.Done() + + stdout := new(bytes.Buffer) + stderr := new(bytes.Buffer) + streamOptions := remotecommand.StreamOptions{ + Stdout: stdout, + Stderr: stderr, + } + request := clientset.CoreV1().RESTClient().Post(). Resource("pods"). Name(podName). @@ -164,34 +166,39 @@ func (collector *InspektorGadgetDNSTraceCollector) runTraceCommandOnPod(gadgetNa TTY: false, Command: command, }, scheme.ParameterCodec) - //TODO start streaming when trace is started + log.Printf("\tPost request to DNS trace stream : %s ", request.URL()) exec, err := remotecommand.NewSPDYExecutor(collector.kubeconfig, "POST", request.URL()) if err != nil { - log.Printf("\tError creating SPDYExecutor for pod exec %q: %s", podName, err) + log.Printf("\tError creating SPDYExecutor for pod exec %q: %v", podName, err) return } + err = exec.Stream(streamOptions) if err != nil { - result := strings.TrimSpace(stdout.String()) + "\n" + strings.TrimSpace(stderr.String()) - result = strings.TrimSpace(result) - log.Printf("\tObtain DNS trace stream erred: %s, %s. Try a different pod ", podName, result) + log.Printf("\tObtain DNS trace stream erred: %s, %v. Try a different pod ", podName, err) return } + log.Printf("\tCollecting DNS trace stream from pod %s", podName) result := strings.TrimSpace(stdout.String()) + "\n" + strings.TrimSpace(stderr.String()) result = strings.TrimSpace(result) - collector.data[fmt.Sprintf("dns-trace-%s", podName)] = result + collector.data[fmt.Sprintf("%s-%s", gadgetName, podName)] = result log.Printf("\tCollected DNS trace stream from pod %s", podName) }(pod.Name) } + + //TODO kill in a proper way log.Printf("\twait for 10 seconds to stop collection dns trace") - time.Sleep(10 * time.Second) + time.Sleep(2 * time.Minute) err = gadgetClient.Delete(context.TODO(), trace) if err != nil { log.Printf("could not stop trace %s: %v", trace.Name, err) } + + // wait for the final result to be written collectorGrp.Wait() + return nil } From 96c9bf6ee3463771094a6b64af8102a7327fbbdb Mon Sep 17 00:00:00 2001 From: Beilei Huang <41132767+bravebeaver@users.noreply.github.com> Date: Wed, 5 Oct 2022 16:44:53 +1300 Subject: [PATCH 08/27] add tcp tracer --- cmd/aks-periscope/aks-periscope.go | 4 +- .../inspecktor_trace_collector.go} | 204 +++++++++--------- .../inspecktor_trace_dns_collector.go | 43 ++++ .../inspecktor_trace_tcp_collector.go | 44 ++++ .../tools-resources/chaos/block-dns-nwp.yaml | 11 + .../tools-resources/chaos/block-tcp.yaml | 17 ++ .../tools-resources/chaos/coredns.yaml | 16 ++ .../tools-resources/chaos/dnsutils.yaml | 16 ++ .../resources/tools-resources/chaos/readme.md | 3 + .../inspektor-gadget/tcp-trace.yaml | 12 ++ 10 files changed, 265 insertions(+), 105 deletions(-) rename pkg/collector/{inspecktor_trace_dns_collector.go => inspektor-gadget/inspecktor_trace_collector.go} (66%) create mode 100644 pkg/collector/inspektor-gadget/inspecktor_trace_dns_collector.go create mode 100644 pkg/collector/inspektor-gadget/inspecktor_trace_tcp_collector.go create mode 100644 pkg/test/resources/tools-resources/chaos/block-dns-nwp.yaml create mode 100644 pkg/test/resources/tools-resources/chaos/block-tcp.yaml create mode 100644 pkg/test/resources/tools-resources/chaos/coredns.yaml create mode 100644 pkg/test/resources/tools-resources/chaos/dnsutils.yaml create mode 100644 pkg/test/resources/tools-resources/chaos/readme.md create mode 100644 pkg/test/resources/tools-resources/inspektor-gadget/tcp-trace.yaml diff --git a/cmd/aks-periscope/aks-periscope.go b/cmd/aks-periscope/aks-periscope.go index 31db7248..ce2cc923 100644 --- a/cmd/aks-periscope/aks-periscope.go +++ b/cmd/aks-periscope/aks-periscope.go @@ -9,6 +9,7 @@ import ( "time" "github.com/Azure/aks-periscope/pkg/collector" + "github.com/Azure/aks-periscope/pkg/collector/inspektor-gadget" "github.com/Azure/aks-periscope/pkg/diagnoser" "github.com/Azure/aks-periscope/pkg/exporter" "github.com/Azure/aks-periscope/pkg/interfaces" @@ -98,7 +99,8 @@ func run(osIdentifier utils.OSIdentifier, knownFilePaths *utils.KnownFilePaths, collector.NewSystemLogsCollector(osIdentifier, runtimeInfo), collector.NewSystemPerfCollector(config, runtimeInfo), collector.NewWindowsLogsCollector(osIdentifier, runtimeInfo, knownFilePaths, fileSystem, 10*time.Second, 20*time.Minute), - collector.NewInspektorGadgetDNSTraceCollector(config, runtimeInfo), + inspektor_gadget.NewInspektorGadgetDNSTraceCollector(config, runtimeInfo), + inspektor_gadget.NewInspektorGadgetTCPTraceCollector(config, runtimeInfo), } collectorGrp := new(sync.WaitGroup) diff --git a/pkg/collector/inspecktor_trace_dns_collector.go b/pkg/collector/inspektor-gadget/inspecktor_trace_collector.go similarity index 66% rename from pkg/collector/inspecktor_trace_dns_collector.go rename to pkg/collector/inspektor-gadget/inspecktor_trace_collector.go index df34b74c..f9ca998f 100644 --- a/pkg/collector/inspecktor_trace_dns_collector.go +++ b/pkg/collector/inspektor-gadget/inspecktor_trace_collector.go @@ -1,4 +1,4 @@ -package collector +package inspektor_gadget import ( "bytes" @@ -27,106 +27,23 @@ const ( GadgetOperation = "gadget.kinvolk.io/operation" ) -// InspektorGadgetDNSTraceCollector defines a InspektorGadget Trace DNS Collector struct -type InspektorGadgetDNSTraceCollector struct { +func init() { + rand.Seed(time.Now().UnixNano()) +} + +// InspektorGadgetTraceCollector defines a InspektorGadget Trace Collector that are common to trace gadgets +type InspektorGadgetTraceCollector struct { data map[string]string kubeconfig *restclient.Config commandRunner *utils.KubeCommandRunner runtimeInfo *utils.RuntimeInfo } -// NewInspektorGadgetDNSTraceCollector is a constructor. -func NewInspektorGadgetDNSTraceCollector(config *restclient.Config, runtimeInfo *utils.RuntimeInfo) *InspektorGadgetDNSTraceCollector { - rand.Seed(time.Now().UnixNano()) - return &InspektorGadgetDNSTraceCollector{ - data: make(map[string]string), - kubeconfig: config, - commandRunner: utils.NewKubeCommandRunner(config), - runtimeInfo: runtimeInfo, - } -} - -func (collector *InspektorGadgetDNSTraceCollector) GetName() string { - return "inspektorgadget-dnstrace" -} - -func (collector *InspektorGadgetDNSTraceCollector) CheckSupported() error { - crds, err := collector.commandRunner.GetCRDUnstructuredList() - if err != nil { - return fmt.Errorf("error listing CRDs in cluster") - } - - for _, crd := range crds.Items { - if strings.Contains(crd.GetName(), "traces.gadget.kinvolk.io") { - return nil - } - } - return fmt.Errorf("does not contain gadget crd") -} - -// Collect implements the interface method -func (collector *InspektorGadgetDNSTraceCollector) Collect() error { - - gadgetScheme := runtime.NewScheme() - - err := gadgetv1alpha1.AddToScheme(gadgetScheme) - if err != nil { - return fmt.Errorf("could not add gadget scheme: %w", err) - } - - gadgetClient, err := runtimeclient.New(collector.kubeconfig, runtimeclient.Options{ - Scheme: gadgetScheme, - }) - if err != nil { - return fmt.Errorf("could not create rest client for gadgets: %w", err) - } - - // Create a dns gadget. - gadgetName := fmt.Sprintf("dns-%s", randomPodID()) - trace := &gadgetv1alpha1.Trace{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "gadget", - Annotations: map[string]string{ - GadgetOperation: string(gadgetv1alpha1.OperationStart), - }, - Name: gadgetName, - }, - Spec: gadgetv1alpha1.TraceSpec{ - Node: collector.runtimeInfo.HostNodeName, - Gadget: "dns", - RunMode: gadgetv1alpha1.RunModeManual, - OutputMode: gadgetv1alpha1.TraceOutputModeStream, - }, - } - err = gadgetClient.Create(context.TODO(), trace) - if err != nil { - return fmt.Errorf("could not create dns trace %s: %w", gadgetName, err) - } - - //collect output - err = collector.runTraceCommandOnPod(gadgetName, gadgetClient, trace) - if err != nil { - log.Printf("\t could not run trace : %s ", err) - return err - } - - return nil -} - -func (collector *InspektorGadgetDNSTraceCollector) GetData() map[string]interfaces.DataValue { - return utils.ToDataValueMap(collector.data) -} - -func randomPodID() string { - output := make([]byte, 5) - allowedCharacters := "0123456789abcdefghijklmnopqrstuvwxyz" - for i := range output { - output[i] = allowedCharacters[rand.Int31n(int32(len(allowedCharacters)))] - } - return string(output) -} +func (collector *InspektorGadgetTraceCollector) runTraceCommandOnPod(traceGadgetName string, + gadgetClient runtimeclient.Client, + trace *gadgetv1alpha1.Trace, + collectingPeriod time.Duration) error { -func (collector *InspektorGadgetDNSTraceCollector) runTraceCommandOnPod(gadgetName string, gadgetClient runtimeclient.Client, trace *gadgetv1alpha1.Trace) error { // Creates the clientset clientset, err := kubernetes.NewForConfig(collector.kubeconfig) if err != nil { @@ -137,7 +54,7 @@ func (collector *InspektorGadgetDNSTraceCollector) runTraceCommandOnPod(gadgetNa if err != nil { return fmt.Errorf("could not list gadget pods: %w", err) } - var command = []string{"./bin/gadgettracermanager", "-call", "receive-stream", "-tracerid", fmt.Sprintf("trace_gadget_%s", gadgetName)} + var command = []string{"./bin/gadgettracermanager", "-call", "receive-stream", "-tracerid", fmt.Sprintf("trace_gadget_%s", traceGadgetName)} collectorGrp := new(sync.WaitGroup) @@ -167,7 +84,7 @@ func (collector *InspektorGadgetDNSTraceCollector) runTraceCommandOnPod(gadgetNa Command: command, }, scheme.ParameterCodec) - log.Printf("\tPost request to DNS trace stream : %s ", request.URL()) + log.Printf("\tPost request to trace stream : %s ", request.URL()) exec, err := remotecommand.NewSPDYExecutor(collector.kubeconfig, "POST", request.URL()) if err != nil { @@ -177,24 +94,25 @@ func (collector *InspektorGadgetDNSTraceCollector) runTraceCommandOnPod(gadgetNa err = exec.Stream(streamOptions) if err != nil { - log.Printf("\tObtain DNS trace stream erred: %s, %v. Try a different pod ", podName, err) + log.Printf("\tObtain trace stream erred: %s, %v. Try a different pod ", podName, err) return } - log.Printf("\tCollecting DNS trace stream from pod %s", podName) + log.Printf("\tCollecting trace stream from pod %s", podName) result := strings.TrimSpace(stdout.String()) + "\n" + strings.TrimSpace(stderr.String()) result = strings.TrimSpace(result) - collector.data[fmt.Sprintf("%s-%s", gadgetName, podName)] = result - log.Printf("\tCollected DNS trace stream from pod %s", podName) + collector.data[fmt.Sprintf("%s-%s", traceGadgetName, podName)] = result + log.Printf("\tCollected trace stream from pod %s", podName) }(pod.Name) } - //TODO kill in a proper way - log.Printf("\twait for 10 seconds to stop collection dns trace") - time.Sleep(2 * time.Minute) + //TODO kill in a proper way by apply annotation + log.Printf("\twait for %v to stop collection", collectingPeriod) + time.Sleep(collectingPeriod) + err = gadgetClient.Delete(context.TODO(), trace) if err != nil { - log.Printf("could not stop trace %s: %v", trace.Name, err) + log.Printf("could not kill trace %s: %v", trace.Name, err) } // wait for the final result to be written @@ -202,3 +120,81 @@ func (collector *InspektorGadgetDNSTraceCollector) runTraceCommandOnPod(gadgetNa return nil } + +func (collector *InspektorGadgetTraceCollector) randomPodID() string { + output := make([]byte, 5) + allowedCharacters := "0123456789abcdefghijklmnopqrstuvwxyz" + for i := range output { + output[i] = allowedCharacters[rand.Int31n(int32(len(allowedCharacters)))] + } + return string(output) +} + +func (collector *InspektorGadgetTraceCollector) CheckSupported() error { + crds, err := collector.commandRunner.GetCRDUnstructuredList() + if err != nil { + return fmt.Errorf("error listing CRDs in cluster") + } + + for _, crd := range crds.Items { + if strings.Contains(crd.GetName(), "traces.gadget.kinvolk.io") { + return nil + } + } + return fmt.Errorf("does not contain gadget crd") +} + +func (collector *InspektorGadgetTraceCollector) GetData() map[string]interfaces.DataValue { + return utils.ToDataValueMap(collector.data) +} + +func (collector *InspektorGadgetTraceCollector) collect(gadgetName string, collectionPeriod time.Duration) error { + + gadgetScheme := runtime.NewScheme() + + err := gadgetv1alpha1.AddToScheme(gadgetScheme) + if err != nil { + return fmt.Errorf("could not add gadget scheme: %w", err) + } + + gadgetClient, err := runtimeclient.New(collector.kubeconfig, runtimeclient.Options{ + Scheme: gadgetScheme, + }) + if err != nil { + return fmt.Errorf("could not create rest client for gadgets: %w", err) + } + + // Create a gadget. + //TODO gadget name should be enum + traceGadgetName := fmt.Sprintf("%s-%s", gadgetName, collector.randomPodID()) + trace := &gadgetv1alpha1.Trace{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "gadget", + Annotations: map[string]string{ + GadgetOperation: string(gadgetv1alpha1.OperationStart), + }, + Name: traceGadgetName, + }, + Spec: gadgetv1alpha1.TraceSpec{ + Node: collector.runtimeInfo.HostNodeName, + Gadget: gadgetName, + RunMode: gadgetv1alpha1.RunModeManual, + OutputMode: gadgetv1alpha1.TraceOutputModeStream, + }, + } + err = gadgetClient.Create(context.TODO(), trace) + + if err != nil { + return fmt.Errorf("could not create trace %s: %w", traceGadgetName, err) + } + + //TODO watch the trace until it is started + //collect output + err = collector.runTraceCommandOnPod(traceGadgetName, gadgetClient, trace, collectionPeriod) + if err != nil { + log.Printf("\t could not run trace : %s ", err) + return err + } + + return nil +} diff --git a/pkg/collector/inspektor-gadget/inspecktor_trace_dns_collector.go b/pkg/collector/inspektor-gadget/inspecktor_trace_dns_collector.go new file mode 100644 index 00000000..34339420 --- /dev/null +++ b/pkg/collector/inspektor-gadget/inspecktor_trace_dns_collector.go @@ -0,0 +1,43 @@ +package inspektor_gadget + +import ( + "time" + + "github.com/Azure/aks-periscope/pkg/interfaces" + "github.com/Azure/aks-periscope/pkg/utils" + restclient "k8s.io/client-go/rest" +) + +// InspektorGadgetDNSTraceCollector defines a InspektorGadget Trace DNS Collector struct +type InspektorGadgetDNSTraceCollector struct { + tracerGadget *InspektorGadgetTraceCollector +} + +func (collector *InspektorGadgetDNSTraceCollector) Collect() error { + return collector.tracerGadget.collect("dns", 2*time.Minute) +} + +func (collector *InspektorGadgetDNSTraceCollector) GetData() map[string]interfaces.DataValue { + //TODO implement me + panic("implement me") +} + +func (collector *InspektorGadgetDNSTraceCollector) CheckSupported() error { + return collector.tracerGadget.CheckSupported() +} + +// NewInspektorGadgetDNSTraceCollector is a constructor. +func NewInspektorGadgetDNSTraceCollector(config *restclient.Config, runtimeInfo *utils.RuntimeInfo) *InspektorGadgetDNSTraceCollector { + return &InspektorGadgetDNSTraceCollector{ + tracerGadget: &InspektorGadgetTraceCollector{ + data: make(map[string]string), + kubeconfig: config, + commandRunner: utils.NewKubeCommandRunner(config), + runtimeInfo: runtimeInfo, + }, + } +} + +func (collector *InspektorGadgetDNSTraceCollector) GetName() string { + return "inspektorgadget-dnstrace" +} diff --git a/pkg/collector/inspektor-gadget/inspecktor_trace_tcp_collector.go b/pkg/collector/inspektor-gadget/inspecktor_trace_tcp_collector.go new file mode 100644 index 00000000..78592ac5 --- /dev/null +++ b/pkg/collector/inspektor-gadget/inspecktor_trace_tcp_collector.go @@ -0,0 +1,44 @@ +package inspektor_gadget + +import ( + "time" + + "github.com/Azure/aks-periscope/pkg/interfaces" + "github.com/Azure/aks-periscope/pkg/utils" + restclient "k8s.io/client-go/rest" +) + +// InspektorGadgetTCPTraceCollector defines a InspektorGadget Trace TCP Collector struct +type InspektorGadgetTCPTraceCollector struct { + tracerGadget *InspektorGadgetTraceCollector +} + +func (collector *InspektorGadgetTCPTraceCollector) CheckSupported() error { + return collector.tracerGadget.CheckSupported() +} + +// NewInspektorGadgetTCPTraceCollector is a constructor. +func NewInspektorGadgetTCPTraceCollector(config *restclient.Config, runtimeInfo *utils.RuntimeInfo) *InspektorGadgetTCPTraceCollector { + + return &InspektorGadgetTCPTraceCollector{ + tracerGadget: &InspektorGadgetTraceCollector{ + data: make(map[string]string), + kubeconfig: config, + commandRunner: utils.NewKubeCommandRunner(config), + runtimeInfo: runtimeInfo, + }, + } +} + +func (collector *InspektorGadgetTCPTraceCollector) GetName() string { + return "inspektorgadget-tcptrace" +} + +// Collect implements the interface method +func (collector *InspektorGadgetTCPTraceCollector) Collect() error { + return collector.tracerGadget.collect("tcptracer", 3*time.Minute) +} + +func (collector *InspektorGadgetTCPTraceCollector) GetData() map[string]interfaces.DataValue { + return collector.tracerGadget.GetData() +} diff --git a/pkg/test/resources/tools-resources/chaos/block-dns-nwp.yaml b/pkg/test/resources/tools-resources/chaos/block-dns-nwp.yaml new file mode 100644 index 00000000..9a36b264 --- /dev/null +++ b/pkg/test/resources/tools-resources/chaos/block-dns-nwp.yaml @@ -0,0 +1,11 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: deny-all-traffic + namespace: demo +spec: + podSelector: + matchLabels: + app: dns + policyTypes: + - Egress diff --git a/pkg/test/resources/tools-resources/chaos/block-tcp.yaml b/pkg/test/resources/tools-resources/chaos/block-tcp.yaml new file mode 100644 index 00000000..49614b05 --- /dev/null +++ b/pkg/test/resources/tools-resources/chaos/block-tcp.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: demo-policy + namespace: demo +spec: + podSelector: + matchLabels: + app: server + ingress: + - from: + - podSelector: + matchLabels: + app: client + ports: + - port: 80 + protocol: TCP \ No newline at end of file diff --git a/pkg/test/resources/tools-resources/chaos/coredns.yaml b/pkg/test/resources/tools-resources/chaos/coredns.yaml new file mode 100644 index 00000000..cd90bf7b --- /dev/null +++ b/pkg/test/resources/tools-resources/chaos/coredns.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: coredns-custom + namespace: kube-system + annotations: + kubectl.kubernetes.io/last-applied-configuration: poos and wees +data: + yourdns.server: | + .:53 { + health + + . { + whoami + } + } \ No newline at end of file diff --git a/pkg/test/resources/tools-resources/chaos/dnsutils.yaml b/pkg/test/resources/tools-resources/chaos/dnsutils.yaml new file mode 100644 index 00000000..1cd412e4 --- /dev/null +++ b/pkg/test/resources/tools-resources/chaos/dnsutils.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + name: dnsutils + namespace: demo + labels: + app: dns +spec: + containers: + - name: dnsutils + image: registry.k8s.io/e2e-test-images/jessie-dnsutils:1.3 + command: + - sleep + - "3600" + imagePullPolicy: IfNotPresent + restartPolicy: Always \ No newline at end of file diff --git a/pkg/test/resources/tools-resources/chaos/readme.md b/pkg/test/resources/tools-resources/chaos/readme.md new file mode 100644 index 00000000..9e0c30f0 --- /dev/null +++ b/pkg/test/resources/tools-resources/chaos/readme.md @@ -0,0 +1,3 @@ +# Chaos + +The folder contains configuration that can break your cluster. \ No newline at end of file diff --git a/pkg/test/resources/tools-resources/inspektor-gadget/tcp-trace.yaml b/pkg/test/resources/tools-resources/inspektor-gadget/tcp-trace.yaml new file mode 100644 index 00000000..6ec44b7d --- /dev/null +++ b/pkg/test/resources/tools-resources/inspektor-gadget/tcp-trace.yaml @@ -0,0 +1,12 @@ +apiVersion: gadget.kinvolk.io/v1alpha1 +kind: Trace +metadata: + name: tcptracer-t27aa + namespace: gadget + annotations: + gadget.kinvolk.io/operation: start +spec: + gadget: tcptracer + runMode: Manual + node: aks-nodepool1-11865456-vmss000000 + outputMode: Stream From 60ea45df353bfe9f968bddb2ac0bb89416a5b830 Mon Sep 17 00:00:00 2001 From: Beilei Huang <41132767+bravebeaver@users.noreply.github.com> Date: Wed, 5 Oct 2022 16:55:33 +1300 Subject: [PATCH 09/27] implement data exporter --- .../inspektor-gadget/inspecktor_trace_dns_collector.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/collector/inspektor-gadget/inspecktor_trace_dns_collector.go b/pkg/collector/inspektor-gadget/inspecktor_trace_dns_collector.go index 34339420..ae7e1366 100644 --- a/pkg/collector/inspektor-gadget/inspecktor_trace_dns_collector.go +++ b/pkg/collector/inspektor-gadget/inspecktor_trace_dns_collector.go @@ -18,8 +18,7 @@ func (collector *InspektorGadgetDNSTraceCollector) Collect() error { } func (collector *InspektorGadgetDNSTraceCollector) GetData() map[string]interfaces.DataValue { - //TODO implement me - panic("implement me") + return collector.tracerGadget.GetData() } func (collector *InspektorGadgetDNSTraceCollector) CheckSupported() error { From d4ee31241aa2b69a54ecf0c5f68357ef3bf8fb2c Mon Sep 17 00:00:00 2001 From: Beilei Huang <41132767+bravebeaver@users.noreply.github.com> Date: Wed, 5 Oct 2022 19:31:00 +1300 Subject: [PATCH 10/27] tidy up logging --- pkg/collector/inspektor-gadget/inspecktor_trace_collector.go | 4 ++-- .../inspektor-gadget/inspecktor_trace_tcp_collector.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/collector/inspektor-gadget/inspecktor_trace_collector.go b/pkg/collector/inspektor-gadget/inspecktor_trace_collector.go index f9ca998f..e2f1517d 100644 --- a/pkg/collector/inspektor-gadget/inspecktor_trace_collector.go +++ b/pkg/collector/inspektor-gadget/inspecktor_trace_collector.go @@ -98,11 +98,11 @@ func (collector *InspektorGadgetTraceCollector) runTraceCommandOnPod(traceGadget return } - log.Printf("\tCollecting trace stream from pod %s", podName) + log.Printf("\tCollecting trace stream %s from pod %s", traceGadgetName, podName) result := strings.TrimSpace(stdout.String()) + "\n" + strings.TrimSpace(stderr.String()) result = strings.TrimSpace(result) collector.data[fmt.Sprintf("%s-%s", traceGadgetName, podName)] = result - log.Printf("\tCollected trace stream from pod %s", podName) + log.Printf("\tCollected trace stream %s from pod %s", traceGadgetName, podName) }(pod.Name) } diff --git a/pkg/collector/inspektor-gadget/inspecktor_trace_tcp_collector.go b/pkg/collector/inspektor-gadget/inspecktor_trace_tcp_collector.go index 78592ac5..2bb6ad21 100644 --- a/pkg/collector/inspektor-gadget/inspecktor_trace_tcp_collector.go +++ b/pkg/collector/inspektor-gadget/inspecktor_trace_tcp_collector.go @@ -36,7 +36,7 @@ func (collector *InspektorGadgetTCPTraceCollector) GetName() string { // Collect implements the interface method func (collector *InspektorGadgetTCPTraceCollector) Collect() error { - return collector.tracerGadget.collect("tcptracer", 3*time.Minute) + return collector.tracerGadget.collect("tcptracer", 2*time.Minute) } func (collector *InspektorGadgetTCPTraceCollector) GetData() map[string]interfaces.DataValue { From 018a605bc0f7594f50c4166beee966fd16f4c1ac Mon Sep 17 00:00:00 2001 From: Beilei Huang <41132767+bravebeaver@users.noreply.github.com> Date: Thu, 6 Oct 2022 16:00:44 +1300 Subject: [PATCH 11/27] add readme --- .../inspecktor_trace_dns_collector.go | 22 +++++---- .../inspecktor_trace_tcp_collector.go | 2 + pkg/collector/inspektor-gadget/readme.md | 44 +++++++++++++++++ .../tools-resources/chaos/fio_configs.yaml | 24 +++++++++ .../chaos/fio_deployment_pvc.yaml | 49 +++++++++++++++++++ .../resources/tools-resources/chaos/readme.md | 3 -- 6 files changed, 132 insertions(+), 12 deletions(-) create mode 100644 pkg/collector/inspektor-gadget/readme.md create mode 100644 pkg/test/resources/tools-resources/chaos/fio_configs.yaml create mode 100644 pkg/test/resources/tools-resources/chaos/fio_deployment_pvc.yaml delete mode 100644 pkg/test/resources/tools-resources/chaos/readme.md diff --git a/pkg/collector/inspektor-gadget/inspecktor_trace_dns_collector.go b/pkg/collector/inspektor-gadget/inspecktor_trace_dns_collector.go index ae7e1366..eba2f5b3 100644 --- a/pkg/collector/inspektor-gadget/inspecktor_trace_dns_collector.go +++ b/pkg/collector/inspektor-gadget/inspecktor_trace_dns_collector.go @@ -13,20 +13,14 @@ type InspektorGadgetDNSTraceCollector struct { tracerGadget *InspektorGadgetTraceCollector } -func (collector *InspektorGadgetDNSTraceCollector) Collect() error { - return collector.tracerGadget.collect("dns", 2*time.Minute) -} - -func (collector *InspektorGadgetDNSTraceCollector) GetData() map[string]interfaces.DataValue { - return collector.tracerGadget.GetData() -} - +// CheckSupported implements the interface method func (collector *InspektorGadgetDNSTraceCollector) CheckSupported() error { return collector.tracerGadget.CheckSupported() } // NewInspektorGadgetDNSTraceCollector is a constructor. func NewInspektorGadgetDNSTraceCollector(config *restclient.Config, runtimeInfo *utils.RuntimeInfo) *InspektorGadgetDNSTraceCollector { + return &InspektorGadgetDNSTraceCollector{ tracerGadget: &InspektorGadgetTraceCollector{ data: make(map[string]string), @@ -38,5 +32,15 @@ func NewInspektorGadgetDNSTraceCollector(config *restclient.Config, runtimeInfo } func (collector *InspektorGadgetDNSTraceCollector) GetName() string { - return "inspektorgadget-dnstrace" + return "inspektorgadget-dns" +} + +// Collect implements the interface method +func (collector *InspektorGadgetDNSTraceCollector) Collect() error { + return collector.tracerGadget.collect("dns", 2*time.Minute) +} + +// GetData implements the interface method +func (collector *InspektorGadgetDNSTraceCollector) GetData() map[string]interfaces.DataValue { + return collector.tracerGadget.GetData() } diff --git a/pkg/collector/inspektor-gadget/inspecktor_trace_tcp_collector.go b/pkg/collector/inspektor-gadget/inspecktor_trace_tcp_collector.go index 2bb6ad21..05b101fc 100644 --- a/pkg/collector/inspektor-gadget/inspecktor_trace_tcp_collector.go +++ b/pkg/collector/inspektor-gadget/inspecktor_trace_tcp_collector.go @@ -13,6 +13,7 @@ type InspektorGadgetTCPTraceCollector struct { tracerGadget *InspektorGadgetTraceCollector } +// CheckSupported implements the interface method func (collector *InspektorGadgetTCPTraceCollector) CheckSupported() error { return collector.tracerGadget.CheckSupported() } @@ -39,6 +40,7 @@ func (collector *InspektorGadgetTCPTraceCollector) Collect() error { return collector.tracerGadget.collect("tcptracer", 2*time.Minute) } +// GetData implements the interface method func (collector *InspektorGadgetTCPTraceCollector) GetData() map[string]interfaces.DataValue { return collector.tracerGadget.GetData() } diff --git a/pkg/collector/inspektor-gadget/readme.md b/pkg/collector/inspektor-gadget/readme.md new file mode 100644 index 00000000..85696922 --- /dev/null +++ b/pkg/collector/inspektor-gadget/readme.md @@ -0,0 +1,44 @@ +# Inspektor Gadget Integration + +## develop locally + +It follows closely to the original developer approach. On top of kind cluster, a managed cluster can be used as well. +Be sure to allow the cluster to access the container image repository. In case of AKS and ACR, run +```bash +az aks update --name --resource-group --attach-acr +``` + +This section summarises the commands in order: +```shell +# after making your development changes +go build ./... +docker build -f ./builder/Dockerfile.linux -t periscope-local . +docker tag periscope-local .azurecr.io/periscope-local: +docker push .azurecr.io/periscope-local: +``` +update deployment/overlays/dev/kustomization.yaml to use the image such that +```yaml +images: +- name: periscope-linux + newName: .azurecr.io/periscope-local + newTag: +``` + +deploy the new version into your cluster +```shell +k apply -k ./deployment/overlays/dev +runId=$(date -u '+%Y-%m-%dT%H-%M-%SZ') +k patch configmap -n aks-periscope-dev diagnostic-config -p="{\"data\":{\"DIAGNOSTIC_RUN_ID\": \"$runId\"}}" +``` + +you can watch the logs of the periscope pods: +```shell +k -n aks-periscope-dev -l app=aks-periscope logs -f +``` +The logs should show that files are collected and written to the designated storage account. + + +## Chaos + +The [folder](pkg/test/resources/tools-resources/chaos) contains configuration that can break your cluster. +Use this to see whether the inspektor gadget can point out the problem. \ No newline at end of file diff --git a/pkg/test/resources/tools-resources/chaos/fio_configs.yaml b/pkg/test/resources/tools-resources/chaos/fio_configs.yaml new file mode 100644 index 00000000..865e642f --- /dev/null +++ b/pkg/test/resources/tools-resources/chaos/fio_configs.yaml @@ -0,0 +1,24 @@ +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: fio-job-config +data: + fio.job: |- + [global] + ioengine=psync + direct=1 + buffered=0 + size=10G + iodepth=1000 + numjobs=100 + group_reporting + refill_buffers + rwmixread=80 + norandommap + randrepeat=0 + percentage_random=0 + bs=512K + buffer_compress_percentage=50 + rw=read + [testjob] diff --git a/pkg/test/resources/tools-resources/chaos/fio_deployment_pvc.yaml b/pkg/test/resources/tools-resources/chaos/fio_deployment_pvc.yaml new file mode 100644 index 00000000..b2e393ac --- /dev/null +++ b/pkg/test/resources/tools-resources/chaos/fio_deployment_pvc.yaml @@ -0,0 +1,49 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: fio + labels: + app: fio +spec: + replicas: 3 + selector: + matchLabels: + app: fio + template: + metadata: + labels: + app: fio + spec: + containers: + - name: fio + image: joshuarobinson/fio:3.19 + command: ["sh"] + args: ["-c", "echo ${HOSTNAME} && mkdir -p /scratch/${HOSTNAME} && fio /configs/fio.job --eta=never --directory=/scratch/${HOSTNAME}"] + volumeMounts: + - name: fio-config-vol + mountPath: /configs + - name: fio-data + mountPath: /scratch + imagePullPolicy: Always + restartPolicy: Always + volumes: + - name: fio-config-vol + configMap: + name: fio-job-config + - name: fio-data + persistentVolumeClaim: + claimName: fio-claim +--- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: fio-claim +spec: + storageClassName: azuredisk-csi-premium-zrs + accessModes: + - ReadWriteMany + volumeMode: Block + resources: + requests: + storage: 1Ti diff --git a/pkg/test/resources/tools-resources/chaos/readme.md b/pkg/test/resources/tools-resources/chaos/readme.md deleted file mode 100644 index 9e0c30f0..00000000 --- a/pkg/test/resources/tools-resources/chaos/readme.md +++ /dev/null @@ -1,3 +0,0 @@ -# Chaos - -The folder contains configuration that can break your cluster. \ No newline at end of file From 534b14d7b32dfbbdb91d58b434f9b8be959eebaa Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Fri, 2 Dec 2022 15:47:39 +1300 Subject: [PATCH 12/27] try using IG packages directly --- cmd/aks-periscope/aks-periscope.go | 6 +- go.mod | 20 +- go.sum | 88 +++++ .../inspecktor_trace_dns_collector.go | 16 +- .../inspecktor_trace_dns_collector_test.go | 128 +++++++ .../inspecktor_trace_tcp_collector.go | 16 +- .../inspecktor_trace_collector.go | 324 ++++++++++-------- pkg/collector/inspektor-gadget/readme.md | 44 --- pkg/collector/kubeobjects_collector_test.go | 16 +- pkg/test/clusterFixture.go | 17 + pkg/test/clusterResourceManagement.go | 2 +- pkg/test/dockerImageManagement.go | 1 + .../tools-resources/chaos/block-dns-nwp.yaml | 7 +- 13 files changed, 447 insertions(+), 238 deletions(-) rename pkg/collector/{inspektor-gadget => }/inspecktor_trace_dns_collector.go (67%) create mode 100644 pkg/collector/inspecktor_trace_dns_collector_test.go rename pkg/collector/{inspektor-gadget => }/inspecktor_trace_tcp_collector.go (67%) delete mode 100644 pkg/collector/inspektor-gadget/readme.md diff --git a/cmd/aks-periscope/aks-periscope.go b/cmd/aks-periscope/aks-periscope.go index ce2cc923..247e86b3 100644 --- a/cmd/aks-periscope/aks-periscope.go +++ b/cmd/aks-periscope/aks-periscope.go @@ -9,7 +9,7 @@ import ( "time" "github.com/Azure/aks-periscope/pkg/collector" - "github.com/Azure/aks-periscope/pkg/collector/inspektor-gadget" + inspektor_gadget "github.com/Azure/aks-periscope/pkg/collector/inspektor-gadget" "github.com/Azure/aks-periscope/pkg/diagnoser" "github.com/Azure/aks-periscope/pkg/exporter" "github.com/Azure/aks-periscope/pkg/interfaces" @@ -99,8 +99,8 @@ func run(osIdentifier utils.OSIdentifier, knownFilePaths *utils.KnownFilePaths, collector.NewSystemLogsCollector(osIdentifier, runtimeInfo), collector.NewSystemPerfCollector(config, runtimeInfo), collector.NewWindowsLogsCollector(osIdentifier, runtimeInfo, knownFilePaths, fileSystem, 10*time.Second, 20*time.Minute), - inspektor_gadget.NewInspektorGadgetDNSTraceCollector(config, runtimeInfo), - inspektor_gadget.NewInspektorGadgetTCPTraceCollector(config, runtimeInfo), + inspektor_gadget.NewInspektorGadgetDNSTraceCollector(osIdentifier, config, runtimeInfo, 2*time.Minute), + inspektor_gadget.NewInspektorGadgetTCPTraceCollector(osIdentifier, config, runtimeInfo, 2*time.Minute), } collectorGrp := new(sync.WaitGroup) diff --git a/go.mod b/go.mod index b1cd5e66..9159c7da 100644 --- a/go.mod +++ b/go.mod @@ -6,18 +6,23 @@ go 1.19 require ( github.com/Azure/azure-storage-blob-go v0.14.0 + github.com/cilium/ebpf v0.9.3 github.com/docker/docker v20.10.17+incompatible + github.com/go-openapi/strfmt v0.19.5 // indirect + github.com/go-openapi/validate v0.19.8 // indirect github.com/google/uuid v1.2.0 github.com/hashicorp/go-multierror v1.1.1 helm.sh/helm/v3 v3.10.3 - k8s.io/api v0.25.2 - k8s.io/apimachinery v0.25.2 - k8s.io/cli-runtime v0.25.2 - k8s.io/client-go v0.25.2 + k8s.io/api v0.25.4 + k8s.io/apimachinery v0.25.4 + k8s.io/cli-runtime v0.25.4 + k8s.io/client-go v0.25.4 k8s.io/kubectl v0.25.2 k8s.io/metrics v0.25.2 ) +require github.com/inspektor-gadget/inspektor-gadget v0.12.1 + require ( github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect @@ -98,7 +103,7 @@ require ( github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.12.1 // indirect + github.com/prometheus/client_golang v1.12.2 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect @@ -119,10 +124,10 @@ require ( golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect - golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect + golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect - golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect + golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 // indirect google.golang.org/grpc v1.47.0 // indirect @@ -143,4 +148,3 @@ require ( sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) - diff --git a/go.sum b/go.sum index 5900da0f..774ae8f1 100644 --- a/go.sum +++ b/go.sum @@ -76,21 +76,26 @@ github.com/Masterminds/squirrel v1.5.3/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA4 github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/hcsshim v0.9.3 h1:k371PzBuRrz2b+ebGuI2nVgVhgsVX60jMfSw80NECxo= +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -112,6 +117,8 @@ github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHe github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.9.3 h1:5KtxXZU+scyERvkJMEm16TbScVvuuMrlhPly78ZMbSc= +github.com/cilium/ebpf v0.9.3/go.mod h1:w27N4UjpaQ9X/DGrSugxUG+H+NhgntDuPb5lCzxCn8A= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -151,6 +158,7 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= @@ -179,6 +187,8 @@ github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8S github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -196,14 +206,52 @@ github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7 github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= +github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= +github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= +github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= +github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= +github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= +github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= +github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= +github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= +github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= +github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= @@ -296,6 +344,7 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= @@ -346,6 +395,8 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inspektor-gadget/inspektor-gadget v0.12.1 h1:rJDc86ls4J3N4e9eWmiOSsIGt35ZBxzQoa9WBEQxkr8= +github.com/inspektor-gadget/inspektor-gadget v0.12.1/go.mod h1:nHHmmKxDgVoKm8ePfG2Z2OP2AZBCllwgwDrhfibcbDE= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -378,6 +429,7 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -392,8 +444,11 @@ github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= @@ -470,6 +525,7 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= @@ -492,6 +548,8 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= +github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -521,6 +579,7 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -550,6 +609,8 @@ github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -558,6 +619,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= @@ -582,6 +645,9 @@ go.etcd.io/etcd/api/v3 v3.5.4 h1:OHVyt3TopwtUQ2GKdd5wu3PmmipR4FTwCqoEjSyRdIc= go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -599,9 +665,12 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -647,12 +716,14 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -724,11 +795,13 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -781,6 +854,8 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI= +golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -799,8 +874,11 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U= +golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -810,6 +888,8 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -1006,16 +1086,24 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.25.2 h1:v6G8RyFcwf0HR5jQGIAYlvtRNrxMJQG1xJzaSeVnIS8= k8s.io/api v0.25.2/go.mod h1:qP1Rn4sCVFwx/xIhe+we2cwBLTXNcheRyYXwajonhy0= +k8s.io/api v0.25.4 h1:3YO8J4RtmG7elEgaWMb4HgmpS2CfY1QlaOz9nwB+ZSs= +k8s.io/api v0.25.4/go.mod h1:IG2+RzyPQLllQxnhzD8KQNEu4c4YvyDTpSMztf4A0OQ= k8s.io/apiextensions-apiserver v0.25.2 h1:8uOQX17RE7XL02ngtnh3TgifY7EhekpK+/piwzQNnBo= k8s.io/apiextensions-apiserver v0.25.2/go.mod h1:iRwwRDlWPfaHhuBfQ0WMa5skdQfrE18QXJaJvIDLvE8= k8s.io/apimachinery v0.25.2 h1:WbxfAjCx+AeN8Ilp9joWnyJ6xu9OMeS/fsfjK/5zaQs= k8s.io/apimachinery v0.25.2/go.mod h1:hqqA1X0bsgsxI6dXsJ4HnNTBOmJNxyPp8dw3u2fSHwA= +k8s.io/apimachinery v0.25.4 h1:CtXsuaitMESSu339tfhVXhQrPET+EiWnIY1rcurKnAc= +k8s.io/apimachinery v0.25.4/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo= k8s.io/apiserver v0.25.2 h1:YePimobk187IMIdnmsMxsfIbC5p4eX3WSOrS9x6FEYw= k8s.io/apiserver v0.25.2/go.mod h1:30r7xyQTREWCkG2uSjgjhQcKVvAAlqoD+YyrqR6Cn+I= k8s.io/cli-runtime v0.25.2 h1:XOx+SKRjBpYMLY/J292BHTkmyDffl/qOx3YSuFZkTuc= k8s.io/cli-runtime v0.25.2/go.mod h1:OQx3+/0st6x5YpkkJQlEWLC73V0wHsOFMC1/roxV8Oc= +k8s.io/cli-runtime v0.25.4 h1:GTSBN7aKBrc2LqpdO30CmHQqJtRmotxV7XsMSP+QZIk= +k8s.io/cli-runtime v0.25.4/go.mod h1:JGOw1CR8v4Mcz6cEKA7bFQe0bPrNn1l5sGAX1/Ke4Eg= k8s.io/client-go v0.25.2 h1:SUPp9p5CwM0yXGQrwYurw9LWz+YtMwhWd0GqOsSiefo= k8s.io/client-go v0.25.2/go.mod h1:i7cNU7N+yGQmJkewcRD2+Vuj4iz7b30kI8OcL3horQ4= +k8s.io/client-go v0.25.4 h1:3RNRDffAkNU56M/a7gUfXaEzdhZlYhoW8dgViGy5fn8= +k8s.io/client-go v0.25.4/go.mod h1:8trHCAC83XKY0wsBIpbirZU4NTUpbuhc2JnI7OruGZw= k8s.io/component-base v0.25.2 h1:Nve/ZyHLUBHz1rqwkjXm/Re6IniNa5k7KgzxZpTfSQY= k8s.io/component-base v0.25.2/go.mod h1:90W21YMr+Yjg7MX+DohmZLzjsBtaxQDDwaX4YxDkl60= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= diff --git a/pkg/collector/inspektor-gadget/inspecktor_trace_dns_collector.go b/pkg/collector/inspecktor_trace_dns_collector.go similarity index 67% rename from pkg/collector/inspektor-gadget/inspecktor_trace_dns_collector.go rename to pkg/collector/inspecktor_trace_dns_collector.go index eba2f5b3..027647c2 100644 --- a/pkg/collector/inspektor-gadget/inspecktor_trace_dns_collector.go +++ b/pkg/collector/inspecktor_trace_dns_collector.go @@ -1,4 +1,4 @@ -package inspektor_gadget +package collector import ( "time" @@ -19,14 +19,16 @@ func (collector *InspektorGadgetDNSTraceCollector) CheckSupported() error { } // NewInspektorGadgetDNSTraceCollector is a constructor. -func NewInspektorGadgetDNSTraceCollector(config *restclient.Config, runtimeInfo *utils.RuntimeInfo) *InspektorGadgetDNSTraceCollector { +func NewInspektorGadgetDNSTraceCollector(osIdentifier utils.OSIdentifier, config *restclient.Config, runtimeInfo *utils.RuntimeInfo, collectingPeriod time.Duration) *InspektorGadgetDNSTraceCollector { return &InspektorGadgetDNSTraceCollector{ tracerGadget: &InspektorGadgetTraceCollector{ - data: make(map[string]string), - kubeconfig: config, - commandRunner: utils.NewKubeCommandRunner(config), - runtimeInfo: runtimeInfo, + data: make(map[string]string), + osIdentifier: osIdentifier, + kubeconfig: config, + commandRunner: utils.NewKubeCommandRunner(config), + runtimeInfo: runtimeInfo, + collectingPeriod: collectingPeriod, }, } } @@ -37,7 +39,7 @@ func (collector *InspektorGadgetDNSTraceCollector) GetName() string { // Collect implements the interface method func (collector *InspektorGadgetDNSTraceCollector) Collect() error { - return collector.tracerGadget.collect("dns", 2*time.Minute) + return collector.tracerGadget.collect("dns") } // GetData implements the interface method diff --git a/pkg/collector/inspecktor_trace_dns_collector_test.go b/pkg/collector/inspecktor_trace_dns_collector_test.go new file mode 100644 index 00000000..38e2ec3f --- /dev/null +++ b/pkg/collector/inspecktor_trace_dns_collector_test.go @@ -0,0 +1,128 @@ +package collector + +import ( + "fmt" + "regexp" + "testing" + "time" + + "github.com/Azure/aks-periscope/pkg/test" + "github.com/Azure/aks-periscope/pkg/utils" + "k8s.io/client-go/rest" +) + +func TestInspektorGadgetDNSTraceCollectorGetName(t *testing.T) { + const expectedName = "inspektorgadget-dns" + + c := NewInspektorGadgetDNSTraceCollector("", nil, nil, 0) + actualName := c.GetName() + if actualName != expectedName { + t.Errorf("unexpected name: expected %s, found %s", expectedName, actualName) + } +} + +func TestInspektorGadgetDNSTraceCollectorCheckSupported(t *testing.T) { + fixture, _ := test.GetClusterFixture() + + // TODO: test absence of "traces.gadget.kinvolk.io" CRD (maybe by injecting expected CRD name into collector) + tests := []struct { + osIdentifier utils.OSIdentifier + wantErr bool + }{ + { + osIdentifier: utils.Windows, + wantErr: true, + }, + { + osIdentifier: utils.Linux, + wantErr: false, + }, + } + + for _, tt := range tests { + c := NewInspektorGadgetDNSTraceCollector(tt.osIdentifier, fixture.PeriscopeAccess.ClientConfig, nil, 0) + err := c.CheckSupported() + if (err != nil) != tt.wantErr { + t.Errorf("CheckSupported() error = %v, wantErr %v", err, tt.wantErr) + } + } +} + +func TestInspektorGadgetDNSTraceCollectorCollect(t *testing.T) { + fixture, _ := test.GetClusterFixture() + + nodeNames, err := fixture.GetNodeNames() + if err != nil { + t.Fatalf("Error getting node names: %v", err) + } + + tests := []struct { + name string + config *rest.Config + hostNodeName string + setupResources []string + wantErr bool + wantData map[string]*regexp.Regexp + }{ + { + name: "bad kubeconfig", + config: &rest.Config{Host: string([]byte{0})}, + hostNodeName: "", + setupResources: []string{}, + wantErr: true, + wantData: nil, + }, + { + name: "valid config", + config: fixture.PeriscopeAccess.ClientConfig, + hostNodeName: nodeNames[0], + setupResources: []string{}, + wantErr: false, + wantData: map[string]*regexp.Regexp{ + "gadget-dns": regexp.MustCompile(fmt.Sprintf(`^\s*{\s*"node":\s*"%s"`, nodeNames[0])), + }, + }, + { + name: "egress denied", + config: fixture.PeriscopeAccess.ClientConfig, + hostNodeName: nodeNames[0], + setupResources: []string{ + "/resources/chaos/block-dns-nwp.yaml", + }, + wantErr: false, + wantData: map[string]*regexp.Regexp{ + "gadget-dns": regexp.MustCompile(fmt.Sprintf(`^\s*{\s*"node":\s*"%s"`, nodeNames[0])), + }, + }, + } + + setupResources := func(command string, resources []string) { + for _, resourcePath := range resources { + installResourceCommand := fmt.Sprintf("kubectl %s -f %s", command, resourcePath) + _, err = fixture.CommandRunner.Run(installResourceCommand, fixture.AdminAccess.GetKubeConfigBinding()) + if err != nil { + t.Fatalf("Error installing resource %s: %v", resourcePath, err) + } + } + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + setupResources("create", tt.setupResources) + defer setupResources("delete", tt.setupResources) + + runtimeInfo := &utils.RuntimeInfo{ + HostNodeName: tt.hostNodeName, + } + + c := NewInspektorGadgetDNSTraceCollector(utils.Linux, tt.config, runtimeInfo, time.Second) + err := c.Collect() + + if (err != nil) != tt.wantErr { + t.Errorf("Collect() error = %v, wantErr %v", err, tt.wantErr) + } + data := c.GetData() + test.CompareCollectorData(t, tt.wantData, data) + }) + } +} diff --git a/pkg/collector/inspektor-gadget/inspecktor_trace_tcp_collector.go b/pkg/collector/inspecktor_trace_tcp_collector.go similarity index 67% rename from pkg/collector/inspektor-gadget/inspecktor_trace_tcp_collector.go rename to pkg/collector/inspecktor_trace_tcp_collector.go index 05b101fc..46c12db0 100644 --- a/pkg/collector/inspektor-gadget/inspecktor_trace_tcp_collector.go +++ b/pkg/collector/inspecktor_trace_tcp_collector.go @@ -1,4 +1,4 @@ -package inspektor_gadget +package collector import ( "time" @@ -19,14 +19,16 @@ func (collector *InspektorGadgetTCPTraceCollector) CheckSupported() error { } // NewInspektorGadgetTCPTraceCollector is a constructor. -func NewInspektorGadgetTCPTraceCollector(config *restclient.Config, runtimeInfo *utils.RuntimeInfo) *InspektorGadgetTCPTraceCollector { +func NewInspektorGadgetTCPTraceCollector(osIdentifier utils.OSIdentifier, config *restclient.Config, runtimeInfo *utils.RuntimeInfo, collectingPeriod time.Duration) *InspektorGadgetTCPTraceCollector { return &InspektorGadgetTCPTraceCollector{ tracerGadget: &InspektorGadgetTraceCollector{ - data: make(map[string]string), - kubeconfig: config, - commandRunner: utils.NewKubeCommandRunner(config), - runtimeInfo: runtimeInfo, + data: make(map[string]string), + osIdentifier: osIdentifier, + kubeconfig: config, + commandRunner: utils.NewKubeCommandRunner(config), + runtimeInfo: runtimeInfo, + collectingPeriod: collectingPeriod, }, } } @@ -37,7 +39,7 @@ func (collector *InspektorGadgetTCPTraceCollector) GetName() string { // Collect implements the interface method func (collector *InspektorGadgetTCPTraceCollector) Collect() error { - return collector.tracerGadget.collect("tcptracer", 2*time.Minute) + return collector.tracerGadget.collect("tcptracer") } // GetData implements the interface method diff --git a/pkg/collector/inspektor-gadget/inspecktor_trace_collector.go b/pkg/collector/inspektor-gadget/inspecktor_trace_collector.go index e2f1517d..00d3546c 100644 --- a/pkg/collector/inspektor-gadget/inspecktor_trace_collector.go +++ b/pkg/collector/inspektor-gadget/inspecktor_trace_collector.go @@ -1,136 +1,137 @@ package inspektor_gadget import ( - "bytes" - "context" "fmt" "log" - "math/rand" "strings" - "sync" "time" "github.com/Azure/aks-periscope/pkg/interfaces" "github.com/Azure/aks-periscope/pkg/utils" - gadgetv1alpha1 "github.com/kinvolk/inspektor-gadget/pkg/apis/gadget/v1alpha1" - "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/kubernetes/scheme" + "github.com/cilium/ebpf/rlimit" + "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/exec/tracer" + "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/exec/types" restclient "k8s.io/client-go/rest" - "k8s.io/client-go/tools/remotecommand" - runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" ) const ( GadgetOperation = "gadget.kinvolk.io/operation" ) -func init() { - rand.Seed(time.Now().UnixNano()) -} - // InspektorGadgetTraceCollector defines a InspektorGadget Trace Collector that are common to trace gadgets type InspektorGadgetTraceCollector struct { - data map[string]string - kubeconfig *restclient.Config - commandRunner *utils.KubeCommandRunner - runtimeInfo *utils.RuntimeInfo + data map[string]string + osIdentifier utils.OSIdentifier + kubeconfig *restclient.Config + commandRunner *utils.KubeCommandRunner + runtimeInfo *utils.RuntimeInfo + collectingPeriod time.Duration } -func (collector *InspektorGadgetTraceCollector) runTraceCommandOnPod(traceGadgetName string, - gadgetClient runtimeclient.Client, - trace *gadgetv1alpha1.Trace, - collectingPeriod time.Duration) error { - - // Creates the clientset - clientset, err := kubernetes.NewForConfig(collector.kubeconfig) - if err != nil { - return fmt.Errorf("getting access to K8S failed: %w", err) - } - - gadgetPods, err := clientset.CoreV1().Pods("gadget").List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return fmt.Errorf("could not list gadget pods: %w", err) - } - var command = []string{"./bin/gadgettracermanager", "-call", "receive-stream", "-tracerid", fmt.Sprintf("trace_gadget_%s", traceGadgetName)} - - collectorGrp := new(sync.WaitGroup) - - for _, pod := range gadgetPods.Items { - - collectorGrp.Add(1) - go func(podName string) { - defer collectorGrp.Done() - - stdout := new(bytes.Buffer) - stderr := new(bytes.Buffer) - streamOptions := remotecommand.StreamOptions{ - Stdout: stdout, - Stderr: stderr, - } - - request := clientset.CoreV1().RESTClient().Post(). - Resource("pods"). - Name(podName). - Namespace("gadget"). - SubResource("exec"). - VersionedParams(&v1.PodExecOptions{ - Stdin: false, - Stdout: true, - Stderr: true, - TTY: false, - Command: command, - }, scheme.ParameterCodec) - - log.Printf("\tPost request to trace stream : %s ", request.URL()) - exec, err := remotecommand.NewSPDYExecutor(collector.kubeconfig, "POST", request.URL()) - - if err != nil { - log.Printf("\tError creating SPDYExecutor for pod exec %q: %v", podName, err) - return - } - - err = exec.Stream(streamOptions) - if err != nil { - log.Printf("\tObtain trace stream erred: %s, %v. Try a different pod ", podName, err) - return - } - - log.Printf("\tCollecting trace stream %s from pod %s", traceGadgetName, podName) - result := strings.TrimSpace(stdout.String()) + "\n" + strings.TrimSpace(stderr.String()) - result = strings.TrimSpace(result) - collector.data[fmt.Sprintf("%s-%s", traceGadgetName, podName)] = result - log.Printf("\tCollected trace stream %s from pod %s", traceGadgetName, podName) - }(pod.Name) - } - - //TODO kill in a proper way by apply annotation - log.Printf("\twait for %v to stop collection", collectingPeriod) - time.Sleep(collectingPeriod) - - err = gadgetClient.Delete(context.TODO(), trace) - if err != nil { - log.Printf("could not kill trace %s: %v", trace.Name, err) - } - - // wait for the final result to be written - collectorGrp.Wait() - - return nil -} +// func (collector *InspektorGadgetTraceCollector) runTraceCommandOnPod(gadgetName string, gadgetClient runtimeclient.Client, trace string) error { + +// // Creates the clientset +// clientset, err := kubernetes.NewForConfig(collector.kubeconfig) +// if err != nil { +// return fmt.Errorf("getting access to K8S failed: %w", err) +// } + +// podName, err := collector.getGadgetPodName(clientset) +// if err != nil { +// return fmt.Errorf("failed to get gadget pod name: %w", err) +// } + +// traceName := collector.getTraceName(gadgetName) +// command := []string{"./bin/gadgettracermanager", "-call", "receive-stream", "-tracerid", fmt.Sprintf("trace_gadget_%s", traceName)} + +// collectChan := make(chan error) +// go func() { +// stdout := new(bytes.Buffer) +// stderr := new(bytes.Buffer) +// streamOptions := remotecommand.StreamOptions{ +// Stdout: stdout, +// Stderr: stderr, +// } + +// request := clientset.CoreV1().RESTClient().Post(). +// Resource("pods"). +// Name(podName). +// Namespace("gadget"). +// SubResource("exec"). +// VersionedParams(&v1.PodExecOptions{ +// Stdin: false, +// Stdout: true, +// Stderr: true, +// TTY: false, +// Command: command, +// }, scheme.ParameterCodec) + +// log.Printf("\tPost request to trace stream : %s ", request.URL()) +// exec, err := remotecommand.NewSPDYExecutor(collector.kubeconfig, "POST", request.URL()) +// if err != nil { +// collectChan <- fmt.Errorf("error creating SPDYExecutor for pod exec %q: %w", podName, err) +// return +// } + +// log.Printf("\tCollecting trace stream %s from pod %s", traceName, podName) +// err = exec.Stream(streamOptions) +// if err != nil { +// collectChan <- fmt.Errorf("error executing command %q on %s: %w\nOutput:\n%s", command, podName, err, stderr.String()) +// return +// } + +// log.Printf("\tCollected trace stream %s from pod %s", traceName, podName) +// result := strings.TrimSpace(stdout.String()) + "\n" + strings.TrimSpace(stderr.String()) + +// // Prefix the data key with 'gadget' to distinguish it from other collectors (e.g. the 'dns' collector). +// // We don't need the node, pod or trace name in the key, because results are output per-node, and there will +// // only be one trace for each gadget on each node. +// collector.data[fmt.Sprintf("gadget-%s", gadgetName)] = result +// collectChan <- nil +// }() + +// //TODO kill in a proper way by apply annotation +// log.Printf("\twait for %v to stop collection", collector.collectingPeriod) +// time.Sleep(collector.collectingPeriod) + +// err = gadgetClient.Delete(context.TODO(), trace) +// if err != nil { +// log.Printf("could not kill trace %s: %v", trace.Name, err) +// } + +// // wait for the final result to be written +// return <-collectChan +// } + +// getGadgetPodName gets the name of the 'gadget' pod that runs on the same node as this Periscope instance +// (Inspektor Gadget runs as a DaemonSet, so we expect there to be exactly one of these). +// func (collector *InspektorGadgetTraceCollector) getGadgetPodName(clientset *kubernetes.Clientset) (string, error) { +// gadgetPods, err := clientset.CoreV1().Pods("gadget").List(context.TODO(), metav1.ListOptions{}) +// if err != nil { +// return "", fmt.Errorf("could not list gadget pods: %w", err) +// } + +// for _, pod := range gadgetPods.Items { +// if pod.Spec.NodeName == collector.runtimeInfo.HostNodeName { +// return pod.Name, nil +// } +// } + +// return "", fmt.Errorf("no gadget pod found on node %q", collector.runtimeInfo.HostNodeName) +// } + +// func (collector *InspektorGadgetTraceCollector) getTraceName(gadgetName string) string { +// // There should be at most one trace for each gadget running on each node, so the combination of +// // gadget name and hostname should be sufficient to uniquely identify this trace. +// return fmt.Sprintf("%s-%s", gadgetName, collector.runtimeInfo.HostNodeName) +// } -func (collector *InspektorGadgetTraceCollector) randomPodID() string { - output := make([]byte, 5) - allowedCharacters := "0123456789abcdefghijklmnopqrstuvwxyz" - for i := range output { - output[i] = allowedCharacters[rand.Int31n(int32(len(allowedCharacters)))] +func (collector *InspektorGadgetTraceCollector) CheckSupported() error { + // Inspektor Gadget relies on eBPF which is not (currently) available on Windows nodes. + if collector.osIdentifier != utils.Linux { + return fmt.Errorf("unsupported OS: %s", collector.osIdentifier) } - return string(output) -} -func (collector *InspektorGadgetTraceCollector) CheckSupported() error { crds, err := collector.commandRunner.GetCRDUnstructuredList() if err != nil { return fmt.Errorf("error listing CRDs in cluster") @@ -148,53 +149,78 @@ func (collector *InspektorGadgetTraceCollector) GetData() map[string]interfaces. return utils.ToDataValueMap(collector.data) } -func (collector *InspektorGadgetTraceCollector) collect(gadgetName string, collectionPeriod time.Duration) error { - - gadgetScheme := runtime.NewScheme() - - err := gadgetv1alpha1.AddToScheme(gadgetScheme) - if err != nil { - return fmt.Errorf("could not add gadget scheme: %w", err) +func (collector *InspektorGadgetTraceCollector) collect(gadgetName string) error { + // From https://www.inspektor-gadget.io/blog/2022/09/using-inspektor-gadget-from-golang-applications/ + // In some kernel versions it's needed to bump the rlimits to + // use run BPF programs. + if err := rlimit.RemoveMemlock(); err != nil { + // Well...maybe we can continue anyway? No harm in trying. Log the error and continue. + log.Printf("\tcould not remove memlock: %v", err) } - gadgetClient, err := runtimeclient.New(collector.kubeconfig, runtimeclient.Options{ - Scheme: gadgetScheme, - }) - if err != nil { - return fmt.Errorf("could not create rest client for gadgets: %w", err) - } - - // Create a gadget. - //TODO gadget name should be enum - traceGadgetName := fmt.Sprintf("%s-%s", gadgetName, collector.randomPodID()) - trace := &gadgetv1alpha1.Trace{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "gadget", - Annotations: map[string]string{ - GadgetOperation: string(gadgetv1alpha1.OperationStart), - }, - Name: traceGadgetName, - }, - Spec: gadgetv1alpha1.TraceSpec{ - Node: collector.runtimeInfo.HostNodeName, - Gadget: gadgetName, - RunMode: gadgetv1alpha1.RunModeManual, - OutputMode: gadgetv1alpha1.TraceOutputModeStream, - }, + eventCallback := func(event types.Event) { + collector.data[gadgetName] = fmt.Sprintf("A new %q process with pid %d was executed\n", event.Comm, event.Pid) } - err = gadgetClient.Create(context.TODO(), trace) + tracer, err := tracer.NewTracer(&tracer.Config{}, nil, eventCallback) if err != nil { - return fmt.Errorf("could not create trace %s: %w", traceGadgetName, err) + return fmt.Errorf("could not create tracer: %w", err) } - //TODO watch the trace until it is started - //collect output - err = collector.runTraceCommandOnPod(traceGadgetName, gadgetClient, trace, collectionPeriod) - if err != nil { - log.Printf("\t could not run trace : %s ", err) - return err - } + defer tracer.Stop() + + log.Printf("\twait for %v to stop collection", collector.collectingPeriod) + time.Sleep(collector.collectingPeriod) return nil + + /////////////////////////////////////////////// + + // gadgetScheme := runtime.NewScheme() + + // err := gadgetv1alpha1.AddToScheme(gadgetScheme) + // if err != nil { + // return fmt.Errorf("could not add gadget scheme: %w", err) + // } + + // gadgetClient, err := runtimeclient.New(collector.kubeconfig, runtimeclient.Options{ + // Scheme: gadgetScheme, + // }) + // if err != nil { + // return fmt.Errorf("could not create rest client for gadgets: %w", err) + // } + + // // Create a gadget. + // //TODO gadget name should be enum + // traceName := collector.getTraceName(gadgetName) + // trace := &gadgetv1alpha1.Trace{ + // ObjectMeta: metav1.ObjectMeta{ + // Namespace: "gadget", + // Annotations: map[string]string{ + // GadgetOperation: string(gadgetv1alpha1.OperationStart), + // }, + // Name: traceName, + // }, + // Spec: gadgetv1alpha1.TraceSpec{ + // Node: collector.runtimeInfo.HostNodeName, + // Gadget: gadgetName, + // RunMode: gadgetv1alpha1.RunModeManual, + // OutputMode: gadgetv1alpha1.TraceOutputModeStream, + // }, + // } + // err = gadgetClient.Create(context.TODO(), trace) + + // if err != nil { + // return fmt.Errorf("could not create trace %s: %w", traceName, err) + // } + + // //TODO watch the trace until it is started + // //collect output + // err = collector.runTraceCommandOnPod(gadgetName, gadgetClient, trace) + // if err != nil { + // log.Printf("\t could not run trace : %s ", err) + // return err + // } + + // return nil } diff --git a/pkg/collector/inspektor-gadget/readme.md b/pkg/collector/inspektor-gadget/readme.md deleted file mode 100644 index 85696922..00000000 --- a/pkg/collector/inspektor-gadget/readme.md +++ /dev/null @@ -1,44 +0,0 @@ -# Inspektor Gadget Integration - -## develop locally - -It follows closely to the original developer approach. On top of kind cluster, a managed cluster can be used as well. -Be sure to allow the cluster to access the container image repository. In case of AKS and ACR, run -```bash -az aks update --name --resource-group --attach-acr -``` - -This section summarises the commands in order: -```shell -# after making your development changes -go build ./... -docker build -f ./builder/Dockerfile.linux -t periscope-local . -docker tag periscope-local .azurecr.io/periscope-local: -docker push .azurecr.io/periscope-local: -``` -update deployment/overlays/dev/kustomization.yaml to use the image such that -```yaml -images: -- name: periscope-linux - newName: .azurecr.io/periscope-local - newTag: -``` - -deploy the new version into your cluster -```shell -k apply -k ./deployment/overlays/dev -runId=$(date -u '+%Y-%m-%dT%H-%M-%SZ') -k patch configmap -n aks-periscope-dev diagnostic-config -p="{\"data\":{\"DIAGNOSTIC_RUN_ID\": \"$runId\"}}" -``` - -you can watch the logs of the periscope pods: -```shell -k -n aks-periscope-dev -l app=aks-periscope logs -f -``` -The logs should show that files are collected and written to the designated storage account. - - -## Chaos - -The [folder](pkg/test/resources/tools-resources/chaos) contains configuration that can break your cluster. -Use this to see whether the inspektor gadget can point out the problem. \ No newline at end of file diff --git a/pkg/collector/kubeobjects_collector_test.go b/pkg/collector/kubeobjects_collector_test.go index a094f5d6..fa3fe06d 100644 --- a/pkg/collector/kubeobjects_collector_test.go +++ b/pkg/collector/kubeobjects_collector_test.go @@ -68,20 +68,6 @@ func getDefaultKubeObjectResults(fixture *test.ClusterFixture) (map[string]*rege return results, nil } -func getNodeNames(fixture *test.ClusterFixture) ([]string, error) { - nodeList, err := fixture.AdminAccess.Clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return nil, fmt.Errorf("error listing nodes: %w", err) - } - - nodeNames := make([]string, len(nodeList.Items)) - for i, node := range nodeList.Items { - nodeNames[i] = node.Name - } - - return nodeNames, nil -} - func getNodeResults(nodeNames []string) map[string]*regexp.Regexp { results := map[string]*regexp.Regexp{} for _, nodeName := range nodeNames { @@ -111,7 +97,7 @@ func TestKubeObjectsCollectorCollect(t *testing.T) { t.Fatalf("Error determining expected results for default configuration: %v", err) } - nodeNames, err := getNodeNames(fixture) + nodeNames, err := fixture.GetNodeNames() if err != nil { t.Fatalf("Error getting node names: %v", err) } diff --git a/pkg/test/clusterFixture.go b/pkg/test/clusterFixture.go index e1bbd7a2..4e7e1daa 100644 --- a/pkg/test/clusterFixture.go +++ b/pkg/test/clusterFixture.go @@ -1,6 +1,7 @@ package test import ( + "context" "fmt" "log" "os" @@ -8,6 +9,7 @@ import ( "time" "github.com/docker/docker/client" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" @@ -95,6 +97,21 @@ func (fixture *ClusterFixture) PrintDiagnostics() { } } +// GetNodeNames retrieves the names of the nodes in the test cluster. +func (fixture *ClusterFixture) GetNodeNames() ([]string, error) { + nodeList, err := fixture.AdminAccess.Clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return nil, fmt.Errorf("error listing nodes: %w", err) + } + + nodeNames := make([]string, len(nodeList.Items)) + for i, node := range nodeList.Items { + nodeNames[i] = node.Name + } + + return nodeNames, nil +} + // GetKubeConfigBinding gets the Docker volume binding required to map the fixture's kubeconfig file // to the expected location in the testing tools container. func (clusterAccess *ClusterAccess) GetKubeConfigBinding() string { diff --git a/pkg/test/clusterResourceManagement.go b/pkg/test/clusterResourceManagement.go index bf8d6a27..1c4584fa 100644 --- a/pkg/test/clusterResourceManagement.go +++ b/pkg/test/clusterResourceManagement.go @@ -143,7 +143,7 @@ func deployOsmApplications(clientset *kubernetes.Clientset, commandRunner *Tools } command, binds = getDeployOsmAppsCommand(kubeConfigFile.Name(), knownNamespaces) - _, err = commandRunner.Run(command, binds...) + output, err = commandRunner.Run(command, binds...) fmt.Printf("%s\n%s\n\n", command, output) if err != nil { return fmt.Errorf("error installing applications for OSM: %w", err) diff --git a/pkg/test/dockerImageManagement.go b/pkg/test/dockerImageManagement.go index c1e907b1..b7adce05 100644 --- a/pkg/test/dockerImageManagement.go +++ b/pkg/test/dockerImageManagement.go @@ -112,6 +112,7 @@ func pullDockerImages(client *dockerclient.Client, imagesToPull []string) error pullOutput, err := client.ImagePull(context.Background(), image, dockertypes.ImagePullOptions{}) if err != nil { pullErrorsChan <- fmt.Errorf("error pulling image %s: %w", image, err) + return } defer pullOutput.Close() _, err = io.Copy(os.Stdout, pullOutput) diff --git a/pkg/test/resources/tools-resources/chaos/block-dns-nwp.yaml b/pkg/test/resources/tools-resources/chaos/block-dns-nwp.yaml index 9a36b264..4e796aa0 100644 --- a/pkg/test/resources/tools-resources/chaos/block-dns-nwp.yaml +++ b/pkg/test/resources/tools-resources/chaos/block-dns-nwp.yaml @@ -1,11 +1,10 @@ apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: - name: deny-all-traffic - namespace: demo + name: deny-all-egress + namespace: gadget spec: podSelector: - matchLabels: - app: dns + matchLabels: {} policyTypes: - Egress From 53862ab9d66a0e743bd5ccc48366b2b8010a6d3e Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Fri, 13 Jan 2023 17:36:08 +1300 Subject: [PATCH 13/27] try to add e2e tests --- .gitignore | 3 + .vscode/launch.json | 15 +- .vscode/tasks.json | 21 ++ cmd/aks-periscope/aks-periscope.go | 27 ++- go.mod | 2 - go.sum | 12 - .../gadget/inspektor_trace_collector.go | 71 ++++++ .../inspecktor_trace_dns_collector.go | 48 ---- .../inspecktor_trace_dns_collector_test.go | 128 ---------- .../inspecktor_trace_collector.go | 226 ------------------ .../inspektor_trace_dns_collector.go | 144 +++++++++++ .../inspektor_trace_dns_collector_test.go | 206 ++++++++++++++++ ...or.go => inspektor_trace_tcp_collector.go} | 32 ++- .../tools-resources/pause-daemonset.yaml | 24 ++ 14 files changed, 526 insertions(+), 433 deletions(-) create mode 100644 .vscode/tasks.json create mode 100644 pkg/collector/gadget/inspektor_trace_collector.go delete mode 100644 pkg/collector/inspecktor_trace_dns_collector.go delete mode 100644 pkg/collector/inspecktor_trace_dns_collector_test.go delete mode 100644 pkg/collector/inspektor-gadget/inspecktor_trace_collector.go create mode 100644 pkg/collector/inspektor_trace_dns_collector.go create mode 100644 pkg/collector/inspektor_trace_dns_collector_test.go rename pkg/collector/{inspecktor_trace_tcp_collector.go => inspektor_trace_tcp_collector.go} (55%) create mode 100644 pkg/test/resources/tools-resources/pause-daemonset.yaml diff --git a/.gitignore b/.gitignore index 02956036..4c816f75 100644 --- a/.gitignore +++ b/.gitignore @@ -344,3 +344,6 @@ deployment/overlays/temp # Local deployment configuration files **/.env **/.env.* + +# Test binaries +__debug_bin \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 16bcb143..b6a37144 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -18,12 +18,19 @@ "name": "Launch Tests with race check", "type": "go", "request": "launch", - "program": "${fileDirname}", - "mode": "test", + //"program": "${fileDirname}", + "program": "${fileDirname}/__debug_bin", + "mode": "exec", "env": {}, - "buildFlags": "-race", + //"buildFlags": "-race", "args": ["-test.v"], - "showLog": true + "showLog": true, + // https://github.com/golang/vscode-go/blob/master/docs/debugging.md#debug-a-package-test-as-root + "console": "integratedTerminal", + // "console": "externalTerminal", + "asRoot": true, + //"cwd": "${fileDirname}", + "preLaunchTask": "go test (debug)", }, ] } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..85542131 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,21 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "go test (debug)", + "type": "shell", + "command": "go", + "args": [ + "test", + "-race", + "-c", + "-gcflags=all=-N -l", + "-o", + "${fileDirname}/__debug_bin" + ], + "options": { + "cwd": "${fileDirname}" + } + } + ] +} \ No newline at end of file diff --git a/cmd/aks-periscope/aks-periscope.go b/cmd/aks-periscope/aks-periscope.go index 247e86b3..2b1c409e 100644 --- a/cmd/aks-periscope/aks-periscope.go +++ b/cmd/aks-periscope/aks-periscope.go @@ -9,11 +9,13 @@ import ( "time" "github.com/Azure/aks-periscope/pkg/collector" - inspektor_gadget "github.com/Azure/aks-periscope/pkg/collector/inspektor-gadget" "github.com/Azure/aks-periscope/pkg/diagnoser" "github.com/Azure/aks-periscope/pkg/exporter" "github.com/Azure/aks-periscope/pkg/interfaces" "github.com/Azure/aks-periscope/pkg/utils" + + containercollection "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection" + restclient "k8s.io/client-go/rest" ) @@ -81,6 +83,25 @@ func run(osIdentifier utils.OSIdentifier, knownFilePaths *utils.KnownFilePaths, } } + // Use the default InspektorGadget behaviour for determining containers: + // https://github.com/inspektor-gadget/inspektor-gadget/blob/6b00fea3f925c9da478126931e774e340ca9bfdf/pkg/gadgettracermanager/gadgettracermanager.go#L275-L283 + var containerCollectionOptions []containercollection.ContainerCollectionOption{ + if runcfanotify.Supported() { + containerCollectionOptions = []containercollection.ContainerCollectionOption{ + containercollection.WithRuncFanotify(), + containercollection.WithInitialKubernetesContainers(runtimeInfo.HostNodeName), + } + } else { + containerCollectionOptions = []containercollection.ContainerCollectionOption{ + containercollection.WithPodInformer(runtimeInfo.HostNodeName), + } + } + + waiter := func() { + log.Printf("\twait for %v to stop collection", collector.collectingPeriod) + time.Sleep(2*time.Minute) + } + dnsCollector := collector.NewDNSCollector(osIdentifier, knownFilePaths, fileSystem) kubeletCmdCollector := collector.NewKubeletCmdCollector(osIdentifier, runtimeInfo) networkOutboundCollector := collector.NewNetworkOutboundCollector() @@ -99,8 +120,8 @@ func run(osIdentifier utils.OSIdentifier, knownFilePaths *utils.KnownFilePaths, collector.NewSystemLogsCollector(osIdentifier, runtimeInfo), collector.NewSystemPerfCollector(config, runtimeInfo), collector.NewWindowsLogsCollector(osIdentifier, runtimeInfo, knownFilePaths, fileSystem, 10*time.Second, 20*time.Minute), - inspektor_gadget.NewInspektorGadgetDNSTraceCollector(osIdentifier, config, runtimeInfo, 2*time.Minute), - inspektor_gadget.NewInspektorGadgetTCPTraceCollector(osIdentifier, config, runtimeInfo, 2*time.Minute), + collector.NewInspektorGadgetDNSTraceCollector(osIdentifier, config, runtimeInfo, waiter, containerCollectionOptions), + collector.NewInspektorGadgetTCPTraceCollector(osIdentifier, config, runtimeInfo, 2*time.Minute), } collectorGrp := new(sync.WaitGroup) diff --git a/go.mod b/go.mod index 9159c7da..958242a7 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,6 @@ require ( github.com/Azure/azure-storage-blob-go v0.14.0 github.com/cilium/ebpf v0.9.3 github.com/docker/docker v20.10.17+incompatible - github.com/go-openapi/strfmt v0.19.5 // indirect - github.com/go-openapi/validate v0.19.8 // indirect github.com/google/uuid v1.2.0 github.com/hashicorp/go-multierror v1.1.1 helm.sh/helm/v3 v3.10.3 diff --git a/go.sum b/go.sum index 774ae8f1..d40e5612 100644 --- a/go.sum +++ b/go.sum @@ -158,7 +158,6 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= -github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= @@ -249,9 +248,6 @@ github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= -github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= -github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= @@ -344,7 +340,6 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= @@ -429,7 +424,6 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -448,7 +442,6 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= @@ -665,7 +658,6 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -723,7 +715,6 @@ golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -795,7 +786,6 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -888,8 +878,6 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= diff --git a/pkg/collector/gadget/inspektor_trace_collector.go b/pkg/collector/gadget/inspektor_trace_collector.go new file mode 100644 index 00000000..c93971c2 --- /dev/null +++ b/pkg/collector/gadget/inspektor_trace_collector.go @@ -0,0 +1,71 @@ +package gadget + +import ( + "fmt" + "log" + "strings" + "time" + + "github.com/Azure/aks-periscope/pkg/interfaces" + "github.com/Azure/aks-periscope/pkg/utils" + "github.com/cilium/ebpf/rlimit" + restclient "k8s.io/client-go/rest" +) + +const ( + GadgetOperation = "gadget.kinvolk.io/operation" +) + +// InspektorGadgetTraceCollector defines a InspektorGadget Trace Collector that are common to trace gadgets +type InspektorGadgetTraceCollector struct { + Data map[string]string + OsIdentifier utils.OSIdentifier + Kubeconfig *restclient.Config + CommandRunner *utils.KubeCommandRunner + RuntimeInfo *utils.RuntimeInfo + CollectingPeriod time.Duration +} + +type Tracer interface { + Stop() +} + +func (collector *InspektorGadgetTraceCollector) CheckSupported() error { + // Inspektor Gadget relies on eBPF which is not (currently) available on Windows nodes. + if collector.OsIdentifier != utils.Linux { + return fmt.Errorf("unsupported OS: %s", collector.OsIdentifier) + } + + crds, err := collector.CommandRunner.GetCRDUnstructuredList() + if err != nil { + return fmt.Errorf("error listing CRDs in cluster") + } + + for _, crd := range crds.Items { + if strings.Contains(crd.GetName(), "traces.gadget.kinvolk.io") { + return nil + } + } + return fmt.Errorf("does not contain gadget crd") +} + +func (collector *InspektorGadgetTraceCollector) GetData() map[string]interfaces.DataValue { + return utils.ToDataValueMap(collector.Data) +} + +func (collector *InspektorGadgetTraceCollector) Collect(gadgetName string, tracer Tracer) error { + // From https://www.inspektor-gadget.io/blog/2022/09/using-inspektor-gadget-from-golang-applications/ + // In some kernel versions it's needed to bump the rlimits to + // use run BPF programs. + if err := rlimit.RemoveMemlock(); err != nil { + // Well...maybe we can continue anyway? No harm in trying. Log the error and continue. + log.Printf("\tcould not remove memlock: %v", err) + } + + defer tracer.Stop() + + log.Printf("\twait for %v to stop collection", collector.CollectingPeriod) + time.Sleep(collector.CollectingPeriod) + + return nil +} diff --git a/pkg/collector/inspecktor_trace_dns_collector.go b/pkg/collector/inspecktor_trace_dns_collector.go deleted file mode 100644 index 027647c2..00000000 --- a/pkg/collector/inspecktor_trace_dns_collector.go +++ /dev/null @@ -1,48 +0,0 @@ -package collector - -import ( - "time" - - "github.com/Azure/aks-periscope/pkg/interfaces" - "github.com/Azure/aks-periscope/pkg/utils" - restclient "k8s.io/client-go/rest" -) - -// InspektorGadgetDNSTraceCollector defines a InspektorGadget Trace DNS Collector struct -type InspektorGadgetDNSTraceCollector struct { - tracerGadget *InspektorGadgetTraceCollector -} - -// CheckSupported implements the interface method -func (collector *InspektorGadgetDNSTraceCollector) CheckSupported() error { - return collector.tracerGadget.CheckSupported() -} - -// NewInspektorGadgetDNSTraceCollector is a constructor. -func NewInspektorGadgetDNSTraceCollector(osIdentifier utils.OSIdentifier, config *restclient.Config, runtimeInfo *utils.RuntimeInfo, collectingPeriod time.Duration) *InspektorGadgetDNSTraceCollector { - - return &InspektorGadgetDNSTraceCollector{ - tracerGadget: &InspektorGadgetTraceCollector{ - data: make(map[string]string), - osIdentifier: osIdentifier, - kubeconfig: config, - commandRunner: utils.NewKubeCommandRunner(config), - runtimeInfo: runtimeInfo, - collectingPeriod: collectingPeriod, - }, - } -} - -func (collector *InspektorGadgetDNSTraceCollector) GetName() string { - return "inspektorgadget-dns" -} - -// Collect implements the interface method -func (collector *InspektorGadgetDNSTraceCollector) Collect() error { - return collector.tracerGadget.collect("dns") -} - -// GetData implements the interface method -func (collector *InspektorGadgetDNSTraceCollector) GetData() map[string]interfaces.DataValue { - return collector.tracerGadget.GetData() -} diff --git a/pkg/collector/inspecktor_trace_dns_collector_test.go b/pkg/collector/inspecktor_trace_dns_collector_test.go deleted file mode 100644 index 38e2ec3f..00000000 --- a/pkg/collector/inspecktor_trace_dns_collector_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package collector - -import ( - "fmt" - "regexp" - "testing" - "time" - - "github.com/Azure/aks-periscope/pkg/test" - "github.com/Azure/aks-periscope/pkg/utils" - "k8s.io/client-go/rest" -) - -func TestInspektorGadgetDNSTraceCollectorGetName(t *testing.T) { - const expectedName = "inspektorgadget-dns" - - c := NewInspektorGadgetDNSTraceCollector("", nil, nil, 0) - actualName := c.GetName() - if actualName != expectedName { - t.Errorf("unexpected name: expected %s, found %s", expectedName, actualName) - } -} - -func TestInspektorGadgetDNSTraceCollectorCheckSupported(t *testing.T) { - fixture, _ := test.GetClusterFixture() - - // TODO: test absence of "traces.gadget.kinvolk.io" CRD (maybe by injecting expected CRD name into collector) - tests := []struct { - osIdentifier utils.OSIdentifier - wantErr bool - }{ - { - osIdentifier: utils.Windows, - wantErr: true, - }, - { - osIdentifier: utils.Linux, - wantErr: false, - }, - } - - for _, tt := range tests { - c := NewInspektorGadgetDNSTraceCollector(tt.osIdentifier, fixture.PeriscopeAccess.ClientConfig, nil, 0) - err := c.CheckSupported() - if (err != nil) != tt.wantErr { - t.Errorf("CheckSupported() error = %v, wantErr %v", err, tt.wantErr) - } - } -} - -func TestInspektorGadgetDNSTraceCollectorCollect(t *testing.T) { - fixture, _ := test.GetClusterFixture() - - nodeNames, err := fixture.GetNodeNames() - if err != nil { - t.Fatalf("Error getting node names: %v", err) - } - - tests := []struct { - name string - config *rest.Config - hostNodeName string - setupResources []string - wantErr bool - wantData map[string]*regexp.Regexp - }{ - { - name: "bad kubeconfig", - config: &rest.Config{Host: string([]byte{0})}, - hostNodeName: "", - setupResources: []string{}, - wantErr: true, - wantData: nil, - }, - { - name: "valid config", - config: fixture.PeriscopeAccess.ClientConfig, - hostNodeName: nodeNames[0], - setupResources: []string{}, - wantErr: false, - wantData: map[string]*regexp.Regexp{ - "gadget-dns": regexp.MustCompile(fmt.Sprintf(`^\s*{\s*"node":\s*"%s"`, nodeNames[0])), - }, - }, - { - name: "egress denied", - config: fixture.PeriscopeAccess.ClientConfig, - hostNodeName: nodeNames[0], - setupResources: []string{ - "/resources/chaos/block-dns-nwp.yaml", - }, - wantErr: false, - wantData: map[string]*regexp.Regexp{ - "gadget-dns": regexp.MustCompile(fmt.Sprintf(`^\s*{\s*"node":\s*"%s"`, nodeNames[0])), - }, - }, - } - - setupResources := func(command string, resources []string) { - for _, resourcePath := range resources { - installResourceCommand := fmt.Sprintf("kubectl %s -f %s", command, resourcePath) - _, err = fixture.CommandRunner.Run(installResourceCommand, fixture.AdminAccess.GetKubeConfigBinding()) - if err != nil { - t.Fatalf("Error installing resource %s: %v", resourcePath, err) - } - } - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - setupResources("create", tt.setupResources) - defer setupResources("delete", tt.setupResources) - - runtimeInfo := &utils.RuntimeInfo{ - HostNodeName: tt.hostNodeName, - } - - c := NewInspektorGadgetDNSTraceCollector(utils.Linux, tt.config, runtimeInfo, time.Second) - err := c.Collect() - - if (err != nil) != tt.wantErr { - t.Errorf("Collect() error = %v, wantErr %v", err, tt.wantErr) - } - data := c.GetData() - test.CompareCollectorData(t, tt.wantData, data) - }) - } -} diff --git a/pkg/collector/inspektor-gadget/inspecktor_trace_collector.go b/pkg/collector/inspektor-gadget/inspecktor_trace_collector.go deleted file mode 100644 index 00d3546c..00000000 --- a/pkg/collector/inspektor-gadget/inspecktor_trace_collector.go +++ /dev/null @@ -1,226 +0,0 @@ -package inspektor_gadget - -import ( - "fmt" - "log" - "strings" - "time" - - "github.com/Azure/aks-periscope/pkg/interfaces" - "github.com/Azure/aks-periscope/pkg/utils" - "github.com/cilium/ebpf/rlimit" - "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/exec/tracer" - "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/exec/types" - restclient "k8s.io/client-go/rest" -) - -const ( - GadgetOperation = "gadget.kinvolk.io/operation" -) - -// InspektorGadgetTraceCollector defines a InspektorGadget Trace Collector that are common to trace gadgets -type InspektorGadgetTraceCollector struct { - data map[string]string - osIdentifier utils.OSIdentifier - kubeconfig *restclient.Config - commandRunner *utils.KubeCommandRunner - runtimeInfo *utils.RuntimeInfo - collectingPeriod time.Duration -} - -// func (collector *InspektorGadgetTraceCollector) runTraceCommandOnPod(gadgetName string, gadgetClient runtimeclient.Client, trace string) error { - -// // Creates the clientset -// clientset, err := kubernetes.NewForConfig(collector.kubeconfig) -// if err != nil { -// return fmt.Errorf("getting access to K8S failed: %w", err) -// } - -// podName, err := collector.getGadgetPodName(clientset) -// if err != nil { -// return fmt.Errorf("failed to get gadget pod name: %w", err) -// } - -// traceName := collector.getTraceName(gadgetName) -// command := []string{"./bin/gadgettracermanager", "-call", "receive-stream", "-tracerid", fmt.Sprintf("trace_gadget_%s", traceName)} - -// collectChan := make(chan error) -// go func() { -// stdout := new(bytes.Buffer) -// stderr := new(bytes.Buffer) -// streamOptions := remotecommand.StreamOptions{ -// Stdout: stdout, -// Stderr: stderr, -// } - -// request := clientset.CoreV1().RESTClient().Post(). -// Resource("pods"). -// Name(podName). -// Namespace("gadget"). -// SubResource("exec"). -// VersionedParams(&v1.PodExecOptions{ -// Stdin: false, -// Stdout: true, -// Stderr: true, -// TTY: false, -// Command: command, -// }, scheme.ParameterCodec) - -// log.Printf("\tPost request to trace stream : %s ", request.URL()) -// exec, err := remotecommand.NewSPDYExecutor(collector.kubeconfig, "POST", request.URL()) -// if err != nil { -// collectChan <- fmt.Errorf("error creating SPDYExecutor for pod exec %q: %w", podName, err) -// return -// } - -// log.Printf("\tCollecting trace stream %s from pod %s", traceName, podName) -// err = exec.Stream(streamOptions) -// if err != nil { -// collectChan <- fmt.Errorf("error executing command %q on %s: %w\nOutput:\n%s", command, podName, err, stderr.String()) -// return -// } - -// log.Printf("\tCollected trace stream %s from pod %s", traceName, podName) -// result := strings.TrimSpace(stdout.String()) + "\n" + strings.TrimSpace(stderr.String()) - -// // Prefix the data key with 'gadget' to distinguish it from other collectors (e.g. the 'dns' collector). -// // We don't need the node, pod or trace name in the key, because results are output per-node, and there will -// // only be one trace for each gadget on each node. -// collector.data[fmt.Sprintf("gadget-%s", gadgetName)] = result -// collectChan <- nil -// }() - -// //TODO kill in a proper way by apply annotation -// log.Printf("\twait for %v to stop collection", collector.collectingPeriod) -// time.Sleep(collector.collectingPeriod) - -// err = gadgetClient.Delete(context.TODO(), trace) -// if err != nil { -// log.Printf("could not kill trace %s: %v", trace.Name, err) -// } - -// // wait for the final result to be written -// return <-collectChan -// } - -// getGadgetPodName gets the name of the 'gadget' pod that runs on the same node as this Periscope instance -// (Inspektor Gadget runs as a DaemonSet, so we expect there to be exactly one of these). -// func (collector *InspektorGadgetTraceCollector) getGadgetPodName(clientset *kubernetes.Clientset) (string, error) { -// gadgetPods, err := clientset.CoreV1().Pods("gadget").List(context.TODO(), metav1.ListOptions{}) -// if err != nil { -// return "", fmt.Errorf("could not list gadget pods: %w", err) -// } - -// for _, pod := range gadgetPods.Items { -// if pod.Spec.NodeName == collector.runtimeInfo.HostNodeName { -// return pod.Name, nil -// } -// } - -// return "", fmt.Errorf("no gadget pod found on node %q", collector.runtimeInfo.HostNodeName) -// } - -// func (collector *InspektorGadgetTraceCollector) getTraceName(gadgetName string) string { -// // There should be at most one trace for each gadget running on each node, so the combination of -// // gadget name and hostname should be sufficient to uniquely identify this trace. -// return fmt.Sprintf("%s-%s", gadgetName, collector.runtimeInfo.HostNodeName) -// } - -func (collector *InspektorGadgetTraceCollector) CheckSupported() error { - // Inspektor Gadget relies on eBPF which is not (currently) available on Windows nodes. - if collector.osIdentifier != utils.Linux { - return fmt.Errorf("unsupported OS: %s", collector.osIdentifier) - } - - crds, err := collector.commandRunner.GetCRDUnstructuredList() - if err != nil { - return fmt.Errorf("error listing CRDs in cluster") - } - - for _, crd := range crds.Items { - if strings.Contains(crd.GetName(), "traces.gadget.kinvolk.io") { - return nil - } - } - return fmt.Errorf("does not contain gadget crd") -} - -func (collector *InspektorGadgetTraceCollector) GetData() map[string]interfaces.DataValue { - return utils.ToDataValueMap(collector.data) -} - -func (collector *InspektorGadgetTraceCollector) collect(gadgetName string) error { - // From https://www.inspektor-gadget.io/blog/2022/09/using-inspektor-gadget-from-golang-applications/ - // In some kernel versions it's needed to bump the rlimits to - // use run BPF programs. - if err := rlimit.RemoveMemlock(); err != nil { - // Well...maybe we can continue anyway? No harm in trying. Log the error and continue. - log.Printf("\tcould not remove memlock: %v", err) - } - - eventCallback := func(event types.Event) { - collector.data[gadgetName] = fmt.Sprintf("A new %q process with pid %d was executed\n", event.Comm, event.Pid) - } - - tracer, err := tracer.NewTracer(&tracer.Config{}, nil, eventCallback) - if err != nil { - return fmt.Errorf("could not create tracer: %w", err) - } - - defer tracer.Stop() - - log.Printf("\twait for %v to stop collection", collector.collectingPeriod) - time.Sleep(collector.collectingPeriod) - - return nil - - /////////////////////////////////////////////// - - // gadgetScheme := runtime.NewScheme() - - // err := gadgetv1alpha1.AddToScheme(gadgetScheme) - // if err != nil { - // return fmt.Errorf("could not add gadget scheme: %w", err) - // } - - // gadgetClient, err := runtimeclient.New(collector.kubeconfig, runtimeclient.Options{ - // Scheme: gadgetScheme, - // }) - // if err != nil { - // return fmt.Errorf("could not create rest client for gadgets: %w", err) - // } - - // // Create a gadget. - // //TODO gadget name should be enum - // traceName := collector.getTraceName(gadgetName) - // trace := &gadgetv1alpha1.Trace{ - // ObjectMeta: metav1.ObjectMeta{ - // Namespace: "gadget", - // Annotations: map[string]string{ - // GadgetOperation: string(gadgetv1alpha1.OperationStart), - // }, - // Name: traceName, - // }, - // Spec: gadgetv1alpha1.TraceSpec{ - // Node: collector.runtimeInfo.HostNodeName, - // Gadget: gadgetName, - // RunMode: gadgetv1alpha1.RunModeManual, - // OutputMode: gadgetv1alpha1.TraceOutputModeStream, - // }, - // } - // err = gadgetClient.Create(context.TODO(), trace) - - // if err != nil { - // return fmt.Errorf("could not create trace %s: %w", traceName, err) - // } - - // //TODO watch the trace until it is started - // //collect output - // err = collector.runTraceCommandOnPod(gadgetName, gadgetClient, trace) - // if err != nil { - // log.Printf("\t could not run trace : %s ", err) - // return err - // } - - // return nil -} diff --git a/pkg/collector/inspektor_trace_dns_collector.go b/pkg/collector/inspektor_trace_dns_collector.go new file mode 100644 index 00000000..c4dfb48f --- /dev/null +++ b/pkg/collector/inspektor_trace_dns_collector.go @@ -0,0 +1,144 @@ +package collector + +import ( + "fmt" + "log" + "strings" + "sync" + + "github.com/Azure/aks-periscope/pkg/interfaces" + "github.com/Azure/aks-periscope/pkg/utils" + "github.com/cilium/ebpf/rlimit" + containercollection "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection" + "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection/networktracer" + "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/dns/tracer" + dnstypes "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/dns/types" + eventtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types" + + restclient "k8s.io/client-go/rest" +) + +// InspektorGadgetDNSTraceCollector defines a InspektorGadget Trace DNS Collector struct +type InspektorGadgetDNSTraceCollector struct { + data map[string]string + osIdentifier utils.OSIdentifier + kubeconfig *restclient.Config + runtimeInfo *utils.RuntimeInfo + waiter func() + containerCollectionOptions []containercollection.ContainerCollectionOption +} + +// CheckSupported implements the interface method +func (collector *InspektorGadgetDNSTraceCollector) CheckSupported() error { + // Inspektor Gadget relies on eBPF which is not (currently) available on Windows nodes. + if collector.osIdentifier != utils.Linux { + return fmt.Errorf("unsupported OS: %s", collector.osIdentifier) + } + return nil +} + +// NewInspektorGadgetDNSTraceCollector is a constructor. +func NewInspektorGadgetDNSTraceCollector( + osIdentifier utils.OSIdentifier, + config *restclient.Config, + runtimeInfo *utils.RuntimeInfo, + waiter func(), + containerCollectionOptions []containercollection.ContainerCollectionOption, +) *InspektorGadgetDNSTraceCollector { + return &InspektorGadgetDNSTraceCollector{ + data: make(map[string]string), + osIdentifier: osIdentifier, + kubeconfig: config, + runtimeInfo: runtimeInfo, + waiter: waiter, + containerCollectionOptions: containerCollectionOptions, + } +} + +func (collector *InspektorGadgetDNSTraceCollector) GetName() string { + return "inspektorgadget-dns" +} + +// Collect implements the interface method +func (collector *InspektorGadgetDNSTraceCollector) Collect() error { + // From https://www.inspektor-gadget.io/blog/2022/09/using-inspektor-gadget-from-golang-applications/ + // In some kernel versions it's needed to bump the rlimits to + // use run BPF programs. + if err := rlimit.RemoveMemlock(); err != nil { + return fmt.Errorf("failed to remove memlock: %w", err) + } + + tracer, err := tracer.NewTracer() + if err != nil { + return fmt.Errorf("failed to start dns tracer: %w", err) + } + defer tracer.Close() + + nodeName := collector.runtimeInfo.HostNodeName + + var mu sync.Mutex + events := []string{} + + eventCallback := func(container *containercollection.Container, event dnstypes.Event) { + // Enrich event with data from container + event.Node = nodeName + if !container.HostNetwork { + event.Namespace = container.Namespace + event.Pod = container.Podname + event.Container = container.Name + } + + eventString := eventtypes.EventString(event) + + mu.Lock() + defer mu.Unlock() + events = append(events, eventString) + } + + callback := func(event containercollection.PubSubEvent) { + // This doesn't *do* anything, but there will be runtime errors if we don't supply a callback. + log.Printf("Container event %q:\n\t%s", event.Type, eventtypes.EventString(event.Container)) + } + + opts := append(collector.containerCollectionOptions, + containercollection.WithPubSub(callback), + containercollection.WithNodeName(nodeName), + containercollection.WithCgroupEnrichment(), + containercollection.WithLinuxNamespaceEnrichment(), + containercollection.WithKubernetesEnrichment(nodeName, collector.kubeconfig), + ) + + containerCollection := &containercollection.ContainerCollection{} + if err = containerCollection.Initialize(opts...); err != nil { + return fmt.Errorf("failed to initialize container collection: %w", err) + } + defer containerCollection.Close() + + config := &networktracer.ConnectToContainerCollectionConfig[dnstypes.Event]{ + Tracer: tracer, + Resolver: containerCollection, + Selector: containercollection.ContainerSelector{}, + EventCallback: eventCallback, + Base: dnstypes.Base, + } + + conn, err := networktracer.ConnectToContainerCollection(config) + if err != nil { + return fmt.Errorf("failed to connect network tracer: %w", err) + } + defer conn.Close() + + collector.waiter() + + mu.Lock() + defer mu.Unlock() + collector.data["dnstracer"] = strings.Join(events, "\n") + log.Print(collector.data["dnstracer"]) + + return nil +} + +// GetData implements the interface method +func (collector *InspektorGadgetDNSTraceCollector) GetData() map[string]interfaces.DataValue { + return utils.ToDataValueMap(collector.data) +} diff --git a/pkg/collector/inspektor_trace_dns_collector_test.go b/pkg/collector/inspektor_trace_dns_collector_test.go new file mode 100644 index 00000000..5037a2c5 --- /dev/null +++ b/pkg/collector/inspektor_trace_dns_collector_test.go @@ -0,0 +1,206 @@ +package collector + +import ( + "context" + "fmt" + "net" + "os" + "regexp" + "strings" + "testing" + + "github.com/Azure/aks-periscope/pkg/test" + "github.com/Azure/aks-periscope/pkg/utils" + containercollection "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection" + ocispec "github.com/opencontainers/runtime-spec/specs-go" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" + "k8s.io/client-go/rest" +) + +func TestInspektorGadgetDNSTraceCollectorGetName(t *testing.T) { + const expectedName = "inspektorgadget-dns" + + c := NewInspektorGadgetDNSTraceCollector("", nil, nil, nil, []containercollection.ContainerCollectionOption{}) + actualName := c.GetName() + if actualName != expectedName { + t.Errorf("unexpected name: expected %s, found %s", expectedName, actualName) + } +} + +func TestInspektorGadgetDNSTraceCollectorCheckSupported(t *testing.T) { + fixture, _ := test.GetClusterFixture() + + tests := []struct { + osIdentifier utils.OSIdentifier + wantErr bool + }{ + { + osIdentifier: utils.Windows, + wantErr: true, + }, + { + osIdentifier: utils.Linux, + wantErr: false, + }, + } + + for _, tt := range tests { + c := NewInspektorGadgetDNSTraceCollector(tt.osIdentifier, fixture.PeriscopeAccess.ClientConfig, nil, nil, []containercollection.ContainerCollectionOption{}) + err := c.CheckSupported() + if (err != nil) != tt.wantErr { + t.Errorf("CheckSupported() error = %v, wantErr %v", err, tt.wantErr) + } + } +} + +func TestInspektorGadgetDNSTraceCollectorCollect(t *testing.T) { + fixture, _ := test.GetClusterFixture() + + nodeNames, err := fixture.GetNodeNames() + if err != nil { + t.Fatalf("Error getting node names: %v", err) + } + + nodeName := nodeNames[0] + + tests := []struct { + name string + config *rest.Config + hostNodeName string + wantErr bool + wantData map[string]*regexp.Regexp + }{ + { + name: "bad kubeconfig", + config: &rest.Config{Host: string([]byte{0})}, + hostNodeName: "", + wantErr: true, + wantData: nil, + }, + { + name: "valid config", + config: fixture.PeriscopeAccess.ClientConfig, + hostNodeName: nodeName, + wantErr: false, + wantData: map[string]*regexp.Regexp{}, + }, + } + + setupCommands := []string{ + fmt.Sprintf("kubectl -n %s apply -f /resources/pause-daemonset.yaml", fixture.KnownNamespaces.Periscope), + fmt.Sprintf("kubectl -n %s rollout status daemonset pauseds --timeout=60s", fixture.KnownNamespaces.Periscope), + } + setupCommand := strings.Join(setupCommands, " && ") + _, err = fixture.CommandRunner.Run(setupCommand, fixture.AdminAccess.GetKubeConfigBinding()) + if err != nil { + t.Fatalf("Error installing test daemonset: %v", err) + } + + pod, err := getTestPod(fixture, nodeName) + if err != nil { + t.Fatalf("Unable to get test pod: %v", err) + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + runtimeInfo := &utils.RuntimeInfo{ + HostNodeName: tt.hostNodeName, + } + + testsready := make(chan struct{}) + testsdone := make(chan struct{}) + waiter := func() { + close(testsready) + <-testsdone + } + + option := getDNSTestContainerOption(pod, testsready, testsdone) + c := NewInspektorGadgetDNSTraceCollector(utils.Linux, tt.config, runtimeInfo, waiter, []containercollection.ContainerCollectionOption{option}) + err := c.Collect() + + if (err != nil) != tt.wantErr { + t.Errorf("Collect() error = %v, wantErr %v", err, tt.wantErr) + } + data := c.GetData() + compareCollectorData(t, tt.wantData, data) + }) + } +} + +func getTestPod(fixture *test.ClusterFixture, nodeName string) (*corev1.Pod, error) { + fieldSelector := fields.OneTermEqualSelector("spec.nodeName", nodeName) + nameRequirement, err := labels.NewRequirement("name", selection.Equals, []string{"pauseds"}) + if err != nil { + return nil, fmt.Errorf("failed to create name requirement: %w", err) + } + labelSelector := labels.NewSelector().Add(*nameRequirement) + pods, err := fixture.AdminAccess.Clientset.CoreV1().Pods(fixture.KnownNamespaces.Periscope).List(context.TODO(), metav1.ListOptions{ + FieldSelector: fieldSelector.String(), + LabelSelector: labelSelector.String(), + }) + if err != nil { + return nil, fmt.Errorf("failed to retrieve test pod: %w", err) + } + if len(pods.Items) != 1 { + return nil, fmt.Errorf("expected one test pod, found %d", len(pods.Items)) + } + return &pods.Items[0], nil +} + +func getDNSTestContainerOption(pod *corev1.Pod, ready chan struct{}, done chan struct{}) func(*containercollection.ContainerCollection) error { + domains := []string{"microsoft.com", "google.com", "shouldnotexist.com"} + + return func(cc *containercollection.ContainerCollection) error { + go func() { + // Wait until the Collect function has set up its trace and is ready to listen for events + <-ready + + // Pretend the test process is a container which has just been launched. + testProcessPid := os.Getpid() + testContainer := containercollection.Container{ + ID: fmt.Sprintf("test%08d", testProcessPid), + // Namespace, Podname and Labels should be populated by the Kubernetes enricher. + Pid: uint32(testProcessPid), + // This would normally be added by the cgroup enricher + CgroupV2: fmt.Sprintf("/kubelet/kubepods/pod%s/k8scontainerid", pod.ObjectMeta.UID), + // If OciConfig.Mounts is populated, it's used by the Kubernetes enricher to set the container name + // when the container is added. + // In gadgettracermanager, whose behaviour we're trying to replicate, the RuncFanotify enricher + // populates this. If we don't populate it here, the kubernetes enricher 'drops' the container: + // (https://github.com/inspektor-gadget/inspektor-gadget/blob/08b450065bb839e33012d80d476b3a3c17946379/pkg/container-collection/options.go#L497-L500) + OciConfig: &ocispec.Spec{ + Mounts: []ocispec.Mount{ + ocispec.Mount{ + Destination: "/dev/termination-log", + Type: "bind", + Source: fmt.Sprintf("/var/lib/kubelet/pods/%s/containers/%s/dnstest/a1234abcd", pod.ObjectMeta.UID, pod.Spec.Containers[0].Name), + Options: []string{"rbind", "rprivate", "rw"}, + }, + }, + }, + } + + // Adding the container will invoke the other ContainerCollectionOptions, which will populate the k8s container properties. + cc.AddContainer(&testContainer) + + // HostNetwork will have been set to true by now (because the 'container' and host PIDs are the same). + // For testing purposes we want it to be false, because the event callback checks this when populating + // the event properties. + testContainer.HostNetwork = false + + for _, domain := range domains { + // Perform a DNS lookup (discarding the result because we're only testing the events it triggers) + net.LookupIP(domain) + } + + cc.RemoveContainer(testContainer.ID) + close(done) + }() + + return nil + } +} diff --git a/pkg/collector/inspecktor_trace_tcp_collector.go b/pkg/collector/inspektor_trace_tcp_collector.go similarity index 55% rename from pkg/collector/inspecktor_trace_tcp_collector.go rename to pkg/collector/inspektor_trace_tcp_collector.go index 46c12db0..bdfd0bb1 100644 --- a/pkg/collector/inspecktor_trace_tcp_collector.go +++ b/pkg/collector/inspektor_trace_tcp_collector.go @@ -1,16 +1,20 @@ package collector import ( + "fmt" "time" + "github.com/Azure/aks-periscope/pkg/collector/gadget" "github.com/Azure/aks-periscope/pkg/interfaces" "github.com/Azure/aks-periscope/pkg/utils" + tcptracer "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/tcp/tracer" + tcptypes "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/tcp/types" restclient "k8s.io/client-go/rest" ) // InspektorGadgetTCPTraceCollector defines a InspektorGadget Trace TCP Collector struct type InspektorGadgetTCPTraceCollector struct { - tracerGadget *InspektorGadgetTraceCollector + tracerGadget *gadget.InspektorGadgetTraceCollector } // CheckSupported implements the interface method @@ -20,15 +24,14 @@ func (collector *InspektorGadgetTCPTraceCollector) CheckSupported() error { // NewInspektorGadgetTCPTraceCollector is a constructor. func NewInspektorGadgetTCPTraceCollector(osIdentifier utils.OSIdentifier, config *restclient.Config, runtimeInfo *utils.RuntimeInfo, collectingPeriod time.Duration) *InspektorGadgetTCPTraceCollector { - return &InspektorGadgetTCPTraceCollector{ - tracerGadget: &InspektorGadgetTraceCollector{ - data: make(map[string]string), - osIdentifier: osIdentifier, - kubeconfig: config, - commandRunner: utils.NewKubeCommandRunner(config), - runtimeInfo: runtimeInfo, - collectingPeriod: collectingPeriod, + tracerGadget: &gadget.InspektorGadgetTraceCollector{ + Data: make(map[string]string), + OsIdentifier: osIdentifier, + Kubeconfig: config, + CommandRunner: utils.NewKubeCommandRunner(config), + RuntimeInfo: runtimeInfo, + CollectingPeriod: collectingPeriod, }, } } @@ -39,7 +42,16 @@ func (collector *InspektorGadgetTCPTraceCollector) GetName() string { // Collect implements the interface method func (collector *InspektorGadgetTCPTraceCollector) Collect() error { - return collector.tracerGadget.collect("tcptracer") + eventCallback := func(event tcptypes.Event) { + collector.tracerGadget.Data["tcptracer"] = fmt.Sprintf("A new %q process with pid %d was executed\n", event.Comm, event.Pid) + } + + tracer, err := tcptracer.NewTracer(&tcptracer.Config{}, nil, eventCallback) + if err != nil { + return fmt.Errorf("could not create tracer: %w", err) + } + + return collector.tracerGadget.Collect("tcptracer", tracer) } // GetData implements the interface method diff --git a/pkg/test/resources/tools-resources/pause-daemonset.yaml b/pkg/test/resources/tools-resources/pause-daemonset.yaml new file mode 100644 index 00000000..351cd3b1 --- /dev/null +++ b/pkg/test/resources/tools-resources/pause-daemonset.yaml @@ -0,0 +1,24 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: pauseds +spec: + selector: + matchLabels: + name: pauseds + template: + metadata: + labels: + name: pauseds + spec: + containers: + - name: testcontainer + image: k8s.gcr.io/pause:3.6 + imagePullPolicy: Never + resources: + limits: + cpu: "0.1" + memory: "10Mi" + tolerations: + - key: node-role.kubernetes.io/master + effect: NoSchedule From 8d018399fe35c79bb1ddf0c8a1b12cde259f5e02 Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Tue, 17 Jan 2023 14:49:43 +1300 Subject: [PATCH 14/27] make tests work --- cmd/aks-periscope/aks-periscope.go | 20 +- .../inspektor_trace_dns_collector.go | 81 ++++---- .../inspektor_trace_dns_collector_test.go | 186 ++++++++++-------- 3 files changed, 168 insertions(+), 119 deletions(-) diff --git a/cmd/aks-periscope/aks-periscope.go b/cmd/aks-periscope/aks-periscope.go index 2b1c409e..fe7ad87d 100644 --- a/cmd/aks-periscope/aks-periscope.go +++ b/cmd/aks-periscope/aks-periscope.go @@ -15,6 +15,7 @@ import ( "github.com/Azure/aks-periscope/pkg/utils" containercollection "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection" + "github.com/inspektor-gadget/inspektor-gadget/pkg/runcfanotify" restclient "k8s.io/client-go/rest" ) @@ -85,7 +86,7 @@ func run(osIdentifier utils.OSIdentifier, knownFilePaths *utils.KnownFilePaths, // Use the default InspektorGadget behaviour for determining containers: // https://github.com/inspektor-gadget/inspektor-gadget/blob/6b00fea3f925c9da478126931e774e340ca9bfdf/pkg/gadgettracermanager/gadgettracermanager.go#L275-L283 - var containerCollectionOptions []containercollection.ContainerCollectionOption{ + var containerCollectionOptions []containercollection.ContainerCollectionOption if runcfanotify.Supported() { containerCollectionOptions = []containercollection.ContainerCollectionOption{ containercollection.WithRuncFanotify(), @@ -97,9 +98,18 @@ func run(osIdentifier utils.OSIdentifier, knownFilePaths *utils.KnownFilePaths, } } - waiter := func() { - log.Printf("\twait for %v to stop collection", collector.collectingPeriod) - time.Sleep(2*time.Minute) + containerCollectionOptions = append( + containerCollectionOptions, + containercollection.WithNodeName(runtimeInfo.HostNodeName), + containercollection.WithCgroupEnrichment(), + containercollection.WithLinuxNamespaceEnrichment(), + containercollection.WithKubernetesEnrichment(runtimeInfo.HostNodeName, config), + ) + + traceCollectionPeriod := 2 * time.Minute + traceWaiter := func() { + log.Printf("\twait for %v to stop collection", traceCollectionPeriod) + time.Sleep(traceCollectionPeriod) } dnsCollector := collector.NewDNSCollector(osIdentifier, knownFilePaths, fileSystem) @@ -120,7 +130,7 @@ func run(osIdentifier utils.OSIdentifier, knownFilePaths *utils.KnownFilePaths, collector.NewSystemLogsCollector(osIdentifier, runtimeInfo), collector.NewSystemPerfCollector(config, runtimeInfo), collector.NewWindowsLogsCollector(osIdentifier, runtimeInfo, knownFilePaths, fileSystem, 10*time.Second, 20*time.Minute), - collector.NewInspektorGadgetDNSTraceCollector(osIdentifier, config, runtimeInfo, waiter, containerCollectionOptions), + collector.NewInspektorGadgetDNSTraceCollector(osIdentifier, runtimeInfo, traceWaiter, containerCollectionOptions), collector.NewInspektorGadgetTCPTraceCollector(osIdentifier, config, runtimeInfo, 2*time.Minute), } diff --git a/pkg/collector/inspektor_trace_dns_collector.go b/pkg/collector/inspektor_trace_dns_collector.go index c4dfb48f..c8277ef4 100644 --- a/pkg/collector/inspektor_trace_dns_collector.go +++ b/pkg/collector/inspektor_trace_dns_collector.go @@ -14,15 +14,12 @@ import ( "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/dns/tracer" dnstypes "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/dns/types" eventtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types" - - restclient "k8s.io/client-go/rest" ) // InspektorGadgetDNSTraceCollector defines a InspektorGadget Trace DNS Collector struct type InspektorGadgetDNSTraceCollector struct { data map[string]string osIdentifier utils.OSIdentifier - kubeconfig *restclient.Config runtimeInfo *utils.RuntimeInfo waiter func() containerCollectionOptions []containercollection.ContainerCollectionOption @@ -40,7 +37,6 @@ func (collector *InspektorGadgetDNSTraceCollector) CheckSupported() error { // NewInspektorGadgetDNSTraceCollector is a constructor. func NewInspektorGadgetDNSTraceCollector( osIdentifier utils.OSIdentifier, - config *restclient.Config, runtimeInfo *utils.RuntimeInfo, waiter func(), containerCollectionOptions []containercollection.ContainerCollectionOption, @@ -48,7 +44,6 @@ func NewInspektorGadgetDNSTraceCollector( return &InspektorGadgetDNSTraceCollector{ data: make(map[string]string), osIdentifier: osIdentifier, - kubeconfig: config, runtimeInfo: runtimeInfo, waiter: waiter, containerCollectionOptions: containerCollectionOptions, @@ -68,20 +63,41 @@ func (collector *InspektorGadgetDNSTraceCollector) Collect() error { return fmt.Errorf("failed to remove memlock: %w", err) } - tracer, err := tracer.NewTracer() - if err != nil { - return fmt.Errorf("failed to start dns tracer: %w", err) + // We want to trace DNS queries from all pods running on the node, not just the current process. + // To do this we need to make use of a ContainerCollection, which can be initially populated + // with all the pod processes, and dynamically updated as pods are created and deleted. + containerEventCallback := func(event containercollection.PubSubEvent) { + // This doesn't *do* anything, but there will be runtime errors if we don't supply a callback. + switch event.Type { + case containercollection.EventTypeAddContainer: + log.Printf("Container added: %q pid %d\n", event.Container.Name, event.Container.Pid) + case containercollection.EventTypeRemoveContainer: + log.Printf("Container removed: %q pid %d\n", event.Container.Name, event.Container.Pid) + } } - defer tracer.Close() - nodeName := collector.runtimeInfo.HostNodeName + // Use the supplied container collection options, but prepend the container event callback. + // The options are all functions that are executed when the container collection is initialized. + opts := append( + []containercollection.ContainerCollectionOption{containercollection.WithPubSub(containerEventCallback)}, + collector.containerCollectionOptions..., + ) + // Initialize the container collection + containerCollection := &containercollection.ContainerCollection{} + if err := containerCollection.Initialize(opts...); err != nil { + return fmt.Errorf("failed to initialize container collection: %w", err) + } + defer containerCollection.Close() + + // Build up a collection of DNS query events, with a mutex to protect against concurrent access. var mu sync.Mutex events := []string{} - eventCallback := func(container *containercollection.Container, event dnstypes.Event) { + // Events will be collected in a callback from the DNS tracer. + dnsEventCallback := func(container *containercollection.Container, event dnstypes.Event) { // Enrich event with data from container - event.Node = nodeName + event.Node = collector.runtimeInfo.HostNodeName if !container.HostNetwork { event.Namespace = container.Namespace event.Pod = container.Podname @@ -95,45 +111,42 @@ func (collector *InspektorGadgetDNSTraceCollector) Collect() error { events = append(events, eventString) } - callback := func(event containercollection.PubSubEvent) { - // This doesn't *do* anything, but there will be runtime errors if we don't supply a callback. - log.Printf("Container event %q:\n\t%s", event.Type, eventtypes.EventString(event.Container)) - } - - opts := append(collector.containerCollectionOptions, - containercollection.WithPubSub(callback), - containercollection.WithNodeName(nodeName), - containercollection.WithCgroupEnrichment(), - containercollection.WithLinuxNamespaceEnrichment(), - containercollection.WithKubernetesEnrichment(nodeName, collector.kubeconfig), - ) - - containerCollection := &containercollection.ContainerCollection{} - if err = containerCollection.Initialize(opts...); err != nil { - return fmt.Errorf("failed to initialize container collection: %w", err) + // The DNS tracer by itself is not associated with any process. It will need to be 'connected' + // to the container collection, which will manage the attaching and detaching of PIDs as + // containers are created and deleted. + tracer, err := tracer.NewTracer() + if err != nil { + return fmt.Errorf("failed to start dns tracer: %w", err) } - defer containerCollection.Close() + defer tracer.Close() + // Set up the information needed to link the tracer to the containers. The selector is empty, + // meaning that all containers in the collection will be traced. config := &networktracer.ConnectToContainerCollectionConfig[dnstypes.Event]{ Tracer: tracer, Resolver: containerCollection, Selector: containercollection.ContainerSelector{}, - EventCallback: eventCallback, + EventCallback: dnsEventCallback, Base: dnstypes.Base, } + // Connect the tracer up. Closing the connection will detach the PIDs from the tracer. conn, err := networktracer.ConnectToContainerCollection(config) if err != nil { return fmt.Errorf("failed to connect network tracer: %w", err) } defer conn.Close() + // The trace is now running. Run whatever function our consumer has supplied before storing the + // collected data. collector.waiter() - mu.Lock() - defer mu.Unlock() - collector.data["dnstracer"] = strings.Join(events, "\n") - log.Print(collector.data["dnstracer"]) + // Store the collected data. + func() { + mu.Lock() + defer mu.Unlock() + collector.data["dnstracer"] = strings.Join(events, "\n") + }() return nil } diff --git a/pkg/collector/inspektor_trace_dns_collector_test.go b/pkg/collector/inspektor_trace_dns_collector_test.go index 5037a2c5..54dcb868 100644 --- a/pkg/collector/inspektor_trace_dns_collector_test.go +++ b/pkg/collector/inspektor_trace_dns_collector_test.go @@ -18,13 +18,12 @@ import ( "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/selection" - "k8s.io/client-go/rest" ) func TestInspektorGadgetDNSTraceCollectorGetName(t *testing.T) { const expectedName = "inspektorgadget-dns" - c := NewInspektorGadgetDNSTraceCollector("", nil, nil, nil, []containercollection.ContainerCollectionOption{}) + c := NewInspektorGadgetDNSTraceCollector("", nil, nil, []containercollection.ContainerCollectionOption{}) actualName := c.GetName() if actualName != expectedName { t.Errorf("unexpected name: expected %s, found %s", expectedName, actualName) @@ -32,8 +31,6 @@ func TestInspektorGadgetDNSTraceCollectorGetName(t *testing.T) { } func TestInspektorGadgetDNSTraceCollectorCheckSupported(t *testing.T) { - fixture, _ := test.GetClusterFixture() - tests := []struct { osIdentifier utils.OSIdentifier wantErr bool @@ -49,7 +46,7 @@ func TestInspektorGadgetDNSTraceCollectorCheckSupported(t *testing.T) { } for _, tt := range tests { - c := NewInspektorGadgetDNSTraceCollector(tt.osIdentifier, fixture.PeriscopeAccess.ClientConfig, nil, nil, []containercollection.ContainerCollectionOption{}) + c := NewInspektorGadgetDNSTraceCollector(tt.osIdentifier, nil, nil, []containercollection.ContainerCollectionOption{}) err := c.CheckSupported() if (err != nil) != tt.wantErr { t.Errorf("CheckSupported() error = %v, wantErr %v", err, tt.wantErr) @@ -67,29 +64,8 @@ func TestInspektorGadgetDNSTraceCollectorCollect(t *testing.T) { nodeName := nodeNames[0] - tests := []struct { - name string - config *rest.Config - hostNodeName string - wantErr bool - wantData map[string]*regexp.Regexp - }{ - { - name: "bad kubeconfig", - config: &rest.Config{Host: string([]byte{0})}, - hostNodeName: "", - wantErr: true, - wantData: nil, - }, - { - name: "valid config", - config: fixture.PeriscopeAccess.ClientConfig, - hostNodeName: nodeName, - wantErr: false, - wantData: map[string]*regexp.Regexp{}, - }, - } - + // Ensure there is a pod running on our node. This pod process won't actually be traced, but we'll pretend + // our DNS queries are coming from this pod. setupCommands := []string{ fmt.Sprintf("kubectl -n %s apply -f /resources/pause-daemonset.yaml", fixture.KnownNamespaces.Periscope), fmt.Sprintf("kubectl -n %s rollout status daemonset pauseds --timeout=60s", fixture.KnownNamespaces.Periscope), @@ -100,26 +76,72 @@ func TestInspektorGadgetDNSTraceCollectorCollect(t *testing.T) { t.Fatalf("Error installing test daemonset: %v", err) } + // Find the pod we've created. pod, err := getTestPod(fixture, nodeName) if err != nil { t.Fatalf("Unable to get test pod: %v", err) } + domains := []string{"microsoft.com", "google.com", "shouldnotexist.com"} + + tests := []struct { + name string + hostNodeName string + wantErr bool + wantData map[string]*regexp.Regexp + }{ + { + name: "valid", + hostNodeName: nodeName, + wantErr: false, + wantData: map[string]*regexp.Regexp{ + "dnstracer": getExpectedDnsTraceData(fixture, nodeName, pod, domains), + }, + }, + } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { runtimeInfo := &utils.RuntimeInfo{ HostNodeName: tt.hostNodeName, } - testsready := make(chan struct{}) - testsdone := make(chan struct{}) + // Use a channel to get hold of the ContainerCollection (via a ContainerCollectionOption). + // We'll use this to add our pretend kubernetes container to. + ccChan := make(chan *containercollection.ContainerCollection) + + // Create a container whose PID is the current process, but has the attributes of the pod. + testContainer := getCurrentProcessAsKubernetesContainer(pod) + + // Make use of container collection options to: + // - Get hold of the ContainerCollection + // - Add node name to the collection + // - Add K8s pod metadata to the containers (based on the pod UID) + // We skip the following options that Periscope uses: + // - WithRuncFanotify: because we're not assuming our test is running in a containerized environment. + // - WithInitialKubernetesContainers: because this uses an in-cluster context that is inaccessible here. + // - WithPodInformer: also uses an in-cluster context. + // - WithCgroupEnrichment: because this process is not expected to have cgroups, and we're faking those. + // - WithLinuxNamespaceEnrichment: because this will set HostNetwork to true, and we're pretending it's false. + opts := []containercollection.ContainerCollectionOption{ + withContainerCollectionReceiver(ccChan), + containercollection.WithNodeName(tt.hostNodeName), + containercollection.WithKubernetesEnrichment(tt.hostNodeName, fixture.PeriscopeAccess.ClientConfig), + } + waiter := func() { - close(testsready) - <-testsdone + // While the tracer is running, add a fake container and perform some DNS queries from its process. + cc := <-ccChan + cc.AddContainer(testContainer) + defer cc.RemoveContainer(testContainer.ID) + + for _, domain := range domains { + // Perform a DNS lookup (discarding the result because we're only testing the events it triggers) + net.LookupIP(domain) + } } - option := getDNSTestContainerOption(pod, testsready, testsdone) - c := NewInspektorGadgetDNSTraceCollector(utils.Linux, tt.config, runtimeInfo, waiter, []containercollection.ContainerCollectionOption{option}) + c := NewInspektorGadgetDNSTraceCollector(utils.Linux, runtimeInfo, waiter, opts) err := c.Collect() if (err != nil) != tt.wantErr { @@ -131,6 +153,28 @@ func TestInspektorGadgetDNSTraceCollectorCollect(t *testing.T) { } } +func getExpectedDnsTraceData(fixture *test.ClusterFixture, nodeName string, pod *corev1.Pod, domains []string) *regexp.Regexp { + containerName := pod.Spec.Containers[0].Name + + eventPatterns := []string{} + eventPatterns = append(eventPatterns, + fmt.Sprintf( + `{"node":%q,"namespace":%q,"pod":%q,"container":%q,"type":"debug","message":"tracer attached"}`, + nodeName, fixture.KnownNamespaces.Periscope, pod.Name, containerName), + ) + + for _, domain := range domains { + eventPatterns = append(eventPatterns, + fmt.Sprintf( + `{"node":%q,"namespace":%q,"pod":%q,"container":%q,"type":"normal","id":"[\d\w\.]+","qr":"Q","nameserver":"[\d\.]+","pktType":"OUTGOING","qtype":"A","name":%q}`, + nodeName, fixture.KnownNamespaces.Periscope, pod.Name, containerName, domain+"."), + ) + } + + pattern := strings.Join(eventPatterns, `(\n.*)*`) + return regexp.MustCompile(pattern) +} + func getTestPod(fixture *test.ClusterFixture, nodeName string) (*corev1.Pod, error) { fieldSelector := fields.OneTermEqualSelector("spec.nodeName", nodeName) nameRequirement, err := labels.NewRequirement("name", selection.Equals, []string{"pauseds"}) @@ -151,56 +195,38 @@ func getTestPod(fixture *test.ClusterFixture, nodeName string) (*corev1.Pod, err return &pods.Items[0], nil } -func getDNSTestContainerOption(pod *corev1.Pod, ready chan struct{}, done chan struct{}) func(*containercollection.ContainerCollection) error { - domains := []string{"microsoft.com", "google.com", "shouldnotexist.com"} +func getCurrentProcessAsKubernetesContainer(pod *corev1.Pod) *containercollection.Container { + // Pretend the current test process is a kubernetes container. + testProcessPid := os.Getpid() + return &containercollection.Container{ + ID: fmt.Sprintf("test%08d", testProcessPid), + // Namespace, Podname and Labels should be populated by the Kubernetes enricher. + Pid: uint32(testProcessPid), + // This would normally be added by the cgroup enricher + CgroupV2: fmt.Sprintf("/kubelet/kubepods/pod%s/k8scontainerid", pod.ObjectMeta.UID), + // If OciConfig.Mounts is populated, it's used by the Kubernetes enricher to set the container name + // when the container is added. + // In gadgettracermanager, whose behaviour we're trying to replicate, the RuncFanotify enricher + // populates this. If we don't populate it here, the kubernetes enricher 'drops' the container: + // (https://github.com/inspektor-gadget/inspektor-gadget/blob/08b450065bb839e33012d80d476b3a3c17946379/pkg/container-collection/options.go#L497-L500) + OciConfig: &ocispec.Spec{ + Mounts: []ocispec.Mount{ + ocispec.Mount{ + Destination: "/dev/termination-log", + Type: "bind", + Source: fmt.Sprintf("/var/lib/kubelet/pods/%s/containers/%s/dnstest/a1234abcd", pod.ObjectMeta.UID, pod.Spec.Containers[0].Name), + Options: []string{"rbind", "rprivate", "rw"}, + }, + }, + }, + } +} +func withContainerCollectionReceiver(ccChan chan *containercollection.ContainerCollection) containercollection.ContainerCollectionOption { return func(cc *containercollection.ContainerCollection) error { go func() { - // Wait until the Collect function has set up its trace and is ready to listen for events - <-ready - - // Pretend the test process is a container which has just been launched. - testProcessPid := os.Getpid() - testContainer := containercollection.Container{ - ID: fmt.Sprintf("test%08d", testProcessPid), - // Namespace, Podname and Labels should be populated by the Kubernetes enricher. - Pid: uint32(testProcessPid), - // This would normally be added by the cgroup enricher - CgroupV2: fmt.Sprintf("/kubelet/kubepods/pod%s/k8scontainerid", pod.ObjectMeta.UID), - // If OciConfig.Mounts is populated, it's used by the Kubernetes enricher to set the container name - // when the container is added. - // In gadgettracermanager, whose behaviour we're trying to replicate, the RuncFanotify enricher - // populates this. If we don't populate it here, the kubernetes enricher 'drops' the container: - // (https://github.com/inspektor-gadget/inspektor-gadget/blob/08b450065bb839e33012d80d476b3a3c17946379/pkg/container-collection/options.go#L497-L500) - OciConfig: &ocispec.Spec{ - Mounts: []ocispec.Mount{ - ocispec.Mount{ - Destination: "/dev/termination-log", - Type: "bind", - Source: fmt.Sprintf("/var/lib/kubelet/pods/%s/containers/%s/dnstest/a1234abcd", pod.ObjectMeta.UID, pod.Spec.Containers[0].Name), - Options: []string{"rbind", "rprivate", "rw"}, - }, - }, - }, - } - - // Adding the container will invoke the other ContainerCollectionOptions, which will populate the k8s container properties. - cc.AddContainer(&testContainer) - - // HostNetwork will have been set to true by now (because the 'container' and host PIDs are the same). - // For testing purposes we want it to be false, because the event callback checks this when populating - // the event properties. - testContainer.HostNetwork = false - - for _, domain := range domains { - // Perform a DNS lookup (discarding the result because we're only testing the events it triggers) - net.LookupIP(domain) - } - - cc.RemoveContainer(testContainer.ID) - close(done) + ccChan <- cc }() - return nil } } From eef7ec40baf9c1ebf197255d87d95db2c43ec627 Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Fri, 20 Jan 2023 15:00:44 +1300 Subject: [PATCH 15/27] fix and test TCP trace collector --- .../gadget/inspektor_trace_collector.go | 71 ---------- pkg/collector/inspektor_trace_common_test.go | 119 ++++++++++++++++ .../inspektor_trace_dns_collector.go | 2 +- .../inspektor_trace_dns_collector_test.go | 103 ++------------ .../inspektor_trace_tcp_collector.go | 118 ++++++++++++--- .../inspektor_trace_tcp_collector_test.go | 134 ++++++++++++++++++ 6 files changed, 361 insertions(+), 186 deletions(-) delete mode 100644 pkg/collector/gadget/inspektor_trace_collector.go create mode 100644 pkg/collector/inspektor_trace_common_test.go create mode 100644 pkg/collector/inspektor_trace_tcp_collector_test.go diff --git a/pkg/collector/gadget/inspektor_trace_collector.go b/pkg/collector/gadget/inspektor_trace_collector.go deleted file mode 100644 index c93971c2..00000000 --- a/pkg/collector/gadget/inspektor_trace_collector.go +++ /dev/null @@ -1,71 +0,0 @@ -package gadget - -import ( - "fmt" - "log" - "strings" - "time" - - "github.com/Azure/aks-periscope/pkg/interfaces" - "github.com/Azure/aks-periscope/pkg/utils" - "github.com/cilium/ebpf/rlimit" - restclient "k8s.io/client-go/rest" -) - -const ( - GadgetOperation = "gadget.kinvolk.io/operation" -) - -// InspektorGadgetTraceCollector defines a InspektorGadget Trace Collector that are common to trace gadgets -type InspektorGadgetTraceCollector struct { - Data map[string]string - OsIdentifier utils.OSIdentifier - Kubeconfig *restclient.Config - CommandRunner *utils.KubeCommandRunner - RuntimeInfo *utils.RuntimeInfo - CollectingPeriod time.Duration -} - -type Tracer interface { - Stop() -} - -func (collector *InspektorGadgetTraceCollector) CheckSupported() error { - // Inspektor Gadget relies on eBPF which is not (currently) available on Windows nodes. - if collector.OsIdentifier != utils.Linux { - return fmt.Errorf("unsupported OS: %s", collector.OsIdentifier) - } - - crds, err := collector.CommandRunner.GetCRDUnstructuredList() - if err != nil { - return fmt.Errorf("error listing CRDs in cluster") - } - - for _, crd := range crds.Items { - if strings.Contains(crd.GetName(), "traces.gadget.kinvolk.io") { - return nil - } - } - return fmt.Errorf("does not contain gadget crd") -} - -func (collector *InspektorGadgetTraceCollector) GetData() map[string]interfaces.DataValue { - return utils.ToDataValueMap(collector.Data) -} - -func (collector *InspektorGadgetTraceCollector) Collect(gadgetName string, tracer Tracer) error { - // From https://www.inspektor-gadget.io/blog/2022/09/using-inspektor-gadget-from-golang-applications/ - // In some kernel versions it's needed to bump the rlimits to - // use run BPF programs. - if err := rlimit.RemoveMemlock(); err != nil { - // Well...maybe we can continue anyway? No harm in trying. Log the error and continue. - log.Printf("\tcould not remove memlock: %v", err) - } - - defer tracer.Stop() - - log.Printf("\twait for %v to stop collection", collector.CollectingPeriod) - time.Sleep(collector.CollectingPeriod) - - return nil -} diff --git a/pkg/collector/inspektor_trace_common_test.go b/pkg/collector/inspektor_trace_common_test.go new file mode 100644 index 00000000..b5f2d138 --- /dev/null +++ b/pkg/collector/inspektor_trace_common_test.go @@ -0,0 +1,119 @@ +package collector + +import ( + "context" + "fmt" + "os" + "strings" + + "github.com/Azure/aks-periscope/pkg/test" + containercollection "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection" + containerutils "github.com/inspektor-gadget/inspektor-gadget/pkg/container-utils" + ocispec "github.com/opencontainers/runtime-spec/specs-go" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" + "k8s.io/client-go/rest" +) + +func getTestContainerCollectionOptions( + ccChan chan *containercollection.ContainerCollection, + nodeName string, + clusterConfig *rest.Config, +) []containercollection.ContainerCollectionOption { + // Make use of container collection options to: + // - Get hold of the ContainerCollection + // - Add node name to the collection + // - Add K8s pod metadata to the containers (based on the pod UID) + // We skip the following options that Periscope uses: + // - WithRuncFanotify: because we're not assuming our test is running in a containerized environment. + // - WithInitialKubernetesContainers: because this uses an in-cluster context that is inaccessible here. + // - WithPodInformer: also uses an in-cluster context. + // - WithCgroupEnrichment: because this process is not expected to have cgroups, and we're faking those. + // - WithLinuxNamespaceEnrichment: because this will set HostNetwork to true, and we're pretending it's false. + return []containercollection.ContainerCollectionOption{ + withContainerCollectionReceiver(ccChan), + containercollection.WithNodeName(nodeName), + containercollection.WithKubernetesEnrichment(nodeName, clusterConfig), + } +} + +func ensurePod(fixture *test.ClusterFixture, nodeName string) (*corev1.Pod, error) { + setupCommands := []string{ + fmt.Sprintf("kubectl -n %s apply -f /resources/pause-daemonset.yaml", fixture.KnownNamespaces.Periscope), + fmt.Sprintf("kubectl -n %s rollout status daemonset pauseds --timeout=60s", fixture.KnownNamespaces.Periscope), + } + setupCommand := strings.Join(setupCommands, " && ") + _, err := fixture.CommandRunner.Run(setupCommand, fixture.AdminAccess.GetKubeConfigBinding()) + if err != nil { + return nil, fmt.Errorf("failed to install test daemonset: %w", err) + } + + // Find the pod we've created. + return getTestPod(fixture, nodeName) +} + +func getTestPod(fixture *test.ClusterFixture, nodeName string) (*corev1.Pod, error) { + fieldSelector := fields.OneTermEqualSelector("spec.nodeName", nodeName) + nameRequirement, err := labels.NewRequirement("name", selection.Equals, []string{"pauseds"}) + if err != nil { + return nil, fmt.Errorf("failed to create name requirement: %w", err) + } + labelSelector := labels.NewSelector().Add(*nameRequirement) + pods, err := fixture.AdminAccess.Clientset.CoreV1().Pods(fixture.KnownNamespaces.Periscope).List(context.TODO(), metav1.ListOptions{ + FieldSelector: fieldSelector.String(), + LabelSelector: labelSelector.String(), + }) + if err != nil { + return nil, fmt.Errorf("failed to retrieve test pod: %w", err) + } + if len(pods.Items) != 1 { + return nil, fmt.Errorf("expected one test pod, found %d", len(pods.Items)) + } + return &pods.Items[0], nil +} + +func getCurrentProcessAsKubernetesContainer(pod *corev1.Pod) (*containercollection.Container, error) { + // Pretend the current test process is a kubernetes container. + testProcessPid := os.Getpid() + mnsnsid, err := containerutils.GetMntNs(testProcessPid) + if err != nil { + return nil, fmt.Errorf("failed to get mnt namespace id: %w", err) + } + + return &containercollection.Container{ + ID: fmt.Sprintf("test%08d", testProcessPid), + // Namespace, Podname and Labels should be populated by the Kubernetes enricher. + Pid: uint32(testProcessPid), + // This would normally be added by the cgroup enricher + CgroupV2: fmt.Sprintf("/kubelet/kubepods/pod%s/k8scontainerid", pod.ObjectMeta.UID), + // If OciConfig.Mounts is populated, it's used by the Kubernetes enricher to set the container name + // when the container is added. + // In gadgettracermanager, whose behaviour we're trying to replicate, the RuncFanotify enricher + // populates this. If we don't populate it here, the kubernetes enricher 'drops' the container: + // (https://github.com/inspektor-gadget/inspektor-gadget/blob/08b450065bb839e33012d80d476b3a3c17946379/pkg/container-collection/options.go#L497-L500) + OciConfig: &ocispec.Spec{ + Mounts: []ocispec.Mount{ + ocispec.Mount{ + Destination: "/dev/termination-log", + Type: "bind", + Source: fmt.Sprintf("/var/lib/kubelet/pods/%s/containers/%s/dnstest/a1234abcd", pod.ObjectMeta.UID, pod.Spec.Containers[0].Name), + Options: []string{"rbind", "rprivate", "rw"}, + }, + }, + }, + // Set to correlate this container with requests coming from the TCP tracer. + Mntns: mnsnsid, + }, nil +} + +func withContainerCollectionReceiver(ccChan chan *containercollection.ContainerCollection) containercollection.ContainerCollectionOption { + return func(cc *containercollection.ContainerCollection) error { + go func() { + ccChan <- cc + }() + return nil + } +} diff --git a/pkg/collector/inspektor_trace_dns_collector.go b/pkg/collector/inspektor_trace_dns_collector.go index c8277ef4..1bbb0b5a 100644 --- a/pkg/collector/inspektor_trace_dns_collector.go +++ b/pkg/collector/inspektor_trace_dns_collector.go @@ -51,7 +51,7 @@ func NewInspektorGadgetDNSTraceCollector( } func (collector *InspektorGadgetDNSTraceCollector) GetName() string { - return "inspektorgadget-dns" + return "inspektorgadget-dnstrace" } // Collect implements the interface method diff --git a/pkg/collector/inspektor_trace_dns_collector_test.go b/pkg/collector/inspektor_trace_dns_collector_test.go index 54dcb868..b41e4437 100644 --- a/pkg/collector/inspektor_trace_dns_collector_test.go +++ b/pkg/collector/inspektor_trace_dns_collector_test.go @@ -1,10 +1,8 @@ package collector import ( - "context" "fmt" "net" - "os" "regexp" "strings" "testing" @@ -12,16 +10,11 @@ import ( "github.com/Azure/aks-periscope/pkg/test" "github.com/Azure/aks-periscope/pkg/utils" containercollection "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection" - ocispec "github.com/opencontainers/runtime-spec/specs-go" corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/selection" ) func TestInspektorGadgetDNSTraceCollectorGetName(t *testing.T) { - const expectedName = "inspektorgadget-dns" + const expectedName = "inspektorgadget-dnstrace" c := NewInspektorGadgetDNSTraceCollector("", nil, nil, []containercollection.ContainerCollectionOption{}) actualName := c.GetName() @@ -65,21 +58,16 @@ func TestInspektorGadgetDNSTraceCollectorCollect(t *testing.T) { nodeName := nodeNames[0] // Ensure there is a pod running on our node. This pod process won't actually be traced, but we'll pretend - // our DNS queries are coming from this pod. - setupCommands := []string{ - fmt.Sprintf("kubectl -n %s apply -f /resources/pause-daemonset.yaml", fixture.KnownNamespaces.Periscope), - fmt.Sprintf("kubectl -n %s rollout status daemonset pauseds --timeout=60s", fixture.KnownNamespaces.Periscope), - } - setupCommand := strings.Join(setupCommands, " && ") - _, err = fixture.CommandRunner.Run(setupCommand, fixture.AdminAccess.GetKubeConfigBinding()) + // our traces are coming from this pod. + pod, err := ensurePod(fixture, nodeName) if err != nil { - t.Fatalf("Error installing test daemonset: %v", err) + t.Fatalf("Error setting up test pod: %v", err) } - // Find the pod we've created. - pod, err := getTestPod(fixture, nodeName) + // Create a container whose PID is the current process, but has the attributes of the pod. + testContainer, err := getCurrentProcessAsKubernetesContainer(pod) if err != nil { - t.Fatalf("Unable to get test pod: %v", err) + t.Fatalf("Unable create container from current process: %v", err) } domains := []string{"microsoft.com", "google.com", "shouldnotexist.com"} @@ -110,24 +98,7 @@ func TestInspektorGadgetDNSTraceCollectorCollect(t *testing.T) { // We'll use this to add our pretend kubernetes container to. ccChan := make(chan *containercollection.ContainerCollection) - // Create a container whose PID is the current process, but has the attributes of the pod. - testContainer := getCurrentProcessAsKubernetesContainer(pod) - - // Make use of container collection options to: - // - Get hold of the ContainerCollection - // - Add node name to the collection - // - Add K8s pod metadata to the containers (based on the pod UID) - // We skip the following options that Periscope uses: - // - WithRuncFanotify: because we're not assuming our test is running in a containerized environment. - // - WithInitialKubernetesContainers: because this uses an in-cluster context that is inaccessible here. - // - WithPodInformer: also uses an in-cluster context. - // - WithCgroupEnrichment: because this process is not expected to have cgroups, and we're faking those. - // - WithLinuxNamespaceEnrichment: because this will set HostNetwork to true, and we're pretending it's false. - opts := []containercollection.ContainerCollectionOption{ - withContainerCollectionReceiver(ccChan), - containercollection.WithNodeName(tt.hostNodeName), - containercollection.WithKubernetesEnrichment(tt.hostNodeName, fixture.PeriscopeAccess.ClientConfig), - } + opts := getTestContainerCollectionOptions(ccChan, tt.hostNodeName, fixture.PeriscopeAccess.ClientConfig) waiter := func() { // While the tracer is running, add a fake container and perform some DNS queries from its process. @@ -166,7 +137,7 @@ func getExpectedDnsTraceData(fixture *test.ClusterFixture, nodeName string, pod for _, domain := range domains { eventPatterns = append(eventPatterns, fmt.Sprintf( - `{"node":%q,"namespace":%q,"pod":%q,"container":%q,"type":"normal","id":"[\d\w\.]+","qr":"Q","nameserver":"[\d\.]+","pktType":"OUTGOING","qtype":"A","name":%q}`, + `{"node":%q,"namespace":%q,"pod":%q,"container":%q,"type":"normal","id":"[\w.]+","qr":"Q","nameserver":"[\d\.]+","pktType":"OUTGOING","qtype":"A","name":%q}`, nodeName, fixture.KnownNamespaces.Periscope, pod.Name, containerName, domain+"."), ) } @@ -174,59 +145,3 @@ func getExpectedDnsTraceData(fixture *test.ClusterFixture, nodeName string, pod pattern := strings.Join(eventPatterns, `(\n.*)*`) return regexp.MustCompile(pattern) } - -func getTestPod(fixture *test.ClusterFixture, nodeName string) (*corev1.Pod, error) { - fieldSelector := fields.OneTermEqualSelector("spec.nodeName", nodeName) - nameRequirement, err := labels.NewRequirement("name", selection.Equals, []string{"pauseds"}) - if err != nil { - return nil, fmt.Errorf("failed to create name requirement: %w", err) - } - labelSelector := labels.NewSelector().Add(*nameRequirement) - pods, err := fixture.AdminAccess.Clientset.CoreV1().Pods(fixture.KnownNamespaces.Periscope).List(context.TODO(), metav1.ListOptions{ - FieldSelector: fieldSelector.String(), - LabelSelector: labelSelector.String(), - }) - if err != nil { - return nil, fmt.Errorf("failed to retrieve test pod: %w", err) - } - if len(pods.Items) != 1 { - return nil, fmt.Errorf("expected one test pod, found %d", len(pods.Items)) - } - return &pods.Items[0], nil -} - -func getCurrentProcessAsKubernetesContainer(pod *corev1.Pod) *containercollection.Container { - // Pretend the current test process is a kubernetes container. - testProcessPid := os.Getpid() - return &containercollection.Container{ - ID: fmt.Sprintf("test%08d", testProcessPid), - // Namespace, Podname and Labels should be populated by the Kubernetes enricher. - Pid: uint32(testProcessPid), - // This would normally be added by the cgroup enricher - CgroupV2: fmt.Sprintf("/kubelet/kubepods/pod%s/k8scontainerid", pod.ObjectMeta.UID), - // If OciConfig.Mounts is populated, it's used by the Kubernetes enricher to set the container name - // when the container is added. - // In gadgettracermanager, whose behaviour we're trying to replicate, the RuncFanotify enricher - // populates this. If we don't populate it here, the kubernetes enricher 'drops' the container: - // (https://github.com/inspektor-gadget/inspektor-gadget/blob/08b450065bb839e33012d80d476b3a3c17946379/pkg/container-collection/options.go#L497-L500) - OciConfig: &ocispec.Spec{ - Mounts: []ocispec.Mount{ - ocispec.Mount{ - Destination: "/dev/termination-log", - Type: "bind", - Source: fmt.Sprintf("/var/lib/kubelet/pods/%s/containers/%s/dnstest/a1234abcd", pod.ObjectMeta.UID, pod.Spec.Containers[0].Name), - Options: []string{"rbind", "rprivate", "rw"}, - }, - }, - }, - } -} - -func withContainerCollectionReceiver(ccChan chan *containercollection.ContainerCollection) containercollection.ContainerCollectionOption { - return func(cc *containercollection.ContainerCollection) error { - go func() { - ccChan <- cc - }() - return nil - } -} diff --git a/pkg/collector/inspektor_trace_tcp_collector.go b/pkg/collector/inspektor_trace_tcp_collector.go index bdfd0bb1..20fd35c9 100644 --- a/pkg/collector/inspektor_trace_tcp_collector.go +++ b/pkg/collector/inspektor_trace_tcp_collector.go @@ -2,37 +2,53 @@ package collector import ( "fmt" - "time" + "log" + "strings" + "sync" - "github.com/Azure/aks-periscope/pkg/collector/gadget" "github.com/Azure/aks-periscope/pkg/interfaces" "github.com/Azure/aks-periscope/pkg/utils" + "github.com/cilium/ebpf/rlimit" + + containercollection "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection" + "github.com/inspektor-gadget/inspektor-gadget/pkg/gadget-collection/gadgets/trace" tcptracer "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/tcp/tracer" tcptypes "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/tcp/types" - restclient "k8s.io/client-go/rest" + standardtracer "github.com/inspektor-gadget/inspektor-gadget/pkg/standardgadgets/trace/tcp" + eventtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types" ) // InspektorGadgetTCPTraceCollector defines a InspektorGadget Trace TCP Collector struct type InspektorGadgetTCPTraceCollector struct { - tracerGadget *gadget.InspektorGadgetTraceCollector + data map[string]string + osIdentifier utils.OSIdentifier + runtimeInfo *utils.RuntimeInfo + waiter func() + containerCollectionOptions []containercollection.ContainerCollectionOption } // CheckSupported implements the interface method func (collector *InspektorGadgetTCPTraceCollector) CheckSupported() error { - return collector.tracerGadget.CheckSupported() + // Inspektor Gadget relies on eBPF which is not (currently) available on Windows nodes. + if collector.osIdentifier != utils.Linux { + return fmt.Errorf("unsupported OS: %s", collector.osIdentifier) + } + return nil } // NewInspektorGadgetTCPTraceCollector is a constructor. -func NewInspektorGadgetTCPTraceCollector(osIdentifier utils.OSIdentifier, config *restclient.Config, runtimeInfo *utils.RuntimeInfo, collectingPeriod time.Duration) *InspektorGadgetTCPTraceCollector { +func NewInspektorGadgetTCPTraceCollector( + osIdentifier utils.OSIdentifier, + runtimeInfo *utils.RuntimeInfo, + waiter func(), + containerCollectionOptions []containercollection.ContainerCollectionOption, +) *InspektorGadgetTCPTraceCollector { return &InspektorGadgetTCPTraceCollector{ - tracerGadget: &gadget.InspektorGadgetTraceCollector{ - Data: make(map[string]string), - OsIdentifier: osIdentifier, - Kubeconfig: config, - CommandRunner: utils.NewKubeCommandRunner(config), - RuntimeInfo: runtimeInfo, - CollectingPeriod: collectingPeriod, - }, + data: make(map[string]string), + osIdentifier: osIdentifier, + runtimeInfo: runtimeInfo, + waiter: waiter, + containerCollectionOptions: containerCollectionOptions, } } @@ -42,19 +58,81 @@ func (collector *InspektorGadgetTCPTraceCollector) GetName() string { // Collect implements the interface method func (collector *InspektorGadgetTCPTraceCollector) Collect() error { - eventCallback := func(event tcptypes.Event) { - collector.tracerGadget.Data["tcptracer"] = fmt.Sprintf("A new %q process with pid %d was executed\n", event.Comm, event.Pid) + // From https://www.inspektor-gadget.io/blog/2022/09/using-inspektor-gadget-from-golang-applications/ + // In some kernel versions it's needed to bump the rlimits to + // use run BPF programs. + if err := rlimit.RemoveMemlock(); err != nil { + return fmt.Errorf("failed to remove memlock: %w", err) + } + + // We want to trace DNS queries from all pods running on the node, not just the current process. + // To do this we need to make use of a ContainerCollection, which can be initially populated + // with all the pod processes, and dynamically updated as pods are created and deleted. + containerEventCallback := func(event containercollection.PubSubEvent) { + // This doesn't *do* anything, but there will be runtime errors if we don't supply a callback. + switch event.Type { + case containercollection.EventTypeAddContainer: + log.Printf("Container added: %q pid %d\n", event.Container.Name, event.Container.Pid) + case containercollection.EventTypeRemoveContainer: + log.Printf("Container removed: %q pid %d\n", event.Container.Name, event.Container.Pid) + } + } + + // Use the supplied container collection options, but prepend the container event callback. + // The options are all functions that are executed when the container collection is initialized. + opts := append( + []containercollection.ContainerCollectionOption{containercollection.WithPubSub(containerEventCallback)}, + collector.containerCollectionOptions..., + ) + + // Initialize the container collection + containerCollection := &containercollection.ContainerCollection{} + if err := containerCollection.Initialize(opts...); err != nil { + return fmt.Errorf("failed to initialize container collection: %w", err) } + defer containerCollection.Close() - tracer, err := tcptracer.NewTracer(&tcptracer.Config{}, nil, eventCallback) + // Build up a collection of DNS query events, with a mutex to protect against concurrent access. + var mu sync.Mutex + events := []string{} + + tcpEventCallback := func(event tcptypes.Event) { + eventString := eventtypes.EventString(event) + + mu.Lock() + defer mu.Unlock() + events = append(events, eventString) + } + + traceConfig := &tcptracer.Config{} + enricher := containerCollection + + var tracer trace.Tracer + tracer, err := tcptracer.NewTracer(traceConfig, enricher, tcpEventCallback) if err != nil { - return fmt.Errorf("could not create tracer: %w", err) + log.Printf("Failed to create core tracer, falling back to standard one: %v", err) + tracer, err = standardtracer.NewTracer(traceConfig, tcpEventCallback) + if err != nil { + return fmt.Errorf("failed to create a tracer: %w", err) + } } + defer tracer.Stop() + + // The trace is now running. Run whatever function our consumer has supplied before storing the + // collected data. + collector.waiter() + + // Store the collected data. + func() { + mu.Lock() + defer mu.Unlock() + collector.data["tcptracer"] = strings.Join(events, "\n") + }() - return collector.tracerGadget.Collect("tcptracer", tracer) + return nil } // GetData implements the interface method func (collector *InspektorGadgetTCPTraceCollector) GetData() map[string]interfaces.DataValue { - return collector.tracerGadget.GetData() + return utils.ToDataValueMap(collector.data) } diff --git a/pkg/collector/inspektor_trace_tcp_collector_test.go b/pkg/collector/inspektor_trace_tcp_collector_test.go new file mode 100644 index 00000000..8e84b196 --- /dev/null +++ b/pkg/collector/inspektor_trace_tcp_collector_test.go @@ -0,0 +1,134 @@ +package collector + +import ( + "fmt" + "net/http" + "regexp" + "testing" + + "github.com/Azure/aks-periscope/pkg/test" + "github.com/Azure/aks-periscope/pkg/utils" + containercollection "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection" + corev1 "k8s.io/api/core/v1" +) + +func TestInspektorGadgetTCPTraceCollectorGetName(t *testing.T) { + const expectedName = "inspektorgadget-tcptrace" + + c := NewInspektorGadgetTCPTraceCollector("", nil, nil, []containercollection.ContainerCollectionOption{}) + actualName := c.GetName() + if actualName != expectedName { + t.Errorf("unexpected name: expected %s, found %s", expectedName, actualName) + } +} + +func TestInspektorGadgetTCPTraceCollectorCheckSupported(t *testing.T) { + tests := []struct { + osIdentifier utils.OSIdentifier + wantErr bool + }{ + { + osIdentifier: utils.Windows, + wantErr: true, + }, + { + osIdentifier: utils.Linux, + wantErr: false, + }, + } + + for _, tt := range tests { + c := NewInspektorGadgetTCPTraceCollector(tt.osIdentifier, nil, nil, []containercollection.ContainerCollectionOption{}) + err := c.CheckSupported() + if (err != nil) != tt.wantErr { + t.Errorf("CheckSupported() error = %v, wantErr %v", err, tt.wantErr) + } + } +} + +func TestInspektorGadgetTCPTraceCollectorCollect(t *testing.T) { + fixture, _ := test.GetClusterFixture() + + nodeNames, err := fixture.GetNodeNames() + if err != nil { + t.Fatalf("Error getting node names: %v", err) + } + + nodeName := nodeNames[0] + + // Ensure there is a pod running on our node. This pod process won't actually be traced, but we'll pretend + // our traces are coming from this pod. + pod, err := ensurePod(fixture, nodeName) + if err != nil { + t.Fatalf("Error setting up test pod: %v", err) + } + + // Create a container whose PID is the current process, but has the attributes of the pod. + testContainer, err := getCurrentProcessAsKubernetesContainer(pod) + if err != nil { + t.Fatalf("Unable create container from current process: %v", err) + } + + tests := []struct { + name string + hostNodeName string + wantErr bool + wantData map[string]*regexp.Regexp + }{ + { + name: "valid", + hostNodeName: nodeName, + wantErr: false, + wantData: map[string]*regexp.Regexp{ + "tcptracer": getExpectedTcpTraceData(fixture, nodeName, pod, testContainer), + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + runtimeInfo := &utils.RuntimeInfo{ + HostNodeName: tt.hostNodeName, + } + + // Use a channel to get hold of the ContainerCollection (via a ContainerCollectionOption). + // We'll use this to add our pretend kubernetes container to. + ccChan := make(chan *containercollection.ContainerCollection) + + opts := getTestContainerCollectionOptions(ccChan, tt.hostNodeName, fixture.PeriscopeAccess.ClientConfig) + + waiter := func() { + // While the tracer is running, add a fake container and perform some DNS queries from its process. + cc := <-ccChan + cc.AddContainer(testContainer) + defer cc.RemoveContainer(testContainer.ID) + + // Make an HTTP request to a non-localhost URL - this should produce a TCP connect event. + url := "https://mcr.microsoft.com/v2/aks/periscope/tags/list" + _, err = http.Get(url) + if err != nil { + t.Fatalf("Unable to make request to %s: %v", url, err) + } + } + + c := NewInspektorGadgetTCPTraceCollector(utils.Linux, runtimeInfo, waiter, opts) + err := c.Collect() + + if (err != nil) != tt.wantErr { + t.Errorf("Collect() error = %v, wantErr %v", err, tt.wantErr) + } + data := c.GetData() + compareCollectorData(t, tt.wantData, data) + }) + } +} + +func getExpectedTcpTraceData(fixture *test.ClusterFixture, nodeName string, pod *corev1.Pod, container *containercollection.Container) *regexp.Regexp { + containerName := pod.Spec.Containers[0].Name + + pattern := fmt.Sprintf( + `{"node":%q,"namespace":%q,"pod":%q,"container":%q,"type":"normal","operation":"connect","pid":\d+,"comm":"[\w.]+","ipversion":4,"saddr":"[\d\.]+","daddr":"[\d\.]+","sport":\d+,"dport":443,"mountnsid":%d}`, + nodeName, fixture.KnownNamespaces.Periscope, pod.Name, containerName, container.Mntns) + + return regexp.MustCompile(pattern) +} From efbbf5f95ac6f28ba3e9e19e6b971cd280216c1a Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Fri, 20 Jan 2023 16:26:08 +1300 Subject: [PATCH 16/27] tidy go.mod --- go.mod | 16 +++++- go.sum | 169 ++++++++++++++++++++++++++++++++------------------------- 2 files changed, 110 insertions(+), 75 deletions(-) diff --git a/go.mod b/go.mod index 958242a7..abaac2c7 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,8 @@ require ( github.com/docker/docker v20.10.17+incompatible github.com/google/uuid v1.2.0 github.com/hashicorp/go-multierror v1.1.1 + github.com/inspektor-gadget/inspektor-gadget v0.12.1 + github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 helm.sh/helm/v3 v3.10.3 k8s.io/api v0.25.4 k8s.io/apimachinery v0.25.4 @@ -19,11 +21,16 @@ require ( k8s.io/metrics v0.25.2 ) -require github.com/inspektor-gadget/inspektor-gadget v0.12.1 - require ( + cloud.google.com/go v0.99.0 // indirect github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest v0.11.27 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.20 // indirect + github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/BurntSushi/toml v1.1.0 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect @@ -59,6 +66,7 @@ require ( github.com/go-openapi/swag v0.19.14 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v4 v4.2.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect @@ -107,11 +115,13 @@ require ( github.com/prometheus/procfs v0.7.3 // indirect github.com/rubenv/sql-migrate v1.1.2 // indirect github.com/russross/blackfriday v1.5.2 // indirect + github.com/s3rj1k/go-fanotify/fanotify v0.0.0-20210917134616-9c00a300bb7a // indirect github.com/shopspring/decimal v1.2.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect github.com/spf13/cast v1.4.1 // indirect github.com/spf13/cobra v1.5.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect @@ -119,6 +129,7 @@ require ( go.etcd.io/etcd/api/v3 v3.5.4 // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect + golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d // indirect golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect @@ -136,6 +147,7 @@ require ( k8s.io/apiextensions-apiserver v0.25.2 // indirect k8s.io/apiserver v0.25.2 // indirect k8s.io/component-base v0.25.2 // indirect + k8s.io/cri-api v0.23.1 // indirect k8s.io/klog/v2 v2.70.1 // indirect k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect diff --git a/go.sum b/go.sum index d40e5612..2f45183c 100644 --- a/go.sum +++ b/go.sum @@ -18,6 +18,15 @@ cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmW cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0 h1:y/cM2iqGgGi5D5DQZl6D9STN/3dR/Vx5Mp8s752oJTY= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -46,11 +55,16 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg6 github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.11.27 h1:F3R3q42aWytozkV8ihzcgMO4OA4cuqr3bNlsEuF6//A= +github.com/Azure/go-autorest/autorest v0.11.27/go.mod h1:7l8ybrIdUmGqZMTD0sRtAr8NvbHjfofbf8RSP2q7w7U= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= github.com/Azure/go-autorest/autorest/adal v0.9.20 h1:gJ3E98kMpFB1MFqQCvA1yFab8vthOeD4VlFRQULxahg= +github.com/Azure/go-autorest/autorest/adal v0.9.20/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= +github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= @@ -76,26 +90,22 @@ github.com/Masterminds/squirrel v1.5.3/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA4 github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/hcsshim v0.9.3 h1:k371PzBuRrz2b+ebGuI2nVgVhgsVX60jMfSw80NECxo= -github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= -github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -109,6 +119,7 @@ github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -124,6 +135,7 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= @@ -171,6 +183,7 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= @@ -184,10 +197,9 @@ github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -205,46 +217,11 @@ github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7 github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= -github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= -github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= -github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= -github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= -github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= -github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= -github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= -github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= -github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= -github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= -github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= -github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= -github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= @@ -266,7 +243,9 @@ github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -281,6 +260,7 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -299,6 +279,7 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -326,6 +307,7 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -337,6 +319,9 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= @@ -346,6 +331,8 @@ github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= @@ -421,8 +408,8 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -438,8 +425,6 @@ github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= @@ -511,14 +496,16 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo/v2 v2.1.6 h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU= github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= @@ -539,8 +526,6 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -563,6 +548,7 @@ github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rubenv/sql-migrate v1.1.2 h1:9M6oj4e//owVVHYrFISmY9LBRw6gzkCNmD9MV36tZeQ= github.com/rubenv/sql-migrate v1.1.2/go.mod h1:/7TZymwxN8VWumcIxw1jjHEcR1djpdkMHQPT4FWdnbQ= @@ -571,8 +557,9 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/s3rj1k/go-fanotify/fanotify v0.0.0-20210917134616-9c00a300bb7a h1:np2nR32/A/VcOG9Hn+IOPA8kMk1gbBzK5LpSsgq5pJI= +github.com/s3rj1k/go-fanotify/fanotify v0.0.0-20210917134616-9c00a300bb7a/go.mod h1:wiP6GQ2T378F+YIyuNw7yXtBxJZR+fqrrn1Z6UHZi0Q= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -585,6 +572,7 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -601,8 +589,6 @@ github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -612,8 +598,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= +github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= @@ -638,9 +624,6 @@ go.etcd.io/etcd/api/v3 v3.5.4 h1:OHVyt3TopwtUQ2GKdd5wu3PmmipR4FTwCqoEjSyRdIc= go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -661,14 +644,14 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -681,6 +664,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d h1:vtUKgx8dahOomfFzLREU8nSv25YHnTgLBn4rDnWZdU0= +golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -708,7 +693,6 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -747,8 +731,11 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -764,6 +751,9 @@ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -791,7 +781,6 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -800,6 +789,7 @@ golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -808,6 +798,7 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -835,15 +826,20 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI= golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -862,13 +858,10 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U= golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -918,7 +911,11 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -946,6 +943,15 @@ google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjR google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -995,7 +1001,24 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 h1:hrbNEivu7Zn1pxvHk6MBrq9iE22woVILTHqexqBxe6I= google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1017,10 +1040,16 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8= google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1072,28 +1101,22 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.25.2 h1:v6G8RyFcwf0HR5jQGIAYlvtRNrxMJQG1xJzaSeVnIS8= -k8s.io/api v0.25.2/go.mod h1:qP1Rn4sCVFwx/xIhe+we2cwBLTXNcheRyYXwajonhy0= k8s.io/api v0.25.4 h1:3YO8J4RtmG7elEgaWMb4HgmpS2CfY1QlaOz9nwB+ZSs= k8s.io/api v0.25.4/go.mod h1:IG2+RzyPQLllQxnhzD8KQNEu4c4YvyDTpSMztf4A0OQ= k8s.io/apiextensions-apiserver v0.25.2 h1:8uOQX17RE7XL02ngtnh3TgifY7EhekpK+/piwzQNnBo= k8s.io/apiextensions-apiserver v0.25.2/go.mod h1:iRwwRDlWPfaHhuBfQ0WMa5skdQfrE18QXJaJvIDLvE8= -k8s.io/apimachinery v0.25.2 h1:WbxfAjCx+AeN8Ilp9joWnyJ6xu9OMeS/fsfjK/5zaQs= -k8s.io/apimachinery v0.25.2/go.mod h1:hqqA1X0bsgsxI6dXsJ4HnNTBOmJNxyPp8dw3u2fSHwA= k8s.io/apimachinery v0.25.4 h1:CtXsuaitMESSu339tfhVXhQrPET+EiWnIY1rcurKnAc= k8s.io/apimachinery v0.25.4/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo= k8s.io/apiserver v0.25.2 h1:YePimobk187IMIdnmsMxsfIbC5p4eX3WSOrS9x6FEYw= k8s.io/apiserver v0.25.2/go.mod h1:30r7xyQTREWCkG2uSjgjhQcKVvAAlqoD+YyrqR6Cn+I= -k8s.io/cli-runtime v0.25.2 h1:XOx+SKRjBpYMLY/J292BHTkmyDffl/qOx3YSuFZkTuc= -k8s.io/cli-runtime v0.25.2/go.mod h1:OQx3+/0st6x5YpkkJQlEWLC73V0wHsOFMC1/roxV8Oc= k8s.io/cli-runtime v0.25.4 h1:GTSBN7aKBrc2LqpdO30CmHQqJtRmotxV7XsMSP+QZIk= k8s.io/cli-runtime v0.25.4/go.mod h1:JGOw1CR8v4Mcz6cEKA7bFQe0bPrNn1l5sGAX1/Ke4Eg= -k8s.io/client-go v0.25.2 h1:SUPp9p5CwM0yXGQrwYurw9LWz+YtMwhWd0GqOsSiefo= -k8s.io/client-go v0.25.2/go.mod h1:i7cNU7N+yGQmJkewcRD2+Vuj4iz7b30kI8OcL3horQ4= k8s.io/client-go v0.25.4 h1:3RNRDffAkNU56M/a7gUfXaEzdhZlYhoW8dgViGy5fn8= k8s.io/client-go v0.25.4/go.mod h1:8trHCAC83XKY0wsBIpbirZU4NTUpbuhc2JnI7OruGZw= k8s.io/component-base v0.25.2 h1:Nve/ZyHLUBHz1rqwkjXm/Re6IniNa5k7KgzxZpTfSQY= k8s.io/component-base v0.25.2/go.mod h1:90W21YMr+Yjg7MX+DohmZLzjsBtaxQDDwaX4YxDkl60= +k8s.io/cri-api v0.23.1 h1:0DHL/hpTf4Fp+QkUXFefWcp1fhjXr9OlNdY9X99c+O8= +k8s.io/cri-api v0.23.1/go.mod h1:REJE3PSU0h/LOV1APBrupxrEJqnoxZC8KWzkBUHwrK4= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= From 2a44057e0b4e59b6f21d28f958392bc3a1cbb1a0 Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Fri, 20 Jan 2023 16:54:54 +1300 Subject: [PATCH 17/27] fix some build errors --- cmd/aks-periscope/aks-periscope.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/aks-periscope/aks-periscope.go b/cmd/aks-periscope/aks-periscope.go index fe7ad87d..12178fae 100644 --- a/cmd/aks-periscope/aks-periscope.go +++ b/cmd/aks-periscope/aks-periscope.go @@ -131,7 +131,7 @@ func run(osIdentifier utils.OSIdentifier, knownFilePaths *utils.KnownFilePaths, collector.NewSystemPerfCollector(config, runtimeInfo), collector.NewWindowsLogsCollector(osIdentifier, runtimeInfo, knownFilePaths, fileSystem, 10*time.Second, 20*time.Minute), collector.NewInspektorGadgetDNSTraceCollector(osIdentifier, runtimeInfo, traceWaiter, containerCollectionOptions), - collector.NewInspektorGadgetTCPTraceCollector(osIdentifier, config, runtimeInfo, 2*time.Minute), + collector.NewInspektorGadgetTCPTraceCollector(osIdentifier, runtimeInfo, traceWaiter, containerCollectionOptions), } collectorGrp := new(sync.WaitGroup) From e0431c3e772fd90cb0ff9f9035ae8dadfc97dda3 Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Mon, 23 Jan 2023 10:02:05 +1300 Subject: [PATCH 18/27] allow building in a container (without .git folder) --- builder/Dockerfile.linux | 2 +- builder/Dockerfile.windows | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/builder/Dockerfile.linux b/builder/Dockerfile.linux index 9459af43..13010c88 100644 --- a/builder/Dockerfile.linux +++ b/builder/Dockerfile.linux @@ -16,7 +16,7 @@ RUN go mod download COPY . . -RUN go build ./cmd/aks-periscope +RUN go build -buildvcs=false ./cmd/aks-periscope # Add dependencies for building nsenter RUN apt-get update && \ diff --git a/builder/Dockerfile.windows b/builder/Dockerfile.windows index a3c94288..bb667b1d 100644 --- a/builder/Dockerfile.windows +++ b/builder/Dockerfile.windows @@ -16,7 +16,7 @@ RUN go mod download COPY . . -RUN go build ./cmd/aks-periscope +RUN go build -buildvcs=false ./cmd/aks-periscope # Runner FROM $BASE_IMAGE From bd44c1e87594e45953d650a34f459272433cefc7 Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Mon, 23 Jan 2023 10:02:56 +1300 Subject: [PATCH 19/27] reduce collection time for traces to avoid huge log outputs --- cmd/aks-periscope/aks-periscope.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/aks-periscope/aks-periscope.go b/cmd/aks-periscope/aks-periscope.go index 12178fae..9b34f1f9 100644 --- a/cmd/aks-periscope/aks-periscope.go +++ b/cmd/aks-periscope/aks-periscope.go @@ -106,7 +106,9 @@ func run(osIdentifier utils.OSIdentifier, knownFilePaths *utils.KnownFilePaths, containercollection.WithKubernetesEnrichment(runtimeInfo.HostNodeName, config), ) - traceCollectionPeriod := 2 * time.Minute + // Traces can produce a lot of data. + // TODO: Consider whether this should be lower or configurable. + traceCollectionPeriod := 30 * time.Second traceWaiter := func() { log.Printf("\twait for %v to stop collection", traceCollectionPeriod) time.Sleep(traceCollectionPeriod) From c94cf069ee73abd6a83086da61c87dae9b8bc53d Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Mon, 23 Jan 2023 10:04:23 +1300 Subject: [PATCH 20/27] ensure container collection can map between containers and PIDs --- deployment/base/daemon-set.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/deployment/base/daemon-set.yaml b/deployment/base/daemon-set.yaml index 6f2e0600..18dcab14 100644 --- a/deployment/base/daemon-set.yaml +++ b/deployment/base/daemon-set.yaml @@ -35,8 +35,8 @@ spec: mountPath: /secret - name: varlog mountPath: /var/log - - name: resolvlog - mountPath: /run/systemd/resolve + - name: run + mountPath: /run - name: etcvmlog mountPath: /etchostlogs resources: @@ -56,9 +56,11 @@ spec: - name: varlog hostPath: path: /var/log - - name: resolvlog + # Need /run from the host to access the container runtime (e.g. containerd) client socket, + # which is used by InspektorGadget to determine the PID for a container ID. + - name: run hostPath: - path: /run/systemd/resolve + path: /run - name: etcvmlog hostPath: path: /etc From d5005e887d8c63dbd1a038f55a08a14c551e3e04 Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Tue, 24 Jan 2023 12:28:17 +1300 Subject: [PATCH 21/27] fix Windows compilation errors --- cmd/aks-periscope/aks-periscope.go | 36 +------------ cmd/aks-periscope/collectorsfactory_linux.go | 52 +++++++++++++++++++ .../collectorsfactory_windows.go | 9 ++++ ...=> inspektor_trace_dns_collector_linux.go} | 7 +-- .../inspektor_trace_dns_collector_test.go | 28 +++------- ...=> inspektor_trace_tcp_collector_linux.go} | 7 +-- .../inspektor_trace_tcp_collector_test.go | 28 +++------- 7 files changed, 76 insertions(+), 91 deletions(-) create mode 100644 cmd/aks-periscope/collectorsfactory_linux.go create mode 100644 cmd/aks-periscope/collectorsfactory_windows.go rename pkg/collector/{inspektor_trace_dns_collector.go => inspektor_trace_dns_collector_linux.go} (96%) rename pkg/collector/{inspektor_trace_tcp_collector.go => inspektor_trace_tcp_collector_linux.go} (95%) diff --git a/cmd/aks-periscope/aks-periscope.go b/cmd/aks-periscope/aks-periscope.go index 9b34f1f9..7420ec80 100644 --- a/cmd/aks-periscope/aks-periscope.go +++ b/cmd/aks-periscope/aks-periscope.go @@ -14,9 +14,6 @@ import ( "github.com/Azure/aks-periscope/pkg/interfaces" "github.com/Azure/aks-periscope/pkg/utils" - containercollection "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection" - "github.com/inspektor-gadget/inspektor-gadget/pkg/runcfanotify" - restclient "k8s.io/client-go/rest" ) @@ -84,36 +81,6 @@ func run(osIdentifier utils.OSIdentifier, knownFilePaths *utils.KnownFilePaths, } } - // Use the default InspektorGadget behaviour for determining containers: - // https://github.com/inspektor-gadget/inspektor-gadget/blob/6b00fea3f925c9da478126931e774e340ca9bfdf/pkg/gadgettracermanager/gadgettracermanager.go#L275-L283 - var containerCollectionOptions []containercollection.ContainerCollectionOption - if runcfanotify.Supported() { - containerCollectionOptions = []containercollection.ContainerCollectionOption{ - containercollection.WithRuncFanotify(), - containercollection.WithInitialKubernetesContainers(runtimeInfo.HostNodeName), - } - } else { - containerCollectionOptions = []containercollection.ContainerCollectionOption{ - containercollection.WithPodInformer(runtimeInfo.HostNodeName), - } - } - - containerCollectionOptions = append( - containerCollectionOptions, - containercollection.WithNodeName(runtimeInfo.HostNodeName), - containercollection.WithCgroupEnrichment(), - containercollection.WithLinuxNamespaceEnrichment(), - containercollection.WithKubernetesEnrichment(runtimeInfo.HostNodeName, config), - ) - - // Traces can produce a lot of data. - // TODO: Consider whether this should be lower or configurable. - traceCollectionPeriod := 30 * time.Second - traceWaiter := func() { - log.Printf("\twait for %v to stop collection", traceCollectionPeriod) - time.Sleep(traceCollectionPeriod) - } - dnsCollector := collector.NewDNSCollector(osIdentifier, knownFilePaths, fileSystem) kubeletCmdCollector := collector.NewKubeletCmdCollector(osIdentifier, runtimeInfo) networkOutboundCollector := collector.NewNetworkOutboundCollector() @@ -132,9 +99,8 @@ func run(osIdentifier utils.OSIdentifier, knownFilePaths *utils.KnownFilePaths, collector.NewSystemLogsCollector(osIdentifier, runtimeInfo), collector.NewSystemPerfCollector(config, runtimeInfo), collector.NewWindowsLogsCollector(osIdentifier, runtimeInfo, knownFilePaths, fileSystem, 10*time.Second, 20*time.Minute), - collector.NewInspektorGadgetDNSTraceCollector(osIdentifier, runtimeInfo, traceWaiter, containerCollectionOptions), - collector.NewInspektorGadgetTCPTraceCollector(osIdentifier, runtimeInfo, traceWaiter, containerCollectionOptions), } + collectors = addOSSpecificCollectors(collectors, config, runtimeInfo) collectorGrp := new(sync.WaitGroup) diff --git a/cmd/aks-periscope/collectorsfactory_linux.go b/cmd/aks-periscope/collectorsfactory_linux.go new file mode 100644 index 00000000..20300fcd --- /dev/null +++ b/cmd/aks-periscope/collectorsfactory_linux.go @@ -0,0 +1,52 @@ +package main + +import ( + "log" + "time" + + "github.com/Azure/aks-periscope/pkg/collector" + "github.com/Azure/aks-periscope/pkg/interfaces" + "github.com/Azure/aks-periscope/pkg/utils" + + containercollection "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection" + "github.com/inspektor-gadget/inspektor-gadget/pkg/runcfanotify" + + restclient "k8s.io/client-go/rest" +) + +func addOSSpecificCollectors(collectors []interfaces.Collector, config *restclient.Config, runtimeInfo *utils.RuntimeInfo) []interfaces.Collector { + // Use the default InspektorGadget behaviour for determining containers: + // https://github.com/inspektor-gadget/inspektor-gadget/blob/6b00fea3f925c9da478126931e774e340ca9bfdf/pkg/gadgettracermanager/gadgettracermanager.go#L275-L283 + var containerCollectionOptions []containercollection.ContainerCollectionOption + if runcfanotify.Supported() { + containerCollectionOptions = []containercollection.ContainerCollectionOption{ + containercollection.WithRuncFanotify(), + containercollection.WithInitialKubernetesContainers(runtimeInfo.HostNodeName), + } + } else { + containerCollectionOptions = []containercollection.ContainerCollectionOption{ + containercollection.WithPodInformer(runtimeInfo.HostNodeName), + } + } + + containerCollectionOptions = append( + containerCollectionOptions, + containercollection.WithNodeName(runtimeInfo.HostNodeName), + containercollection.WithCgroupEnrichment(), + containercollection.WithLinuxNamespaceEnrichment(), + containercollection.WithKubernetesEnrichment(runtimeInfo.HostNodeName, config), + ) + + // Traces can produce a lot of data. + // TODO: Consider whether this should be lower or configurable. + traceCollectionPeriod := 30 * time.Second + traceWaiter := func() { + log.Printf("\twait for %v to stop collection", traceCollectionPeriod) + time.Sleep(traceCollectionPeriod) + } + + return append(collectors, + collector.NewInspektorGadgetDNSTraceCollector(runtimeInfo, traceWaiter, containerCollectionOptions), + collector.NewInspektorGadgetTCPTraceCollector(runtimeInfo, traceWaiter, containerCollectionOptions), + ) +} diff --git a/cmd/aks-periscope/collectorsfactory_windows.go b/cmd/aks-periscope/collectorsfactory_windows.go new file mode 100644 index 00000000..a1aa2cce --- /dev/null +++ b/cmd/aks-periscope/collectorsfactory_windows.go @@ -0,0 +1,9 @@ +package main + +import ( + "github.com/Azure/aks-periscope/pkg/interfaces" +) + +func addOSSpecificCollectors(collectors []interfaces.Collector, config *restclient.Config, runtimeInfo *utils.RuntimeInfo) []interfaces.Collector { + return collectors +} diff --git a/pkg/collector/inspektor_trace_dns_collector.go b/pkg/collector/inspektor_trace_dns_collector_linux.go similarity index 96% rename from pkg/collector/inspektor_trace_dns_collector.go rename to pkg/collector/inspektor_trace_dns_collector_linux.go index 1bbb0b5a..2c0ddbb2 100644 --- a/pkg/collector/inspektor_trace_dns_collector.go +++ b/pkg/collector/inspektor_trace_dns_collector_linux.go @@ -19,7 +19,6 @@ import ( // InspektorGadgetDNSTraceCollector defines a InspektorGadget Trace DNS Collector struct type InspektorGadgetDNSTraceCollector struct { data map[string]string - osIdentifier utils.OSIdentifier runtimeInfo *utils.RuntimeInfo waiter func() containerCollectionOptions []containercollection.ContainerCollectionOption @@ -28,22 +27,18 @@ type InspektorGadgetDNSTraceCollector struct { // CheckSupported implements the interface method func (collector *InspektorGadgetDNSTraceCollector) CheckSupported() error { // Inspektor Gadget relies on eBPF which is not (currently) available on Windows nodes. - if collector.osIdentifier != utils.Linux { - return fmt.Errorf("unsupported OS: %s", collector.osIdentifier) - } + // However, we're only compiling this for Linux OS right now, so we can skip the OS check. return nil } // NewInspektorGadgetDNSTraceCollector is a constructor. func NewInspektorGadgetDNSTraceCollector( - osIdentifier utils.OSIdentifier, runtimeInfo *utils.RuntimeInfo, waiter func(), containerCollectionOptions []containercollection.ContainerCollectionOption, ) *InspektorGadgetDNSTraceCollector { return &InspektorGadgetDNSTraceCollector{ data: make(map[string]string), - osIdentifier: osIdentifier, runtimeInfo: runtimeInfo, waiter: waiter, containerCollectionOptions: containerCollectionOptions, diff --git a/pkg/collector/inspektor_trace_dns_collector_test.go b/pkg/collector/inspektor_trace_dns_collector_test.go index b41e4437..2a32f237 100644 --- a/pkg/collector/inspektor_trace_dns_collector_test.go +++ b/pkg/collector/inspektor_trace_dns_collector_test.go @@ -16,7 +16,7 @@ import ( func TestInspektorGadgetDNSTraceCollectorGetName(t *testing.T) { const expectedName = "inspektorgadget-dnstrace" - c := NewInspektorGadgetDNSTraceCollector("", nil, nil, []containercollection.ContainerCollectionOption{}) + c := NewInspektorGadgetDNSTraceCollector(nil, nil, []containercollection.ContainerCollectionOption{}) actualName := c.GetName() if actualName != expectedName { t.Errorf("unexpected name: expected %s, found %s", expectedName, actualName) @@ -24,26 +24,10 @@ func TestInspektorGadgetDNSTraceCollectorGetName(t *testing.T) { } func TestInspektorGadgetDNSTraceCollectorCheckSupported(t *testing.T) { - tests := []struct { - osIdentifier utils.OSIdentifier - wantErr bool - }{ - { - osIdentifier: utils.Windows, - wantErr: true, - }, - { - osIdentifier: utils.Linux, - wantErr: false, - }, - } - - for _, tt := range tests { - c := NewInspektorGadgetDNSTraceCollector(tt.osIdentifier, nil, nil, []containercollection.ContainerCollectionOption{}) - err := c.CheckSupported() - if (err != nil) != tt.wantErr { - t.Errorf("CheckSupported() error = %v, wantErr %v", err, tt.wantErr) - } + c := NewInspektorGadgetDNSTraceCollector(nil, nil, []containercollection.ContainerCollectionOption{}) + err := c.CheckSupported() + if err != nil { + t.Errorf("error checking supported: %v", err) } } @@ -112,7 +96,7 @@ func TestInspektorGadgetDNSTraceCollectorCollect(t *testing.T) { } } - c := NewInspektorGadgetDNSTraceCollector(utils.Linux, runtimeInfo, waiter, opts) + c := NewInspektorGadgetDNSTraceCollector(runtimeInfo, waiter, opts) err := c.Collect() if (err != nil) != tt.wantErr { diff --git a/pkg/collector/inspektor_trace_tcp_collector.go b/pkg/collector/inspektor_trace_tcp_collector_linux.go similarity index 95% rename from pkg/collector/inspektor_trace_tcp_collector.go rename to pkg/collector/inspektor_trace_tcp_collector_linux.go index 20fd35c9..5b586a45 100644 --- a/pkg/collector/inspektor_trace_tcp_collector.go +++ b/pkg/collector/inspektor_trace_tcp_collector_linux.go @@ -21,7 +21,6 @@ import ( // InspektorGadgetTCPTraceCollector defines a InspektorGadget Trace TCP Collector struct type InspektorGadgetTCPTraceCollector struct { data map[string]string - osIdentifier utils.OSIdentifier runtimeInfo *utils.RuntimeInfo waiter func() containerCollectionOptions []containercollection.ContainerCollectionOption @@ -30,22 +29,18 @@ type InspektorGadgetTCPTraceCollector struct { // CheckSupported implements the interface method func (collector *InspektorGadgetTCPTraceCollector) CheckSupported() error { // Inspektor Gadget relies on eBPF which is not (currently) available on Windows nodes. - if collector.osIdentifier != utils.Linux { - return fmt.Errorf("unsupported OS: %s", collector.osIdentifier) - } + // However, we're only compiling this for Linux OS right now, so we can skip the OS check. return nil } // NewInspektorGadgetTCPTraceCollector is a constructor. func NewInspektorGadgetTCPTraceCollector( - osIdentifier utils.OSIdentifier, runtimeInfo *utils.RuntimeInfo, waiter func(), containerCollectionOptions []containercollection.ContainerCollectionOption, ) *InspektorGadgetTCPTraceCollector { return &InspektorGadgetTCPTraceCollector{ data: make(map[string]string), - osIdentifier: osIdentifier, runtimeInfo: runtimeInfo, waiter: waiter, containerCollectionOptions: containerCollectionOptions, diff --git a/pkg/collector/inspektor_trace_tcp_collector_test.go b/pkg/collector/inspektor_trace_tcp_collector_test.go index 8e84b196..43d057a0 100644 --- a/pkg/collector/inspektor_trace_tcp_collector_test.go +++ b/pkg/collector/inspektor_trace_tcp_collector_test.go @@ -15,7 +15,7 @@ import ( func TestInspektorGadgetTCPTraceCollectorGetName(t *testing.T) { const expectedName = "inspektorgadget-tcptrace" - c := NewInspektorGadgetTCPTraceCollector("", nil, nil, []containercollection.ContainerCollectionOption{}) + c := NewInspektorGadgetTCPTraceCollector(nil, nil, []containercollection.ContainerCollectionOption{}) actualName := c.GetName() if actualName != expectedName { t.Errorf("unexpected name: expected %s, found %s", expectedName, actualName) @@ -23,26 +23,10 @@ func TestInspektorGadgetTCPTraceCollectorGetName(t *testing.T) { } func TestInspektorGadgetTCPTraceCollectorCheckSupported(t *testing.T) { - tests := []struct { - osIdentifier utils.OSIdentifier - wantErr bool - }{ - { - osIdentifier: utils.Windows, - wantErr: true, - }, - { - osIdentifier: utils.Linux, - wantErr: false, - }, - } - - for _, tt := range tests { - c := NewInspektorGadgetTCPTraceCollector(tt.osIdentifier, nil, nil, []containercollection.ContainerCollectionOption{}) - err := c.CheckSupported() - if (err != nil) != tt.wantErr { - t.Errorf("CheckSupported() error = %v, wantErr %v", err, tt.wantErr) - } + c := NewInspektorGadgetTCPTraceCollector(nil, nil, []containercollection.ContainerCollectionOption{}) + err := c.CheckSupported() + if err != nil { + t.Errorf("error checking supported: %v", err) } } @@ -111,7 +95,7 @@ func TestInspektorGadgetTCPTraceCollectorCollect(t *testing.T) { } } - c := NewInspektorGadgetTCPTraceCollector(utils.Linux, runtimeInfo, waiter, opts) + c := NewInspektorGadgetTCPTraceCollector(runtimeInfo, waiter, opts) err := c.Collect() if (err != nil) != tt.wantErr { From 147120380cd8c6c51494daa6ec42d9e5a6380048 Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Tue, 24 Jan 2023 12:34:25 +1300 Subject: [PATCH 22/27] fixup! try to add e2e tests --- .vscode/launch.json | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index b6a37144..790cbf1a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,28 +8,14 @@ "name": "Launch Tests", "type": "go", "request": "launch", - "program": "${fileDirname}", - "mode": "test", - "env": {}, - "args": ["-test.v"], - "showLog": true - }, - { - "name": "Launch Tests with race check", - "type": "go", - "request": "launch", - //"program": "${fileDirname}", "program": "${fileDirname}/__debug_bin", "mode": "exec", "env": {}, - //"buildFlags": "-race", "args": ["-test.v"], "showLog": true, // https://github.com/golang/vscode-go/blob/master/docs/debugging.md#debug-a-package-test-as-root "console": "integratedTerminal", - // "console": "externalTerminal", "asRoot": true, - //"cwd": "${fileDirname}", "preLaunchTask": "go test (debug)", }, ] From e5cd7b80b529922cb3b01928202058a5f27eff9f Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Tue, 24 Jan 2023 12:40:05 +1300 Subject: [PATCH 23/27] revert changes for running IG as daemonset --- deployment/base/cluster-role.yaml | 8 +-- .../tools-resources/chaos/block-dns-nwp.yaml | 10 ---- .../tools-resources/chaos/block-tcp.yaml | 17 ------- .../tools-resources/chaos/coredns.yaml | 16 ------ .../tools-resources/chaos/dnsutils.yaml | 16 ------ .../tools-resources/chaos/fio_configs.yaml | 24 --------- .../chaos/fio_deployment_pvc.yaml | 49 ------------------- .../inspektor-gadget/biolatency.yaml | 9 ---- .../inspektor-gadget/biotop-trace.yaml | 18 ------- .../inspektor-gadget/dns-trace.yaml | 12 ----- .../inspektor-gadget/filetop-trace.yaml | 9 ---- .../inspektor-gadget/tcp-trace.yaml | 12 ----- 12 files changed, 1 insertion(+), 199 deletions(-) delete mode 100644 pkg/test/resources/tools-resources/chaos/block-dns-nwp.yaml delete mode 100644 pkg/test/resources/tools-resources/chaos/block-tcp.yaml delete mode 100644 pkg/test/resources/tools-resources/chaos/coredns.yaml delete mode 100644 pkg/test/resources/tools-resources/chaos/dnsutils.yaml delete mode 100644 pkg/test/resources/tools-resources/chaos/fio_configs.yaml delete mode 100644 pkg/test/resources/tools-resources/chaos/fio_deployment_pvc.yaml delete mode 100644 pkg/test/resources/tools-resources/inspektor-gadget/biolatency.yaml delete mode 100644 pkg/test/resources/tools-resources/inspektor-gadget/biotop-trace.yaml delete mode 100644 pkg/test/resources/tools-resources/inspektor-gadget/dns-trace.yaml delete mode 100644 pkg/test/resources/tools-resources/inspektor-gadget/filetop-trace.yaml delete mode 100644 pkg/test/resources/tools-resources/inspektor-gadget/tcp-trace.yaml diff --git a/deployment/base/cluster-role.yaml b/deployment/base/cluster-role.yaml index 7c0f1312..192e7db7 100644 --- a/deployment/base/cluster-role.yaml +++ b/deployment/base/cluster-role.yaml @@ -10,7 +10,7 @@ rules: resources: ["secrets"] verbs: ["list"] - apiGroups: [""] - resources: ["pods/portforward", "pods/exec"] + resources: ["pods/portforward"] verbs: ["create"] - apiGroups: ["aks-periscope.azure.github.com"] resources: ["diagnostics"] @@ -21,15 +21,9 @@ rules: - apiGroups: ["access.smi-spec.io", "specs.smi-spec.io", "split.smi-spec.io"] resources: ["*"] verbs: ["get", "list", "watch"] -- apiGroups: ["gadget.kinvolk.io"] - resources: ["*"] - verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] - apiGroups: ["config.openservicemesh.io"] resources: ["meshconfigs"] verbs: ["get", "list"] - apiGroups: ["admissionregistration.k8s.io"] resources: ["mutatingwebhookconfigurations", "validatingwebhookconfigurations"] verbs: ["get", "list"] -- apiGroups: ["admissionregistration.k8s.io"] - resources: ["mutatingwebhookconfigurations", "validatingwebhookconfigurations"] - verbs: ["get", "list"] diff --git a/pkg/test/resources/tools-resources/chaos/block-dns-nwp.yaml b/pkg/test/resources/tools-resources/chaos/block-dns-nwp.yaml deleted file mode 100644 index 4e796aa0..00000000 --- a/pkg/test/resources/tools-resources/chaos/block-dns-nwp.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: deny-all-egress - namespace: gadget -spec: - podSelector: - matchLabels: {} - policyTypes: - - Egress diff --git a/pkg/test/resources/tools-resources/chaos/block-tcp.yaml b/pkg/test/resources/tools-resources/chaos/block-tcp.yaml deleted file mode 100644 index 49614b05..00000000 --- a/pkg/test/resources/tools-resources/chaos/block-tcp.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: demo-policy - namespace: demo -spec: - podSelector: - matchLabels: - app: server - ingress: - - from: - - podSelector: - matchLabels: - app: client - ports: - - port: 80 - protocol: TCP \ No newline at end of file diff --git a/pkg/test/resources/tools-resources/chaos/coredns.yaml b/pkg/test/resources/tools-resources/chaos/coredns.yaml deleted file mode 100644 index cd90bf7b..00000000 --- a/pkg/test/resources/tools-resources/chaos/coredns.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: coredns-custom - namespace: kube-system - annotations: - kubectl.kubernetes.io/last-applied-configuration: poos and wees -data: - yourdns.server: | - .:53 { - health - - . { - whoami - } - } \ No newline at end of file diff --git a/pkg/test/resources/tools-resources/chaos/dnsutils.yaml b/pkg/test/resources/tools-resources/chaos/dnsutils.yaml deleted file mode 100644 index 1cd412e4..00000000 --- a/pkg/test/resources/tools-resources/chaos/dnsutils.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: dnsutils - namespace: demo - labels: - app: dns -spec: - containers: - - name: dnsutils - image: registry.k8s.io/e2e-test-images/jessie-dnsutils:1.3 - command: - - sleep - - "3600" - imagePullPolicy: IfNotPresent - restartPolicy: Always \ No newline at end of file diff --git a/pkg/test/resources/tools-resources/chaos/fio_configs.yaml b/pkg/test/resources/tools-resources/chaos/fio_configs.yaml deleted file mode 100644 index 865e642f..00000000 --- a/pkg/test/resources/tools-resources/chaos/fio_configs.yaml +++ /dev/null @@ -1,24 +0,0 @@ ---- -kind: ConfigMap -apiVersion: v1 -metadata: - name: fio-job-config -data: - fio.job: |- - [global] - ioengine=psync - direct=1 - buffered=0 - size=10G - iodepth=1000 - numjobs=100 - group_reporting - refill_buffers - rwmixread=80 - norandommap - randrepeat=0 - percentage_random=0 - bs=512K - buffer_compress_percentage=50 - rw=read - [testjob] diff --git a/pkg/test/resources/tools-resources/chaos/fio_deployment_pvc.yaml b/pkg/test/resources/tools-resources/chaos/fio_deployment_pvc.yaml deleted file mode 100644 index b2e393ac..00000000 --- a/pkg/test/resources/tools-resources/chaos/fio_deployment_pvc.yaml +++ /dev/null @@ -1,49 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: fio - labels: - app: fio -spec: - replicas: 3 - selector: - matchLabels: - app: fio - template: - metadata: - labels: - app: fio - spec: - containers: - - name: fio - image: joshuarobinson/fio:3.19 - command: ["sh"] - args: ["-c", "echo ${HOSTNAME} && mkdir -p /scratch/${HOSTNAME} && fio /configs/fio.job --eta=never --directory=/scratch/${HOSTNAME}"] - volumeMounts: - - name: fio-config-vol - mountPath: /configs - - name: fio-data - mountPath: /scratch - imagePullPolicy: Always - restartPolicy: Always - volumes: - - name: fio-config-vol - configMap: - name: fio-job-config - - name: fio-data - persistentVolumeClaim: - claimName: fio-claim ---- -kind: PersistentVolumeClaim -apiVersion: v1 -metadata: - name: fio-claim -spec: - storageClassName: azuredisk-csi-premium-zrs - accessModes: - - ReadWriteMany - volumeMode: Block - resources: - requests: - storage: 1Ti diff --git a/pkg/test/resources/tools-resources/inspektor-gadget/biolatency.yaml b/pkg/test/resources/tools-resources/inspektor-gadget/biolatency.yaml deleted file mode 100644 index 369e6583..00000000 --- a/pkg/test/resources/tools-resources/inspektor-gadget/biolatency.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: gadget.kinvolk.io/v1alpha1 -kind: Trace -metadata: - name: biolatency - namespace: gadget -spec: - gadget: biolatency - runMode: Manual - outputMode: Status \ No newline at end of file diff --git a/pkg/test/resources/tools-resources/inspektor-gadget/biotop-trace.yaml b/pkg/test/resources/tools-resources/inspektor-gadget/biotop-trace.yaml deleted file mode 100644 index 4989885e..00000000 --- a/pkg/test/resources/tools-resources/inspektor-gadget/biotop-trace.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: gadget.kinvolk.io/v1alpha1 -kind: Trace -metadata: - name: biotop-f - namespace: gadget - labels: - gadgetName: biotop - namespace: demo - outputMode: Stream -spec: - gadget: biotop - runMode: Manual - outputMode: Stream - node: aks-agentpool-14358782-vmss000002 - parameters: - interval: "1" - max_rows: "20" - sort_by: all \ No newline at end of file diff --git a/pkg/test/resources/tools-resources/inspektor-gadget/dns-trace.yaml b/pkg/test/resources/tools-resources/inspektor-gadget/dns-trace.yaml deleted file mode 100644 index aa5e8880..00000000 --- a/pkg/test/resources/tools-resources/inspektor-gadget/dns-trace.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: gadget.kinvolk.io/v1alpha1 -kind: Trace -metadata: - name: dns-k9ptr - namespace: gadget - annotations: - gadget.kinvolk.io/operation: start -spec: - node: aks-agentpool-14358782-vmss000000 - gadget: dns - outputMode: Stream - runMode: Manual \ No newline at end of file diff --git a/pkg/test/resources/tools-resources/inspektor-gadget/filetop-trace.yaml b/pkg/test/resources/tools-resources/inspektor-gadget/filetop-trace.yaml deleted file mode 100644 index b3e54d3d..00000000 --- a/pkg/test/resources/tools-resources/inspektor-gadget/filetop-trace.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: gadget.kinvolk.io/v1alpha1 -kind: Trace -metadata: - name: filetop - namespace: gadget -spec: - gadget: filetop - runMode: Manual - outputMode: Stream \ No newline at end of file diff --git a/pkg/test/resources/tools-resources/inspektor-gadget/tcp-trace.yaml b/pkg/test/resources/tools-resources/inspektor-gadget/tcp-trace.yaml deleted file mode 100644 index 6ec44b7d..00000000 --- a/pkg/test/resources/tools-resources/inspektor-gadget/tcp-trace.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: gadget.kinvolk.io/v1alpha1 -kind: Trace -metadata: - name: tcptracer-t27aa - namespace: gadget - annotations: - gadget.kinvolk.io/operation: start -spec: - gadget: tcptracer - runMode: Manual - node: aks-nodepool1-11865456-vmss000000 - outputMode: Stream From 0acc84b51edf787090049550da91b927addb7ad4 Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Fri, 12 May 2023 16:12:39 +1200 Subject: [PATCH 24/27] try to fix linting error and test failure --- .github/workflows/ci-pipeline.yaml | 2 +- pkg/collector/inspektor_trace_dns_collector_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-pipeline.yaml b/.github/workflows/ci-pipeline.yaml index c089a21c..49d1aa40 100644 --- a/.github/workflows/ci-pipeline.yaml +++ b/.github/workflows/ci-pipeline.yaml @@ -48,6 +48,6 @@ jobs: with: go-version: ${{ env.GO_VERSION }} - name: Go tests - run: go test -v -race -coverprofile=coverage.out -covermode=atomic ./... + run: sudo go test -v -race -coverprofile=coverage.out -covermode=atomic ./... - name: Upload coverage to Codecov run: bash <(curl -s https://codecov.io/bash) -C $(Build.SourceVersion) diff --git a/pkg/collector/inspektor_trace_dns_collector_test.go b/pkg/collector/inspektor_trace_dns_collector_test.go index 2a32f237..4e02f8c8 100644 --- a/pkg/collector/inspektor_trace_dns_collector_test.go +++ b/pkg/collector/inspektor_trace_dns_collector_test.go @@ -92,7 +92,7 @@ func TestInspektorGadgetDNSTraceCollectorCollect(t *testing.T) { for _, domain := range domains { // Perform a DNS lookup (discarding the result because we're only testing the events it triggers) - net.LookupIP(domain) + _, _ = net.LookupIP(domain) } } From 1475a27f85823a8b67e7e202b4fef2de2e40d0dd Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Fri, 12 May 2023 16:44:10 +1200 Subject: [PATCH 25/27] fix systemlogs test --- pkg/collector/systemlogs_collector_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/collector/systemlogs_collector_test.go b/pkg/collector/systemlogs_collector_test.go index 70a09038..b3964aed 100644 --- a/pkg/collector/systemlogs_collector_test.go +++ b/pkg/collector/systemlogs_collector_test.go @@ -64,7 +64,7 @@ func TestSystemLogsCollectorCollect(t *testing.T) { { name: "get system logs", want: 1, - wantErr: true, + wantErr: false, }, } From ed625da0e2fb9b0cf001cfb571e83cbcfb8d2157 Mon Sep 17 00:00:00 2001 From: Beilei Huang Date: Tue, 16 May 2023 12:34:58 +1200 Subject: [PATCH 26/27] fix go linting issues --- pkg/collector/inspektor_trace_common_test.go | 2 +- pkg/collector/smi_collector_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/collector/inspektor_trace_common_test.go b/pkg/collector/inspektor_trace_common_test.go index b5f2d138..2915cef9 100644 --- a/pkg/collector/inspektor_trace_common_test.go +++ b/pkg/collector/inspektor_trace_common_test.go @@ -96,7 +96,7 @@ func getCurrentProcessAsKubernetesContainer(pod *corev1.Pod) (*containercollecti // (https://github.com/inspektor-gadget/inspektor-gadget/blob/08b450065bb839e33012d80d476b3a3c17946379/pkg/container-collection/options.go#L497-L500) OciConfig: &ocispec.Spec{ Mounts: []ocispec.Mount{ - ocispec.Mount{ + { Destination: "/dev/termination-log", Type: "bind", Source: fmt.Sprintf("/var/lib/kubelet/pods/%s/containers/%s/dnstest/a1234abcd", pod.ObjectMeta.UID, pod.Spec.Containers[0].Name), diff --git a/pkg/collector/smi_collector_test.go b/pkg/collector/smi_collector_test.go index 31d47938..3c5d1746 100644 --- a/pkg/collector/smi_collector_test.go +++ b/pkg/collector/smi_collector_test.go @@ -148,7 +148,7 @@ func getExpectedSmiData(knownNamespaces *test.KnownNamespaces) map[string]*regex crdName: "tcproutes.specs.smi-spec.io", kind: "TCPRoute", resources: []crdResource{ - crdResource{ + { namespace: knownNamespaces.OsmBookWarehouse, name: "mysql", apiVersion: "specs.smi-spec.io/v1alpha4", @@ -159,7 +159,7 @@ func getExpectedSmiData(knownNamespaces *test.KnownNamespaces) map[string]*regex crdName: "trafficsplits.split.smi-spec.io", kind: "TrafficSplit", resources: []crdResource{ - crdResource{ + { namespace: knownNamespaces.OsmBookStore, name: "bookstore-split", apiVersion: "split.smi-spec.io/v1alpha2", From f7e18fef82d3846291007215bbc9de699dd46a5b Mon Sep 17 00:00:00 2001 From: Peter Bomber Date: Tue, 16 May 2023 13:59:01 +1200 Subject: [PATCH 27/27] fix windows build errors --- cmd/aks-periscope/collectorsfactory_windows.go | 2 ++ ...ctor_test.go => inspektor_trace_dns_collector_linux_test.go} | 0 ...ctor_test.go => inspektor_trace_tcp_collector_linux_test.go} | 0 3 files changed, 2 insertions(+) rename pkg/collector/{inspektor_trace_dns_collector_test.go => inspektor_trace_dns_collector_linux_test.go} (100%) rename pkg/collector/{inspektor_trace_tcp_collector_test.go => inspektor_trace_tcp_collector_linux_test.go} (100%) diff --git a/cmd/aks-periscope/collectorsfactory_windows.go b/cmd/aks-periscope/collectorsfactory_windows.go index a1aa2cce..ed275435 100644 --- a/cmd/aks-periscope/collectorsfactory_windows.go +++ b/cmd/aks-periscope/collectorsfactory_windows.go @@ -2,6 +2,8 @@ package main import ( "github.com/Azure/aks-periscope/pkg/interfaces" + "github.com/Azure/aks-periscope/pkg/utils" + restclient "k8s.io/client-go/rest" ) func addOSSpecificCollectors(collectors []interfaces.Collector, config *restclient.Config, runtimeInfo *utils.RuntimeInfo) []interfaces.Collector { diff --git a/pkg/collector/inspektor_trace_dns_collector_test.go b/pkg/collector/inspektor_trace_dns_collector_linux_test.go similarity index 100% rename from pkg/collector/inspektor_trace_dns_collector_test.go rename to pkg/collector/inspektor_trace_dns_collector_linux_test.go diff --git a/pkg/collector/inspektor_trace_tcp_collector_test.go b/pkg/collector/inspektor_trace_tcp_collector_linux_test.go similarity index 100% rename from pkg/collector/inspektor_trace_tcp_collector_test.go rename to pkg/collector/inspektor_trace_tcp_collector_linux_test.go