From cd9cf60140bd90ba63a769f257ada564906acfb0 Mon Sep 17 00:00:00 2001 From: Chris Suszynski Date: Tue, 29 Oct 2024 19:07:49 +0100 Subject: [PATCH] :gift: Easier debugging, especially for the in-cluster sender (#375) * Easier to debug the failures, especially for in-cluster sender * Configurable retries and deadline for ICS * Collect and log in-cluster job' pods and their logs * Fancy error handler * Linter fixes * Gather K8s events as well * Using TUI package to bring fancy UI for error handling * Unit tests fixes * Remove deactivated linters * Update e2e tests to refer to exec log on failure * Fixing the test (but still have race condition) * Remove spinner race condition * Error handler test * Update deps --- .golangci.yaml | 5 -- build/go.mod | 4 +- build/go.sum | 8 +- cmd/kn-event/main.go | 2 +- go.mod | 39 ++++++--- go.sum | 81 ++++++++++++++----- go.work.sum | 74 +++++++++++++++++- internal/cli/build.go | 7 +- internal/cli/errors.go | 98 +++++++++++++++++++++++ internal/cli/errors_test.go | 86 ++++++++++++++++++++ internal/cli/root.go | 33 ++++++-- internal/cli/send.go | 22 ++---- pkg/cli/context.go | 14 ++++ pkg/errors/delegate.go | 25 ++++++ pkg/errors/wrap.go | 61 +++++++++++++++ pkg/errors/wrap_test.go | 54 +++++++++++++ pkg/event/sender.go | 12 ++- pkg/ics/send.go | 10 +-- pkg/ics/types.go | 6 +- pkg/k8s/errors.go | 4 +- pkg/k8s/job_gatherer.go | 110 ++++++++++++++++++++++++++ pkg/k8s/jobrunner.go | 62 +++++++++++---- pkg/k8s/jobrunner_test.go | 152 +++++++++++++++++++++++++++++------- pkg/sender/in_cluster.go | 43 +++++++--- test/e2e-tests.sh | 1 + test/e2e/ics_send.go | 76 ++++-------------- 26 files changed, 887 insertions(+), 202 deletions(-) create mode 100644 internal/cli/errors.go create mode 100644 internal/cli/errors_test.go create mode 100644 pkg/errors/delegate.go create mode 100644 pkg/errors/wrap.go create mode 100644 pkg/errors/wrap_test.go create mode 100644 pkg/k8s/job_gatherer.go diff --git a/.golangci.yaml b/.golangci.yaml index 33cc6a09a..11474148b 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -19,13 +19,8 @@ linters: disable: - paralleltest - nlreturn - - exhaustivestruct - wsl - godox - - scopelint - - maligned - - interfacer - - golint - ireturn - varnamelen - exhaustruct diff --git a/build/go.mod b/build/go.mod index 91e3748c0..7a10e2d2c 100644 --- a/build/go.mod +++ b/build/go.mod @@ -191,8 +191,8 @@ require ( k8s.io/apimachinery v0.30.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect - knative.dev/client-pkg v0.0.0-20240808015000-22f598931483 // indirect - knative.dev/pkg v0.0.0-20241021183759-9b9d535af5ad // indirect + knative.dev/client-pkg v0.0.0-20241022130700-7b4bb48ac250 // indirect + knative.dev/pkg v0.0.0-20241026180704-25f6002b00f3 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kind v0.22.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect diff --git a/build/go.sum b/build/go.sum index 1580febbe..c487befb3 100644 --- a/build/go.sum +++ b/build/go.sum @@ -798,10 +798,10 @@ k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -knative.dev/client-pkg v0.0.0-20240808015000-22f598931483 h1:jBfmxcR0H5Z9IzamelZtmmg9jfeOXfssllUVX5M4Xzs= -knative.dev/client-pkg v0.0.0-20240808015000-22f598931483/go.mod h1:Y56KfZx3gJJpju88l86jQ9csxywLiopR0GkxCWW3+Kg= -knative.dev/pkg v0.0.0-20241021183759-9b9d535af5ad h1:Nrjtr2H168rJeamH4QdyLMV1lEKHejNhaj1ymgQMfLk= -knative.dev/pkg v0.0.0-20241021183759-9b9d535af5ad/go.mod h1:StJI72GWcm/iErmk4RqFJiOo8RLbVqPbHxUqeVwAzeo= +knative.dev/client-pkg v0.0.0-20241022130700-7b4bb48ac250 h1:hxR3hLPdJ9N+qC0ULT2vxTqXyzX8o/0W9ZfUmZ+XBBE= +knative.dev/client-pkg v0.0.0-20241022130700-7b4bb48ac250/go.mod h1:1Wp8+rz7JT3c17r0+2IdxWjkNvEZ/4/AHywaV12nq3I= +knative.dev/pkg v0.0.0-20241026180704-25f6002b00f3 h1:uUSDGlOIkdPT4svjlhi+JEnP2Ufw7AM/F5QDYiEL02U= +knative.dev/pkg v0.0.0-20241026180704-25f6002b00f3/go.mod h1:FeMbTLlxQqSASwlRCrYEOsZ0OKUgSj52qxhECwYCJsw= knative.dev/toolbox/magetasks v0.0.0-20240412084849-703489d35306 h1:mG2rEGCg4vZAs+D2rIzISuqmND8HNkcNCYvRmEXvG8s= knative.dev/toolbox/magetasks v0.0.0-20240412084849-703489d35306/go.mod h1:+LHHOXHlXXXiD8WG0ke72XTt/SSpSqUUX1dG8h9AGIE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/cmd/kn-event/main.go b/cmd/kn-event/main.go index de60ad3c6..38439f3bc 100644 --- a/cmd/kn-event/main.go +++ b/cmd/kn-event/main.go @@ -6,5 +6,5 @@ import ( ) func main() { - commandline.New(new(cli.App)).ExecuteOrDie(cli.Options...) + commandline.New(new(cli.App)).ExecuteOrDie(cli.EffectiveOptions()...) } diff --git a/go.mod b/go.mod index c5d20fe41..7cfb1fb93 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.22.0 require ( github.com/cloudevents/sdk-go/v2 v2.15.2 + github.com/fatih/color v1.16.0 github.com/ghodss/yaml v1.0.0 github.com/gobuffalo/flect v1.0.3 github.com/google/go-containerregistry v0.19.1 @@ -13,9 +14,10 @@ require ( github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 + github.com/spf13/viper v1.18.2 github.com/stretchr/testify v1.9.0 github.com/thediveo/enumflag v0.10.0 - github.com/wavesoftware/go-commandline v1.1.0 + github.com/wavesoftware/go-commandline v1.3.0 github.com/wavesoftware/go-ensure v1.0.0 go.uber.org/zap v1.27.0 gopkg.in/yaml.v2 v2.4.0 @@ -23,12 +25,12 @@ require ( k8s.io/api v0.30.3 k8s.io/apimachinery v0.30.3 k8s.io/client-go v0.30.3 - knative.dev/client/pkg v0.0.0-20241016014431-dbb49e603ce2 - knative.dev/eventing v0.42.1-0.20241016013536-6aa49dc1db88 - knative.dev/hack v0.0.0-20241010131451-05b2fb30cb4d - knative.dev/pkg v0.0.0-20241021183759-9b9d535af5ad - knative.dev/reconciler-test v0.0.0-20241015093232-09111f0f1364 - knative.dev/serving v0.42.1-0.20241021145327-c93d8c49a1b7 + knative.dev/client/pkg v0.0.0-20241028111248-117a365d93f7 + knative.dev/eventing v0.43.1-0.20241028083747-ef6b31a697e7 + knative.dev/hack v0.0.0-20241025103803-ef6e7e983a60 + knative.dev/pkg v0.0.0-20241026180704-25f6002b00f3 + knative.dev/reconciler-test v0.0.0-20241024141702-aae114c1c0e3 + knative.dev/serving v0.43.1-0.20241025124202-16d2da814851 sigs.k8s.io/yaml v1.4.0 ) @@ -39,15 +41,23 @@ require ( emperror.dev/errors v0.8.1 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blendle/zapdriver v1.3.1 // indirect github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/charmbracelet/bubbles v0.18.0 // indirect + github.com/charmbracelet/bubbletea v0.25.0 // indirect + github.com/charmbracelet/harmonica v0.2.0 // indirect + github.com/charmbracelet/lipgloss v0.10.0 // indirect github.com/cloudevents/conformance v0.2.0 // indirect github.com/cloudevents/sdk-go/sql/v2 v2.15.2 // indirect + github.com/containerd/console v1.0.4 // indirect github.com/creack/pty v1.1.21 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect + github.com/erikgeiser/promptkit v0.9.0 // indirect github.com/evanphx/json-patch v5.9.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect @@ -75,14 +85,23 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // 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 + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.15.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nxadm/tail v1.4.11 // indirect github.com/onsi/ginkgo v1.16.5 // indirect @@ -98,13 +117,13 @@ require ( github.com/prometheus/statsd_exporter v0.22.8 // indirect github.com/rickb777/date v1.20.0 // indirect github.com/rickb777/plural v1.4.1 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // 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/spf13/viper v1.18.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/wavesoftware/go-retcode v1.0.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect @@ -134,8 +153,8 @@ require ( k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20240808142205-8e686545bdb8 // indirect k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect - knative.dev/client-pkg v0.0.0-20240808015000-22f598931483 // indirect - knative.dev/networking v0.0.0-20241015085032-a3d46633cfb3 // indirect + knative.dev/client-pkg v0.0.0-20241022130700-7b4bb48ac250 // indirect + knative.dev/networking v0.0.0-20241024135302-d5387fab1de1 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect diff --git a/go.sum b/go.sum index 578082e6f..ac8156ef5 100644 --- a/go.sum +++ b/go.sum @@ -56,6 +56,10 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves= github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -70,6 +74,14 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0= +github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw= +github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM= +github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg= +github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ= +github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= +github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s= +github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -81,6 +93,8 @@ github.com/cloudevents/sdk-go/sql/v2 v2.15.2/go.mod h1:us+PSk8OXdk8pDbRfvxy5w8ub github.com/cloudevents/sdk-go/v2 v2.15.2 h1:54+I5xQEnI73RBhWHxbI1XJcqOFOVJN85vb41+8mHUc= github.com/cloudevents/sdk-go/v2 v2.15.2/go.mod h1:lL7kSWAE/V8VI4Wh0jbL2v/jvqsm6tjmaQBSvxcv4uE= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro= +github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= @@ -111,10 +125,14 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/erikgeiser/promptkit v0.9.0 h1:3qL1mS/ntCrXdb8sTP/ka82CJ9kEQaGuYXNrYJkWYBc= +github.com/erikgeiser/promptkit v0.9.0/go.mod h1:pU9dtogSe3Jlc2AY77EP7R4WFP/vgD4v+iImC83KsCo= 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/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= 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= @@ -299,12 +317,24 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 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.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75 h1:P8UmIzZMYDR+NGImiFvErt6VWfIRPuGM+vyjiEdkmIw= +github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -322,6 +352,14 @@ 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/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -410,6 +448,10 @@ github.com/rickb777/date v1.20.0 h1:oRGcq4b+ba12N/HnsVZuWSK/QJb/o/hnjOJEyRMGUT0= github.com/rickb777/date v1.20.0/go.mod h1:8AR0TBrjDGUjwKToBI8L+RafzNg7gqlT0ox0cERCwEo= github.com/rickb777/plural v1.4.1 h1:5MMLcbIaapLFmvDGRT5iPk8877hpTPt8Y9cdSKRw9sU= github.com/rickb777/plural v1.4.1/go.mod h1:kdmXUpmKBJTS0FtG/TFumd//VBWsNTD7zOw7x4umxNw= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -481,8 +523,8 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/wavesoftware/go-commandline v1.1.0 h1:Lm9WS8UWG55tnGl/Ke1PepyTPF/1YvasBsOtXWz/fsw= -github.com/wavesoftware/go-commandline v1.1.0/go.mod h1:msUGDOY3s8jITVYse8ANZn8H6YE5x7h2bWMmKha4ftw= +github.com/wavesoftware/go-commandline v1.3.0 h1:mlX4aa8wHFVqAEYvPmsXwuGVF9DKhRvxtR2QjqHt5Ec= +github.com/wavesoftware/go-commandline v1.3.0/go.mod h1:msUGDOY3s8jITVYse8ANZn8H6YE5x7h2bWMmKha4ftw= github.com/wavesoftware/go-ensure v1.0.0 h1:6X3gQL5psBWwtu/H9a+69xQ+JGTUELaLhgOB/iB3AQk= github.com/wavesoftware/go-ensure v1.0.0/go.mod h1:K2UAFSwMTvpiRGay/M3aEYYuurcR8S4A6HkQlJPV8k4= github.com/wavesoftware/go-retcode v1.0.0 h1:Z53+VpIHMvRMtjS6jPScdihbAN1ks3lIJ5Mj32gCpno= @@ -674,7 +716,10 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -896,22 +941,22 @@ k8s.io/kube-openapi v0.0.0-20240808142205-8e686545bdb8 h1:1Wof1cGQgA5pqgo8MxKPtf k8s.io/kube-openapi v0.0.0-20240808142205-8e686545bdb8/go.mod h1:Os6V6dZwLNii3vxFpxcNaTmH8LJJBkOTg1N0tOA0fvA= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -knative.dev/client-pkg v0.0.0-20240808015000-22f598931483 h1:jBfmxcR0H5Z9IzamelZtmmg9jfeOXfssllUVX5M4Xzs= -knative.dev/client-pkg v0.0.0-20240808015000-22f598931483/go.mod h1:Y56KfZx3gJJpju88l86jQ9csxywLiopR0GkxCWW3+Kg= -knative.dev/client/pkg v0.0.0-20241016014431-dbb49e603ce2 h1:RjuhdklDowLODd2cWDbTU5PU1182ik5MEw4DP5pvhWs= -knative.dev/client/pkg v0.0.0-20241016014431-dbb49e603ce2/go.mod h1:JR3XomuVf2cBqgvXFONkX6Ebf1/gJwUnl/1OH47U18g= -knative.dev/eventing v0.42.1-0.20241016013536-6aa49dc1db88 h1:Y50FB+2J5/DejNBre3klilKPmJFx31wv1OtTbpQUrjA= -knative.dev/eventing v0.42.1-0.20241016013536-6aa49dc1db88/go.mod h1:5+F5Htg4l8TMn2bb8sjCiFdojIFqrSPyUj81/VXIVdA= -knative.dev/hack v0.0.0-20241010131451-05b2fb30cb4d h1:aCfX7kwkvgGxXXGbso5tLqdwQmzBkJ9d+EIRwksKTvk= -knative.dev/hack v0.0.0-20241010131451-05b2fb30cb4d/go.mod h1:R0ritgYtjLDO9527h5vb5X6gfvt5LCrJ55BNbVDsWiY= -knative.dev/networking v0.0.0-20241015085032-a3d46633cfb3 h1:pnCWTaxtOdiqtjJC0kGw+4qC7ChH3DkchReSSSBtLQ8= -knative.dev/networking v0.0.0-20241015085032-a3d46633cfb3/go.mod h1:xaOhZH277o5f7VTWOBeDQNrGGXeNV2B9dxMn3bp26Ow= -knative.dev/pkg v0.0.0-20241021183759-9b9d535af5ad h1:Nrjtr2H168rJeamH4QdyLMV1lEKHejNhaj1ymgQMfLk= -knative.dev/pkg v0.0.0-20241021183759-9b9d535af5ad/go.mod h1:StJI72GWcm/iErmk4RqFJiOo8RLbVqPbHxUqeVwAzeo= -knative.dev/reconciler-test v0.0.0-20241015093232-09111f0f1364 h1:DIc+vbaFKOSGktPXJ1MaXIXoDjlmUIXQkHiZaPcYGbQ= -knative.dev/reconciler-test v0.0.0-20241015093232-09111f0f1364/go.mod h1:PVRnK/YQo9s3foRtut00oAxvCPc9f/qV2PApZh/rMPw= -knative.dev/serving v0.42.1-0.20241021145327-c93d8c49a1b7 h1:fydpJaCGILSagGqCNZExUyGuq2CaeT8dnuQjK9MykHs= -knative.dev/serving v0.42.1-0.20241021145327-c93d8c49a1b7/go.mod h1:1t1/B5Y4nrTprJGBLtkiz5ZgHy0AKgNjQdLsj5SfwDw= +knative.dev/client-pkg v0.0.0-20241022130700-7b4bb48ac250 h1:hxR3hLPdJ9N+qC0ULT2vxTqXyzX8o/0W9ZfUmZ+XBBE= +knative.dev/client-pkg v0.0.0-20241022130700-7b4bb48ac250/go.mod h1:1Wp8+rz7JT3c17r0+2IdxWjkNvEZ/4/AHywaV12nq3I= +knative.dev/client/pkg v0.0.0-20241028111248-117a365d93f7 h1:CYO+QLIz2lQMLksaMRWtHb/CaoxX0oxE40NGrtRQzCU= +knative.dev/client/pkg v0.0.0-20241028111248-117a365d93f7/go.mod h1:A4G6AOnjrtDEPzj8ungJk2/3IWz9DMJZDbdSMkkQLEQ= +knative.dev/eventing v0.43.1-0.20241028083747-ef6b31a697e7 h1:pYKhXbvHVOmQumyKS7vjQBaB11rXzeAjz84z2L9qrtM= +knative.dev/eventing v0.43.1-0.20241028083747-ef6b31a697e7/go.mod h1:2mdt9J66vQYzxizDz8I/F6IGzV1QgwCkacBR8X12Ssk= +knative.dev/hack v0.0.0-20241025103803-ef6e7e983a60 h1:LjBbosBvW/9/qjzIJtGpehPsbNWVvy1Fz8yZvMbFWe4= +knative.dev/hack v0.0.0-20241025103803-ef6e7e983a60/go.mod h1:R0ritgYtjLDO9527h5vb5X6gfvt5LCrJ55BNbVDsWiY= +knative.dev/networking v0.0.0-20241024135302-d5387fab1de1 h1:eU3Jgfr3XjxRJkyyOp2wSoI/pm9Z0I1wgw6iBxG1VUo= +knative.dev/networking v0.0.0-20241024135302-d5387fab1de1/go.mod h1:slScd6CR0VlxLiKVFSJTVj/ne8C7elWEE4F93nVOOJk= +knative.dev/pkg v0.0.0-20241026180704-25f6002b00f3 h1:uUSDGlOIkdPT4svjlhi+JEnP2Ufw7AM/F5QDYiEL02U= +knative.dev/pkg v0.0.0-20241026180704-25f6002b00f3/go.mod h1:FeMbTLlxQqSASwlRCrYEOsZ0OKUgSj52qxhECwYCJsw= +knative.dev/reconciler-test v0.0.0-20241024141702-aae114c1c0e3 h1:pa3b/0EKzONPLBHqM0RFzG5EaB+k8OTyHGaUXWPIgns= +knative.dev/reconciler-test v0.0.0-20241024141702-aae114c1c0e3/go.mod h1:W9Kmdoxelg2mswUpDKerL/4Ih1/ouVhlSMeZeJ5LX9c= +knative.dev/serving v0.43.1-0.20241025124202-16d2da814851 h1:iIqXMol/cei3PAyRizQrBE+NSFR/fq8GdAp8g62Uqi4= +knative.dev/serving v0.43.1-0.20241025124202-16d2da814851/go.mod h1:FGW1QEwQ0x2KWenTEZ+YNflBdBL9ATC8okmDoHo+yJ0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/go.work.sum b/go.work.sum index 75e16584e..27e33214f 100644 --- a/go.work.sum +++ b/go.work.sum @@ -72,6 +72,8 @@ github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRB github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= github.com/ahmetb/gen-crd-api-reference-docs v0.3.1-0.20210609063737-0067dc6dcea2 h1:t/ces1/q8tuApSb+T5ajsu3wqkofUT43U1gpDYTPYME= github.com/ahmetb/gen-crd-api-reference-docs v0.3.1-0.20210609063737-0067dc6dcea2/go.mod h1:TdjdkYhlOifCQWPs1UdTma97kQQMozf5h26hTuG70u8= +github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b h1:doCpXjVwui6HUN+xgNsNS3SZ0/jUZ68Eb+mJRNOZfog= +github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60= github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= @@ -128,6 +130,8 @@ github.com/beevik/ntp v0.3.0 h1:xzVrPrE4ziasFXgBVBZJDP0Wg/KpMwk2KHJ4Ba8GrDw= github.com/beevik/ntp v0.3.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bmizerany/perks v0.0.0-20230307044200-03f9df79da1e h1:mWOqoK5jV13ChKf/aF3plwQ96laasTJgZi4f1aSOu+M= +github.com/bmizerany/perks v0.0.0-20230307044200-03f9df79da1e/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= github.com/bobuhiro11/gokvm v0.0.8-0.20231003020000-f53faca69d28 h1:pO0VjeSk0Tcd0NIHxgD6Gyd8T0pw79hs6Usr2Cwr16M= github.com/bobuhiro11/gokvm v0.0.8-0.20231003020000-f53faca69d28/go.mod h1:xQjzvEq5CXolwHJyswTQXuGXNjF3bYavvXZXDZS+FTI= github.com/buildkite/agent/v3 v3.62.0 h1:yvzSjI8Lgifw883I8m9u8/L/Thxt4cLFd5aWPn3gg70= @@ -149,6 +153,7 @@ github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4r github.com/cert-manager/cert-manager v1.13.3 h1:3R4G0RI7K0OkTZhWlVOC5SGZMYa2NwqmQJoyKydrz/M= github.com/cert-manager/cert-manager v1.13.3/go.mod h1:BM2+Pt/NmSv1Zr25/MHv6BgIEF9IUxA1xAjp80qkxgc= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= @@ -185,6 +190,7 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 h1:2Dx4IHfC1yHWI12AxQDJM1QbRCDfk6M+blLzlZCXdrc= github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs= @@ -194,6 +200,10 @@ github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRk github.com/depcheck-test/depcheck-test v0.0.0-20220607135614-199033aaa936 h1:foGzavPWwtoyBvjWyKJYDYsyzy+23iBV7NKTwdk+LRY= github.com/depcheck-test/depcheck-test v0.0.0-20220607135614-199033aaa936/go.mod h1:ttKPnOepYt4LLzD+loXQ1rT6EmpyIYHro7TAJuIIlHo= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 h1:XOPLOMn/zT4jIgxfxSsoXPxkrzz0FaCHwp33x5POJ+Q= +github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= +github.com/dgryski/go-lttb v0.0.0-20230207170358-f8fc36cdbff1 h1:dxwR3CStJdJamsIoMPCmxuIfBAPTgmzvFax+MvFav3M= +github.com/dgryski/go-lttb v0.0.0-20230207170358-f8fc36cdbff1/go.mod h1:UwftcHUI/qTYvLAxrWmANuRckf8+08O3C3hwStvkhDU= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954 h1:RMLoZVzv4GliuWafOuPuQDKSm1SJph7uCRnnS61JAn4= @@ -230,6 +240,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-piv/piv-go v1.11.0 h1:5vAaCdRTFSIW4PeqMbnsDlUZ7odMYWnHBDGdmtU/Zhg= github.com/go-piv/piv-go v1.11.0/go.mod h1:NZ2zmjVkfFaL/CF8cVQ/pXdXtuj110zEKGdJM6fJZZM= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -261,12 +272,14 @@ github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/cel-go v0.17.8 h1:j9m730pMZt1Fc4oKhCLUHfjj6527LuhYcYw0Rl8gqto= github.com/google/cel-go v0.17.8/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= github.com/google/certificate-transparency-go v1.1.7 h1:IASD+NtgSTJLPdzkthwvAG1ZVbF2WtFg4IvoA68XGSw= github.com/google/certificate-transparency-go v1.1.7/go.mod h1:FSSBo8fyMVgqptbfF6j5p/XNdgQftAhSmXcIxV9iphE= github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM= github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20230209165335-3624968304fd h1:hQf//Ak0trkoqnm94i9mw00d7axUwfK92hMxslxNKYc= github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20230209165335-3624968304fd/go.mod h1:x5fIlj5elU+/eYF60q4eASMQ9kDc+GMFa7UU9M3mFFw= github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20230209165335-3624968304fd h1:AQZlI371LcvBYY/7Q55TjxrpZJs6wtEXMw4Wq38XLy8= @@ -275,6 +288,8 @@ github.com/google/go-github/v55 v55.0.0 h1:4pp/1tNMB9X/LuAhs5i0KQAE40NmiR/y6prLN github.com/google/go-github/v55 v55.0.0/go.mod h1:JLahOTA1DnXzhxEymmFF5PP2tSS9JVNj68mSZNDwskA= github.com/google/go-tpm v0.9.1-0.20230914180155-ee6cbcd136f8 h1:g9RVRZdQrNEK2E94RcFescvXFC9afWsFar4IIdejP34= github.com/google/go-tpm v0.9.1-0.20230914180155-ee6cbcd136f8/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian/v3 v3.0.0 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs= github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= @@ -297,8 +312,11 @@ github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720 github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= @@ -331,6 +349,8 @@ github.com/hugelgupf/go-shlex v0.0.0-20200702092117-c80c9d0918fa h1:s3KPo0nThtvj github.com/hugelgupf/go-shlex v0.0.0-20200702092117-c80c9d0918fa/go.mod h1:I1uW6ymzwsy5TlQgD1bFAghdMgBYqH1qtCeHoZgHMqs= github.com/hugelgupf/vmtest v0.0.0-20240216064925-0561770280a1 h1:jWoR2Yqg8tzM0v6LAiP7i1bikZJu3gxpgvu3g1Lw+a0= github.com/hugelgupf/vmtest v0.0.0-20240216064925-0561770280a1/go.mod h1:B63hDJMhTupLWCHwopAyEo7wRFowx9kOc8m8j1sfOqE= +github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc= +github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 h1:mV02weKRL81bEnm8A0HT1/CAelMQDBuQIfLw8n+d6xI= github.com/in-toto/in-toto-golang v0.9.0 h1:tHny7ac4KgtsfrG6ybU8gVOZux2H8jN05AXJ9EBM1XU= github.com/in-toto/in-toto-golang v0.9.0/go.mod h1:xsBVrVsHNsB61++S6Dy2vWosKhuA3lUTQd+eF9HdeMo= @@ -387,6 +407,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJ github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= @@ -415,6 +437,8 @@ github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI= github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= +github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= +github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -454,6 +478,8 @@ github.com/pborman/getopt/v2 v2.1.0/go.mod h1:4NtW75ny4eBw9fO1bhtNdYTlZKYX5/tBLt github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1 h1:VGcrWe3yk6o+t7BdVNy5UDPWa4OZuDWtE1W1ZbS7Kyw= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/profile v1.2.1 h1:F++O52m40owAmADcojzM+9gyjmMOY/T4oYJkgFDH8RE= github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= @@ -463,6 +489,11 @@ github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc= github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/prometheus v0.53.1 h1:B0xu4VuVTKYrIuBMn/4YSUoIPYxs956qsOfcS4rqCuA= +github.com/prometheus/prometheus v0.53.1/go.mod h1:RZDkzs+ShMBDkAPQkLEaLBXpjmDcjhNxU2drUVPgKUU= github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= github.com/protocolbuffers/txtpbfmt v0.0.0-20231025115547-084445ff1adf h1:014O62zIzQwvoD7Ekj3ePDF5bv9Xxy0w6AZk0qYbjUk= github.com/protocolbuffers/txtpbfmt v0.0.0-20231025115547-084445ff1adf/go.mod h1:jgxiZysxFPM+iWKwQwPR+y+Jvo54ARd4EisXxKYpB5c= @@ -477,6 +508,8 @@ github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0 github.com/rekby/gpt v0.0.0-20200219180433-a930afbc6edc h1:goZGTwEEn8mWLcY012VouWZWkJ8GrXm9tS3VORMxT90= github.com/rekby/gpt v0.0.0-20200219180433-a930afbc6edc/go.mod h1:scrOqOnnHVKCHENvFw8k9ajCb88uqLQDA4BvuJNJ2ew= github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 h1:18kd+8ZUlt/ARXhljq+14TwAoKa61q6dX8jtwOf6DH8= @@ -528,6 +561,8 @@ github.com/spiffe/go-spiffe/v2 v2.1.7/go.mod h1:QJDGdhXllxjxvd5B+2XnhhXB/+rC8gr+ github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94 h1:0ngsPmuP6XIjiFRNFYlvKwSr5zff2v+uPHaffZ6/M4k= +github.com/streadway/quantile v0.0.0-20220407130108-4246515d968d h1:X4+kt6zM/OVO6gbJdAfJR60MGPsqCzbtXNnjoGqdfAs= +github.com/streadway/quantile v0.0.0-20220407130108-4246515d968d/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807 h1:LUsDduamlucuNnWcaTbXQ6aLILFcLXADpOzeEH3U+OI= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= @@ -642,20 +677,46 @@ gocloud.dev v0.36.0 h1:q5zoXux4xkOZP473e1EZbG8Gq9f0vlg1VNH5Du/ybus= gocloud.dev v0.36.0/go.mod h1:bLxah6JQVKBaIxzsr5BQLYB4IYdWHkMZdzCXlo6F0gg= golang.org/x/arch v0.2.0 h1:W1sUEHXiJTfjaFJ5SLo0N6lZn+0eO5gWD1MFeTGqQEY= golang.org/x/arch v0.2.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457 h1:zf5N6UOrA487eEFacMePxjXAJctxKmyjKUsjA11Uzuk= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca h1:PupagGYwj8+I4ubCxcmcBRk3VlUWtTg5huQpZR9flmE= +gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6 h1:4WsZyVtkthqrHTbDCJfiTs8IWNYE4uvsSDgaV6xpp+o= +gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20240528184218-531527333157 h1:u7WMYrIrVvs0TF5yaKwKNbcJyySYf+HAIFXxWltJOXE= google.golang.org/genproto v0.0.0-20240528184218-531527333157/go.mod h1:ubQlAQnzejB8uZzszhrTCU2Fyp6Vi7ZE5nn0c3W8+qQ= google.golang.org/genproto/googleapis/bytestream v0.0.0-20240528184218-531527333157 h1:znHUtThh5/fLbEC/p3Khp5xOucyAgMZ1Nj9ditbxd44= google.golang.org/genproto/googleapis/bytestream v0.0.0-20240528184218-531527333157/go.mod h1:0J6mmn3XAEjfNbPvpH63c0RXCjGNFcCzlEfWSN4In+k= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= @@ -664,6 +725,7 @@ gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYs gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= k8s.io/code-generator v0.30.3 h1:bmtnLJKagDS5f5uOEpLyJiDfIMKXGMKgOLBdde+w0Mc= k8s.io/code-generator v0.30.3/go.mod h1:PFgBiv+miFV7TZYp+RXgROkhA+sWYZ+mtpbMLofMke8= @@ -675,16 +737,19 @@ k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70 h1:NGrVE502P0s0/1hudf8zjgwki1 k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/kms v0.30.3 h1:NLg+oN45S2Y3U0WiLRzbS61AY/XrS5JBMZp531Z+Pho= k8s.io/kms v0.30.3/go.mod h1:GrMurD0qk3G4yNgGcsCEmepqf9KyyIrTXYR2lyUOJC4= -knative.dev/caching v0.0.0-20241015090132-ccfb189fed8e h1:SFUaPsSwBOLnrakXCoOi+iGe74xGW3TRDwDXmD29xyo= -knative.dev/caching v0.0.0-20241015090132-ccfb189fed8e/go.mod h1:Gdarh0MOPnzYhT7/f5FFFClwRbbp0bJGK8J2Viu1g54= -knative.dev/hack/schema v0.0.0-20241010131451-05b2fb30cb4d h1:N+UlBE8F8LJUh/m6cYSwzqdqNg65BD9jbWoWO9nfqEA= -knative.dev/hack/schema v0.0.0-20241010131451-05b2fb30cb4d/go.mod h1:jRH/sx6mwwuMVhvJgnzSaoYA1N4qaIkJa+zxEGtVA5I= +knative.dev/caching v0.0.0-20241024134602-3f5cd81853a0 h1:l1LdDpHpILHw/z0zmRnQsAQGteSXlC/VToHcu1qk+A4= +knative.dev/caching v0.0.0-20241024134602-3f5cd81853a0/go.mod h1:dDbjWQ3bY15TU6FSJ4I9C6noGKpu+MvPGOLHjDf4zx4= +knative.dev/hack/schema v0.0.0-20241025103803-ef6e7e983a60 h1:lQC/oc1VksTbv+MOxprFqz6g0rO8DZGocpM/2/gkCDM= +knative.dev/hack/schema v0.0.0-20241025103803-ef6e7e983a60/go.mod h1:jRH/sx6mwwuMVhvJgnzSaoYA1N4qaIkJa+zxEGtVA5I= mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg= mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8= pack.ag/tftp v1.0.1-0.20181129014014-07909dfbde3c h1:4DHuGX0VtxRIyjXlVpcjSGEmZ7OnIK7Hvo+INnxI8yk= pack.ag/tftp v1.0.1-0.20181129014014-07909dfbde3c/go.mod h1:N1Pyo5YG+K90XHoR2vfLPhpRuE8ziqbgMn/r/SghZas= +pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= +pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= @@ -694,6 +759,7 @@ sigs.k8s.io/gateway-api v0.8.0 h1:isQQ3Jx2qFP7vaA3ls0846F0Amp9Eq14P08xbSwVbQg= sigs.k8s.io/gateway-api v0.8.0/go.mod h1:okOnjPNBFbIS/Rw9kAhuIUaIkLhTKEu+ARIuXk2dgaM= sigs.k8s.io/release-utils v0.7.7 h1:JKDOvhCk6zW8ipEOkpTGDH/mW3TI+XqtPp16aaQ79FU= sigs.k8s.io/release-utils v0.7.7/go.mod h1:iU7DGVNi3umZJ8q6aHyUFzsDUIaYwNnNKGHo3YE5E3s= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= software.sslmate.com/src/go-pkcs12 v0.2.0 h1:nlFkj7bTysH6VkC4fGphtjXRbezREPgrHuJG20hBGPE= software.sslmate.com/src/go-pkcs12 v0.2.0/go.mod h1:23rNcYsMabIc1otwLpTkCCPwUq6kQsTyowttG/as0kQ= src.elv.sh v0.16.0-rc1.0.20220116211855-fda62502ad7f h1:pjVeIo9Ba6K1Wy+rlwX91zT7A+xGEmxiNRBdN04gDTQ= diff --git a/internal/cli/build.go b/internal/cli/build.go index 9d9e1bcb8..1e4316764 100644 --- a/internal/cli/build.go +++ b/internal/cli/build.go @@ -17,7 +17,6 @@ package cli import ( - "errors" "fmt" "github.com/spf13/cobra" @@ -25,6 +24,7 @@ import ( outlogging "knative.dev/client/pkg/output/logging" "knative.dev/kn-plugin-event/pkg/binding" "knative.dev/kn-plugin-event/pkg/cli" + "knative.dev/kn-plugin-event/pkg/errors" ) // ErrCantBePresented is returned if data can't be presented. @@ -62,8 +62,5 @@ func (b *buildCommand) run(cmd *cobra.Command, _ []string) error { } func cantBuildEventError(err error) error { - if errors.Is(err, cli.ErrCantBuildEvent) { - return err - } - return fmt.Errorf("%w: %w", cli.ErrCantBuildEvent, err) + return errors.Wrap(err, cli.ErrCantBuildEvent) } diff --git a/internal/cli/errors.go b/internal/cli/errors.go new file mode 100644 index 000000000..c9c1ca676 --- /dev/null +++ b/internal/cli/errors.go @@ -0,0 +1,98 @@ +/* + Copyright 2024 The Knative Authors + + 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. +*/ + +package cli + +import ( + "io" + "regexp" + "strings" + + "github.com/fatih/color" + "github.com/spf13/cobra" + outlogging "knative.dev/client/pkg/output/logging" + "knative.dev/client/pkg/output/term" + "knative.dev/kn-plugin-event/pkg/errors" +) + +const likelyErrorChainDepth = 3 + +var ( + numbersRE = regexp.MustCompile(`\s+\d+\s+`) + stringRE = regexp.MustCompile(`\s+"[^"]+"\s+`) +) + +func errorHandler(err error, cmd *cobra.Command) bool { + prettyPrintErr(err, cmd) + ctx := cmd.Context() + if logfile := outlogging.LogFileFrom(ctx); logfile != nil { + logpath := logfile.Name() + hint := "🌟 Hint:" + if term.IsFancy(cmd.ErrOrStderr()) { + logpath = color.CyanString(logpath) + hint = color.YellowString(hint) + } + cmd.PrintErrln() + cmd.PrintErrln(hint, "The execution logs could help debug the failure.") + cmd.PrintErrln(" Consider, taking a look at the log file:", logpath) + } + return false +} + +func prettyPrintErr(err error, cmd *cobra.Command) { + prefix := "🔥 Error:" + stderr := cmd.ErrOrStderr() + if term.IsFancy(stderr) { + prefix = color.RedString(prefix) + } + messages := make([]string, 0, likelyErrorChainDepth) + messages = append(messages, err.Error()) + for { + if err = errors.Cause(err); err != nil { + messages = append(messages, err.Error()) + } else { + break + } + } + for i := 0; i < len(messages); i++ { + j := i + 1 + if j < len(messages) { + messages[i] = strings.Replace(messages[i], ": "+messages[j], "", 1) + } + if i == 0 { + cmd.PrintErrln(prefix, colorizeMessage(messages[i], stderr)) + } else { + padding := strings.Repeat(" ", i) + "└─ caused by:" + if term.IsFancy(stderr) { + padding = color.RedString(padding) + } + cmd.PrintErrln(padding, colorizeMessage(messages[i], stderr)) + } + } +} + +func colorizeMessage(msg string, out io.Writer) string { + if !term.IsFancy(out) { + return msg + } + msg = numbersRE.ReplaceAllStringFunc(msg, func(num string) string { + return color.YellowString(num) + }) + msg = stringRE.ReplaceAllStringFunc(msg, func(s string) string { + return color.GreenString(s) + }) + return msg +} diff --git a/internal/cli/errors_test.go b/internal/cli/errors_test.go new file mode 100644 index 000000000..fdd3a0ef6 --- /dev/null +++ b/internal/cli/errors_test.go @@ -0,0 +1,86 @@ +/* + Copyright 2024 The Knative Authors + + 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. +*/ + +package cli_test + +import ( + "bytes" + "context" + "os" + "path" + "strings" + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/require" + "github.com/wavesoftware/go-commandline" + "gotest.tools/v3/assert" + outlogging "knative.dev/client/pkg/output/logging" + "knative.dev/kn-plugin-event/internal/cli" + "knative.dev/kn-plugin-event/pkg/errors" +) + +var errFoo = errors.New("foo") + +func TestErrorHandler(t *testing.T) { + t.Setenv("FORCE_COLOR", "yes") + cmd := &cobra.Command{ + Use: "example", + SilenceErrors: true, + SilenceUsage: true, + RunE: func(_ *cobra.Command, _ []string) error { + return errors.Wrap(errFoo, cli.ErrCantBePresented) + }, + } + logfilePath := path.Join(os.TempDir(), "log.jsonl") + const fileMode = 0o600 + logfile, err := os.OpenFile(logfilePath, os.O_CREATE, fileMode) + require.NoError(t, err) + defer func(logfile *os.File) { + _ = logfile.Close() + }(logfile) + ctx := outlogging.WithLogFile(context.TODO(), logfile) + cmd.SetContext(ctx) + errBuf := bytes.NewBufferString("") + cmd.SetErr(errBuf) + var gotCode *int + opts := append( + cli.EffectiveOptions(), + commandline.WithExit(func(code int) { + gotCode = &code + }), + ) + commandline.New(app{cmd}).ExecuteOrDie(opts...) + assert.Check(t, gotCode != nil) + assert.Equal(t, *gotCode, 227) + wantErrorOutput := ` +🔥 Error: can't be presented + └─ caused by: foo + +🌟 Hint: The execution logs could help debug the failure. + Consider, taking a look at the log file: ` + wantErrorOutput += logfilePath + "\n" + wantErrorOutput = strings.TrimPrefix(wantErrorOutput, "\n") + assert.Equal(t, wantErrorOutput, errBuf.String()) +} + +type app struct { + cmd *cobra.Command +} + +func (a app) Command() *cobra.Command { + return a.cmd +} diff --git a/internal/cli/root.go b/internal/cli/root.go index 1af0d124c..e9a07589a 100644 --- a/internal/cli/root.go +++ b/internal/cli/root.go @@ -21,6 +21,7 @@ import ( "github.com/thediveo/enumflag" "github.com/wavesoftware/go-commandline" "go.uber.org/zap/zapcore" + "knative.dev/client/pkg/config" outlogging "knative.dev/client/pkg/output/logging" "knative.dev/kn-plugin-event/pkg/cli" "knative.dev/kn-plugin-event/pkg/metadata" @@ -29,17 +30,28 @@ import ( // Options to override the commandline for testing purposes. var Options []commandline.Option //nolint:gochecknoglobals +// EffectiveOptions are the options used for command run. +// +// TODO: Consider migrating to Cobra' error handler, see: https://github.com/spf13/cobra/pull/2199 +func EffectiveOptions() []commandline.Option { + return append( + []commandline.Option{commandline.WithErrorHandler(errorHandler)}, + Options..., + ) +} + type App struct { cli.Params } func (a *App) Command() *cobra.Command { c := &cobra.Command{ - Use: metadata.PluginUse, - Aliases: []string{"kn " + metadata.PluginUse}, - Short: metadata.PluginDescription, - Long: metadata.PluginLongDescription, - SilenceUsage: true, + Use: metadata.PluginUse, + Aliases: []string{"kn " + metadata.PluginUse}, + Short: metadata.PluginDescription, + Long: metadata.PluginLongDescription, + SilenceUsage: true, + SilenceErrors: true, } eventArgs := &cli.EventArgs{} @@ -53,12 +65,13 @@ func (a *App) Command() *cobra.Command { c.AddCommand(each.command()) } c.SetContext(cli.InitialContext()) - c.PersistentPreRun = func(cmd *cobra.Command, _ []string) { + c.PersistentPreRunE = func(cmd *cobra.Command, _ []string) error { lvl := zapcore.InfoLevel if a.Verbose { lvl = zapcore.DebugLevel } cli.SetupOutput(cmd, cli.DefaultLoggingSetup(lvl)) + return config.BootstrapConfig() } c.PersistentPostRunE = func(cmd *cobra.Command, _ []string) error { closer := outlogging.LogFileCloserFrom(cmd.Context()) @@ -71,15 +84,19 @@ func (a *App) Command() *cobra.Command { } func (a *App) setGlobalFlags(c *cobra.Command) { - c.PersistentFlags().BoolVarP( + fl := c.PersistentFlags() + fl.BoolVarP( &a.Verbose, "verbose", "v", false, "verbose output", ) - c.PersistentFlags().VarP( + fl.VarP( enumflag.New(&a.OutputMode, "output", outputModeIDs(), enumflag.EnumCaseInsensitive), "output", "o", "OutputMode format. One of: human|json|yaml.", ) + // TODO: config.BootstrapConfig should allow to add bootstrap flags to command + _ = fl.String("config", "", "") + _ = fl.MarkHidden("config") } var _ commandline.CobraProvider = new(App) diff --git a/internal/cli/send.go b/internal/cli/send.go index 793fc8a45..eb6ffa2e3 100644 --- a/internal/cli/send.go +++ b/internal/cli/send.go @@ -17,24 +17,17 @@ package cli import ( - "errors" - "fmt" - "github.com/spf13/cobra" "knative.dev/client/pkg/flags/sink" "knative.dev/kn-plugin-event/pkg/binding" "knative.dev/kn-plugin-event/pkg/cli" + "knative.dev/kn-plugin-event/pkg/errors" "knative.dev/kn-plugin-event/pkg/event" ) -var ( - // ErrSendTargetValidationFailed is returned if a send target can't pass a - // validation. - ErrSendTargetValidationFailed = errors.New("send target validation failed") - - // ErrCantSendEvent is returned if event can't be sent. - ErrCantSendEvent = errors.New("can't send event") -) +// ErrSendTargetValidationFailed is returned if the send target can't pass a +// validation. +var ErrSendTargetValidationFailed = errors.New("send target validation failed") type sendCommand struct { target *cli.TargetArgs @@ -63,7 +56,7 @@ option isn't specified target URL will not be changed.`, c.PreRunE = func(*cobra.Command, []string) error { err := cli.ValidateTarget(s.target) if err != nil { - return fmt.Errorf("%w: %w", ErrSendTargetValidationFailed, err) + return errors.Wrap(err, ErrSendTargetValidationFailed) } return nil } @@ -84,8 +77,5 @@ func (s *sendCommand) run(cmd *cobra.Command, _ []string) error { } func cantSentEvent(err error) error { - if errors.Is(err, event.ErrCantSentEvent) { - return err - } - return fmt.Errorf("%w: %w", event.ErrCantSentEvent, err) + return errors.Wrap(err, event.ErrCantSentEvent) } diff --git a/pkg/cli/context.go b/pkg/cli/context.go index 592ba9ebc..c462ad6e9 100644 --- a/pkg/cli/context.go +++ b/pkg/cli/context.go @@ -21,10 +21,13 @@ import ( "io" "os" + "github.com/fatih/color" + "github.com/spf13/cobra" "go.uber.org/zap" "go.uber.org/zap/zapcore" "knative.dev/client/pkg/output" outlogging "knative.dev/client/pkg/output/logging" + "knative.dev/client/pkg/output/term" "knative.dev/pkg/logging" "knative.dev/pkg/signals" ) @@ -37,6 +40,9 @@ type Cobralike interface { SetOut(out io.Writer) OutOrStderr() io.Writer + SetErrPrefix(prefix string) + HasParent() bool + Parent() *cobra.Command } // InitialContext returns the initial context object, so it could be set ahead @@ -95,6 +101,14 @@ func SetupOutput(cbr Cobralike, loggingSetup LoggingSetup) { ctx = output.WithContext(ctx, cbr) ctx = loggingSetup(ctx) cbr.SetContext(ctx) + + if term.IsFancy(cbr.OutOrStdout()) { + cbr.SetErrPrefix(color.RedString("Error:")) + } + if cbr.HasParent() { + cmd := cbr.Parent() + cmd.SetContext(ctx) + } } var ( diff --git a/pkg/errors/delegate.go b/pkg/errors/delegate.go new file mode 100644 index 000000000..9374edb60 --- /dev/null +++ b/pkg/errors/delegate.go @@ -0,0 +1,25 @@ +/* + Copyright 2024 The Knative Authors + + 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. +*/ + +package errors + +import "errors" + +// New returns an error that formats as the given text. +// Each call to New returns a distinct error value even if the text is identical. +func New(text string) error { + return errors.New(text) //nolint:err113 +} diff --git a/pkg/errors/wrap.go b/pkg/errors/wrap.go new file mode 100644 index 000000000..8ff61c983 --- /dev/null +++ b/pkg/errors/wrap.go @@ -0,0 +1,61 @@ +/* + Copyright 2024 The Knative Authors + + 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. +*/ + +package errors + +import ( + "errors" + "fmt" +) + +// Wrap an error with provided wrap error. Will check if the error is already +// of given type to prevent over-wrapping. +func Wrap(err, wrap error) error { + if errors.Is(err, wrap) { + return err + } + return fmt.Errorf("%w: %w", wrap, err) +} + +// UnwrapAll will get all the wrapped errors of a given one, regardless if a +// single error was wrapped or multiple. +func UnwrapAll(err error) []error { + cause := errors.Unwrap(err) + if cause != nil { + return []error{cause} + } + eg, ok := err.(multipleErrors) + if !ok { + return nil + } + return append(([]error)(nil), eg.Unwrap()...) +} + +// Cause will determine the cause error of the given one, by returning the +// second wrapped error. +func Cause(err error) error { + errs := UnwrapAll(err) + switch len(errs) { + case 0, 1: + return nil + default: + return errs[1] + } +} + +type multipleErrors interface { + Unwrap() []error +} diff --git a/pkg/errors/wrap_test.go b/pkg/errors/wrap_test.go new file mode 100644 index 000000000..8db80cff6 --- /dev/null +++ b/pkg/errors/wrap_test.go @@ -0,0 +1,54 @@ +/* + Copyright 2024 The Knative Authors + + 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. +*/ + +package errors_test + +import ( + "fmt" + "testing" + + "gotest.tools/v3/assert" + "knative.dev/kn-plugin-event/pkg/errors" +) + +var ( + errFoo = errors.New("foo") + errBar = errors.New("bar") +) + +func TestWrap(t *testing.T) { + err := errors.Wrap(errFoo, errBar) + assert.ErrorIs(t, err, errFoo) + assert.ErrorIs(t, err, errBar) + assert.Error(t, err, "bar: foo") +} + +func TestCause(t *testing.T) { + ferr := fmt.Errorf("%w: fizz", errFoo) + err := errors.Wrap(ferr, errBar) + got := errors.Cause(err) + assert.Equal(t, got, ferr) + assert.Equal(t, errors.Cause(ferr), nil) +} + +func TestUnwrapAll(t *testing.T) { + ferr := fmt.Errorf("%w: fizz", errFoo) + err := errors.Wrap(ferr, errBar) + got := errors.UnwrapAll(err) + assert.Assert(t, len(got) == 2) + assert.Equal(t, got[0], errBar) + assert.ErrorIs(t, got[1], errFoo) +} diff --git a/pkg/event/sender.go b/pkg/event/sender.go index 34a9b135a..a64245937 100644 --- a/pkg/event/sender.go +++ b/pkg/event/sender.go @@ -6,12 +6,12 @@ import ( "fmt" cloudevents "github.com/cloudevents/sdk-go/v2" + outlogging "knative.dev/client/pkg/output/logging" "knative.dev/kn-plugin-event/pkg/k8s" - "knative.dev/pkg/logging" ) -// ErrCantSentEvent if event can't be sent. -var ErrCantSentEvent = errors.New("can't sent event") +// ErrCantSentEvent if the event can't be sent. +var ErrCantSentEvent = errors.New("can't sent the event") // Sender will send event to specified target. type Sender interface { @@ -43,8 +43,12 @@ type sendLogic struct { } func (l *sendLogic) Send(ctx context.Context, ce cloudevents.Event) error { + log := outlogging.LoggerFrom(ctx) + cebytes, _ := ce.MarshalJSON() + log.WithFields(outlogging.Fields{ + "event": string(cebytes), + }).Debug("Sending the event") err := l.Sender.Send(ctx, ce) - log := logging.FromContext(ctx) if err == nil { log.Infof("Event (ID: %s) have been sent.", ce.ID()) return nil diff --git a/pkg/ics/send.go b/pkg/ics/send.go index 746658d89..ddbc8a650 100644 --- a/pkg/ics/send.go +++ b/pkg/ics/send.go @@ -2,12 +2,12 @@ package ics import ( "context" - "fmt" cloudevents "github.com/cloudevents/sdk-go/v2" "github.com/kelseyhightower/envconfig" "go.uber.org/zap" "knative.dev/client/pkg/flags/sink" + "knative.dev/kn-plugin-event/pkg/errors" "knative.dev/kn-plugin-event/pkg/event" "knative.dev/kn-plugin-event/pkg/k8s" "knative.dev/pkg/apis" @@ -23,7 +23,7 @@ func (app *App) SendFromEnv(ctx context.Context, cfg *k8s.Configurator) error { } err = c.sender.Send(ctx, *c.ce) if err != nil { - return fmt.Errorf("%w: %w", ErrCantSendWithICS, err) + return errors.Wrap(err, ErrICSFailed) } log := logging.FromContext(ctx) log.Infow("Event sent", zap.String("ce-id", c.ce.ID())) @@ -36,18 +36,18 @@ func (app *App) configure(cfg *k8s.Configurator) (config, error) { } err := envconfig.Process("K", args) if err != nil { - return config{}, fmt.Errorf("%w: %w", ErrCantConfigureICS, err) + return config{}, errors.Wrap(err, ErrCantConfigureICS) } u, err := apis.ParseURL(args.Sink) if err != nil { - return config{}, fmt.Errorf("%w: %w", ErrCantConfigureICS, err) + return config{}, errors.Wrap(err, ErrCantConfigureICS) } target := &event.Target{ Reference: &sink.Reference{URL: u}, } s, err := app.Binding.CreateSender(cfg, target) if err != nil { - return config{}, fmt.Errorf("%w: %w", ErrCantConfigureICS, err) + return config{}, errors.Wrap(err, ErrCantConfigureICS) } ce, err := Decode(args.Event) if err != nil { diff --git a/pkg/ics/types.go b/pkg/ics/types.go index 1356ca775..a0f8c0dbd 100644 --- a/pkg/ics/types.go +++ b/pkg/ics/types.go @@ -15,9 +15,9 @@ var ( ErrCouldntDecode = errors.New("couldn't decode an event") // ErrCantConfigureICS is returned when the problem occurs while trying to // configure ICS sender. - ErrCantConfigureICS = errors.New("can't configure ICS sender") - // ErrCantSendWithICS if can't send with ICS sender. - ErrCantSendWithICS = errors.New("can't send with ICS sender") + ErrCantConfigureICS = errors.New("can't configure in-cluster sender") + // ErrICSFailed if the in-cluster sender has failed. + ErrICSFailed = errors.New("the in-cluster sender failure") ) // Args holds a list of args for in-cluster-sender. diff --git a/pkg/k8s/errors.go b/pkg/k8s/errors.go index 4e227512b..10a06cbe9 100644 --- a/pkg/k8s/errors.go +++ b/pkg/k8s/errors.go @@ -12,6 +12,6 @@ var ( // ErrUnexcpected if something unexpected actually has happened. ErrUnexcpected = errors.New("something unexpected actually has happened") - // ErrICSenderJobFailed if the ICS job runner has failed. - ErrICSenderJobFailed = errors.New("the ICS job runner has failed") + // ErrJobFailed if the job has failed. + ErrJobFailed = errors.New("the Kubernetes job failed") ) diff --git a/pkg/k8s/job_gatherer.go b/pkg/k8s/job_gatherer.go new file mode 100644 index 000000000..006afb026 --- /dev/null +++ b/pkg/k8s/job_gatherer.go @@ -0,0 +1,110 @@ +/* + Copyright 2024 The Knative Authors + + 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. +*/ + +package k8s + +import ( + "context" + "encoding/json" + "fmt" + "reflect" + + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1" + outlogging "knative.dev/client/pkg/output/logging" + "knative.dev/pkg/ptr" +) + +type jobGatherer struct { + kube Clients +} + +func (g jobGatherer) gather(ctx context.Context, job *batchv1.Job) outlogging.Fields { + fields := outlogging.Fields{} + fields["image"] = job.Spec.Template.Spec.Containers[0].Image + asJSONIntoFields(job, "job", fields) + // empty status -> the job isn't started yet + if !reflect.DeepEqual(job.Status, batchv1.JobStatus{}) { + // collect for a job that has been executed only + g.gatherInfoOfPodsForJob(ctx, job, fields) + } + return fields +} + +func (g jobGatherer) gatherInfoOfPodsForJob( + ctx context.Context, job *batchv1.Job, fields outlogging.Fields, +) { + podsClient := g.kube.Typed().CoreV1().Pods(job.GetNamespace()) + list, err := podsClient.List(ctx, metav1.ListOptions{LabelSelector: "job-name=" + job.GetName()}) + if err != nil { + fields["podlist-err"] = err.Error() + } else { + asJSONIntoFields(list, "pods", fields) + collectPodLogs(ctx, list, podsClient, fields) + eventsClient := g.kube.Typed().CoreV1().Events(job.GetNamespace()) + collectPodEvents(ctx, list, eventsClient, fields) + } +} + +func collectPodLogs( + ctx context.Context, list *corev1.PodList, podsClient typedcorev1.PodInterface, + fields outlogging.Fields, +) { + logs := make(map[string]string, list.Size()) + for _, pod := range list.Items { + podLogs, plerr := podsClient.GetLogs(pod.GetName(), &corev1.PodLogOptions{}).DoRaw(ctx) + if plerr != nil { + fields["podlogs-err"] = plerr.Error() + break + } + logs[pod.GetName()] = string(podLogs) + } + asJSONIntoFields(logs, "logs", fields) +} + +func collectPodEvents( + ctx context.Context, list *corev1.PodList, eventsClient typedcorev1.EventInterface, + fields outlogging.Fields, +) { + events := make(map[string]*corev1.EventList, list.Size()) + for _, pod := range list.Items { + selector := eventsClient.GetFieldSelector( + ptr.String(pod.GetName()), ptr.String(pod.GetNamespace()), + nil, ptr.String(string(pod.UID)), + ).String() + eventList, err := eventsClient.List(ctx, metav1.ListOptions{ + FieldSelector: selector, + }) + if err != nil { + fields["events-err"] = err.Error() + break + } + events[pod.GetName()] = eventList + } + asJSONIntoFields(events, "events", fields) +} + +func asJSONIntoFields(obj any, label string, fields outlogging.Fields) { + if bytes, err := json.Marshal(obj); err == nil { + fields[label] = string(bytes) + } else { + fields[label] = fmt.Sprintf("%#v", obj) + errLabel := label + "-json-marshal-err" + fields[errLabel] = err.Error() + } +} diff --git a/pkg/k8s/jobrunner.go b/pkg/k8s/jobrunner.go index 6a8b62633..be2bcc52c 100644 --- a/pkg/k8s/jobrunner.go +++ b/pkg/k8s/jobrunner.go @@ -8,6 +8,9 @@ import ( batchv1 "k8s.io/api/batch/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/watch" + outlogging "knative.dev/client/pkg/output/logging" + "knative.dev/client/pkg/output/tui" + "knative.dev/kn-plugin-event/pkg/errors" ) // JobRunner will launch a Job and monitor it for completion. @@ -38,8 +41,10 @@ func (j *jobRunner) Run(ctx context.Context, job *batchv1.Job) error { tsk := task{ errs, ready, &sync.WaitGroup{}, } + j.logJobInfo(ctx, "Job to be executed", job) + tasks := []func(context.Context, *batchv1.Job, task){ - // wait is started first, making sure to capture success, even the ultra-fast one. + // wait is started first, making sure to capture success, even the ultra-fast one. j.waitForSuccess, j.createJob, } @@ -66,25 +71,41 @@ func (j *jobRunner) createJob(ctx context.Context, job *batchv1.Job, tsk task) { jobs := j.kube.Typed().BatchV1().Jobs(job.Namespace) _, err := jobs.Create(ctx, job, metav1.CreateOptions{}) if err != nil { - tsk.errs <- fmt.Errorf("%w: %w", ErrICSenderJobFailed, err) + tsk.errs <- errors.Wrap(err, ErrJobFailed) } } func (j *jobRunner) waitForSuccess(ctx context.Context, job *batchv1.Job, tsk task) { defer tsk.wg.Done() - err := j.watchJob(ctx, job, tsk, func(job *batchv1.Job) (bool, error) { - if job.Status.CompletionTime == nil && job.Status.Failed == 0 { + message := "📬 Sending event within the cluster" + spin := tui.NewWidgets(ctx).NewSpinner(message) + err := spin.With(func(sc tui.SpinnerControl) error { + return j.watchJob(ctx, job, tsk, func(job *batchv1.Job) (bool, error) { + if job.Status.Succeeded >= 1 { + j.logJobInfo(ctx, "Successful job", job) + return true, nil + } + limit := int32(0) + if job.Spec.BackoffLimit != nil { + limit = *job.Spec.BackoffLimit + } + if job.Status.Failed > 0 { + retryMsg := fmt.Sprintf(" (try %d/%d)", job.Status.Failed+1, limit) + sc.UpdateMessage(message + retryMsg) + } + if job.Status.Failed >= limit { + sc.UpdateMessage(message) + j.logJobInfo(ctx, "Failed job", job) + return false, fmt.Errorf( + "%w %d times, exceeding the limit (job \"%s\" has been left on "+ + "the cluster for debugging)", + ErrJobFailed, job.Status.Failed, job.GetName()) + } return false, nil - } - // We should be done if we reach here. - if job.Status.Succeeded < 1 { - return false, fmt.Errorf("%w: %s", ErrICSenderJobFailed, - "expected to have successful job") - } - return true, nil + }) }) if err != nil { - tsk.errs <- fmt.Errorf("%w: %w", ErrICSenderJobFailed, err) + tsk.errs <- errors.Wrap(err, ErrJobFailed) } } @@ -100,14 +121,14 @@ func (j *jobRunner) deleteJob(ctx context.Context, job *batchv1.Job) error { PropagationPolicy: &policy, }) if err != nil { - return fmt.Errorf("%w: %w", ErrICSenderJobFailed, err) + return errors.Wrap(err, ErrJobFailed) } pods := j.kube.Typed().CoreV1().Pods(job.GetNamespace()) err = pods.DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{ LabelSelector: "job-name=" + job.GetName(), }) if err != nil { - return fmt.Errorf("%w: %w", ErrICSenderJobFailed, err) + return errors.Wrap(err, ErrJobFailed) } return nil } @@ -123,7 +144,7 @@ func (j *jobRunner) watchJob( FieldSelector: "metadata.name=" + obj.GetName(), }) if err != nil { - return fmt.Errorf("%w: %w", ErrICSenderJobFailed, err) + return errors.Wrap(err, ErrJobFailed) } defer watcher.Stop() resultCh := watcher.ResultChan() @@ -132,13 +153,13 @@ func (j *jobRunner) watchJob( if result.Type == watch.Added || result.Type == watch.Modified { job, ok := result.Object.(*batchv1.Job) if !ok { - return fmt.Errorf("%w: %s: %T", ErrICSenderJobFailed, + return fmt.Errorf("%w: %s: %T", ErrJobFailed, "expected to watch batchv1.Job, got", result.Object) } var brk bool brk, err = changeFn(job) if err != nil { - return fmt.Errorf("%w: %w", ErrICSenderJobFailed, err) + return errors.Wrap(err, ErrJobFailed) } if brk { return nil @@ -147,3 +168,10 @@ func (j *jobRunner) watchJob( } return nil } + +func (j *jobRunner) logJobInfo(ctx context.Context, label string, job *batchv1.Job) { + log := outlogging.LoggerFrom(ctx) + g := jobGatherer{kube: j.kube} + fields := g.gather(ctx, job) + log.WithFields(fields).Debug(label) +} diff --git a/pkg/k8s/jobrunner_test.go b/pkg/k8s/jobrunner_test.go index 75cf0b30d..1eccb8fc0 100644 --- a/pkg/k8s/jobrunner_test.go +++ b/pkg/k8s/jobrunner_test.go @@ -2,56 +2,150 @@ package k8s_test import ( "context" + "fmt" "math/rand" "strconv" "sync" "testing" "time" - "gotest.tools/v3/assert" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" + typedbatchv1 "k8s.io/client-go/kubernetes/typed/batch/v1" + "knative.dev/client/pkg/output" "knative.dev/kn-plugin-event/pkg/k8s" "knative.dev/kn-plugin-event/pkg/tests" + testlogging "knative.dev/pkg/logging/testing" + "knative.dev/pkg/ptr" ) func TestJobRunnerRun(t *testing.T) { - clients := &tests.FakeClients{TB: t, Objects: make([]runtime.Object, 0)} - runner := k8s.NewJobRunner(clients) - job := examplePiJob() - jobs := clients.Typed().BatchV1().Jobs(job.Namespace) - ctx, cancel := context.WithTimeout(context.TODO(), time.Second) - defer cancel() - watcher, err := jobs.Watch(ctx, metav1.ListOptions{}) - assert.NilError(t, err) - wg := sync.WaitGroup{} - wg.Add(1) - go func() { - defer wg.Done() - assert.NilError(t, runner.Run(ctx, &job)) - }() - ev := <-watcher.ResultChan() - assert.Equal(t, ev.Type, watch.Added) - jobc, ok := ev.Object.(*batchv1.Job) - assert.Check(t, ok) - assert.Equal(t, jobc.Name, job.GetName()) - watcher.Stop() - sucJob := jobSuccess(job) - _, err = jobs.Update(ctx, &sucJob, metav1.UpdateOptions{}) - assert.NilError(t, err) - wg.Wait() + t.Parallel() + tcs := []testJobRunnerRunTestCase{{ + "successful", + 1, + nil, + }, { + "failure", + 3, + k8s.ErrJobFailed, + }} + for _, tc := range tcs { + t.Run(tc.name, testJobRunnerRun(tc)) + } +} + +type testJobRunnerRunTestCase struct { + name string + fails int + err error +} + +func testJobRunnerRun(tc testJobRunnerRunTestCase) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + execs := tc.fails + 1 + job := examplePiJob() + objs := make([]runtime.Object, 0, execs) + for i := range execs { + objs = append(objs, podForJob(i, job)) + } + clients := &tests.FakeClients{TB: t, Objects: objs} + runner := k8s.NewJobRunner(clients) + jobs := clients.Typed().BatchV1().Jobs(job.Namespace) + ctx, cancel := context.WithTimeout(testlogging.TestContextWithLogger(t), time.Second) + printer := output.NewTestPrinter() + defer cancel() + ctx = output.WithContext(ctx, printer) + watcher, err := jobs.Watch(ctx, metav1.ListOptions{}) + require.NoError(t, err) + wg := sync.WaitGroup{} + wg.Add(1) + errs := make(chan error) + go func() { + defer wg.Done() + if err := runner.Run(ctx, &job); err != nil { + errs <- err + } + close(errs) + // sleep a little, so the TUI had a chance to print the output + time.Sleep(time.Millisecond) + }() + ev := <-watcher.ResultChan() + assert.Equal(t, watch.Added, ev.Type) + jobc, ok := ev.Object.(*batchv1.Job) + assert.True(t, ok) + assert.Equal(t, jobc.Name, job.GetName()) + watcher.Stop() + + completeJob(ctx, t, tc, job, jobs) + err = <-errs + wg.Wait() + + assert.Contains(t, printer.Outputs().Out.String(), + "Sending event within the cluster") + require.ErrorIs(t, err, tc.err) + if tc.err == nil { + assert.Contains(t, printer.Outputs().Out.String(), + "Done") + } + } +} + +func completeJob( + ctx context.Context, t *testing.T, tc testJobRunnerRunTestCase, + job batchv1.Job, jobs typedbatchv1.JobInterface, +) { + t.Helper() + for range tc.fails { + job = addFailure(job) + _, err := jobs.Update(ctx, &job, metav1.UpdateOptions{}) + require.NoError(t, err) + } + if tc.fails < int(*job.Spec.BackoffLimit) { + job = completeSuccessfully(job) + _, err := jobs.Update(ctx, &job, metav1.UpdateOptions{}) + require.NoError(t, err) + } +} + +func podForJob(i int, job batchv1.Job) *corev1.Pod { + return &corev1.Pod{ + TypeMeta: metav1.TypeMeta{ + Kind: "Pod", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprint("run-", i), + Namespace: job.GetNamespace(), + Labels: map[string]string{ + "job-name": job.GetName(), + }, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Image: "example.org/foo/bar", + }}, + }, + } +} + +func addFailure(job batchv1.Job) batchv1.Job { + job.Status.Failed++ + return job } -func jobSuccess(job batchv1.Job) batchv1.Job { +func completeSuccessfully(job batchv1.Job) batchv1.Job { now := metav1.Now() - job.Status.Succeeded = 1 + job.Status.Succeeded++ job.Status.Active = 0 job.Status.Failed = 0 job.Status.CompletionTime = &now - job.Status.StartTime = &now job.Status.Conditions = []batchv1.JobCondition{{ Type: batchv1.JobComplete, Status: corev1.ConditionTrue, @@ -72,8 +166,10 @@ func examplePiJob() batchv1.Job { Namespace: "demo", }, Spec: batchv1.JobSpec{ + BackoffLimit: ptr.Int32(3), Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ + ActiveDeadlineSeconds: ptr.Int64(10), Containers: []corev1.Container{{ Image: "docker.io/library/perl", Command: []string{"perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"}, diff --git a/pkg/sender/in_cluster.go b/pkg/sender/in_cluster.go index b56dde072..b532b3996 100644 --- a/pkg/sender/in_cluster.go +++ b/pkg/sender/in_cluster.go @@ -2,20 +2,27 @@ package sender import ( "context" - "fmt" cloudevents "github.com/cloudevents/sdk-go/v2" + "github.com/spf13/viper" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/rand" + "knative.dev/kn-plugin-event/pkg/errors" "knative.dev/kn-plugin-event/pkg/event" - ics2 "knative.dev/kn-plugin-event/pkg/ics" + "knative.dev/kn-plugin-event/pkg/ics" "knative.dev/kn-plugin-event/pkg/k8s" "knative.dev/kn-plugin-event/pkg/metadata" ) -const idLength = 16 +const ( + idLength = 6 + retriesDefault = 3 + retriesConfigKey = "plugins.event.in-cluster-sender.retries" + deadlineDefault = 10 // seconds + deadlineConfigKey = "plugins.event.in-cluster-sender.deadline" +) type inClusterSender struct { namespace string @@ -29,11 +36,11 @@ func (i *inClusterSender) Send(ctx context.Context, ce cloudevents.Event) error ctx, i.target.Reference, i.target.RelativeURI, ) if err != nil { - return fmt.Errorf("%w: %w", k8s.ErrInvalidReference, err) + return errors.Wrap(err, k8s.ErrInvalidReference) } - kevent, err := ics2.Encode(ce) - if err != nil { - return fmt.Errorf("%w: %w", ics2.ErrCouldntEncode, err) + kevent, ierr := ics.Encode(ce) + if ierr != nil { + return errors.Wrap(ierr, ics.ErrCouldntEncode) } job := &batchv1.Job{ ObjectMeta: metav1.ObjectMeta{ @@ -44,9 +51,11 @@ func (i *inClusterSender) Send(ctx context.Context, ce cloudevents.Event) error }, }, Spec: batchv1.JobSpec{ + BackoffLimit: retries(), Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ - RestartPolicy: corev1.RestartPolicyNever, + RestartPolicy: corev1.RestartPolicyNever, + ActiveDeadlineSeconds: deadline(), Containers: []corev1.Container{{ Name: "kn-event-sender", Image: metadata.ResolveImage(), @@ -64,11 +73,27 @@ func (i *inClusterSender) Send(ctx context.Context, ce cloudevents.Event) error } err = i.jobRunner.Run(ctx, job) if err != nil { - return fmt.Errorf("%w: %w", ics2.ErrCantSendWithICS, err) + return errors.Wrap(err, ics.ErrICSFailed) } return nil } +func deadline() *int64 { + v := int64(deadlineDefault) + if viper.IsSet(deadlineConfigKey) { + v = viper.GetInt64(deadlineConfigKey) + } + return &v +} + +func retries() *int32 { + v := int32(retriesDefault) + if viper.IsSet(retriesConfigKey) { + v = viper.GetInt32(retriesConfigKey) + } + return &v +} + func newJobName() string { id := rand.String(idLength) return "kn-event-sender-" + id diff --git a/test/e2e-tests.sh b/test/e2e-tests.sh index c589ed970..33ab5cd56 100755 --- a/test/e2e-tests.sh +++ b/test/e2e-tests.sh @@ -2,6 +2,7 @@ set -Eeo pipefail +# shellcheck disable=SC1090 source "$(go run knative.dev/hack/cmd/script e2e-tests.sh)" function start_latest_knative_serving() { diff --git a/test/e2e/ics_send.go b/test/e2e/ics_send.go index d89c4f4e2..769212077 100644 --- a/test/e2e/ics_send.go +++ b/test/e2e/ics_send.go @@ -5,27 +5,27 @@ package e2e import ( "context" "fmt" - "strings" + "os" + "path" cloudevents "github.com/cloudevents/sdk-go/v2" cetest "github.com/cloudevents/sdk-go/v2/test" "github.com/stretchr/testify/assert" "gotest.tools/v3/icmd" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + configdir "knative.dev/client/pkg/config/dir" "knative.dev/kn-plugin-event/test" - kubeclient "knative.dev/pkg/client/injection/kube/client" "knative.dev/pkg/logging" "knative.dev/reconciler-test/pkg/environment" "knative.dev/reconciler-test/pkg/eventshub" eventshubassert "knative.dev/reconciler-test/pkg/eventshub/assert" "knative.dev/reconciler-test/pkg/feature" - "sigs.k8s.io/yaml" ) const ( issue228Warn = "child pods are preserved by default when jobs are deleted; " + "set propagationPolicy=Background to remove them or set " + "propagationPolicy=Orphan to suppress this warning" + dirPerm = 0o750 ) // SendEventFeature will create a feature.Feature that will test sending an @@ -63,6 +63,15 @@ func sendEvent(ev cloudevents.Event, sink Sink) feature.StepFn { "--to", sink.String(), } cmd := test.ResolveKnEventCommand(t).ToIcmd(args...) + artifacts := os.Getenv("ARTIFACTS") + if artifacts == "" { + artifacts = os.TempDir() + } + cacheDir := path.Join(artifacts, t.Name()) + if err := os.MkdirAll(cacheDir, dirPerm); err != nil { + t.Fatal(err) + } + cmd.Env = append(os.Environ(), configdir.CacheDirEnvName+"="+cacheDir) log = log.With(json("cmd", cmd)) log.Info("Running") result := icmd.RunCmd(cmd) @@ -70,7 +79,8 @@ func sendEvent(ev cloudevents.Event, sink Sink) feature.StepFn { ExitCode: 0, Err: fmt.Sprintf("Event (ID: %s) have been sent.", ev.ID()), }); err != nil { - handleSendErr(ctx, t, err, ev) + t.Fatal(err, "\n\nExecution log: "+ + path.Join(cacheDir, "last-exec.log.jsonl")) } assert.NotContains(t, result.Stderr(), issue228Warn) log.Info("Succeeded") @@ -82,59 +92,3 @@ func receiveEvent(ev cloudevents.Event, sinkName string) feature.StepFn { MatchEvent(cetest.HasId(ev.ID())). Exact(1) } - -// handleSendErr will handle the error from sending event. -func handleSendErr(ctx context.Context, t feature.T, err error, ev cloudevents.Event) { - // TODO: most of this code should be moved to production CLI, so that in case - // of send error, a nice, report is produced. - // See: https://github.com/knative-extensions/kn-plugin-event/issues/129 - if err == nil { - return - } - kube := kubeclient.Get(ctx) - ns := environment.FromContext(ctx).Namespace() - log := logging.FromContext(ctx) - jobs := kube.BatchV1().Jobs(ns) - pods := kube.CoreV1().Pods(ns) - events := kube.CoreV1().Events(ns) - jlist, kerr := jobs.List(ctx, metav1.ListOptions{ - LabelSelector: "event-id=" + ev.ID(), - }) - if kerr != nil { - log.Error(kerr) - } - if len(jlist.Items) != 1 { - t.Fatal(err) - } - jobName := jlist.Items[0].Name - plist, kerr := pods.List(ctx, metav1.ListOptions{ - LabelSelector: "job-name=" + jobName, - }) - if kerr != nil { - log.Error(kerr) - } - podLogs := make([]string, 0, len(plist.Items)) - for _, item := range plist.Items { - var bytes []byte - bytes, kerr = pods.GetLogs(item.Name, nil).DoRaw(ctx) - if kerr != nil { - log.Error(kerr) - } - podLogs = append(podLogs, string(bytes)) - } - podsYaml, merr := yaml.Marshal(plist.Items) - if merr != nil { - log.Error(merr) - } - elist, eerr := events.List(ctx, metav1.ListOptions{}) - if eerr != nil { - log.Error(eerr) - } - eventsYaml, eerr := yaml.Marshal(elist.Items) - if eerr != nil { - log.Error(eerr) - } - t.Fatal(err, "\n\nJob logs (", len(plist.Items), "):\n", - strings.Join(podLogs, "\n---\n"), "\n\nPods:\n", - string(podsYaml), "\n\nEvents:\n", string(eventsYaml)) -}