diff --git a/.github/workflows/release-charts.yaml b/.github/workflows/release-charts.yaml index d01578a79..cf6738b1a 100644 --- a/.github/workflows/release-charts.yaml +++ b/.github/workflows/release-charts.yaml @@ -40,7 +40,7 @@ jobs: run: | set -euo pipefail export TAG=$(make version) - helm package ./deploy/manifests/controller/helm/retina --version $TAG + helm package ./deploy/legacy/manifests/controller/helm/retina --version $TAG # Get Helm chart's SHA digest from helm push cmd output helm push retina-$TAG.tgz oci://ghcr.io/${{ github.repository }}/charts >> helm_push_result.txt 2>&1 cat helm_push_result.txt diff --git a/.golangci.yaml b/.golangci.yaml index 8457366f8..7f3cd015e 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -12,6 +12,7 @@ linters: disable: - maligned - scopelint + - gci enable: - exportloopref - goconst diff --git a/Makefile b/Makefile index 0ffb838d0..a35a0dfcf 100644 --- a/Makefile +++ b/Makefile @@ -34,6 +34,8 @@ PLATFORM ?= $(OS)/$(ARCH) PLATFORMS ?= linux/amd64 linux/arm64 windows/amd64 OS_VERSION ?= ltsc2019 +HUBBLE_VERSION ?= v0.13.0 + CONTAINER_BUILDER ?= docker CONTAINER_RUNTIME ?= docker YEAR ?= 2022 @@ -41,6 +43,12 @@ YEAR ?= 2022 ALL_ARCH.linux = amd64 arm64 ALL_ARCH.windows = amd64 +####### +# TLS # +####### +ENABLE_TLS ?= true +CERT_DIR := $(REPO_ROOT)/.certs + # TAG is OS and platform agonstic, which can be used for binary version and image manifest tag, # while RETINA_PLATFORM_TAG is platform specific, which can be used for image built for specific platforms. RETINA_PLATFORM_TAG ?= $(TAG)-$(subst /,-,$(PLATFORM)) @@ -236,6 +244,7 @@ container-docker: buildx # util target to build container images using docker bu --build-arg GOARCH=$$arch \ --build-arg GOOS=$$os \ --build-arg OS_VERSION=$(OS_VERSION) \ + --build-arg HUBBLE_VERSION=$(HUBBLE_VERSION) \ --build-arg VERSION=$(VERSION) $(EXTRA_BUILD_ARGS) \ --target=$(TARGET) \ -t $(IMAGE_REGISTRY)/$(IMAGE):$(TAG) \ @@ -376,7 +385,7 @@ HELM_IMAGE_TAG ?= v0.0.2 # basic/node-level mode helm-install: manifests - helm upgrade --install retina ./deploy/manifests/controller/helm/retina/ \ + helm upgrade --install retina ./deploy/legacy/manifests/controller/helm/retina/ \ --namespace kube-system \ --set image.repository=$(IMAGE_REGISTRY)/$(RETINA_IMAGE) \ --set image.initRepository=$(IMAGE_REGISTRY)/$(RETINA_INIT_IMAGE) \ @@ -389,7 +398,7 @@ helm-install: manifests --set enabledPlugin_linux="\[dropreason\,packetforward\,linuxutil\,dns\]" helm-install-with-operator: manifests - helm upgrade --install retina ./deploy/manifests/controller/helm/retina/ \ + helm upgrade --install retina ./deploy/legacy/manifests/controller/helm/retina/ \ --namespace kube-system \ --set image.repository=$(IMAGE_REGISTRY)/$(RETINA_IMAGE) \ --set image.initRepository=$(IMAGE_REGISTRY)/$(RETINA_INIT_IMAGE) \ @@ -406,7 +415,7 @@ helm-install-with-operator: manifests # advanced/pod-level mode with scale limitations, where metrics are aggregated by source and destination Pod helm-install-advanced-remote-context: manifests - helm upgrade --install retina ./deploy/manifests/controller/helm/retina/ \ + helm upgrade --install retina ./deploy/legacy/manifests/controller/helm/retina/ \ --namespace kube-system \ --set image.repository=$(IMAGE_REGISTRY)/$(RETINA_IMAGE) \ --set image.initRepository=$(IMAGE_REGISTRY)/$(RETINA_INIT_IMAGE) \ @@ -425,7 +434,7 @@ helm-install-advanced-remote-context: manifests # advanced/pod-level mode designed for scale, where metrics are aggregated by "local" Pod (source for outgoing traffic, destination for incoming traffic) helm-install-advanced-local-context: manifests - helm upgrade --install retina ./deploy/manifests/controller/helm/retina/ \ + helm upgrade --install retina ./deploy/legacy/manifests/controller/helm/retina/ \ --namespace kube-system \ --set image.repository=$(IMAGE_REGISTRY)/$(RETINA_IMAGE) \ --set image.initRepository=$(IMAGE_REGISTRY)/$(RETINA_INIT_IMAGE) \ @@ -442,9 +451,57 @@ helm-install-advanced-local-context: manifests --set enablePodLevel=true \ --set enableAnnotations=true +helm-install-hubble: + helm upgrade --install retina ./deploy/hubble/manifests/controller/helm/retina/ \ + --namespace kube-system \ + --set operator.enabled=true \ + --set operator.repository=$(IMAGE_REGISTRY)/$(RETINA_OPERATOR_IMAGE) \ + --set operator.tag=$(HELM_IMAGE_TAG) \ + --set agent.enabled=true \ + --set agent.repository=$(IMAGE_REGISTRY)/$(RETINA_IMAGE) \ + --set agent.tag=$(HELM_IMAGE_TAG) \ + --set agent.init.enabled=true \ + --set agent.init.repository=$(IMAGE_REGISTRY)/$(RETINA_INIT_IMAGE) \ + --set agent.init.tag=$(HELM_IMAGE_TAG) \ + --set logLevel=info \ + --set hubble.tls.enabled=$(ENABLE_TLS) \ + --set hubble.relay.tls.server.enabled=$(ENABLE_TLS) \ + --set hubble.tls.auto.enabled=$(ENABLE_TLS) \ + --set hubble.tls.auto.method=cronJob \ + --set hubble.tls.auto.certValidityDuration=1 \ + --set hubble.tls.auto.schedule="*/10 * * * *" + +helm-install-without-tls: clean-certs + $(MAKE) helm-install-hubble ENABLE_TLS=false + helm-uninstall: helm uninstall retina -n kube-system +.PHONY: get-certs +get-certs: + mkdir -p $(CERT_DIR) + $(foreach kv,$(CERT_FILES),\ + $(eval FILE=$(word 1,$(subst :, ,$(kv)))) \ + $(eval CONFIG_KEY=$(word 2,$(subst :, ,$(kv)))) \ + kubectl get secret $(TLS_SECRET_NAME) \ + -n kube-system \ + -o jsonpath="{.data['$(call escape_dot,$(FILE))']}" \ + | base64 -d > $(CERT_DIR)/$(FILE);\ + hubble config set $(CONFIG_KEY) $(CERT_DIR)/$(FILE);\ + ) + hubble config set tls true + hubble config set tls-server-name instance.hubble-relay.cilium.io + +.PHONY: clean-certs +clean-certs: + rm -rf $(CERT_DIR) + $(foreach kv,$(CERT_FILES),\ + $(eval CONFIG_KEY=$(word 2,$(subst :, ,$(kv)))) \ + hubble config reset $(CONFIG_KEY);\ + ) + hubble config set tls false + hubble config reset tls-server-name + .PHONY: docs docs: echo $(PWD) @@ -463,6 +520,12 @@ quick-build: quick-deploy: $(MAKE) helm-install-advanced-local-context HELM_IMAGE_TAG=$(TAG)-linux-amd64 +.PHONY: quick-deploy-hubble +quick-deploy-hubble: + $(MAKE) helm-uninstall || true + $(MAKE) helm-install-without-tls HELM_IMAGE_TAG=$(TAG)-linux-amd64 + .PHONY: simplify-dashboards simplify-dashboards: - cd deploy/grafana/dashboards/ && go test . -tags=dashboard,simplifydashboard -v + cd deploy/legacy/graphana/dashboards && go test . -tags=dashboard,simplifydashboard -v && cd $(REPO_ROOT) + diff --git a/cmd/hubble/LICENSE b/cmd/hubble/LICENSE new file mode 100644 index 000000000..c8d4ae33c --- /dev/null +++ b/cmd/hubble/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} Authors of Cilium and Retina + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/cmd/hubble/cells_linux.go b/cmd/hubble/cells_linux.go new file mode 100644 index 000000000..9851f6247 --- /dev/null +++ b/cmd/hubble/cells_linux.go @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// Copyright Authors of Cilium. +// Modified by Authors of Retina. +package hubble + +import ( + "github.com/cilium/cilium/pkg/defaults" + "github.com/cilium/cilium/pkg/gops" + "github.com/cilium/cilium/pkg/hive/cell" + k8sClient "github.com/cilium/cilium/pkg/k8s/client" + "github.com/cilium/cilium/pkg/option" + "github.com/cilium/cilium/pkg/pprof" + "github.com/cilium/proxy/pkg/logging" + "github.com/cilium/proxy/pkg/logging/logfields" + "github.com/microsoft/retina/pkg/config" + rnode "github.com/microsoft/retina/pkg/controllers/daemon/nodereconciler" + hubbleserver "github.com/microsoft/retina/pkg/hubble" + retinak8s "github.com/microsoft/retina/pkg/k8s" + "github.com/microsoft/retina/pkg/managers/pluginmanager" + "github.com/microsoft/retina/pkg/monitoragent" + "github.com/microsoft/retina/pkg/servermanager" + "github.com/microsoft/retina/pkg/shared/telemetry" + "k8s.io/client-go/rest" +) + +var ( + Agent = cell.Module( + "agent", + "Retina-Agent", + Infrastructure, + ControlPlane, + ) + daemonSubsys = "daemon" + logger = logging.DefaultLogger.WithField(logfields.LogSubsys, daemonSubsys) + + Infrastructure = cell.Module( + "infrastructure", + "Infrastructure", + + // Register the pprof HTTP handlers, to get runtime profiling data. + pprof.Cell, + cell.Config(pprof.Config{ + Pprof: true, + PprofAddress: option.PprofAddressAgent, + PprofPort: option.PprofPortAgent, + }), + + // Runs the gops agent, a tool to diagnose Go processes. + gops.Cell(defaults.GopsPortAgent), + + // Parse Retina specific configuration + config.Cell, + + // Kubernetes client + k8sClient.Cell, + + cell.Provide(func(cfg config.Config, k8sCfg *rest.Config) telemetry.Config { + return telemetry.Config{ + Component: "retina-agent", + EnableTelemetry: cfg.EnableTelemetry, + ApplicationInsightsID: applicationInsightsID, + RetinaVersion: retinaVersion, + EnabledPlugins: cfg.EnabledPlugin, + } + }), + telemetry.Constructor, + + // cell.Provide(func() cell.Lifecycle { + // return &cell.DefaultLifecycle{} + // }), + ) + + ControlPlane = cell.Module( + "control-plane", + "Control Plane", + + // monitorAgent.Cell, + monitoragent.Cell, + + daemonCell, + + // Provides the node reconciler + rnode.Cell, + + // Provides the hubble agent + hubbleserver.Cell, + + pluginmanager.Cell, + + retinak8s.Cell, + + servermanager.Cell, + + telemetry.Heartbeat, + ) +) diff --git a/cmd/hubble/daemon_linux.go b/cmd/hubble/daemon_linux.go new file mode 100644 index 000000000..2c4c82a61 --- /dev/null +++ b/cmd/hubble/daemon_linux.go @@ -0,0 +1,154 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// Copyright Authors of Cilium. +// Modified by Authors of Retina. +package hubble + +import ( + "context" + "fmt" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + + "github.com/microsoft/retina/pkg/config" + "github.com/microsoft/retina/pkg/managers/pluginmanager" + "github.com/microsoft/retina/pkg/managers/servermanager" + + retinak8s "github.com/microsoft/retina/pkg/k8s" + + "github.com/cilium/cilium/pkg/hive/cell" + v1 "github.com/cilium/cilium/pkg/hubble/api/v1" + "github.com/cilium/cilium/pkg/ipcache" + "github.com/cilium/cilium/pkg/k8s" + k8sClient "github.com/cilium/cilium/pkg/k8s/client" + "github.com/cilium/cilium/pkg/k8s/watchers" + monitoragent "github.com/cilium/cilium/pkg/monitor/agent" + "github.com/cilium/cilium/pkg/node" + "github.com/cilium/workerpool" + + corev1 "k8s.io/api/core/v1" + k8sruntime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + logf "sigs.k8s.io/controller-runtime/pkg/log" + zapf "sigs.k8s.io/controller-runtime/pkg/log/zap" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" +) + +var ( + scheme = k8sruntime.NewScheme() + daemonCell = cell.Module( + "daemon", + "Retina-Agent Daemon", + // Create the controller manager, provides the hive with the controller manager and its client + cell.Provide(func(k8sCfg *rest.Config, logger logrus.FieldLogger, rcfg config.RetinaHubbleConfig) (ctrl.Manager, client.Client, error) { + if err := corev1.AddToScheme(scheme); err != nil { //nolint:govet // intentional shadow + logger.Error("failed to add corev1 to scheme") + return nil, nil, errors.Wrap(err, "failed to add corev1 to scheme") + } + + mgrOption := ctrl.Options{ + Scheme: scheme, + Metrics: metricsserver.Options{ + BindAddress: rcfg.MetricsBindAddress, + }, + HealthProbeBindAddress: rcfg.HealthProbeBindAddress, + LeaderElection: rcfg.LeaderElection, + LeaderElectionID: "ecaf1259.retina.io", + } + + logf.SetLogger(zapf.New()) + ctrlManager, err := ctrl.NewManager(k8sCfg, mgrOption) + if err != nil { + logger.Error("failed to create manager") + return nil, nil, fmt.Errorf("creating new controller-runtime manager: %w", err) + } + + return ctrlManager, ctrlManager.GetClient(), nil + }), + + // Start the controller manager + cell.Invoke(func(l logrus.FieldLogger, lifecycle cell.Lifecycle, ctrlManager ctrl.Manager) { + var wp *workerpool.WorkerPool + lifecycle.Append( + cell.Hook{ + OnStart: func(cell.HookContext) error { + wp = workerpool.New(1) + l.Info("starting controller-runtime manager") + if err := wp.Submit("controller-runtime manager", ctrlManager.Start); err != nil { + return errors.Wrap(err, "failed to submit controller-runtime manager to workerpool") + } + return nil + }, + OnStop: func(cell.HookContext) error { + if err := wp.Close(); err != nil { + return errors.Wrap(err, "failed to close controller-runtime workerpool") + } + return nil + }, + }, + ) + }), + cell.Invoke(newDaemonPromise), + ) +) + +type Daemon struct { + clientset k8sClient.Clientset + + log logrus.FieldLogger + monitorAgent monitoragent.Agent + pluginManager *pluginmanager.PluginManager + HTTPServer *servermanager.HTTPServer + client client.Client + eventChan chan *v1.Event + k8swatcher *watchers.K8sWatcher + localNodeStore *node.LocalNodeStore + ipc *ipcache.IPCache + svcCache *k8s.ServiceCache +} + +func newDaemon(params *daemonParams) *Daemon { + return &Daemon{ + monitorAgent: params.MonitorAgent, + pluginManager: params.PluginManager, + HTTPServer: params.HTTPServer, + clientset: params.Clientset, + log: params.Log, + client: params.Client, + eventChan: params.EventChan, + k8swatcher: params.K8sWatcher, + localNodeStore: params.Lnds, + ipc: params.IPC, + svcCache: params.SvcCache, + } +} + +func (d *Daemon) Run(ctx context.Context) error { + // Start K8s watcher + d.log.WithField("localNodeStore", d.localNodeStore).Info("Starting local node store") + + // Start K8s watcher. Will block till sync is complete or timeout. + // If sync doesn't complete within timeout (3 minutes), causes fatal error. + retinak8s.Start(ctx, d.k8swatcher) + + go d.generateEvents(ctx) + return nil +} + +func (d *Daemon) generateEvents(ctx context.Context) { + for { + select { + case <-ctx.Done(): + return + case event := <-d.eventChan: + d.log.WithField("event", event).Debug("Sending event to monitor agent") + err := d.monitorAgent.SendEvent(0, event) + if err != nil { + d.log.WithError(err).Error("Unable to send event to monitor agent") + } + } + } +} diff --git a/cmd/hubble/daemon_main_linux.go b/cmd/hubble/daemon_main_linux.go new file mode 100644 index 000000000..9b60e5b65 --- /dev/null +++ b/cmd/hubble/daemon_main_linux.go @@ -0,0 +1,315 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// Copyright Authors of Cilium. +// Modified by Authors of Retina. +// This bootstraps Hubble control plane. +package hubble + +import ( + "context" + "fmt" + "io" + "math" + "path/filepath" + "strings" + + zaphook "github.com/Sytten/logrus-zap-hook" + "github.com/cilium/cilium/pkg/defaults" + "github.com/cilium/cilium/pkg/hive" + "github.com/cilium/cilium/pkg/hive/cell" + v1 "github.com/cilium/cilium/pkg/hubble/api/v1" + "github.com/cilium/cilium/pkg/hubble/exporter/exporteroption" + "github.com/cilium/cilium/pkg/hubble/observer/observeroption" + "github.com/cilium/cilium/pkg/ipcache" + "github.com/cilium/cilium/pkg/k8s" + k8sClient "github.com/cilium/cilium/pkg/k8s/client" + "github.com/cilium/cilium/pkg/k8s/watchers" + "github.com/cilium/cilium/pkg/metrics" + monitorAgent "github.com/cilium/cilium/pkg/monitor/agent" + monitorAPI "github.com/cilium/cilium/pkg/monitor/api" + "github.com/cilium/cilium/pkg/node" + "github.com/cilium/cilium/pkg/option" + "github.com/cilium/cilium/pkg/promise" + "github.com/cilium/cilium/pkg/time" + "github.com/cilium/proxy/pkg/logging" + "github.com/microsoft/retina/pkg/config" + "github.com/microsoft/retina/pkg/log" + "github.com/microsoft/retina/pkg/managers/pluginmanager" + "github.com/microsoft/retina/pkg/managers/servermanager" + sharedconfig "github.com/microsoft/retina/pkg/shared/config" + "github.com/microsoft/retina/pkg/telemetry" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "go.uber.org/zap" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +const ( + configFileName string = "config.yaml" + logFileName string = "retina.log" +) + +var ( + // Below two fields are set while building the binary + // they are passed in as ldflags + // see dockerfile + applicationInsightsID string + retinaVersion string +) + +func InitGlobalFlags(cmd *cobra.Command, vp *viper.Viper) { + flags := cmd.Flags() + + flags.String(option.IdentityAllocationMode, option.IdentityAllocationModeCRD, "Identity allocation mode") + + // Add all the flags Hubble supports currently. + flags.String(option.ConfigDir, "/retina/config", `Configuration directory that contains a file for each option`) + option.BindEnv(vp, option.ConfigDir) + + flags.Bool(option.EnableHubble, false, "Enable hubble server") + option.BindEnv(vp, option.EnableHubble) + + flags.String(option.HubbleSocketPath, defaults.HubbleSockPath, "Set hubble's socket path to listen for connections") + option.BindEnv(vp, option.HubbleSocketPath) + + flags.String(option.HubbleListenAddress, "", `An additional address for Hubble server to listen to, e.g. ":4244"`) + option.BindEnv(vp, option.HubbleListenAddress) + + flags.Bool(option.HubblePreferIpv6, false, "Prefer IPv6 addresses for announcing nodes when both address types are available.") + option.BindEnv(vp, option.HubblePreferIpv6) + + flags.Bool(option.HubbleTLSDisabled, false, "Allow Hubble server to run on the given listen address without TLS.") + option.BindEnv(vp, option.HubbleTLSDisabled) + + flags.String(option.HubbleTLSCertFile, "", "Path to the public key file for the Hubble server. The file must contain PEM encoded data.") + option.BindEnv(vp, option.HubbleTLSCertFile) + + flags.String(option.HubbleTLSKeyFile, "", "Path to the private key file for the Hubble server. The file must contain PEM encoded data.") + option.BindEnv(vp, option.HubbleTLSKeyFile) + + flags.StringSlice(option.HubbleTLSClientCAFiles, []string{}, "Paths to one or more public key files of client CA certificates to use for TLS with mutual authentication (mTLS). The files must contain PEM encoded data. When provided, this option effectively enables mTLS.") //nolint:lll // long line (over 80 characters). + option.BindEnv(vp, option.HubbleTLSClientCAFiles) + + flags.Int(option.HubbleEventBufferCapacity, observeroption.Default.MaxFlows.AsInt(), "Capacity of Hubble events buffer. The provided value must be one less than an integer power of two and no larger than 65535 (ie: 1, 3, ..., 2047, 4095, ..., 65535)") //nolint:lll // long line. + option.BindEnv(vp, option.HubbleEventBufferCapacity) + + flags.Int(option.HubbleEventQueueSize, 0, "Buffer size of the channel to receive monitor events.") + option.BindEnv(vp, option.HubbleEventQueueSize) + + flags.String(option.HubbleMetricsServer, "", "Address to serve Hubble metrics on.") + option.BindEnv(vp, option.HubbleMetricsServer) + + flags.StringSlice(option.HubbleMetrics, []string{}, "List of Hubble metrics to enable.") + option.BindEnv(vp, option.HubbleMetrics) + + flags.String(option.HubbleFlowlogsConfigFilePath, "", "Filepath with configuration of hubble flowlogs") + option.BindEnv(vp, option.HubbleFlowlogsConfigFilePath) + + flags.String(option.HubbleExportFilePath, exporteroption.Default.Path, "Filepath to write Hubble events to.") + option.BindEnv(vp, option.HubbleExportFilePath) + + flags.Int(option.HubbleExportFileMaxSizeMB, exporteroption.Default.MaxSizeMB, "Size in MB at which to rotate Hubble export file.") + option.BindEnv(vp, option.HubbleExportFileMaxSizeMB) + + flags.Int(option.HubbleExportFileMaxBackups, exporteroption.Default.MaxBackups, "Number of rotated Hubble export files to keep.") + option.BindEnv(vp, option.HubbleExportFileMaxBackups) + + flags.Bool(option.HubbleExportFileCompress, exporteroption.Default.Compress, "Compress rotated Hubble export files.") + option.BindEnv(vp, option.HubbleExportFileCompress) + + flags.StringSlice(option.HubbleExportAllowlist, []string{}, "Specify allowlist as JSON encoded FlowFilters to Hubble exporter.") + option.BindEnv(vp, option.HubbleExportAllowlist) + + flags.StringSlice(option.HubbleExportDenylist, []string{}, "Specify denylist as JSON encoded FlowFilters to Hubble exporter.") + option.BindEnv(vp, option.HubbleExportDenylist) + + flags.StringSlice(option.HubbleExportFieldmask, []string{}, "Specify list of fields to use for field mask in Hubble exporter.") + option.BindEnv(vp, option.HubbleExportFieldmask) + + flags.Bool(option.EnableHubbleRecorderAPI, true, "Enable the Hubble recorder API") + option.BindEnv(vp, option.EnableHubbleRecorderAPI) + + flags.String(option.HubbleRecorderStoragePath, defaults.HubbleRecorderStoragePath, "Directory in which pcap files created via the Hubble Recorder API are stored") + option.BindEnv(vp, option.HubbleRecorderStoragePath) + + flags.Int(option.HubbleRecorderSinkQueueSize, defaults.HubbleRecorderSinkQueueSize, "Queue size of each Hubble recorder sink") + option.BindEnv(vp, option.HubbleRecorderSinkQueueSize) + + flags.Bool(option.HubbleSkipUnknownCGroupIDs, true, "Skip Hubble events with unknown cgroup ids") + option.BindEnv(vp, option.HubbleSkipUnknownCGroupIDs) + + flags.StringSlice(option.HubbleMonitorEvents, []string{}, + fmt.Sprintf( + "Cilium monitor events for Hubble to observe: [%s]. By default, Hubble observes all monitor events.", + strings.Join(monitorAPI.AllMessageTypeNames(), " "), + ), + ) + option.BindEnv(vp, option.HubbleMonitorEvents) + + flags.Bool(option.HubbleRedactEnabled, defaults.HubbleRedactEnabled, "Hubble redact sensitive information from flows") + option.BindEnv(vp, option.HubbleRedactEnabled) + + flags.Bool(option.HubbleRedactHttpURLQuery, defaults.HubbleRedactHttpURLQuery, "Hubble redact http URL query from flows") + option.BindEnv(vp, option.HubbleRedactHttpURLQuery) + + flags.Bool(option.HubbleRedactHttpUserInfo, defaults.HubbleRedactHttpUserInfo, "Hubble redact http user info from flows") + option.BindEnv(vp, option.HubbleRedactHttpUserInfo) + + flags.Bool(option.HubbleRedactKafkaApiKey, defaults.HubbleRedactKafkaApiKey, "Hubble redact Kafka API key from flows") + option.BindEnv(vp, option.HubbleRedactKafkaApiKey) + + flags.StringSlice(option.HubbleRedactHttpHeadersAllow, []string{}, "HTTP headers to keep visible in flows") + option.BindEnv(vp, option.HubbleRedactHttpHeadersAllow) + + flags.StringSlice(option.HubbleRedactHttpHeadersDeny, []string{}, "HTTP headers to redact from flows") + option.BindEnv(vp, option.HubbleRedactHttpHeadersDeny) + + if err := vp.BindPFlags(flags); err != nil { + logger.Fatalf("BindPFlags failed: %s", err) + } +} + +type daemonParams struct { + cell.In + + Lifecycle cell.Lifecycle + Clientset k8sClient.Clientset + MonitorAgent monitorAgent.Agent + PluginManager *pluginmanager.PluginManager + HTTPServer *servermanager.HTTPServer + Log logrus.FieldLogger + Client client.Client + EventChan chan *v1.Event + K8sWatcher *watchers.K8sWatcher + Lnds *node.LocalNodeStore + IPC *ipcache.IPCache + SvcCache *k8s.ServiceCache + Telemetry telemetry.Telemetry + Config config.Config +} + +func newDaemonPromise(params daemonParams) promise.Promise[*Daemon] { + daemonResolver, daemonPromise := promise.New[*Daemon]() + + // daemonCtx is the daemon-wide context cancelled when stopping. + daemonCtx, cancelDaemonCtx := context.WithCancel(context.Background()) + + var daemon *Daemon + params.Lifecycle.Append(cell.Hook{ + OnStart: func(cell.HookContext) error { + d := newDaemon(¶ms) + daemon = d + daemonResolver.Resolve(daemon) + + d.log.Info("starting Retina Enterprise version: ", retinaVersion) + err := d.Run(daemonCtx) + if err != nil { + return fmt.Errorf("daemon run failed: %w", err) + } + + return nil + }, + OnStop: func(cell.HookContext) error { + cancelDaemonCtx() + return nil + }, + }) + return daemonPromise +} + +func initLogging() { + logger := setupDefaultLogger() + retinaConfig, _ := getRetinaConfig(logger) + k8sCfg, _ := sharedconfig.GetK8sConfig() + zapLogger := setupZapLogger(retinaConfig, k8sCfg) + setupLoggingHooks(logger, zapLogger) + bootstrapLogging(logger) +} + +func setupDefaultLogger() *logrus.Logger { + logger := logging.DefaultLogger + logger.ReportCaller = true + logger.SetOutput(io.Discard) + return logger +} + +func getRetinaConfig(logger *logrus.Logger) (*config.Config, error) { + retinaConfigFile := filepath.Join(option.Config.ConfigDir, configFileName) + conf, err := config.GetConfig(retinaConfigFile) + if err != nil { + logger.WithError(err).Error("Failed to get config file") + return nil, fmt.Errorf("getting config from file %q: %w", configFileName, err) + } + return conf, nil +} + +func setupZapLogger(retinaConfig *config.Config, k8sCfg *rest.Config) *log.ZapLogger { + logOpts := &log.LogOpts{ + Level: retinaConfig.LogLevel, + File: false, + FileName: logFileName, + MaxFileSizeMB: 100, //nolint:gomnd // this is obvious from usage + MaxBackups: 3, //nolint:gomnd // this is obvious from usage + MaxAgeDays: 30, //nolint:gomnd // this is obvious from usage + ApplicationInsightsID: applicationInsightsID, + EnableTelemetry: retinaConfig.EnableTelemetry, + } + + persistentFields := []zap.Field{ + zap.String("version", retinaVersion), + zap.String("apiserver", k8sCfg.Host), + zap.Strings("plugins", retinaConfig.EnabledPlugin), + } + + _, err := log.SetupZapLogger(logOpts, persistentFields...) + if err != nil { + logger.Fatalf("Failed to setup zap logger: %v", err) + } + + namedLogger := log.Logger().Named("retina-with-hubble") + namedLogger.Info("Traces telemetry initialized with zapai", zap.String("version", retinaVersion), zap.String("appInsightsID", applicationInsightsID)) + + return namedLogger +} + +func setupLoggingHooks(logger *logrus.Logger, zapLogger *log.ZapLogger) { + logger.Hooks.Add(metrics.NewLoggingHook()) + + zapHook, err := zaphook.NewZapHook(zapLogger.Logger) + if err != nil { + logger.WithError(err).Error("Failed to create zap hook") + } else { + logger.Hooks.Add(zapHook) + } +} + +func bootstrapLogging(logger *logrus.Logger) { + if err := logging.SetupLogging(option.Config.LogDriver, logging.LogOptions(option.Config.LogOpt), "retina-agent", option.Config.Debug); err != nil { + logger.Fatal(err) + } +} + +func initDaemonConfig(vp *viper.Viper) { + option.Config.Populate(vp) + if option.Config.HubbleEventBufferCapacity == 0 { + option.Config.HubbleEventBufferCapacity = int(math.Pow(2, 14) - 1) //nolint:gomnd // this is just math + } + + time.MaxInternalTimerDelay = vp.GetDuration(option.MaxInternalTimerDelay) +} + +func Execute(cobraCmd *cobra.Command, h *hive.Hive) { + fn := option.InitConfig(cobraCmd, "retina-agent", "retina", h.Viper()) + fn() + initDaemonConfig(h.Viper()) + initLogging() + + //nolint:gocritic // without granular commits this commented-out code may be lost + // initEnv(h.Viper()) + + if err := h.Run(); err != nil { + logger.Fatal(err) + } +} diff --git a/cmd/hubble_linux.go b/cmd/hubble_linux.go new file mode 100644 index 000000000..322281444 --- /dev/null +++ b/cmd/hubble_linux.go @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +package cmd + +import ( + "fmt" + + "github.com/cilium/cilium/pkg/hive" + "github.com/microsoft/retina/cmd/hubble" + "github.com/spf13/cobra" + "go.etcd.io/etcd/version" +) + +var ( + h = hive.New(hubble.Agent) + + hubbleCmd = &cobra.Command{ + Use: "hubble-control-plane", + Short: "Start Hubble control plane", + Run: func(cobraCmd *cobra.Command, _ []string) { + if v, _ := cobraCmd.Flags().GetBool("version"); v { + fmt.Printf("%s %s\n", cobraCmd.Name(), version.Version) + } + hubble.Execute(cobraCmd, h) + }, + } +) + +func init() { + h.RegisterFlags(hubbleCmd.Flags()) + hubbleCmd.AddCommand(h.Command()) + + hubble.InitGlobalFlags(hubbleCmd, h.Viper()) + + rootCmd.AddCommand(hubbleCmd) +} diff --git a/cmd/legacy/daemon.go b/cmd/legacy/daemon.go new file mode 100644 index 000000000..06a5cb9d3 --- /dev/null +++ b/cmd/legacy/daemon.go @@ -0,0 +1,302 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +package legacy + +import ( + "fmt" + "os" + "strings" + "time" + + "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/fields" + k8sruntime "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/client-go/kubernetes" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + crcache "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" + kcfg "sigs.k8s.io/controller-runtime/pkg/client/config" + "sigs.k8s.io/controller-runtime/pkg/healthz" + crmgr "sigs.k8s.io/controller-runtime/pkg/manager" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + + "github.com/go-logr/zapr" + retinav1alpha1 "github.com/microsoft/retina/crd/api/v1alpha1" + "github.com/microsoft/retina/pkg/config" + controllercache "github.com/microsoft/retina/pkg/controllers/cache" + mcc "github.com/microsoft/retina/pkg/controllers/daemon/metricsconfiguration" + namespacecontroller "github.com/microsoft/retina/pkg/controllers/daemon/namespace" + nc "github.com/microsoft/retina/pkg/controllers/daemon/node" + pc "github.com/microsoft/retina/pkg/controllers/daemon/pod" + kec "github.com/microsoft/retina/pkg/controllers/daemon/retinaendpoint" + sc "github.com/microsoft/retina/pkg/controllers/daemon/service" + + "github.com/microsoft/retina/pkg/enricher" + "github.com/microsoft/retina/pkg/log" + cm "github.com/microsoft/retina/pkg/managers/controllermanager" + "github.com/microsoft/retina/pkg/managers/filtermanager" + "github.com/microsoft/retina/pkg/metrics" + mm "github.com/microsoft/retina/pkg/module/metrics" + "github.com/microsoft/retina/pkg/pubsub" + "github.com/microsoft/retina/pkg/telemetry" +) + +const ( + logFileName = "retina.log" + heartbeatInterval = 5 * time.Minute + + nodeNameEnvKey = "NODE_NAME" + nodeIPEnvKey = "NODE_IP" +) + +var ( + scheme = k8sruntime.NewScheme() + + // applicationInsightsID is the instrumentation key for Azure Application Insights + // It is set during the build process using the -ldflags flag + // If it is set, the application will send telemetry to the corresponding Application Insights resource. + applicationInsightsID string + version string +) + +func init() { + //+kubebuilder:scaffold:scheme + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(retinav1alpha1.AddToScheme(scheme)) +} + +type Daemon struct { + metricsAddr string + probeAddr string + enableLeaderElection bool + configFile string +} + +func NewDaemon(metricsAddr, probeAddr, configFile string, enableLeaderElection bool) *Daemon { + return &Daemon{ + metricsAddr: metricsAddr, + probeAddr: probeAddr, + enableLeaderElection: enableLeaderElection, + configFile: configFile, + } +} + +func (d *Daemon) Start() error { + fmt.Printf("starting Retina daemon with legacy control plane %v\n", version) + + if applicationInsightsID != "" { + telemetry.InitAppInsights(applicationInsightsID, version) + defer telemetry.ShutdownAppInsights() + defer telemetry.TrackPanic() + } + + daemonConfig, err := config.GetConfig(d.configFile) + if err != nil { + panic(err) + } + + fmt.Println("init client-go") + cfg, err := kcfg.GetConfig() + if err != nil { + panic(err) + } + + fmt.Println("init logger") + zl, err := log.SetupZapLogger(&log.LogOpts{ + Level: daemonConfig.LogLevel, + File: false, + FileName: logFileName, + MaxFileSizeMB: 100, //nolint:gomnd // defaults + MaxBackups: 3, //nolint:gomnd // defaults + MaxAgeDays: 30, //nolint:gomnd // defaults + ApplicationInsightsID: applicationInsightsID, + EnableTelemetry: daemonConfig.EnableTelemetry, + }, + zap.String("version", version), + zap.String("apiserver", cfg.Host), + zap.String("plugins", strings.Join(daemonConfig.EnabledPlugin, `,`)), + ) + if err != nil { + panic(err) + } + defer zl.Close() + mainLogger := zl.Named("main").Sugar() + + metrics.InitializeMetrics() + + var tel telemetry.Telemetry + if daemonConfig.EnableTelemetry && applicationInsightsID != "" { + mainLogger.Info("telemetry enabled", zap.String("applicationInsightsID", applicationInsightsID)) + tel = telemetry.NewAppInsightsTelemetryClient("retina-agent", map[string]string{ + "version": version, + "apiserver": cfg.Host, + "plugins": strings.Join(daemonConfig.EnabledPlugin, `,`), + }) + } else { + mainLogger.Info("telemetry disabled") + tel = telemetry.NewNoopTelemetry() + } + + // Create a manager for controller-runtime + + mgrOption := crmgr.Options{ + Scheme: scheme, + Metrics: metricsserver.Options{ + BindAddress: d.metricsAddr, + }, + HealthProbeBindAddress: d.probeAddr, + LeaderElection: d.enableLeaderElection, + LeaderElectionID: "ecaf1259.retina.sh", + } + + // Local context has its meaning only when pod level(advanced) metrics is enabled. + if daemonConfig.EnablePodLevel && !daemonConfig.RemoteContext { + mainLogger.Info("Remote context is disabled, only pods deployed on the same node as retina-agent will be monitored") + // the new cache sets Selector options on the Manager cache which are used + // to perform *server-side* filtering of the cached objects. This is very important + // for high node/pod count clusters, as it keeps us from watching objects at the + // whole cluster scope when we are only interested in the Node's scope. + nodeName := os.Getenv(nodeNameEnvKey) + if nodeName == "" { + mainLogger.Fatal("failed to get node name from environment variable", zap.String("node name env key", nodeNameEnvKey)) + } + podNodeNameSelector := fields.SelectorFromSet(fields.Set{"spec.nodeName": nodeName}) + // Ignore hostnetwork pods which share the same IP with the node and pods on the same node. + // Unlike spec.nodeName, field label "spec.hostNetwork" is not supported, and as a workaround, + // We use status.podIP to filter out hostnetwork pods. + // https://github.com/kubernetes/kubernetes/blob/41da26dbe15207cbe5b6c36b48a31d2cd3344123/pkg/apis/core/v1/conversion.go#L36 + nodeIP := os.Getenv(nodeIPEnvKey) + if nodeIP == "" { + mainLogger.Fatal("failed to get node IP from environment variable", zap.String("node IP env key", nodeIPEnvKey)) + } + podNodeIPNotMatchSelector := fields.OneTermNotEqualSelector("status.podIP", nodeIP) + podSelector := fields.AndSelectors(podNodeNameSelector, podNodeIPNotMatchSelector) + + mainLogger.Info("pod selector when remote context is disabled", zap.String("pod selector", podSelector.String())) + mgrOption.Cache = crcache.Options{ + ByObject: map[client.Object]crcache.ByObject{ + &corev1.Pod{}: { + Field: podSelector, + }, + }, + } + } + + mgr, err := crmgr.New(cfg, mgrOption) + if err != nil { + mainLogger.Error("Unable to start manager", zap.Error(err)) + return fmt.Errorf("creating controller-runtime manager: %w", err) + } + + //+kubebuilder:scaffold:builder + + if healthCheckErr := mgr.AddHealthzCheck("healthz", healthz.Ping); healthCheckErr != nil { + mainLogger.Fatal("Unable to set up health check", zap.Error(healthCheckErr)) + } + if addReadyCheckErr := mgr.AddReadyzCheck("readyz", healthz.Ping); addReadyCheckErr != nil { + mainLogger.Fatal("Unable to set up ready check", zap.Error(addReadyCheckErr)) + } + + // k8s Client used for informers + cl := kubernetes.NewForConfigOrDie(mgr.GetConfig()) + + serverVersion, err := cl.Discovery().ServerVersion() + if err != nil { + mainLogger.Error("failed to get Kubernetes server version: ", zap.Error(err)) + } else { + mainLogger.Infof("Kubernetes server version: %v", serverVersion) + } + + // Setup RetinaEndpoint controller. + // TODO(mainred): This is to temporarily create a cache and pubsub for RetinaEndpoint, need to refactor this. + ctx := ctrl.SetupSignalHandler() + ctrl.SetLogger(zapr.NewLogger(zl.Logger.Named("controller-runtime"))) + + if daemonConfig.EnablePodLevel { + pubSub := pubsub.New() + controllerCache := controllercache.New(pubSub) + enrich := enricher.New(ctx, controllerCache) + //nolint:govet // shadowing this err is fine + fm, err := filtermanager.Init(5) //nolint:gomnd // defaults + if err != nil { + mainLogger.Fatal("unable to create filter manager", zap.Error(err)) + } + defer fm.Stop() //nolint:errcheck // best effort + enrich.Run() + metricsModule := mm.InitModule(ctx, daemonConfig, pubSub, enrich, fm, controllerCache) + + if !daemonConfig.RemoteContext { + mainLogger.Info("Initializing Pod controller") + + podController := pc.New(mgr.GetClient(), controllerCache) + if err := podController.SetupWithManager(mgr); err != nil { + mainLogger.Fatal("unable to create PodController", zap.Error(err)) + } + } else if daemonConfig.EnableRetinaEndpoint { + mainLogger.Info("RetinaEndpoint is enabled") + mainLogger.Info("Initializing RetinaEndpoint controller") + + retinaEndpointController := kec.New(mgr.GetClient(), controllerCache) + if err := retinaEndpointController.SetupWithManager(mgr); err != nil { + mainLogger.Fatal("unable to create retinaEndpointController", zap.Error(err)) + } + } + + mainLogger.Info("Initializing Node controller") + nodeController := nc.New(mgr.GetClient(), controllerCache) + if err := nodeController.SetupWithManager(mgr); err != nil { + mainLogger.Fatal("unable to create nodeController", zap.Error(err)) + } + + mainLogger.Info("Initializing Service controller") + svcController := sc.New(mgr.GetClient(), controllerCache) + if err := svcController.SetupWithManager(mgr); err != nil { + mainLogger.Fatal("unable to create svcController", zap.Error(err)) + } + + if daemonConfig.EnableAnnotations { + mainLogger.Info("Initializing MetricsConfig namespaceController") + namespaceController := namespacecontroller.New(mgr.GetClient(), controllerCache, metricsModule) + if err := namespaceController.SetupWithManager(mgr); err != nil { + mainLogger.Fatal("unable to create namespaceController", zap.Error(err)) + } + go namespaceController.Start(ctx) + } else { + mainLogger.Info("Initializing MetricsConfig controller") + metricsConfigController := mcc.New(mgr.GetClient(), mgr.GetScheme(), metricsModule) + if err := metricsConfigController.SetupWithManager(mgr); err != nil { + mainLogger.Fatal("unable to create metricsConfigController", zap.Error(err)) + } + } + } + + controllerMgr, err := cm.NewControllerManager(daemonConfig, cl, tel) + if err != nil { + mainLogger.Fatal("Failed to create controller manager", zap.Error(err)) + } + if err := controllerMgr.Init(ctx); err != nil { + mainLogger.Fatal("Failed to initialize controller manager", zap.Error(err)) + } + // Stop is best effort. If it fails, we still want to stop the main process. + // This is needed for graceful shutdown of Retina plugins. + // Do it in the main thread as graceful shutdown is important. + defer controllerMgr.Stop(ctx) + + // start heartbeat goroutine for application insights + go tel.Heartbeat(ctx, heartbeatInterval) + + // Start controller manager, which will start http server and plugin manager. + go controllerMgr.Start(ctx) + mainLogger.Info("Started controller manager") + + // Start all registered controllers. This will block until container receives SIGTERM. + if err := mgr.Start(ctx); err != nil { + mainLogger.Fatal("unable to start manager", zap.Error(err)) + } + + mainLogger.Info("Network observability exiting. Till next time!") + return nil +} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 000000000..b1cec2ae0 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +package cmd + +import ( + "fmt" + "os" + + "github.com/microsoft/retina/cmd/legacy" + "github.com/spf13/cobra" +) + +const ( + configFileName = "/retina/config/config.yaml" +) + +var ( + metricsAddr string + probeAddr string + enableLeaderElection bool + cfgFile string + + rootCmd = &cobra.Command{ + Use: "retina-agent", + Short: "Retina Agent", + Long: "Start Retina Agent", + RunE: func(cmd *cobra.Command, args []string) error { + // Do Stuff Here + fmt.Println("Starting Retina Agent") + d := legacy.NewDaemon(metricsAddr, probeAddr, cfgFile, enableLeaderElection) + if err := d.Start(); err != nil { + return fmt.Errorf("starting daemon: %w", err) + } + return nil + }, + } +) + +func init() { + rootCmd.Flags().StringVar(&metricsAddr, "metrics-bind-address", ":18080", "The address the metric endpoint binds to.") + rootCmd.Flags().StringVar(&probeAddr, "health-probe-bind-address", ":18081", "The address the probe endpoint binds to.") + rootCmd.Flags().BoolVar(&enableLeaderElection, "leader-elect", false, "Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.") + rootCmd.Flags().StringVar(&cfgFile, "config", configFileName, "config file") +} + +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} diff --git a/controller/Dockerfile b/controller/Dockerfile index 0b959492b..3035d1ef3 100644 --- a/controller/Dockerfile +++ b/controller/Dockerfile @@ -80,13 +80,27 @@ RUN tdnf install -y \ iproute \ iptables \ tcpdump \ - which + which \ + wget \ + gnupg2 \ + ca-certificates \ + tar RUN mkdir -p /tmp/bin RUN arr="clang tcpdump ip ss iptables-legacy iptables-legacy-save iptables-nft iptables-nft-save cp uname" ;\ for i in $arr; do \ cp $(which $i) /tmp/bin; \ done - +# Download Hubble +ARG GOARCH=amd64 +ENV HUBBLE_ARCH=${GOARCH} +ARG HUBBLE_VERSION=v0.13.0 +ENV HUBBLE_VERSION=${HUBBLE_VERSION} +RUN echo "Hubble version: $HUBBLE_VERSION" && \ + wget --no-check-certificate https://github.com/cilium/hubble/releases/download/$HUBBLE_VERSION/hubble-linux-${HUBBLE_ARCH}.tar.gz && \ + wget --no-check-certificate https://github.com/cilium/hubble/releases/download/$HUBBLE_VERSION/hubble-linux-${HUBBLE_ARCH}.tar.gz.sha256sum && \ + sha256sum --check hubble-linux-${HUBBLE_ARCH}.tar.gz.sha256sum && \ + tar xzvfC hubble-linux-${HUBBLE_ARCH}.tar.gz /usr/local && \ + rm hubble-linux-${HUBBLE_ARCH}.tar.gz && rm hubble-linux-${HUBBLE_ARCH}.tar.gz.sha256sum # init final image FROM mariner-distroless as init @@ -106,6 +120,10 @@ COPY --from=tools /tmp/bin/ /bin COPY --from=controller-bin /go/bin/retina/controller /retina/controller COPY --from=controller-bin /go/src/github.com/microsoft/retina/pkg/plugin /go/src/github.com/microsoft/retina/pkg/plugin COPY --from=capture-bin /go/bin/retina/captureworkload /retina/captureworkload +# Copy Hubble. +COPY --from=tools /usr/local/hubble /bin/hubble +# Set Hubble server. +ENV HUBBLE_SERVER=unix:///var/run/cilium/hubble.sock ENTRYPOINT ["./retina/controller"] diff --git a/controller/main.go b/controller/main.go index 261edf2d1..b9cd9386b 100644 --- a/controller/main.go +++ b/controller/main.go @@ -3,305 +3,9 @@ package main import ( - "flag" - "fmt" - "os" - "strings" - "time" - - "go.uber.org/zap" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/fields" - k8sruntime "k8s.io/apimachinery/pkg/runtime" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/client-go/kubernetes" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - ctrl "sigs.k8s.io/controller-runtime" - crcache "sigs.k8s.io/controller-runtime/pkg/cache" - "sigs.k8s.io/controller-runtime/pkg/client" - kcfg "sigs.k8s.io/controller-runtime/pkg/client/config" - "sigs.k8s.io/controller-runtime/pkg/healthz" - crmgr "sigs.k8s.io/controller-runtime/pkg/manager" - metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" - - "github.com/go-logr/zapr" - retinav1alpha1 "github.com/microsoft/retina/crd/api/v1alpha1" - "github.com/microsoft/retina/pkg/config" - controllercache "github.com/microsoft/retina/pkg/controllers/cache" - mcc "github.com/microsoft/retina/pkg/controllers/daemon/metricsconfiguration" - namespacecontroller "github.com/microsoft/retina/pkg/controllers/daemon/namespace" - nc "github.com/microsoft/retina/pkg/controllers/daemon/node" - pc "github.com/microsoft/retina/pkg/controllers/daemon/pod" - kec "github.com/microsoft/retina/pkg/controllers/daemon/retinaendpoint" - sc "github.com/microsoft/retina/pkg/controllers/daemon/service" - - "github.com/microsoft/retina/pkg/enricher" - "github.com/microsoft/retina/pkg/log" - cm "github.com/microsoft/retina/pkg/managers/controllermanager" - "github.com/microsoft/retina/pkg/managers/filtermanager" - "github.com/microsoft/retina/pkg/metrics" - mm "github.com/microsoft/retina/pkg/module/metrics" - "github.com/microsoft/retina/pkg/pubsub" - "github.com/microsoft/retina/pkg/telemetry" -) - -const ( - configFileName = "/retina/config/config.yaml" - logFileName = "retina.log" - heartbeatInterval = 5 * time.Minute - - nodeNameEnvKey = "NODE_NAME" - nodeIPEnvKey = "NODE_IP" + "github.com/microsoft/retina/cmd" ) -var ( - scheme = k8sruntime.NewScheme() - - // applicationInsightsID is the instrumentation key for Azure Application Insights - // It is set during the build process using the -ldflags flag - // If it is set, the application will send telemetry to the corresponding Application Insights resource. - applicationInsightsID string - version string - - cfgFile string -) - -func init() { - //+kubebuilder:scaffold:scheme - utilruntime.Must(clientgoscheme.AddToScheme(scheme)) - utilruntime.Must(retinav1alpha1.AddToScheme(scheme)) -} - func main() { - fmt.Printf("starting Retina %v", version) - var metricsAddr string - var enableLeaderElection bool - var probeAddr string - flag.StringVar(&metricsAddr, "metrics-bind-address", ":18080", "The address the metric endpoint binds to.") - flag.StringVar(&probeAddr, "health-probe-bind-address", ":18081", "The address the probe endpoint binds to.") - flag.BoolVar(&enableLeaderElection, "leader-elect", false, - "Enable leader election for controller manager. "+ - "Enabling this will ensure there is only one active controller manager.") - - if applicationInsightsID != "" { - telemetry.InitAppInsights(applicationInsightsID, version) - defer telemetry.ShutdownAppInsights() - defer telemetry.TrackPanic() - } - - flag.StringVar(&cfgFile, "config", configFileName, "config file") - flag.Parse() - - fmt.Printf("loading config %s\n", cfgFile) - config, err := config.GetConfig(cfgFile) - if err != nil { - panic(err) - } - - fmt.Println("init client-go") - cfg, err := kcfg.GetConfig() - if err != nil { - panic(err) - } - - fmt.Println("init logger") - zl, err := log.SetupZapLogger(&log.LogOpts{ - Level: config.LogLevel, - File: false, - FileName: logFileName, - MaxFileSizeMB: 100, //nolint:gomnd // defaults - MaxBackups: 3, //nolint:gomnd // defaults - MaxAgeDays: 30, //nolint:gomnd // defaults - ApplicationInsightsID: applicationInsightsID, - EnableTelemetry: config.EnableTelemetry, - }, - zap.String("version", version), - zap.String("apiserver", cfg.Host), - zap.String("plugins", strings.Join(config.EnabledPlugin, `,`)), - ) - if err != nil { - panic(err) - } - defer zl.Close() - mainLogger := zl.Named("main").Sugar() - - metrics.InitializeMetrics() - - var tel telemetry.Telemetry - if config.EnableTelemetry && applicationInsightsID != "" { - mainLogger.Info("telemetry enabled", zap.String("applicationInsightsID", applicationInsightsID)) - tel = telemetry.NewAppInsightsTelemetryClient("retina-agent", map[string]string{ - "version": version, - "apiserver": cfg.Host, - "plugins": strings.Join(config.EnabledPlugin, `,`), - }) - } else { - mainLogger.Info("telemetry disabled") - tel = telemetry.NewNoopTelemetry() - } - - // Create a manager for controller-runtime - - mgrOption := crmgr.Options{ - Scheme: scheme, - Metrics: metricsserver.Options{ - BindAddress: metricsAddr, - }, - HealthProbeBindAddress: probeAddr, - LeaderElection: enableLeaderElection, - LeaderElectionID: "ecaf1259.retina.sh", - } - - // Local context has its meaning only when pod level(advanced) metrics is enabled. - if config.EnablePodLevel && !config.RemoteContext { - mainLogger.Info("Remote context is disabled, only pods deployed on the same node as retina-agent will be monitored") - // the new cache sets Selector options on the Manager cache which are used - // to perform *server-side* filtering of the cached objects. This is very important - // for high node/pod count clusters, as it keeps us from watching objects at the - // whole cluster scope when we are only interested in the Node's scope. - nodeName := os.Getenv(nodeNameEnvKey) - if len(nodeName) == 0 { - mainLogger.Error("failed to get node name from environment variable", zap.String("node name env key", nodeNameEnvKey)) - os.Exit(1) - } - podNodeNameSelector := fields.SelectorFromSet(fields.Set{"spec.nodeName": nodeName}) - // Ignore hostnetwork pods which share the same IP with the node and pods on the same node. - // Unlike spec.nodeName, field label "spec.hostNetwork" is not supported, and as a workaround, - // We use status.podIP to filter out hostnetwork pods. - // https://github.com/kubernetes/kubernetes/blob/41da26dbe15207cbe5b6c36b48a31d2cd3344123/pkg/apis/core/v1/conversion.go#L36 - nodeIP := os.Getenv(nodeIPEnvKey) - if len(nodeIP) == 0 { - mainLogger.Error("failed to get node IP from environment variable", zap.String("node IP env key", nodeIPEnvKey)) - os.Exit(1) - } - podNodeIPNotMatchSelector := fields.OneTermNotEqualSelector("status.podIP", nodeIP) - podSelector := fields.AndSelectors(podNodeNameSelector, podNodeIPNotMatchSelector) - - mainLogger.Info("pod selector when remote context is disabled", zap.String("pod selector", podSelector.String())) - mgrOption.Cache = crcache.Options{ - ByObject: map[client.Object]crcache.ByObject{ - &corev1.Pod{}: { - Field: podSelector, - }, - }, - } - } - - mgr, err := crmgr.New(cfg, mgrOption) - if err != nil { - mainLogger.Error("Unable to start manager", zap.Error(err)) - os.Exit(1) - } - - //+kubebuilder:scaffold:builder - - if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { - mainLogger.Error("Unable to set up health check", zap.Error(err)) - os.Exit(1) - } - if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { - mainLogger.Error("Unable to set up ready check", zap.Error(err)) - os.Exit(1) - } - - // k8s Client used for informers - cl := kubernetes.NewForConfigOrDie(mgr.GetConfig()) - - serverVersion, err := cl.Discovery().ServerVersion() - if err != nil { - mainLogger.Error("failed to get Kubernetes server version: ", zap.Error(err)) - } else { - mainLogger.Infof("Kubernetes server version: %v", serverVersion) - } - - // Setup RetinaEndpoint controller. - // TODO(mainred): This is to temporarily create a cache and pubsub for RetinaEndpoint, need to refactor this. - ctx := ctrl.SetupSignalHandler() - ctrl.SetLogger(zapr.NewLogger(zl.Logger.Named("controller-runtime"))) - - if config.EnablePodLevel { - pubSub := pubsub.New() - controllerCache := controllercache.New(pubSub) - enrich := enricher.New(ctx, controllerCache) - fm, err := filtermanager.Init(5) - if err != nil { - mainLogger.Error("unable to create filter manager", zap.Error(err)) - os.Exit(1) - } - defer fm.Stop() - enrich.Run() - metricsModule := mm.InitModule(ctx, config, pubSub, enrich, fm, controllerCache) - - if !config.RemoteContext { - mainLogger.Info("Initializing Pod controller") - - podController := pc.New(mgr.GetClient(), controllerCache) - if err := podController.SetupWithManager(mgr); err != nil { - mainLogger.Fatal("unable to create PodController", zap.Error(err)) - } - } else { - if config.EnableRetinaEndpoint { - mainLogger.Info("RetinaEndpoint is enabled") - mainLogger.Info("Initializing RetinaEndpoint controller") - - retinaEndpointController := kec.New(mgr.GetClient(), controllerCache) - if err := retinaEndpointController.SetupWithManager(mgr); err != nil { - mainLogger.Fatal("unable to create retinaEndpointController", zap.Error(err)) - } - } - } - - mainLogger.Info("Initializing Node controller") - nodeController := nc.New(mgr.GetClient(), controllerCache) - if err := nodeController.SetupWithManager(mgr); err != nil { - mainLogger.Fatal("unable to create nodeController", zap.Error(err)) - } - - mainLogger.Info("Initializing Service controller") - svcController := sc.New(mgr.GetClient(), controllerCache) - if err := svcController.SetupWithManager(mgr); err != nil { - mainLogger.Fatal("unable to create svcController", zap.Error(err)) - } - - if config.EnableAnnotations { - mainLogger.Info("Initializing MetricsConfig namespaceController") - namespaceController := namespacecontroller.New(mgr.GetClient(), controllerCache, metricsModule) - if err := namespaceController.SetupWithManager(mgr); err != nil { - mainLogger.Fatal("unable to create namespaceController", zap.Error(err)) - } - go namespaceController.Start(ctx) - } else { - mainLogger.Info("Initializing MetricsConfig controller") - metricsConfigController := mcc.New(mgr.GetClient(), mgr.GetScheme(), metricsModule) - if err := metricsConfigController.SetupWithManager(mgr); err != nil { - mainLogger.Fatal("unable to create metricsConfigController", zap.Error(err)) - } - } - } - - controllerMgr, err := cm.NewControllerManager(config, cl, tel) - if err != nil { - mainLogger.Fatal("Failed to create controller manager", zap.Error(err)) - } - if err := controllerMgr.Init(ctx); err != nil { - mainLogger.Fatal("Failed to initialize controller manager", zap.Error(err)) - } - // Stop is best effort. If it fails, we still want to stop the main process. - // This is needed for graceful shutdown of Retina plugins. - // Do it in the main thread as graceful shutdown is important. - defer controllerMgr.Stop(ctx) - - // start heartbeat goroutine for application insights - go tel.Heartbeat(ctx, heartbeatInterval) - - // Start controller manager, which will start http server and plugin manager. - go controllerMgr.Start(ctx) - mainLogger.Info("Started controller manager") - - // Start all registered controllers. This will block until container receives SIGTERM. - if err := mgr.Start(ctx); err != nil { - mainLogger.Fatal("unable to start manager", zap.Error(err)) - } - - mainLogger.Info("Network observability exiting. Till next time!") + cmd.Execute() } diff --git a/crd/Makefile b/crd/Makefile index 9a1e3caab..9a2b61610 100644 --- a/crd/Makefile +++ b/crd/Makefile @@ -4,7 +4,7 @@ REPO_ROOT = $(shell git rev-parse --show-toplevel) TOOLS_DIR = $(REPO_ROOT)/hack/tools TOOLS_BIN_DIR = $(TOOLS_DIR)/bin CONTROLLER_GEN = $(TOOLS_BIN_DIR)/controller-gen -HELM_CRD_DIR = $(REPO_ROOT)/deploy/manifests/controller/helm/retina/crds +HELM_CRD_DIR = $(REPO_ROOT)/deploy/legacy/manifests/controller/helm/retina/crds .PHONY: generate manifests diff --git a/deploy/grafana/dashboards/README.md b/deploy/grafana/dashboards/README.md deleted file mode 100644 index 1dfbae4b4..000000000 --- a/deploy/grafana/dashboards/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# README - -Dashboards here are a copy of dashboards published in Retina organization on grafana.com diff --git a/deploy/hubble/grafana/dashboards/clusters.json b/deploy/hubble/grafana/dashboards/clusters.json new file mode 100644 index 000000000..b620b8a3b --- /dev/null +++ b/deploy/hubble/grafana/dashboards/clusters.json @@ -0,0 +1,3734 @@ +{ + "__inputs": [], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.15" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "editable": true, + "id": null, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "k8s:network-observability" + ], + "targetBlank": false, + "title": "Dashboards: Network Observability", + "tooltip": "", + "type": "dashboards", + "url": "" + }, + { + "asDropdown": false, + "icon": "info", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Documentation", + "tooltip": "", + "type": "link", + "url": "https://aka.ms/NetObsAddonDoc" + } + ], + "liveNow": true, + "panels": [ + { + "gridPos": { + "h": 4, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 35, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Network Observability Metrics\n\nUse this dashboard to visualise metrics from the Network Observability add-on for AKS. Dashboard displays metrics from Linux and Windows Clusters. To hide the irrelevant metrics, simply collapse the unwanted sections. Alternatively, you can edit the dashboard to delete unwanted panels. For any questions or issues, please see [our documentation](https://aka.ms/NetObsAddonDoc).", + "mode": "markdown" + }, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 4 + }, + "id": 155, + "panels": [], + "title": "Fleet View", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 5 + }, + "id": 156, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": false, + "fields": "", + "reducer": [ + "max" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Bytes Forwarded" + } + ] + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (cluster) (\r\n rate(networkobservability_forward_bytes[$__rate_interval])\r\n or\r\n rate(kappie_forward_bytes[$__rate_interval])\r\n or\r\n rate(cilium_forward_bytes_total[$__rate_interval])\r\n)", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Current Traffic by Cluster", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true + }, + "indexByName": {}, + "renameByName": { + "Value": "Bytes Forwarded", + "cluster": "Cluster" + } + } + } + ], + "transparent": true, + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "semi-dark-blue", + "mode": "continuous-BlYlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 18, + "x": 6, + "y": 5 + }, + "id": 123, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by(cluster) (\r\n rate(networkobservability_forward_count{instance=~\"$Nodes\"}[$__rate_interval])\r\n or\r\n on(cluster)\r\n rate(kappie_forward_count{instance=~\"$Nodes\"}[$__rate_interval])\r\n or\r\n on(cluster)\r\n rate(cilium_forward_count_total{instance=~\"$Nodes\"}[$__rate_interval])\r\n)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Bytes Forwarded by Cluster", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 12 + }, + "id": 158, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": false, + "fields": "", + "reducer": [ + "max" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Bytes Dropped" + } + ] + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (cluster) (\r\n rate(networkobservability_drop_bytes[$__rate_interval])\r\n or\r\n rate(kappie_drop_bytes[$__rate_interval])\r\n or\r\n rate(cilium_drop_bytes_total[$__rate_interval])\r\n)", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Current Dropped Traffic by Cluster", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true + }, + "indexByName": {}, + "renameByName": { + "Value": "Bytes Dropped", + "cluster": "Cluster" + } + } + } + ], + "transparent": true, + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 9, + "x": 6, + "y": 12 + }, + "id": 129, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by(cluster) (rate(networkobservability_drop_bytes[$__rate_interval]))\r\nor\r\nsum by(cluster) (rate(kappie_drop_bytes[$__rate_interval]))\r\nor\r\nsum by(cluster) (rate(cilium_drop_bytes_total[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Bytes Dropped by Cluster", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 9, + "x": 15, + "y": 12 + }, + "id": 130, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by(cluster) (rate(networkobservability_drop_count[$__rate_interval]))\r\nor\r\nsum by(cluster) (rate(kappie_drop_count[$__rate_interval]))\r\nor\r\nsum by(cluster) (rate(cilium_drop_count_total[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Packets Dropped By Cluster", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 57, + "panels": [], + "title": "Traffic (on $cluster)", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 0, + "y": 20 + }, + "id": 141, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_forward_bytes{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_forward_bytes{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(cilium_forward_bytes_total{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "Max Egress Bytes", + "range": true, + "refId": "A" + } + ], + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 3, + "y": 20 + }, + "id": 145, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(rate(networkobservability_forward_bytes{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_forward_bytes{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(cilium_forward_bytes_total{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "format": "time_series", + "instant": false, + "legendFormat": "Min Egress Bytes", + "range": true, + "refId": "A" + } + ], + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 6, + "y": 20 + }, + "id": 120, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_forward_count{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_forward_count{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(cilium_forward_count_total{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "Max Egress Packets", + "range": true, + "refId": "A" + } + ], + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 9, + "y": 20 + }, + "id": 146, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_forward_count{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_forward_count{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(cilium_forward_count_total{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "Min Egress Packets", + "range": true, + "refId": "A" + } + ], + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 12, + "y": 20 + }, + "id": 147, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_forward_bytes{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_forward_bytes{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(cilium_forward_bytes_total{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "Max Ingress Bytes", + "range": true, + "refId": "A" + } + ], + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 15, + "y": 20 + }, + "id": 148, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_forward_bytes{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_forward_bytes{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(cilium_forward_bytes_total{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "Min Ingress Bytes", + "range": true, + "refId": "A" + } + ], + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 18, + "y": 20 + }, + "id": 149, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_forward_count{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_forward_count{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(cilium_forward_count_total{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "Max Ingress Packets", + "range": true, + "refId": "A" + } + ], + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 21, + "y": 20 + }, + "id": 150, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_forward_count{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_forward_count{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(cilium_forward_count_total{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "Min Ingress Packets", + "range": true, + "refId": "A" + } + ], + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "super-light-blue", + "mode": "fixed" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 24 + }, + "id": 119, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_forward_bytes{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_forward_bytes{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(cilium_forward_bytes_total{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "Egress Bytes", + "range": true, + "refId": "A" + } + ], + "title": "Egress Bytes", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "super-light-blue", + "mode": "fixed" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 24 + }, + "id": 143, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_forward_count{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_forward_count{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(cilium_forward_count_total{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "Egress Packets", + "range": true, + "refId": "A" + } + ], + "title": "Egress Packets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "super-light-blue", + "mode": "fixed" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 24 + }, + "id": 142, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_forward_bytes{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_forward_bytes{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(cilium_forward_bytes_total{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "Ingress Bytes", + "range": true, + "refId": "A" + } + ], + "title": "Ingress Bytes", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "super-light-blue", + "mode": "fixed" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 24 + }, + "id": 144, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_forward_count{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_forward_count{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(cilium_forward_count_total{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "Ingress Packets", + "range": true, + "refId": "A" + } + ], + "title": "Ingress Packets", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 30 + }, + "id": 55, + "panels": [], + "title": "Drops (on $cluster)", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "fixed" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 31 + }, + "id": 124, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_drop_count{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_drop_count{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(cilium_drop_count_total{direction=\"egress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "Dropped Packets (Egress)", + "range": true, + "refId": "A" + } + ], + "title": "Packets Dropped - Egress", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "fixed" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 31 + }, + "id": 125, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_drop_count{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_drop_count{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(cilium_drop_count_total{direction=\"ingress\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "Dropped Packets (Ingress)", + "range": true, + "refId": "A" + } + ], + "title": "Packets Dropped - Ingress", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "fixed" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 31 + }, + "id": 114, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_drop_count{direction=\"unknown\", instance=~\"$Nodes\", cluster=\"$cluster\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_drop_count{direction=\"unknown\", instance=~\"$Nodes\", cluster=\"$cluster\"}[$__rate_interval]))", + "legendFormat": "Dropped Packets (Unknown)", + "range": true, + "refId": "A" + } + ], + "title": "Packets Dropped - Unknown", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Values:\n- Non-Cilium (Linux):\n - iptable_rule_drop: packet dropped in iptables, e.g., because of a NetworkPolicy if using --network-policy=azure\n - iptable_nat_drop: packet dropped in iptables during NAT (Network Address Translation)\n - tcp_connect_basic: packet dropped by tcp connect\n - tcp_accept_basic: packet dropped by tcp accept\n - tcp_close_basic: packet dropped by tcp close\n - conntrack_add_drop: packet dropped while conntrack (connection tracking) was adding the connection\n- Cilium (Linux):\n - Many possible values", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-YlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 38 + }, + "id": 86, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (reason) (rate(networkobservability_drop_bytes{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0\r\nor\r\nsum by (reason) (rate(kappie_drop_bytes{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0\r\nor\r\nsum by (reason) (rate(cilium_drop_bytes_total{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Bytes Dropped by Reason", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Values:\n- Non-Cilium (Linux):\n - iptable_rule_drop: packet dropped in iptables, e.g., because of a NetworkPolicy if using --network-policy=azure\n - iptable_nat_drop: packet dropped in iptables during NAT (Network Address Translation)\n - tcp_connect_basic: packet dropped by tcp connect\n - tcp_accept_basic: packet dropped by tcp accept\n - tcp_close_basic: packet dropped by tcp close\n - conntrack_add_drop: packet dropped while conntrack (connection tracking) was adding the connection\n - rx_dropped: an interface dropped a received packet\n - tx_dropped: an interface dropped a transmitted packet\n- Non-Cilium (Windows):\n - aclrule: dropped by an ACL rule in VFP, e.g., because of a NetworkPolicy\n - endpoint: dropped by an HNS Pod Endpoint \n- Cilium (Linux):\n - Many possible values", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-YlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 38 + }, + "id": 88, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (reason) (rate(networkobservability_drop_count{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0\r\nor\r\nsum by (reason) (rate(kappie_drop_count{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0\r\nor\r\nsum by (reason) (rate(cilium_drop_count_total{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0\r\nor\r\nsum by (reason) (\r\n label_replace(\r\n rate(networkobservability_interface_stats{statistic_name=\"rx_dropped\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]),\r\n \"reason\",\r\n \"$1\",\r\n \"statistic_name\",\r\n \"(.*)\"\r\n )\r\n)\r\nor # cannot combine these interface_stats expressions into one using regex, since regex would capture anything with rx_dropped or tx_dropped in it\r\nsum by (reason) (\r\n label_replace(\r\n rate(networkobservability_interface_stats{statistic_name=\"tx_dropped\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]),\r\n \"reason\",\r\n \"$1\",\r\n \"statistic_name\",\r\n \"(.*)\"\r\n )\r\n)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Packets Dropped by Reason", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-BlYlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 46 + }, + "id": 131, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by(instance) (rate(networkobservability_drop_bytes{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0\r\nor\r\nsum by(instance) (rate(kappie_drop_bytes{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0\r\nor\r\nsum by(instance) (rate(cilium_drop_bytes_total{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Bytes Dropped by Node", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-YlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 46 + }, + "id": 132, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by(instance) (rate(networkobservability_drop_count{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0\r\nor\r\nsum by(instance) (rate(kappie_drop_count{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0\r\nor\r\nsum by(instance) (rate(cilium_drop_count_total{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Packets Dropped by Node", + "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 54 + }, + "id": 59, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 64, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by(state) (networkobservability_tcp_state{cluster=\"$cluster\", instance=~\"$Nodes\"})\r\nor\r\nsum by(state) (kappie_tcp_state{cluster=\"$cluster\", instance=~\"$Nodes\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "TCP Active Connections by State", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 68, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by(address) (networkobservability_tcp_connection_remote{cluster=\"$cluster\", instance=~\"$Nodes\", address!~\"127.0.0.1|0.0.0.0\"})\r\nor\r\nsum by(address) (kappie_tcp_connection_remote{cluster=\"$cluster\", instance=~\"$Nodes\", address!~\"127.0.0.1|0.0.0.0\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "TCP Active Connections by Remote Addr", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-BlPu" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 10, + "x": 0, + "y": 16 + }, + "id": 65, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_tcp_connection_stats{statistic_name=\"tcptimeouts\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_tcp_connection_stats{statistic_name=\"tcptimeouts\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "TCP Timeouts", + "range": true, + "refId": "A" + } + ], + "title": "TCP Connection Timeouts", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-BlPu" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 10, + "y": 16 + }, + "id": 66, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_tcp_connection_stats{statistic_name=\"resetcount\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_tcp_connection_stats{statistic_name=\"resetcount\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "TCP Resets", + "range": true, + "refId": "A" + } + ], + "title": "TCP Connection Resets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-BlPu" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 17, + "y": 16 + }, + "id": 69, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_tcp_connection_stats{statistic_name=\"tcptsreorder\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_tcp_connection_stats{statistic_name=\"tcptsreorder\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "TCP Reorders", + "range": true, + "refId": "A" + } + ], + "title": "TCP Connection Reorders", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Windows Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-BlPu" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 24 + }, + "id": 61, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_tcp_flag_counters{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_tcp_flag_counters{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "TCP packets", + "range": true, + "refId": "A" + } + ], + "title": "Windows TCP Packets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Windows Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-BlPu" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 24 + }, + "id": 62, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_tcp_flag_counters{flag=\"rst\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_tcp_flag_counters{flag=\"rst\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "TCP Reset Packets", + "range": true, + "refId": "A" + } + ], + "title": "Windows TCP RST Packets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Windows Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-BlPu" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 24 + }, + "id": 70, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_tcp_flag_counters{flag=\"synack\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum(rate(kappie_tcp_flag_counters{flag=\"synack\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "TCP SYN-ACK packets", + "range": true, + "refId": "A" + } + ], + "title": "Windows TCP SYN-ACK Packets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-BlPu" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 72, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(networkobservability_udp_connection_stats{statistic_name=\"active\", cluster=\"$cluster\", instance=~\"$Nodes\"})\r\nor\r\nsum(kappie_udp_connection_stats{statistic_name=\"active\", cluster=\"$cluster\", instance=~\"$Nodes\"})", + "legendFormat": "Total UDP Connections", + "range": true, + "refId": "A" + } + ], + "title": "UDP Connections", + "type": "timeseries" + } + ], + "title": "Connections (on $cluster)", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 55 + }, + "id": 74, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 33 + }, + "id": 76, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (interface_name) (rate(networkobservability_interface_stats{statistic_name=\"rx_packets\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum by (interface_name) (rate(kappie_interface_stats{statistic_name=\"rx_packets\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "{{interface_name}}", + "range": true, + "refId": "A" + } + ], + "title": "RX Packets by Interface", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 33 + }, + "id": 77, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (interface_name) (rate(networkobservability_interface_stats{statistic_name=\"tx_packets\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))\r\nor\r\nsum by (interface_name) (rate(kappie_interface_stats{statistic_name=\"tx_packets\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval]))", + "legendFormat": "{{interface_name}}", + "range": true, + "refId": "A" + } + ], + "title": "TX Packets by Interface", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 33 + }, + "id": 94, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (instance) (rate(networkobservability_interface_stats{statistic_name=~\"rx[0-9]+_cache_full\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0\r\nor\r\nsum by (instance) (rate(kappie_interface_stats{statistic_name=~\"rx[0-9]+_cache_full\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Rx Cache Full error", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 33 + }, + "id": 93, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (instance) (rate(networkobservability_interface_stats{statistic_name=~\"tx[0-9]+_nop\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0\r\nor\r\nsum by (instance) (rate(kappie_interface_stats{statistic_name=~\"tx[0-9]+_nop\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0", + "hide": false, + "legendFormat": "{{instance}}", + "range": true, + "refId": "B" + } + ], + "title": "Tx No Op Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 41 + }, + "id": 161, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (instance) (rate(networkobservability_interface_stats{statistic_name=\"rx_dropped\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Dropped Rx Packets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 41 + }, + "id": 162, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (instance) (rate(networkobservability_interface_stats{statistic_name=\"tx_dropped\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Dropped Tx Packets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 41 + }, + "id": 160, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (instance) (rate(networkobservability_interface_stats{statistic_name=\"rx_comp_full\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0\r\nor\r\nsum by (instance) (rate(kappie_interface_stats{statistic_name=\"rx_comp_full\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Rx Comp Full Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 41 + }, + "id": 159, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (instance) (rate(networkobservability_interface_stats{statistic_name=\"tx_send_full\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0\r\nor\r\nsum by (instance) (rate(kappie_interface_stats{statistic_name=\"tx_send_full\", cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) > 0", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Tx Send Full Errors", + "type": "timeseries" + } + ], + "title": "Interfaces/Nodes (on $cluster)", + "type": "row" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [ + "k8s:network-observability" + ], + "templating": { + "list": [ + { + "current": {}, + "hide": 0, + "includeAll": false, + "label": "Data Source", + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": "(.*)", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(kube_node_info, cluster)", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "label_values(kube_node_info, cluster)", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "allValue": "(.*)", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(kube_node_info{cluster=\"$cluster\"},node)", + "hide": 0, + "includeAll": true, + "label": "Nodes", + "multi": true, + "name": "Nodes", + "options": [], + "query": { + "query": "label_values(kube_node_info{cluster=\"$cluster\"},node)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Kubernetes / Networking / Clusters", + "uid": "NetObs6738", + "version": 39 +} diff --git a/deploy/hubble/grafana/dashboards/dns.json b/deploy/hubble/grafana/dashboards/dns.json new file mode 100644 index 000000000..b6417f593 --- /dev/null +++ b/deploy/hubble/grafana/dashboards/dns.json @@ -0,0 +1,1022 @@ +{ + "__inputs": [], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.15" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "editable": true, + "id": null, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "k8s:network-observability" + ], + "targetBlank": false, + "title": "Dashboards: Network Observability", + "tooltip": "", + "type": "dashboards", + "url": "" + }, + { + "asDropdown": false, + "icon": "info", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Documentation", + "tooltip": "", + "type": "link", + "url": "https://aka.ms/NetObsAddonDoc" + } + ], + "liveNow": true, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "req/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 0 + }, + "id": 135, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum (rate(networkobservability_dns_request_count{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) by (query_type) > 0", + "legendFormat": "{{query_type}}", + "range": true, + "refId": "A" + } + ], + "title": "DNS Requests", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "resp/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 0 + }, + "id": 136, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum (rate(networkobservability_dns_response_count{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) by (query_type) > 0", + "legendFormat": "{{query_type}}", + "range": true, + "refId": "A" + } + ], + "title": "DNS Responses", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 0 + }, + "id": 137, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(\r\n 1 - (\r\n sum (networkobservability_dns_response_count{cluster=\"$cluster\", instance=~\"$Nodes\"}) by (query_type) / sum (networkobservability_dns_request_count{cluster=\"$cluster\", instance=~\"$Nodes\"}) by (query_type)\r\n )\r\n) * 100 * (\r\n (\r\n sum (rate(networkobservability_dns_response_count{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) by (query_type)\r\n ) > bool 0\r\n) > 0", + "legendFormat": "{{query_type}}", + "range": true, + "refId": "A" + } + ], + "title": "DNS Missing Response", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "resp/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 5 + }, + "id": 139, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(networkobservability_dns_response_count{cluster=\"$cluster\", instance=~\"$Nodes\", return_code=\"NoError\"}[$__rate_interval])) by (num_response) > 0", + "legendFormat": "{{num_response}}", + "range": true, + "refId": "A" + } + ], + "title": "DNS Response IPs Returned", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "resp/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 5 + }, + "id": 138, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(\r\n sum by (return_code, query_type) (\r\n rate(networkobservability_dns_response_count{cluster=\"$cluster\", instance=~\"$Nodes\", return_code!=\"NoError\"}[$__rate_interval])\r\n ) > 0, \"return_code\", \"non-existent domain\", \"return_code\", \"nxdomain\"\r\n ), \"return_code\", \"server failure\", \"return_code\", \"servfail\"\r\n)", + "legendFormat": "{{return_code}} ({{query_type}})", + "range": true, + "refId": "A" + } + ], + "title": "DNS Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "req/min" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 12 + }, + "id": 140, + "options": { + "legend": { + "calcs": [ + "max", + "last" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(topk(10, sum (60*rate(networkobservability_dns_request_count{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) by (query, query_type)), 1)", + "interval": "", + "legendFormat": "{{query}} ({{query_type}})", + "range": true, + "refId": "A" + } + ], + "title": "Top DNS Queries (Requests)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "resp/min" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 144, + "options": { + "legend": { + "calcs": [ + "max", + "last" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(topk(10, sum (60*rate(networkobservability_dns_response_count{cluster=\"$cluster\", instance=~\"$Nodes\"}[$__rate_interval])) by (query, query_type)), 1)", + "interval": "", + "legendFormat": "{{query}} ({{query_type}})", + "range": true, + "refId": "A" + } + ], + "title": "Top DNS Queries (Responses)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non-Cilium only", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 28 + }, + "id": 143, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "frameIndex": 22, + "showHeader": true, + "sortBy": [ + { + "desc": false, + "displayName": "Query" + } + ] + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "label_replace(\r\n label_replace(\r\n sum by (query, query_type, response, return_code) (\r\n 60*rate(networkobservability_dns_response_count{cluster=\"$cluster\", instance=~\"$Nodes\", num_response!=\"0\", response!=\"\"}[$__rate_interval])\r\n ), \"return_code\", \"non-existent domain\", \"return_code\", \"nxdomain\"\r\n ), \"return_code\", \"success\", \"return_code\", \"noerror\"\r\n)", + "instant": true, + "interval": "", + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "DNS Response Table", + "transformations": [ + { + "id": "labelsToFields", + "options": { + "keepLabels": [ + "num_response", + "query", + "query_type", + "response", + "return_code" + ] + } + }, + { + "id": "merge", + "options": {} + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true + }, + "indexByName": { + "Time": 0, + "Value": 1, + "num_response": 5, + "query": 2, + "query_type": 3, + "response": 6, + "return_code": 4 + }, + "renameByName": { + "Value": "Responses/Min", + "num_response": "IPs in Response", + "query": "Query", + "query_type": "Type", + "response": "Response", + "return_code": "Return Code" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "req/min" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 36 + }, + "id": 141, + "options": { + "legend": { + "calcs": [ + "max", + "last" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_dns_responses_total{cluster=\"$cluster\", instance=~\"$Nodes\", rcode=\"No Error\", destination=~\"/\"}[1m])) by (destination)", + "interval": "", + "legendFormat": "{{destination}}", + "range": true, + "refId": "A" + } + ], + "title": "Top Pods with DNS Errors", + "type": "timeseries" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [ + "k8s:network-observability" + ], + "templating": { + "list": [ + { + "current": {}, + "hide": 0, + "includeAll": false, + "label": "Data Source", + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(kube_node_info, cluster)", + "hide": 0, + "includeAll": true, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "label_values(kube_node_info, cluster)", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(kube_node_info, node)", + "hide": 0, + "includeAll": true, + "label": "Nodes", + "multi": true, + "name": "Nodes", + "options": [], + "query": { + "query": "label_values(kube_node_info, node)", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Kubernetes / Networking / DNS", + "uid": "NetObsDNS6741", + "version": 1 +} diff --git a/deploy/hubble/grafana/dashboards/pod-flows-namespace.json b/deploy/hubble/grafana/dashboards/pod-flows-namespace.json new file mode 100644 index 000000000..0ce2a61c2 --- /dev/null +++ b/deploy/hubble/grafana/dashboards/pod-flows-namespace.json @@ -0,0 +1,4269 @@ +{ + "__inputs": [], + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "bargauge", + "name": "Bar gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.15" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "editable": true, + "id": null, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "k8s:network-observability" + ], + "targetBlank": false, + "title": "Dashboards: Network Observability", + "tooltip": "", + "type": "dashboards", + "url": "" + }, + { + "asDropdown": false, + "icon": "info", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Documentation", + "tooltip": "Documentation", + "type": "link", + "url": "https://aka.ms/NetObsAddonDoc" + } + ], + "liveNow": true, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 179, + "panels": [], + "title": "Top Namespaces", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "displayName": "${__field.displayName}", + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 167, + "options": { + "displayMode": "basic", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "valueMode": "color" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "topk(\r\n 10, round(sum by (namespace) (\r\n label_replace(\r\n sum by (source) (rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"/\"}[$__rate_interval])),\r\n \"namespace\", \"$1\", \"source\", \"([-a-z0-9]+)/.+\"\r\n )\r\n ), 0.01)\r\n) > 0", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Top Source Namespaces (Outgoing Traffic)", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "displayName": "${__field.displayName}", + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 212, + "options": { + "displayMode": "basic", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "valueMode": "color" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "topk(\r\n 10, round(sum by (namespace) (\r\n label_replace(\r\n sum by (destination) (rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"/\"}[$__rate_interval])),\r\n \"namespace\", \"$1\", \"destination\", \"([-a-z0-9]+)/.+\"\r\n )\r\n ), 0.01)\r\n) > 0", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Top Destination Namespaces (Incoming Traffic)", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Drops seen on the VM of the source Pod (a drop will appear for only one of \"incoming\" or \"outgoing\")", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "fixed" + }, + "displayName": "${__field.displayName}", + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 5 + }, + "id": 214, + "options": { + "displayMode": "basic", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "text": {}, + "valueMode": "color" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "topk(\r\n 10, round(sum by (namespace) (\r\n label_replace(\r\n sum by (source) (rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"/\", verdict=\"dropped\"}[$__rate_interval])),\r\n \"namespace\", \"$1\", \"source\", \"([-a-z0-9]+)/.+\"\r\n )\r\n ), 0.01)\r\n) > 0", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Top Namespaces with Outgoing Drops", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Drops seen on the VM of the destination Pod (a drop will appear for only one of \"incoming\" or \"outgoing\")", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "fixed" + }, + "displayName": "${__field.displayName}", + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 5 + }, + "id": 213, + "options": { + "displayMode": "basic", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "text": {}, + "valueMode": "color" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "topk(\r\n 10, round(sum by (namespace) (\r\n label_replace(\r\n sum by (destination) (rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"/\", verdict=\"dropped\"}[$__rate_interval])),\r\n \"namespace\", \"$1\", \"destination\", \"([-a-z0-9]+)/.+\"\r\n )\r\n ), 0.01)\r\n) > 0", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Top Namespaces with Incoming Drops", + "type": "bargauge" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 216, + "panels": [], + "title": "Namespace Snapshot ($namespace)", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "purple", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 10 + }, + "id": 192, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count(\r\n sum by (source) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", verdict=\"forwarded\"}[10m])\r\n ) >= 0.01\r\n)", + "hide": false, + "instant": true, + "legendFormat": "Pods with Outgoing Traffic", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Outgoing Traffic (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 6, + "y": 10 + }, + "id": 193, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum (rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", verdict=\"forwarded\"}[$__rate_interval])), 0.01)", + "hide": false, + "instant": false, + "legendFormat": "Max Outgoing Traffic", + "range": true, + "refId": "A" + } + ], + "title": "Max Outgoing Traffic", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "super-light-blue", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 9, + "y": 10 + }, + "id": 198, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum (rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", verdict=\"forwarded\"}[$__rate_interval])), 0.01)", + "hide": false, + "instant": false, + "legendFormat": "Min Outgoing Traffic", + "range": true, + "refId": "A" + } + ], + "title": "Min Outgoing Traffic", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "purple", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 10 + }, + "id": 200, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count(\r\n sum by (destination) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", verdict=\"forwarded\"}[10m])\r\n ) >= 0.01\r\n)", + "hide": false, + "instant": true, + "legendFormat": "Pods with Incoming Traffic", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Incoming Traffic (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 18, + "y": 10 + }, + "id": 201, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum (rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", verdict=\"forwarded\"}[$__rate_interval])), 0.01)", + "hide": false, + "instant": false, + "legendFormat": "Max Incoming Traffic", + "range": true, + "refId": "A" + } + ], + "title": "Max Incoming Traffic", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "super-light-blue", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 10 + }, + "id": 202, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum (rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", verdict=\"forwarded\"}[$__rate_interval])), 0.01)", + "hide": false, + "instant": false, + "legendFormat": "Min Incoming Traffic", + "range": true, + "refId": "A" + } + ], + "title": "Min Incoming Traffic", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Drops seen on the VM of the source Pod (a drop will appear for only one of \"incoming\" or \"outgoing\")", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "orange", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 13 + }, + "id": 194, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count (\r\n sum by (source) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", verdict=\"dropped\"}[10m])\r\n ) >= 0.01\r\n)", + "hide": false, + "instant": true, + "legendFormat": "Pods with Outgoing Drops", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Outgoing Drops (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 6, + "y": 13 + }, + "id": 204, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum (rate(hubble_flows_processed_total{verdict=\"dropped\", cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\"}[$__rate_interval])), 0.01)", + "hide": false, + "instant": false, + "legendFormat": "Max Outgoing Drops", + "range": true, + "refId": "A" + } + ], + "title": "Max Outgoing Drops", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "super-light-red", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 9, + "y": 13 + }, + "id": 205, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum (rate(hubble_flows_processed_total{verdict=\"dropped\", cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\"}[$__rate_interval])), 0.01)", + "hide": false, + "instant": false, + "legendFormat": "Min Outgoing Drops", + "range": true, + "refId": "A" + } + ], + "title": "Min Outgoing Drops", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Drops seen on the VM of the destination Pod (a drop will appear for only one of \"incoming\" or \"outgoing\")", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "orange", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 13 + }, + "id": 203, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count (\r\n sum by (destination) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", verdict=\"dropped\"}[10m])\r\n ) >= 0.01\r\n)", + "hide": false, + "instant": true, + "legendFormat": "Pods with Incoming Drops", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Incoming Drops (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 18, + "y": 13 + }, + "id": 195, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum (rate(hubble_flows_processed_total{verdict=\"dropped\", cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\"}[$__rate_interval])), 0.01)", + "hide": false, + "instant": false, + "legendFormat": "Max Incoming Drops", + "range": true, + "refId": "A" + } + ], + "title": "Max Incoming Drops", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "super-light-red", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 13 + }, + "id": 199, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum (rate(hubble_flows_processed_total{verdict=\"dropped\", cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\"}[$__rate_interval])), 0.01)", + "hide": false, + "instant": false, + "legendFormat": "Min Incoming Drops", + "range": true, + "refId": "A" + } + ], + "title": "Min Incoming Drops", + "transparent": true, + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 178, + "panels": [], + "title": "Flows (in $namespace)", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Values:\n- to-stack: traffic leaving Pod\n- to-network/overlay: traffic leaving Node", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 17 + }, + "id": 174, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\"}[$__rate_interval])) by (type, subtype)", + "legendFormat": "{{type}}/{{subtype}}", + "range": true, + "refId": "A" + } + ], + "title": "Outgoing Traffic by Trace Type", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Values:\n- to-endpoint: traffic reaching Pod\n- from-network/overlay: traffic reaching Node\n", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 17 + }, + "id": 176, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\"}[$__rate_interval])) by (type, subtype)", + "legendFormat": "{{type}}/{{subtype}}", + "range": true, + "refId": "A" + } + ], + "title": "Incoming Traffic by Trace Type", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 24 + }, + "id": 175, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\"}[$__rate_interval])) by (verdict)", + "legendFormat": "{{verdict}}", + "range": true, + "refId": "A" + } + ], + "title": "Outgoing Traffic by Verdict", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 24 + }, + "id": 177, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\"}[$__rate_interval])) by (verdict)", + "legendFormat": "{{verdict}}", + "range": true, + "refId": "A" + } + ], + "title": "Incoming Traffic by Verdict", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 31 + }, + "id": 224, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "BuPu", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(sum by (source) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\"}[$__rate_interval])\r\n), 0.01)) > 0", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Outgoing Traffic for Top Source Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 31 + }, + "id": 225, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "BuPu", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(sum by (destination) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\"}[$__rate_interval])\r\n), 0.01)) > 0", + "hide": false, + "legendFormat": "{{destination}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Incoming Traffic for Top Destination Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 40 + }, + "id": 219, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum by (source) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\"}[$__rate_interval])\r\n), 0.01) > 0", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Outgoing Traffic by Source Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 40 + }, + "id": 206, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum by (destination) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\"}[$__rate_interval])\r\n), 0.01) > 0", + "hide": false, + "legendFormat": "{{destination}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Incoming Traffic by Destination Pod", + "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 49 + }, + "id": 183, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 50 + }, + "id": 228, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Oranges", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(sum by (source) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", verdict=\"dropped\"}[$__rate_interval])\r\n), 0.01)) > 0", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Outgoing Drops for Top Source Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 50 + }, + "id": 227, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Oranges", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(sum by (destination) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", verdict=\"dropped\"}[$__rate_interval])\r\n), 0.01)) > 0", + "hide": false, + "legendFormat": "{{destination}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Incoming Drops for Top Destination Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Drops seen on the VM of the source Pod (a drop will appear for only one of \"incoming\" or \"outgoing\")", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-YlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 59 + }, + "id": 211, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(\r\n sum by (source) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", verdict=\"dropped\"}[$__rate_interval])\r\n ), 0.01\r\n)", + "legendFormat": "{{destination}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Outgoing Drops by Source Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Drops seen on the VM of the destination Pod (a drop will appear for only one of \"incoming\" or \"outgoing\")", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-YlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 59 + }, + "id": 220, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(\r\n sum by (destination) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", verdict=\"dropped\"}[$__rate_interval])\r\n ), 0.01\r\n)", + "legendFormat": "{{destination}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Incoming Drops by Destination Pod", + "type": "timeseries" + } + ], + "title": "Drops (in $namespace)", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 50 + }, + "id": 182, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "orange" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 0, + "y": 51 + }, + "id": 221, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count (\r\n (\r\n (sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", flag=\"SYN\"}[10m])\r\n ) by (source) > 0) - sum(\r\n label_replace(\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", flag=\"SYN-ACK\"}[10m])\r\n ) by (destination), \"source\", \"$1\", \"destination\", \"(.*)\"\r\n )\r\n ) without (destination)\r\n ) >= 0.01\r\n)", + "instant": true, + "legendFormat": "Pods Missing SYN-ACKs", + "range": false, + "refId": "A" + } + ], + "title": "Pods Missing SYN-ACKs (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 5, + "y": 51 + }, + "id": 222, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", flag=\"SYN\"}[$__rate_interval])\r\n ) by (source) > 0 - sum(\r\n label_replace(\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", flag=\"SYN-ACK\"}[$__rate_interval])\r\n ) by (destination), \"source\", \"$1\", \"destination\", \"(.*)\"\r\n )\r\n ) without (destination)\r\n), 0.01)", + "legendFormat": "Max Packets Missing SYN-ACKs", + "range": true, + "refId": "A" + } + ], + "title": "Max Packets Missing SYN-ACKs", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-red" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 9, + "y": 51 + }, + "id": 223, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", flag=\"SYN\"}[$__rate_interval])\r\n ) by (source) > 0 - sum(\r\n label_replace(\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", flag=\"SYN-ACK\"}[$__rate_interval])\r\n ) by (destination), \"source\", \"$1\", \"destination\", \"(.*)\"\r\n )\r\n ) without (destination)\r\n), 0.01) > 0", + "legendFormat": "Min Packets Missing SYN-ACKs", + "range": true, + "refId": "A" + } + ], + "title": "Min Packets Missing SYN-ACKs", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 54 + }, + "id": 232, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Oranges", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", flag=\"SYN\"}[$__rate_interval])\r\n ) by (source) > 0 - sum(\r\n label_replace(\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", flag=\"SYN-ACK\"}[$__rate_interval])\r\n ) by (destination), \"source\", \"$1\", \"destination\", \"(.*)\"\r\n )\r\n ) without (destination), 0.01\r\n)) > 0", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Missing TCP SYN-ACKs by Top Source Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-YlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 54 + }, + "id": 184, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", flag=\"SYN\"}[$__rate_interval])\r\n ) by (source) > 0 - sum(\r\n label_replace(\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", flag=\"SYN-ACK\"}[$__rate_interval])\r\n ) by (destination), \"source\", \"$1\", \"destination\", \"(.*)\"\r\n )\r\n ) without (destination), 0.01\r\n)", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Missing TCP SYN-ACKs by Source Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "orange" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 0, + "y": 63 + }, + "id": 238, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count (\r\n sum by (source) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", flag=\"RST\"}[10m])\r\n ) >= 0.01\r\n)", + "instant": true, + "legendFormat": "Pods with Outgoing RST", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Outgoing RST (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 5, + "y": 63 + }, + "id": 239, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", flag=\"RST\"}[$__rate_interval])\r\n )\r\n), 0.01)", + "legendFormat": "Max Outgoing RST Packets", + "range": true, + "refId": "A" + } + ], + "title": "Max Outgoing RST Packets", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-red" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 9, + "y": 63 + }, + "id": 240, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", flag=\"RST\"}[$__rate_interval])\r\n )\r\n), 0.01)", + "legendFormat": "Min Outgoing RST Packets", + "range": true, + "refId": "A" + } + ], + "title": "Min Outgoing RST", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "orange" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 12, + "y": 63 + }, + "id": 233, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count (\r\n sum by (destination) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", flag=\"RST\"}[10m])\r\n ) >= 0.01\r\n)", + "instant": true, + "legendFormat": "Pods with Incoming RST", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Incoming RST (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 17, + "y": 63 + }, + "id": 234, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", flag=\"RST\"}[$__rate_interval])\r\n )\r\n), 0.01)", + "legendFormat": "Max Incoming RST Packets", + "range": true, + "refId": "A" + } + ], + "title": "Max Incoming RST Packets", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-red" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 63 + }, + "id": 235, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", flag=\"RST\"}[$__rate_interval])\r\n )\r\n), 0.01)", + "legendFormat": "Min Incoming RST Packets", + "range": true, + "refId": "A" + } + ], + "title": "Min Incoming RST", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 66 + }, + "id": 237, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Oranges", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(sum by (source) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", flag=\"RST\"}[$__rate_interval])\r\n), 0.01)) > 0", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Outgoing TCP RST by Top Source Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 66 + }, + "id": 236, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Oranges", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(sum by (destination) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", flag=\"RST\"}[$__rate_interval])\r\n), 0.01)) > 0", + "hide": false, + "legendFormat": "{{destination}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Incoming TCP RST by Top Destination Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-YlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 75 + }, + "id": 241, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum by (source) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", flag=\"RST\"}[$__rate_interval])\r\n), 0.01)", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Outgoing TCP RST by Source Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-YlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 75 + }, + "id": 242, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum by (destination) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", flag=\"RST\"}[$__rate_interval])\r\n), 0.01)", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Incoming TCP RST by Destination Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 0, + "y": 84 + }, + "id": 243, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count (\r\n sum by (source) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", flag=\"FIN\"}[10m])\r\n ) >= 0.01\r\n)", + "instant": true, + "legendFormat": "Pods with Outgoing FIN", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Outgoing FIN (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 5, + "y": 84 + }, + "id": 244, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", flag=\"FIN\"}[$__rate_interval])\r\n )\r\n), 0.01)", + "legendFormat": "Max Outgoing FIN Packets", + "range": true, + "refId": "A" + } + ], + "title": "Max Outgoing FIN Packets", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 9, + "y": 84 + }, + "id": 245, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", flag=\"FIN\"}[$__rate_interval])\r\n )\r\n), 0.01)", + "legendFormat": "Min Outgoing FIN Packets", + "range": true, + "refId": "A" + } + ], + "title": "MIN Outgoing FIN", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 12, + "y": 84 + }, + "id": 246, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count (\r\n sum by (destination) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", flag=\"FIN\"}[10m])\r\n ) >= 0.01\r\n)", + "instant": true, + "legendFormat": "Pods with Incoming FIN", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Incoming FIN (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 17, + "y": 84 + }, + "id": 247, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", flag=\"FIN\"}[$__rate_interval])\r\n )\r\n), 0.01)", + "legendFormat": "Max Incoming FIN Packets", + "range": true, + "refId": "A" + } + ], + "title": "Max Incoming FIN Packets", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue" + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 84 + }, + "id": 248, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", flag=\"FIN\"}[$__rate_interval])\r\n )\r\n), 0.01)", + "legendFormat": "Min Incoming FIN Packets", + "range": true, + "refId": "A" + } + ], + "title": "Min Incoming FIN", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 87 + }, + "id": 249, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "BuPu", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(sum by (source) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", flag=\"FIN\"}[$__rate_interval])\r\n), 0.01)) > 0", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Outgoing TCP FIN by Top Source Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 87 + }, + "id": 250, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "BuPu", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(sum by (destination) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", flag=\"FIN\"}[$__rate_interval])\r\n), 0.01)) > 0", + "hide": false, + "legendFormat": "{{destination}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Incoming TCP FIN by Top Destination Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 96 + }, + "id": 251, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum by (source) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/\", flag=\"FIN\"}[$__rate_interval])\r\n), 0.01)", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Outgoing TCP FIN by Source Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 96 + }, + "id": 252, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum by (destination) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/\", flag=\"FIN\"}[$__rate_interval])\r\n), 0.01)", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Incoming TCP FIN by Destination Pod", + "type": "timeseries" + } + ], + "title": "TCP (in $namespace)", + "type": "row" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [ + "k8s:network-observability" + ], + "templating": { + "list": [ + { + "current": {}, + "hide": 0, + "includeAll": false, + "label": "Data Source", + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": "(.*)", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(kube_node_info, cluster)", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "label_values(kube_node_info, cluster)", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "allValue": "(.*)", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(kube_node_info{cluster=\"$cluster\"},node)", + "hide": 0, + "includeAll": true, + "label": "Nodes", + "multi": true, + "name": "Nodes", + "options": [], + "query": { + "query": "label_values(kube_node_info{cluster=\"$cluster\"},node)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "allValue": "(.*)", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "query_result(label_replace(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\"}, \"ns\", \"$1\", \"destination\", \"(.*)\") or label_replace(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\"}, \"ns\", \"$1\", \"source\", \"(.*)\"))", + "description": "", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": { + "query": "query_result(label_replace(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\"}, \"ns\", \"$1\", \"destination\", \"(.*)\") or label_replace(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\"}, \"ns\", \"$1\", \"source\", \"(.*)\"))", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "/ns=\"([-a-z0-9]+)/.*/", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Kubernetes / Networking / Pod Flows (Namespace)", + "uid": "NetObsFlowsNamespace6739", + "version": 1 +} diff --git a/deploy/hubble/grafana/dashboards/pod-flows-workload.json b/deploy/hubble/grafana/dashboards/pod-flows-workload.json new file mode 100644 index 000000000..5f711f546 --- /dev/null +++ b/deploy/hubble/grafana/dashboards/pod-flows-workload.json @@ -0,0 +1,4019 @@ +{ + "__inputs": [], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.15" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "editable": true, + "id": null, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "k8s:network-observability" + ], + "targetBlank": false, + "title": "Dashboards: Network Observability", + "tooltip": "", + "type": "dashboards", + "url": "" + }, + { + "asDropdown": false, + "icon": "info", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Documentation", + "tooltip": "Documentation", + "type": "link", + "url": "https://aka.ms/NetObsAddonDoc" + } + ], + "liveNow": true, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 216, + "panels": [], + "title": "Workload Snapshot ($workload)", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "purple", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 1 + }, + "id": 192, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count(\r\n sum by (source) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", verdict=\"forwarded\"}[10m])\r\n ) >= 0.01\r\n)", + "hide": false, + "instant": true, + "legendFormat": "Pods with Outgoing Traffic", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Outgoing Traffic (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 6, + "y": 1 + }, + "id": 193, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum (rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", verdict=\"forwarded\"}[$__rate_interval])), 0.01)", + "hide": false, + "instant": false, + "legendFormat": "Max Outgoing Traffic", + "range": true, + "refId": "A" + } + ], + "title": "Max Outgoing Traffic", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "super-light-blue", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 9, + "y": 1 + }, + "id": 198, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum (rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", verdict=\"forwarded\"}[$__rate_interval])), 0.01)", + "hide": false, + "instant": false, + "legendFormat": "Min Outgoing Traffic", + "range": true, + "refId": "A" + } + ], + "title": "Min Outgoing Traffic", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "purple", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 1 + }, + "id": 200, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count(\r\n sum by (destination) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", verdict=\"forwarded\"}[10m])\r\n ) >= 0.01\r\n)", + "hide": false, + "instant": true, + "legendFormat": "Pods with Incoming Traffic", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Incoming Traffic (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 18, + "y": 1 + }, + "id": 201, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum (rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", verdict=\"forwarded\"}[$__rate_interval])), 0.01)", + "hide": false, + "instant": false, + "legendFormat": "Max Incoming Traffic", + "range": true, + "refId": "A" + } + ], + "title": "Max Incoming Traffic", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "super-light-blue", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 1 + }, + "id": 202, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum (rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", verdict=\"forwarded\"}[$__rate_interval])), 0.01)", + "hide": false, + "instant": false, + "legendFormat": "Min Incoming Traffic", + "range": true, + "refId": "A" + } + ], + "title": "Min Incoming Traffic", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Drops seen on the VM of the source Pod (a drop will appear for only one of \"incoming\" or \"outgoing\")", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "orange", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 4 + }, + "id": 194, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count (\r\n sum by (source) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", verdict=\"dropped\"}[10m])\r\n ) >= 0.01\r\n)", + "hide": false, + "instant": true, + "legendFormat": "Pods with Outgoing Drops", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Outgoing Drops (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 6, + "y": 4 + }, + "id": 204, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum (rate(hubble_flows_processed_total{verdict=\"dropped\", cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\"}[$__rate_interval])), 0.01)", + "hide": false, + "instant": false, + "legendFormat": "Max Outgoing Drops", + "range": true, + "refId": "A" + } + ], + "title": "Max Outgoing Drops", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "super-light-red", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 9, + "y": 4 + }, + "id": 205, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum (rate(hubble_flows_processed_total{verdict=\"dropped\", cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\"}[$__rate_interval])), 0.01)", + "hide": false, + "instant": false, + "legendFormat": "Min Outgoing Drops", + "range": true, + "refId": "A" + } + ], + "title": "Min Outgoing Drops", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Drops seen on the VM of the destination Pod (a drop will appear for only one of \"incoming\" or \"outgoing\")", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "orange", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 4 + }, + "id": 203, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count (\r\n sum by (destination) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", verdict=\"dropped\"}[10m])\r\n ) >= 0.01\r\n)", + "hide": false, + "instant": true, + "legendFormat": "Pods with Incoming Drops", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Incoming Drops (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 18, + "y": 4 + }, + "id": 195, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum (rate(hubble_flows_processed_total{verdict=\"dropped\", cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\"}[$__rate_interval])), 0.01)", + "hide": false, + "instant": false, + "legendFormat": "Max Incoming Drops", + "range": true, + "refId": "A" + } + ], + "title": "Max Incoming Drops", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "super-light-red", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 4 + }, + "id": 199, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum (rate(hubble_flows_processed_total{verdict=\"dropped\", cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\"}[$__rate_interval])), 0.01)", + "hide": false, + "instant": false, + "legendFormat": "Min Incoming Drops", + "range": true, + "refId": "A" + } + ], + "title": "Min Incoming Drops", + "transparent": true, + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 178, + "panels": [], + "title": "Flows (for $workload)", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Values:\n- to-stack: traffic leaving Pod\n- to-network/overlay: traffic leaving Node", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 174, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\"}[$__rate_interval])) by (type, subtype)", + "legendFormat": "{{type}}/{{subtype}}", + "range": true, + "refId": "A" + } + ], + "title": "Outgoing Traffic by Trace Type", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Values:\n- to-endpoint: traffic reaching Pod\n- from-network/overlay: traffic reaching Node", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 176, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\"}[$__rate_interval])) by (type, subtype)", + "legendFormat": "{{type}}/{{subtype}}", + "range": true, + "refId": "A" + } + ], + "title": "Incoming Traffic by Trace Type", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 15 + }, + "id": 175, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\"}[$__rate_interval])) by (verdict)", + "legendFormat": "{{verdict}}", + "range": true, + "refId": "A" + } + ], + "title": "Outgoing Traffic by Verdict", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 15 + }, + "id": 177, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\"}[$__rate_interval])) by (verdict)", + "legendFormat": "{{verdict}}", + "range": true, + "refId": "A" + } + ], + "title": "Incoming Traffic by Verdict", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 22 + }, + "id": 224, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "BuPu", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(sum by (source) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\"}[$__rate_interval])\r\n), 0.01)) > 0", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Outgoing Traffic for Top Source Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 22 + }, + "id": 225, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "BuPu", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(sum by (destination) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\"}[$__rate_interval])\r\n), 0.01)) > 0", + "hide": false, + "legendFormat": "{{destination}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Incoming Traffic for Top Destination Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 31 + }, + "id": 219, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum by (source) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\"}[$__rate_interval])\r\n), 0.01) > 0", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Outgoing Traffic by Source Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 31 + }, + "id": 206, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum by (destination) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\"}[$__rate_interval])\r\n), 0.01) > 0", + "hide": false, + "legendFormat": "{{destination}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Incoming Traffic by Destination Pod", + "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 40 + }, + "id": 183, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 9 + }, + "id": 228, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Oranges", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(sum by (source) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", verdict=\"dropped\"}[$__rate_interval])\r\n), 0.01)) > 0", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Outgoing Drops for Top Source Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 9 + }, + "id": 227, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Oranges", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(sum by (destination) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", verdict=\"dropped\"}[$__rate_interval])\r\n), 0.01)) > 0", + "hide": false, + "legendFormat": "{{destination}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Incoming Drops for Top Destination Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Drops seen on the VM of the source Pod (a drop will appear for only one of \"incoming\" or \"outgoing\")", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-YlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 18 + }, + "id": 211, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(\r\n sum by (source) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", verdict=\"dropped\"}[$__rate_interval])\r\n ), 0.01\r\n)", + "legendFormat": "{{destination}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Outgoing Drops by Source Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Drops seen on the VM of the destination Pod (a drop will appear for only one of \"incoming\" or \"outgoing\")", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-YlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 18 + }, + "id": 220, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(\r\n sum by (destination) (\r\n rate(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", verdict=\"dropped\"}[$__rate_interval])\r\n ), 0.01\r\n)", + "legendFormat": "{{destination}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Incoming Drops by Destination Pod", + "type": "timeseries" + } + ], + "title": "Drops (for $workload)", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 182, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "orange", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 0, + "y": 10 + }, + "id": 221, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count (\r\n (\r\n (sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", flag=\"SYN\"}[10m])\r\n ) by (source) > 0) - sum(\r\n label_replace(\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", flag=\"SYN-ACK\"}[10m])\r\n ) by (destination), \"source\", \"$1\", \"destination\", \"(.*)\"\r\n )\r\n ) without (destination)\r\n ) >= 0.01\r\n)", + "instant": true, + "legendFormat": "Pods Missing SYN-ACKs", + "range": false, + "refId": "A" + } + ], + "title": "Pods Missing SYN-ACKs (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 5, + "y": 10 + }, + "id": 222, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", flag=\"SYN\"}[$__rate_interval])\r\n ) by (source) > 0 - sum(\r\n label_replace(\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", flag=\"SYN-ACK\"}[$__rate_interval])\r\n ) by (destination), \"source\", \"$1\", \"destination\", \"(.*)\"\r\n )\r\n ) without (destination)\r\n), 0.01)", + "legendFormat": "Max Packets Missing SYN-ACKs", + "range": true, + "refId": "A" + } + ], + "title": "Max Packets Missing SYN-ACKs", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-red", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 9, + "y": 10 + }, + "id": 223, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", flag=\"SYN\"}[$__rate_interval])\r\n ) by (source) > 0 - sum(\r\n label_replace(\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", flag=\"SYN-ACK\"}[$__rate_interval])\r\n ) by (destination), \"source\", \"$1\", \"destination\", \"(.*)\"\r\n )\r\n ) without (destination)\r\n), 0.01) > 0", + "legendFormat": "Min Packets Missing SYN-ACKs", + "range": true, + "refId": "A" + } + ], + "title": "Min Packets Missing SYN-ACKs", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 13 + }, + "id": 232, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Oranges", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", flag=\"SYN\"}[$__rate_interval])\r\n ) by (source) > 0 - sum(\r\n label_replace(\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", flag=\"SYN-ACK\"}[$__rate_interval])\r\n ) by (destination), \"source\", \"$1\", \"destination\", \"(.*)\"\r\n )\r\n ) without (destination), 0.01\r\n)) > 0", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Missing TCP SYN-ACKs by Top Source Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-YlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 13 + }, + "id": 184, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", flag=\"SYN\"}[$__rate_interval])\r\n ) by (source) > 0 - sum(\r\n label_replace(\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", flag=\"SYN-ACK\"}[$__rate_interval])\r\n ) by (destination), \"source\", \"$1\", \"destination\", \"(.*)\"\r\n )\r\n ) without (destination), 0.01\r\n)", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Missing TCP SYN-ACKs by Source Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "orange", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 0, + "y": 22 + }, + "id": 238, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count (\r\n sum by (source) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", flag=\"RST\"}[10m])\r\n ) >= 0.01\r\n)", + "instant": true, + "legendFormat": "Pods with Outgoing RST", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Outgoing RST (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 5, + "y": 22 + }, + "id": 239, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", flag=\"RST\"}[$__rate_interval])\r\n )\r\n), 0.01)", + "legendFormat": "Max Outgoing RST Packets", + "range": true, + "refId": "A" + } + ], + "title": "Max Outgoing RST Packets", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-red", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 9, + "y": 22 + }, + "id": 240, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", flag=\"RST\"}[$__rate_interval])\r\n )\r\n), 0.01)", + "legendFormat": "Min Outgoing RST Packets", + "range": true, + "refId": "A" + } + ], + "title": "Min Outgoing RST", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "orange", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 12, + "y": 22 + }, + "id": 233, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count (\r\n sum by (destination) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", flag=\"RST\"}[10m])\r\n ) >= 0.01\r\n)", + "instant": true, + "legendFormat": "Pods with Incoming RST", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Incoming RST (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 17, + "y": 22 + }, + "id": 234, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", flag=\"RST\"}[$__rate_interval])\r\n )\r\n), 0.01)", + "legendFormat": "Max Incoming RST Packets", + "range": true, + "refId": "A" + } + ], + "title": "Max Incoming RST Packets", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-red", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 22 + }, + "id": 235, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", flag=\"RST\"}[$__rate_interval])\r\n )\r\n), 0.01)", + "legendFormat": "Min Incoming RST Packets", + "range": true, + "refId": "A" + } + ], + "title": "Min Incoming RST", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 25 + }, + "id": 237, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Oranges", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(sum by (source) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", flag=\"RST\"}[$__rate_interval])\r\n), 0.01)) > 0", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Outgoing TCP RST by Top Source Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 25 + }, + "id": 236, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Oranges", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(sum by (destination) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", flag=\"RST\"}[$__rate_interval])\r\n), 0.01)) > 0", + "hide": false, + "legendFormat": "{{destination}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Incoming TCP RST by Top Destination Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-YlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 3, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 34 + }, + "id": 241, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum by (source) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", flag=\"RST\"}[$__rate_interval])\r\n), 0.01)", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Outgoing TCP RST by Source Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-YlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 34 + }, + "id": 242, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum by (destination) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", flag=\"RST\"}[$__rate_interval])\r\n), 0.01)", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Incoming TCP RST by Destination Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 0, + "y": 43 + }, + "id": 243, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count (\r\n sum by (source) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", flag=\"FIN\"}[10m])\r\n ) >= 0.01\r\n)", + "instant": true, + "legendFormat": "Pods with Outgoing FIN", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Outgoing FIN (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 5, + "y": 43 + }, + "id": 244, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", flag=\"FIN\"}[$__rate_interval])\r\n )\r\n), 0.01)", + "legendFormat": "Max Outgoing FIN Packets", + "range": true, + "refId": "A" + } + ], + "title": "Max Outgoing FIN Packets", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 9, + "y": 43 + }, + "id": 245, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", flag=\"FIN\"}[$__rate_interval])\r\n )\r\n), 0.01)", + "legendFormat": "Min Outgoing FIN Packets", + "range": true, + "refId": "A" + } + ], + "title": "MIN Outgoing FIN", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 12, + "y": 43 + }, + "id": 246, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count (\r\n sum by (destination) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", flag=\"FIN\"}[10m])\r\n ) >= 0.01\r\n)", + "instant": true, + "legendFormat": "Pods with Incoming FIN", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Incoming FIN (past 10 minutes)", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 17, + "y": 43 + }, + "id": 247, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", flag=\"FIN\"}[$__rate_interval])\r\n )\r\n), 0.01)", + "legendFormat": "Max Incoming FIN Packets", + "range": true, + "refId": "A" + } + ], + "title": "Max Incoming FIN Packets", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 43 + }, + "id": 248, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "min" + ], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum (\r\n sum(\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", flag=\"FIN\"}[$__rate_interval])\r\n )\r\n), 0.01)", + "legendFormat": "Min Incoming FIN Packets", + "range": true, + "refId": "A" + } + ], + "title": "Min Incoming FIN", + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 46 + }, + "id": 249, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "BuPu", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(sum by (source) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", flag=\"FIN\"}[$__rate_interval])\r\n), 0.01)) > 0", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Outgoing TCP FIN by Top Source Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "TypeError means there are no drops or no data", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 46 + }, + "id": 250, + "options": { + "calculate": false, + "cellGap": 1, + "cellValues": { + "unit": "pps" + }, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "BuPu", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, round(sum by (destination) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", flag=\"FIN\"}[$__rate_interval])\r\n), 0.01)) > 0", + "hide": false, + "legendFormat": "{{destination}}", + "range": true, + "refId": "A" + } + ], + "title": "Heatmap of Incoming TCP FIN by Top Destination Pods", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 55 + }, + "id": 251, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum by (source) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/$workload\", flag=\"FIN\"}[$__rate_interval])\r\n), 0.01)", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Outgoing TCP FIN by Source Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 55 + }, + "id": 252, + "options": { + "legend": { + "calcs": [ + "max", + "min", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "round(sum by (destination) (\r\n rate(hubble_tcp_flags_total{cluster=~\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/$workload\", flag=\"FIN\"}[$__rate_interval])\r\n), 0.01)", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Stacked (Total) Incoming TCP FIN by Destination Pod", + "type": "timeseries" + } + ], + "title": "TCP (for $workload)", + "type": "row" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [ + "k8s:network-observability" + ], + "templating": { + "list": [ + { + "current": {}, + "hide": 0, + "includeAll": false, + "label": "Data Source", + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": "(.*)", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(kube_node_info, cluster)", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "label_values(kube_node_info, cluster)", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "allValue": "(.*)", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(kube_node_info{cluster=\"$cluster\"},node)", + "hide": 0, + "includeAll": true, + "label": "Nodes", + "multi": true, + "name": "Nodes", + "options": [], + "query": { + "query": "label_values(kube_node_info{cluster=\"$cluster\"},node)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "allValue": "(.*)", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "query_result(label_replace(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\"}, \"ns\", \"$1\", \"destination\", \"(.*)\") or label_replace(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\"}, \"ns\", \"$1\", \"source\", \"(.*)\"))", + "description": "", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": { + "query": "query_result(label_replace(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\"}, \"ns\", \"$1\", \"destination\", \"(.*)\") or label_replace(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\"}, \"ns\", \"$1\", \"source\", \"(.*)\"))", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "/ns=\"([-a-z0-9]+)/.*/", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "allValue": "(.*)", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "query_result(sum by (workload) (label_replace(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/[a-z0-9]+$\"}, \"workload\", \"$1\", \"destination\", \"^$namespace/([a-z0-9]+)\")) or sum by (workload) (label_replace(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/[a-z0-9]+-\"}, \"workload\", \"$1\", \"destination\", \"^$namespace/(.*)-[a-z0-9]+\"))or sum by (workload) (label_replace(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/[a-z0-9]+$\"}, \"workload\", \"$1\", \"source\", \"^$namespace/([a-z0-9]+)\")) or sum by (workload) (label_replace(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/[a-z0-9]+-\"}, \"workload\", \"$1\", \"source\", \"^$namespace/(.*)-[a-z0-9]+\")))", + "description": "", + "hide": 0, + "includeAll": false, + "label": "Workload", + "multi": false, + "name": "workload", + "options": [], + "query": { + "query": "query_result(sum by (workload) (label_replace(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/[a-z0-9]+$\"}, \"workload\", \"$1\", \"destination\", \"^$namespace/([a-z0-9]+)\")) or sum by (workload) (label_replace(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", destination=~\"^$namespace/[a-z0-9]+-\"}, \"workload\", \"$1\", \"destination\", \"^$namespace/(.*)-[a-z0-9]+\"))or sum by (workload) (label_replace(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/[a-z0-9]+$\"}, \"workload\", \"$1\", \"source\", \"^$namespace/([a-z0-9]+)\")) or sum by (workload) (label_replace(hubble_flows_processed_total{cluster=\"$cluster\", instance=~\"$Nodes\", source=~\"^$namespace/[a-z0-9]+-\"}, \"workload\", \"$1\", \"source\", \"^$namespace/(.*)-[a-z0-9]+\")))", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "/workload=\"([-a-z0-9]+)/g", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Kubernetes / Networking / Pod Flows (Workload)", + "uid": "NetObsFlowsWorkload6740", + "version": 1 +} diff --git a/deploy/manifests/controller/helm/retina/.helmignore b/deploy/hubble/manifests/controller/helm/retina/.helmignore similarity index 100% rename from deploy/manifests/controller/helm/retina/.helmignore rename to deploy/hubble/manifests/controller/helm/retina/.helmignore diff --git a/deploy/hubble/manifests/controller/helm/retina/Chart.yaml b/deploy/hubble/manifests/controller/helm/retina/Chart.yaml new file mode 100644 index 000000000..994713661 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: retina +description: A Helm chart for Retina Network Observability in Kubernetes with dependencies + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.0.1 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.0.1" diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/_helpers.tpl b/deploy/hubble/manifests/controller/helm/retina/templates/_helpers.tpl new file mode 100644 index 000000000..ce2573467 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/_helpers.tpl @@ -0,0 +1,82 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "retina.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "retina.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "retina.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "retina.labels" -}} +helm.sh/chart: {{ include "retina.chart" . }} +{{ include "retina.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "retina.selectorLabels" -}} +app.kubernetes.io/name: {{ include "retina.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +{{- define "retina.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "retina.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} +*/}} + +{{- define "cilium.image" -}} +{{- $digest := (.useDigest | default false) | ternary (printf "@%s" .digest) "" -}} +{{- if .override -}} +{{- printf "%s" .override -}} +{{- else -}} +{{- printf "%s:%s%s" .repository .tag $digest -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for cronjob. +*/}} +{{- define "cronjob.apiVersion" -}} +{{- if semverCompare ">=1.21-0" .Capabilities.KubeVersion.Version -}} +{{- print "batch/v1" -}} +{{- else -}} +{{- print "batch/v1beta1" -}} +{{- end -}} +{{- end -}} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/agent/clusterrole.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/agent/clusterrole.yaml new file mode 100644 index 000000000..bd60f37cd --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/agent/clusterrole.yaml @@ -0,0 +1,93 @@ +{{- if .Values.agent.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + namespace: {{ .Values.namespace }} + name: retina-cluster-reader +rules: + - apiGroups: [""] # "" indicates the core API group + resources: ["pods", "services", "replicationcontrollers", "nodes", "namespaces"] + verbs: ["get", "watch", "list"] + - apiGroups: ["apps"] + resources: ["deployments", "replicasets"] + verbs: ["get", "watch", "list"] + - apiGroups: ["networking.azure.com"] + resources: ["clusterobservers"] + verbs: ["get", "list", "watch"] + - apiGroups: + - retina.io + resources: + - retinaendpoints + verbs: + - get + - list + - watch + {{- if .Values.operator.enabled }} + - apiGroups: + - "" + resources: + - namespaces + - endpoints + verbs: + - get + - list + - watch + - apiGroups: + - retina.io + resources: + - retinaendpoints + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - retina.io + resources: + - metricsconfigurations + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - retina.io + resources: + - retinaendpoints/finalizers + verbs: + - update + - apiGroups: + - retina.io + resources: + - retinaendpoints/status + verbs: + - get + - patch + - update + - apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - get + - list + - watch + - apiGroups: + - cilium.io + resources: + - ciliumnodes + - ciliumidentities + - ciliumendpoints + verbs: + - get + - list + - watch + {{- end }} + +{{- end}} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/agent/clusterrolebinding.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/agent/clusterrolebinding.yaml new file mode 100644 index 000000000..5e16af04a --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/agent/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +{{- if .Values.agent.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: retina-cluster-reader-binding + namespace: {{ .Values.namespace }} +subjects: + - kind: ServiceAccount + name: retina-agent + namespace: {{ .Values.namespace }} +roleRef: + kind: ClusterRole + name: retina-cluster-reader + apiGroup: rbac.authorization.k8s.io + +{{- end}} \ No newline at end of file diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/agent/configmap.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/agent/configmap.yaml new file mode 100644 index 000000000..beea5ba49 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/agent/configmap.yaml @@ -0,0 +1,135 @@ +{{- if .Values.agent.enabled -}} +{{- if .Values.os.linux -}} +{{- $cluster := .Values.cluster | required "missing cluster value" -}} +{{- $clusterName := $cluster.name | required "missing cluster.name value" -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "retina.name" . }}-config + namespace: {{ .Values.namespace }} +data: + leader-election: {{ .Values.agent.leaderElection | quote }} + cluster-name: {{ $clusterName }} + {{- if .Values.hubble.enabled }} + # Enable Hubble gRPC service. + enable-hubble: {{ .Values.hubble.enabled | quote }} + # UNIX domain socket for Hubble server to listen to. + hubble-socket-path: {{ .Values.hubble.socketPath | quote }} +{{- if hasKey .Values.hubble "eventQueueSize" }} + # Buffer size of the channel for Hubble to receive monitor events. If this field is not set, + # the buffer size is set to the default monitor queue size. + hubble-event-queue-size: {{ .Values.hubble.eventQueueSize | quote }} +{{- end }} +{{- if hasKey .Values.hubble "eventBufferCapacity" }} + # Capacity of the buffer to store recent events. + hubble-event-buffer-capacity: {{ .Values.hubble.eventBufferCapacity | quote }} +{{- end }} +{{- if .Values.hubble.metrics.enabled }} + # Address to expose Hubble metrics (e.g. ":7070"). Metrics server will be disabled if this + # field is not set. + hubble-metrics-server: ":{{ .Values.hubble.metrics.port }}" + # A space separated list of metrics to enable. See [0] for available metrics. + # + # https://github.com/cilium/hubble/blob/master/Documentation/metrics.md + hubble-metrics: {{- range .Values.hubble.metrics.enabled }} + {{.}} +{{- end }} + enable-hubble-open-metrics: {{ .Values.hubble.metrics.enableOpenMetrics | quote }} +{{- end }} +{{- if .Values.hubble.redact }} +{{- if eq .Values.hubble.redact.enabled true }} + # Enables hubble redact capabilities + hubble-redact-enabled: "true" +{{- if .Values.hubble.redact.http }} + # Enables redaction of the http URL query part in flows + hubble-redact-http-urlquery: {{ .Values.hubble.redact.http.urlQuery | quote }} + # Enables redaction of the http user info in flows + hubble-redact-http-userinfo: {{ .Values.hubble.redact.http.userInfo | quote }} +{{- if .Values.hubble.redact.http.headers }} +{{- if .Values.hubble.redact.http.headers.allow }} + # Redact all http headers that do not match this list + hubble-redact-http-headers-allow: {{- range .Values.hubble.redact.http.headers.allow }} + {{ . }} +{{- end }} +{{- end }} +{{- if .Values.hubble.redact.http.headers.deny }} + # Redact all http headers that match this list + hubble-redact-http-headers-deny: {{- range .Values.hubble.redact.http.headers.deny }} + {{ . }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} +{{- if .Values.hubble.redact.kafka }} + # Enables redaction of the Kafka API key part in flows + hubble-redact-kafka-apikey: {{ .Values.hubble.redact.kafka.apiKey | quote }} +{{- end }} +{{- end }} +{{- end }} +{{- if .Values.hubble.export }} + hubble-export-file-max-size-mb: {{ .Values.hubble.export.fileMaxSizeMb | quote }} + hubble-export-file-max-backups: {{ .Values.hubble.export.fileMaxBackups | quote }} +{{- if .Values.hubble.export.static.enabled }} + hubble-export-file-path: {{ .Values.hubble.export.static.filePath | quote }} + hubble-export-fieldmask: {{ .Values.hubble.export.static.fieldMask | join " " | quote }} + hubble-export-allowlist: {{ .Values.hubble.export.static.allowList | join "," | quote }} + hubble-export-denylist: {{ .Values.hubble.export.static.denyList | join "," | quote }} +{{- end }} +{{- if .Values.hubble.export.dynamic.enabled }} + hubble-flowlogs-config-path: /flowlog-config/flowlogs.yaml +{{- end }} +{{- end }} +{{- if hasKey .Values.hubble "listenAddress" }} + # An additional address for Hubble server to listen to (e.g. ":4244"). + hubble-listen-address: {{ .Values.hubble.listenAddress | quote }} +{{- if .Values.hubble.tls.enabled }} + hubble-disable-tls: "false" + hubble-tls-cert-file: /var/lib/cilium/tls/hubble/server.crt + hubble-tls-key-file: /var/lib/cilium/tls/hubble/server.key + hubble-tls-client-ca-files: /var/lib/cilium/tls/hubble/client-ca.crt +{{- else }} + hubble-disable-tls: "true" +{{- end }} +{{- end }} +{{- if .Values.hubble.preferIpv6 }} + hubble-prefer-ipv6: "true" +{{- end }} +{{- if (not (kindIs "invalid" .Values.hubble.skipUnknownCGroupIDs)) }} + hubble-skip-unknown-cgroup-ids: {{ .Values.hubble.skipUnknownCGroupIDs | quote }} +{{- end }} +{{- end }} + config.yaml: |- + apiServer: + host: {{ .Values.apiServer.host }} + port: {{ .Values.retinaPort }} + logLevel: {{ .Values.logLevel }} + enabledPlugin: {{ .Values.enabledPlugin_linux }} + metricsInterval: {{ .Values.metricsInterval }} + enableTelemetry: {{ .Values.enableTelemetry }} + enablePodLevel: {{ .Values.enablePodLevel }} + remoteContext: {{ .Values.remoteContext }} + enableAnnotations: {{ .Values.enableAnnotations }} + bypassLookupIPOfInterest: {{ .Values.bypassLookupIPOfInterest }} +{{- end}} +--- +{{- if .Values.os.windows}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "retina.name" . }}-config-win + namespace: {{ .Values.namespace }} +data: + config.yaml: |- + apiServer: + host: {{ .Values.apiServer.host }} + port: {{ .Values.retinaPort }} + logLevel: {{ .Values.logLevel }} + enabledPlugin: {{ .Values.enabledPlugin_win }} + metricsInterval: {{ .Values.metricsInterval }} + enableTelemetry: {{ .Values.enableTelemetry }} + enablePodLevel: {{ .Values.enablePodLevel }} + remoteContext: {{ .Values.remoteContext }} + bypassLookupIPOfInterest: {{ .Values.bypassLookupIPOfInterest }} +{{- end}} + +{{- end}} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/agent/daemonset.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/agent/daemonset.yaml new file mode 100644 index 000000000..436148200 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/agent/daemonset.yaml @@ -0,0 +1,233 @@ +{{- if .Values.agent.enabled -}} +{{- if .Values.os.linux -}} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ .Values.agent.name }} + namespace: {{ .Values.namespace }} + labels: + k8s-app: {{ include "retina.name" . }} +spec: + selector: + matchLabels: + app: {{ include "retina.name" . }} + template: + metadata: + labels: + app: {{ include "retina.name" . }} + k8s-app: {{ include "retina.name" . }} + annotations: + prometheus.io/port: "{{ .Values.retinaPort }}" + prometheus.io/scrape: "true" + checksum/config: {{ include (print $.Template.BasePath "/agent/configmap.yaml") . | sha256sum }} + spec: + hostNetwork: true + serviceAccountName: {{ .Values.serviceAccount.name }} + nodeSelector: + kubernetes.io/os: linux + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + initContainers: + - name: retina-agent-init + image: {{ .Values.agent.init.repository }}:{{ .Values.agent.init.tag }} + imagePullPolicy: {{ .Values.agent.pullPolicy }} + terminationMessagePolicy: FallbackToLogsOnError + securityContext: + privileged: true + volumeMounts: + - name: bpf + mountPath: /sys/fs/bpf + mountPropagation: Bidirectional + - name: varrun + mountPath: /var/run + mountPropagation: Bidirectional + containers: + - name: {{ include "retina.name" . }} + image: {{ .Values.agent.repository }}:{{ .Values.agent.tag }} + imagePullPolicy: {{ .Values.agent.pullPolicy }} + {{- if .Values.agent.container.retina.command }} + command: + {{- range .Values.agent.container.retina.command }} + - {{ . }} + {{- end }} + {{- end }} + {{- if .Values.agent.container.retina.args}} + args: + - --health-probe-bind-address={{ .Values.agent.container.retina.healthProbeBindAddress }} + - --metrics-bind-address={{ .Values.agent.container.retina.metricsBindAddress }} + {{- range $.Values.agent.container.retina.args}} + - {{ . | quote }} + {{- end}} + {{- end}} + ports: + - containerPort: {{ .Values.agent.container.retina.ports.containerPort }} + resources: + limits: + memory: {{ .Values.resources.limits.memory | quote }} + cpu: {{ .Values.resources.limits.cpu | quote }} + readinessProbe: + httpGet: + path: /metrics + port: {{ .Values.agent.container.retina.ports.containerPort }} + initialDelaySeconds: 10 + periodSeconds: 30 + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: NODE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + securityContext: + capabilities: + add: + {{- range .Values.securityContext.capabilities.add }} + - {{ . }} + {{- end }} + privileged: {{ .Values.securityContext.privileged }} + {{- if .Values.volumeMounts }} + volumeMounts: + {{- range $name, $mountPath := .Values.volumeMounts }} + - name: {{ $name }} + mountPath: {{ $mountPath }} + {{- end }} + {{- if .Values.hubble.tls.enabled }} + - name: tls + mountPath: /var/lib/cilium/tls/hubble + readOnly: true + {{- end }} + {{- end }} + terminationGracePeriodSeconds: 90 # Allow for retina to cleanup plugin resources. + volumes: + {{- range $name, $hostPath := .Values.volumeMounts}} + - name: {{ $name }} + {{ if eq $name "config" }} + configMap: + name: {{ $.Values.nameOverride }}-config + {{ else if eq $name "tmp"}} + emptyDir: {} + {{ else }} + hostPath: + path: {{ $hostPath }} + {{ end }} + {{- end }} + {{- if .Values.hubble.tls.enabled }} + - name: tls + projected: + defaultMode: 0400 + sources: + - secret: + name: hubble-server-certs + items: + - key: tls.crt + path: server.crt + - key: tls.key + path: server.key + - key: ca.crt + path: client-ca.crt + {{- end }} + nodeSelector: + kubernetes.io/os: linux +{{- end }} +--- +{{- if .Values.os.windows}} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + labels: + k8s-app: {{ include "retina.name" . }} + name: {{ .Values.agent_win.name }} + namespace: {{ .Values.namespace }} + annotations: + prometheus.io/port: "{{ .Values.retinaPort }}" + prometheus.io/scrape: "true" + checksum/config: {{ include (print $.Template.BasePath "/agent/configmap.yaml") . | sha256sum }} +spec: + selector: + matchLabels: + k8s-app: {{ include "retina.name" . }} + template: + metadata: + labels: + app: {{ include "retina.name" . }} + k8s-app: {{ include "retina.name" . }} + name: {{ include "retina.name" . }} + namespace: {{ .Values.namespace }} + spec: + serviceAccountName: {{ .Values.serviceAccount.name }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + windowsOptions: + hostProcess: true + runAsUserName: {{ .Values.securityContext.windowsOptions.runAsUserName}} + runAsNonRoot: false + hostNetwork: true + containers: + - name: retinawin + image: {{ .Values.agent.repository }}:{{ .Values.agent.tag }} + ports: + - containerPort: {{ .Values.agent.container.retina.ports.containerPort }} + command: + - powershell.exe + - -command + - .\setkubeconfigpath.ps1; ./controller.exe --config ./retina/config.yaml --kubeconfig ./kubeconfig + readinessProbe: + httpGet: + path: /metrics + port: {{ .Values.agent.container.retina.ports.containerPort }} + initialDelaySeconds: 15 + periodSeconds: 10 + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: NODE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + securityContext: + capabilities: + add: + {{- range .Values.securityContext.capabilities.add }} + - {{ . }} + {{- end }} + privileged: {{ .Values.securityContext.privileged }} + {{- if .Values.volumeMounts_win }} + volumeMounts: + {{- range $name, $mountPath := .Values.volumeMounts_win }} + - name: {{ $name }} + mountPath: {{ $mountPath }} + {{- end }} + {{- end }} + nodeSelector: + kubernetes.io/os: windows + volumes: + {{- range $name, $mountPath := .Values.volumeMounts_win }} + - name: {{ $name }} + configMap: + name: {{ $name }} + {{- end }} +{{- end }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/agent/service.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/agent/service.yaml new file mode 100644 index 000000000..562e2a5f6 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/agent/service.yaml @@ -0,0 +1,16 @@ +{{- if .Values.agent.enabled -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "retina.fullname" . }} + namespace: {{ .Values.namespace }} + labels: + app: {{ include "retina.name" . }} +spec: + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.retinaPort }} + selector: + app: {{ include "retina.name" . }} + +{{- end}} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/agent/serviceaccount.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/agent/serviceaccount.yaml new file mode 100644 index 000000000..0aa222703 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/agent/serviceaccount.yaml @@ -0,0 +1,8 @@ +{{- if .Values.agent.enabled -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.serviceAccount.name }} + namespace: {{ .Values.namespace }} + +{{- end}} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/configmap.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/configmap.yaml new file mode 100644 index 000000000..93f5b8d88 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/configmap.yaml @@ -0,0 +1,51 @@ +{{- if and .Values.hubble.enabled .Values.hubble.relay.enabled }} +{{- $peerSvcPort := .Values.hubble.peerService.servicePort -}} +{{- if not .Values.hubble.peerService.servicePort }} +{{- $peerSvcPort = (.Values.hubble.tls.enabled | ternary 443 80) -}} +{{- end }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: hubble-relay-config + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.relay.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +data: + config.yaml: | + cluster-name: {{ .Values.cluster.name }} + peer-service: "hubble-peer.{{ .Release.Namespace }}.svc.{{ .Values.hubble.peerService.clusterDomain }}:{{ $peerSvcPort }}" + listen-address: {{ .Values.hubble.relay.listenHost }}:{{ .Values.hubble.relay.listenPort }} + gops: {{ .Values.hubble.relay.gops.enabled }} + gops-port: {{ .Values.hubble.relay.gops.port | quote }} + {{- if .Values.hubble.relay.pprof.enabled }} + pprof: {{ .Values.hubble.relay.pprof.enabled | quote }} + pprof-address: {{ .Values.hubble.relay.pprof.address | quote }} + pprof-port: {{ .Values.hubble.relay.pprof.port | quote }} + {{- end }} + {{- if .Values.hubble.relay.prometheus.enabled }} + metrics-listen-address: ":{{ .Values.hubble.relay.prometheus.port }}" + {{- end }} + dial-timeout: {{ .Values.hubble.relay.dialTimeout }} + retry-timeout: {{ .Values.hubble.relay.retryTimeout }} + sort-buffer-len-max: {{ .Values.hubble.relay.sortBufferLenMax }} + sort-buffer-drain-timeout: {{ .Values.hubble.relay.sortBufferDrainTimeout }} + {{- if .Values.hubble.tls.enabled }} + tls-hubble-client-cert-file: /var/lib/hubble-relay/tls/client.crt + tls-hubble-client-key-file: /var/lib/hubble-relay/tls/client.key + tls-hubble-server-ca-files: /var/lib/hubble-relay/tls/hubble-server-ca.crt + {{- else }} + disable-client-tls: true + {{- end }} + {{- if and .Values.hubble.tls.enabled .Values.hubble.relay.tls.server.enabled }} + tls-relay-server-cert-file: /var/lib/hubble-relay/tls/server.crt + tls-relay-server-key-file: /var/lib/hubble-relay/tls/server.key + {{- if .Values.hubble.relay.tls.server.mtls }} + tls-relay-client-ca-files: /var/lib/hubble-relay/tls/hubble-server-ca.crt + {{- end }} + {{- else }} + disable-server-tls: true + {{- end }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/deployment.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/deployment.yaml new file mode 100644 index 000000000..71b06b6e7 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/deployment.yaml @@ -0,0 +1,214 @@ +{{- if and .Values.hubble.enabled .Values.hubble.relay.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: hubble-relay + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.relay.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + k8s-app: hubble-relay + app.kubernetes.io/name: hubble-relay + app.kubernetes.io/part-of: cilium +spec: + replicas: {{ .Values.hubble.relay.replicas }} + selector: + matchLabels: + k8s-app: hubble-relay + {{- with .Values.hubble.relay.updateStrategy }} + strategy: + {{- toYaml . | trim | nindent 4 }} + {{- end }} + template: + metadata: + annotations: + {{- if .Values.hubble.relay.rollOutPods }} + # ensure pods roll when configmap updates + cilium.io/hubble-relay-configmap-checksum: {{ include (print $.Template.BasePath "/hubble-relay/configmap.yaml") . | sha256sum | quote }} + {{- end }} + {{- with .Values.hubble.relay.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + k8s-app: hubble-relay + app.kubernetes.io/name: hubble-relay + app.kubernetes.io/part-of: cilium + {{- with .Values.hubble.relay.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.hubble.relay.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: hubble-relay + {{- with .Values.hubble.relay.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + image: "{{ .Values.hubble.relay.image.repository }}:{{ .Values.hubble.relay.image.tag }}" + imagePullPolicy: {{ .Values.hubble.relay.image.pullPolicy }} + command: + - hubble-relay + args: + - serve + {{- if not .Values.hubble.relay.tls.server.enabled }} + - --disable-client-tls + - --disable-server-tls + {{- end }} + {{- if .Values.debug.enabled }} + - --debug + {{- end }} + ports: + - name: grpc + containerPort: {{ .Values.hubble.relay.listenPort }} + {{- if .Values.hubble.relay.prometheus.enabled }} + - name: prometheus + containerPort: {{ .Values.hubble.relay.prometheus.port }} + protocol: TCP + {{- end }} + readinessProbe: + {{- include "hubble-relay.probe" . | nindent 12 }} + {{- if semverCompare "<1.20-0" .Capabilities.KubeVersion.Version }} + # Starting from Kubernetes 1.20, we are using startupProbe instead + # of this field. + initialDelaySeconds: 5 + {{- end }} + livenessProbe: + {{- include "hubble-relay.probe" . | nindent 12 }} + {{- if semverCompare "<1.20-0" .Capabilities.KubeVersion.Version }} + # Starting from Kubernetes 1.20, we are using startupProbe instead + # of this field. + initialDelaySeconds: 60 + {{- end }} + {{- if semverCompare ">=1.20-0" .Capabilities.KubeVersion.Version }} + startupProbe: + # give the relay one minute to start up + {{- include "hubble-relay.probe" . | nindent 12 }} + failureThreshold: 20 + periodSeconds: 3 + {{- end }} + {{- with .Values.hubble.relay.extraEnv }} + env: + {{- toYaml . | trim | nindent 12 }} + {{- end }} + {{- with .Values.hubble.relay.resources }} + resources: + {{- toYaml . | trim | nindent 12 }} + {{- end }} + volumeMounts: + - name: config + mountPath: /etc/hubble-relay + readOnly: true + {{- if .Values.hubble.tls.enabled }} + - name: tls + mountPath: /var/lib/hubble-relay/tls + readOnly: true + {{- end }} + {{- with .Values.hubble.relay.extraVolumeMounts }} + {{- toYaml . | nindent 10 }} + {{- end }} + terminationMessagePolicy: FallbackToLogsOnError + restartPolicy: Always + priorityClassName: {{ .Values.hubble.relay.priorityClassName }} + serviceAccount: {{ .Values.serviceAccounts.relay.name | quote }} + serviceAccountName: {{ .Values.serviceAccounts.relay.name | quote }} + automountServiceAccountToken: {{ .Values.serviceAccounts.relay.automount }} + terminationGracePeriodSeconds: {{ .Values.hubble.relay.terminationGracePeriodSeconds }} + {{- with .Values.hubble.relay.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.hubble.relay.topologySpreadConstraints }} + topologySpreadConstraints: + {{- range $constraint := . }} + - {{ toYaml $constraint | nindent 8 | trim }} + {{- if not $constraint.labelSelector }} + labelSelector: + matchLabels: + k8s-app: hubble-relay + {{- end }} + {{- end }} + {{- end }} + {{- with .Values.hubble.relay.nodeSelector }} + nodeSelector: + {{- toYaml . | trim | nindent 8 }} + {{- end }} + {{- with .Values.hubble.relay.tolerations }} + tolerations: + {{- toYaml . | trim | nindent 8 }} + {{- end }} + volumes: + - name: config + configMap: + name: hubble-relay-config + items: + - key: config.yaml + path: config.yaml + {{- if .Values.hubble.tls.enabled }} + - name: tls + projected: + # note: the leading zero means this number is in octal representation: do not remove it + defaultMode: 0400 + sources: + - secret: + name: hubble-relay-client-certs + items: + - key: tls.crt + path: client.crt + - key: tls.key + path: client.key + {{- if not .Values.tls.caBundle.enabled }} + - key: ca.crt + path: hubble-server-ca.crt + {{- else }} + - {{ .Values.tls.caBundle.useSecret | ternary "secret" "configMap" }}: + name: {{ .Values.tls.caBundle.name }} + items: + - key: {{ .Values.tls.caBundle.key }} + path: hubble-server-ca.crt + {{- end }} + {{- if .Values.hubble.relay.tls.server.enabled }} + - secret: + name: hubble-relay-server-certs + items: + - key: tls.crt + path: server.crt + - key: tls.key + path: server.key + {{- end }} + {{- end }} + {{- with .Values.hubble.relay.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end }} + +{{- define "hubble-relay.probe" }} +{{- /* This distinction can be removed once we drop support for k8s 1.23 */}} +{{- if and (semverCompare ">=1.24-0" .Capabilities.KubeVersion.Version) (not .Values.hubble.tls.enabled) -}} +grpc: + port: {{ .Values.hubble.relay.listenPort }} +{{- else }} +exec: + command: + - grpc_health_probe + - -addr=localhost:{{ .Values.hubble.relay.listenPort }} +{{- if .Values.hubble.tls.enabled }} + - -tls + - -tls-ca-cert=/var/lib/hubble-relay/tls/hubble-server-ca.crt + - -tls-client-cert=/var/lib/hubble-relay/tls/client.crt + - -tls-client-key=/var/lib/hubble-relay/tls/client.key + - -tls-server-name=instance.hubble-relay.cilium.io + - -connect-timeout=5s + - -rpc-timeout=5s +{{- end }} +{{- end }} +timeoutSeconds: 3 +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/metrics-service.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/metrics-service.yaml new file mode 100644 index 000000000..1066c6c4c --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/metrics-service.yaml @@ -0,0 +1,24 @@ +{{- if and .Values.hubble.enabled .Values.hubble.relay.enabled .Values.hubble.relay.prometheus.enabled }} +# We use a separate service from hubble-relay which can be exposed externally +kind: Service +apiVersion: v1 +metadata: + name: hubble-relay-metrics + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.relay.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + k8s-app: hubble-relay +spec: + clusterIP: None + type: ClusterIP + selector: + k8s-app: hubble-relay + ports: + - name: metrics + port: {{ .Values.hubble.relay.prometheus.port }} + protocol: TCP + targetPort: prometheus +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/poddisruptionbudget.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/poddisruptionbudget.yaml new file mode 100644 index 000000000..4fd6da9ba --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/poddisruptionbudget.yaml @@ -0,0 +1,26 @@ +{{- if and .Values.hubble.enabled .Values.hubble.relay.enabled .Values.hubble.relay.podDisruptionBudget.enabled }} +{{- $component := .Values.hubble.relay.podDisruptionBudget }} +apiVersion: {{ include "podDisruptionBudget.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: hubble-relay + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.relay.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + k8s-app: hubble-relay + app.kubernetes.io/name: hubble-relay + app.kubernetes.io/part-of: cilium +spec: + {{- with $component.maxUnavailable }} + maxUnavailable: {{ . }} + {{- end }} + {{- with $component.minAvailable }} + minAvailable: {{ . }} + {{- end }} + selector: + matchLabels: + k8s-app: hubble-relay +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/service.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/service.yaml new file mode 100644 index 000000000..fc13c9016 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/service.yaml @@ -0,0 +1,30 @@ +{{- if and .Values.hubble.enabled .Values.hubble.relay.enabled }} +kind: Service +apiVersion: v1 +metadata: + name: hubble-relay + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.relay.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + k8s-app: hubble-relay + app.kubernetes.io/name: hubble-relay + app.kubernetes.io/part-of: retina +spec: + type: {{ .Values.hubble.relay.service.type | quote }} + selector: + k8s-app: hubble-relay + ports: + - protocol: TCP + {{- if .Values.hubble.relay.servicePort }} + port: {{ .Values.hubble.relay.servicePort }} + {{- else }} + port: {{ .Values.hubble.relay.tls.server.enabled | ternary 443 80 }} + {{- end }} + targetPort: {{ .Values.hubble.relay.listenPort }} + {{- if and (eq "NodePort" .Values.hubble.relay.service.type) .Values.hubble.relay.service.nodePort }} + nodePort: {{ .Values.hubble.relay.service.nodePort }} + {{- end }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/serviceaccount.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/serviceaccount.yaml new file mode 100644 index 000000000..cf56d6314 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.hubble.enabled .Values.hubble.relay.enabled .Values.serviceAccounts.relay.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.serviceAccounts.relay.name | quote }} + namespace: {{ .Release.Namespace }} + {{- if or .Values.serviceAccounts.relay.annotations .Values.hubble.relay.annotations }} + annotations: + {{- with .Values.hubble.relay.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.serviceAccounts.relay.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/servicemonitor.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/servicemonitor.yaml new file mode 100644 index 000000000..4e41fdf3c --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-relay/servicemonitor.yaml @@ -0,0 +1,39 @@ +{{- if and .Values.hubble.enabled .Values.hubble.relay.enabled .Values.hubble.relay.prometheus.enabled .Values.hubble.relay.prometheus.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: hubble-relay + namespace: {{ .Values.hubble.relay.prometheus.serviceMonitor.namespace | default .Release.Namespace }} + labels: + {{- with .Values.hubble.relay.prometheus.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if or .Values.hubble.relay.prometheus.serviceMonitor.annotations .Values.hubble.relay.annotations }} + annotations: + {{- with .Values.hubble.relay.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.hubble.relay.prometheus.serviceMonitor.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +spec: + selector: + matchLabels: + k8s-app: hubble-relay + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + endpoints: + - port: metrics + interval: {{ .Values.hubble.relay.prometheus.serviceMonitor.interval | quote }} + path: /metrics + {{- with .Values.hubble.relay.prometheus.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.hubble.relay.prometheus.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/_nginx.tpl b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/_nginx.tpl new file mode 100644 index 000000000..e787b5aad --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/_nginx.tpl @@ -0,0 +1,61 @@ +{{- define "hubble-ui.nginx.conf" }} +server { + listen 8081; +{{- if .Values.hubble.ui.frontend.server.ipv6.enabled }} + listen [::]:8081; +{{- end }} + server_name localhost; + root /app; + index index.html; + client_max_body_size 1G; + + location / { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + + # CORS + add_header Access-Control-Allow-Methods "GET, POST, PUT, HEAD, DELETE, OPTIONS"; + add_header Access-Control-Allow-Origin *; + add_header Access-Control-Max-Age 1728000; + add_header Access-Control-Expose-Headers content-length,grpc-status,grpc-message; + add_header Access-Control-Allow-Headers range,keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout; + if ($request_method = OPTIONS) { + return 204; + } + # /CORS + + location {{ .Values.hubble.ui.baseUrl }}api { + {{- if not (eq .Values.hubble.ui.baseUrl "/") }} + rewrite ^{{ (trimSuffix "/" .Values.hubble.ui.baseUrl) }}(/.*)$ $1 break; + {{- end }} + proxy_http_version 1.1; + proxy_pass_request_headers on; + proxy_hide_header Access-Control-Allow-Origin; + {{- if eq .Values.hubble.ui.baseUrl "/" }} + proxy_pass http://127.0.0.1:8090; + {{- else }} + proxy_pass http://127.0.0.1:8090/; + {{- end }} + } + + {{- if not (eq .Values.hubble.ui.baseUrl "/") }} + sub_filter_once on; + sub_filter '' ''; + {{- end }} + location {{ .Values.hubble.ui.baseUrl }} { + {{- if not (eq .Values.hubble.ui.baseUrl "/") }} + rewrite ^{{ (trimSuffix "/" .Values.hubble.ui.baseUrl) }}(/.*)$ $1 break; + {{- end }} + # double `/index.html` is required here + try_files $uri $uri/ /index.html /index.html; + } + + # Liveness probe + location /healthz { + access_log off; + add_header Content-Type text/plain; + return 200 'ok'; + } + } +} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/clusterrole.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/clusterrole.yaml new file mode 100644 index 000000000..5df709f76 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/clusterrole.yaml @@ -0,0 +1,50 @@ +{{- if and (or .Values.hubble.enabled .Values.hubble.ui.standalone.enabled) .Values.hubble.ui.enabled .Values.serviceAccounts.ui.create }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: hubble-ui + {{- with .Values.hubble.ui.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app.kubernetes.io/part-of: cilium +rules: +- apiGroups: + - networking.k8s.io + resources: + - networkpolicies + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - componentstatuses + - endpoints + - namespaces + - nodes + - pods + - services + verbs: + - get + - list + - watch +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - list + - watch +- apiGroups: + - cilium.io + resources: + - "*" + verbs: + - get + - list + - watch +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/clusterrolebinding.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/clusterrolebinding.yaml new file mode 100644 index 000000000..d091786b2 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/clusterrolebinding.yaml @@ -0,0 +1,20 @@ +{{- if and (or .Values.hubble.enabled .Values.hubble.ui.standalone.enabled) .Values.hubble.ui.enabled .Values.serviceAccounts.ui.create }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: hubble-ui + {{- with .Values.hubble.ui.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app.kubernetes.io/part-of: cilium +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: hubble-ui +subjects: +- kind: ServiceAccount + name: {{ .Values.serviceAccounts.ui.name | quote }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/configmap.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/configmap.yaml new file mode 100644 index 000000000..8b5f01412 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/configmap.yaml @@ -0,0 +1,14 @@ +{{- if and (or .Values.hubble.enabled .Values.hubble.ui.standalone.enabled) .Values.hubble.ui.enabled }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: hubble-ui-nginx + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.ui.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +data: + nginx.conf: {{ include "hubble-ui.nginx.conf" . | trim | quote }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/deployment.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/deployment.yaml new file mode 100644 index 000000000..51c1e4721 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/deployment.yaml @@ -0,0 +1,216 @@ +{{- if and (or .Values.hubble.enabled .Values.hubble.ui.standalone.enabled) .Values.hubble.ui.enabled }} +kind: Deployment +apiVersion: apps/v1 +metadata: + name: hubble-ui + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.ui.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + k8s-app: hubble-ui + app.kubernetes.io/name: hubble-ui + app.kubernetes.io/part-of: cilium +spec: + replicas: {{ .Values.hubble.ui.replicas }} + selector: + matchLabels: + k8s-app: hubble-ui + {{- with .Values.hubble.ui.updateStrategy }} + strategy: + {{- toYaml . | trim | nindent 4 }} + {{- end }} + template: + metadata: + annotations: + {{- if .Values.hubble.ui.rollOutPods }} + # ensure pods roll when configmap updates + cilium.io/hubble-ui-nginx-configmap-checksum: {{ include (print $.Template.BasePath "/hubble-ui/configmap.yaml") . | sha256sum | quote }} + {{- end }} + {{- with .Values.hubble.ui.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + k8s-app: hubble-ui + app.kubernetes.io/name: hubble-ui + app.kubernetes.io/part-of: cilium + {{- with .Values.hubble.ui.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.hubble.ui.securityContext }} + {{- if .enabled }} + securityContext: + {{- omit . "enabled" | toYaml | nindent 8 }} + {{- end}} + {{- end }} + priorityClassName: {{ .Values.hubble.ui.priorityClassName }} + serviceAccount: {{ .Values.serviceAccounts.ui.name | quote }} + serviceAccountName: {{ .Values.serviceAccounts.ui.name | quote }} + automountServiceAccountToken: {{ .Values.serviceAccounts.ui.automount }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: frontend + image: "{{ .Values.hubble.ui.frontend.image.repository }}:{{ .Values.hubble.ui.frontend.image.tag }}" + imagePullPolicy: {{ .Values.hubble.ui.frontend.image.pullPolicy }} + ports: + - name: http + containerPort: 8081 + {{- with .Values.hubble.ui.frontend.extraEnv }} + env: + {{- toYaml . | trim | nindent 12 }} + {{- end }} + livenessProbe: + httpGet: + path: /healthz + port: 8081 + readinessProbe: + httpGet: + path: / + port: 8081 + {{- with .Values.hubble.ui.frontend.resources }} + resources: + {{- toYaml . | trim | nindent 10 }} + {{- end }} + volumeMounts: + - name: hubble-ui-nginx-conf + mountPath: /etc/nginx/conf.d/default.conf + subPath: nginx.conf + - name: tmp-dir + mountPath: /tmp + {{- with .Values.hubble.ui.frontend.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + terminationMessagePolicy: FallbackToLogsOnError + {{- with .Values.hubble.ui.frontend.securityContext }} + securityContext: + {{- toYaml . | trim | nindent 10 }} + {{- end }} + - name: backend + image: "{{ .Values.hubble.ui.backend.image.repository }}:{{ .Values.hubble.ui.backend.image.tag}}" + imagePullPolicy: {{ .Values.hubble.ui.backend.image.pullPolicy }} + env: + - name: EVENTS_SERVER_PORT + value: "8090" + {{- if .Values.hubble.relay.tls.server.enabled }} + - name: FLOWS_API_ADDR + value: "hubble-relay:443" + - name: TLS_TO_RELAY_ENABLED + value: "true" + - name: TLS_RELAY_SERVER_NAME + value: {{ .Values.hubble.relay.tls.server.relayName }} + - name: TLS_RELAY_CA_CERT_FILES + value: /var/lib/hubble-ui/certs/hubble-relay-ca.crt + - name: TLS_RELAY_CLIENT_CERT_FILE + value: /var/lib/hubble-ui/certs/client.crt + - name: TLS_RELAY_CLIENT_KEY_FILE + value: /var/lib/hubble-ui/certs/client.key + {{- else }} + - name: FLOWS_API_ADDR + value: "hubble-relay:80" + {{- end }} + {{- with .Values.hubble.ui.backend.extraEnv }} + {{- toYaml . | trim | nindent 8 }} + {{- end }} + {{- if .Values.hubble.ui.backend.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /healthz + port: 8090 + {{- end }} + {{- if .Values.hubble.ui.backend.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: /healthz + port: 8090 + {{- end }} + ports: + - name: grpc + containerPort: 8090 + {{- with .Values.hubble.ui.backend.resources }} + resources: + {{- toYaml . | trim | nindent 10 }} + {{- end }} + volumeMounts: + {{- if .Values.hubble.relay.tls.server.enabled }} + - name: hubble-ui-client-certs + mountPath: /var/lib/hubble-ui/certs + readOnly: true + {{- end }} + {{- with .Values.hubble.ui.backend.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + terminationMessagePolicy: FallbackToLogsOnError + {{- with .Values.hubble.ui.backend.securityContext }} + securityContext: + {{- toYaml . | trim | nindent 10 }} + {{- end }} + {{- with .Values.hubble.ui.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.hubble.ui.topologySpreadConstraints }} + topologySpreadConstraints: + {{- range $constraint := . }} + - {{ toYaml $constraint | nindent 8 | trim }} + {{- if not $constraint.labelSelector }} + labelSelector: + matchLabels: + k8s-app: hubble-ui + {{- end }} + {{- end }} + {{- end }} + {{- with .Values.hubble.ui.nodeSelector }} + nodeSelector: + {{- toYaml . | trim | nindent 8 }} + {{- end }} + {{- with .Values.hubble.ui.tolerations }} + tolerations: + {{- toYaml . | trim | nindent 8 }} + {{- end }} + volumes: + - configMap: + defaultMode: 420 + name: hubble-ui-nginx + name: hubble-ui-nginx-conf + - emptyDir: {} + name: tmp-dir + {{- if .Values.hubble.relay.tls.server.enabled }} + - name: hubble-ui-client-certs + {{- if .Values.hubble.ui.standalone.enabled }} + {{- toYaml .Values.hubble.ui.standalone.tls.certsVolume | nindent 8 }} + {{- else }} + projected: + # note: the leading zero means this number is in octal representation: do not remove it + defaultMode: 0400 + sources: + - secret: + name: hubble-relay-client-certs + items: + - key: tls.crt + path: client.crt + - key: tls.key + path: client.key + {{- if not .Values.tls.caBundle.enabled }} + - key: ca.crt + path: hubble-relay-ca.crt + {{- else }} + - {{ .Values.tls.caBundle.useSecret | ternary "secret" "configMap" }}: + name: {{ .Values.tls.caBundle.name }} + items: + - key: {{ .Values.tls.caBundle.key }} + path: hubble-relay-ca.crt + {{- end }} + {{- end }} + {{- end }} + {{- with .Values.hubble.ui.frontend.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.hubble.ui.backend.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/ingress.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/ingress.yaml new file mode 100644 index 000000000..2c0ff7d3e --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/ingress.yaml @@ -0,0 +1,40 @@ +{{- if and (or .Values.hubble.enabled .Values.hubble.ui.standalone.enabled) .Values.hubble.ui.enabled .Values.hubble.ui.ingress.enabled }} +{{- $baseUrl := .Values.hubble.ui.baseUrl -}} +apiVersion: {{ template "ingress.apiVersion" . }} +kind: Ingress +metadata: + name: hubble-ui + namespace: {{ .Release.Namespace }} + labels: + k8s-app: hubble-ui + app.kubernetes.io/name: hubble-ui + app.kubernetes.io/part-of: cilium + {{- with .Values.hubble.ui.ingress.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if or .Values.hubble.ui.ingress.annotations .Values.hubble.ui.annotations }} + annotations: + {{- with .Values.hubble.ui.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.hubble.ui.ingress.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +spec: + {{- if .Values.hubble.ui.ingress.className }} + ingressClassName: {{ .Values.hubble.ui.ingress.className }} + {{- end }} + {{- if .Values.hubble.ui.ingress.tls }} + tls: + {{- toYaml .Values.hubble.ui.ingress.tls | nindent 4 }} + {{- end }} + rules: + {{- range .Values.hubble.ui.ingress.hosts }} + - host: {{ . }} + http: + paths: + - path: {{ $baseUrl | quote }} + {{- include "ingress.paths" $ | nindent 12 }} + {{- end }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/poddisruptionbudget.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/poddisruptionbudget.yaml new file mode 100644 index 000000000..af3b6705d --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/poddisruptionbudget.yaml @@ -0,0 +1,26 @@ +{{- if and (or .Values.hubble.enabled .Values.hubble.ui.standalone.enabled) .Values.hubble.ui.enabled .Values.hubble.ui.podDisruptionBudget.enabled }} +{{- $component := .Values.hubble.ui.podDisruptionBudget }} +apiVersion: {{ include "podDisruptionBudget.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: hubble-ui + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.ui.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + k8s-app: hubble-ui + app.kubernetes.io/name: hubble-ui + app.kubernetes.io/part-of: cilium +spec: + {{- with $component.maxUnavailable }} + maxUnavailable: {{ . }} + {{- end }} + {{- with $component.minAvailable }} + minAvailable: {{ . }} + {{- end }} + selector: + matchLabels: + k8s-app: hubble-ui +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/service.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/service.yaml new file mode 100644 index 000000000..a820b3420 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/service.yaml @@ -0,0 +1,31 @@ +{{- if and (or .Values.hubble.enabled .Values.hubble.ui.standalone.enabled) .Values.hubble.ui.enabled }} +kind: Service +apiVersion: v1 +metadata: + name: hubble-ui + namespace: {{ .Release.Namespace }} + {{- if or .Values.hubble.ui.service.annotations .Values.hubble.ui.annotations }} + annotations: + {{- with .Values.hubble.ui.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.hubble.ui.service.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} + labels: + k8s-app: hubble-ui + app.kubernetes.io/name: hubble-ui + app.kubernetes.io/part-of: cilium +spec: + type: {{ .Values.hubble.ui.service.type | quote }} + selector: + k8s-app: hubble-ui + ports: + - name: http + port: 80 + targetPort: 8081 + {{- if and (eq "NodePort" .Values.hubble.ui.service.type) .Values.hubble.ui.service.nodePort }} + nodePort: {{ .Values.hubble.ui.service.nodePort }} + {{- end }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/serviceaccount.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/serviceaccount.yaml new file mode 100644 index 000000000..dc02ea2bf --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble-ui/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if and (or .Values.hubble.enabled .Values.hubble.ui.standalone.enabled) .Values.hubble.ui.enabled .Values.serviceAccounts.ui.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.serviceAccounts.ui.name | quote }} + namespace: {{ .Release.Namespace }} + {{- if or .Values.serviceAccounts.ui.annotations .Values.hubble.ui.annotations }} + annotations: + {{- with .Values.hubble.ui.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.serviceAccounts.ui.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/dashboards-configmap.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/dashboards-configmap.yaml new file mode 100644 index 000000000..c668ebfd3 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/dashboards-configmap.yaml @@ -0,0 +1,30 @@ +{{- if .Values.hubble.metrics.dashboards.enabled }} +{{- $files := .Files.Glob "files/hubble/dashboards/*.json" }} +{{- range $path, $fileContents := $files }} +{{- $dashboardName := regexReplaceAll "(^.*/)(.*)\\.json$" $path "${2}" }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ $dashboardName | trunc 63 | trimSuffix "-" }} + namespace: {{ $.Values.hubble.metrics.dashboards.namespace | default $.Release.Namespace }} + labels: + k8s-app: hubble + app.kubernetes.io/name: hubble + app.kubernetes.io/part-of: cilium + {{- if $.Values.hubble.metrics.dashboards.label }} + {{ $.Values.hubble.metrics.dashboards.label }}: {{ ternary $.Values.hubble.metrics.dashboards.labelValue "1" (not (empty $.Values.hubble.metrics.dashboards.labelValue)) | quote }} + {{- end }} + {{- if or $.Values.hubble.metrics.dashboards.annotations $.Values.hubble.annotations }} + annotations: + {{- with $.Values.hubble.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $.Values.hubble.metrics.dashboards.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +data: + {{ $dashboardName }}.json: {{ $.Files.Get $path | toJson }} +{{- end }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/metrics-service.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/metrics-service.yaml new file mode 100644 index 000000000..a2886c676 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/metrics-service.yaml @@ -0,0 +1,36 @@ +{{- if and .Values.hubble.enabled .Values.hubble.metrics.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: network-observability + namespace: {{ .Release.Namespace }} + labels: + k8s-app: networkobservability + app.kubernetes.io/name: networkobservability + app.kubernetes.io/part-of: retina + annotations: + {{- with .Values.hubble.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.hubble.metrics.serviceAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if not .Values.hubble.metrics.serviceMonitor.enabled }} + prometheus.io/scrape: "true" + prometheus.io/port: {{ .Values.hubble.metrics.port | quote }} + {{- end }} +spec: + clusterIP: None + type: ClusterIP + ports: + - name: hubble + port: {{ .Values.hubble.metrics.port }} + protocol: TCP + targetPort: {{ .Values.hubble.metrics.port }} + - name: retina + port: {{ .Values.retinaPort }} + protocol: TCP + targetPort: {{ .Values.retinaPort }} + selector: + k8s-app: retina +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/peer-service.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/peer-service.yaml new file mode 100644 index 000000000..06f765b31 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/peer-service.yaml @@ -0,0 +1,30 @@ +{{- if and .Values.agent .Values.hubble.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: hubble-peer + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + k8s-app: retina + app.kubernetes.io/part-of: retina + app.kubernetes.io/name: hubble-peer +spec: + selector: + k8s-app: retina + ports: + - name: peer-service + {{- if .Values.hubble.peerService.servicePort }} + port: {{ .Values.hubble.peerService.servicePort }} + {{- else }} + port: {{ .Values.hubble.tls.enabled | ternary 443 80 }} + {{- end }} + protocol: TCP + targetPort: {{ .Values.hubble.peerService.targetPort }} +{{- if semverCompare ">=1.22-0" .Capabilities.KubeVersion.GitVersion }} + internalTrafficPolicy: Local +{{- end }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/servicemonitor.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/servicemonitor.yaml new file mode 100644 index 000000000..3b3ba8ba2 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/servicemonitor.yaml @@ -0,0 +1,44 @@ +{{- if and .Values.hubble.enabled .Values.hubble.metrics.enabled .Values.hubble.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: hubble + namespace: {{ .Values.prometheus.serviceMonitor.namespace | default .Release.Namespace }} + labels: + app.kubernetes.io/part-of: cilium + {{- with .Values.hubble.metrics.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if or .Values.hubble.metrics.serviceMonitor.annotations .Values.hubble.annotations }} + annotations: + {{- with .Values.hubble.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.hubble.metrics.serviceMonitor.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +spec: + selector: + matchLabels: + k8s-app: hubble + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + endpoints: + - port: hubble-metrics + interval: {{ .Values.hubble.metrics.serviceMonitor.interval | quote }} + honorLabels: true + path: /metrics + {{- with .Values.hubble.metrics.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.hubble.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- if .Values.hubble.metrics.serviceMonitor.jobLabel }} + jobLabel: {{ .Values.hubble.metrics.serviceMonitor.jobLabel | quote }} +{{- end }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-certmanager/relay-client-secret.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-certmanager/relay-client-secret.yaml new file mode 100644 index 000000000..1dd96b18c --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-certmanager/relay-client-secret.yaml @@ -0,0 +1,22 @@ +{{- if and .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "certmanager") .Values.hubble.relay.enabled }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: hubble-relay-client-certs + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + issuerRef: + {{- toYaml .Values.hubble.tls.auto.certManagerIssuerRef | nindent 4 }} + secretName: hubble-relay-client-certs + commonName: "*.hubble-relay.cilium.io" + dnsNames: + - "*.hubble-relay.cilium.io" + duration: {{ printf "%dh0m0s" (mul .Values.hubble.tls.auto.certValidityDuration 24) }} + privateKey: + rotationPolicy: Always +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-certmanager/relay-server-secret.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-certmanager/relay-server-secret.yaml new file mode 100644 index 000000000..845b4fb8e --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-certmanager/relay-server-secret.yaml @@ -0,0 +1,31 @@ +{{- if and .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "certmanager") .Values.hubble.relay.enabled .Values.hubble.relay.tls.server.enabled }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: hubble-relay-server-certs + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + issuerRef: + {{- toYaml .Values.hubble.tls.auto.certManagerIssuerRef | nindent 4 }} + secretName: hubble-relay-server-certs + commonName: "*.hubble-relay.cilium.io" + dnsNames: + - "*.hubble-relay.cilium.io" + {{- range $dns := .Values.hubble.relay.tls.server.extraDnsNames }} + - {{ $dns | quote }} + {{- end }} + {{- if .Values.hubble.relay.tls.server.extraIpAddresses }} + ipAddresses: + {{- range $ip := .Values.hubble.relay.tls.server.extraIpAddresses }} + - {{ $ip | quote }} + {{- end }} + {{- end }} + duration: {{ printf "%dh0m0s" (mul .Values.hubble.tls.auto.certValidityDuration 24) }} + privateKey: + rotationPolicy: Always +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-certmanager/server-secret.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-certmanager/server-secret.yaml new file mode 100644 index 000000000..5f202e10b --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-certmanager/server-secret.yaml @@ -0,0 +1,32 @@ +{{- if and .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "certmanager") }} +{{- $cn := list "*" (.Values.cluster.name | replace "." "-") "hubble-grpc.cilium.io" | join "." }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: hubble-server-certs + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + issuerRef: + {{- toYaml .Values.hubble.tls.auto.certManagerIssuerRef | nindent 4 }} + secretName: hubble-server-certs + commonName: {{ $cn | quote }} + dnsNames: + - {{ $cn | quote }} + {{- range $dns := .Values.hubble.tls.server.extraDnsNames }} + - {{ $dns | quote }} + {{- end }} + {{- if .Values.hubble.tls.server.extraIpAddresses }} + ipAddresses: + {{- range $ip := .Values.hubble.tls.server.extraIpAddresses }} + - {{ $ip | quote }} + {{- end }} + {{- end }} + duration: {{ printf "%dh0m0s" (mul .Values.hubble.tls.auto.certValidityDuration 24) }} + privateKey: + rotationPolicy: Always +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-certmanager/ui-client-certs.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-certmanager/ui-client-certs.yaml new file mode 100644 index 000000000..5006666ec --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-certmanager/ui-client-certs.yaml @@ -0,0 +1,22 @@ +{{- if and .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "certmanager") .Values.hubble.ui.enabled .Values.hubble.relay.enabled .Values.hubble.relay.tls.server.enabled }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: hubble-ui-client-certs + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + issuerRef: + {{- toYaml .Values.hubble.tls.auto.certManagerIssuerRef | nindent 4 }} + secretName: hubble-ui-client-certs + commonName: "*.hubble-ui.cilium.io" + dnsNames: + - "*.hubble-ui.cilium.io" + duration: {{ printf "%dh0m0s" (mul .Values.hubble.tls.auto.certValidityDuration 24) }} + privateKey: + rotationPolicy: Always +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/_job-spec.tpl b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/_job-spec.tpl new file mode 100644 index 000000000..67ef0e648 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/_job-spec.tpl @@ -0,0 +1,71 @@ +{{- define "hubble-generate-certs.job.spec" }} +{{- $certValiditySecondsStr := printf "%ds" (mul .Values.hubble.tls.auto.certValidityDuration 24 60 60) -}} +{{- $cluster := .Values.cluster | required "missing cluster value" -}} +{{- $clusterName := $cluster.name | required "missing cluster.name value" -}} + +spec: + template: + metadata: + labels: + k8s-app: hubble-generate-certs + {{- with .Values.certgen.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + containers: + - name: certgen + image: {{ include "cilium.image" .Values.certgen.image | quote }} + imagePullPolicy: {{ .Values.certgen.image.pullPolicy }} + command: + - "/usr/bin/cilium-certgen" + # Because this is executed as a job, we pass the values as command + # line args instead of via config map. This allows users to inspect + # the values used in past runs by inspecting the completed pod. + args: + - "--cilium-namespace={{ .Release.Namespace }}" + {{- if .Values.debug.enabled }} + - "--debug" + {{- end }} + - "--ca-generate" + - "--ca-reuse-secret" + {{- if and .Values.tls.ca.cert .Values.tls.ca.key }} + - "--ca-secret-name=cilium-ca" + {{- end }} + - "--hubble-server-cert-generate" + - "--hubble-server-cert-common-name={{ list "*" ($clusterName | replace "." "-") "hubble-grpc.cilium.io" | join "." }}" + - "--hubble-server-cert-validity-duration={{ $certValiditySecondsStr }}" + {{- if .Values.hubble.relay.enabled }} + - "--hubble-relay-client-cert-generate" + - "--hubble-relay-client-cert-validity-duration={{ $certValiditySecondsStr }}" + {{- end }} + {{- if and .Values.hubble.relay.enabled .Values.hubble.relay.tls.server.enabled }} + - "--hubble-relay-server-cert-generate" + - "--hubble-relay-server-cert-validity-duration={{ $certValiditySecondsStr }}" + {{- end }} + {{- with .Values.certgen.extraVolumeMounts }} + volumeMounts: + {{- toYaml . | nindent 10 }} + {{- end }} + hostNetwork: true + {{- with .Values.certgen.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccount: {{ .Values.serviceAccounts.hubblecertgen.name | quote }} + serviceAccountName: {{ .Values.serviceAccounts.hubblecertgen.name | quote }} + automountServiceAccountToken: {{ .Values.serviceAccounts.hubblecertgen.automount }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: OnFailure + {{- with .Values.certgen.extraVolumes }} + volumes: + {{- toYaml . | nindent 6 }} + {{- end }} + affinity: + {{- with .Values.certgen.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + ttlSecondsAfterFinished: {{ .Values.certgen.ttlSecondsAfterFinished }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/clusterrole.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/clusterrole.yaml new file mode 100644 index 000000000..74d078317 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/clusterrole.yaml @@ -0,0 +1,38 @@ +{{- if and .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "cronJob") .Values.serviceAccounts.hubblecertgen.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: hubble-generate-certs + {{- with .Values.hubble.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app.kubernetes.io/part-of: cilium +rules: + - apiGroups: + - "" + resources: + - secrets + verbs: + - create + - apiGroups: + - "" + resources: + - secrets + resourceNames: + - hubble-server-certs + - hubble-relay-client-certs + - hubble-relay-server-certs + verbs: + - update + - apiGroups: + - "" + resources: + - secrets + resourceNames: + - cilium-ca + verbs: + - get + - update +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/clusterrolebinding.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/clusterrolebinding.yaml new file mode 100644 index 000000000..5938f16cc --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/clusterrolebinding.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "cronJob") .Values.serviceAccounts.hubblecertgen.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: hubble-generate-certs + {{- with .Values.hubble.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app.kubernetes.io/part-of: cilium +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: hubble-generate-certs +subjects: +- kind: ServiceAccount + name: {{ .Values.serviceAccounts.hubblecertgen.name | quote }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/cronjob.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/cronjob.yaml new file mode 100644 index 000000000..fa9966080 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/cronjob.yaml @@ -0,0 +1,25 @@ +{{- if and .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "cronJob") .Values.hubble.tls.auto.schedule }} +apiVersion: {{ include "cronjob.apiVersion" . }} +kind: CronJob +metadata: + name: hubble-generate-certs + namespace: {{ .Release.Namespace }} + labels: + k8s-app: hubble-generate-certs + app.kubernetes.io/name: hubble-generate-certs + app.kubernetes.io/part-of: cilium + {{- if or .Values.certgen.annotations.cronJob .Values.hubble.annotations }} + annotations: + {{- with .Values.hubble.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.certgen.annotations.cronJob }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +spec: + schedule: {{ .Values.hubble.tls.auto.schedule | quote }} + concurrencyPolicy: Forbid + jobTemplate: + {{- include "hubble-generate-certs.job.spec" . | nindent 4 }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/job.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/job.yaml new file mode 100644 index 000000000..69fa8331e --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/job.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "cronJob") }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: hubble-generate-certs + namespace: {{ .Release.Namespace }} + labels: + k8s-app: hubble-generate-certs + app.kubernetes.io/name: hubble-generate-certs + app.kubernetes.io/part-of: cilium + annotations: + {{- with .Values.certgen.annotations.job }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.hubble.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{ include "hubble-generate-certs.job.spec" . }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/serviceaccount.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/serviceaccount.yaml new file mode 100644 index 000000000..62a8de804 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-cronjob/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "cronJob") .Values.serviceAccounts.hubblecertgen.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.serviceAccounts.hubblecertgen.name | quote }} + namespace: {{ .Release.Namespace }} + {{- if or .Values.serviceAccounts.hubblecertgen.annotations .Values.hubble.annotations }} + annotations: + {{- with .Values.hubble.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.serviceAccounts.hubblecertgen.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-helm/_helpers.tpl b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-helm/_helpers.tpl new file mode 100644 index 000000000..79babf94f --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-helm/_helpers.tpl @@ -0,0 +1,31 @@ +{{/* +Generate TLS certificates for Hubble Server and Hubble Relay. + +Note: Always use this template as follows: + + {{- $_ := include "hubble-generate-certs.helm.setup-ca" . -}} + +The assignment to `$_` is required because we store the generated CI in a global `ca` variable. +Please, don't try to "simplify" this, as without this trick, every generated +certificate would be signed by a different CA. +*/}} +{{- define "hubble-generate-certs.helm.setup-ca" }} + {{- if not .ca }} + {{- $ca := "" -}} + {{- $crt := .Values.tls.ca.cert -}} + {{- $key := .Values.tls.ca.key -}} + {{- if and $crt $key }} + {{- $ca = buildCustomCert $crt $key -}} + {{- else }} + {{- $_ := include "cilium.ca.setup" . -}} + {{- with lookup "v1" "Secret" .Release.Namespace .commonCASecretName }} + {{- $crt := index .data "ca.crt" }} + {{- $key := index .data "ca.key" }} + {{- $ca = buildCustomCert $crt $key -}} + {{- else }} + {{- $ca = .commonCA -}} + {{- end }} + {{- end }} + {{- $_ := set . "ca" $ca -}} + {{- end }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-helm/relay-client-secret.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-helm/relay-client-secret.yaml new file mode 100644 index 000000000..e1d6e8763 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-helm/relay-client-secret.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "helm") .Values.hubble.relay.enabled }} +{{- $_ := include "hubble-generate-certs.helm.setup-ca" . -}} +{{- $cn := "*.hubble-relay.cilium.io" }} +{{- $dns := list $cn }} +{{- $cert := genSignedCert $cn nil $dns (.Values.hubble.tls.auto.certValidityDuration | int) .ca -}} +--- +apiVersion: v1 +kind: Secret +metadata: + name: hubble-relay-client-certs + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +type: kubernetes.io/tls +data: + ca.crt: {{ .ca.Cert | b64enc }} + tls.crt: {{ $cert.Cert | b64enc }} + tls.key: {{ $cert.Key | b64enc }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-helm/relay-server-secret.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-helm/relay-server-secret.yaml new file mode 100644 index 000000000..902c2be4f --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-helm/relay-server-secret.yaml @@ -0,0 +1,22 @@ +{{- if and .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "helm") .Values.hubble.relay.enabled .Values.hubble.relay.tls.server.enabled }} +{{- $_ := include "hubble-generate-certs.helm.setup-ca" . -}} +{{- $cn := "*.hubble-relay.cilium.io" }} +{{- $ip := .Values.hubble.relay.tls.server.extraIpAddresses }} +{{- $dns := prepend .Values.hubble.relay.tls.server.extraDnsNames $cn }} +{{- $cert := genSignedCert $cn $ip $dns (.Values.hubble.tls.auto.certValidityDuration | int) .ca -}} +--- +apiVersion: v1 +kind: Secret +metadata: + name: hubble-relay-server-certs + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +type: kubernetes.io/tls +data: + ca.crt: {{ .ca.Cert | b64enc }} + tls.crt: {{ $cert.Cert | b64enc }} + tls.key: {{ $cert.Key | b64enc }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-helm/server-secret.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-helm/server-secret.yaml new file mode 100644 index 000000000..a05c32667 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-helm/server-secret.yaml @@ -0,0 +1,22 @@ +{{- if and .Values.agent .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "helm") }} +{{- $_ := include "hubble-generate-certs.helm.setup-ca" . -}} +{{- $cn := list "*" (.Values.cluster.name | replace "." "-") "hubble-grpc.cilium.io" | join "." }} +{{- $ip := .Values.hubble.tls.server.extraIpAddresses }} +{{- $dns := prepend .Values.hubble.tls.server.extraDnsNames $cn }} +{{- $cert := genSignedCert $cn $ip $dns (.Values.hubble.tls.auto.certValidityDuration | int) .ca -}} +--- +apiVersion: v1 +kind: Secret +metadata: + name: hubble-server-certs + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +type: kubernetes.io/tls +data: + ca.crt: {{ .ca.Cert | b64enc }} + tls.crt: {{ $cert.Cert | b64enc }} + tls.key: {{ $cert.Key | b64enc }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-helm/ui-client-certs.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-helm/ui-client-certs.yaml new file mode 100644 index 000000000..7b385b26b --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-helm/ui-client-certs.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "helm") .Values.hubble.ui.enabled .Values.hubble.relay.enabled .Values.hubble.relay.tls.server.enabled }} +{{- $_ := include "hubble-generate-certs.helm.setup-ca" . -}} +{{- $cn := "*.hubble-ui.cilium.io" }} +{{- $dns := list $cn }} +{{- $cert := genSignedCert $cn nil $dns (.Values.hubble.tls.auto.certValidityDuration | int) .ca -}} +--- +apiVersion: v1 +kind: Secret +metadata: + name: hubble-ui-client-certs + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +type: kubernetes.io/tls +data: + ca.crt: {{ .ca.Cert | b64enc }} + tls.crt: {{ $cert.Cert | b64enc }} + tls.key: {{ $cert.Key | b64enc }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-provided/relay-client-secret.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-provided/relay-client-secret.yaml new file mode 100644 index 000000000..b1512ed27 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-provided/relay-client-secret.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.hubble.enabled .Values.hubble.tls.enabled (not .Values.hubble.tls.auto.enabled) .Values.hubble.relay.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: hubble-relay-client-certs + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +type: kubernetes.io/tls +data: + ca.crt: {{ .Values.tls.ca.cert }} + tls.crt: {{ .Values.hubble.relay.tls.client.cert | required "missing hubble.relay.tls.client.cert" }} + tls.key: {{ .Values.hubble.relay.tls.client.key | required "missing hubble.relay.tls.client.key" }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-provided/relay-server-secret.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-provided/relay-server-secret.yaml new file mode 100644 index 000000000..07059143c --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-provided/relay-server-secret.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.hubble.enabled .Values.hubble.tls.enabled (not .Values.hubble.tls.auto.enabled) .Values.hubble.relay.enabled .Values.hubble.relay.tls.server.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: hubble-relay-server-certs + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +type: kubernetes.io/tls +data: + ca.crt: {{ .Values.tls.ca.cert }} + tls.crt: {{ .Values.hubble.relay.tls.server.cert | required "missing hubble.relay.tls.server.cert" }} + tls.key: {{ .Values.hubble.relay.tls.server.key | required "missing hubble.relay.tls.server.key" }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-provided/server-secret.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-provided/server-secret.yaml new file mode 100644 index 000000000..f659a1fb0 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-provided/server-secret.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.agent .Values.hubble.enabled .Values.hubble.tls.enabled (not .Values.hubble.tls.auto.enabled) }} +apiVersion: v1 +kind: Secret +metadata: + name: hubble-server-certs + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +type: kubernetes.io/tls +data: + ca.crt: {{ .Values.tls.ca.cert }} + tls.crt: {{ .Values.hubble.tls.server.cert | required "missing hubble.tls.server.cert" }} + tls.key: {{ .Values.hubble.tls.server.key | required "missing hubble.tls.server.key" }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-provided/ui-client-certs.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-provided/ui-client-certs.yaml new file mode 100644 index 000000000..ca7683a4a --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/hubble/tls-provided/ui-client-certs.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.hubble.enabled .Values.hubble.tls.enabled (not .Values.hubble.tls.auto.enabled) .Values.hubble.ui.enabled .Values.hubble.relay.enabled .Values.hubble.relay.tls.server.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: hubble-ui-client-certs + namespace: {{ .Release.Namespace }} + {{- with .Values.hubble.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +type: kubernetes.io/tls +data: + ca.crt: {{ .Values.tls.ca.cert }} + tls.crt: {{ .Values.hubble.ui.tls.client.cert | required "missing hubble.ui.tls.client.cert" }} + tls.key: {{ .Values.hubble.ui.tls.client.key | required "missing hubble.ui.tls.client.key" }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/operator/clusterrole.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/operator/clusterrole.yaml new file mode 100644 index 000000000..e143cd4d0 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/operator/clusterrole.yaml @@ -0,0 +1,110 @@ +{{- if .Values.operator.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: retina-operator-role +rules: + - apiGroups: + - "apiextensions.k8s.io" + resources: + - "customresourcedefinitions" + verbs: + - "create" + - "get" + - "update" + - "delete" + - "patch" + - apiGroups: + - "" + resources: + - pods + - namespaces + verbs: + - get + - list + - watch + - apiGroups: + - batch + resources: + - jobs + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch + - apiGroups: + - batch + resources: + - jobs/status + verbs: + - get + - apiGroups: + - retina.io + resources: + - captures + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - retina.io + resources: + - captures/finalizers + verbs: + - update + - apiGroups: + - retina.io + resources: + - captures/status + verbs: + - get + - patch + - update + - apiGroups: + - cilium.io + resources: + - ciliumidentities + - ciliumendpoints + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + # for endpointgc + # will not create ciliumnode objects + - apiGroups: + - cilium.io + resources: + - ciliumnodes + verbs: + - get + - list + - watch + # For cilium-operator running in HA mode. + # + # Cilium operator running in HA mode requires the use of ResourceLock for Leader Election + # between multiple running instances. + # The preferred way of doing this is to use LeasesResourceLock as edits to Leases are less + # common and fewer objects in the cluster watch "all Leases". + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - get + - update + +{{- end -}} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/operator/clusterrolebinding.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/operator/clusterrolebinding.yaml new file mode 100644 index 000000000..09580886c --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/operator/clusterrolebinding.yaml @@ -0,0 +1,22 @@ +{{- if .Values.operator.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: clusterrolebinding + app.kubernetes.io/instance: retina-operator-rolebinding + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + name: retina-operator-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: retina-operator-role +subjects: +- kind: ServiceAccount + name: retina-operator + namespace: kube-system + +{{- end -}} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/operator/configmap.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/operator/configmap.yaml new file mode 100644 index 000000000..208ce1d43 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/operator/configmap.yaml @@ -0,0 +1,14 @@ +{{- if .Values.operator.enabled -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: retina-operator-config + namespace: {{ .Values.namespace }} +data: + enable-telemetry: {{ .Values.enableTelemetry | quote }} + log-opt: "{\"level\":\"{{ .Values.logLevel }}\"}" + leader-election: {{ .Values.operator.leaderElection | quote }} + identity-gc-interval: {{ .Values.operator.identityGCInterval }} + cilium-endpoint-gc-interval: {{ .Values.operator.endpointGCInterval }} + +{{- end -}} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/operator/deployment.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/operator/deployment.yaml new file mode 100644 index 000000000..7aed8c528 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/operator/deployment.yaml @@ -0,0 +1,98 @@ +{{- if .Values.operator.enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: retina-operator + namespace: kube-system + labels: + app: retina-operator + control-plane: retina-operator + app.kubernetes.io/name: deployment + app.kubernetes.io/instance: retina-operator + app.kubernetes.io/component: retina-operator + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize +spec: + selector: + matchLabels: + control-plane: retina-operator + replicas: 1 + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: retina-operator + labels: + app: retina-operator + control-plane: retina-operator + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + - key: kubernetes.io/os + operator: In + values: + - linux + securityContext: + runAsNonRoot: true + runAsUser: 1000 + containers: + - command: + - /retina-operator + args: + - --config-dir=/retina + image: {{ .Values.operator.repository }}:{{ .Values.operator.tag }} + imagePullPolicy: {{ .Values.operator.pullPolicy }} + name: retina-operator + env: + # this env var is used by retina OSS telemetry and zap + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + volumeMounts: + - name: retina-operator-config + mountPath: /retina/ + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + # livenessProbe: + # httpGet: + # path: /healthz + # port: 8081 + # initialDelaySeconds: 15 + # periodSeconds: 20 + # readinessProbe: + # httpGet: + # path: /readyz + # port: 8081 + # initialDelaySeconds: 5 + # periodSeconds: 10 + resources: + limits: + cpu: 500m + memory: 500Mi + requests: + cpu: 10m + memory: 64Mi + serviceAccountName: retina-operator + terminationGracePeriodSeconds: 10 + volumes: + - name: retina-operator-config + configMap: + name: retina-operator-config + +{{- end -}} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/operator/serviceaccount.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/operator/serviceaccount.yaml new file mode 100644 index 000000000..5bc62e53b --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/operator/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.operator.enabled -}} + +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/name: serviceaccount + app.kubernetes.io/instance: retina-operator + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + name: retina-operator + namespace: kube-system + +{{- end -}} diff --git a/deploy/hubble/manifests/controller/helm/retina/templates/validate.yaml b/deploy/hubble/manifests/controller/helm/retina/templates/validate.yaml new file mode 100644 index 000000000..d47341504 --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/templates/validate.yaml @@ -0,0 +1,47 @@ +{{/* validate hubble config */}} +{{- if and .Values.hubble.ui.enabled (not .Values.hubble.ui.standalone.enabled) }} + {{- if not .Values.hubble.relay.enabled }} + {{ fail "Hubble UI requires .Values.hubble.relay.enabled=true" }} + {{- end }} +{{- end }} +{{- if and .Values.hubble.ui.enabled .Values.hubble.ui.standalone.enabled .Values.hubble.relay.tls.server.enabled }} + {{- if not .Values.hubble.ui.standalone.tls.certsVolume }} + {{ fail "Hubble UI in standalone with Hubble Relay server TLS enabled requires providing .Values.hubble.ui.standalone.tls.certsVolume for mounting client certificates in the backend pod" }} + {{- end }} +{{- end }} +{{- if .Values.hubble.relay.enabled }} + {{- if not .Values.hubble.enabled }} + {{ fail "Hubble Relay requires .Values.hubble.enabled=true" }} + {{- end }} +{{- end }} + +{{- if and .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "certmanager") }} + {{- if not .Values.hubble.tls.auto.certManagerIssuerRef }} + {{ fail "Hubble TLS certgen method=certmanager requires that user specifies .Values.hubble.tls.auto.certManagerIssuerRef" }} + {{- end }} +{{- end }} + +{{- if and .Values.hubble.redact.http.headers.allow .Values.hubble.redact.http.headers.deny }} + {{ fail "Only one of .Values.hubble.redact.http.headers.allow, .Values.hubble.redact.http.headers.deny can be specified"}} +{{- end }} + +{{/* validate hubble-ui specific config */}} +{{- if and .Values.hubble.ui.enabled + (ne .Values.hubble.ui.backend.image.tag "latest") + (ne .Values.hubble.ui.frontend.image.tag "latest") }} + {{- if regexReplaceAll "@.*$" .Values.hubble.ui.backend.image.tag "" | trimPrefix "v" | semverCompare "<0.9.0" }} + {{ fail "Hubble UI requires hubble.ui.backend.image.tag to be '>=v0.9.0'" }} + {{- end }} + {{- if regexReplaceAll "@.*$" .Values.hubble.ui.frontend.image.tag "" | trimPrefix "v" | semverCompare "<0.9.0" }} + {{ fail "Hubble UI requires hubble.ui.frontend.image.tag to be '>=v0.9.0'" }} + {{- end }} +{{- end }} + +{{- if .Values.externalWorkloads.enabled }} + {{- if ne .Values.identityAllocationMode "crd" }} + {{ fail (printf "External workloads support cannot be enabled in combination with .Values.identityAllocationMode=%s" .Values.identityAllocationMode ) }} + {{- end }} + {{- if .Values.disableEndpointCRD }} + {{ fail "External workloads support cannot be enabled in combination with .Values.disableEndpointCRD=true" }} + {{- end }} +{{- end }} diff --git a/deploy/hubble/manifests/controller/helm/retina/values.yaml b/deploy/hubble/manifests/controller/helm/retina/values.yaml new file mode 100644 index 000000000..75b91a54e --- /dev/null +++ b/deploy/hubble/manifests/controller/helm/retina/values.yaml @@ -0,0 +1,920 @@ +# Default values for retina. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +debug: + enabled: false + +cluster: + name: "default" + +# Support linux and windows by default. +os: + linux: true + windows: false + +# FIXME: remove unnecessary pieces, etc. +operator: + enabled: true + repository: acndev.azurecr.io/retina-operator + pullPolicy: Always + tag: "latest" + leaderElection: true + identityGCInterval: 15m # cilium default + endpointGCInterval: 5m # cilium default + +agent: + leaderElection: false + enabled: true + name: retina-agent + repository: acndev.azurecr.io/retina-agent + tag: "latest" + init: + enabled: true + name: retina-agent-init + repository: acndev.azurecr.io/retina-agent-init + tag: "latest" + pullPolicy: Always + container: + retina: + command: + - "/retina/controller" + args: + - "hubble-control-plane" + - "--config-dir" + - "/retina/config" + healthProbeBindAddress: ":18081" + metricsBindAddress: ":18080" + ports: + containerPort: 10093 + +enablePodLevel: true +remoteContext: false +enableAnnotations: false +bypassLookupIPOfInterest: true + +imagePullSecrets: [] +nameOverride: "retina" +fullnameOverride: "retina-svc" + +namespace: kube-system + +agent_win: + name: retina-agent-win + +retinaPort: 10093 + +apiServer: + host: "0.0.0.0" + port: 10093 + +# Supported - debug, info, error, warn, panic, fatal. +logLevel: info + +enabledPlugin_linux: '["linuxutil","packetforward","packetparser","dns", "dropreason"]' +enabledPlugin_win: '["hnsstats"]' + +enableTelemetry: true + +# Interval, in seconds, to scrape/publish metrics. +metricsInterval: 10 + +azure: + appinsights: + instrumentation_key: "app-insights-instrumentation-key" + +# volume mounts with name and mountPath +volumeMounts: + debug: /sys/kernel/debug + trace: /sys/kernel/tracing + bpf: /sys/fs/bpf + cgroup: /sys/fs/cgroup + tmp: /tmp + config: /retina/config + varrun: /var/run + +#volume mounts for indows +volumeMounts_win: + retina-config-win: retina + +securityContext: + privileged: false + capabilities: + add: + - SYS_ADMIN + - SYS_RESOURCE + - NET_ADMIN # for packetparser plugin + - IPC_LOCK # for mmap() calls made by NewReader(), ref: https://man7.org/linux/man-pages/man2/mmap.2.html + windowsOptions: + runAsUserName: "NT AUTHORITY\\SYSTEM" + +service: + type: ClusterIP + port: 10093 + targetPort: 10093 + name: retina + +serviceAccount: + annotations: {} + name: "retina-agent" + +resources: + limits: + memory: "500Mi" + cpu: "500m" + +# -- Define serviceAccount names for components. +# @default -- Component's fully qualified name. +serviceAccounts: + relay: + create: true + name: hubble-relay + automount: false + annotations: {} + ui: + create: true + name: hubble-ui + automount: true + annotations: {} + # -- Hubblecertgen is used if hubble.tls.auto.method=cronJob + hubblecertgen: + create: true + name: hubble-generate-certs + automount: true + annotations: {} + +# -- Configure external workloads support +externalWorkloads: + # -- Enable support for external workloads, such as VMs (false by default). + enabled: false + +####################### +# # +# Hubble Config # +# # +####################### +# https://github.com/cilium/cilium/blob/2afcb614a3eeef0df963fffc52006063f96bcac9/install/kubernetes/cilium/values.yaml#L993 + +hubble: + # -- Enable Hubble (true by default). + enabled: true + + # -- Annotations to be added to all top-level hubble objects (resources under templates/hubble) + annotations: {} + + # -- Buffer size of the channel Hubble uses to receive monitor events. If this + # value is not set, the queue size is set to the default monitor queue size. + eventQueueSize: "16383" + + # -- Number of recent flows for Hubble to cache. Defaults to 4095. + # Possible values are: + # 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, + # 2047, 4095, 8191, 16383, 32767, 65535 + # eventBufferCapacity: "4095" + + # -- Hubble metrics configuration. + # See https://docs.cilium.io/en/stable/observability/metrics/#hubble-metrics + # for more comprehensive documentation about Hubble metrics. + metrics: + # -- Configures the list of metrics to collect. If empty or null, metrics + # are disabled. + # Example: + # + # enabled: + # - dns:query;ignoreAAAA + # - drop + # - tcp + # - flow + # - icmp + # - http + # + # You can specify the list of metrics from the helm CLI: + # + # --set hubble.metrics.enabled="{dns:query;ignoreAAAA,drop,tcp,flow,icmp,http}" + # + enabled: + - flow:sourceEgressContext=pod;destinationIngressContext=pod + - tcp:sourceEgressContext=pod;destinationIngressContext=pod + - dns:query;sourceEgressContext=pod;destinationIngressContext=pod + - drop:sourceEgressContext=pod;destinationIngressContext=pod + # -- Enables exporting hubble metrics in OpenMetrics format. + enableOpenMetrics: false + # -- Configure the port the hubble metric server listens on. + port: 9965 + # -- Annotations to be added to hubble-metrics service. + serviceAnnotations: {} + serviceMonitor: + # -- Create ServiceMonitor resources for Prometheus Operator. + # This requires the prometheus CRDs to be available. + # ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml) + enabled: false + # -- Labels to add to ServiceMonitor hubble + labels: {} + # -- Annotations to add to ServiceMonitor hubble + annotations: {} + # -- jobLabel to add for ServiceMonitor hubble + jobLabel: "" + # -- Interval for scrape metrics. + interval: "10s" + # -- Relabeling configs for the ServiceMonitor hubble + relabelings: + - sourceLabels: + - __meta_kubernetes_pod_node_name + targetLabel: node + replacement: ${1} + # -- Metrics relabeling configs for the ServiceMonitor hubble + metricRelabelings: ~ + # -- Grafana dashboards for hubble + # grafana can import dashboards based on the label and value + # ref: https://github.com/grafana/helm-charts/tree/main/charts/grafana#sidecar-for-dashboards + dashboards: + enabled: false + label: grafana_dashboard + namespace: ~ + labelValue: "1" + annotations: {} + + # -- Unix domain socket path to listen to when Hubble is enabled. + socketPath: /var/run/cilium/hubble.sock + + # -- Enables redacting sensitive information present in Layer 7 flows. + redact: + enabled: false + http: + # -- Enables redacting URL query (GET) parameters. + # Example: + # + # redact: + # enabled: true + # http: + # urlQuery: true + # + # You can specify the options from the helm CLI: + # + # --set hubble.redact.enabled="true" + # --set hubble.redact.http.urlQuery="true" + urlQuery: false + # -- Enables redacting user info, e.g., password when basic auth is used. + # Example: + # + # redact: + # enabled: true + # http: + # userInfo: true + # + # You can specify the options from the helm CLI: + # + # --set hubble.redact.enabled="true" + # --set hubble.redact.http.userInfo="true" + userInfo: true + headers: + # -- List of HTTP headers to allow: headers not matching will be redacted. Note: `allow` and `deny` lists cannot be used both at the same time, only one can be present. + # Example: + # redact: + # enabled: true + # http: + # headers: + # allow: + # - traceparent + # - tracestate + # - Cache-Control + # + # You can specify the options from the helm CLI: + # --set hubble.redact.enabled="true" + # --set hubble.redact.http.headers.allow="traceparent,tracestate,Cache-Control" + allow: [] + # -- List of HTTP headers to deny: matching headers will be redacted. Note: `allow` and `deny` lists cannot be used both at the same time, only one can be present. + # Example: + # redact: + # enabled: true + # http: + # headers: + # deny: + # - Authorization + # - Proxy-Authorization + # + # You can specify the options from the helm CLI: + # --set hubble.redact.enabled="true" + # --set hubble.redact.http.headers.deny="Authorization,Proxy-Authorization" + deny: [] + kafka: + # -- Enables redacting Kafka's API key. + # Example: + # + # redact: + # enabled: true + # kafka: + # apiKey: true + # + # You can specify the options from the helm CLI: + # + # --set hubble.redact.enabled="true" + # --set hubble.redact.kafka.apiKey="true" + apiKey: false + + # -- An additional address for Hubble to listen to. + # Set this field ":4244" if you are enabling Hubble Relay, as it assumes that + # Hubble is listening on port 4244. + listenAddress: ":4244" + # -- Whether Hubble should prefer to announce IPv6 or IPv4 addresses if both are available. + preferIpv6: false + # -- (bool) Skip Hubble events with unknown cgroup ids + # @default -- `true` + skipUnknownCGroupIDs: ~ + + peerService: + # -- Service Port for the Peer service. + # If not set, it is dynamically assigned to port 443 if TLS is enabled and to + # port 80 if not. + servicePort: 80 + # -- Target Port for the Peer service, must match the hubble.listenAddress' + # port. + targetPort: 4244 + # -- The cluster domain to use to query the Hubble Peer service. It should + # be the local cluster. + clusterDomain: cluster.local + # -- TLS configuration for Hubble + tls: + # -- Enable mutual TLS for listenAddress. Setting this value to false is + # highly discouraged as the Hubble API provides access to potentially + # sensitive network flow metadata and is exposed on the host network. + enabled: true + # -- Configure automatic TLS certificates generation. + auto: + # -- Auto-generate certificates. + # When set to true, automatically generate a CA and certificates to + # enable mTLS between Hubble server and Hubble Relay instances. If set to + # false, the certs for Hubble server need to be provided by setting + # appropriate values below. + enabled: true + # -- Set the method to auto-generate certificates. Supported values: + # - helm: This method uses Helm to generate all certificates. + # - cronJob: This method uses a Kubernetes CronJob the generate any + # certificates not provided by the user at installation + # time. + # - certmanager: This method use cert-manager to generate & rotate certificates. + method: cronJob + # -- Generated certificates validity duration in days. + certValidityDuration: 120 + # -- Schedule for certificates regeneration (regardless of their expiration date). + # Only used if method is "cronJob". If nil, then no recurring job will be created. + # Instead, only the one-shot job is deployed to generate the certificates at + # installation time. + # + # Defaults to midnight of the first day of every fourth month. For syntax, see + # https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#schedule-syntax + schedule: "0 0 1 */4 *" + + # [Example] + # certManagerIssuerRef: + # group: cert-manager.io + # kind: ClusterIssuer + # name: ca-issuer + # -- certmanager issuer used when hubble.tls.auto.method=certmanager. + certManagerIssuerRef: {} + + # -- base64 encoded PEM values for the Hubble server certificate and private key + server: + cert: "" + key: "" + # -- Extra DNS names added to certificate when it's auto generated + extraDnsNames: [] + # -- Extra IP addresses added to certificate when it's auto generated + extraIpAddresses: [] + + relay: + # -- Enable Hubble Relay (requires hubble.enabled=true) + enabled: true + + # -- Roll out Hubble Relay pods automatically when configmap is updated. + rollOutPods: false + + # -- Hubble-relay container image. + image: + override: ~ + repository: "mcr.microsoft.com/oss/cilium/hubble-relay" + tag: "v1.15.0" + digest: "sha256:19cd56e7618832257bf88b2f281287cb57f9f7fcb9e04775a6198d4bc4daffae" + useDigest: false + pullPolicy: "Always" + + # -- Specifies the resources for the hubble-relay pods + resources: {} + + # -- Number of replicas run for the hubble-relay deployment. + replicas: 1 + + # -- Affinity for hubble-replay + affinity: + podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - topologyKey: kubernetes.io/hostname + labelSelector: + matchLabels: + k8s-app: retina + + # -- Pod topology spread constraints for hubble-relay + topologySpreadConstraints: + [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # whenUnsatisfiable: DoNotSchedule + + # -- Node labels for pod assignment + # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector + nodeSelector: + kubernetes.io/os: linux + + # -- Node tolerations for pod assignment on nodes with taints + # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ + tolerations: [] + + # -- Additional hubble-relay environment variables. + extraEnv: [] + + # -- Annotations to be added to all top-level hubble-relay objects (resources under templates/hubble-relay) + annotations: {} + + # -- Annotations to be added to hubble-relay pods + podAnnotations: {} + + # -- Labels to be added to hubble-relay pods + podLabels: {} + + # PodDisruptionBudget settings + podDisruptionBudget: + # -- enable PodDisruptionBudget + # ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ + enabled: false + # -- Minimum number/percentage of pods that should remain scheduled. + # When it's set, maxUnavailable must be disabled by `maxUnavailable: null` + minAvailable: null + # -- Maximum number/percentage of pods that may be made unavailable + maxUnavailable: 1 + + # -- The priority class to use for hubble-relay + priorityClassName: "" + + # -- Configure termination grace period for hubble relay Deployment. + terminationGracePeriodSeconds: 1 + + # -- hubble-relay update strategy + updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + + # -- Additional hubble-relay volumes. + extraVolumes: [] + + # -- Additional hubble-relay volumeMounts. + extraVolumeMounts: [] + + # -- hubble-relay pod security context + podSecurityContext: + fsGroup: 65532 + + # -- hubble-relay container security context + securityContext: + # readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 65532 + runAsGroup: 65532 + capabilities: + drop: + - ALL + + # -- hubble-relay service configuration. + service: + # --- The type of service used for Hubble Relay access, either ClusterIP or NodePort. + type: ClusterIP + # --- The port to use when the service type is set to NodePort. + nodePort: 31234 + + # -- Host to listen to. Specify an empty string to bind to all the interfaces. + listenHost: "" + + # -- Port to listen to. + listenPort: "4245" + + # -- TLS configuration for Hubble Relay + tls: + # -- base64 encoded PEM values for the hubble-relay client certificate and private key + # This keypair is presented to Hubble server instances for mTLS + # authentication and is required when hubble.tls.enabled is true. + # These values need to be set manually if hubble.tls.auto.enabled is false. + client: + cert: "" + key: "" + # -- base64 encoded PEM values for the hubble-relay server certificate and private key + server: + # When set to true, enable TLS on for Hubble Relay server + # (ie: for clients connecting to the Hubble Relay API). + enabled: true + # When set to true enforces mutual TLS between Hubble Relay server and its clients. + # False allow non-mutual TLS connections. + # This option has no effect when TLS is disabled. + mtls: true + # These values need to be set manually if hubble.tls.auto.enabled is false. + cert: "" + key: "" + # -- extra DNS names added to certificate when its auto gen + extraDnsNames: [] + # -- extra IP addresses added to certificate when its auto gen + extraIpAddresses: [] + # DNS name used by the backend to connect to the relay + # This is a simple workaround as the relay certificates are currently hardcoded to + # *.hubble-relay.cilium.io + # See https://github.com/cilium/cilium/pull/28709#discussion_r1371792546 + # For GKE Dataplane V2 this should be set to relay.kube-system.svc.cluster.local + relayName: "ui.hubble-relay.cilium.io" + + # -- Dial timeout to connect to the local hubble instance to receive peer information (e.g. "30s"). + dialTimeout: ~ + + # -- Backoff duration to retry connecting to the local hubble instance in case of failure (e.g. "30s"). + retryTimeout: ~ + + # -- Max number of flows that can be buffered for sorting before being sent to the + # client (per request) (e.g. 100). + sortBufferLenMax: ~ + + # -- When the per-request flows sort buffer is not full, a flow is drained every + # time this timeout is reached (only affects requests in follow-mode) (e.g. "1s"). + sortBufferDrainTimeout: ~ + + # -- Port to use for the k8s service backed by hubble-relay pods. + # If not set, it is dynamically assigned to port 443 if TLS is enabled and to + # port 80 if not. + # servicePort: 80 + + # -- Enable prometheus metrics for hubble-relay on the configured port at + # /metrics + prometheus: + enabled: false + port: 9966 + serviceMonitor: + # -- Enable service monitors. + # This requires the prometheus CRDs to be available (see https://github.com/prometheus-operator/prometheus-operator/blob/main/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml) + enabled: false + # -- Labels to add to ServiceMonitor hubble-relay + labels: {} + # -- Annotations to add to ServiceMonitor hubble-relay + annotations: {} + # -- Interval for scrape metrics. + interval: "10s" + # -- Specify the Kubernetes namespace where Prometheus expects to find + # service monitors configured. + # namespace: "" + # -- Relabeling configs for the ServiceMonitor hubble-relay + relabelings: ~ + # -- Metrics relabeling configs for the ServiceMonitor hubble-relay + metricRelabelings: ~ + + gops: + # -- Enable gops for hubble-relay + enabled: true + # -- Configure gops listen port for hubble-relay + port: 9893 + + pprof: + # -- Enable pprof for hubble-relay + enabled: false + # -- Configure pprof listen address for hubble-relay + address: localhost + # -- Configure pprof listen port for hubble-relay + port: 6062 + + ui: + # -- Whether to enable the Hubble UI. + enabled: true + + standalone: + # -- When true, it will allow installing the Hubble UI only, without checking dependencies. + # It is useful if a cluster already has cilium and Hubble relay installed and you just + # want Hubble UI to be deployed. + # When installed via helm, installing UI should be done via `helm upgrade` and when installed via the cilium cli, then `cilium hubble enable --ui` + enabled: false + + tls: + # -- When deploying Hubble UI in standalone, with tls enabled for Hubble relay, it is required + # to provide a volume for mounting the client certificates. + certsVolume: + {} + # projected: + # defaultMode: 0400 + # sources: + # - secret: + # name: hubble-ui-client-certs + # items: + # - key: tls.crt + # path: client.crt + # - key: tls.key + # path: client.key + # - key: ca.crt + # path: hubble-relay-ca.crt + + # -- Roll out Hubble-ui pods automatically when configmap is updated. + rollOutPods: false + + tls: + # -- base64 encoded PEM values used to connect to hubble-relay + # This keypair is presented to Hubble Relay instances for mTLS + # authentication and is required when hubble.relay.tls.server.enabled is true. + # These values need to be set manually if hubble.tls.auto.enabled is false. + client: + cert: "" + key: "" + + backend: + # -- Hubble-ui backend image. + image: + override: ~ + repository: "mcr.microsoft.com/oss/cilium/hubble-ui-backend" + tag: "v0.12.2" + digest: "sha256:b73dd1ac1b7159d42cdba31433964313e756daafefffad5e91c3b61b47c3782f" + useDigest: true + pullPolicy: "Always" + + # -- Hubble-ui backend security context. + securityContext: {} + + # -- Additional hubble-ui backend environment variables. + extraEnv: [] + + # -- Additional hubble-ui backend volumes. + extraVolumes: [] + + # -- Additional hubble-ui backend volumeMounts. + extraVolumeMounts: [] + + livenessProbe: + # -- Enable liveness probe for Hubble-ui backend (requires Hubble-ui 0.12+) + enabled: false + + readinessProbe: + # -- Enable readiness probe for Hubble-ui backend (requires Hubble-ui 0.12+) + enabled: false + + # -- Resource requests and limits for the 'backend' container of the 'hubble-ui' deployment. + resources: {} + # limits: + # cpu: 1000m + # memory: 1024M + # requests: + # cpu: 100m + # memory: 64Mi + + frontend: + # -- Hubble-ui frontend image. + image: + override: ~ + repository: "mcr.microsoft.com/oss/cilium/hubble-ui" + tag: "v0.12.2" + digest: "sha256:8c53cdaebb4ae863ad061387a68ea06e38777d2911e6c0e570be1932bb4ba526" + useDigest: true + pullPolicy: "Always" + + # -- Hubble-ui frontend security context. + securityContext: {} + + # -- Additional hubble-ui frontend environment variables. + extraEnv: [] + + # -- Additional hubble-ui frontend volumes. + extraVolumes: [] + + # -- Additional hubble-ui frontend volumeMounts. + extraVolumeMounts: [] + + # -- Resource requests and limits for the 'frontend' container of the 'hubble-ui' deployment. + resources: {} + # limits: + # cpu: 1000m + # memory: 1024M + # requests: + # cpu: 100m + # memory: 64Mi + server: + # -- Controls server listener for ipv6 + ipv6: + enabled: true + + # -- The number of replicas of Hubble UI to deploy. + replicas: 1 + + # -- Annotations to be added to all top-level hubble-ui objects (resources under templates/hubble-ui) + annotations: {} + + # -- Annotations to be added to hubble-ui pods + podAnnotations: {} + + # -- Labels to be added to hubble-ui pods + podLabels: {} + + # PodDisruptionBudget settings + podDisruptionBudget: + # -- enable PodDisruptionBudget + # ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ + enabled: false + # -- Minimum number/percentage of pods that should remain scheduled. + # When it's set, maxUnavailable must be disabled by `maxUnavailable: null` + minAvailable: null + # -- Maximum number/percentage of pods that may be made unavailable + maxUnavailable: 1 + + # -- Affinity for hubble-ui + affinity: {} + + # -- Pod topology spread constraints for hubble-ui + topologySpreadConstraints: + [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # whenUnsatisfiable: DoNotSchedule + + # -- Node labels for pod assignment + # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector + nodeSelector: + kubernetes.io/os: linux + + # -- Node tolerations for pod assignment on nodes with taints + # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ + tolerations: [] + + # -- The priority class to use for hubble-ui + priorityClassName: "" + + # -- hubble-ui update strategy. + updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + + # -- Security context to be added to Hubble UI pods + securityContext: + runAsUser: 1001 + runAsGroup: 1001 + fsGroup: 1001 + + # -- hubble-ui service configuration. + service: + # -- Annotations to be added for the Hubble UI service + annotations: {} + # --- The type of service used for Hubble UI access, either ClusterIP or NodePort. + type: ClusterIP + # --- The port to use when the service type is set to NodePort. + nodePort: 31235 + + # -- Defines base url prefix for all hubble-ui http requests. + # It needs to be changed in case if ingress for hubble-ui is configured under some sub-path. + # Trailing `/` is required for custom path, ex. `/service-map/` + baseUrl: "/" + + # -- hubble-ui ingress configuration. + ingress: + enabled: false + annotations: + {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + className: "" + hosts: + - chart-example.local + labels: {} + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + + # -- Hubble flows export. + export: + # --- Defines max file size of output file before it gets rotated. + fileMaxSizeMb: 10 + # --- Defines max number of backup/rotated files. + fileMaxBackups: 5 + # --- Static exporter configuration. + # Static exporter is bound to agent lifecycle. + static: + enabled: false + filePath: /var/run/cilium/hubble/events.log + fieldMask: [] + # - time + # - source + # - destination + # - verdict + allowList: [] + # - '{"verdict":["DROPPED","ERROR"]}' + denyList: [] + # - '{"source_pod":["kube-system/"]}' + # - '{"destination_pod":["kube-system/"]}' + # --- Dynamic exporters configuration. + # Dynamic exporters may be reconfigured without a need of agent restarts. + dynamic: + enabled: false + config: + # ---- Name of configmap with configuration that may be altered to reconfigure exporters within a running agents. + configMapName: cilium-flowlog-config + # ---- True if helm installer should create config map. + # Switch to false if you want to self maintain the file content. + createConfigMap: true + # ---- Exporters configuration in YAML format. + content: + - name: all + fieldMask: [] + includeFilters: [] + excludeFilters: [] + filePath: "/var/run/cilium/hubble/events.log" + #- name: "test002" + # filePath: "/var/log/network/flow-log/pa/test002.log" + # fieldMask: ["source.namespace", "source.pod_name", "destination.namespace", "destination.pod_name", "verdict"] + # includeFilters: + # - source_pod: ["default/"] + # event_type: + # - type: 1 + # - destination_pod: ["frontend/nginx-975996d4c-7hhgt"] + # excludeFilters: [] + # end: "2023-10-09T23:59:59-07:00" + +# -- Configure certificate generation for Hubble integration. +# If hubble.tls.auto.method=cronJob, these values are used +# for the Kubernetes CronJob which will be scheduled regularly to +# (re)generate any certificates not provided manually. +certgen: + image: + override: ~ + repository: "mcr.microsoft.com/oss/cilium/certgen" + tag: "v0.1.9" + #digest: "sha256:89a0847753686444daabde9474b48340993bd19c7bea66a46e45b2974b82041f" + useDigest: false + pullPolicy: "Always" + # -- Seconds after which the completed job pod will be deleted + ttlSecondsAfterFinished: 1800 + # -- Labels to be added to hubble-certgen pods + podLabels: {} + # -- Annotations to be added to the hubble-certgen initial Job and CronJob + annotations: + job: {} + cronJob: {} + # -- Node tolerations for pod assignment on nodes with taints + # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ + tolerations: [] + + # -- Additional certgen volumes. + extraVolumes: [] + + # -- Additional certgen volumeMounts. + extraVolumeMounts: [] + + # -- Affinity for certgen + affinity: {} + +tls: + # -- This configures how the Cilium agent loads the secrets used TLS-aware CiliumNetworkPolicies + # (namely the secrets referenced by terminatingTLS and originatingTLS). + # Possible values: + # - local + # - k8s + secretsBackend: local + + # -- Base64 encoded PEM values for the CA certificate and private key. + # This can be used as common CA to generate certificates used by hubble and clustermesh components. + # It is neither required nor used when cert-manager is used to generate the certificates. + ca: + # -- Optional CA cert. If it is provided, it will be used by cilium to + # generate all other certificates. Otherwise, an ephemeral CA is generated. + cert: "" + + # -- Optional CA private key. If it is provided, it will be used by cilium to + # generate all other certificates. Otherwise, an ephemeral CA is generated. + key: "" + + # -- Generated certificates validity duration in days. This will be used for auto generated CA. + certValidityDuration: 1095 + + # -- Configure the CA trust bundle used for the validation of the certificates + # leveraged by hubble and clustermesh. When enabled, it overrides the content of the + # 'ca.crt' field of the respective certificates, allowing for CA rotation with no down-time. + caBundle: + # -- Enable the use of the CA trust bundle. + enabled: false + + # -- Name of the ConfigMap containing the CA trust bundle. + name: cilium-root-ca.crt + + # -- Entry of the ConfigMap containing the CA trust bundle. + key: ca.crt + + # -- Use a Secret instead of a ConfigMap. + useSecret: false + + # If uncommented, creates the ConfigMap and fills it with the specified content. + # Otherwise, the ConfigMap is assumed to be already present in .Release.Namespace. + # + # content: | + # -----BEGIN CERTIFICATE----- + # ... + # -----END CERTIFICATE----- + # -----BEGIN CERTIFICATE----- + # ... + # -----END CERTIFICATE----- diff --git a/deploy/grafana/dashboards/clusters.json b/deploy/legacy/graphana/dashboards/clusters.json similarity index 100% rename from deploy/grafana/dashboards/clusters.json rename to deploy/legacy/graphana/dashboards/clusters.json diff --git a/deploy/grafana/dashboards/dns.json b/deploy/legacy/graphana/dashboards/dns.json similarity index 100% rename from deploy/grafana/dashboards/dns.json rename to deploy/legacy/graphana/dashboards/dns.json diff --git a/deploy/grafana/dashboards/pod-level.json b/deploy/legacy/graphana/dashboards/pod-level.json similarity index 100% rename from deploy/grafana/dashboards/pod-level.json rename to deploy/legacy/graphana/dashboards/pod-level.json diff --git a/deploy/grafana/dashboards/simplify-grafana-overwrite_test.go b/deploy/legacy/graphana/dashboards/simplify-grafana-overwrite_test.go similarity index 99% rename from deploy/grafana/dashboards/simplify-grafana-overwrite_test.go rename to deploy/legacy/graphana/dashboards/simplify-grafana-overwrite_test.go index 277a1100c..413cae54b 100644 --- a/deploy/grafana/dashboards/simplify-grafana-overwrite_test.go +++ b/deploy/legacy/graphana/dashboards/simplify-grafana-overwrite_test.go @@ -3,10 +3,9 @@ package dashboard import ( - "testing" - "os" "path/filepath" + "testing" ) // TestOverwriteDashboards simplifies and overwrites Grafana dashboards in this folder. diff --git a/deploy/grafana/dashboards/simplify-grafana.go b/deploy/legacy/graphana/dashboards/simplify-grafana.go similarity index 98% rename from deploy/grafana/dashboards/simplify-grafana.go rename to deploy/legacy/graphana/dashboards/simplify-grafana.go index adc1a0ac1..dc90f5f80 100644 --- a/deploy/grafana/dashboards/simplify-grafana.go +++ b/deploy/legacy/graphana/dashboards/simplify-grafana.go @@ -54,7 +54,7 @@ func SimplifyGrafana(filename string, overwrite bool) map[string]interface{} { log.Fatal(err) } - err = os.WriteFile(filename, simplifiedData, 0644) + err = os.WriteFile(filename, simplifiedData, 0o644) if err != nil { log.Fatal(err) } diff --git a/deploy/grafana/dashboards/simplify-grafana_test.go b/deploy/legacy/graphana/dashboards/simplify-grafana_test.go similarity index 99% rename from deploy/grafana/dashboards/simplify-grafana_test.go rename to deploy/legacy/graphana/dashboards/simplify-grafana_test.go index 53372e98f..58e4a2633 100644 --- a/deploy/grafana/dashboards/simplify-grafana_test.go +++ b/deploy/legacy/graphana/dashboards/simplify-grafana_test.go @@ -3,11 +3,10 @@ package dashboard import ( - "testing" "os" "path/filepath" - "reflect" + "testing" ) // TestDashboardsAreSimplified ensures that all dashboards are simplified diff --git a/deploy/legacy/manifests/controller/helm/retina/.helmignore b/deploy/legacy/manifests/controller/helm/retina/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/deploy/legacy/manifests/controller/helm/retina/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/deploy/manifests/controller/helm/retina/Chart.yaml b/deploy/legacy/manifests/controller/helm/retina/Chart.yaml similarity index 100% rename from deploy/manifests/controller/helm/retina/Chart.yaml rename to deploy/legacy/manifests/controller/helm/retina/Chart.yaml diff --git a/deploy/manifests/controller/helm/retina/crds/retina.sh_captures.yaml b/deploy/legacy/manifests/controller/helm/retina/crds/retina.sh_captures.yaml similarity index 100% rename from deploy/manifests/controller/helm/retina/crds/retina.sh_captures.yaml rename to deploy/legacy/manifests/controller/helm/retina/crds/retina.sh_captures.yaml diff --git a/deploy/manifests/controller/helm/retina/crds/retina.sh_metricsconfigurations.yaml b/deploy/legacy/manifests/controller/helm/retina/crds/retina.sh_metricsconfigurations.yaml similarity index 100% rename from deploy/manifests/controller/helm/retina/crds/retina.sh_metricsconfigurations.yaml rename to deploy/legacy/manifests/controller/helm/retina/crds/retina.sh_metricsconfigurations.yaml diff --git a/deploy/manifests/controller/helm/retina/crds/retina.sh_retinaendpoints.yaml b/deploy/legacy/manifests/controller/helm/retina/crds/retina.sh_retinaendpoints.yaml similarity index 100% rename from deploy/manifests/controller/helm/retina/crds/retina.sh_retinaendpoints.yaml rename to deploy/legacy/manifests/controller/helm/retina/crds/retina.sh_retinaendpoints.yaml diff --git a/deploy/manifests/controller/helm/retina/crds/retina.sh_tracesconfigurations.yaml b/deploy/legacy/manifests/controller/helm/retina/crds/retina.sh_tracesconfigurations.yaml similarity index 100% rename from deploy/manifests/controller/helm/retina/crds/retina.sh_tracesconfigurations.yaml rename to deploy/legacy/manifests/controller/helm/retina/crds/retina.sh_tracesconfigurations.yaml diff --git a/deploy/manifests/controller/helm/retina/templates/NOTES.txt b/deploy/legacy/manifests/controller/helm/retina/templates/NOTES.txt similarity index 65% rename from deploy/manifests/controller/helm/retina/templates/NOTES.txt rename to deploy/legacy/manifests/controller/helm/retina/templates/NOTES.txt index 8d0773b91..46dfb7e9a 100644 --- a/deploy/manifests/controller/helm/retina/templates/NOTES.txt +++ b/deploy/legacy/manifests/controller/helm/retina/templates/NOTES.txt @@ -1,3 +1,3 @@ -1. Installing retina service using helm: helm install retina ./deploy/manifests/controller/helm/retina/ --namespace kube-system --dependency-update +1. Installing retina service using helm: helm install retina ./deploy/legacy/manifests/controller/helm/retina/ --namespace kube-system --dependency-update 2. Cleaning up/uninstalling/deleting retina and dependencies related: helm uninstall retina -n kube-system diff --git a/deploy/manifests/controller/helm/retina/templates/_helpers.tpl b/deploy/legacy/manifests/controller/helm/retina/templates/_helpers.tpl similarity index 100% rename from deploy/manifests/controller/helm/retina/templates/_helpers.tpl rename to deploy/legacy/manifests/controller/helm/retina/templates/_helpers.tpl diff --git a/deploy/manifests/controller/helm/retina/templates/configmap.yaml b/deploy/legacy/manifests/controller/helm/retina/templates/configmap.yaml similarity index 100% rename from deploy/manifests/controller/helm/retina/templates/configmap.yaml rename to deploy/legacy/manifests/controller/helm/retina/templates/configmap.yaml diff --git a/deploy/manifests/controller/helm/retina/templates/daemonset.yaml b/deploy/legacy/manifests/controller/helm/retina/templates/daemonset.yaml similarity index 100% rename from deploy/manifests/controller/helm/retina/templates/daemonset.yaml rename to deploy/legacy/manifests/controller/helm/retina/templates/daemonset.yaml diff --git a/deploy/manifests/controller/helm/retina/templates/networkobserver.yaml b/deploy/legacy/manifests/controller/helm/retina/templates/networkobserver.yaml similarity index 100% rename from deploy/manifests/controller/helm/retina/templates/networkobserver.yaml rename to deploy/legacy/manifests/controller/helm/retina/templates/networkobserver.yaml diff --git a/deploy/manifests/controller/helm/retina/templates/operator.yaml b/deploy/legacy/manifests/controller/helm/retina/templates/operator.yaml similarity index 100% rename from deploy/manifests/controller/helm/retina/templates/operator.yaml rename to deploy/legacy/manifests/controller/helm/retina/templates/operator.yaml diff --git a/deploy/manifests/controller/helm/retina/templates/podmonitor.yaml b/deploy/legacy/manifests/controller/helm/retina/templates/podmonitor.yaml similarity index 100% rename from deploy/manifests/controller/helm/retina/templates/podmonitor.yaml rename to deploy/legacy/manifests/controller/helm/retina/templates/podmonitor.yaml diff --git a/deploy/manifests/controller/helm/retina/templates/rbac.yaml b/deploy/legacy/manifests/controller/helm/retina/templates/rbac.yaml similarity index 100% rename from deploy/manifests/controller/helm/retina/templates/rbac.yaml rename to deploy/legacy/manifests/controller/helm/retina/templates/rbac.yaml diff --git a/deploy/manifests/controller/helm/retina/templates/service.yaml b/deploy/legacy/manifests/controller/helm/retina/templates/service.yaml similarity index 100% rename from deploy/manifests/controller/helm/retina/templates/service.yaml rename to deploy/legacy/manifests/controller/helm/retina/templates/service.yaml diff --git a/deploy/manifests/controller/helm/retina/templates/serviceaccount.yaml b/deploy/legacy/manifests/controller/helm/retina/templates/serviceaccount.yaml similarity index 100% rename from deploy/manifests/controller/helm/retina/templates/serviceaccount.yaml rename to deploy/legacy/manifests/controller/helm/retina/templates/serviceaccount.yaml diff --git a/deploy/manifests/controller/helm/retina/templates/tests/test-connection.yaml b/deploy/legacy/manifests/controller/helm/retina/templates/tests/test-connection.yaml similarity index 100% rename from deploy/manifests/controller/helm/retina/templates/tests/test-connection.yaml rename to deploy/legacy/manifests/controller/helm/retina/templates/tests/test-connection.yaml diff --git a/deploy/manifests/controller/helm/retina/values.yaml b/deploy/legacy/manifests/controller/helm/retina/values.yaml similarity index 100% rename from deploy/manifests/controller/helm/retina/values.yaml rename to deploy/legacy/manifests/controller/helm/retina/values.yaml diff --git a/deploy/prometheus/ama-metrics-settings-configmap.yaml b/deploy/legacy/prometheus/ama-metrics-settings-configmap.yaml similarity index 100% rename from deploy/prometheus/ama-metrics-settings-configmap.yaml rename to deploy/legacy/prometheus/ama-metrics-settings-configmap.yaml diff --git a/deploy/prometheus/collector-config-template.yml b/deploy/legacy/prometheus/collector-config-template.yml similarity index 100% rename from deploy/prometheus/collector-config-template.yml rename to deploy/legacy/prometheus/collector-config-template.yml diff --git a/deploy/prometheus/deploy-retina-clusters.sh b/deploy/legacy/prometheus/deploy-retina-clusters.sh similarity index 100% rename from deploy/prometheus/deploy-retina-clusters.sh rename to deploy/legacy/prometheus/deploy-retina-clusters.sh diff --git a/deploy/prometheus/network-observability/create-cm.sh b/deploy/legacy/prometheus/network-observability/create-cm.sh similarity index 72% rename from deploy/prometheus/network-observability/create-cm.sh rename to deploy/legacy/prometheus/network-observability/create-cm.sh index 3573f794f..cc93571a6 100755 --- a/deploy/prometheus/network-observability/create-cm.sh +++ b/deploy/legacy/prometheus/network-observability/create-cm.sh @@ -1,5 +1,5 @@ #!/bin/bash kubectl delete cm ama-metrics-prometheus-config-node -n kube-system -kubectl create configmap ama-metrics-prometheus-config-node --from-file=./deploy/prometheus/cilium/prometheus-config -n kube-system +kubectl create configmap ama-metrics-prometheus-config-node --from-file=./deploy/legacy/prometheus/cilium/prometheus-config -n kube-system k rollout restart ds ama-metrics-node -n kube-system diff --git a/deploy/prometheus/network-observability/network-observability-svc.yaml b/deploy/legacy/prometheus/network-observability/network-observability-svc.yaml similarity index 100% rename from deploy/prometheus/network-observability/network-observability-svc.yaml rename to deploy/legacy/prometheus/network-observability/network-observability-svc.yaml diff --git a/deploy/prometheus/network-observability/prometheus-config b/deploy/legacy/prometheus/network-observability/prometheus-config similarity index 100% rename from deploy/prometheus/network-observability/prometheus-config rename to deploy/legacy/prometheus/network-observability/prometheus-config diff --git a/deploy/prometheus/retina-windows/create-cm.sh b/deploy/legacy/prometheus/retina-windows/create-cm.sh similarity index 63% rename from deploy/prometheus/retina-windows/create-cm.sh rename to deploy/legacy/prometheus/retina-windows/create-cm.sh index 05d9f6657..347d9315e 100755 --- a/deploy/prometheus/retina-windows/create-cm.sh +++ b/deploy/legacy/prometheus/retina-windows/create-cm.sh @@ -2,4 +2,4 @@ kubectl delete cm ama-metrics-prometheus-config-node -n kube-system -kubectl create configmap ama-metrics-prometheus-config-node --from-file=./deploy/prometheus/retina-windows/prometheus-config -n kube-system +kubectl create configmap ama-metrics-prometheus-config-node --from-file=./deploy/legacy/prometheus/retina-windows/prometheus-config -n kube-system diff --git a/deploy/prometheus/retina-windows/prometheus-config b/deploy/legacy/prometheus/retina-windows/prometheus-config similarity index 100% rename from deploy/prometheus/retina-windows/prometheus-config rename to deploy/legacy/prometheus/retina-windows/prometheus-config diff --git a/deploy/prometheus/retina/create-cm.sh b/deploy/legacy/prometheus/retina/create-cm.sh similarity index 50% rename from deploy/prometheus/retina/create-cm.sh rename to deploy/legacy/prometheus/retina/create-cm.sh index 8b5444bd4..873658fc6 100755 --- a/deploy/prometheus/retina/create-cm.sh +++ b/deploy/legacy/prometheus/retina/create-cm.sh @@ -1,3 +1,3 @@ #!/bin/bash -kubectl create configmap ama-metrics-prometheus-config-node --from-file=./deploy/prometheus/retina/prometheus-config -n kube-system +kubectl create configmap ama-metrics-prometheus-config-node --from-file=./deploy/legacy/prometheus/retina/prometheus-config -n kube-system diff --git a/deploy/prometheus/retina/prometheus-config b/deploy/legacy/prometheus/retina/prometheus-config similarity index 100% rename from deploy/prometheus/retina/prometheus-config rename to deploy/legacy/prometheus/retina/prometheus-config diff --git a/deploy/prometheus/values.yaml b/deploy/legacy/prometheus/values.yaml similarity index 100% rename from deploy/prometheus/values.yaml rename to deploy/legacy/prometheus/values.yaml diff --git a/deploy/registercrd.go b/deploy/legacy/registercrd.go similarity index 100% rename from deploy/registercrd.go rename to deploy/legacy/registercrd.go diff --git a/deploy/registercrd_test.go b/deploy/legacy/registercrd_test.go similarity index 100% rename from deploy/registercrd_test.go rename to deploy/legacy/registercrd_test.go diff --git a/docs/CRDs/Capture.md b/docs/CRDs/Capture.md index 093783d5a..7cbf2410f 100644 --- a/docs/CRDs/Capture.md +++ b/docs/CRDs/Capture.md @@ -9,7 +9,7 @@ To use the `Capture` CRD, [install Retina](../installation/setup.md) with captur ## CRD Specification -The full specification for the `Capture` CRD can be found in the [Capture CRD](https://github.com/microsoft/retina/blob/main/deploy/manifests/controller/helm/retina/crds/retina.sh_captures.yaml) file. +The full specification for the `Capture` CRD can be found in the [Capture CRD](https://github.com/microsoft/retina/blob/main/deploy/legacy/manifests/controller/helm/retina/crds/retina.sh_captures.yaml) file. The `Capture` CRD is defined with the following specifications: diff --git a/docs/CRDs/MetricsConfiguration.md b/docs/CRDs/MetricsConfiguration.md index 99de9d7e2..3e6815ec3 100644 --- a/docs/CRDs/MetricsConfiguration.md +++ b/docs/CRDs/MetricsConfiguration.md @@ -6,7 +6,7 @@ Retina by default emits node level metrics, however, customers can apply `Metric ## CRD Specification -The full specification for the `MetricsConfiguration` CRD can be found in the [MetricsConfiguration CRD](https://github.com/microsoft/retina/blob/main/deploy/manifests/controller/helm/retina/crds/retina.sh_metricsconfigurations.yaml) file. +The full specification for the `MetricsConfiguration` CRD can be found in the [MetricsConfiguration CRD](https://github.com/microsoft/retina/blob/main/deploy/legacy/manifests/controller/helm/retina/crds/retina.sh_metricsconfigurations.yaml) file. The `MetricsConfiguration` CRD is defined with the following specifications: diff --git a/docs/CRDs/RetinaEndpoint.md b/docs/CRDs/RetinaEndpoint.md index 434beb6d8..7f24d78a7 100644 --- a/docs/CRDs/RetinaEndpoint.md +++ b/docs/CRDs/RetinaEndpoint.md @@ -8,7 +8,7 @@ In large-scale API servers, each Retina Pod needs to learn about cluster state, ## CRD Specification -The full specification for the `RetinaEndpoint` CRD can be found in the [RetinaEndpoint CRD]( https://github.com/microsoft/retina/blob/main/deploy/manifests/controller/helm/retina/crds/retina.sh_retinaendpoints.yaml) file. +The full specification for the `RetinaEndpoint` CRD can be found in the [RetinaEndpoint CRD]( https://github.com/microsoft/retina/blob/main/deploy/legacy/manifests/controller/helm/retina/crds/retina.sh_retinaendpoints.yaml) file. The `RetinaEndpoint` CRD is defined with the following specifications: diff --git a/docs/installation/config.md b/docs/installation/config.md index 8ca09ad18..54d74ed7b 100644 --- a/docs/installation/config.md +++ b/docs/installation/config.md @@ -3,7 +3,7 @@ ## Overview To customize metrics and other options, you can modify Retina's ConfigMap called `retina-config`. -Defaults are specified for each component in *deploy/manifests/controller/helm/retina/values.yaml*. +Defaults are specified for each component in *deploy/legacy/manifests/controller/helm/retina/values.yaml*. ## Agent Config diff --git a/docs/installation/prometheus-unmanaged.md b/docs/installation/prometheus-unmanaged.md index 19f314c82..33b6e5233 100644 --- a/docs/installation/prometheus-unmanaged.md +++ b/docs/installation/prometheus-unmanaged.md @@ -15,7 +15,7 @@ helm repo update ``` -2. Save **[these Prometheus values](https://github.com/microsoft/retina/blob/main/deploy/prometheus/values.yaml)** below to `deploy/prometheus/values.yaml` +2. Save **[these Prometheus values](https://github.com/microsoft/retina/blob/main/deploy/legacy/prometheus/values.yaml)** below to `deploy/legacy/prometheus/values.yaml` 3. Install the Prometheus chart diff --git a/docs/unsorted/aks-setup.md b/docs/unsorted/aks-setup.md index 8ee13f6bc..d62902d64 100644 --- a/docs/unsorted/aks-setup.md +++ b/docs/unsorted/aks-setup.md @@ -15,4 +15,4 @@ 8. Push to container registry: `docker push /retina:` 9. Installing retina onto the cluster - -`helm install retina /deploy/manifests/controller/helm/retina/ --create-namespace --namespace retina --dependency-update` +`helm install retina /deploy/legacy/manifests/controller/helm/retina/ --create-namespace --namespace retina --dependency-update` diff --git a/go.mod b/go.mod index a13eddcf0..b2f3bb50d 100644 --- a/go.mod +++ b/go.mod @@ -6,8 +6,8 @@ require ( github.com/go-chi/chi/v5 v5.0.11 github.com/google/uuid v1.6.0 github.com/prometheus/client_golang v1.19.1 - github.com/spf13/cobra v1.8.1 - go.uber.org/zap v1.26.0 + github.com/spf13/cobra v1.8.0 + go.uber.org/zap v1.27.0 k8s.io/client-go v0.30.1 ) @@ -51,7 +51,9 @@ require ( github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect - github.com/cilium/proxy v0.0.0-20231031145409-f19708f3d018 // indirect + github.com/cilium/dns v1.1.51-0.20231120140355-729345173dc3 // indirect + github.com/cilium/lumberjack/v2 v2.3.0 // indirect + github.com/cilium/stream v0.0.0-20240226091623-f979d32855f8 // indirect github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa // indirect github.com/containerd/cgroups/v3 v3.0.2 // indirect github.com/containerd/containerd v1.7.14 // indirect @@ -61,6 +63,7 @@ require ( github.com/containerd/log v0.1.0 // indirect github.com/containerd/ttrpc v1.2.3 // indirect github.com/containerd/typeurl/v2 v2.1.1 // indirect + github.com/containernetworking/cni v1.1.2 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect @@ -76,7 +79,7 @@ require ( github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/go-restful/v3 v3.11.2 // indirect github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect - github.com/evanphx/json-patch v5.7.0+incompatible // indirect + github.com/evanphx/json-patch v5.9.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/fatih/color v1.16.0 // indirect @@ -85,17 +88,16 @@ require ( github.com/go-errors/errors v1.4.2 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect - github.com/go-openapi/analysis v0.21.4 // indirect - github.com/go-openapi/errors v0.20.4 // indirect - github.com/go-openapi/jsonpointer v0.20.2 // indirect - github.com/go-openapi/jsonreference v0.20.4 // indirect - github.com/go-openapi/loads v0.21.2 // indirect - github.com/go-openapi/runtime v0.26.2 // indirect - github.com/go-openapi/spec v0.20.11 // indirect - github.com/go-openapi/strfmt v0.21.9 // indirect - github.com/go-openapi/swag v0.22.10 // indirect - github.com/go-openapi/validate v0.22.3 // indirect + github.com/go-openapi/analysis v0.23.0 // indirect + github.com/go-openapi/errors v0.22.0 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/loads v0.22.0 // indirect + github.com/go-openapi/runtime v0.28.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/strfmt v0.23.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/validate v0.24.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect @@ -105,18 +107,20 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/btree v1.1.2 // indirect github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect + github.com/google/gops v0.3.27 // indirect github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect + github.com/google/renameio/v2 v2.0.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.1 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect - github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/hashicorp/consul/api v1.28.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect @@ -136,7 +140,7 @@ require ( github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect - github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/mackerelio/go-osstat v0.2.4 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -172,7 +176,6 @@ require ( github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rubenv/sql-migrate v1.5.2 // indirect @@ -181,26 +184,25 @@ require ( github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect - github.com/shirou/gopsutil/v3 v3.23.2 // indirect github.com/shopspring/decimal v1.3.1 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect - github.com/tklauser/go-sysconf v0.3.11 // indirect - github.com/tklauser/numcpus v0.7.0 // indirect + github.com/tidwall/gjson v1.17.1 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/sjson v1.2.5 // indirect github.com/vishvananda/netns v0.0.4 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect - github.com/yusufpapurcu/wmi v1.2.3 // indirect go.etcd.io/etcd/api/v3 v3.5.12 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.12 // indirect go.etcd.io/etcd/client/v3 v3.5.12 // indirect - go.mongodb.org/mongo-driver v1.13.1 // indirect + go.mongodb.org/mongo-driver v1.14.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect go.starlark.net v0.0.0-20230814145427-12f4cb8177e4 // indirect @@ -214,7 +216,7 @@ require ( gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect google.golang.org/grpc v1.62.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect @@ -237,7 +239,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 go.uber.org/multierr v1.11.0 // indirect golang.org/x/net v0.26.0 // indirect @@ -270,16 +272,21 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2 github.com/Microsoft/hcsshim v0.12.0-rc.3 + github.com/Sytten/logrus-zap-hook v0.1.0 github.com/aws/aws-sdk-go-v2 v1.30.0 - github.com/aws/aws-sdk-go-v2/config v1.27.22 - github.com/aws/aws-sdk-go-v2/credentials v1.17.22 - github.com/aws/aws-sdk-go-v2/service/s3 v1.57.0 + github.com/aws/aws-sdk-go-v2/config v1.27.21 + github.com/aws/aws-sdk-go-v2/credentials v1.17.21 + github.com/aws/aws-sdk-go-v2/service/s3 v1.56.1 github.com/cakturk/go-netstat v0.0.0-20200220111822-e5b49efee7a5 - github.com/cilium/cilium v1.15.6 + github.com/cilium/cilium v1.16.0-pre.1.0.20240403152809-b9853ecbcaeb github.com/cilium/ebpf v0.15.0 + github.com/cilium/proxy v0.0.0-20231031145409-f19708f3d018 + github.com/cilium/workerpool v1.2.0 github.com/florianl/go-tc v0.4.3 github.com/go-logr/zapr v1.3.0 + github.com/golang/mock v1.1.1 github.com/google/gopacket v1.1.19 + github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/inspektor-gadget/inspektor-gadget v0.27.0 github.com/jellydator/ttlcache/v3 v3.1.1 github.com/jsternberg/zap-logfmt v1.3.0 @@ -290,13 +297,15 @@ require ( github.com/prometheus/client_model v0.6.1 github.com/prometheus/common v0.55.0 github.com/safchain/ethtool v0.4.1 + github.com/sirupsen/logrus v1.9.3 github.com/spf13/viper v1.19.0 github.com/vishvananda/netlink v1.2.1-beta.2.0.20240524165444-4d4ba1473f21 + go.etcd.io/etcd v3.3.27+incompatible go.opentelemetry.io/otel v1.27.0 go.opentelemetry.io/otel/metric v1.27.0 go.opentelemetry.io/otel/trace v1.27.0 go.uber.org/mock v0.4.0 - golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 + golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gotest.tools v2.2.0+incompatible gotest.tools/v3 v3.5.1 diff --git a/go.sum b/go.sum index 26cb5d057..8e80b1b64 100644 --- a/go.sum +++ b/go.sum @@ -81,6 +81,8 @@ github.com/Microsoft/hcsshim v0.12.0-rc.3 h1:5GNGrobGs/sN/0nFO21W9k4lFn+iXXZAE8f github.com/Microsoft/hcsshim v0.12.0-rc.3/go.mod h1:WuNfcaYNaw+KpCEsZCIM6HCEmu0c5HfXpi+dDSmveP0= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/Sytten/logrus-zap-hook v0.1.0 h1:GPsDlO0b+rvfb6WohFNreI3Fe2I6MDyv1afoYPE2Kzk= +github.com/Sytten/logrus-zap-hook v0.1.0/go.mod h1:J0ktevklw/xJNpI2FzfTdJssk4P0vq3K2qzwihJ2gWU= 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= @@ -93,17 +95,16 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go-v2 v1.30.0 h1:6qAwtzlfcTtcL8NHtbDQAqgM5s6NDipQTkPxyH/6kAA= github.com/aws/aws-sdk-go-v2 v1.30.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2/go.mod h1:lPprDr1e6cJdyYeGXnRaJoP4Md+cDBvi2eOj00BlGmg= -github.com/aws/aws-sdk-go-v2/config v1.27.22 h1:TRkQVtpDINt+Na/ToU7iptyW6U0awAwJ24q4XN+59k8= -github.com/aws/aws-sdk-go-v2/config v1.27.22/go.mod h1:EYY3mVgFRUWkh6QNKH64MdyKs1YSUgatc0Zp3MDxi7c= -github.com/aws/aws-sdk-go-v2/credentials v1.17.22 h1:wu9kXQbbt64ul09v3ye4HYleAr4WiGV/uv69EXKDEr0= -github.com/aws/aws-sdk-go-v2/credentials v1.17.22/go.mod h1:pcvMtPcxJn3r2k6mZD9I0EcumLqPLA7V/0iCgOIlY+o= +github.com/aws/aws-sdk-go-v2/config v1.27.21 h1:yPX3pjGCe2hJsetlmGNB4Mngu7UPmvWPzzWCv1+boeM= +github.com/aws/aws-sdk-go-v2/config v1.27.21/go.mod h1:4XtlEU6DzNai8RMbjSF5MgGZtYvrhBP/aKZcRtZAVdM= +github.com/aws/aws-sdk-go-v2/credentials v1.17.21 h1:pjAqgzfgFhTv5grc7xPHtXCAaMapzmwA7aU+c/SZQGw= +github.com/aws/aws-sdk-go-v2/credentials v1.17.21/go.mod h1:nhK6PtBlfHTUDVmBLr1dg+WHCOCK+1Fu/WQyVHPsgNQ= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8 h1:FR+oWPFb/8qMVYMWN98bUZAGqPvLHiyqg1wqQGfUAXY= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8/go.mod h1:EgSKcHiuuakEIxJcKGzVNWh5srVAQ3jKaSrBGRYvM48= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12 h1:SJ04WXGTwnHlWIODtC5kJzKbeuHt+OUNOgKg7nfnUGw= @@ -122,8 +123,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.14 h1:zSDPny/p github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.14/go.mod h1:3TTcI5JSzda1nw/pkVC9dhgLre0SNBFj2lYS4GctXKI= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.12 h1:tzha+v1SCEBpXWEuw6B/+jm4h5z8hZbTpXz0zRZqTnw= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.12/go.mod h1:n+nt2qjHGoseWeLHt1vEr6ZRCCxIN2KcNpJxBcYQSwI= -github.com/aws/aws-sdk-go-v2/service/s3 v1.57.0 h1:v2DWNY6ll3JK62Bx1khUu9fJ4f3TwXllIEJxI7dDv/o= -github.com/aws/aws-sdk-go-v2/service/s3 v1.57.0/go.mod h1:8rDw3mVwmvIWWX/+LWY3PPIMZuwnQdJMCt0iVFVT3qw= +github.com/aws/aws-sdk-go-v2/service/s3 v1.56.1 h1:wsg9Z/vNnCmxWikfGIoOlnExtEU459cR+2d+iDJ8elo= +github.com/aws/aws-sdk-go-v2/service/s3 v1.56.1/go.mod h1:8rDw3mVwmvIWWX/+LWY3PPIMZuwnQdJMCt0iVFVT3qw= github.com/aws/aws-sdk-go-v2/service/sso v1.22.0 h1:lPIAPCRoJkmotLTU/9B6icUFlYDpEuWjKeL79XROv1M= github.com/aws/aws-sdk-go-v2/service/sso v1.22.0/go.mod h1:lcQG/MmxydijbeTOp04hIuJwXGWPZGI3bwdFDGRTv14= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.0 h1:/4r71ghx+hX9spr884cqXHPEmPzqH/J3K7fkE1yfcmw= @@ -164,15 +165,25 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/checkmate v1.0.3 h1:CQC5eOmlAZeEjPrVZY3ZwEBH64lHlx9mXYdUehEwI5w= github.com/cilium/checkmate v1.0.3/go.mod h1:KiBTasf39/F2hf2yAmHw21YFl3hcEyP4Yk6filxc12A= -github.com/cilium/cilium v1.15.6 h1:YT6UYuvdua6N1KQ6mRprymCct6Ee7uCE1hckbAR2bRM= -github.com/cilium/cilium v1.15.6/go.mod h1:UEP0tpPVhdrLC7rCHZwZ8hTpd6d01dF/1GvFPo8UhXE= +github.com/cilium/cilium v1.16.0-pre.1.0.20240403152809-b9853ecbcaeb h1:77M/pRhFWIImKh9KNCbx+afVN9E8zBmySuoKnw9wkWQ= +github.com/cilium/cilium v1.16.0-pre.1.0.20240403152809-b9853ecbcaeb/go.mod h1:ks3XSifKcx50E7JwdyKssalQ10xvwC+/sHmpBvDezmM= +github.com/cilium/dns v1.1.51-0.20231120140355-729345173dc3 h1:3PErIjIq4DlOwNsQNPcILFzbGnxPuKuqJsHEFpiwstM= +github.com/cilium/dns v1.1.51-0.20231120140355-729345173dc3/go.mod h1:/7LC2GOgyXJ7maupZlaVIumYQiGPIgllSf6mA9sg6RU= github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/cilium/ebpf v0.8.1/go.mod h1:f5zLIM0FSNuAkSyLAN7X+Hy6yznlF1mNiWUMfxMtrgk= github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk= github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso= +github.com/cilium/fake v0.6.1 h1:cLkNx1nkF0b0pPW79JaQxaI5oG2/rBzRKpp0YUg1fTA= +github.com/cilium/fake v0.6.1/go.mod h1:V9lCbbcsnSf3vB6sdOP7Q0bsUUJ/jyHPZxnFAw5nPUc= +github.com/cilium/lumberjack/v2 v2.3.0 h1:IhVJMvPpqDYmQzC0KDhAoy7KlaRsyOsZnT97Nsa3u0o= +github.com/cilium/lumberjack/v2 v2.3.0/go.mod h1:yfbtPGmg4i//5oEqzaMxDqSWqgfZFmMoV70Mc2k6v0A= github.com/cilium/proxy v0.0.0-20231031145409-f19708f3d018 h1:R/QlThqx099hS6req1k2Q87fvLSRgCEicQGate9vxO4= github.com/cilium/proxy v0.0.0-20231031145409-f19708f3d018/go.mod h1:p044XccCmONGIUbx3bJ7qvHXK0RcrdvIvbTGiu/RjUA= +github.com/cilium/stream v0.0.0-20240226091623-f979d32855f8 h1:j6VF1s6gz3etRH5ObCr0UUyJblP9cK5fbgkQTz8fTRA= +github.com/cilium/stream v0.0.0-20240226091623-f979d32855f8/go.mod h1:/e83AwqvNKpyg4n3C41qmnmj1x2G9DwzI+jb7GkF4lI= +github.com/cilium/workerpool v1.2.0 h1:Wc2iOPTvCgWKQXeq4L5tnx4QFEI+z5q1+bSpSS0cnAY= +github.com/cilium/workerpool v1.2.0/go.mod h1:GOYJhwlnIjR+jWSDNBb5kw47G1H/XA9X4WOBpgr4pQU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -195,11 +206,13 @@ github.com/containerd/ttrpc v1.2.3 h1:4jlhbXIGvijRtNC8F/5CpuJZ7yKOBFGFOOXg1bkISz github.com/containerd/ttrpc v1.2.3/go.mod h1:ieWsXucbb8Mj9PH0rXCw1i8IunRbbAiDkpXkbfflWBM= github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4= github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= +github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl31EQbXALQ= +github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= @@ -241,8 +254,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= -github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= -github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= +github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= @@ -263,6 +276,7 @@ github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09 github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= @@ -284,42 +298,32 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= -github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= -github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.4 h1:unTcVm6PispJsMECE3zWgvG4xTiKda1LIR5rCRWLG6M= -github.com/go-openapi/errors v0.20.4/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= -github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= -github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= -github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= -github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= -github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= -github.com/go-openapi/runtime v0.26.2 h1:elWyB9MacRzvIVgAZCBJmqTi7hBzU0hlKD4IvfX0Zl0= -github.com/go-openapi/runtime v0.26.2/go.mod h1:O034jyRZ557uJKzngbMDJXkcKJVzXJiymdSfgejrcRw= -github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/spec v0.20.11 h1:J/TzFDLTt4Rcl/l1PmyErvkqlJDncGvPTMnCI39I4gY= -github.com/go-openapi/spec v0.20.11/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= -github.com/go-openapi/strfmt v0.21.9 h1:LnEGOO9qyEC1v22Bzr323M98G13paIUGPU7yeJtG9Xs= -github.com/go-openapi/strfmt v0.21.9/go.mod h1:0k3v301mglEaZRJdDDGSlN6Npq4VMVU69DE0LUyf7uA= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.10 h1:4y86NVn7Z2yYd6pfS4Z+Nyh3aAUL3Nul+LMbhFKy0gA= -github.com/go-openapi/swag v0.22.10/go.mod h1:Cnn8BYtRlx6BNE3DPN86f/xkapGIcLWzh3CLEb4C1jI= -github.com/go-openapi/validate v0.22.3 h1:KxG9mu5HBRYbecRb37KRCihvGGtND2aXziBAv0NNfyI= -github.com/go-openapi/validate v0.22.3/go.mod h1:kVxh31KbfsxU8ZyoHaDbLBWU5CnMdqBUEtadQ2G4d5M= +github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= +github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= +github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= +github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= +github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= +github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ= +github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= +github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= +github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= @@ -348,6 +352,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 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= @@ -358,11 +363,12 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -390,8 +396,13 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= +github.com/google/gops v0.3.27 h1:BDdWfedShsBbeatZ820oA4DbVOC8yJ4NI8xAlDFWfgI= +github.com/google/gops v0.3.27/go.mod h1:lYqabmfnq4Q6UumWNx96Hjup5BDAVc8zmfIy0SkNCSk= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg= +github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= 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.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -429,9 +440,11 @@ github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVH github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix/v2 v2.1.0 h1:CUW5RYIcysz+D3B+l1mDeXrQ7fUvGGCwJfdASSzbrfo= +github.com/hashicorp/go-immutable-radix/v2 v2.1.0/go.mod h1:hgdqLXA4f6NIjRVisM1TJ9aOJVNRqKZj+xDGF6m7PBw= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= -github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs= +github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= @@ -440,15 +453,15 @@ github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-sockaddr v1.0.5 h1:dvk7TIXCZpmfOlM+9mlcrWmWjw/wlKT+VDq2wMvfPJU= +github.com/hashicorp/go-sockaddr v1.0.5/go.mod h1:uoUUmtwU7n9Dv3O4SNLeFvg0SxQ3lyjsj6+CCykpaxI= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= @@ -466,6 +479,7 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= @@ -507,7 +521,6 @@ github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -532,13 +545,10 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/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/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/mackerelio/go-osstat v0.2.4 h1:qxGbdPkFo65PXOb/F/nhDKpF2nGmGaCFDLXoZjJTtUs= +github.com/mackerelio/go-osstat v0.2.4/go.mod h1:Zy+qzGdZs3A9cuIqmgbJvwbmLQH9dJvtio5ZjJTbdlQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -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/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= @@ -590,8 +600,9 @@ github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8Ku github.com/microsoft/ApplicationInsights-Go v0.4.4 h1:G4+H9WNs6ygSCe6sUyxRc2U81TI5Es90b2t/MwX5KqY= github.com/microsoft/ApplicationInsights-Go v0.4.4/go.mod h1:fKRUseBqkw6bDiXTs3ESTiU/4YTIHsQS4W3fP2ieF4U= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= +github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= @@ -601,8 +612,6 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= @@ -635,7 +644,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -643,14 +651,21 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -686,8 +701,6 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -734,10 +747,8 @@ github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71e github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shirou/gopsutil/v3 v3.23.2 h1:PAWSuiAszn7IhPMBtXsbSCafej7PqUOvY6YywlQUExU= -github.com/shirou/gopsutil/v3 v3.23.2/go.mod h1:gv0aQw33GLo3pG8SiWKiQrbDzbRY1K80RyZJ7V4Th1M= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -752,8 +763,8 @@ github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNo github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= @@ -768,7 +779,6 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= @@ -783,20 +793,18 @@ github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSW github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tedsuo/ifrit v0.0.0-20180802180643-bea94bb476cc/go.mod h1:eyZnKCc955uh98WQvzOm0dgAeLnf2O0Rz0LPoC5ze+0= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= -github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= -github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= -github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= -github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= +github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/vishvananda/netlink v1.2.1-beta.2.0.20240524165444-4d4ba1473f21 h1:tcHUxOT8j/R+0S+A1j8D2InqguXFNxAiij+8QFOlX7Y= github.com/vishvananda/netlink v1.2.1-beta.2.0.20240524165444-4d4ba1473f21/go.mod h1:whJevzBpTrid75eZy99s3DqCmy05NfibNaF2Ol5Ox5A= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= -github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -806,28 +814,25 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= -github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +go.etcd.io/etcd v3.3.27+incompatible h1:5hMrpf6REqTHV2LW2OclNpRtxI0k9ZplMemJsMSWju0= +go.etcd.io/etcd v3.3.27+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= go.etcd.io/etcd/api/v3 v3.5.12 h1:W4sw5ZoU2Juc9gBWuLk5U6fHfNVyY1WC5g9uiXZio/c= go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= go.etcd.io/etcd/client/pkg/v3 v3.5.12 h1:EYDL6pWwyOsylrQyLp2w+HkQ46ATiOvoEdMarindU2A= go.etcd.io/etcd/client/pkg/v3 v3.5.12/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4= go.etcd.io/etcd/client/v3 v3.5.12 h1:v5lCPXn1pf1Uu3M4laUE2hp/geOTc5uPcYYsNe1lDxg= go.etcd.io/etcd/client/v3 v3.5.12/go.mod h1:tSbBCakoWmmddL+BKVAJHa9km+O/E+bumDe9mSbPiqw= -go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= -go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk= -go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo= +go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= +go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= @@ -836,8 +841,8 @@ go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 h1:FyjCyI9jVEfqhUh2MoSkmolPjfh5fp2hnV0b0irxH4Q= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY= go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= @@ -848,16 +853,19 @@ go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lI go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.starlark.net v0.0.0-20230814145427-12f4cb8177e4 h1:Ydko8M6UfXgvSpGOnbAjRMQDIvBheUsjBjkm6Azcpf4= go.starlark.net v0.0.0-20230814145427-12f4cb8177e4/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -866,15 +874,14 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/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-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 h1:6R2FC06FonbXQ8pK11/PDFY6N6LWlf9KlzibaCapmqc= +golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -899,6 +906,7 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -907,6 +915,7 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -942,23 +951,26 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/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-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1000,7 +1012,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= @@ -1016,6 +1027,7 @@ golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= @@ -1035,8 +1047,8 @@ google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJ google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 h1:rIo7ocm2roD9DcFIX67Ym8icoGCKSARAiPljFhh5suQ= google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c h1:lfpJ/2rWPa/kJgxyyXM8PrNnfCzcmxJ265mADgwmvLI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -1054,6 +1066,7 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= @@ -1061,7 +1074,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= @@ -1082,8 +1094,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= diff --git a/init/retina/main_linux.go b/init/retina/main_linux.go index 70152b579..02a351472 100644 --- a/init/retina/main_linux.go +++ b/init/retina/main_linux.go @@ -5,6 +5,7 @@ package main import ( "github.com/microsoft/retina/pkg/bpf" + "github.com/microsoft/retina/pkg/ciliumfs" "github.com/microsoft/retina/pkg/log" "github.com/microsoft/retina/pkg/telemetry" "go.uber.org/zap" @@ -40,4 +41,7 @@ func main() { // Setup BPF bpf.Setup(l) + + // Setup CiliumFS. + ciliumfs.Setup(l) } diff --git a/operator/main.go b/operator/main.go index 6a1ad6e72..d9eea22ff 100644 --- a/operator/main.go +++ b/operator/main.go @@ -44,7 +44,7 @@ import ( metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" retinav1alpha1 "github.com/microsoft/retina/crd/api/v1alpha1" - deploy "github.com/microsoft/retina/deploy" + deploy "github.com/microsoft/retina/deploy/legacy" "github.com/microsoft/retina/operator/cache" config "github.com/microsoft/retina/operator/config" captureUtils "github.com/microsoft/retina/pkg/capture/utils" diff --git a/pkg/ciliumfs/setup_linux.go b/pkg/ciliumfs/setup_linux.go new file mode 100644 index 000000000..0a79a9aba --- /dev/null +++ b/pkg/ciliumfs/setup_linux.go @@ -0,0 +1,30 @@ +package ciliumfs + +import ( + "os" + + "go.uber.org/zap" +) + +const ciliumDir = "/var/run/cilium" + +func Setup(l *zap.Logger) { + // Create /var/run/cilium directory. + fp, err := os.Stat(ciliumDir) + if err != nil { + l.Warn("Failed to stat directory", zap.String("dir path", ciliumDir), zap.Error(err)) + if os.IsNotExist(err) { + l.Info("Directory does not exist", zap.String("dir path", ciliumDir), zap.Error(err)) + // Path does not exist. Create it. + err = os.MkdirAll("/var/run/cilium", 0o755) //nolint:gomnd // 0o755 is the permission mode. + if err != nil { + l.Error("Failed to create directory", zap.String("dir path", ciliumDir), zap.Error(err)) + l.Panic("Failed to create directory", zap.String("dir path", ciliumDir), zap.Error(err)) + } + } else { + // Some other error. Return. + l.Panic("Failed to stat directory", zap.String("dir path", ciliumDir), zap.Error(err)) + } + } + l.Info("Created directory", zap.String("dir path", ciliumDir), zap.Any("file", fp)) +} diff --git a/pkg/config/hubble_config_linux.go b/pkg/config/hubble_config_linux.go new file mode 100644 index 000000000..8f558c0bd --- /dev/null +++ b/pkg/config/hubble_config_linux.go @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +package config + +import ( + "path/filepath" + + "github.com/cilium/cilium/pkg/hive/cell" + "github.com/cilium/cilium/pkg/option" + sharedconfig "github.com/microsoft/retina/pkg/shared/config" + "github.com/sirupsen/logrus" + "github.com/spf13/pflag" +) + +const configFileName string = "config.yaml" + +// RetinaHubbleConfig is a collection of configuration information needed by +// Retina-services for proper functioning. +type RetinaHubbleConfig struct { + // NOTE: metrics-bind-address and health-probe-bind-address should be used ONLY as container args (NOT in ConfigMap) to keep parity with non-enterprise Retina + MetricsBindAddress string + HealthProbeBindAddress string + + LeaderElection bool + ClusterName string // the name of the cluster (primarily used for TLS) +} + +// Flags is responsible for binding flags provided by the user to the various +// fields of the Config. +func (c RetinaHubbleConfig) Flags(flags *pflag.FlagSet) { + // NOTE: metrics-bind-address and health-probe-bind-address should be used ONLY as container args (NOT in ConfigMap) to keep parity with non-enterprise Retina + flags.String("metrics-bind-address", c.MetricsBindAddress, "The address the metric endpoint binds to.") + flags.String("health-probe-bind-address", c.HealthProbeBindAddress, "The address the probe endpoint binds to.") + + flags.Bool("leader-election", c.LeaderElection, "Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.") + flags.String("cluster-name", c.ClusterName, "name of the cluster") +} + +var ( + DefaultRetinaHubbleConfig = RetinaHubbleConfig{ + MetricsBindAddress: ":18000", + HealthProbeBindAddress: ":18001", + LeaderElection: false, + ClusterName: "default", + } + + DefaultRetinaConfig = &Config{ + EnableTelemetry: false, + EnabledPlugin: []string{"packetforward", "dropreason", "linuxutil", "dns"}, + EnablePodLevel: true, + LogLevel: "info", + BypassLookupIPOfInterest: true, + } + + Cell = cell.Module( + "agent-config", + "Agent Config", + + // Provide option.Config via hive so cells can depend on the agent config. + cell.Provide(func() *option.DaemonConfig { + return option.Config + }), + + cell.Config(DefaultRetinaHubbleConfig), + + cell.Provide(func(logger logrus.FieldLogger) (Config, error) { + retinaConfigFile := filepath.Join(option.Config.ConfigDir, configFileName) + conf, err := GetConfig(retinaConfigFile) + if err != nil { + logger.Error(err) + conf = DefaultRetinaConfig + } + logger.Info(conf) + return *conf, nil + }), + sharedconfig.Cell, + ) +) diff --git a/pkg/controllers/daemon/nodereconciler/cell_linux.go b/pkg/controllers/daemon/nodereconciler/cell_linux.go new file mode 100644 index 000000000..b70e16f5c --- /dev/null +++ b/pkg/controllers/daemon/nodereconciler/cell_linux.go @@ -0,0 +1,61 @@ +package nodereconciler + +import ( + "os" + + datapath "github.com/cilium/cilium/pkg/datapath/types" + "github.com/cilium/cilium/pkg/hive/cell" + "github.com/cilium/cilium/pkg/ipcache" + "github.com/cilium/cilium/pkg/node/types" + "github.com/microsoft/retina/pkg/config" + "github.com/microsoft/retina/pkg/log" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var Cell = cell.Module( + "node-controller", + "Node Controller monitors Node CRUD events", + cell.Provide(newNodeController), + // Setting up the node controller with the controller manager + cell.Invoke(func(l logrus.FieldLogger, nr *NodeReconciler, ctrlManager ctrl.Manager) error { + l.Info("Setting up node controller with manager") + if err := nr.SetupWithManager(ctrlManager); err != nil { + l.Errorf("failed to setup node controller with manager: %v", err) + return errors.Wrap(err, "failed to setup node controller with manager") + } + return nil + }), +) + +type params struct { + cell.In + + Config config.RetinaHubbleConfig + Logger logrus.FieldLogger + Client client.Client + IPCache *ipcache.IPCache +} + +func newNodeController(params params) (*NodeReconciler, error) { + // TODO: pubsub needs retina logger to already be enabled. Currently + // we are going to do this within infra module, in which during runtime this will throw a nil pointer err. + // see if we can avoid this? + opts := log.GetDefaultLogOpts() + _, err := log.SetupZapLogger(opts) + if err != nil { + return nil, errors.Wrap(err, "failed to setup logger") + } + n := &NodeReconciler{ + Client: params.Client, + clusterName: params.Config.ClusterName, + l: params.Logger.WithField("component", "node-controller"), + nodes: make(map[string]types.Node), + handlers: make(map[string]datapath.NodeHandler), + c: params.IPCache, + localNodeIP: os.Getenv("NODE_IP"), + } + return n, nil +} diff --git a/pkg/controllers/daemon/nodereconciler/node_controller_linux.go b/pkg/controllers/daemon/nodereconciler/node_controller_linux.go new file mode 100644 index 000000000..3f9f97bf5 --- /dev/null +++ b/pkg/controllers/daemon/nodereconciler/node_controller_linux.go @@ -0,0 +1,212 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +package nodereconciler + +import ( + "context" + "fmt" + "net" + "reflect" + "sync" + + "github.com/microsoft/retina/pkg/common/apiretry" + "github.com/sirupsen/logrus" + "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + errors "k8s.io/apimachinery/pkg/api/errors" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + datapath "github.com/cilium/cilium/pkg/datapath/types" + "github.com/cilium/cilium/pkg/identity" + ipc "github.com/cilium/cilium/pkg/ipcache" + "github.com/cilium/cilium/pkg/node/addressing" + "github.com/cilium/cilium/pkg/node/types" + "github.com/cilium/cilium/pkg/source" +) + +// NodeReconciler reconciles a Node object. +// This is pretty basic for now, need fine tuning, scale test, etc. +type NodeReconciler struct { + client.Client + + clusterName string + + l logrus.FieldLogger + handlers map[string]datapath.NodeHandler + nodes map[string]types.Node + c *ipc.IPCache + localNodeIP string + m sync.RWMutex +} + +// isNodeUpdated checks if the node has been updated. +// This is a simple check for labels and annotations +// being updated. Those are the only fields that are mutable. +// AKS specific for now. +func isNodeUpdated(n1, n2 types.Node) bool { + if !reflect.DeepEqual(n1.Labels, n2.Labels) { + return true + } + if !reflect.DeepEqual(n1.Annotations, n2.Annotations) { + return true + } + return false +} + +func (r *NodeReconciler) addNode(node *corev1.Node) { + r.m.Lock() + defer r.m.Unlock() + + addresses := []types.Address{} + for _, address := range node.Status.Addresses { + if address.Type == corev1.NodeInternalIP { + if ip := net.ParseIP(address.Address); ip != nil { + addresses = append(addresses, types.Address{ + IP: ip, + Type: addressing.NodeInternalIP, + }) + } + } + if address.Type == corev1.NodeExternalIP { + if ip := net.ParseIP(address.Address); ip != nil { + addresses = append(addresses, types.Address{ + IP: ip, + Type: addressing.NodeExternalIP, + }) + } + } + } + nd := types.Node{ + Name: node.Name, + IPAddresses: addresses, + Labels: node.Labels, + Annotations: node.Annotations, + } + nd.Cluster = r.clusterName + + // Check if the node already exists. + if curNode, ok := r.nodes[node.Name]; ok && !isNodeUpdated(curNode, nd) { + r.l.Debug("Node already exists", zap.String("Node", node.Name)) + } + + r.nodes[node.Name] = nd + + for _, handler := range r.handlers { + err := handler.NodeAdd(nd) + if err != nil { + r.l.Error("Failed to add Node to datapath handler", zap.Error(err), zap.String("handler", handler.Name()), zap.String("Node", node.Name)) + } + } + + id := identity.ReservedIdentityRemoteNode + // Check if the node is the local node. + for _, address := range nd.IPAddresses { + if address.IP.String() == r.localNodeIP { + id = identity.ReservedIdentityHost + } + } + for _, address := range nd.IPAddresses { + _, err := r.c.Upsert(address.ToString(), nil, 0, nil, ipc.Identity{ID: id, Source: source.Kubernetes}) //nolint:staticcheck // TODO(timraymond): no clear upgrade path + if err != nil { + r.l.Debug("failed to add IP to ipcache", zap.Error(err)) + } + r.l.Debug("Added IP to ipcache", zap.String("IP", address.ToString())) + } + + r.l.Info("Added Node", zap.String("Node", node.Name)) +} + +func (r *NodeReconciler) deleteNode(node *corev1.Node) { + r.m.Lock() + defer r.m.Unlock() + nd, ok := r.nodes[node.Name] + if !ok { + r.l.Warn("Node not found", zap.String("Node", node.Name)) + return + } + delete(r.nodes, node.Name) + + for _, handler := range r.handlers { + err := handler.NodeDelete(nd) + if err != nil { + r.l.Error("Failed to delete Node from datapath handler", zap.Error(err), zap.String("handler", handler.Name()), zap.String("Node", node.Name)) + } + } + for _, address := range nd.IPAddresses { + //nolint:staticcheck // TODO(timraymond): unhelpful deprecation notice: migration path unclear + r.c.Delete(address.ToString(), source.Kubernetes) + r.l.Debug("Deleted IP from ipcache", zap.String("IP", address.ToString())) + } + r.l.Debug("Deleted Node", zap.String("Node", node.Name)) +} + +func (r *NodeReconciler) Subscribe(nh datapath.NodeHandler) { + r.l.Debug("Subscribing to datapath handler") + r.m.RLock() + defer r.m.RUnlock() + + r.handlers[nh.Name()] = nh + for i := range r.nodes { + node := r.nodes[i] + if err := nh.NodeAdd(node); err != nil { + r.l.Error("Failed to add Node to datapath handler", zap.Error(err), zap.String("Node", node.Name)) + } + } +} + +func (r *NodeReconciler) Unsubscribe(nh datapath.NodeHandler) { + r.l.Debug("Unsubscribing from datapath handler") + r.m.Lock() + defer r.m.Unlock() + delete(r.handlers, nh.Name()) +} + +// +kubebuilder:rbac:groups="",resources=nodes,verbs=get;list +func (r *NodeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + r.l.Debug("Reconciling Node", zap.String("Node", req.NamespacedName.String())) + + node := &corev1.Node{} + if err := apiretry.Do( + func() error { + err := r.Client.Get(ctx, req.NamespacedName, node) + if err != nil { + return fmt.Errorf("getting node: %w", err) + } + return nil + }, + ); err != nil { + if errors.IsNotFound(err) { + // Node deleted since reconcile request received. + r.l.Debug("Node deleted since reconcile request received", zap.String("Node", req.NamespacedName.String())) + node.Name = req.Name + r.deleteNode(node) + return ctrl.Result{}, nil + } + r.l.Error("Failed to fetch Node", zap.Error(err), zap.String("Node", req.NamespacedName.String())) + return ctrl.Result{}, fmt.Errorf("retrieving node info: %w", err) + } + + if !node.ObjectMeta.DeletionTimestamp.IsZero() { + r.l.Info("Node is being deleted", zap.String("Node", req.Name)) + r.deleteNode(node) + return ctrl.Result{}, nil + } + + r.addNode(node) + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *NodeReconciler) SetupWithManager(mgr ctrl.Manager) error { + r.l.Debug("Setting up Node controller") + err := ctrl.NewControllerManagedBy(mgr). + For(&corev1.Node{}). + Complete(r) + if err != nil { + return fmt.Errorf("setting up node controller: %w", err) + } + return nil +} diff --git a/pkg/controllers/daemon/retinaendpoint/suite_test.go b/pkg/controllers/daemon/retinaendpoint/suite_test.go index c8243aa8f..54bc4bafb 100644 --- a/pkg/controllers/daemon/retinaendpoint/suite_test.go +++ b/pkg/controllers/daemon/retinaendpoint/suite_test.go @@ -54,7 +54,7 @@ var _ = BeforeSuite(func() { By("Bootstrapping test environment") testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("../../../..", "deploy/manifests/controller/helm/retina/crds")}, + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "..", "deploy", "legacy", "manifests", "controller", "helm", "retina", "crds")}, ErrorIfCRDPathMissing: true, } diff --git a/pkg/controllers/operator/capture/suite_test.go b/pkg/controllers/operator/capture/suite_test.go index a0d81d57e..1030639e7 100644 --- a/pkg/controllers/operator/capture/suite_test.go +++ b/pkg/controllers/operator/capture/suite_test.go @@ -48,7 +48,7 @@ var _ = BeforeSuite(func() { By("Bootstrapping test environment") testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("../../../..", "deploy/manifests/controller/helm/retina/crds")}, + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "..", "deploy", "legacy", "manifests", "controller", "helm", "retina", "crds")}, ErrorIfCRDPathMissing: true, } diff --git a/pkg/hubble/cell_linux.go b/pkg/hubble/cell_linux.go new file mode 100644 index 000000000..43e22c983 --- /dev/null +++ b/pkg/hubble/cell_linux.go @@ -0,0 +1,34 @@ +package hubble + +import ( + "github.com/cilium/cilium/pkg/hive/cell" + "github.com/cilium/workerpool" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +var Cell = cell.Module( + "retina-hubble", + "Retina-Hubble runs a Hubble server and observer within the Retina agent", + cell.Provide(newRetinaHubble), + cell.Invoke(func(l logrus.FieldLogger, lifecycle cell.Lifecycle, rh *RetinaHubble) { + var wp *workerpool.WorkerPool + lifecycle.Append(cell.Hook{ + OnStart: func(cell.HookContext) error { + wp = workerpool.New(1) + rh.log.Info("Starting Retina-Hubble") + if err := wp.Submit("retina-hubble", rh.launchWithDefaultOptions); err != nil { + rh.log.Fatalf("failed to submit retina-hubble to workerpool: %s", err) + return errors.Wrap(err, "failed to submit retina-hubble to workerpool") + } + return nil + }, + OnStop: func(cell.HookContext) error { + if err := wp.Close(); err != nil { + return errors.Wrap(err, "failed to close retina-hubble workerpool") + } + return nil + }, + }) + }), +) diff --git a/pkg/hubble/common/decoder_linux.go b/pkg/hubble/common/decoder_linux.go new file mode 100644 index 000000000..95a530b0f --- /dev/null +++ b/pkg/hubble/common/decoder_linux.go @@ -0,0 +1,93 @@ +package common + +import ( + "net/netip" + "os" + + "github.com/cilium/cilium/api/v1/flow" + "github.com/cilium/cilium/pkg/identity" + ipc "github.com/cilium/cilium/pkg/ipcache" + "github.com/cilium/cilium/pkg/labels" +) + +//go:generate go run github.com/golang/mock/mockgen@v1.6.0 -source decoder.go -destination=mocks/mock_types.go -package=mocks + +type EpDecoder interface { + Decode(ip netip.Addr) *flow.Endpoint + IsEndpointOnLocalHost(ip string) bool +} + +type epDecoder struct { + localHostIP string + ipcache *ipc.IPCache +} + +func NewEpDecoder(c *ipc.IPCache) *epDecoder { //nolint:revive // This is a factory function. + return &epDecoder{ + localHostIP: os.Getenv("NODE_IP"), + ipcache: c, + } +} + +func (e *epDecoder) Decode(ip netip.Addr) *flow.Endpoint { + ep := &flow.Endpoint{} + if metadata := e.ipcache.GetK8sMetadata(ip); metadata != nil { + ep.PodName = metadata.PodName + ep.Namespace = metadata.Namespace + } + id, ok := e.ipcache.LookupByIP(ip.String()) + if !ok { + // Default to world. + id = ipc.Identity{ID: identity.ReservedIdentityWorld} + } + ep.ID = id.ID.Uint32() + ep.Identity = id.ID.Uint32() + + switch id.ID { //nolint:exhaustive // We don't need all the cases. + case identity.ReservedIdentityHost: + ep.Labels = labels.LabelHost.GetModel() + case identity.ReservedIdentityKubeAPIServer: + ep.Labels = labels.LabelKubeAPIServer.GetModel() + case identity.ReservedIdentityRemoteNode: + ep.Labels = labels.LabelRemoteNode.GetModel() + case identity.ReservedIdentityWorld: + ep.Labels = labels.LabelWorld.GetModel() + default: + ep.Labels = e.ipcache.GetMetadataLabelsByIP(ip).GetModel() + } + + return ep +} + +func (e *epDecoder) endpointHostIP(ip string) string { + hostIP, _ := e.ipcache.GetHostIPCache(ip) + return hostIP.String() +} + +func (e *epDecoder) IsEndpointOnLocalHost(ip string) bool { + return e.localHostIP == e.endpointHostIP(ip) +} + +// type SvcDecoder interface { +// Decode(ip netip.Addr) *flow.Service +// } +// +// type svcDecoder struct { +// svccache *k8s.ServiceCache +// } +// +// func NewSvcDecoder(sc *k8s.ServiceCache) *svcDecoder { +// return &svcDecoder{ +// svccache: sc, +// } +// } +// +// func (s *svcDecoder) Decode(ip netip.Addr) *flow.Service { +// svc := &flow.Service{} +// +// if svcID, ok := s.svccache.GetServiceIDFromFrontendIP(ip.String()); ok { +// svc.Name = svcID.Name +// svc.Namespace = svcID.Namespace +// } +// return svc +// } diff --git a/pkg/hubble/hubble_linux.go b/pkg/hubble/hubble_linux.go new file mode 100644 index 000000000..b6a62f26c --- /dev/null +++ b/pkg/hubble/hubble_linux.go @@ -0,0 +1,247 @@ +package hubble + +import ( + "context" + "fmt" + + "github.com/cilium/cilium/api/v1/flow" + "github.com/cilium/cilium/pkg/crypto/certloader" + "github.com/cilium/cilium/pkg/hive/cell" + "github.com/cilium/cilium/pkg/hubble/container" + "github.com/cilium/cilium/pkg/hubble/metrics" + "github.com/cilium/cilium/pkg/hubble/monitor" + "github.com/cilium/cilium/pkg/hubble/observer" + "github.com/cilium/cilium/pkg/hubble/observer/observeroption" + "github.com/cilium/cilium/pkg/hubble/peer" + "github.com/cilium/cilium/pkg/hubble/peer/serviceoption" + "github.com/cilium/cilium/pkg/hubble/server" + "github.com/cilium/cilium/pkg/hubble/server/serveroption" + "github.com/cilium/cilium/pkg/ipcache" + "github.com/cilium/cilium/pkg/logging/logfields" + monitoragent "github.com/cilium/cilium/pkg/monitor/agent" + "github.com/cilium/cilium/pkg/option" + grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" + rnode "github.com/microsoft/retina/pkg/controllers/daemon/nodereconciler" + "github.com/microsoft/retina/pkg/hubble/parser" + "github.com/pkg/errors" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/sirupsen/logrus" + "go.uber.org/zap" +) + +type RetinaHubble struct { + log *logrus.Entry + client client.Client + monitorAgent monitoragent.Agent + ipc *ipcache.IPCache + nodeReconciler *rnode.NodeReconciler +} + +type hubbleParams struct { + cell.In + + Client client.Client + MonitorAgent monitoragent.Agent + IPCache *ipcache.IPCache + NodeReconciler *rnode.NodeReconciler + Log logrus.FieldLogger +} + +func newRetinaHubble(params hubbleParams) *RetinaHubble { + rh := &RetinaHubble{ + log: params.Log.WithField(logfields.LogSubsys, "retina-hubble"), + client: params.Client, + monitorAgent: params.MonitorAgent, + ipc: params.IPCache, + nodeReconciler: params.NodeReconciler, + } + rh.log.Logger.SetLevel(logrus.InfoLevel) + + return rh +} + +func (rh *RetinaHubble) defaultOptions() { + // Not final, will be updated later. + option.Config.HubblePreferIpv6 = false + option.Config.EnableHighScaleIPcache = false + option.Config.EnableHubbleOpenMetrics = false + + rh.log.Info("Starting Hubble with configuration", zap.Any("config", option.Config)) +} + +func (rh *RetinaHubble) getHubbleEventBufferCapacity() (container.Capacity, error) { + kap, err := container.NewCapacity(option.Config.HubbleEventBufferCapacity) + if err != nil { + return nil, fmt.Errorf("creating container capacity: %w", err) + } + return kap, nil +} + +func (rh *RetinaHubble) start(ctx context.Context) error { + var ( + localSrvOpts []serveroption.Option + remoteOpts []serveroption.Option + observerOpts []observeroption.Option + // parserOpts []parserOptions.Option + ) + + // ---------------------------------------------------------------------------------------------------------------------------------------------------- // + // Setup metrics. + grpcMetrics := grpc_prometheus.NewServerMetrics() + if err := metrics.EnableMetrics(rh.log, option.Config.HubbleMetricsServer, option.Config.HubbleMetrics, grpcMetrics, option.Config.EnableHubbleOpenMetrics); err != nil { + rh.log.Error("Failed to enable metrics", zap.Error(err)) + return fmt.Errorf("enabling metrics: %w", err) + } + + // ---------------------------------------------------------------------------------------------------------------------------------------------------- // + // Start the Hubble observer. + maxFlows, err := rh.getHubbleEventBufferCapacity() + if err != nil { + rh.log.Error("Failed to get Hubble event buffer capacity", zap.Error(err)) + return err + } + observerOpts = append(observerOpts, + observeroption.WithMaxFlows(maxFlows), + observeroption.WithMonitorBuffer(option.Config.HubbleEventQueueSize), + observeroption.WithOnDecodedFlowFunc(func(ctx context.Context, flow *flow.Flow) (bool, error) { + err = metrics.ProcessFlow(ctx, flow) + if err != nil { + rh.log.Error("Failed to process flow", zap.Any("flow", flow), zap.Error(err)) + return false, fmt.Errorf("processing flow: %w", err) + } + return false, nil + }), + ) + + // TODO: Replace with our custom parser. + payloadParser := parser.New(rh.log, rh.ipc) + + namespaceManager := observer.NewNamespaceManager() + go namespaceManager.Run(ctx) + + hubbleObserver, err := observer.NewLocalServer( + payloadParser, + namespaceManager, + rh.log, + observerOpts..., + ) + if err != nil { + rh.log.Error("Failed to create Hubble observer", zap.Error(err)) + return fmt.Errorf("starting local server: %w", err) + } + go hubbleObserver.Start() + + // Registering the Observer as consumer for monitor events. + rh.monitorAgent.RegisterNewConsumer(monitor.NewConsumer(hubbleObserver)) + + // ---------------------------------------------------------------------------------------------------------------------------------------------------- // + // Start the local server. + sockPath := "unix://" + option.Config.HubbleSocketPath + var peerServiceOptions []serviceoption.Option + var tlsCfg *certloader.WatchedServerConfig + + tlsPeerOpt := []serviceoption.Option{serviceoption.WithoutTLSInfo()} + tlsSrvOpt := serveroption.WithInsecure() + if !option.Config.HubbleTLSDisabled { + tlsCfg, err = rh.fetchTLSConfig(ctx) + if err != nil { + return errors.Wrap(err, "fetching TLS config") + } + + tlsPeerOpt = []serviceoption.Option{} + tlsSrvOpt = serveroption.WithServerTLS(tlsCfg) + } + peerServiceOptions = append(peerServiceOptions, tlsPeerOpt...) + + peerSvc := peer.NewService(rh.nodeReconciler, peerServiceOptions...) + localSrvOpts = append(localSrvOpts, + serveroption.WithUnixSocketListener(sockPath), + serveroption.WithHealthService(), + serveroption.WithObserverService(hubbleObserver), + serveroption.WithPeerService(peerSvc), + // The local server does not need to be guarded by TLS. + // It's only used for local communication. + serveroption.WithInsecure(), + ) + + localSrv, err := server.NewServer(rh.log, localSrvOpts...) + if err != nil { + rh.log.Error("Failed to initialize local Hubble server", zap.Error(err)) + return fmt.Errorf("starting peer service: %w", err) + } + rh.log.Info("Started local Hubble server", zap.String("address", sockPath)) + + go func() { + //nolint:govet // shadowing the err is intentional here + if err := localSrv.Serve(); err != nil { + rh.log.Error("Error while serving from local Hubble server", zap.Error(err)) + } + }() + // Cleanup the local socket on exit. + go func() { + <-ctx.Done() + localSrv.Stop() + peerSvc.Close() + rh.log.Info("Stopped local Hubble server") + }() + + // ---------------------------------------------------------------------------------------------------------------------------------------------------- // + // Start remote server. + address := option.Config.HubbleListenAddress + remoteOpts = append(remoteOpts, + serveroption.WithTCPListener(address), + serveroption.WithHealthService(), + serveroption.WithPeerService(peerSvc), + serveroption.WithObserverService(hubbleObserver), + tlsSrvOpt, + ) + + srv, err := server.NewServer(rh.log, remoteOpts...) + if err != nil { + rh.log.Error("Failed to initialize Hubble remote server", zap.Error(err)) + return fmt.Errorf("starting remote server: %w", err) + } + rh.log.Info("Started Hubble remote server", zap.String("address", address)) + + go func() { + if err := srv.Serve(); err != nil { + rh.log.Error("Error while serving from Hubble remote server", zap.Error(err)) + } + }() + // Cleanup the remote server on exit. + go func() { + <-ctx.Done() + srv.Stop() + rh.log.Info("Stopped Hubble remote server") + }() + return nil +} + +func (rh *RetinaHubble) fetchTLSConfig(ctx context.Context) (*certloader.WatchedServerConfig, error) { + tlsChan, err := certloader.FutureWatchedServerConfig(rh.log, option.Config.HubbleTLSClientCAFiles, option.Config.HubbleTLSCertFile, option.Config.HubbleTLSKeyFile) + if err != nil { + return nil, errors.Wrap(err, "retrieving TLS configuration future") + } + + rh.log.Info("waiting for TLS credentials") + select { + case t := <-tlsChan: + rh.log.Info("received TLS credentials") + + // ensure the certificate fetching stops when the context is canceled + go func() { + <-ctx.Done() + t.Stop() + }() + + return t, nil + case <-ctx.Done(): + return nil, errors.Wrap(ctx.Err(), "waiting for TLS credentials") + } +} + +func (rh *RetinaHubble) launchWithDefaultOptions(ctx context.Context) error { + rh.defaultOptions() + return rh.start(ctx) +} diff --git a/pkg/hubble/parser/layer34/parser_linux.go b/pkg/hubble/parser/layer34/parser_linux.go new file mode 100644 index 000000000..c094cddf5 --- /dev/null +++ b/pkg/hubble/parser/layer34/parser_linux.go @@ -0,0 +1,135 @@ +package layer34 + +import ( + "fmt" + "net/netip" + + "github.com/cilium/cilium/api/v1/flow" + "github.com/cilium/cilium/pkg/ipcache" + "github.com/microsoft/retina/pkg/hubble/common" + "github.com/microsoft/retina/pkg/utils" + "github.com/sirupsen/logrus" + "go.uber.org/zap" + "google.golang.org/protobuf/types/known/wrapperspb" +) + +type Parser struct { + l *logrus.Entry + ep common.EpDecoder +} + +func New(l *logrus.Entry, c *ipcache.IPCache) *Parser { + p := &Parser{ + l: l.WithField("subsys", "layer34"), + ep: common.NewEpDecoder(c), + } + // Log the localHostIP for debugging purposes. + return p +} + +// Decode enriches the flow with metadata from the IP cache and service cache. +func (p *Parser) Decode(f *flow.Flow) *flow.Flow { + if f == nil { + return nil + } + if f.GetIP() == nil { + p.l.Warn("Failed to get IP from flow", zap.Any("flow", f)) + return f + } + sourceIP, err := netip.ParseAddr(f.GetIP().GetSource()) + if err != nil { + p.l.Warn("Failed to parse source IP", zap.Error(err)) + return f + } + destIP, err := netip.ParseAddr(f.GetIP().GetDestination()) + if err != nil { + p.l.Warn("Failed to parse destination IP", zap.Error(err)) + return f + } + + // Decode the flow's source and destination IPs to their respective endpoints. + f.Source = p.ep.Decode(sourceIP) + f.Destination = p.ep.Decode(destIP) + + // Add IsReply to flow. + p.decodeIsReply(f) + + // Add L34 Summary to flow. + p.decodeSummary(f) + + // Add TrafficDirection to flow. + p.decodeTrafficDirection(f) + + return f +} + +func (p *Parser) decodeSummary(f *flow.Flow) { + if f.GetVerdict() == flow.Verdict_DROPPED { + // Setting subtype to DROPPED for huuble cli. + if f.GetEventType() != nil { + f.GetEventType().SubType = int32(f.GetDropReasonDesc()) + //nolint:lll // long line is long + f.Summary = fmt.Sprintf("Drop Reason: %s\nNote: This reason is most accurate. Prefer over others while using Hubble CLI.", utils.DropReasonDescription(f)) // nolint:staticcheck // We need summary for now. + } + return + + } + + // Add Summary based off of L4 protocol. + // Needed for huuble cli. + if f.GetL4() != nil && f.GetL4().GetProtocol() != nil { + switch f.GetL4().GetProtocol().(type) { + case *flow.Layer4_TCP: + tcpFlags := f.GetL4().GetTCP().GetFlags() + if tcpFlags != nil { + f.Summary = "TCP Flags: " + tcpFlags.String() // nolint:staticcheck // We need summary for now. + } + case *flow.Layer4_UDP: + f.Summary = "UDP" // nolint:staticcheck // We need summary for now. + } + } +} + +// decodeIsReply sets the flow's IsReply field. +// Heuristic: If the flow has a TCP ACK flag, it is a reply. +// TODO: In future, the dataplane would need to maintain a contrack table +// to determine if a flow is a reply. +// Ref: https://github.com/cilium/cilium/blob/840cc579b7b5aac24ba00c4d8c8f1d10334882fa/bpf/lib/conntrack_map.h#L5 +func (p *Parser) decodeIsReply(f *flow.Flow) { + // Not applicable for DROPPED verdicts. + if f.GetVerdict() == flow.Verdict_DROPPED { + f.IsReply = nil + return + } + + if f.GetL4() != nil && f.GetL4().GetProtocol() != nil { + switch f.GetL4().GetProtocol().(type) { // nolint:gocritic + case *flow.Layer4_TCP: + tcpFlags := f.GetL4().GetTCP().GetFlags() + if tcpFlags != nil { + f.IsReply = &wrapperspb.BoolValue{Value: tcpFlags.GetACK()} + } + } + } +} + +// decodeTrafficDirection decodes the traffic direction of the flow. +// It is only required for DROPPED verdicts because dropreason bpf program +// cannot determine the traffic direction. We determine using the source endpoint's +// node IP. +// Note: If the source and destination are on the same node, then the traffic is outbound. +func (p *Parser) decodeTrafficDirection(f *flow.Flow) { + // Only required for DROPPED verdicts. + if f.GetVerdict() != flow.Verdict_DROPPED { + return + } + + // If the source EP's node is the same as the current node, then the traffic is outbound. + if p.ep.IsEndpointOnLocalHost(f.GetIP().GetSource()) { + f.TrafficDirection = flow.TrafficDirection_EGRESS + return + } + + // Default to ingress. + f.TrafficDirection = flow.TrafficDirection_INGRESS +} diff --git a/pkg/hubble/parser/parser_linux.go b/pkg/hubble/parser/parser_linux.go new file mode 100644 index 000000000..fd75d0fd2 --- /dev/null +++ b/pkg/hubble/parser/parser_linux.go @@ -0,0 +1,94 @@ +package parser + +import ( + "errors" + + "github.com/cilium/cilium/api/v1/flow" + v1 "github.com/cilium/cilium/pkg/hubble/api/v1" + observer "github.com/cilium/cilium/pkg/hubble/observer/types" + ipc "github.com/cilium/cilium/pkg/ipcache" + "github.com/microsoft/retina/pkg/hubble/parser/layer34" + "github.com/microsoft/retina/pkg/hubble/parser/seven" + "github.com/sirupsen/logrus" + "go.uber.org/zap" + "google.golang.org/protobuf/types/known/timestamppb" +) + +var ( + errV1Event = errors.New("failed to cast agent event to v1.Event") + errEnrich = errors.New("failed to enrich flow") + errEmptyPayload = errors.New("empty payload") + errUnknownPayload = errors.New("unknown payload") +) + +type Parser struct { + l logrus.FieldLogger + ipcache *ipc.IPCache + + l34 *layer34.Parser + l7 *seven.Parser +} + +func New(l *logrus.Entry, c *ipc.IPCache) *Parser { + return &Parser{ + l: l, + ipcache: c, + + l34: layer34.New(l, c), + l7: seven.New(l, c), + } +} + +func (p *Parser) Decode(monitorEvent *observer.MonitorEvent) (*v1.Event, error) { + switch monitorEvent.Payload.(type) { //nolint:gocritic + case *observer.AgentEvent: + payload := monitorEvent.Payload.(*observer.AgentEvent) + ev, ok := payload.Message.(*v1.Event) + if !ok { + return nil, errV1Event + } + f := p._decode(ev) + if f == nil { + return nil, errEnrich + } + ev.Event = f + ev.Timestamp = timestamppb.Now() + return ev, nil + case nil: + return nil, errEmptyPayload + default: + return nil, errUnknownPayload + } +} + +func (p *Parser) _decode(event *v1.Event) *flow.Flow { + if event == nil { + return nil + } + + // Enrich the event with the IP address of the source and destination. + // This is used to enrich the event with the source and destination + // node names. + f, ok := event.Event.(*flow.Flow) + if !ok { + p.l.Warn("Failed to cast event to flow", zap.Any("event", event.Event)) + return nil + } + if f == nil { + p.l.Warn("Failed to get flow from event", zap.Any("event", event)) + return nil + } + + // Decode the flow based on its type. + switch f.GetType() { //nolint:exhaustive // We only care about the known types. + case flow.FlowType_L3_L4: + f = p.l34.Decode(f) + case flow.FlowType_L7: + f = p.l7.Decode(f) + default: + p.l.Warn("Unknown flow type", zap.Any("flow", f)) + } + + p.l.Debug("Enriched flow", zap.Any("flow", f)) + return f +} diff --git a/pkg/hubble/parser/seven/parser_linux.go b/pkg/hubble/parser/seven/parser_linux.go new file mode 100644 index 000000000..69b562b1b --- /dev/null +++ b/pkg/hubble/parser/seven/parser_linux.go @@ -0,0 +1,146 @@ +package seven + +import ( + "fmt" + "net/netip" + "strings" + + "github.com/cilium/cilium/api/v1/flow" + "github.com/cilium/cilium/pkg/ipcache" + "github.com/google/gopacket/layers" + "github.com/microsoft/retina/pkg/hubble/common" + "github.com/sirupsen/logrus" + "go.uber.org/zap" +) + +type Parser struct { + l *logrus.Entry + ep common.EpDecoder +} + +func New(l *logrus.Entry, c *ipcache.IPCache) *Parser { + return &Parser{ + l: l.WithField("subsys", "seven"), + ep: common.NewEpDecoder(c), + } +} + +func (p *Parser) Decode(f *flow.Flow) *flow.Flow { + if f == nil { + return nil + } + + // Decode the flow's IP addresses to their respective endpoints. + p.decodeIP(f) + + // Decode the flow's L7 protocol. + l7 := f.GetL7() + if l7 == nil { + return f + } + + record := l7.GetRecord() + if record == nil { + return f + } + + switch record.(type) { + case *flow.Layer7_Dns: + return p.decodeDNS(f) + case *flow.Layer7_Http: + return p.decodeHTTP(f) + } + return f +} + +func (p *Parser) decodeIP(f *flow.Flow) { + if f == nil { + return + } + + // Decode the flow's source and destination IPs to their respective endpoints. + if f.GetIP() == nil { + p.l.Warn("Failed to get IP from flow", zap.Any("flow", f)) + return + } + sourceIP, err := netip.ParseAddr(f.GetIP().GetSource()) + if err != nil { + p.l.Warn("Failed to parse source IP", zap.Error(err)) + return + } + destIP, err := netip.ParseAddr(f.GetIP().GetDestination()) + if err != nil { + p.l.Warn("Failed to parse destination IP", zap.Error(err)) + return + } + + f.Source = p.ep.Decode(sourceIP) + f.Destination = p.ep.Decode(destIP) +} + +func (p *Parser) decodeDNS(f *flow.Flow) *flow.Flow { + l7 := f.GetL7() + if l7 == nil { + return f + } + + dns := l7.GetDns() + if dns != nil { + //nolint:staticcheck // TODO(timraymond): no good migration path documented + f.Summary = dnsSummary(dns, l7.GetType()) + } + + f.Verdict = flow.Verdict_FORWARDED + + return f +} + +func (p *Parser) decodeHTTP(f *flow.Flow) *flow.Flow { + l7 := f.GetL7() + if l7 == nil { + return f + } + + // TODO need to implemented + // noop for timebeing + + f.Verdict = flow.Verdict_FORWARDED + return f +} + +func dnsSummary(dns *flow.DNS, flowtype flow.L7FlowType) string { + if len(dns.GetQtypes()) == 0 { + return "" + } + qTypeStr := strings.Join(dns.GetQtypes(), ",") + + switch flowtype { //nolint:exhaustive // the other two types are "sample", and "unknown" which we can ignore + case flow.L7FlowType_REQUEST: + return fmt.Sprintf("DNS Query %s %s", dns.GetQuery(), qTypeStr) + case flow.L7FlowType_RESPONSE: + rcode := layers.DNSResponseCode(dns.GetRcode()) + + var answer string + if rcode != layers.DNSResponseCodeNoErr { + answer = fmt.Sprintf("RCode: %s", rcode) + } else { + parts := make([]string, 0) + + if len(dns.GetIps()) > 0 { + parts = append(parts, fmt.Sprintf("%q", strings.Join(dns.GetIps(), ","))) + } + + if len(dns.GetCnames()) > 0 { + parts = append(parts, fmt.Sprintf("CNAMEs: %q", strings.Join(dns.GetCnames(), ","))) + } + + answer = strings.Join(parts, " ") + } + + sourceType := "Query" + + return fmt.Sprintf("DNS Answer %s (%s %s %s)", answer, sourceType, dns.GetQuery(), qTypeStr) + } + + return "" +} diff --git a/pkg/k8s/apiserver_linux.go b/pkg/k8s/apiserver_linux.go new file mode 100644 index 000000000..31c4ab008 --- /dev/null +++ b/pkg/k8s/apiserver_linux.go @@ -0,0 +1,89 @@ +package k8s + +import ( + "github.com/cilium/cilium/pkg/hive/cell" + "github.com/cilium/cilium/pkg/identity" + "github.com/cilium/cilium/pkg/ipcache" + "github.com/cilium/cilium/pkg/source" + "github.com/microsoft/retina/pkg/common" + cc "github.com/microsoft/retina/pkg/controllers/cache" + "github.com/sirupsen/logrus" +) + +type params struct { + cell.In + + Logger logrus.FieldLogger + IPCache *ipcache.IPCache + Lifecycle cell.Lifecycle +} + +func newAPIServerEventHandler(p params) *APIServerEventHandler { + a := &APIServerEventHandler{ + c: p.IPCache, + l: p.Logger, + } + return a +} + +type APIServerEventHandler struct { + c *ipcache.IPCache + l logrus.FieldLogger +} + +func (a *APIServerEventHandler) handleAPIServerEvent(event interface{}) { + cacheEvent, ok := event.(*cc.CacheEvent) + if !ok { + a.l.WithField("Event", event).Warn("Received unknown event type") + return + } + switch cacheEvent.Type { //nolint:exhaustive // the default case adequately handles these + case cc.EventTypeAddAPIServerIPs: + apiserverObj, ok := cacheEvent.Obj.(*common.APIServerObject) + if !ok { + a.l.WithField("Cache Event", cacheEvent).Warn("Received unknown event type") + return + } + ips := apiserverObj.IPs() + if len(ips) == 0 { + a.l.WithField("Cache Event", cacheEvent).Warn("Received empty API server IPs") + return + } + for _, ip := range ips { + //nolint:staticcheck // TODO(timraymond): unclear how to migrate this + _, err := a.c.Upsert(ip.String(), nil, 0, nil, ipcache.Identity{ID: identity.ReservedIdentityKubeAPIServer, Source: source.Kubernetes}) + if err != nil { + a.l.WithError(err).WithFields(logrus.Fields{ + "IP": ips[0].String(), + }).Error("Failed to add API server IPs to ipcache") + return + } + } + a.l.WithFields(logrus.Fields{ + "IP": ips[0].String(), + }).Info("Added API server IPs to ipcache") + case cc.EventTypeDeleteAPIServerIPs: + apiserverObj, ok := cacheEvent.Obj.(*common.APIServerObject) + if !ok { + a.l.WithField("Cache Event", cacheEvent).Warn("Received unknown event type") + return + } + ips := apiserverObj.IPs() + if len(ips) == 0 { + a.l.WithField("Cache Event", cacheEvent).Warn("Received empty API server IPs") + return + } + for _, ip := range ips { + //nolint:staticcheck // TODO(timraymond): unclear how to migrate this + a.c.Delete(ip.String(), source.Kubernetes) + } + a.l.WithFields(logrus.Fields{ + "IP": ips[0].String(), + }).Info("Deleted API server IPs from ipcache") + default: + a.l.WithFields(logrus.Fields{ + "Cache Event": cacheEvent, + "Type": cacheEvent.Type, + }).Warn("Received unknown cache event") + } +} diff --git a/pkg/k8s/cell_linux.go b/pkg/k8s/cell_linux.go new file mode 100644 index 000000000..22dbb2a9f --- /dev/null +++ b/pkg/k8s/cell_linux.go @@ -0,0 +1,138 @@ +package k8s + +import ( + "context" + + daemonk8s "github.com/cilium/cilium/daemon/k8s" + "github.com/cilium/cilium/pkg/hive/cell" + "github.com/cilium/cilium/pkg/identity/cache" + "github.com/cilium/cilium/pkg/ipcache" + ciliumk8s "github.com/cilium/cilium/pkg/k8s" + cilium_api_v2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2" + cilium_api_v2alpha1 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2alpha1" + "github.com/cilium/cilium/pkg/k8s/client" + "github.com/cilium/cilium/pkg/k8s/resource" + slim_corev1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/core/v1" + slim_networkingv1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/networking/v1" + "github.com/cilium/cilium/pkg/k8s/synced" + "github.com/cilium/cilium/pkg/k8s/types" + "github.com/cilium/cilium/pkg/k8s/watchers" + "github.com/cilium/cilium/pkg/node" + "github.com/cilium/cilium/pkg/option" + "github.com/microsoft/retina/pkg/common" + "github.com/microsoft/retina/pkg/pubsub" + "github.com/sirupsen/logrus" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var Cell = cell.Module( + "k8s-watcher", + "Kubernetes watchers needed by the agent", + + cell.Provide( + func(cell.Lifecycle, client.Clientset) (daemonk8s.LocalPodResource, error) { + return &fakeresource[*slim_corev1.Pod]{}, nil + }, + func() resource.Resource[*slim_corev1.Namespace] { + return &fakeresource[*slim_corev1.Namespace]{} + }, + func() daemonk8s.LocalNodeResource { + return &fakeresource[*slim_corev1.Node]{} + }, + func() daemonk8s.LocalCiliumNodeResource { + return &fakeresource[*cilium_api_v2.CiliumNode]{} + }, + func() resource.Resource[*slim_networkingv1.NetworkPolicy] { + return &fakeresource[*slim_networkingv1.NetworkPolicy]{} + }, + func() resource.Resource[*cilium_api_v2.CiliumNetworkPolicy] { + return &fakeresource[*cilium_api_v2.CiliumNetworkPolicy]{} + }, + func() resource.Resource[*cilium_api_v2.CiliumClusterwideNetworkPolicy] { + return &fakeresource[*cilium_api_v2.CiliumClusterwideNetworkPolicy]{} + }, + func() resource.Resource[*cilium_api_v2alpha1.CiliumCIDRGroup] { + return &fakeresource[*cilium_api_v2alpha1.CiliumCIDRGroup]{} + }, + func() resource.Resource[*cilium_api_v2alpha1.CiliumEndpointSlice] { + return &fakeresource[*cilium_api_v2alpha1.CiliumEndpointSlice]{} + }, + func() resource.Resource[*types.CiliumEndpoint] { + return &fakeresource[*types.CiliumEndpoint]{} + }, + func() resource.Resource[*cilium_api_v2.CiliumNode] { + return &fakeresource[*cilium_api_v2.CiliumNode]{} + }, + func() daemonk8s.ServiceNonHeadless { + return &fakeresource[*slim_corev1.Service]{} + }, + func() daemonk8s.EndpointsNonHeadless { + return &fakeresource[*ciliumk8s.Endpoints]{} + }, + func() watchers.WatcherConfiguration { + return &watcherconfig{} + }, + ), + + cell.Provide(func(lc cell.Lifecycle, cs client.Clientset) (resource.Resource[*ciliumk8s.Endpoints], error) { + //nolint:wrapcheck // a wrapped error here is of dubious value + return ciliumk8s.EndpointsResource(lc, ciliumk8s.Config{ + EnableK8sEndpointSlice: true, + K8sServiceProxyName: "", + }, cs) + }), + + cell.Provide(func(lc cell.Lifecycle, cs client.Clientset) (resource.Resource[*slim_corev1.Service], error) { + //nolint:wrapcheck // a wrapped error here is of dubious value + return ciliumk8s.ServiceResource( + lc, + ciliumk8s.Config{ + EnableK8sEndpointSlice: false, + K8sServiceProxyName: "", + }, + cs, + func(*metav1.ListOptions) {}, + ) + }), + + // Provide everything needed for the watchers. + cell.Provide(func() *ipcache.IPCache { + iao := &identityAllocatorOwner{} + idAlloc := &cachingIdentityAllocator{ + cache.NewCachingIdentityAllocator(iao), + nil, + } + return ipcache.NewIPCache(&ipcache.Configuration{ + Context: context.Background(), + IdentityAllocator: idAlloc, + PolicyHandler: &policyhandler{}, + DatapathHandler: &datapathhandler{}, + }) + }), + + cell.Provide(func() *ciliumk8s.ServiceCache { + option.Config.K8sServiceCacheSize = 1000 + return ciliumk8s.NewServiceCache(&nodeaddressing{}) + }), + + cell.Provide(func() node.LocalNodeSynchronizer { + return &nodeSynchronizer{ + l: logrus.WithField("module", "node-synchronizer"), + } + }), + node.LocalNodeStoreCell, + + synced.Cell, + + cell.Provide(NewWatcher), + + cell.Provide(newAPIServerEventHandler), + cell.Invoke(func(a *APIServerEventHandler) { + ps := pubsub.New() + fn := pubsub.CallBackFunc(a.handleAPIServerEvent) + uuid := ps.Subscribe(common.PubSubAPIServer, &fn) + a.l.WithFields(logrus.Fields{ + "uuid": uuid, + }).Info("Subscribed to PubSub APIServer") + }), +) diff --git a/pkg/k8s/local_node_synchronizer_linux.go b/pkg/k8s/local_node_synchronizer_linux.go new file mode 100644 index 000000000..4ce5402d9 --- /dev/null +++ b/pkg/k8s/local_node_synchronizer_linux.go @@ -0,0 +1,43 @@ +package k8s + +import ( + "context" + "net" + "os" + + "github.com/cilium/cilium/pkg/node" + "github.com/cilium/cilium/pkg/node/addressing" + nodetypes "github.com/cilium/cilium/pkg/node/types" + "github.com/sirupsen/logrus" +) + +type nodeSynchronizer struct { + l *logrus.Entry +} + +func (n *nodeSynchronizer) InitLocalNode(_ context.Context, ln *node.LocalNode) error { + if ln == nil { + n.l.Warn("Local node is nil") + return nil + } + nodeIP := os.Getenv("NODE_IP") + if nodeIP == "" { + n.l.Warn("Failed to get NODE_IP") + return nil + } + ln.Node = nodetypes.Node{ + IPAddresses: []nodetypes.Address{ + { + IP: net.ParseIP(nodeIP), + Type: addressing.NodeExternalIP, + }, + }, + Labels: make(map[string]string), + Annotations: make(map[string]string), + } + return nil +} + +func (n *nodeSynchronizer) SyncLocalNode(context.Context, *node.LocalNodeStore) { + n.l.Info("SyncLocalNode called") +} diff --git a/pkg/k8s/placeholders_linux.go b/pkg/k8s/placeholders_linux.go new file mode 100644 index 000000000..7ef457901 --- /dev/null +++ b/pkg/k8s/placeholders_linux.go @@ -0,0 +1,136 @@ +package k8s + +import ( + "context" + "net" + "net/netip" + "sync" + "time" + + datapathtypes "github.com/cilium/cilium/pkg/datapath/types" + "github.com/cilium/cilium/pkg/endpoint" + "github.com/cilium/cilium/pkg/identity" + "github.com/cilium/cilium/pkg/identity/cache" + "github.com/cilium/cilium/pkg/ipcache" + "github.com/cilium/cilium/pkg/k8s/resource" + slim_corev1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/core/v1" + nodetypes "github.com/cilium/cilium/pkg/node/types" + k8sRuntime "k8s.io/apimachinery/pkg/runtime" +) + +type fakeresource[T k8sRuntime.Object] struct{} + +func (f *fakeresource[T]) Events(_ context.Context, _ ...resource.EventsOpt) <-chan resource.Event[T] { + return make(<-chan resource.Event[T]) +} + +func (f *fakeresource[T]) Store(_ context.Context) (resource.Store[T], error) { + return nil, nil +} + +func (f *fakeresource[T]) Observe(context.Context, func(resource.Event[T]), func(error)) { +} + +type watcherconfig struct { + internalconfigs +} + +type internalconfigs struct{} + +func (w *internalconfigs) K8sNetworkPolicyEnabled() bool { + return false +} + +func (w *internalconfigs) K8sIngressControllerEnabled() bool { + return false +} + +func (w *internalconfigs) K8sGatewayAPIEnabled() bool { + return false +} + +type epmgr struct{} + +func (e *epmgr) LookupCEPName(string) *endpoint.Endpoint { + return nil +} + +func (e *epmgr) GetEndpoints() []*endpoint.Endpoint { + return nil +} + +func (e *epmgr) GetHostEndpoint() *endpoint.Endpoint { + return nil +} + +func (e *epmgr) GetEndpointsByPodName(string) []*endpoint.Endpoint { + return nil +} + +func (e *epmgr) WaitForEndpointsAtPolicyRev(context.Context, uint64) error { + return nil +} + +func (e *epmgr) UpdatePolicyMaps(context.Context, *sync.WaitGroup) *sync.WaitGroup { + return nil +} + +type nodediscovermgr struct{} + +func (n *nodediscovermgr) WaitForLocalNodeInit() {} + +func (n *nodediscovermgr) NodeDeleted(nodetypes.Node) {} + +func (n *nodediscovermgr) NodeUpdated(nodetypes.Node) {} + +func (n *nodediscovermgr) ClusterSizeDependantInterval(time.Duration) time.Duration { + return time.Duration(0) +} + +type cgrpmgr struct{} + +func (c *cgrpmgr) OnAddPod(*slim_corev1.Pod) {} + +func (c *cgrpmgr) OnUpdatePod(*slim_corev1.Pod, *slim_corev1.Pod) {} + +func (c *cgrpmgr) OnDeletePod(*slim_corev1.Pod) {} + +type nodeaddressing struct{} + +func (n *nodeaddressing) IPv6() datapathtypes.NodeAddressingFamily { + return nil +} + +func (n *nodeaddressing) IPv4() datapathtypes.NodeAddressingFamily { + return nil +} + +type identityAllocatorOwner struct{} + +func (i *identityAllocatorOwner) UpdateIdentities(cache.IdentityCache, cache.IdentityCache) {} + +func (i *identityAllocatorOwner) GetNodeSuffix() string { + return "" +} + +type cachingIdentityAllocator struct { + *cache.CachingIdentityAllocator + ipcache *ipcache.IPCache +} + +func (c cachingIdentityAllocator) AllocateCIDRsForIPs([]net.IP, map[netip.Prefix]*identity.Identity) ([]*identity.Identity, error) { + return nil, nil +} + +func (c cachingIdentityAllocator) ReleaseCIDRIdentitiesByID(context.Context, []identity.NumericIdentity) { +} + +type policyhandler struct{} + +func (p *policyhandler) UpdateIdentities(cache.IdentityCache, cache.IdentityCache, *sync.WaitGroup) {} + +type datapathhandler struct{} + +func (d *datapathhandler) UpdatePolicyMaps(context.Context, *sync.WaitGroup) *sync.WaitGroup { + return &sync.WaitGroup{} +} diff --git a/pkg/k8s/watcher_linux.go b/pkg/k8s/watcher_linux.go new file mode 100644 index 000000000..3bdc50acb --- /dev/null +++ b/pkg/k8s/watcher_linux.go @@ -0,0 +1,94 @@ +package k8s + +import ( + "context" + "sync" + "time" + + agentK8s "github.com/cilium/cilium/daemon/k8s" + "github.com/cilium/cilium/pkg/hive/cell" + "github.com/cilium/cilium/pkg/ipcache" + "github.com/cilium/cilium/pkg/k8s" + "github.com/cilium/cilium/pkg/k8s/client" + "github.com/cilium/cilium/pkg/k8s/synced" + "github.com/cilium/cilium/pkg/k8s/watchers" + "github.com/cilium/cilium/pkg/logging" + "github.com/cilium/cilium/pkg/logging/logfields" + "github.com/cilium/cilium/pkg/option" +) + +const ( + K8sAPIGroupCiliumEndpointV2 = "cilium/v2::CiliumEndpoint" +) + +var ( + once sync.Once + w *watchers.K8sWatcher + logger = logging.DefaultLogger.WithField(logfields.LogSubsys, "k8s-watcher") + // k8sResources = []string{K8sAPIGroupCiliumEndpointV2, resources.K8sAPIGroupServiceV1Core} + k8sResources = []string{} +) + +type watcherParams struct { + cell.In + + Lifecycle cell.Lifecycle + C client.Clientset + R agentK8s.Resources + IPcache *ipcache.IPCache + SvcCache *k8s.ServiceCache + Wcfg watchers.WatcherConfiguration + ResourcesSynced *synced.Resources + APIGroups *synced.APIGroups +} + +func NewWatcher(params watcherParams) (*watchers.K8sWatcher, error) { + return newInstance(params.C, params.ResourcesSynced, params.APIGroups, params.R, params.IPcache, params.SvcCache, params.Wcfg) +} + +func newInstance( + c client.Clientset, + resourcesSynced *synced.Resources, + apiGroups *synced.APIGroups, + r agentK8s.Resources, + ipc *ipcache.IPCache, + svcCache *k8s.ServiceCache, + wcfg watchers.WatcherConfiguration, +) (*watchers.K8sWatcher, error) { + option.Config.BGPAnnounceLBIP = false + once.Do(func() { + w = watchers.NewK8sWatcher( + c, // clientset + resourcesSynced, + apiGroups, + &epmgr{}, // endpointManager + &nodediscovermgr{}, // nodeDiscoverManager + nil, // policyManager + nil, // policyRepository + nil, // svcManager + nil, // Datapath + nil, // redirectPolicyManager + nil, // bgpSpeakerManager + wcfg, // WatcherConfiguration + ipc, // ipcacheManager + &cgrpmgr{}, // cgroupManager + r, // agentK8s.Resources + svcCache, // *k8s.ServiceCache + nil, // bandwidth.Manager + ) + }) + return w, nil +} + +func Start(ctx context.Context, k *watchers.K8sWatcher) { + logger.Info("Starting Kubernetes watcher") + + option.Config.K8sSyncTimeout = 3 * time.Minute //nolint:gomnd // this duration is self-explanatory + syncdCache := make(chan struct{}) + go k.InitK8sSubsystem(ctx, k8sResources, []string{}, syncdCache) + logger.WithField("k8s resources", k8sResources).Info("Kubernetes watcher started, will wait for cache sync") + + // Wait for K8s watcher to sync. If doesn't complete in 3 minutes, causes fatal error. + <-syncdCache + logger.Info("Kubernetes watcher synced") +} diff --git a/pkg/managers/pluginmanager/cells_linux.go b/pkg/managers/pluginmanager/cells_linux.go new file mode 100644 index 000000000..3008f2cd9 --- /dev/null +++ b/pkg/managers/pluginmanager/cells_linux.go @@ -0,0 +1,83 @@ +package pluginmanager + +import ( + "context" + "sync" + + "github.com/cilium/cilium/pkg/hive/cell" + v1 "github.com/cilium/cilium/pkg/hubble/api/v1" + "github.com/microsoft/retina/pkg/config" + "github.com/microsoft/retina/pkg/metrics" + "github.com/microsoft/retina/pkg/plugin/api" + "github.com/microsoft/retina/pkg/telemetry" + "github.com/sirupsen/logrus" +) + +const ( + // Default external channel size for events + // This is the default size of the channel that is used to send events from plugins to hubble + DefaultExternalEventChannelSize = 10000 +) + +var Cell = cell.Module( + "pluginmanager", + "Manages Retina eBPF plugins", + cell.Provide(func() chan *v1.Event { + return make(chan *v1.Event, DefaultExternalEventChannelSize) + }), + cell.Provide(newPluginManager), +) + +type pluginManagerParams struct { + cell.In + + Log logrus.FieldLogger + Lifecycle cell.Lifecycle + Config config.Config + Telemetry telemetry.Telemetry + EventChan chan *v1.Event +} + +func newPluginManager(params pluginManagerParams) (*PluginManager, error) { + logger := params.Log.WithField("module", "pluginmanager") + + // Enable Metrics in retina + metrics.InitializeMetrics() + + enabledPlugins := []api.PluginName{} + for _, pluginName := range params.Config.EnabledPlugin { + enabledPlugins = append(enabledPlugins, api.PluginName(pluginName)) + } + pluginMgr, err := NewPluginManager(¶ms.Config, params.Telemetry, enabledPlugins...) + if err != nil { + return &PluginManager{}, err + } + + pmCtx, cancelCtx := context.WithCancel(context.Background()) + // Setup the event channel to be used by hubble + pluginMgr.SetupChannel(params.EventChan) + + var wg sync.WaitGroup + params.Lifecycle.Append(cell.Hook{ + OnStart: func(cell.HookContext) error { + var err error + wg.Add(1) + go func() { + defer wg.Done() + err = pluginMgr.Start(pmCtx) + if err != nil { + logger.WithError(err).Fatal("failed to start plugin manager") + } + }() + + return err + }, + OnStop: func(cell.HookContext) error { + cancelCtx() + pluginMgr.Stop() + wg.Wait() + return nil + }, + }) + return pluginMgr, nil +} diff --git a/pkg/monitoragent/cell_linux.go b/pkg/monitoragent/cell_linux.go new file mode 100644 index 000000000..ac2428f6f --- /dev/null +++ b/pkg/monitoragent/cell_linux.go @@ -0,0 +1,92 @@ +package monitoragent + +import ( + "context" + "fmt" + + "github.com/cilium/cilium/pkg/common" + "github.com/cilium/cilium/pkg/defaults" + "github.com/cilium/cilium/pkg/hive/cell" + "github.com/cilium/cilium/pkg/logging" + "github.com/cilium/cilium/pkg/logging/logfields" + ciliumagent "github.com/cilium/cilium/pkg/monitor/agent" + "github.com/cilium/cilium/pkg/monitor/agent/consumer" + "github.com/cilium/cilium/pkg/monitor/agent/listener" + "github.com/sirupsen/logrus" + "github.com/spf13/pflag" +) + +var ( + Cell = cell.Module( + "monitor-agent", + "Consumes the cilium events map and distributes those and other agent events", + + cell.Provide(newMonitorAgent), + cell.Config(defaultConfig), + ) + + log = logging.DefaultLogger.WithField(logfields.LogSubsys, "monitor-agent") +) + +type AgentConfig struct { + // EnableMonitor enables the monitor unix domain socket server + EnableMonitor bool + + // MonitorQueueSize is the size of the monitor event queue + MonitorQueueSize int +} + +var defaultConfig = AgentConfig{ + EnableMonitor: true, +} + +func (def AgentConfig) Flags(flags *pflag.FlagSet) { + flags.Bool("enable-monitor", def.EnableMonitor, "Enable the monitor unix domain socket server") + flags.Int("monitor-queue-size", 0, "Size of the event queue when reading monitor events") +} + +type agentParams struct { + cell.In + + Lifecycle cell.Lifecycle + Log logrus.FieldLogger + Config AgentConfig +} + +func newMonitorAgent(params agentParams) ciliumagent.Agent { + ctx, cancel := context.WithCancel(context.Background()) + agent := &monitorAgent{ + ctx: ctx, + listeners: make(map[listener.MonitorListener]struct{}), + consumers: make(map[consumer.MonitorConsumer]struct{}), + perfReaderCancel: func() {}, // no-op to avoid doing null checks everywhere + } + + params.Lifecycle.Append(cell.Hook{ + OnStart: func(cell.HookContext) error { + var err error + if params.Config.EnableMonitor { + queueSize := params.Config.MonitorQueueSize + if queueSize == 0 { + queueSize = common.GetNumPossibleCPUs(log) * defaults.MonitorQueueSizePerCPU + if queueSize > defaults.MonitorQueueSizePerCPUMaximum { + queueSize = defaults.MonitorQueueSizePerCPUMaximum + } + } + + monitorErr := ciliumagent.ServeMonitorAPI(ctx, agent, queueSize) + if monitorErr != nil { + log.WithError(monitorErr).Error("encountered error serving monitor agent API") + return fmt.Errorf("encountered error serving monitor agent API: %w", monitorErr) + } + } + return err + }, + OnStop: func(cell.HookContext) error { + cancel() + return nil + }, + }) + + return agent +} diff --git a/pkg/monitoragent/monitoragent_linux.go b/pkg/monitoragent/monitoragent_linux.go new file mode 100644 index 000000000..8a16addcf --- /dev/null +++ b/pkg/monitoragent/monitoragent_linux.go @@ -0,0 +1,217 @@ +package monitoragent + +import ( + "bytes" + "context" + "encoding/gob" + "errors" + "fmt" + + "github.com/cilium/cilium/api/v1/models" + "github.com/cilium/cilium/pkg/lock" + "github.com/cilium/cilium/pkg/monitor/agent/consumer" + "github.com/cilium/cilium/pkg/monitor/agent/listener" + "github.com/cilium/cilium/pkg/monitor/api" + "github.com/cilium/cilium/pkg/monitor/payload" + "github.com/sirupsen/logrus" +) + +var ( + errMonitorAgentNotSetup = fmt.Errorf("monitor agent is not set up") + errUnexpectedEvent = errors.New("unexpected event type for MessageTypeAgent") +) + +// isCtxDone is a utility function that returns true when the context's Done() +// channel is closed. It is intended to simplify goroutines that need to check +// this multiple times in their loop. +func isCtxDone(ctx context.Context) bool { + select { + case <-ctx.Done(): + return true + default: + return false + } +} + +type monitorAgent struct { + lock.Mutex + models.MonitorStatus + + ctx context.Context + perfReaderCancel context.CancelFunc + + // listeners are external cilium monitor clients which receive raw + // gob-encoded payloads + listeners map[listener.MonitorListener]struct{} + // consumers are internal clients which receive decoded messages + consumers map[consumer.MonitorConsumer]struct{} +} + +func (a *monitorAgent) AttachToEventsMap(int) error { + return nil +} + +func (a *monitorAgent) SendEvent(typ int, event interface{}) error { + if a == nil { + return errMonitorAgentNotSetup + } + + // Two types of clients are currently supported: consumers and listeners. + // The former ones expect decoded messages, so the notification does not + // require any additional marshalling operation before sending an event. + // Instead, the latter expect gob-encoded payloads, and the whole marshalling + // process may be quite expensive. + // While we want to avoid marshalling events if there are no active + // listeners, there's no need to check for active consumers ahead of time. + + a.notifyAgentEvent(typ, event) + + // do not marshal notifications if there are no active listeners + if !a.hasListeners() { + return nil + } + + // marshal notifications into JSON format for legacy listeners + if typ == api.MessageTypeAgent { + msg, ok := event.(api.AgentNotifyMessage) + if !ok { + return errUnexpectedEvent + } + var err error + event, err = msg.ToJSON() + if err != nil { + return fmt.Errorf("unable to JSON encode agent notification: %w", err) + } + } + + var buf bytes.Buffer + if err := buf.WriteByte(byte(typ)); err != nil { + return fmt.Errorf("unable to initialize buffer: %w", err) + } + if err := gob.NewEncoder(&buf).Encode(event); err != nil { + return fmt.Errorf("unable to gob encode: %w", err) + } + + p := payload.Payload{Data: buf.Bytes(), CPU: 0, Lost: 0, Type: payload.EventSample} + a.sendToListeners(&p) + + return nil +} + +func (a *monitorAgent) RegisterNewListener(newListener listener.MonitorListener) { + if a == nil || newListener == nil { + return + } + + a.Lock() + defer a.Unlock() + + if isCtxDone(a.ctx) { + log.Debug("RegisterNewListener called on stopped monitor") + newListener.Close() + return + } + + version := newListener.Version() + switch newListener.Version() { //nolint:exhaustive // the only other case is unsupported which is covered by default + case listener.Version1_2: + a.listeners[newListener] = struct{}{} + default: + newListener.Close() + log.WithField("version", version).Error("Closing listener from unsupported monitor client version") + } + + log.WithFields(logrus.Fields{ + "count.listener": len(a.listeners), + "version": version, + }).Debug("New listener connected") +} + +func (a *monitorAgent) RemoveListener(ml listener.MonitorListener) { + if a == nil || ml == nil { + return + } + + a.Lock() + defer a.Unlock() + + // Remove the listener and close it. + delete(a.listeners, ml) + log.WithFields(logrus.Fields{ + "count.listener": len(a.listeners), + "version": ml.Version(), + }).Debug("Removed listener") + ml.Close() +} + +func (a *monitorAgent) RegisterNewConsumer(newConsumer consumer.MonitorConsumer) { + if a == nil || newConsumer == nil { + return + } + + if isCtxDone(a.ctx) { + log.Debug("RegisterNewConsumer called on stopped monitor") + return + } + + a.Lock() + defer a.Unlock() + + a.consumers[newConsumer] = struct{}{} +} + +func (a *monitorAgent) RemoveConsumer(mc consumer.MonitorConsumer) { + if a == nil || mc == nil { + return + } + + a.Lock() + defer a.Unlock() + + delete(a.consumers, mc) + if !a.hasSubscribersLocked() { + a.perfReaderCancel() + } +} + +func (a *monitorAgent) State() *models.MonitorStatus { + return nil +} + +// hasSubscribersLocked returns true if there are listeners or consumers +// subscribed to the agent right now. +// Note: it is critical to hold the lock for this operation. +func (a *monitorAgent) hasSubscribersLocked() bool { + return len(a.listeners)+len(a.consumers) != 0 +} + +// hasListeners returns true if there are listeners subscribed to the +// agent right now. +func (a *monitorAgent) hasListeners() bool { + a.Lock() + defer a.Unlock() + return len(a.listeners) != 0 +} + +// sendToListeners enqueues the payload to all listeners. +func (a *monitorAgent) sendToListeners(pl *payload.Payload) { + a.Lock() + defer a.Unlock() + a.sendToListenersLocked(pl) +} + +// sendToListenersLocked enqueues the payload to all listeners while holding the monitor lock. +func (a *monitorAgent) sendToListenersLocked(pl *payload.Payload) { + for ml := range a.listeners { + ml.Enqueue(pl) + } +} + +// notifyAgentEvent notifies all consumers about an agent event. +func (a *monitorAgent) notifyAgentEvent(typ int, message interface{}) { + a.Lock() + defer a.Unlock() + for mc := range a.consumers { + mc.NotifyAgentEvent(typ, message) + } +} diff --git a/pkg/plugin/packetparser/packetparser_linux.go b/pkg/plugin/packetparser/packetparser_linux.go index ce1a95126..c57f06558 100644 --- a/pkg/plugin/packetparser/packetparser_linux.go +++ b/pkg/plugin/packetparser/packetparser_linux.go @@ -579,8 +579,6 @@ func (p *packetParser) processRecord(ctx context.Context, id int) { // Add metadata to the flow. utils.AddRetinaMetadata(fl, meta) - p.l.Debug("Received packet", zap.Any("flow", fl)) - // Write the event to the enricher. ev := &v1.Event{ Event: fl, @@ -639,11 +637,9 @@ func (p *packetParser) readData() { select { case p.recordsChannel <- record: - p.l.Debug("Sent record to channel", zap.Any("record", record)) default: // Channel is full, drop the record. // We shouldn't slow down the perf array reader. - // p.l.Warn("Channel is full, dropping record", zap.Any("lost samples", record)) metrics.LostEventsCounter.WithLabelValues(utils.BufferedChannel, string(Name)).Inc() } } diff --git a/pkg/servermanager/cell_linux.go b/pkg/servermanager/cell_linux.go new file mode 100644 index 000000000..b0315c54e --- /dev/null +++ b/pkg/servermanager/cell_linux.go @@ -0,0 +1,60 @@ +package servermanager + +import ( + "context" + "fmt" + "sync" + + "github.com/cilium/cilium/pkg/hive/cell" + "github.com/microsoft/retina/pkg/config" + sm "github.com/microsoft/retina/pkg/managers/servermanager" + "github.com/sirupsen/logrus" +) + +var Cell = cell.Module( + "servermanager", + "Manages Retina basic metrics server", + cell.Provide(newServerManager), +) + +type serverParams struct { + cell.In + + Log logrus.FieldLogger + Lifecycle cell.Lifecycle + Config config.Config +} + +func newServerManager(params serverParams) (*sm.HTTPServer, error) { + logger := params.Log.WithField("module", "servermanager") + + serverCtx, cancelCtx := context.WithCancel(context.Background()) + serverManager := sm.NewHTTPServer(params.Config.ApiServer.Host, params.Config.ApiServer.Port) + if err := serverManager.Init(); err != nil { + logger.WithError(err).Error("Unable to initialize Http server") + cancelCtx() + return nil, fmt.Errorf("unable to initialize Http server: %w", err) + } + + wg := sync.WaitGroup{} + params.Lifecycle.Append(cell.Hook{ + OnStart: func(cell.HookContext) error { + wg.Add(1) + go func() { + defer wg.Done() + if err := serverManager.Start(serverCtx); err != nil { + logger.WithError(err).Error("Unable to start server") + } + }() + + return nil + }, + OnStop: func(cell.HookContext) error { + cancelCtx() + wg.Wait() + return nil + }, + }) + + return serverManager, nil +} diff --git a/pkg/shared/config/config_linux.go b/pkg/shared/config/config_linux.go new file mode 100644 index 000000000..168b0c34c --- /dev/null +++ b/pkg/shared/config/config_linux.go @@ -0,0 +1,23 @@ +package config + +import ( + "fmt" + + "github.com/cilium/cilium/pkg/hive/cell" + "k8s.io/client-go/rest" + kcfg "sigs.k8s.io/controller-runtime/pkg/client/config" +) + +var Cell = cell.Module( + "shared-config", + "Shared Config", + cell.Provide(GetK8sConfig), +) + +func GetK8sConfig() (*rest.Config, error) { + k8sCfg, err := kcfg.GetConfig() + if err != nil { + return &rest.Config{}, fmt.Errorf("failed to get k8s config: %w", err) + } + return k8sCfg, nil +} diff --git a/pkg/shared/config/type.go b/pkg/shared/config/type.go new file mode 100644 index 000000000..fe7e61446 --- /dev/null +++ b/pkg/shared/config/type.go @@ -0,0 +1,2 @@ +// Placeholder file. Required for windows build and lint. +package config diff --git a/pkg/shared/telemetry/cell_linux.go b/pkg/shared/telemetry/cell_linux.go new file mode 100644 index 000000000..717de3670 --- /dev/null +++ b/pkg/shared/telemetry/cell_linux.go @@ -0,0 +1,90 @@ +package telemetry + +import ( + "context" + "strings" + "time" + + "github.com/cilium/cilium/pkg/hive/cell" + "github.com/microsoft/retina/pkg/telemetry" + "github.com/sirupsen/logrus" + "k8s.io/client-go/rest" +) + +const heartbeatInterval = 5 * time.Minute + +type Config struct { + Component string + EnableTelemetry bool + ApplicationInsightsID string + RetinaVersion string + // EnabledPlugins is optional + EnabledPlugins []string +} + +type params struct { + cell.In + + Config Config + K8sCfg *rest.Config +} + +var ( + Constructor = cell.Module( + "telemetry", + "provides telemetry", + cell.Provide(func(p params, l logrus.FieldLogger) (telemetry.Telemetry, error) { + l.WithFields(logrus.Fields{ + "app-insights-id": p.Config.ApplicationInsightsID, + "retina-version": p.Config.RetinaVersion, + }).Info("configuring telemetry") + + if p.Config.EnableTelemetry { + if p.Config.ApplicationInsightsID == "" { + l.Info("cannot enable telemetry: empty app insights id") + return telemetry.NewNoopTelemetry(), nil + } + + l.Info("telemetry enabled") + + // initialize Application Insights + telemetry.InitAppInsights(p.Config.ApplicationInsightsID, p.Config.RetinaVersion) + + properties := map[string]string{ + "version": p.Config.RetinaVersion, + "apiserver": p.K8sCfg.Host, + } + if len(p.Config.EnabledPlugins) > 0 { + properties["plugins"] = strings.Join(p.Config.EnabledPlugins, `,`) + } + + tel := telemetry.NewAppInsightsTelemetryClient(p.Config.Component, properties) + return tel, nil + } + + l.Info("telemetry disabled") + return telemetry.NewNoopTelemetry(), nil + }), + ) + + Heartbeat = cell.Module( + "heartbeat", + "sends periodic telemetry heartbeat", + cell.Invoke( + func(tel telemetry.Telemetry, lifecycle cell.Lifecycle, l logrus.FieldLogger) { + ctx, cancelCtx := context.WithCancel(context.Background()) + lifecycle.Append(cell.Hook{ + OnStart: func(cell.HookContext) error { + l.Info("starting periodic heartbeat") + go tel.Heartbeat(ctx, heartbeatInterval) + return nil + }, + OnStop: func(cell.HookContext) error { + cancelCtx() + return nil + }, + }) + }, + ), + ) +) diff --git a/pkg/shared/telemetry/type.go b/pkg/shared/telemetry/type.go new file mode 100644 index 000000000..4517a9e84 --- /dev/null +++ b/pkg/shared/telemetry/type.go @@ -0,0 +1,2 @@ +// Placeholder file. Required for windows build and lint. +package telemetry diff --git a/test/e2e/framework/azure/create-cluster.go b/test/e2e/framework/azure/create-cluster.go index efb9a72d6..160d81fa8 100644 --- a/test/e2e/framework/azure/create-cluster.go +++ b/test/e2e/framework/azure/create-cluster.go @@ -68,7 +68,7 @@ func GetStarterClusterTemplate(location string) armcontainerservice.ManagedClust */ AgentPoolProfiles: []*armcontainerservice.ManagedClusterAgentPoolProfile{ { - Type: to.Ptr(armcontainerservice.AgentPoolTypeVirtualMachineScaleSets), + Type: to.Ptr(armcontainerservice.AgentPoolTypeVirtualMachineScaleSets), // AvailabilityZones: []*string{to.Ptr("1")}, Count: to.Ptr[int32](MaxNumberOfNodes), EnableNodePublicIP: to.Ptr(false), diff --git a/test/e2e/framework/kubernetes/exec-pod.go b/test/e2e/framework/kubernetes/exec-pod.go index 456a43eb0..2991a90aa 100644 --- a/test/e2e/framework/kubernetes/exec-pod.go +++ b/test/e2e/framework/kubernetes/exec-pod.go @@ -80,7 +80,6 @@ func ExecPod(ctx context.Context, kubeConfigFilePath, namespace, podName, comman Stdout: os.Stdout, Stderr: os.Stderr, }) - if err != nil { return fmt.Errorf("error executing command: %w", err) } diff --git a/test/e2e/retina_e2e_test.go b/test/e2e/retina_e2e_test.go index 1c2c2e76d..29aac9f9f 100644 --- a/test/e2e/retina_e2e_test.go +++ b/test/e2e/retina_e2e_test.go @@ -35,7 +35,7 @@ func TestE2ERetina(t *testing.T) { // Get to root of the repo by going up two directories rootDir := filepath.Dir(filepath.Dir(cwd)) - chartPath := filepath.Join(rootDir, "deploy", "manifests", "controller", "helm", "retina") + chartPath := filepath.Join(rootDir, "deploy", "legacy", "manifests", "controller", "helm", "retina") profilePath := filepath.Join(rootDir, "test", "profiles", "advanced", "values.yaml") kubeConfigFilePath := filepath.Join(rootDir, "test", "e2e", "test.pem") diff --git a/test/profiles/localctx/values.yaml b/test/profiles/localctx/values.yaml index c9c8448b9..6da54adc4 100644 --- a/test/profiles/localctx/values.yaml +++ b/test/profiles/localctx/values.yaml @@ -1,6 +1,6 @@ operator: enabled: false -# Plugins will default to deploy/manifests/controller/helm/retina/values.yaml +# Plugins will default to deploy/legacy/manifests/controller/helm/retina/values.yaml # TODO add all plugins that we want to test here for local context. remoteContext: false enablePodLevel: true diff --git a/windows/readme.md b/windows/readme.md index 40343ccfd..8b7fefef8 100644 --- a/windows/readme.md +++ b/windows/readme.md @@ -3,7 +3,7 @@ 1. Cordon all windows nodes. Until the below selector is added, needed so helm install isn't blocked. 2. Install Linux Retina helm chart. - `helm install retina ./deploy/manifests/controller/helm/retina/ --namespace kube-system` + `helm install retina ./deploy/legacy/manifests/controller/helm/retina/ --namespace kube-system` 3. Uncordon the Windows and nodes.