From 24df947ee1f66e54bf72776080602898b99732d0 Mon Sep 17 00:00:00 2001 From: Andrew Seigner Date: Tue, 4 May 2021 16:47:22 -0700 Subject: [PATCH] Add Buoyant Cloud Agent to repo (#15) The Buoyant Cloud Agent was previously developed in a private repo. Move Buoyant Cloud Agent into this repo. This consolidates the Linkerd Buoyant extension CLI and agent into one place, and couples their release cycles. No functional changes to the CLI or agent in this branch. The CLI is moved under a `cli` directory, and same with `agent`. Future agent Docker images are moving from: `ghcr.io/buoyantio/bcloud-agent:*` to: `ghcr.io/buoyantio/linkerd-buoyant:*` Signed-off-by: Andrew Seigner --- .github/workflows/actions.yml | 69 +- .gitignore | 1 + README.md | 52 +- agent/Dockerfile | 22 + agent/main.go | 162 +++ agent/pkg/api/api.go | 33 + agent/pkg/api/api_test.go | 10 + agent/pkg/api/event.go | 22 + agent/pkg/api/event_test.go | 66 + agent/pkg/api/test_helpers.go | 122 ++ agent/pkg/api/workload.go | 79 ++ agent/pkg/api/workload_test.go | 99 ++ agent/pkg/handler/event.go | 65 + agent/pkg/handler/event_test.go | 171 +++ agent/pkg/handler/workload.go | 276 ++++ agent/pkg/handler/workload_test.go | 317 +++++ agent/pkg/k8s/event.go | 127 ++ agent/pkg/k8s/event_test.go | 111 ++ agent/pkg/k8s/helpers_test.go | 15 + agent/pkg/k8s/k8s.go | 147 ++ agent/pkg/k8s/k8s_test.go | 80 ++ agent/pkg/k8s/workload.go | 159 +++ agent/pkg/k8s/workload_test.go | 243 ++++ bin/gen-proto | 34 + bin/go-run | 15 + bin/protoc | 31 + {cmd => cli/cmd}/check.go | 4 +- {cmd => cli/cmd}/check_test.go | 2 +- {cmd => cli/cmd}/config.go | 0 {cmd => cli/cmd}/config_test.go | 0 {cmd => cli/cmd}/dashboard.go | 0 {cmd => cli/cmd}/dashboard_test.go | 0 {cmd => cli/cmd}/install.go | 2 +- {cmd => cli/cmd}/install_test.go | 4 +- {cmd => cli/cmd}/root.go | 2 +- {cmd => cli/cmd}/uninstall.go | 2 +- {cmd => cli/cmd}/uninstall_test.go | 2 +- {cmd => cli/cmd}/version.go | 4 +- {cmd => cli/cmd}/version_test.go | 2 +- main.go => cli/main.go | 2 +- {pkg => cli/pkg}/healthcheck/healthcheck.go | 4 +- .../pkg}/healthcheck/healthcheck_test.go | 4 +- {pkg => cli/pkg}/k8s/agent.go | 0 {pkg => cli/pkg}/k8s/agent_test.go | 0 {pkg => cli/pkg}/k8s/client.go | 0 {pkg => cli/pkg}/k8s/client_test.go | 0 {pkg => cli/pkg}/k8s/mock_client.go | 0 {pkg => cli/pkg}/k8s/resource.go | 0 {pkg => cli/pkg}/k8s/resource_test.go | 0 {pkg => cli/pkg}/version/version.go | 0 {pkg => cli/pkg}/version/version_test.go | 0 gen/bcloud/buoyant-cloud-api.pb.go | 1250 +++++++++++++++++ gen/bcloud/buoyant-cloud-api_grpc.pb.go | 172 +++ go.mod | 13 +- go.sum | 136 +- proto/buoyant-cloud-api.proto | 102 ++ 56 files changed, 4163 insertions(+), 72 deletions(-) create mode 100644 agent/Dockerfile create mode 100644 agent/main.go create mode 100644 agent/pkg/api/api.go create mode 100644 agent/pkg/api/api_test.go create mode 100644 agent/pkg/api/event.go create mode 100644 agent/pkg/api/event_test.go create mode 100644 agent/pkg/api/test_helpers.go create mode 100644 agent/pkg/api/workload.go create mode 100644 agent/pkg/api/workload_test.go create mode 100644 agent/pkg/handler/event.go create mode 100644 agent/pkg/handler/event_test.go create mode 100644 agent/pkg/handler/workload.go create mode 100644 agent/pkg/handler/workload_test.go create mode 100644 agent/pkg/k8s/event.go create mode 100644 agent/pkg/k8s/event_test.go create mode 100644 agent/pkg/k8s/helpers_test.go create mode 100644 agent/pkg/k8s/k8s.go create mode 100644 agent/pkg/k8s/k8s_test.go create mode 100644 agent/pkg/k8s/workload.go create mode 100644 agent/pkg/k8s/workload_test.go create mode 100755 bin/gen-proto create mode 100755 bin/go-run create mode 100755 bin/protoc rename {cmd => cli/cmd}/check.go (94%) rename {cmd => cli/cmd}/check_test.go (88%) rename {cmd => cli/cmd}/config.go (100%) rename {cmd => cli/cmd}/config_test.go (100%) rename {cmd => cli/cmd}/dashboard.go (100%) rename {cmd => cli/cmd}/dashboard_test.go (100%) rename {cmd => cli/cmd}/install.go (98%) rename {cmd => cli/cmd}/install_test.go (98%) rename {cmd => cli/cmd}/root.go (97%) rename {cmd => cli/cmd}/uninstall.go (97%) rename {cmd => cli/cmd}/uninstall_test.go (93%) rename {cmd => cli/cmd}/version.go (93%) rename {cmd => cli/cmd}/version_test.go (96%) rename main.go => cli/main.go (81%) rename {pkg => cli/pkg}/healthcheck/healthcheck.go (98%) rename {pkg => cli/pkg}/healthcheck/healthcheck_test.go (97%) rename {pkg => cli/pkg}/k8s/agent.go (100%) rename {pkg => cli/pkg}/k8s/agent_test.go (100%) rename {pkg => cli/pkg}/k8s/client.go (100%) rename {pkg => cli/pkg}/k8s/client_test.go (100%) rename {pkg => cli/pkg}/k8s/mock_client.go (100%) rename {pkg => cli/pkg}/k8s/resource.go (100%) rename {pkg => cli/pkg}/k8s/resource_test.go (100%) rename {pkg => cli/pkg}/version/version.go (100%) rename {pkg => cli/pkg}/version/version_test.go (100%) create mode 100644 gen/bcloud/buoyant-cloud-api.pb.go create mode 100644 gen/bcloud/buoyant-cloud-api_grpc.pb.go create mode 100644 proto/buoyant-cloud-api.proto diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 65d5ff6..99d50c0 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -26,7 +26,7 @@ jobs: uses: actions/checkout@v2 - name: Test - run: go test -race -v ./... + run: go test -race -mod=readonly -cover -v ./... go_lint: name: Go Lint @@ -83,7 +83,7 @@ jobs: run: echo "linkerd-buoyant-bin=linkerd-buoyant-${{ env.tag }}-${{ matrix.platform }}${{ matrix.exe }}" >> $GITHUB_ENV - name: Build CLI - run: CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build -o ${{ env.linkerd-buoyant-bin }} -mod=readonly -ldflags "-s -w -X github.com/buoyantio/linkerd-buoyant/pkg/version.Version=${{ env.tag }}" + run: CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build -o ${{ env.linkerd-buoyant-bin }} -mod=readonly -ldflags "-s -w -X github.com/buoyantio/linkerd-buoyant/cli/pkg/version.Version=${{ env.tag }}" cli/main.go - name: Upload CLI Executable uses: actions/upload-artifact@v2 @@ -127,6 +127,66 @@ jobs: chmod +x ${{ env.linkerd-buoyant-bin }} ./${{ env.linkerd-buoyant-bin }} version --cli + # everything below here for main merges or releases (tags) + docker_build_and_push: + name: Docker Build and Push + if: startsWith(github.ref, 'refs/tags') || github.ref == 'refs/heads/main' + needs: + - go_unit_tests + - go_lint + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Cache Docker layers + uses: actions/cache@v2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Login to GHCR + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Generate Docker tags (for main) + if: github.ref == 'refs/heads/main' + run: | + echo "platforms=linux/amd64" >> $GITHUB_ENV + echo "docker_tags=ghcr.io/buoyantio/linkerd-buoyant:latest" >> $GITHUB_ENV + - name: Generate Docker tags (for tagged release) + if: startsWith(github.ref, 'refs/tags') + run: | + echo "platforms=linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7" >> $GITHUB_ENV + echo "docker_tags=ghcr.io/buoyantio/linkerd-buoyant:latest,ghcr.io/buoyantio/linkerd-buoyant:${GITHUB_REF##*/}" >> $GITHUB_ENV + + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + file: agent/Dockerfile + platforms: ${{ env.platforms }} + push: true + tags: ${{ env.docker_tags }} + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new + - name: Move cache + # Temp fix + # https://github.com/docker/build-push-action/issues/252 + # https://github.com/moby/buildkit/issues/1896 + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache + # everything below here for releases (tags) create_release: if: startsWith(github.ref, 'refs/tags') @@ -135,6 +195,7 @@ jobs: - go_unit_tests - go_lint - smoke_test_cli + - docker_build_and_push runs-on: ubuntu-20.04 outputs: upload_url: ${{ steps.create_release.outputs.upload_url }} @@ -146,8 +207,8 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ github.ref }} - release_name: Release ${{ github.ref }} - draft: false + release_name: ${{ github.ref }} + draft: true prerelease: false upload_release_assets: diff --git a/.gitignore b/.gitignore index eb5a316..326a8dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ +.gorun target diff --git a/README.md b/README.md index ad27c6c..b27b40a 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,16 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/buoyantio/linkerd-buoyant)](https://goreportcard.com/report/github.com/buoyantio/linkerd-buoyant) [![GitHub license](https://img.shields.io/github/license/buoyantio/linkerd-buoyant.svg)](LICENSE) -The Linkerd Buoyant extension is a CLI tool for managing the Buoyant Cloud -Agent. +The Linkerd Buoyant extension connects your +[Linkerd](https://linkerd.io)-enabled Kubernetes cluster to +[Buoyant Cloud](https://buoyant.cloud), the global platform health dashboard for +Linkerd. -## Install +This repo consists of two components: +- [`agent`](agent): Runs on your Kubernetes cluster. +- [`cli`](cli): Runs locally or wherever you install the Linkerd CLI. + +## Install CLI To install the CLI, run: @@ -18,7 +24,7 @@ curl -sL https://buoyant.cloud/install | sh Alternatively, you can download the CLI directly via the [releases page](https://github.com/BuoyantIO/linkerd-buoyant/releases). -## Usage +### Usage ```bash $ linkerd-buoyant @@ -48,19 +54,49 @@ Use "linkerd-buoyant [command] --help" for more information about a command. ## Development -Run locally: +### Agent + +Build and run: +```bash +bin/go-run agent +``` + +Docker build: +```bash +docker buildx build -f agent/Dockerfile -t ghcr.io/buoyantio/linkerd-buoyant:latest . +``` + +### CLI + +Build and run: ```bash -go run main.go +bin/go-run cli ``` Run with a version number: ```bash -go run -ldflags "-s -w -X github.com/buoyantio/linkerd-buoyant/pkg/version.Version=vX.Y.Z" main.go version +go run -ldflags "-s -w -X github.com/buoyantio/linkerd-buoyant/cli/pkg/version.Version=vX.Y.Z" cli/main.go version ``` Test against a local server: ```bash -go run main.go --bcloud-server http://localhost:8084 +bin/go-run cli --bcloud-server http://localhost:8084 check +``` + +### Protobuf + +The generated protobuf bindings in `gen` come from the `proto` directory in this +repo. If you make changes there, re-generate them with: + +```bash +bin/gen-proto +``` + +### Testing + +```bash +go test -race -cover ./... +bin/lint ``` ## Release diff --git a/agent/Dockerfile b/agent/Dockerfile new file mode 100644 index 0000000..f838c25 --- /dev/null +++ b/agent/Dockerfile @@ -0,0 +1,22 @@ +FROM golang:1.16.2-buster as golang + +WORKDIR /bcloud-build + +COPY go.mod go.mod +COPY go.sum go.sum +RUN go mod download + +COPY agent/main.go agent/main.go +COPY agent/pkg agent/pkg +COPY gen gen +RUN CGO_ENABLED=0 GOOS=linux go build -o /bcloud-agent -mod=readonly agent/main.go + + +FROM debian:buster-20210208-slim + +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=golang /bcloud-agent . +ENTRYPOINT ["./bcloud-agent"] diff --git a/agent/main.go b/agent/main.go new file mode 100644 index 0000000..37caa15 --- /dev/null +++ b/agent/main.go @@ -0,0 +1,162 @@ +package main + +import ( + "crypto/tls" + "flag" + "os" + "os/signal" + "syscall" + "time" + + "github.com/buoyantio/linkerd-buoyant/agent/pkg/api" + "github.com/buoyantio/linkerd-buoyant/agent/pkg/handler" + "github.com/buoyantio/linkerd-buoyant/agent/pkg/k8s" + pb "github.com/buoyantio/linkerd-buoyant/gen/bcloud" + "github.com/linkerd/linkerd2/pkg/admin" + log "github.com/sirupsen/logrus" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/klog" + + // Load all the auth plugins for the cloud providers. + // This enables connecting to a k8s cluster from outside the cluster, during + // development. + _ "k8s.io/client-go/plugin/pkg/client/auth" +) + +func dieIf(err error) { + if err != nil { + log.Fatal(err.Error()) + } +} + +func main() { + bcloudID := flag.String("bcloud-id", "", "bcloud id, takes precedence over BUOYANT_CLOUD_ID env var") + bcloudKey := flag.String("bcloud-key", "", "bcloud key, takes precedence over BUOYANT_CLOUD_KEY env var") + adminAddr := flag.String("admin-addr", ":9990", "address of agent admin server") + grpcAddr := flag.String("grpc-addr", "api.buoyant.cloud:443", "address of the Buoyant Cloud API") + kubeConfigPath := flag.String("kubeconfig", "", "path to kube config") + logLevel := flag.String("log-level", "info", "log level, must be one of: panic, fatal, error, warn, info, debug, trace") + insecure := flag.Bool("insecure", false, "disable TLS in development mode") + + // klog flags + klog.InitFlags(nil) + flag.Set("stderrthreshold", "FATAL") + flag.Set("logtostderr", "true") + flag.Set("v", "0") + + flag.Parse() + + // set global log level and format + + level, err := log.ParseLevel(*logLevel) + dieIf(err) + log.SetLevel(level) + log.SetFormatter(&log.TextFormatter{FullTimestamp: true}) + + // klog flags for debugging + if level >= log.DebugLevel { + flag.Set("stderrthreshold", "INFO") + flag.Set("v", "6") // At 7 and higher, authorization tokens get logged. + } + // pipe klog entries to logrus + klog.SetOutput(log.StandardLogger().Writer()) + + // handle interrupts + + stop := make(chan os.Signal, 1) + signal.Notify(stop, os.Interrupt, syscall.SIGTERM) + shutdown := make(chan struct{}, 1) + + // read the bcloud ID from flag or environment variable + + id := os.Getenv("BUOYANT_CLOUD_ID") + if *bcloudID != "" { + id = *bcloudID + } + if id == "" { + log.Fatal("missing bcloud id! set -bcloud-id flag or BUOYANT_CLOUD_ID env var") + } + log.Debugf("using bcloud id %s", id) + + key := os.Getenv("BUOYANT_CLOUD_KEY") + if *bcloudKey != "" { + key = *bcloudKey + } + if key == "" { + log.Fatal("missing bcloud key! set -bcloud-key flag or BUOYANT_CLOUD_KEY env var") + } + + // setup kubernetes clients and shared informers + + rules := clientcmd.NewDefaultClientConfigLoadingRules() + if *kubeConfigPath != "" { + rules.ExplicitPath = *kubeConfigPath + } + + k8sConfig, err := clientcmd. + NewNonInteractiveDeferredLoadingClientConfig(rules, &clientcmd.ConfigOverrides{}). + ClientConfig() + dieIf(err) + + k8sCS, err := kubernetes.NewForConfig(k8sConfig) + dieIf(err) + sharedInformers := informers.NewSharedInformerFactory(k8sCS, 10*time.Minute) + + k8sClient := k8s.NewClient(sharedInformers) + + // wait for discovery API to load + + log.Info("waiting for Kubernetes API availability") + populateGroupList := func() (done bool, err error) { + _, err = k8sCS.DiscoveryClient.ServerGroups() + if err != nil { + log.Debug("cannot reach Kubernetes API; retrying") + return false, nil + } + log.Info("Kubernetes API reached") + return true, nil + } + err = wait.PollImmediate(time.Second, time.Minute, populateGroupList) + dieIf(err) + + // create bcloud grpc api client and streams + + var opts grpc.DialOption + if *insecure { + opts = grpc.WithInsecure() + } else { + creds := credentials.NewTLS(&tls.Config{}) + opts = grpc.WithTransportCredentials(creds) + } + conn, err := grpc.Dial(*grpcAddr, opts) + dieIf(err) + + bcloudClient := pb.NewApiClient(conn) + apiClient := api.NewClient(id, key, bcloudClient) + + // create handlers + eventHandler := handler.NewEvent(k8sClient, apiClient) + workloadHandler := handler.NewWorkload(k8sClient, apiClient) + + // start shared informer and wait for sync + err = k8sClient.Sync(shutdown, 60*time.Second) + dieIf(err) + + // start handlers + go eventHandler.Start(sharedInformers) + go workloadHandler.Start(sharedInformers) + + // run admin server + go admin.StartServer(*adminAddr) + + // wait for shutdown + <-stop + log.Info("shutting down") + workloadHandler.Stop() + close(shutdown) +} diff --git a/agent/pkg/api/api.go b/agent/pkg/api/api.go new file mode 100644 index 0000000..bb6a3b5 --- /dev/null +++ b/agent/pkg/api/api.go @@ -0,0 +1,33 @@ +package api + +import ( + "sync" + + pb "github.com/buoyantio/linkerd-buoyant/gen/bcloud" + log "github.com/sirupsen/logrus" +) + +// Client provides a simple Buoyant Cloud API client. +type Client struct { + auth *pb.Auth + + client pb.ApiClient + stream pb.Api_WorkloadStreamClient + + log *log.Entry + + // protects stream + sync.Mutex +} + +// NewClient instantiates a new Buoyant Cloud API client. +func NewClient(id string, key string, client pb.ApiClient) *Client { + return &Client{ + auth: &pb.Auth{ + AgentId: id, + AgentKey: key, + }, + client: client, + log: log.WithField("api", id), + } +} diff --git a/agent/pkg/api/api_test.go b/agent/pkg/api/api_test.go new file mode 100644 index 0000000..abfb97c --- /dev/null +++ b/agent/pkg/api/api_test.go @@ -0,0 +1,10 @@ +package api + +import "testing" + +func TestNewClient(t *testing.T) { + c := NewClient("", "", nil) + if c == nil { + t.Errorf("Unexpected nil client") + } +} diff --git a/agent/pkg/api/event.go b/agent/pkg/api/event.go new file mode 100644 index 0000000..37360dc --- /dev/null +++ b/agent/pkg/api/event.go @@ -0,0 +1,22 @@ +package api + +import ( + "context" + + pb "github.com/buoyantio/linkerd-buoyant/gen/bcloud" + "google.golang.org/protobuf/encoding/prototext" +) + +// AddEvent wraps the Buoyant Cloud API AddEvent gRPC unary endpoint. +func (c *Client) AddEvent(event *pb.Event) error { + // create new message with Auth + bcloudEvent := &pb.Event{ + Auth: c.auth, + Event: event.Event, + Owner: event.Owner, + } + c.log.Tracef("AddEvent: %s", prototext.Format(bcloudEvent)) + + _, err := c.client.AddEvent(context.Background(), bcloudEvent) + return err +} diff --git a/agent/pkg/api/event_test.go b/agent/pkg/api/event_test.go new file mode 100644 index 0000000..669a605 --- /dev/null +++ b/agent/pkg/api/event_test.go @@ -0,0 +1,66 @@ +package api + +import ( + "errors" + "testing" + + pb "github.com/buoyantio/linkerd-buoyant/gen/bcloud" +) + +func TestAddEvent(t *testing.T) { + t.Run("calls the api and gets a response", func(t *testing.T) { + fixtures := []*struct { + testName string + event *pb.Event + err error + }{ + { + "bad API response", + &pb.Event{}, + errors.New("bad response"), + }, + { + "empty event", + &pb.Event{}, + nil, + }, + } + + for _, tc := range fixtures { + tc := tc + t.Run(tc.testName, func(t *testing.T) { + m := &MockBcloudClient{err: tc.err} + c := NewClient("", "", m) + + err := c.AddEvent(tc.event) + if tc.err != err { + t.Errorf("Expected %s, got %s", tc.err, err) + } + + if len(m.Events()) != 1 { + t.Errorf("Expected 1 event, got %d", len(m.Events())) + } + }) + } + }) + + t.Run("sets auth info", func(t *testing.T) { + fakeID := "fake-id" + fakeKey := "fake-key" + + m := &MockBcloudClient{} + c := NewClient(fakeID, fakeKey, m) + + err := c.AddEvent(&pb.Event{}) + if err != nil { + t.Error(err) + } + + if m.id != fakeID { + t.Errorf("Expected %s, got %s", fakeID, m.id) + } + if m.key != fakeKey { + t.Errorf("Expected %s, got %s", fakeKey, m.key) + } + }) +} diff --git a/agent/pkg/api/test_helpers.go b/agent/pkg/api/test_helpers.go new file mode 100644 index 0000000..352b383 --- /dev/null +++ b/agent/pkg/api/test_helpers.go @@ -0,0 +1,122 @@ +package api + +import ( + "context" + "sync" + + pb "github.com/buoyantio/linkerd-buoyant/gen/bcloud" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +// MockBcloudClient satisfies the bcloud.ApiClient and +// bcloud.Api_WorkloadStreamClient interfaces, and saves all params and messages +// passed to it. +type MockBcloudClient struct { + // input + err error + + // output + id string + key string + messages []*pb.WorkloadMessage + events []*pb.Event + + // protects messages and events + sync.Mutex +} + +// +// MockBcloudClient methods +// + +func (m *MockBcloudClient) Events() []*pb.Event { + m.Lock() + defer m.Unlock() + + events := make([]*pb.Event, len(m.events)) + for i, e := range m.events { + events[i] = e + } + + return events +} + +func (m *MockBcloudClient) Messages() []*pb.WorkloadMessage { + m.Lock() + defer m.Unlock() + + messages := make([]*pb.WorkloadMessage, len(m.messages)) + for i, m := range m.messages { + messages[i] = m + } + + return messages +} + +// +// bcloud.ApiClient methods +// + +func (m *MockBcloudClient) WorkloadStream( + ctx context.Context, _ ...grpc.CallOption, +) (pb.Api_WorkloadStreamClient, error) { + return m, m.err +} + +func (m *MockBcloudClient) AddEvent( + ctx context.Context, event *pb.Event, _ ...grpc.CallOption, +) (*pb.Empty, error) { + m.Lock() + defer m.Unlock() + + m.id = event.GetAuth().GetAgentId() + m.key = event.GetAuth().GetAgentKey() + m.events = append(m.events, event) + return nil, m.err +} + +// +// bcloud.Api_WorkloadStreamClient methods +// + +func (m *MockBcloudClient) Send(msg *pb.WorkloadMessage) error { + m.Lock() + defer m.Unlock() + + _, ok := msg.Message.(*pb.WorkloadMessage_Auth) + if ok { + m.id = msg.GetAuth().GetAgentId() + m.key = msg.GetAuth().GetAgentKey() + } + + m.messages = append(m.messages, msg) + return nil +} + +func (m *MockBcloudClient) CloseAndRecv() (*pb.Empty, error) { + return nil, nil +} + +// +// grpc.ClientStream methods +// + +func (m *MockBcloudClient) Header() (metadata.MD, error) { + return nil, nil +} +func (m *MockBcloudClient) Trailer() metadata.MD { + return nil +} +func (m *MockBcloudClient) CloseSend() error { + return nil +} +func (m *MockBcloudClient) Context() context.Context { + return nil +} +func (m *MockBcloudClient) SendMsg(_ interface{}) error { + return nil +} +func (m *MockBcloudClient) RecvMsg(_ interface{}) error { + return nil +} diff --git a/agent/pkg/api/workload.go b/agent/pkg/api/workload.go new file mode 100644 index 0000000..8bde724 --- /dev/null +++ b/agent/pkg/api/workload.go @@ -0,0 +1,79 @@ +package api + +import ( + "context" + "io" + "time" + + pb "github.com/buoyantio/linkerd-buoyant/gen/bcloud" +) + +// WorkloadStream wraps the Buoyant Cloud API WorkloadStream gRPC endpoint, and +// manages the client-side stream. +func (c *Client) WorkloadStream(msg *pb.WorkloadMessage) error { + // loop and reset the stream if it has been closed + for { + err := c.sendMessage(msg) + if err == io.EOF { + c.log.Info("WorkloadStream closed") + c.resetStream() + continue + } else if err != nil { + c.log.Errorf("WorkloadStream failed to send: %s", err) + } + + return err + } +} + +func (c *Client) sendMessage(msg *pb.WorkloadMessage) error { + c.Lock() + defer c.Unlock() + if c.stream == nil { + c.stream = c.newStream() + } + + return c.stream.Send(msg) +} + +func (c *Client) newStream() pb.Api_WorkloadStreamClient { + var stream pb.Api_WorkloadStreamClient + + // loop until the request to initiate a stream succeeds + for { + var err error + stream, err = c.client.WorkloadStream(context.Background()) + if err != nil { + c.log.Errorf("failed to initiate stream: %s", err) + time.Sleep(100 * time.Millisecond) + continue + } + + c.log.Info("WorkloadStream opened") + + err = stream.Send(&pb.WorkloadMessage{ + Message: &pb.WorkloadMessage_Auth{ + Auth: c.auth, + }, + }) + if err != nil { + c.log.Errorf("failed to send auth message: %s", err) + time.Sleep(100 * time.Millisecond) + continue + } + + break + } + + c.log.Info("WorkloadStream connected") + return stream +} + +func (c *Client) resetStream() { + c.Lock() + defer c.Unlock() + if c.stream != nil { + c.stream.CloseSend() + c.stream = nil + } +} diff --git a/agent/pkg/api/workload_test.go b/agent/pkg/api/workload_test.go new file mode 100644 index 0000000..49ef727 --- /dev/null +++ b/agent/pkg/api/workload_test.go @@ -0,0 +1,99 @@ +package api + +import ( + "testing" + + pb "github.com/buoyantio/linkerd-buoyant/gen/bcloud" +) + +func TestWorkloadStream(t *testing.T) { + t.Run("streams a workload message", func(t *testing.T) { + fixtures := []*struct { + testName string + msgs []*pb.WorkloadMessage + msgCount int + }{ + { + "no workload messages", + nil, + 0, + }, + { + "one workload message", + []*pb.WorkloadMessage{{}}, + 2, + }, + { + "two workload message", + []*pb.WorkloadMessage{{}, {}}, + 3, + }, + } + + for _, tc := range fixtures { + tc := tc + t.Run(tc.testName, func(t *testing.T) { + m := &MockBcloudClient{} + c := NewClient("", "", m) + + for _, msg := range tc.msgs { + err := c.WorkloadStream(msg) + if err != nil { + t.Error(err) + } + } + + if len(m.Messages()) != tc.msgCount { + t.Errorf("Expected %d message, got %d", tc.msgCount, len(m.Messages())) + } + }) + } + }) + + t.Run("sets auth info", func(t *testing.T) { + fakeID := "fake-id" + fakeKey := "fake-key" + + fixtures := []*struct { + testName string + msgs []*pb.WorkloadMessage + expID string + expKey string + }{ + { + "auth not set", + nil, + "", + "", + }, + { + "auth set", + []*pb.WorkloadMessage{{}}, + fakeID, + fakeKey, + }, + } + + for _, tc := range fixtures { + tc := tc + t.Run(tc.testName, func(t *testing.T) { + m := &MockBcloudClient{} + c := NewClient(fakeID, fakeKey, m) + + for _, msg := range tc.msgs { + err := c.WorkloadStream(msg) + if err != nil { + t.Error(err) + } + } + + if m.id != tc.expID { + t.Errorf("Expected %s, got %s", tc.expID, m.id) + } + if m.key != tc.expKey { + t.Errorf("Expected %s, got %s", tc.expKey, m.key) + } + }) + } + }) +} diff --git a/agent/pkg/handler/event.go b/agent/pkg/handler/event.go new file mode 100644 index 0000000..08fbd70 --- /dev/null +++ b/agent/pkg/handler/event.go @@ -0,0 +1,65 @@ +package handler + +import ( + "github.com/buoyantio/linkerd-buoyant/agent/pkg/api" + "github.com/buoyantio/linkerd-buoyant/agent/pkg/k8s" + log "github.com/sirupsen/logrus" + v1 "k8s.io/api/core/v1" + "k8s.io/client-go/informers" + "k8s.io/client-go/tools/cache" +) + +// Event listens to the k8s API for events, and forwards them to the Buoyant +// Cloud API. +type Event struct { + api *api.Client + k8s *k8s.Client + log *log.Entry +} + +// NewEvent instantiates a new k8s event handler. +func NewEvent(k8sClient *k8s.Client, apiClient *api.Client) *Event { + log := log.WithField("handler", "event") + log.Debug("initializing") + + return &Event{ + api: apiClient, + k8s: k8sClient, + log: log, + } +} + +// Start initiates listening to a k8s event handler. +func (h *Event) Start(sharedInformers informers.SharedInformerFactory) { + sharedInformers.Core().V1().Events().Informer().AddEventHandler( + cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + event := obj.(*v1.Event) + h.handleEvent(event) + }, + }, + ) +} + +func (h *Event) handleEvent(event *v1.Event) error { + h.log.Tracef("handleEvent: %+v\n", event) + + e, err := h.k8s.EventToPB(event) + if err != nil { + h.log.Errorf("Failed to create event: %s", err) + return err + } + + if e == nil { + h.log.Tracef("non-workload event, skipping: [%+v]", event) + return nil + } + + err = h.api.AddEvent(e) + if err != nil { + h.log.Errorf("Failed to send event: %s", err) + return err + } + + return nil +} diff --git a/agent/pkg/handler/event_test.go b/agent/pkg/handler/event_test.go new file mode 100644 index 0000000..907a1da --- /dev/null +++ b/agent/pkg/handler/event_test.go @@ -0,0 +1,171 @@ +package handler + +import ( + "context" + "testing" + "time" + + "github.com/buoyantio/linkerd-buoyant/agent/pkg/api" + "github.com/buoyantio/linkerd-buoyant/agent/pkg/k8s" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes/fake" +) + +func TestEvent(t *testing.T) { + dsName := "fake-ds" + dsNamespace := "fake-ds-ns" + deployName := "fake-deploy" + deployNamespace := "fake-deploy-ns" + + fixtures := []*struct { + testName string + events []*corev1.Event + objs []runtime.Object + expEvents int + }{ + { + "no events", + nil, + nil, + 0, + }, + { + "one event", + []*corev1.Event{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-event", + }, + InvolvedObject: corev1.ObjectReference{ + Kind: k8s.DaemonSet, + Name: dsName, + Namespace: dsNamespace, + }, + }, + }, + []runtime.Object{ + &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: dsName, + Namespace: dsNamespace, + }, + Spec: appsv1.DaemonSetSpec{ + Selector: &metav1.LabelSelector{}, + }, + }, + }, + 1, + }, + { + "one daemonset event and one deployment event", + []*corev1.Event{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "ds-event", + }, + InvolvedObject: corev1.ObjectReference{ + Kind: k8s.DaemonSet, + Name: dsName, + Namespace: dsNamespace, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "deploy-event", + }, + InvolvedObject: corev1.ObjectReference{ + Kind: k8s.Deployment, + Name: deployName, + Namespace: deployNamespace, + }, + }, + }, + []runtime.Object{ + &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: dsName, + Namespace: dsNamespace, + }, + Spec: appsv1.DaemonSetSpec{ + Selector: &metav1.LabelSelector{}, + }, + }, + &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: deployName, + Namespace: deployNamespace, + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{}, + }, + }, + }, + 2, + }, + { + "one event without an owner", + []*corev1.Event{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-event", + }, + InvolvedObject: corev1.ObjectReference{ + Kind: k8s.DaemonSet, + Name: dsName, + Namespace: dsNamespace, + }, + }, + }, + nil, + 0, + }, + } + + for _, tc := range fixtures { + tc := tc + t.Run(tc.testName, func(t *testing.T) { + cs := fake.NewSimpleClientset(tc.objs...) + sharedInformers := informers.NewSharedInformerFactory(cs, 10*time.Minute) + k8sClient := k8s.NewClient(sharedInformers) + + m := &api.MockBcloudClient{} + apiClient := api.NewClient("", "", m) + + eh := NewEvent(k8sClient, apiClient) + if len(m.Events()) != 0 { + t.Errorf("Expected no events sent, got %d", len(m.Events())) + } + eh.Start(sharedInformers) + err := k8sClient.Sync(nil, time.Second) + if err != nil { + t.Error(err) + } + + for _, e := range tc.events { + _, err = cs.CoreV1().Events(dsNamespace).Create(context.TODO(), e, metav1.CreateOptions{}) + if err != nil { + t.Errorf("Error injecting event: %v", err) + } + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + for { + if len(m.Events()) == tc.expEvents { + break + } + + select { + case <-time.After(10 * time.Millisecond): + case <-ctx.Done(): + t.Errorf("Expected %d event(s) sent to API, got %d", tc.expEvents, len(m.Events())) + return + } + } + }) + } +} diff --git a/agent/pkg/handler/workload.go b/agent/pkg/handler/workload.go new file mode 100644 index 0000000..9d99fa0 --- /dev/null +++ b/agent/pkg/handler/workload.go @@ -0,0 +1,276 @@ +package handler + +import ( + "time" + + "github.com/buoyantio/linkerd-buoyant/agent/pkg/api" + "github.com/buoyantio/linkerd-buoyant/agent/pkg/k8s" + pb "github.com/buoyantio/linkerd-buoyant/gen/bcloud" + log "github.com/sirupsen/logrus" + "google.golang.org/protobuf/encoding/prototext" + "google.golang.org/protobuf/types/known/timestamppb" + appsv1 "k8s.io/api/apps/v1" + "k8s.io/client-go/informers" + "k8s.io/client-go/tools/cache" +) + +const ( + workloadsRefreshInterval = 10 * time.Minute +) + +// Workload listens to the k8s API for DaemonSet, Deployment, and StatefulSet +// changes, and forwards them to the Buoyant Cloud API. +type Workload struct { + log *log.Entry + api *api.Client + k8s *k8s.Client + stopCh chan struct{} +} + +// NewWorkload instantiates a new k8s workload handler. +func NewWorkload(k8sClient *k8s.Client, apiClient *api.Client) *Workload { + log := log.WithField("handler", "workload") + log.Debug("initializing") + + handler := &Workload{ + log: log, + api: apiClient, + k8s: k8sClient, + stopCh: make(chan struct{}), + } + + return handler +} + +// +// Workload +// + +// Start begins a polling loop, periodically resyncing all k8s objects with the +// Buoyant Cloud API. This syncing operation runs independently from the k8s +// handlers, but messages are syncronized via the WorkloadStream. +func (h *Workload) Start(sharedInformers informers.SharedInformerFactory) { + sharedInformers.Apps().V1().Deployments().Informer().AddEventHandler( + cache.ResourceEventHandlerFuncs{ + AddFunc: h.handleDeployAdd, + UpdateFunc: h.handleDeployUpdate, + DeleteFunc: h.handleDeployDelete, + }, + ) + sharedInformers.Apps().V1().DaemonSets().Informer().AddEventHandler( + cache.ResourceEventHandlerFuncs{ + AddFunc: h.handleDSAdd, + UpdateFunc: h.handleDSUpdate, + DeleteFunc: h.handleDSDelete, + }, + ) + sharedInformers.Apps().V1().StatefulSets().Informer().AddEventHandler( + cache.ResourceEventHandlerFuncs{ + AddFunc: h.handleSTSAdd, + UpdateFunc: h.handleSTSUpdate, + DeleteFunc: h.handleSTSDelete, + }, + ) + + ticker := time.NewTicker(workloadsRefreshInterval) + for { + select { + case <-ticker.C: + h.handleWorkloadList() + case <-h.stopCh: + return + } + } +} + +// Stop terminates the WorkloadStream resync loop. +func (h *Workload) Stop() { + h.log.Info("shutting down") + close(h.stopCh) +} + +// +// Deployments +// + +func (h *Workload) handleDeployAdd(obj interface{}) { + deploy := obj.(*appsv1.Deployment) + h.log.Debugf("adding Deployment %s/%s", deploy.Namespace, deploy.Name) + h.handleAdd(h.k8s.DeployToWorkload(deploy)) +} + +func (h *Workload) handleDeployUpdate(oldObj, newObj interface{}) { + oldDeploy := oldObj.(*appsv1.Deployment) + newDeploy := newObj.(*appsv1.Deployment) + h.log.Debugf("updating Deployment %s/%s", newDeploy.Namespace, newDeploy.Name) + h.handleUpdate(h.k8s.DeployToWorkload(oldDeploy), h.k8s.DeployToWorkload(newDeploy)) +} + +func (h *Workload) handleDeployDelete(obj interface{}) { + deploy, ok := obj.(*appsv1.Deployment) + if !ok { + tombstone, ok := obj.(cache.DeletedFinalStateUnknown) + if !ok { + h.log.Errorf("couldn't get object from tombstone %+v", obj) + return + } + deploy, ok = tombstone.Obj.(*appsv1.Deployment) + if !ok { + h.log.Errorf("tombstone contained object that is not a Deployment %+v", obj) + return + } + } + + h.log.Debugf("deleting Deployment %s/%s", deploy.Namespace, deploy.Name) + + h.handleDelete(h.k8s.DeployToWorkload(deploy)) +} + +// +// DaemonSets +// + +func (h *Workload) handleDSAdd(obj interface{}) { + ds := obj.(*appsv1.DaemonSet) + h.log.Debugf("adding DaemonSet %s/%s", ds.Namespace, ds.Name) + h.handleAdd(h.k8s.DSToWorkload(ds)) +} + +func (h *Workload) handleDSUpdate(oldObj, newObj interface{}) { + oldDS := oldObj.(*appsv1.DaemonSet) + newDS := newObj.(*appsv1.DaemonSet) + h.log.Debugf("updating DaemonSet %s/%s", newDS.Namespace, newDS.Name) + h.handleUpdate(h.k8s.DSToWorkload(oldDS), h.k8s.DSToWorkload(newDS)) +} + +func (h *Workload) handleDSDelete(obj interface{}) { + ds, ok := obj.(*appsv1.DaemonSet) + if !ok { + tombstone, ok := obj.(cache.DeletedFinalStateUnknown) + if !ok { + h.log.Errorf("couldn't get object from tombstone %+v", obj) + return + } + ds, ok = tombstone.Obj.(*appsv1.DaemonSet) + if !ok { + h.log.Errorf("tombstone contained object that is not a daemonset %+v", obj) + return + } + } + + h.log.Debugf("deleting DaemonSet %s/%s", ds.Namespace, ds.Name) + + h.handleDelete(h.k8s.DSToWorkload(ds)) +} + +// +// StatefulSets +// + +func (h *Workload) handleSTSAdd(obj interface{}) { + ds := obj.(*appsv1.StatefulSet) + h.log.Debugf("adding StatefulSet %s/%s", ds.Namespace, ds.Name) + h.handleAdd(h.k8s.STSToWorkload(ds)) +} + +func (h *Workload) handleSTSUpdate(oldObj, newObj interface{}) { + oldSTS := oldObj.(*appsv1.StatefulSet) + newSTS := newObj.(*appsv1.StatefulSet) + h.log.Debugf("updating StatefulSet %s/%s", newSTS.Namespace, newSTS.Name) + h.handleUpdate(h.k8s.STSToWorkload(oldSTS), h.k8s.STSToWorkload(newSTS)) +} + +func (h *Workload) handleSTSDelete(obj interface{}) { + sts, ok := obj.(*appsv1.StatefulSet) + if !ok { + tombstone, ok := obj.(cache.DeletedFinalStateUnknown) + if !ok { + h.log.Errorf("couldn't get object from tombstone %+v", obj) + return + } + sts, ok = tombstone.Obj.(*appsv1.StatefulSet) + if !ok { + h.log.Errorf("tombstone contained object that is not a StatefulSet %+v", obj) + return + } + } + + h.log.Debugf("deleting StatefulSet %s/%s", sts.Namespace, sts.Name) + + h.handleDelete(h.k8s.STSToWorkload(sts)) +} + +// +// Generic workload handlers +// + +func (h *Workload) handleAdd(workload *pb.Workload) { + m := &pb.WorkloadMessage{ + Message: &pb.WorkloadMessage_Added{ + Added: &pb.AddWorkload{Workload: workload}, + }, + } + h.log.Tracef("handleAdd: %s", prototext.Format(m)) + + err := h.api.WorkloadStream(m) + if err != nil { + h.log.Errorf("error sending add message: %s", err) + } +} + +func (h *Workload) handleUpdate(oldWorkload *pb.Workload, newWorkload *pb.Workload) { + now := time.Now() + m := &pb.WorkloadMessage{ + Message: &pb.WorkloadMessage_Updated{ + Updated: &pb.UpdateWorkload{ + OldWorkload: oldWorkload, + NewWorkload: newWorkload, + Timestamp: ×tamppb.Timestamp{ + Seconds: now.Unix(), + Nanos: int32(now.Nanosecond()), + }, + }, + }, + } + h.log.Tracef("handleUpdate: %s", prototext.Format(m)) + + err := h.api.WorkloadStream(m) + if err != nil { + h.log.Errorf("error sending update message: %s", err) + } +} + +func (h *Workload) handleDelete(workload *pb.Workload) { + m := &pb.WorkloadMessage{ + Message: &pb.WorkloadMessage_Deleted{ + Deleted: &pb.DeleteWorkload{Workload: workload}, + }, + } + + h.log.Tracef("handleDelete: %s", prototext.Format(m)) + + err := h.api.WorkloadStream(m) + if err != nil { + h.log.Errorf("error sending delete message: %s", err) + } +} + +func (h *Workload) handleWorkloadList() { + workloads, err := h.k8s.ListWorkloads() + if err != nil { + h.log.Errorf("error listing all workloads: %s", err) + return + } + + m := &pb.WorkloadMessage{ + Message: &pb.WorkloadMessage_List{ + List: &pb.ListWorkloads{Workloads: workloads}, + }, + } + h.log.Tracef("handleWorkloadList: %s", prototext.Format(m)) + + err = h.api.WorkloadStream(m) + if err != nil { + h.log.Errorf("error sending list message: %s", err) + } +} diff --git a/agent/pkg/handler/workload_test.go b/agent/pkg/handler/workload_test.go new file mode 100644 index 0000000..86f7cda --- /dev/null +++ b/agent/pkg/handler/workload_test.go @@ -0,0 +1,317 @@ +package handler + +import ( + "context" + "testing" + "time" + + "github.com/buoyantio/linkerd-buoyant/agent/pkg/api" + "github.com/buoyantio/linkerd-buoyant/agent/pkg/k8s" + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes/fake" +) + +func TestWorkloadStream(t *testing.T) { + workloadName := "fake-workload" + workloadNS := "fake-ns" + + ds1 := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: workloadName + "-1", + Namespace: workloadNS + "-1", + }, + Spec: appsv1.DaemonSetSpec{ + Selector: &metav1.LabelSelector{}, + }, + } + ds2 := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: workloadName + "-2", + Namespace: workloadNS + "-2", + }, + Spec: appsv1.DaemonSetSpec{ + Selector: &metav1.LabelSelector{}, + }, + } + deploy1 := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: workloadName + "-1", + Namespace: workloadNS + "-1", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{}, + }, + } + deploy2 := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: workloadName + "-2", + Namespace: workloadNS + "-2", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{}, + }, + } + sts1 := &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: workloadName + "-1", + Namespace: workloadNS + "-1", + }, + Spec: appsv1.StatefulSetSpec{ + Selector: &metav1.LabelSelector{}, + }, + } + sts2 := &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: workloadName + "-2", + Namespace: workloadNS + "-2", + }, + Spec: appsv1.StatefulSetSpec{ + Selector: &metav1.LabelSelector{}, + }, + } + + fixtures := []*struct { + testName string + existingWorkloads map[string][]runtime.Object + createWorkloads map[string][]runtime.Object + updateWorkloads map[string][]runtime.Object + deleteWorkloads map[string][]runtime.Object + expMessages int + }{ + { + "no workloads", + nil, + nil, + nil, + nil, + 0, + }, + { + "three existing workloads", + map[string][]runtime.Object{ + k8s.DaemonSet: {ds1}, + k8s.Deployment: {deploy1}, + k8s.StatefulSet: {sts1}, + }, + nil, + nil, + nil, + 4, + }, + { + "three create workloads", + nil, + map[string][]runtime.Object{ + k8s.DaemonSet: {ds1}, + k8s.Deployment: {deploy1}, + k8s.StatefulSet: {sts1}, + }, + nil, + nil, + 4, + }, + { + "three existing and three create workloads", + map[string][]runtime.Object{ + k8s.DaemonSet: {ds1}, + k8s.Deployment: {deploy1}, + k8s.StatefulSet: {sts1}, + }, + map[string][]runtime.Object{ + k8s.DaemonSet: {ds2}, + k8s.Deployment: {deploy2}, + k8s.StatefulSet: {sts2}, + }, + nil, + nil, + 7, + }, + { + "three existing and three update workloads", + map[string][]runtime.Object{ + k8s.DaemonSet: {ds1}, + k8s.Deployment: {deploy1}, + k8s.StatefulSet: {sts1}, + }, + nil, + map[string][]runtime.Object{ + k8s.DaemonSet: {ds1}, + k8s.Deployment: {deploy1}, + k8s.StatefulSet: {sts1}, + }, + nil, + 7, + }, + { + "three existing and three delete workloads", + map[string][]runtime.Object{ + k8s.DaemonSet: {ds1}, + k8s.Deployment: {deploy1}, + k8s.StatefulSet: {sts1}, + }, + nil, + nil, + map[string][]runtime.Object{ + k8s.DaemonSet: {ds1}, + k8s.Deployment: {deploy1}, + k8s.StatefulSet: {sts1}, + }, + 7, + }, + } + + for _, tc := range fixtures { + tc := tc + t.Run(tc.testName, func(t *testing.T) { + objs := []runtime.Object{} + for _, wrks := range tc.existingWorkloads { + objs = append(objs, wrks...) + } + cs := fake.NewSimpleClientset(objs...) + sharedInformers := informers.NewSharedInformerFactory(cs, 10*time.Minute) + k8sClient := k8s.NewClient(sharedInformers) + + m := &api.MockBcloudClient{} + apiClient := api.NewClient("", "", m) + + wh := NewWorkload(k8sClient, apiClient) + if len(m.Messages()) != 0 { + t.Errorf("Expected no messages sent, got %d", len(m.Messages())) + } + go wh.Start(sharedInformers) + err := k8sClient.Sync(nil, time.Second) + if err != nil { + t.Error(err) + } + + for k, objs := range tc.createWorkloads { + for _, o := range objs { + switch k { + case k8s.DaemonSet: + ds, ok := o.(*appsv1.DaemonSet) + if !ok { + t.Errorf("failed type assertion to appsv1.DaemonSet: %+v", o) + } + + _, err = cs.AppsV1().DaemonSets(ds.Namespace).Create(context.TODO(), ds, metav1.CreateOptions{}) + if err != nil { + t.Errorf("Error injecting appsv1.DaemonSet: %v", err) + } + case k8s.Deployment: + deploy, ok := o.(*appsv1.Deployment) + if !ok { + t.Errorf("failed type assertion to appsv1.Deployment: %+v", o) + } + + _, err = cs.AppsV1().Deployments(deploy.Namespace).Create(context.TODO(), deploy, metav1.CreateOptions{}) + if err != nil { + t.Errorf("Error injecting appsv1.Deployment: %v", err) + } + case k8s.StatefulSet: + sts, ok := o.(*appsv1.StatefulSet) + if !ok { + t.Errorf("failed type assertion to appsv1.StatefulSet: %+v", o) + } + + _, err = cs.AppsV1().StatefulSets(sts.Namespace).Create(context.TODO(), sts, metav1.CreateOptions{}) + if err != nil { + t.Errorf("Error injecting appsv1.StatefulSet: %v", err) + } + } + } + } + + for k, objs := range tc.updateWorkloads { + for _, o := range objs { + switch k { + case k8s.DaemonSet: + ds, ok := o.(*appsv1.DaemonSet) + if !ok { + t.Errorf("failed type assertion to appsv1.DaemonSet: %+v", o) + } + + _, err = cs.AppsV1().DaemonSets(ds.Namespace).Update(context.TODO(), ds, metav1.UpdateOptions{}) + if err != nil { + t.Errorf("Error injecting appsv1.DaemonSet: %v", err) + } + case k8s.Deployment: + deploy, ok := o.(*appsv1.Deployment) + if !ok { + t.Errorf("failed type assertion to appsv1.Deployment: %+v", o) + } + + _, err = cs.AppsV1().Deployments(deploy.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{}) + if err != nil { + t.Errorf("Error injecting appsv1.Deployment: %v", err) + } + case k8s.StatefulSet: + sts, ok := o.(*appsv1.StatefulSet) + if !ok { + t.Errorf("failed type assertion to appsv1.StatefulSet: %+v", o) + } + + _, err = cs.AppsV1().StatefulSets(sts.Namespace).Update(context.TODO(), sts, metav1.UpdateOptions{}) + if err != nil { + t.Errorf("Error injecting appsv1.StatefulSet: %v", err) + } + } + } + } + + for k, objs := range tc.deleteWorkloads { + for _, o := range objs { + switch k { + case k8s.DaemonSet: + ds, ok := o.(*appsv1.DaemonSet) + if !ok { + t.Errorf("failed type assertion to appsv1.DaemonSet: %+v", o) + } + + err = cs.AppsV1().DaemonSets(ds.Namespace).Delete(context.TODO(), ds.GetName(), metav1.DeleteOptions{}) + if err != nil { + t.Errorf("Error injecting appsv1.DaemonSet: %v", err) + } + case k8s.Deployment: + deploy, ok := o.(*appsv1.Deployment) + if !ok { + t.Errorf("failed type assertion to appsv1.Deployment: %+v", o) + } + + err = cs.AppsV1().Deployments(deploy.Namespace).Delete(context.TODO(), deploy.GetName(), metav1.DeleteOptions{}) + if err != nil { + t.Errorf("Error injecting appsv1.Deployment: %v", err) + } + case k8s.StatefulSet: + sts, ok := o.(*appsv1.StatefulSet) + if !ok { + t.Errorf("failed type assertion to appsv1.StatefulSet: %+v", o) + } + + err = cs.AppsV1().StatefulSets(sts.Namespace).Delete(context.TODO(), sts.GetName(), metav1.DeleteOptions{}) + if err != nil { + t.Errorf("Error injecting appsv1.StatefulSet: %v", err) + } + } + } + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + for { + if len(m.Messages()) == tc.expMessages { + break + } + + select { + case <-time.After(10 * time.Millisecond): + case <-ctx.Done(): + t.Errorf("Expected %d messages(s) sent to API, got %d", tc.expMessages, len(m.Messages())) + return + } + } + }) + } +} diff --git a/agent/pkg/k8s/event.go b/agent/pkg/k8s/event.go new file mode 100644 index 0000000..b448c8d --- /dev/null +++ b/agent/pkg/k8s/event.go @@ -0,0 +1,127 @@ +package k8s + +import ( + "fmt" + + pb "github.com/buoyantio/linkerd-buoyant/gen/bcloud" + v1 "k8s.io/api/core/v1" +) + +// EventToPB converts a Kubernetes event to a bcloud protobuf event. If the +// owner of the event is not a DeamonSet, Deployment, or StatefulSet, return a +// nil event without error. +func (c *Client) EventToPB(event *v1.Event) (*pb.Event, error) { + involvedObj := event.InvolvedObject + name := involvedObj.Name + kind := involvedObj.Kind + + switch involvedObj.Kind { + case ReplicaSet: + var err error + name, err = c.rsToDeploy(involvedObj.Name, involvedObj.Namespace) + if err != nil { + c.log.Debugf("Failed to get owner for ReplicaSet event [%s/%s]: %s", involvedObj.Namespace, involvedObj.Name, err) + return nil, err + } + kind = Deployment + case Pod: + var err error + name, kind, err = c.podToWorkload(involvedObj.Name, involvedObj.Namespace) + if err != nil { + c.log.Debugf("Failed to get owner for Pod event [%s/%s]: %s", involvedObj.Namespace, involvedObj.Name, err) + return nil, err + } + } + + if !isValidWorkloadKind(kind) { + c.log.Tracef("invalid workload kind: %s", kind) + return nil, nil + } + + workload, err := c.createWorkload(name, involvedObj.Namespace, kind) + if err != nil { + c.log.Errorf("Failed to create workload for [%s/%s/%s]: %s", kind, involvedObj.Namespace, name, err) + return nil, err + } + + return &pb.Event{ + Event: c.serialize(event, v1.SchemeGroupVersion), + Owner: workload, + }, nil +} + +func (c *Client) rsToDeploy(replicaSetName, namespace string) (string, error) { + deployName := "" + rs, err := c.rsLister.ReplicaSets(namespace).Get(replicaSetName) + if err != nil { + return deployName, err + } + rsOwners := rs.GetOwnerReferences() + if len(rsOwners) > 0 { + deployName = rsOwners[0].Name + } + return deployName, nil +} + +func (c *Client) podToWorkload(podName, namespace string) (string, string, error) { + p, err := c.podLister.Pods(namespace).Get(podName) + if err != nil { + return "", "", err + } + + var workloadName, workloadKind string + + podOwners := p.GetOwnerReferences() + if len(podOwners) > 0 { + ownerRs := podOwners[0] + if ownerRs.Kind == ReplicaSet { + workloadKind = Deployment + workloadName, err = c.rsToDeploy(ownerRs.Name, namespace) + if err != nil { + return "", "", err + } + } else { + workloadKind = ownerRs.Kind + workloadName = ownerRs.Name + } + } + return workloadName, workloadKind, nil +} + +func (c *Client) createWorkload(name, namespace, kind string) (*pb.Workload, error) { + if !isValidWorkloadKind(kind) { + return nil, fmt.Errorf("can't handle events for unsupported resource kind %s", kind) + } + + var workload *pb.Workload + switch kind { + case DaemonSet: + ds, err := c.dsLister.DaemonSets(namespace).Get(name) + if err != nil { + return nil, err + } + workload = c.DSToWorkload(ds) + + case Deployment: + deploy, err := c.deployLister.Deployments(namespace).Get(name) + if err != nil { + return nil, err + } + workload = c.DeployToWorkload(deploy) + + case StatefulSet: + sts, err := c.stsLister.StatefulSets(namespace).Get(name) + if err != nil { + return nil, err + } + workload = c.STSToWorkload(sts) + } + + return workload, nil +} + +// isValidWorkloadKind returns true if the given kind is one of daemonSet, +// deployment, or statefulset. Otherwise, it returns false. +func isValidWorkloadKind(kind string) bool { + return kind == DaemonSet || kind == Deployment || kind == StatefulSet +} diff --git a/agent/pkg/k8s/event_test.go b/agent/pkg/k8s/event_test.go new file mode 100644 index 0000000..96ebf49 --- /dev/null +++ b/agent/pkg/k8s/event_test.go @@ -0,0 +1,111 @@ +package k8s + +import ( + "testing" + "time" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func TestEventToPB(t *testing.T) { + fixtures := []*struct { + testName string + event *corev1.Event + objs []runtime.Object + err error + }{ + { + "empty event", + &corev1.Event{}, + nil, + nil, + }, + { + "missing daemonset event", + &corev1.Event{ + InvolvedObject: corev1.ObjectReference{ + Kind: DaemonSet, + Name: "test-ds", + Namespace: "test-ns", + }, + }, + nil, + k8serrors.NewNotFound(schema.GroupResource{Group: "apps", Resource: "daemonset"}, "test-ds"), + }, + { + "daemonset event", + &corev1.Event{ + InvolvedObject: corev1.ObjectReference{ + Kind: DaemonSet, + Name: "test-ds", + Namespace: "test-ns", + }, + }, + []runtime.Object{ + &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-ds", + Namespace: "test-ns", + }, + Spec: appsv1.DaemonSetSpec{ + Selector: &metav1.LabelSelector{}, + }, + }, + }, + nil, + }, + { + "deployment event", + &corev1.Event{ + InvolvedObject: corev1.ObjectReference{ + Kind: Deployment, + Name: "test-deploy", + Namespace: "test-deploy-ns", + }, + }, + []runtime.Object{ + &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-deploy", + Namespace: "test-deploy-ns", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{}, + }, + }, + }, + nil, + }, + } + + for _, tc := range fixtures { + tc := tc + t.Run(tc.testName, func(t *testing.T) { + c := fakeClient(tc.objs...) + err := c.Sync(nil, time.Second) + if err != nil { + t.Error(err) + } + + _, err = c.EventToPB(tc.event) + errCmp(t, tc.err, err) + }) + } +} + +func errCmp(t *testing.T, expErr, err error) { + if expErr == nil && err == nil { + return + } + + if expErr == nil && err != nil || + expErr != nil && err == nil || + expErr.Error() != err.Error() { + t.Errorf("Unexpected error: [%s], Expected: [%s]", err, expErr) + } +} diff --git a/agent/pkg/k8s/helpers_test.go b/agent/pkg/k8s/helpers_test.go new file mode 100644 index 0000000..98538e4 --- /dev/null +++ b/agent/pkg/k8s/helpers_test.go @@ -0,0 +1,15 @@ +package k8s + +import ( + "time" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes/fake" +) + +func fakeClient(objects ...runtime.Object) *Client { + cs := fake.NewSimpleClientset(objects...) + sharedInformers := informers.NewSharedInformerFactory(cs, 10*time.Minute) + return NewClient(sharedInformers) +} diff --git a/agent/pkg/k8s/k8s.go b/agent/pkg/k8s/k8s.go new file mode 100644 index 0000000..c1e1a99 --- /dev/null +++ b/agent/pkg/k8s/k8s.go @@ -0,0 +1,147 @@ +package k8s + +import ( + "context" + "errors" + "time" + + log "github.com/sirupsen/logrus" + appsv1 "k8s.io/api/apps/v1" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer/protobuf" + "k8s.io/client-go/informers" + corev1informers "k8s.io/client-go/informers/core/v1" + "k8s.io/client-go/kubernetes/scheme" + appsv1listers "k8s.io/client-go/listers/apps/v1" + corev1listers "k8s.io/client-go/listers/core/v1" + "k8s.io/client-go/tools/cache" +) + +type Client struct { + encoders map[runtime.GroupVersioner]runtime.Encoder + + sharedInformers informers.SharedInformerFactory + + podLister corev1listers.PodLister + rsLister appsv1listers.ReplicaSetLister + dsLister appsv1listers.DaemonSetLister + deployLister appsv1listers.DeploymentLister + stsLister appsv1listers.StatefulSetLister + + podSynced cache.InformerSynced + rsSynced cache.InformerSynced + dsSynced cache.InformerSynced + deploySynced cache.InformerSynced + stsSynced cache.InformerSynced + + eventInformer corev1informers.EventInformer + eventSynced cache.InformerSynced + + log *log.Entry +} + +const ( + DaemonSet = "DaemonSet" + Deployment = "Deployment" + Namespace = "Namespace" + Pod = "Pod" + ReplicaSet = "ReplicaSet" + StatefulSet = "StatefulSet" +) + +var errSyncCache = errors.New("failed to sync caches") + +func NewClient(sharedInformers informers.SharedInformerFactory) *Client { + log := log.WithField("client", "k8s") + log.Debug("initializing") + + protoSerializer := protobuf.NewSerializer(scheme.Scheme, scheme.Scheme) + encoders := map[runtime.GroupVersioner]runtime.Encoder{ + v1.SchemeGroupVersion: scheme.Codecs.EncoderForVersion(protoSerializer, v1.SchemeGroupVersion), + appsv1.SchemeGroupVersion: scheme.Codecs.EncoderForVersion(protoSerializer, appsv1.SchemeGroupVersion), + } + + podInformer := sharedInformers.Core().V1().Pods() + podInformerSynced := podInformer.Informer().HasSynced + + rsInformer := sharedInformers.Apps().V1().ReplicaSets() + rsInformerSynced := rsInformer.Informer().HasSynced + + dsInformer := sharedInformers.Apps().V1().DaemonSets() + dsInformerSynced := dsInformer.Informer().HasSynced + + deployInformer := sharedInformers.Apps().V1().Deployments() + deployInformerSynced := deployInformer.Informer().HasSynced + + stsInformer := sharedInformers.Apps().V1().StatefulSets() + stsInformerSynced := stsInformer.Informer().HasSynced + + eventInformer := sharedInformers.Core().V1().Events() + eventInformerSynced := eventInformer.Informer().HasSynced + + return &Client{ + encoders: encoders, + + sharedInformers: sharedInformers, + + podLister: podInformer.Lister(), + rsLister: rsInformer.Lister(), + dsLister: dsInformer.Lister(), + deployLister: deployInformer.Lister(), + stsLister: stsInformer.Lister(), + + podSynced: podInformerSynced, + rsSynced: rsInformerSynced, + dsSynced: dsInformerSynced, + deploySynced: deployInformerSynced, + stsSynced: stsInformerSynced, + + eventInformer: eventInformer, + eventSynced: eventInformerSynced, + + log: log, + } +} + +func (c *Client) Sync(stopCh <-chan struct{}, timeout time.Duration) error { + c.sharedInformers.Start(stopCh) + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + c.log.Infof("waiting for caches to sync") + if !cache.WaitForCacheSync( + ctx.Done(), + c.rsSynced, + c.podSynced, + c.dsSynced, + c.deploySynced, + c.stsSynced, + c.eventSynced, + ) { + c.log.Error(errSyncCache) + return errSyncCache + } + c.log.Infof("caches synced") + + return nil +} + +// Serialize takes a k8s object and serializes it into a byte slice. +// For more info on k8s serialization: +// https://github.com/kubernetes/api#recommended-use +func (c *Client) serialize(obj runtime.Object, gv runtime.GroupVersioner) []byte { + encoder, ok := c.encoders[gv] + if !ok { + c.log.Errorf("Unsupported GroupVersioner: %v", gv) + return nil + } + + buf, err := runtime.Encode(encoder, obj.DeepCopyObject()) + if err != nil { + c.log.Errorf("Encode failed: %s", err) + return nil + } + return buf +} diff --git a/agent/pkg/k8s/k8s_test.go b/agent/pkg/k8s/k8s_test.go new file mode 100644 index 0000000..65394b2 --- /dev/null +++ b/agent/pkg/k8s/k8s_test.go @@ -0,0 +1,80 @@ +package k8s + +import ( + "testing" + "time" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +func TestNewClient(t *testing.T) { + fixtures := []*struct { + testName string + objects []runtime.Object + }{ + { + "no objects", + nil, + }, + { + "one pod", + []runtime.Object{ + &corev1.Pod{}, + }, + }, + } + + for _, tc := range fixtures { + tc := tc + t.Run(tc.testName, func(t *testing.T) { + c := fakeClient(tc.objects...) + c.Sync(nil, time.Second) + }) + } +} + +func TestSync(t *testing.T) { + openCh := make(chan struct{}) + bufferedCh := make(chan struct{}, 10) + closedCh := make(chan struct{}) + close(closedCh) + + fixtures := []*struct { + testName string + stopCh <-chan struct{} + err error + }{ + { + "nil channel", + nil, + nil, + }, + { + "open channel", + openCh, + nil, + }, + { + "buffered channel", + bufferedCh, + nil, + }, + { + "closed channel", + closedCh, + errSyncCache, + }, + } + + for _, tc := range fixtures { + tc := tc + t.Run(tc.testName, func(t *testing.T) { + c := fakeClient() + err := c.Sync(tc.stopCh, time.Second) + if err != tc.err { + t.Errorf("Expected %s, got %s", tc.err, err) + } + }) + } +} diff --git a/agent/pkg/k8s/workload.go b/agent/pkg/k8s/workload.go new file mode 100644 index 0000000..8bb14eb --- /dev/null +++ b/agent/pkg/k8s/workload.go @@ -0,0 +1,159 @@ +package k8s + +import ( + pb "github.com/buoyantio/linkerd-buoyant/gen/bcloud" + appsv1 "k8s.io/api/apps/v1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" +) + +// DSToWorkload serializes a k8s DaemonSet object and wraps it in a bcloud API +// proto message. +func (c *Client) DSToWorkload(ds *appsv1.DaemonSet) *pb.Workload { + return &pb.Workload{ + Workload: &pb.Workload_Daemonset{ + Daemonset: &pb.DaemonSet{ + DaemonSet: c.serialize(ds, appsv1.SchemeGroupVersion), + Pods: c.getPodsFor(ds), + }, + }, + } +} + +// DeployToWorkload serializes a k8s Deployment object and wraps it in a bcloud +// API proto message. +func (c *Client) DeployToWorkload(deploy *appsv1.Deployment) *pb.Workload { + return &pb.Workload{ + Workload: &pb.Workload_Deployment{ + Deployment: &pb.Deployment{ + Deployment: c.serialize(deploy, appsv1.SchemeGroupVersion), + ReplicaSets: c.deployToRS(deploy), + }, + }, + } +} + +// STSToWorkload serializes a k8s StatefulSet object and wraps it in a bcloud +// API proto message. +func (c *Client) STSToWorkload(sts *appsv1.StatefulSet) *pb.Workload { + return &pb.Workload{ + Workload: &pb.Workload_Statefulset{ + Statefulset: &pb.StatefulSet{ + StatefulSet: c.serialize(sts, appsv1.SchemeGroupVersion), + Pods: c.getPodsFor(sts), + }, + }, + } +} + +func (c *Client) ListWorkloads() ([]*pb.Workload, error) { + workloads := []*pb.Workload{} + + dsList, err := c.dsLister.List(labels.Everything()) + if err != nil { + c.log.Errorf("error listing all DeamonSets: %s", err) + return nil, err + } + for _, ds := range dsList { + workloads = append(workloads, c.DSToWorkload(ds)) + } + + deployList, err := c.deployLister.List(labels.Everything()) + if err != nil { + c.log.Errorf("error listing all deployments: %s", err) + return nil, err + } + for _, deploy := range deployList { + workloads = append(workloads, c.DeployToWorkload(deploy)) + } + + stsList, err := c.stsLister.List(labels.Everything()) + if err != nil { + c.log.Errorf("error listing all StatefulSets: %s", err) + return nil, err + } + for _, sts := range stsList { + workloads = append(workloads, c.STSToWorkload(sts)) + } + + return workloads, nil +} + +func (c *Client) deployToRS(deploy *appsv1.Deployment) []*pb.ReplicaSet { + rsSelector := labels.Set(deploy.Spec.Selector.MatchLabels).AsSelector() + replicaSets, err := c.rsLister.ReplicaSets(deploy.GetNamespace()).List(rsSelector) + if err != nil { + c.log.Errorf("failed to retrieve ReplicaSets for %s/%s", deploy.GetNamespace(), deploy.GetName()) + return nil + } + + pbReplicaSets := make([]*pb.ReplicaSet, len(replicaSets)) + for i, rs := range replicaSets { + pbReplicaSets[i] = &pb.ReplicaSet{ + ReplicaSet: c.serialize(rs, appsv1.SchemeGroupVersion), + Pods: c.getPodsFor(rs), + } + } + + return pbReplicaSets +} + +// based on github.com/linkerd/linkerd2/controller/k8s/api.go +func (c *Client) getPodsFor( + obj runtime.Object, +) []*pb.Pod { + var namespace string + var selector labels.Selector + var ownerUID types.UID + var err error + + switch typed := obj.(type) { + case *appsv1.DaemonSet: + namespace = typed.Namespace + selector = labels.Set(typed.Spec.Selector.MatchLabels).AsSelector() + ownerUID = typed.UID + + case *appsv1.ReplicaSet: + namespace = typed.Namespace + selector = labels.Set(typed.Spec.Selector.MatchLabels).AsSelector() + ownerUID = typed.UID + + case *appsv1.StatefulSet: + namespace = typed.Namespace + selector = labels.Set(typed.Spec.Selector.MatchLabels).AsSelector() + ownerUID = typed.UID + + default: + c.log.Errorf("unrecognized runtime object: %v", obj) + return nil + } + + pods, err := c.podLister.Pods(namespace).List(selector) + if err != nil { + c.log.Errorf("failed to get pods for %s/%v", namespace, selector) + return nil + } + + pbPods := []*pb.Pod{} + for _, pod := range pods { + if isOwner(ownerUID, pod.GetOwnerReferences()) { + pbPods = append(pbPods, &pb.Pod{ + Pod: c.serialize(pod, v1.SchemeGroupVersion), + }) + } + } + + return pbPods +} + +func isOwner(u types.UID, ownerRefs []metav1.OwnerReference) bool { + for _, or := range ownerRefs { + if u == or.UID { + return true + } + } + return false +} diff --git a/agent/pkg/k8s/workload_test.go b/agent/pkg/k8s/workload_test.go new file mode 100644 index 0000000..660923b --- /dev/null +++ b/agent/pkg/k8s/workload_test.go @@ -0,0 +1,243 @@ +package k8s + +import ( + "testing" + "time" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/kubernetes/scheme" +) + +var ( + om = metav1.ObjectMeta{ + Name: "name", + Namespace: "namespace", + } + template = corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: "template-name", + Namespace: "template-namespace", + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + {Name: "container-name"}, + }, + }, + } +) + +func TestDSToWorkload(t *testing.T) { + fixtures := []*struct { + testName string + ds *appsv1.DaemonSet + }{ + { + "empty object", + &appsv1.DaemonSet{ + Spec: appsv1.DaemonSetSpec{ + Selector: &metav1.LabelSelector{}, + }, + }, + }, + { + "populated object", + &appsv1.DaemonSet{ + ObjectMeta: om, + Spec: appsv1.DaemonSetSpec{ + Template: template, + Selector: &metav1.LabelSelector{}, + }, + }, + }, + } + + for _, tc := range fixtures { + tc := tc + t.Run(tc.testName, func(t *testing.T) { + workload := fakeClient().DSToWorkload(tc.ds) + + obj, gvk, err := deserialize( + workload.GetDaemonset().DaemonSet, + ) + if err != nil { + t.Error(err) + } + ds, ok := obj.(*appsv1.DaemonSet) + if !ok { + t.Errorf("failed type assertion to appsv1.DaemonSet: %+v", obj) + } + + if !equality.Semantic.DeepEqual(ds.String(), tc.ds.String()) { + t.Errorf("Expected: [%+v], got: [%+v]", tc.ds.String(), ds.String()) + } + + expectedGVK := schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: DaemonSet} + if gvk.String() != expectedGVK.String() { + t.Errorf("Expected: [%s], got: [%s]", expectedGVK, gvk) + } + }) + } +} + +func TestDeployToWorkload(t *testing.T) { + fixtures := []*struct { + testName string + deploy *appsv1.Deployment + }{ + { + "empty object", + &appsv1.Deployment{ + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{}, + }, + }, + }, + { + "populated object", + &appsv1.Deployment{ + ObjectMeta: om, + Spec: appsv1.DeploymentSpec{ + Template: template, + Selector: &metav1.LabelSelector{}, + }, + }, + }, + } + + for _, tc := range fixtures { + tc := tc + t.Run(tc.testName, func(t *testing.T) { + workload := fakeClient().DeployToWorkload(tc.deploy) + + obj, gvk, err := deserialize( + workload.GetDeployment().Deployment, + ) + if err != nil { + t.Error(err) + } + deploy, ok := obj.(*appsv1.Deployment) + if !ok { + t.Errorf("failed type assertion to appsv1.Deployment: %+v", obj) + } + + if !equality.Semantic.DeepEqual(deploy.String(), tc.deploy.String()) { + t.Errorf("Expected: [%+v], got: [%+v]", tc.deploy.String(), deploy.String()) + } + + expectedGVK := schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: Deployment} + if gvk.String() != expectedGVK.String() { + t.Errorf("Expected: [%s], got: [%s]", expectedGVK, gvk) + } + }) + } +} + +func TestSTSToWorkload(t *testing.T) { + fixtures := []*struct { + testName string + sts *appsv1.StatefulSet + }{ + { + "empty object", + &appsv1.StatefulSet{ + Spec: appsv1.StatefulSetSpec{ + Selector: &metav1.LabelSelector{}, + }, + }, + }, + { + "populated object", + &appsv1.StatefulSet{ + ObjectMeta: om, + Spec: appsv1.StatefulSetSpec{ + Template: template, + Selector: &metav1.LabelSelector{}, + }, + }, + }, + } + + for _, tc := range fixtures { + tc := tc + t.Run(tc.testName, func(t *testing.T) { + workload := fakeClient().STSToWorkload(tc.sts) + + obj, gvk, err := deserialize( + workload.GetStatefulset().StatefulSet, + ) + if err != nil { + t.Error(err) + } + sts, ok := obj.(*appsv1.StatefulSet) + if !ok { + t.Errorf("failed type assertion to appsv1.StatefulSet: %+v", obj) + } + + if !equality.Semantic.DeepEqual(sts.String(), tc.sts.String()) { + t.Errorf("Expected: [%+v], got: [%+v]", tc.sts.String(), sts.String()) + } + + expectedGVK := schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: StatefulSet} + if gvk.String() != expectedGVK.String() { + t.Errorf("Expected: [%s], got: [%s]", expectedGVK, gvk) + } + }) + } +} + +func TestListWorkloads(t *testing.T) { + objects := []runtime.Object{ + &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ds-1", + }, + Spec: appsv1.DaemonSetSpec{ + Selector: &metav1.LabelSelector{}, + }, + }, + &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ds-2", + }, + Spec: appsv1.DaemonSetSpec{ + Selector: &metav1.LabelSelector{}, + }, + }, + &appsv1.Deployment{ + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{}, + }, + }, + &appsv1.StatefulSet{ + Spec: appsv1.StatefulSetSpec{ + Selector: &metav1.LabelSelector{}, + }, + }, + &corev1.Endpoints{}, + &corev1.Pod{}, + } + c := fakeClient(objects...) + c.Sync(nil, time.Second) + + workloads, err := c.ListWorkloads() + if err != nil { + t.Error(err) + } + + if len(workloads) != 4 { + t.Errorf("Expected [4] workloads, got [%d]: %+v", len(workloads), workloads) + } +} + +// +// test helpers +// + +func deserialize(b []byte) (runtime.Object, *schema.GroupVersionKind, error) { + return scheme.Codecs.UniversalDeserializer().Decode(b, nil, nil) +} diff --git a/bin/gen-proto b/bin/gen-proto new file mode 100755 index 0000000..9dec209 --- /dev/null +++ b/bin/gen-proto @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +set -e + +# keep in sync with bin/proto +protocversion=3.15.8 + +# keep in sync with go.mod +protoc_gen_go_version=v1.26.0 +protoc_gen_go_grpc_version=v1.1.0 + +# fetch tools and dependencies + +go get google.golang.org/protobuf/cmd/protoc-gen-go@$protoc_gen_go_version +go get google.golang.org/grpc/cmd/protoc-gen-go-grpc@$protoc_gen_go_grpc_version + +deps=$(mktemp -d -t deps.XXX) + +mkdir -p $deps/google/protobuf +curl -sL https://raw.githubusercontent.com/protocolbuffers/protobuf/v$protocversion/src/google/protobuf/timestamp.proto > $deps/google/protobuf/timestamp.proto + +# build protobuf + +basedir=$(cd "$(dirname "$0")"/..; pwd) +outdir="$basedir"/gen/bcloud +mkdir -p $outdir +"$basedir"/bin/protoc \ + --proto_path="$basedir"/proto \ + --proto_path=$deps \ + --go_out=$outdir \ + --go_opt=paths=source_relative \ + --go-grpc_out=$outdir \ + --go-grpc_opt=paths=source_relative \ + "$basedir"/proto/buoyant-cloud-api.proto diff --git a/bin/go-run b/bin/go-run new file mode 100755 index 0000000..1be34b1 --- /dev/null +++ b/bin/go-run @@ -0,0 +1,15 @@ +#!/bin/bash + +set -eu +cd "$(pwd -P)" + +bindir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +if [ "$#" -eq 0 ]; then + echo "Usage: bin/go-run path/to/main [args]" >&2 + exit 1 +fi + +go build -v -race -o .gorun "./$1" +shift +exec ./.gorun "$@" diff --git a/bin/protoc b/bin/protoc new file mode 100755 index 0000000..5b91b70 --- /dev/null +++ b/bin/protoc @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -eu + +if [ "$(uname -s)" = "Darwin" ]; then + os=osx +else + os=linux +fi +arch=$(uname -m) + +# keep in sync with bin/gen-proto +protocversion=3.15.8 +targetbin=target/bin +protocbin=$targetbin/protoc-${protocversion} +protocurl="https://github.com/protocolbuffers/protobuf/releases/download/v${protocversion}/protoc-${protocversion}-${os}-${arch}.zip" + +if [ ! -f "$protocbin" ]; then + tmp=$(mktemp -d -t protoc.XXX) + mkdir -p $targetbin + ( + cd "$tmp" + curl -L --silent --fail -o "./protoc.zip" "$protocurl" + unzip -q "./protoc.zip" bin/protoc + chmod +x bin/protoc + ) + mv "$tmp/bin/protoc" "$protocbin" + rm -rf "$tmp" +fi + +./$protocbin "$@" diff --git a/cmd/check.go b/cli/cmd/check.go similarity index 94% rename from cmd/check.go rename to cli/cmd/check.go index dad781a..37689f6 100644 --- a/cmd/check.go +++ b/cli/cmd/check.go @@ -6,8 +6,8 @@ import ( "os" "time" - pkghealthcheck "github.com/buoyantio/linkerd-buoyant/pkg/healthcheck" - "github.com/buoyantio/linkerd-buoyant/pkg/k8s" + pkghealthcheck "github.com/buoyantio/linkerd-buoyant/cli/pkg/healthcheck" + "github.com/buoyantio/linkerd-buoyant/cli/pkg/k8s" "github.com/linkerd/linkerd2/pkg/healthcheck" "github.com/spf13/cobra" ) diff --git a/cmd/check_test.go b/cli/cmd/check_test.go similarity index 88% rename from cmd/check_test.go rename to cli/cmd/check_test.go index 048541b..6c48689 100644 --- a/cmd/check_test.go +++ b/cli/cmd/check_test.go @@ -5,7 +5,7 @@ import ( "reflect" "testing" - "github.com/buoyantio/linkerd-buoyant/pkg/k8s" + "github.com/buoyantio/linkerd-buoyant/cli/pkg/k8s" ) func TestCheck(t *testing.T) { diff --git a/cmd/config.go b/cli/cmd/config.go similarity index 100% rename from cmd/config.go rename to cli/cmd/config.go diff --git a/cmd/config_test.go b/cli/cmd/config_test.go similarity index 100% rename from cmd/config_test.go rename to cli/cmd/config_test.go diff --git a/cmd/dashboard.go b/cli/cmd/dashboard.go similarity index 100% rename from cmd/dashboard.go rename to cli/cmd/dashboard.go diff --git a/cmd/dashboard_test.go b/cli/cmd/dashboard_test.go similarity index 100% rename from cmd/dashboard_test.go rename to cli/cmd/dashboard_test.go diff --git a/cmd/install.go b/cli/cmd/install.go similarity index 98% rename from cmd/install.go rename to cli/cmd/install.go index 176024d..dbb5536 100644 --- a/cmd/install.go +++ b/cli/cmd/install.go @@ -11,7 +11,7 @@ import ( "net/http" "time" - "github.com/buoyantio/linkerd-buoyant/pkg/k8s" + "github.com/buoyantio/linkerd-buoyant/cli/pkg/k8s" "github.com/pkg/browser" "github.com/spf13/cobra" ) diff --git a/cmd/install_test.go b/cli/cmd/install_test.go similarity index 98% rename from cmd/install_test.go rename to cli/cmd/install_test.go index 46197c2..025ba16 100644 --- a/cmd/install_test.go +++ b/cli/cmd/install_test.go @@ -10,8 +10,8 @@ import ( "strings" "testing" - "github.com/buoyantio/linkerd-buoyant/pkg/k8s" - "github.com/buoyantio/linkerd-buoyant/pkg/version" + "github.com/buoyantio/linkerd-buoyant/cli/pkg/k8s" + "github.com/buoyantio/linkerd-buoyant/cli/pkg/version" ) func TestInstallNewAgent(t *testing.T) { diff --git a/cmd/root.go b/cli/cmd/root.go similarity index 97% rename from cmd/root.go rename to cli/cmd/root.go index 89203e5..c4146b2 100644 --- a/cmd/root.go +++ b/cli/cmd/root.go @@ -4,7 +4,7 @@ import ( "os" "path/filepath" - "github.com/buoyantio/linkerd-buoyant/pkg/version" + "github.com/buoyantio/linkerd-buoyant/cli/pkg/version" "github.com/fatih/color" "github.com/pkg/browser" "github.com/spf13/cobra" diff --git a/cmd/uninstall.go b/cli/cmd/uninstall.go similarity index 97% rename from cmd/uninstall.go rename to cli/cmd/uninstall.go index 15e6cfd..159c484 100644 --- a/cmd/uninstall.go +++ b/cli/cmd/uninstall.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/buoyantio/linkerd-buoyant/pkg/k8s" + "github.com/buoyantio/linkerd-buoyant/cli/pkg/k8s" "github.com/spf13/cobra" ) diff --git a/cmd/uninstall_test.go b/cli/cmd/uninstall_test.go similarity index 93% rename from cmd/uninstall_test.go rename to cli/cmd/uninstall_test.go index 9057a24..5f86bee 100644 --- a/cmd/uninstall_test.go +++ b/cli/cmd/uninstall_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/buoyantio/linkerd-buoyant/pkg/k8s" + "github.com/buoyantio/linkerd-buoyant/cli/pkg/k8s" ) func TestUninstall(t *testing.T) { diff --git a/cmd/version.go b/cli/cmd/version.go similarity index 93% rename from cmd/version.go rename to cli/cmd/version.go index 1d91b60..c052992 100644 --- a/cmd/version.go +++ b/cli/cmd/version.go @@ -4,8 +4,8 @@ import ( "context" "fmt" - "github.com/buoyantio/linkerd-buoyant/pkg/k8s" - "github.com/buoyantio/linkerd-buoyant/pkg/version" + "github.com/buoyantio/linkerd-buoyant/cli/pkg/k8s" + "github.com/buoyantio/linkerd-buoyant/cli/pkg/version" "github.com/spf13/cobra" ) diff --git a/cmd/version_test.go b/cli/cmd/version_test.go similarity index 96% rename from cmd/version_test.go rename to cli/cmd/version_test.go index 6346994..978160e 100644 --- a/cmd/version_test.go +++ b/cli/cmd/version_test.go @@ -5,7 +5,7 @@ import ( "context" "testing" - "github.com/buoyantio/linkerd-buoyant/pkg/k8s" + "github.com/buoyantio/linkerd-buoyant/cli/pkg/k8s" ) func TestVersion(t *testing.T) { diff --git a/main.go b/cli/main.go similarity index 81% rename from main.go rename to cli/main.go index 0244b01..7c36394 100644 --- a/main.go +++ b/cli/main.go @@ -3,7 +3,7 @@ package main import ( "os" - "github.com/buoyantio/linkerd-buoyant/cmd" + "github.com/buoyantio/linkerd-buoyant/cli/cmd" // Load all the auth plugins for the cloud providers. _ "k8s.io/client-go/plugin/pkg/client/auth" diff --git a/pkg/healthcheck/healthcheck.go b/cli/pkg/healthcheck/healthcheck.go similarity index 98% rename from pkg/healthcheck/healthcheck.go rename to cli/pkg/healthcheck/healthcheck.go index 8c45dc4..21ce7d8 100644 --- a/pkg/healthcheck/healthcheck.go +++ b/cli/pkg/healthcheck/healthcheck.go @@ -5,8 +5,8 @@ import ( "fmt" "net/http" - "github.com/buoyantio/linkerd-buoyant/pkg/k8s" - "github.com/buoyantio/linkerd-buoyant/pkg/version" + "github.com/buoyantio/linkerd-buoyant/cli/pkg/k8s" + "github.com/buoyantio/linkerd-buoyant/cli/pkg/version" "github.com/linkerd/linkerd2/pkg/healthcheck" l5dk8s "github.com/linkerd/linkerd2/pkg/k8s" appsv1 "k8s.io/api/apps/v1" diff --git a/pkg/healthcheck/healthcheck_test.go b/cli/pkg/healthcheck/healthcheck_test.go similarity index 97% rename from pkg/healthcheck/healthcheck_test.go rename to cli/pkg/healthcheck/healthcheck_test.go index 637f095..6b09b6c 100644 --- a/pkg/healthcheck/healthcheck_test.go +++ b/cli/pkg/healthcheck/healthcheck_test.go @@ -7,8 +7,8 @@ import ( "net/http/httptest" "testing" - "github.com/buoyantio/linkerd-buoyant/pkg/k8s" - "github.com/buoyantio/linkerd-buoyant/pkg/version" + "github.com/buoyantio/linkerd-buoyant/cli/pkg/k8s" + "github.com/buoyantio/linkerd-buoyant/cli/pkg/version" "github.com/linkerd/linkerd2/pkg/healthcheck" l5dk8s "github.com/linkerd/linkerd2/pkg/k8s" appsv1 "k8s.io/api/apps/v1" diff --git a/pkg/k8s/agent.go b/cli/pkg/k8s/agent.go similarity index 100% rename from pkg/k8s/agent.go rename to cli/pkg/k8s/agent.go diff --git a/pkg/k8s/agent_test.go b/cli/pkg/k8s/agent_test.go similarity index 100% rename from pkg/k8s/agent_test.go rename to cli/pkg/k8s/agent_test.go diff --git a/pkg/k8s/client.go b/cli/pkg/k8s/client.go similarity index 100% rename from pkg/k8s/client.go rename to cli/pkg/k8s/client.go diff --git a/pkg/k8s/client_test.go b/cli/pkg/k8s/client_test.go similarity index 100% rename from pkg/k8s/client_test.go rename to cli/pkg/k8s/client_test.go diff --git a/pkg/k8s/mock_client.go b/cli/pkg/k8s/mock_client.go similarity index 100% rename from pkg/k8s/mock_client.go rename to cli/pkg/k8s/mock_client.go diff --git a/pkg/k8s/resource.go b/cli/pkg/k8s/resource.go similarity index 100% rename from pkg/k8s/resource.go rename to cli/pkg/k8s/resource.go diff --git a/pkg/k8s/resource_test.go b/cli/pkg/k8s/resource_test.go similarity index 100% rename from pkg/k8s/resource_test.go rename to cli/pkg/k8s/resource_test.go diff --git a/pkg/version/version.go b/cli/pkg/version/version.go similarity index 100% rename from pkg/version/version.go rename to cli/pkg/version/version.go diff --git a/pkg/version/version_test.go b/cli/pkg/version/version_test.go similarity index 100% rename from pkg/version/version_test.go rename to cli/pkg/version/version_test.go diff --git a/gen/bcloud/buoyant-cloud-api.pb.go b/gen/bcloud/buoyant-cloud-api.pb.go new file mode 100644 index 0000000..01bacda --- /dev/null +++ b/gen/bcloud/buoyant-cloud-api.pb.go @@ -0,0 +1,1250 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.15.8 +// source: buoyant-cloud-api.proto + +package bcloud + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Empty struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *Empty) Reset() { + *x = Empty{} + if protoimpl.UnsafeEnabled { + mi := &file_buoyant_cloud_api_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Empty) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Empty) ProtoMessage() {} + +func (x *Empty) ProtoReflect() protoreflect.Message { + mi := &file_buoyant_cloud_api_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Empty.ProtoReflect.Descriptor instead. +func (*Empty) Descriptor() ([]byte, []int) { + return file_buoyant_cloud_api_proto_rawDescGZIP(), []int{0} +} + +type Auth struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AgentId string `protobuf:"bytes,1,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"` + AgentKey string `protobuf:"bytes,2,opt,name=agent_key,json=agentKey,proto3" json:"agent_key,omitempty"` +} + +func (x *Auth) Reset() { + *x = Auth{} + if protoimpl.UnsafeEnabled { + mi := &file_buoyant_cloud_api_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Auth) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Auth) ProtoMessage() {} + +func (x *Auth) ProtoReflect() protoreflect.Message { + mi := &file_buoyant_cloud_api_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Auth.ProtoReflect.Descriptor instead. +func (*Auth) Descriptor() ([]byte, []int) { + return file_buoyant_cloud_api_proto_rawDescGZIP(), []int{1} +} + +func (x *Auth) GetAgentId() string { + if x != nil { + return x.AgentId + } + return "" +} + +func (x *Auth) GetAgentKey() string { + if x != nil { + return x.AgentKey + } + return "" +} + +type Workload struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Workload: + // *Workload_Daemonset + // *Workload_Deployment + // *Workload_Statefulset + Workload isWorkload_Workload `protobuf_oneof:"workload"` +} + +func (x *Workload) Reset() { + *x = Workload{} + if protoimpl.UnsafeEnabled { + mi := &file_buoyant_cloud_api_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Workload) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Workload) ProtoMessage() {} + +func (x *Workload) ProtoReflect() protoreflect.Message { + mi := &file_buoyant_cloud_api_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Workload.ProtoReflect.Descriptor instead. +func (*Workload) Descriptor() ([]byte, []int) { + return file_buoyant_cloud_api_proto_rawDescGZIP(), []int{2} +} + +func (m *Workload) GetWorkload() isWorkload_Workload { + if m != nil { + return m.Workload + } + return nil +} + +func (x *Workload) GetDaemonset() *DaemonSet { + if x, ok := x.GetWorkload().(*Workload_Daemonset); ok { + return x.Daemonset + } + return nil +} + +func (x *Workload) GetDeployment() *Deployment { + if x, ok := x.GetWorkload().(*Workload_Deployment); ok { + return x.Deployment + } + return nil +} + +func (x *Workload) GetStatefulset() *StatefulSet { + if x, ok := x.GetWorkload().(*Workload_Statefulset); ok { + return x.Statefulset + } + return nil +} + +type isWorkload_Workload interface { + isWorkload_Workload() +} + +type Workload_Daemonset struct { + Daemonset *DaemonSet `protobuf:"bytes,1,opt,name=daemonset,proto3,oneof"` +} + +type Workload_Deployment struct { + Deployment *Deployment `protobuf:"bytes,2,opt,name=deployment,proto3,oneof"` +} + +type Workload_Statefulset struct { + Statefulset *StatefulSet `protobuf:"bytes,3,opt,name=statefulset,proto3,oneof"` +} + +func (*Workload_Daemonset) isWorkload_Workload() {} + +func (*Workload_Deployment) isWorkload_Workload() {} + +func (*Workload_Statefulset) isWorkload_Workload() {} + +type DaemonSet struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DaemonSet []byte `protobuf:"bytes,1,opt,name=daemon_set,json=daemonSet,proto3" json:"daemon_set,omitempty"` + Pods []*Pod `protobuf:"bytes,2,rep,name=pods,proto3" json:"pods,omitempty"` +} + +func (x *DaemonSet) Reset() { + *x = DaemonSet{} + if protoimpl.UnsafeEnabled { + mi := &file_buoyant_cloud_api_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DaemonSet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DaemonSet) ProtoMessage() {} + +func (x *DaemonSet) ProtoReflect() protoreflect.Message { + mi := &file_buoyant_cloud_api_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DaemonSet.ProtoReflect.Descriptor instead. +func (*DaemonSet) Descriptor() ([]byte, []int) { + return file_buoyant_cloud_api_proto_rawDescGZIP(), []int{3} +} + +func (x *DaemonSet) GetDaemonSet() []byte { + if x != nil { + return x.DaemonSet + } + return nil +} + +func (x *DaemonSet) GetPods() []*Pod { + if x != nil { + return x.Pods + } + return nil +} + +type Deployment struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Deployment []byte `protobuf:"bytes,1,opt,name=deployment,proto3" json:"deployment,omitempty"` + ReplicaSets []*ReplicaSet `protobuf:"bytes,2,rep,name=replica_sets,json=replicaSets,proto3" json:"replica_sets,omitempty"` +} + +func (x *Deployment) Reset() { + *x = Deployment{} + if protoimpl.UnsafeEnabled { + mi := &file_buoyant_cloud_api_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Deployment) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Deployment) ProtoMessage() {} + +func (x *Deployment) ProtoReflect() protoreflect.Message { + mi := &file_buoyant_cloud_api_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Deployment.ProtoReflect.Descriptor instead. +func (*Deployment) Descriptor() ([]byte, []int) { + return file_buoyant_cloud_api_proto_rawDescGZIP(), []int{4} +} + +func (x *Deployment) GetDeployment() []byte { + if x != nil { + return x.Deployment + } + return nil +} + +func (x *Deployment) GetReplicaSets() []*ReplicaSet { + if x != nil { + return x.ReplicaSets + } + return nil +} + +type StatefulSet struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StatefulSet []byte `protobuf:"bytes,1,opt,name=stateful_set,json=statefulSet,proto3" json:"stateful_set,omitempty"` + Pods []*Pod `protobuf:"bytes,2,rep,name=pods,proto3" json:"pods,omitempty"` +} + +func (x *StatefulSet) Reset() { + *x = StatefulSet{} + if protoimpl.UnsafeEnabled { + mi := &file_buoyant_cloud_api_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StatefulSet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatefulSet) ProtoMessage() {} + +func (x *StatefulSet) ProtoReflect() protoreflect.Message { + mi := &file_buoyant_cloud_api_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StatefulSet.ProtoReflect.Descriptor instead. +func (*StatefulSet) Descriptor() ([]byte, []int) { + return file_buoyant_cloud_api_proto_rawDescGZIP(), []int{5} +} + +func (x *StatefulSet) GetStatefulSet() []byte { + if x != nil { + return x.StatefulSet + } + return nil +} + +func (x *StatefulSet) GetPods() []*Pod { + if x != nil { + return x.Pods + } + return nil +} + +type ReplicaSet struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ReplicaSet []byte `protobuf:"bytes,1,opt,name=replica_set,json=replicaSet,proto3" json:"replica_set,omitempty"` + Pods []*Pod `protobuf:"bytes,2,rep,name=pods,proto3" json:"pods,omitempty"` +} + +func (x *ReplicaSet) Reset() { + *x = ReplicaSet{} + if protoimpl.UnsafeEnabled { + mi := &file_buoyant_cloud_api_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReplicaSet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReplicaSet) ProtoMessage() {} + +func (x *ReplicaSet) ProtoReflect() protoreflect.Message { + mi := &file_buoyant_cloud_api_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReplicaSet.ProtoReflect.Descriptor instead. +func (*ReplicaSet) Descriptor() ([]byte, []int) { + return file_buoyant_cloud_api_proto_rawDescGZIP(), []int{6} +} + +func (x *ReplicaSet) GetReplicaSet() []byte { + if x != nil { + return x.ReplicaSet + } + return nil +} + +func (x *ReplicaSet) GetPods() []*Pod { + if x != nil { + return x.Pods + } + return nil +} + +type Pod struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pod []byte `protobuf:"bytes,1,opt,name=pod,proto3" json:"pod,omitempty"` +} + +func (x *Pod) Reset() { + *x = Pod{} + if protoimpl.UnsafeEnabled { + mi := &file_buoyant_cloud_api_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Pod) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Pod) ProtoMessage() {} + +func (x *Pod) ProtoReflect() protoreflect.Message { + mi := &file_buoyant_cloud_api_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Pod.ProtoReflect.Descriptor instead. +func (*Pod) Descriptor() ([]byte, []int) { + return file_buoyant_cloud_api_proto_rawDescGZIP(), []int{7} +} + +func (x *Pod) GetPod() []byte { + if x != nil { + return x.Pod + } + return nil +} + +type WorkloadMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Message: + // *WorkloadMessage_Auth + // *WorkloadMessage_Added + // *WorkloadMessage_Updated + // *WorkloadMessage_Deleted + // *WorkloadMessage_List + Message isWorkloadMessage_Message `protobuf_oneof:"message"` +} + +func (x *WorkloadMessage) Reset() { + *x = WorkloadMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_buoyant_cloud_api_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WorkloadMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WorkloadMessage) ProtoMessage() {} + +func (x *WorkloadMessage) ProtoReflect() protoreflect.Message { + mi := &file_buoyant_cloud_api_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WorkloadMessage.ProtoReflect.Descriptor instead. +func (*WorkloadMessage) Descriptor() ([]byte, []int) { + return file_buoyant_cloud_api_proto_rawDescGZIP(), []int{8} +} + +func (m *WorkloadMessage) GetMessage() isWorkloadMessage_Message { + if m != nil { + return m.Message + } + return nil +} + +func (x *WorkloadMessage) GetAuth() *Auth { + if x, ok := x.GetMessage().(*WorkloadMessage_Auth); ok { + return x.Auth + } + return nil +} + +func (x *WorkloadMessage) GetAdded() *AddWorkload { + if x, ok := x.GetMessage().(*WorkloadMessage_Added); ok { + return x.Added + } + return nil +} + +func (x *WorkloadMessage) GetUpdated() *UpdateWorkload { + if x, ok := x.GetMessage().(*WorkloadMessage_Updated); ok { + return x.Updated + } + return nil +} + +func (x *WorkloadMessage) GetDeleted() *DeleteWorkload { + if x, ok := x.GetMessage().(*WorkloadMessage_Deleted); ok { + return x.Deleted + } + return nil +} + +func (x *WorkloadMessage) GetList() *ListWorkloads { + if x, ok := x.GetMessage().(*WorkloadMessage_List); ok { + return x.List + } + return nil +} + +type isWorkloadMessage_Message interface { + isWorkloadMessage_Message() +} + +type WorkloadMessage_Auth struct { + Auth *Auth `protobuf:"bytes,1,opt,name=auth,proto3,oneof"` +} + +type WorkloadMessage_Added struct { + Added *AddWorkload `protobuf:"bytes,2,opt,name=added,proto3,oneof"` +} + +type WorkloadMessage_Updated struct { + Updated *UpdateWorkload `protobuf:"bytes,3,opt,name=updated,proto3,oneof"` +} + +type WorkloadMessage_Deleted struct { + Deleted *DeleteWorkload `protobuf:"bytes,4,opt,name=deleted,proto3,oneof"` +} + +type WorkloadMessage_List struct { + List *ListWorkloads `protobuf:"bytes,5,opt,name=list,proto3,oneof"` +} + +func (*WorkloadMessage_Auth) isWorkloadMessage_Message() {} + +func (*WorkloadMessage_Added) isWorkloadMessage_Message() {} + +func (*WorkloadMessage_Updated) isWorkloadMessage_Message() {} + +func (*WorkloadMessage_Deleted) isWorkloadMessage_Message() {} + +func (*WorkloadMessage_List) isWorkloadMessage_Message() {} + +type AddWorkload struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Workload *Workload `protobuf:"bytes,1,opt,name=workload,proto3" json:"workload,omitempty"` +} + +func (x *AddWorkload) Reset() { + *x = AddWorkload{} + if protoimpl.UnsafeEnabled { + mi := &file_buoyant_cloud_api_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddWorkload) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddWorkload) ProtoMessage() {} + +func (x *AddWorkload) ProtoReflect() protoreflect.Message { + mi := &file_buoyant_cloud_api_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddWorkload.ProtoReflect.Descriptor instead. +func (*AddWorkload) Descriptor() ([]byte, []int) { + return file_buoyant_cloud_api_proto_rawDescGZIP(), []int{9} +} + +func (x *AddWorkload) GetWorkload() *Workload { + if x != nil { + return x.Workload + } + return nil +} + +type DeleteWorkload struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Workload *Workload `protobuf:"bytes,1,opt,name=workload,proto3" json:"workload,omitempty"` +} + +func (x *DeleteWorkload) Reset() { + *x = DeleteWorkload{} + if protoimpl.UnsafeEnabled { + mi := &file_buoyant_cloud_api_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteWorkload) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteWorkload) ProtoMessage() {} + +func (x *DeleteWorkload) ProtoReflect() protoreflect.Message { + mi := &file_buoyant_cloud_api_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteWorkload.ProtoReflect.Descriptor instead. +func (*DeleteWorkload) Descriptor() ([]byte, []int) { + return file_buoyant_cloud_api_proto_rawDescGZIP(), []int{10} +} + +func (x *DeleteWorkload) GetWorkload() *Workload { + if x != nil { + return x.Workload + } + return nil +} + +type UpdateWorkload struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OldWorkload *Workload `protobuf:"bytes,1,opt,name=old_workload,json=oldWorkload,proto3" json:"old_workload,omitempty"` + NewWorkload *Workload `protobuf:"bytes,2,opt,name=new_workload,json=newWorkload,proto3" json:"new_workload,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` +} + +func (x *UpdateWorkload) Reset() { + *x = UpdateWorkload{} + if protoimpl.UnsafeEnabled { + mi := &file_buoyant_cloud_api_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateWorkload) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateWorkload) ProtoMessage() {} + +func (x *UpdateWorkload) ProtoReflect() protoreflect.Message { + mi := &file_buoyant_cloud_api_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateWorkload.ProtoReflect.Descriptor instead. +func (*UpdateWorkload) Descriptor() ([]byte, []int) { + return file_buoyant_cloud_api_proto_rawDescGZIP(), []int{11} +} + +func (x *UpdateWorkload) GetOldWorkload() *Workload { + if x != nil { + return x.OldWorkload + } + return nil +} + +func (x *UpdateWorkload) GetNewWorkload() *Workload { + if x != nil { + return x.NewWorkload + } + return nil +} + +func (x *UpdateWorkload) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp + } + return nil +} + +type ListWorkloads struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Workloads []*Workload `protobuf:"bytes,1,rep,name=workloads,proto3" json:"workloads,omitempty"` +} + +func (x *ListWorkloads) Reset() { + *x = ListWorkloads{} + if protoimpl.UnsafeEnabled { + mi := &file_buoyant_cloud_api_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListWorkloads) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListWorkloads) ProtoMessage() {} + +func (x *ListWorkloads) ProtoReflect() protoreflect.Message { + mi := &file_buoyant_cloud_api_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListWorkloads.ProtoReflect.Descriptor instead. +func (*ListWorkloads) Descriptor() ([]byte, []int) { + return file_buoyant_cloud_api_proto_rawDescGZIP(), []int{12} +} + +func (x *ListWorkloads) GetWorkloads() []*Workload { + if x != nil { + return x.Workloads + } + return nil +} + +type Event struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Auth *Auth `protobuf:"bytes,1,opt,name=auth,proto3" json:"auth,omitempty"` + Event []byte `protobuf:"bytes,2,opt,name=event,proto3" json:"event,omitempty"` + Owner *Workload `protobuf:"bytes,3,opt,name=owner,proto3" json:"owner,omitempty"` +} + +func (x *Event) Reset() { + *x = Event{} + if protoimpl.UnsafeEnabled { + mi := &file_buoyant_cloud_api_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Event) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Event) ProtoMessage() {} + +func (x *Event) ProtoReflect() protoreflect.Message { + mi := &file_buoyant_cloud_api_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Event.ProtoReflect.Descriptor instead. +func (*Event) Descriptor() ([]byte, []int) { + return file_buoyant_cloud_api_proto_rawDescGZIP(), []int{13} +} + +func (x *Event) GetAuth() *Auth { + if x != nil { + return x.Auth + } + return nil +} + +func (x *Event) GetEvent() []byte { + if x != nil { + return x.Event + } + return nil +} + +func (x *Event) GetOwner() *Workload { + if x != nil { + return x.Owner + } + return nil +} + +var File_buoyant_cloud_api_proto protoreflect.FileDescriptor + +var file_buoyant_cloud_api_proto_rawDesc = []byte{ + 0x0a, 0x17, 0x62, 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2d, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, + 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x62, 0x75, 0x6f, 0x79, 0x61, + 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x22, 0x3e, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x4b, + 0x65, 0x79, 0x22, 0xcd, 0x01, 0x0a, 0x08, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x12, + 0x38, 0x0a, 0x09, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x62, 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, + 0x75, 0x64, 0x2e, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x48, 0x00, 0x52, 0x09, + 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x73, 0x65, 0x74, 0x12, 0x3b, 0x0a, 0x0a, 0x64, 0x65, 0x70, + 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, + 0x62, 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x44, 0x65, + 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x6c, + 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x3e, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x65, 0x66, + 0x75, 0x6c, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x62, 0x75, + 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x66, 0x75, 0x6c, 0x53, 0x65, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x66, 0x75, 0x6c, 0x73, 0x65, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, + 0x61, 0x64, 0x22, 0x52, 0x0a, 0x09, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x12, + 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x09, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x12, 0x26, + 0x0a, 0x04, 0x70, 0x6f, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, + 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x50, 0x6f, 0x64, + 0x52, 0x04, 0x70, 0x6f, 0x64, 0x73, 0x22, 0x6a, 0x0a, 0x0a, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x0c, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x5f, + 0x73, 0x65, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x62, 0x75, 0x6f, + 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x53, 0x65, 0x74, 0x52, 0x0b, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x53, 0x65, + 0x74, 0x73, 0x22, 0x58, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x66, 0x75, 0x6c, 0x53, 0x65, + 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x65, 0x66, 0x75, 0x6c, 0x5f, 0x73, 0x65, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x65, 0x66, 0x75, + 0x6c, 0x53, 0x65, 0x74, 0x12, 0x26, 0x0a, 0x04, 0x70, 0x6f, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, + 0x75, 0x64, 0x2e, 0x50, 0x6f, 0x64, 0x52, 0x04, 0x70, 0x6f, 0x64, 0x73, 0x22, 0x55, 0x0a, 0x0a, + 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x53, 0x65, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0a, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x53, 0x65, 0x74, 0x12, 0x26, 0x0a, 0x04, 0x70, + 0x6f, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, 0x75, 0x6f, 0x79, + 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x50, 0x6f, 0x64, 0x52, 0x04, 0x70, + 0x6f, 0x64, 0x73, 0x22, 0x17, 0x0a, 0x03, 0x50, 0x6f, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x6f, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x70, 0x6f, 0x64, 0x22, 0xa5, 0x02, 0x0a, + 0x0f, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x29, 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, + 0x2e, 0x62, 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x41, + 0x75, 0x74, 0x68, 0x48, 0x00, 0x52, 0x04, 0x61, 0x75, 0x74, 0x68, 0x12, 0x32, 0x0a, 0x05, 0x61, + 0x64, 0x64, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x62, 0x75, 0x6f, + 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x41, 0x64, 0x64, 0x57, 0x6f, + 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x00, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, + 0x39, 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x62, 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x48, + 0x00, 0x52, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x39, 0x0a, 0x07, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x62, 0x75, + 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x00, 0x52, 0x07, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x32, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, + 0x73, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x42, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x6c, + 0x6f, 0x61, 0x64, 0x12, 0x33, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x62, 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, + 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x08, + 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x45, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x33, 0x0a, 0x08, 0x77, 0x6f, + 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x62, + 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x57, 0x6f, 0x72, + 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x22, + 0xc2, 0x01, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, + 0x61, 0x64, 0x12, 0x3a, 0x0a, 0x0c, 0x6f, 0x6c, 0x64, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, + 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x62, 0x75, 0x6f, 0x79, 0x61, + 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, + 0x64, 0x52, 0x0b, 0x6f, 0x6c, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3a, + 0x0a, 0x0c, 0x6e, 0x65, 0x77, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x62, 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, + 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x0b, 0x6e, + 0x65, 0x77, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x22, 0x46, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, + 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x12, 0x35, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, + 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x62, 0x75, 0x6f, 0x79, 0x61, + 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, + 0x64, 0x52, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x22, 0x75, 0x0a, 0x05, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x62, 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x04, 0x61, 0x75, 0x74, 0x68, 0x12, 0x14, + 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x62, 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x05, 0x6f, 0x77, + 0x6e, 0x65, 0x72, 0x32, 0x8b, 0x01, 0x0a, 0x03, 0x41, 0x70, 0x69, 0x12, 0x4a, 0x0a, 0x0e, 0x57, + 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1e, 0x2e, + 0x62, 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x57, 0x6f, + 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x14, 0x2e, + 0x62, 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x22, 0x00, 0x28, 0x01, 0x12, 0x38, 0x0a, 0x08, 0x41, 0x64, 0x64, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x12, 0x14, 0x2e, 0x62, 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0x14, 0x2e, 0x62, 0x75, 0x6f, 0x79, + 0x61, 0x6e, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, + 0x00, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x62, 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x69, 0x6f, 0x2f, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x72, + 0x64, 0x2d, 0x62, 0x75, 0x6f, 0x79, 0x61, 0x6e, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x62, 0x63, + 0x6c, 0x6f, 0x75, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_buoyant_cloud_api_proto_rawDescOnce sync.Once + file_buoyant_cloud_api_proto_rawDescData = file_buoyant_cloud_api_proto_rawDesc +) + +func file_buoyant_cloud_api_proto_rawDescGZIP() []byte { + file_buoyant_cloud_api_proto_rawDescOnce.Do(func() { + file_buoyant_cloud_api_proto_rawDescData = protoimpl.X.CompressGZIP(file_buoyant_cloud_api_proto_rawDescData) + }) + return file_buoyant_cloud_api_proto_rawDescData +} + +var file_buoyant_cloud_api_proto_msgTypes = make([]protoimpl.MessageInfo, 14) +var file_buoyant_cloud_api_proto_goTypes = []interface{}{ + (*Empty)(nil), // 0: buoyant.cloud.Empty + (*Auth)(nil), // 1: buoyant.cloud.Auth + (*Workload)(nil), // 2: buoyant.cloud.Workload + (*DaemonSet)(nil), // 3: buoyant.cloud.DaemonSet + (*Deployment)(nil), // 4: buoyant.cloud.Deployment + (*StatefulSet)(nil), // 5: buoyant.cloud.StatefulSet + (*ReplicaSet)(nil), // 6: buoyant.cloud.ReplicaSet + (*Pod)(nil), // 7: buoyant.cloud.Pod + (*WorkloadMessage)(nil), // 8: buoyant.cloud.WorkloadMessage + (*AddWorkload)(nil), // 9: buoyant.cloud.AddWorkload + (*DeleteWorkload)(nil), // 10: buoyant.cloud.DeleteWorkload + (*UpdateWorkload)(nil), // 11: buoyant.cloud.UpdateWorkload + (*ListWorkloads)(nil), // 12: buoyant.cloud.ListWorkloads + (*Event)(nil), // 13: buoyant.cloud.Event + (*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp +} +var file_buoyant_cloud_api_proto_depIdxs = []int32{ + 3, // 0: buoyant.cloud.Workload.daemonset:type_name -> buoyant.cloud.DaemonSet + 4, // 1: buoyant.cloud.Workload.deployment:type_name -> buoyant.cloud.Deployment + 5, // 2: buoyant.cloud.Workload.statefulset:type_name -> buoyant.cloud.StatefulSet + 7, // 3: buoyant.cloud.DaemonSet.pods:type_name -> buoyant.cloud.Pod + 6, // 4: buoyant.cloud.Deployment.replica_sets:type_name -> buoyant.cloud.ReplicaSet + 7, // 5: buoyant.cloud.StatefulSet.pods:type_name -> buoyant.cloud.Pod + 7, // 6: buoyant.cloud.ReplicaSet.pods:type_name -> buoyant.cloud.Pod + 1, // 7: buoyant.cloud.WorkloadMessage.auth:type_name -> buoyant.cloud.Auth + 9, // 8: buoyant.cloud.WorkloadMessage.added:type_name -> buoyant.cloud.AddWorkload + 11, // 9: buoyant.cloud.WorkloadMessage.updated:type_name -> buoyant.cloud.UpdateWorkload + 10, // 10: buoyant.cloud.WorkloadMessage.deleted:type_name -> buoyant.cloud.DeleteWorkload + 12, // 11: buoyant.cloud.WorkloadMessage.list:type_name -> buoyant.cloud.ListWorkloads + 2, // 12: buoyant.cloud.AddWorkload.workload:type_name -> buoyant.cloud.Workload + 2, // 13: buoyant.cloud.DeleteWorkload.workload:type_name -> buoyant.cloud.Workload + 2, // 14: buoyant.cloud.UpdateWorkload.old_workload:type_name -> buoyant.cloud.Workload + 2, // 15: buoyant.cloud.UpdateWorkload.new_workload:type_name -> buoyant.cloud.Workload + 14, // 16: buoyant.cloud.UpdateWorkload.timestamp:type_name -> google.protobuf.Timestamp + 2, // 17: buoyant.cloud.ListWorkloads.workloads:type_name -> buoyant.cloud.Workload + 1, // 18: buoyant.cloud.Event.auth:type_name -> buoyant.cloud.Auth + 2, // 19: buoyant.cloud.Event.owner:type_name -> buoyant.cloud.Workload + 8, // 20: buoyant.cloud.Api.WorkloadStream:input_type -> buoyant.cloud.WorkloadMessage + 13, // 21: buoyant.cloud.Api.AddEvent:input_type -> buoyant.cloud.Event + 0, // 22: buoyant.cloud.Api.WorkloadStream:output_type -> buoyant.cloud.Empty + 0, // 23: buoyant.cloud.Api.AddEvent:output_type -> buoyant.cloud.Empty + 22, // [22:24] is the sub-list for method output_type + 20, // [20:22] is the sub-list for method input_type + 20, // [20:20] is the sub-list for extension type_name + 20, // [20:20] is the sub-list for extension extendee + 0, // [0:20] is the sub-list for field type_name +} + +func init() { file_buoyant_cloud_api_proto_init() } +func file_buoyant_cloud_api_proto_init() { + if File_buoyant_cloud_api_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_buoyant_cloud_api_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Empty); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_buoyant_cloud_api_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Auth); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_buoyant_cloud_api_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Workload); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_buoyant_cloud_api_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DaemonSet); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_buoyant_cloud_api_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Deployment); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_buoyant_cloud_api_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StatefulSet); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_buoyant_cloud_api_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReplicaSet); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_buoyant_cloud_api_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Pod); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_buoyant_cloud_api_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WorkloadMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_buoyant_cloud_api_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddWorkload); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_buoyant_cloud_api_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteWorkload); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_buoyant_cloud_api_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateWorkload); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_buoyant_cloud_api_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListWorkloads); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_buoyant_cloud_api_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Event); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_buoyant_cloud_api_proto_msgTypes[2].OneofWrappers = []interface{}{ + (*Workload_Daemonset)(nil), + (*Workload_Deployment)(nil), + (*Workload_Statefulset)(nil), + } + file_buoyant_cloud_api_proto_msgTypes[8].OneofWrappers = []interface{}{ + (*WorkloadMessage_Auth)(nil), + (*WorkloadMessage_Added)(nil), + (*WorkloadMessage_Updated)(nil), + (*WorkloadMessage_Deleted)(nil), + (*WorkloadMessage_List)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_buoyant_cloud_api_proto_rawDesc, + NumEnums: 0, + NumMessages: 14, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_buoyant_cloud_api_proto_goTypes, + DependencyIndexes: file_buoyant_cloud_api_proto_depIdxs, + MessageInfos: file_buoyant_cloud_api_proto_msgTypes, + }.Build() + File_buoyant_cloud_api_proto = out.File + file_buoyant_cloud_api_proto_rawDesc = nil + file_buoyant_cloud_api_proto_goTypes = nil + file_buoyant_cloud_api_proto_depIdxs = nil +} diff --git a/gen/bcloud/buoyant-cloud-api_grpc.pb.go b/gen/bcloud/buoyant-cloud-api_grpc.pb.go new file mode 100644 index 0000000..b17ee79 --- /dev/null +++ b/gen/bcloud/buoyant-cloud-api_grpc.pb.go @@ -0,0 +1,172 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package bcloud + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// ApiClient is the client API for Api service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type ApiClient interface { + WorkloadStream(ctx context.Context, opts ...grpc.CallOption) (Api_WorkloadStreamClient, error) + AddEvent(ctx context.Context, in *Event, opts ...grpc.CallOption) (*Empty, error) +} + +type apiClient struct { + cc grpc.ClientConnInterface +} + +func NewApiClient(cc grpc.ClientConnInterface) ApiClient { + return &apiClient{cc} +} + +func (c *apiClient) WorkloadStream(ctx context.Context, opts ...grpc.CallOption) (Api_WorkloadStreamClient, error) { + stream, err := c.cc.NewStream(ctx, &Api_ServiceDesc.Streams[0], "/buoyant.cloud.Api/WorkloadStream", opts...) + if err != nil { + return nil, err + } + x := &apiWorkloadStreamClient{stream} + return x, nil +} + +type Api_WorkloadStreamClient interface { + Send(*WorkloadMessage) error + CloseAndRecv() (*Empty, error) + grpc.ClientStream +} + +type apiWorkloadStreamClient struct { + grpc.ClientStream +} + +func (x *apiWorkloadStreamClient) Send(m *WorkloadMessage) error { + return x.ClientStream.SendMsg(m) +} + +func (x *apiWorkloadStreamClient) CloseAndRecv() (*Empty, error) { + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + m := new(Empty) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *apiClient) AddEvent(ctx context.Context, in *Event, opts ...grpc.CallOption) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, "/buoyant.cloud.Api/AddEvent", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ApiServer is the server API for Api service. +// All implementations must embed UnimplementedApiServer +// for forward compatibility +type ApiServer interface { + WorkloadStream(Api_WorkloadStreamServer) error + AddEvent(context.Context, *Event) (*Empty, error) + mustEmbedUnimplementedApiServer() +} + +// UnimplementedApiServer must be embedded to have forward compatible implementations. +type UnimplementedApiServer struct { +} + +func (UnimplementedApiServer) WorkloadStream(Api_WorkloadStreamServer) error { + return status.Errorf(codes.Unimplemented, "method WorkloadStream not implemented") +} +func (UnimplementedApiServer) AddEvent(context.Context, *Event) (*Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddEvent not implemented") +} +func (UnimplementedApiServer) mustEmbedUnimplementedApiServer() {} + +// UnsafeApiServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ApiServer will +// result in compilation errors. +type UnsafeApiServer interface { + mustEmbedUnimplementedApiServer() +} + +func RegisterApiServer(s grpc.ServiceRegistrar, srv ApiServer) { + s.RegisterService(&Api_ServiceDesc, srv) +} + +func _Api_WorkloadStream_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(ApiServer).WorkloadStream(&apiWorkloadStreamServer{stream}) +} + +type Api_WorkloadStreamServer interface { + SendAndClose(*Empty) error + Recv() (*WorkloadMessage, error) + grpc.ServerStream +} + +type apiWorkloadStreamServer struct { + grpc.ServerStream +} + +func (x *apiWorkloadStreamServer) SendAndClose(m *Empty) error { + return x.ServerStream.SendMsg(m) +} + +func (x *apiWorkloadStreamServer) Recv() (*WorkloadMessage, error) { + m := new(WorkloadMessage) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _Api_AddEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Event) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ApiServer).AddEvent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/buoyant.cloud.Api/AddEvent", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ApiServer).AddEvent(ctx, req.(*Event)) + } + return interceptor(ctx, in, info, handler) +} + +// Api_ServiceDesc is the grpc.ServiceDesc for Api service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Api_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "buoyant.cloud.Api", + HandlerType: (*ApiServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AddEvent", + Handler: _Api_AddEvent_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "WorkloadStream", + Handler: _Api_WorkloadStream_Handler, + ClientStreams: true, + }, + }, + Metadata: "buoyant-cloud-api.proto", +} diff --git a/go.mod b/go.mod index 0d63c97..a7807c9 100644 --- a/go.mod +++ b/go.mod @@ -6,10 +6,15 @@ require ( github.com/fatih/color v1.9.0 github.com/linkerd/linkerd2 v0.5.1-0.20210212214341-d2a40276107e github.com/pkg/browser v0.0.0-20201112035734-206646e67786 + github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.1.3 - k8s.io/api v0.20.2 - k8s.io/apimachinery v0.20.2 - k8s.io/client-go v0.20.2 - k8s.io/kubectl v0.20.2 + google.golang.org/grpc v1.37.0 + google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 // indirect + google.golang.org/protobuf v1.26.0 + k8s.io/api v0.21.0 + k8s.io/apimachinery v0.21.0 + k8s.io/client-go v0.21.0 + k8s.io/klog v1.0.0 + k8s.io/kubectl v0.21.0 sigs.k8s.io/yaml v1.2.0 ) diff --git a/go.sum b/go.sum index 53c5789..f151845 100644 --- a/go.sum +++ b/go.sum @@ -33,9 +33,9 @@ github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= -github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= -github.com/Azure/go-autorest/autorest v0.11.3 h1:fyYnmYujkIXUgv88D9/Wo2ybE4Zwd/TmQd5sSI5u2Ws= github.com/Azure/go-autorest/autorest v0.11.3/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.12 h1:gI8ytXbxMfI+IVbI9mP2JGCTXIuhHLgRlvQ9X4PsnHE= +github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= @@ -138,6 +138,7 @@ github.com/clarketm/json v1.13.4/go.mod h1:ynr2LRfb0fQU34l07csRNBTcivjySLLiY1YzQ github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= @@ -168,6 +169,8 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -192,7 +195,6 @@ github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -212,9 +214,11 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 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/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b/go.mod h1:NAJj0yf/KaRKURN6nyi7A9IZydMivZEm9oQLWNjfKDc= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= @@ -236,6 +240,7 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -247,8 +252,9 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= @@ -280,10 +286,12 @@ github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsd github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= @@ -292,11 +300,13 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= +github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc= @@ -309,8 +319,9 @@ github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFG github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -337,8 +348,9 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W 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 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= @@ -350,8 +362,9 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -362,6 +375,7 @@ github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= @@ -449,18 +463,19 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +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/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -484,6 +499,7 @@ github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= @@ -497,6 +513,7 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-oci8 v0.0.7/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -518,13 +535,17 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= @@ -538,6 +559,8 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nsf/termbox-go v0.0.0-20180613055208-5c94acc5e6eb/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= @@ -545,6 +568,7 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -647,8 +671,9 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/servicemeshinterface/smi-sdk-go v0.4.1 h1:L8nS7WtVlGoEJF7RdCbwh0Oj/JheGY+5fa3R+cA2ReY= github.com/servicemeshinterface/smi-sdk-go v0.4.1/go.mod h1:9rsLPBNcqfDNmEgyYwpopn93aE9yz46d2EHFBNOYj/w= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= @@ -659,8 +684,9 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -721,8 +747,10 @@ 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/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= @@ -742,6 +770,7 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -770,8 +799,9 @@ golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -802,6 +832,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -837,8 +868,10 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= +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= +golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM= +golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -851,6 +884,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -881,6 +915,7 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w 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-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -898,9 +933,16 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY= -golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073 h1:8qxJSnu+7dRq6upnbntrmriWByIakBuct5OM/MdQC1M= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -913,8 +955,8 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -962,6 +1004,9 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1025,8 +1070,11 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.31.1 h1:SfXqXS5hkufcdZ/mHtYCh53P2b+92WQq/DZcKLgsFRs= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.37.0 h1:uSZWeQJX5j11bIQ4AJoj+McDBo29cY1MCoC1wO3ts+c= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1036,15 +1084,18 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= 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 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= @@ -1066,6 +1117,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/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= @@ -1073,6 +1125,7 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= helm.sh/helm/v3 v3.4.1 h1:NIdlBGKFRTAkhz0ooYKw1VBbmTldxNAZRY1nH6Glk6I= helm.sh/helm/v3 v3.4.1/go.mod h1:MeRlXlmCr5CWYKvqIPgXrSmcIXJpv7qcsKV3uTvcZSM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1085,58 +1138,58 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8= k8s.io/api v0.18.8/go.mod h1:d/CXqwWv+Z2XEG1LgceeDmHQwpUJhROPx16SlxJgERY= k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= -k8s.io/api v0.20.2 h1:y/HR22XDZY3pniu9hIFDLpUCPq2w5eQ6aV/VFQ7uJMw= -k8s.io/api v0.20.2/go.mod h1:d7n6Ehyzx+S+cE3VhTGfVNNqtGc/oL9DCdYYahlurV8= +k8s.io/api v0.21.0 h1:gu5iGF4V6tfVCQ/R+8Hc0h7H1JuEhzyEi9S4R5LM8+Y= +k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= k8s.io/apiextensions-apiserver v0.19.3 h1:WZxBypSHW4SdXHbdPTS/Jy7L2la6Niggs8BuU5o+avo= k8s.io/apiextensions-apiserver v0.19.3/go.mod h1:igVEkrE9TzInc1tYE7qSqxaLg/rEAp6B5+k9Q7+IC8Q= k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.18.8/go.mod h1:6sQd+iHEqmOtALqOFjSWp2KZ9F0wlU/nWm0ZgsYWMig= k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= -k8s.io/apimachinery v0.20.2 h1:hFx6Sbt1oG0n6DZ+g4bFt5f6BoMkOjKWsQFu077M3Vg= -k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.21.0 h1:3Fx+41if+IRavNcKOz09FwEXDBG6ORh6iMsTSelhkMA= +k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= k8s.io/apiserver v0.18.8/go.mod h1:12u5FuGql8Cc497ORNj79rhPdiXQC4bf53X/skR/1YM= k8s.io/apiserver v0.19.3/go.mod h1:bx6dMm+H6ifgKFpCQT/SAhPwhzoeIMlHIaibomUDec0= k8s.io/cli-runtime v0.19.3/go.mod h1:q+l845i5/uWzcUpCrl+L4f3XLaJi8ZeLVQ/decwty0A= -k8s.io/cli-runtime v0.20.2/go.mod h1:FjH6uIZZZP3XmwrXWeeYCbgxcrD6YXxoAykBaWH0VdM= +k8s.io/cli-runtime v0.21.0/go.mod h1:XoaHP93mGPF37MkLbjGVYqg3S1MnsFdKtiA/RZzzxOo= k8s.io/client-go v0.18.0/go.mod h1:uQSYDYs4WhVZ9i6AIoEZuwUggLVEF64HOD37boKAtF8= k8s.io/client-go v0.18.8/go.mod h1:HqFqMllQ5NnQJNwjro9k5zMyfhZlOwpuTLVrxjkYSxU= k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= -k8s.io/client-go v0.20.2 h1:uuf+iIAbfnCSw8IGAv/Rg0giM+2bOzHLOsbbrwrdhNQ= -k8s.io/client-go v0.20.2/go.mod h1:kH5brqWqp7HDxUFKoEgiI4v8G1xzbe9giaCenUWJzgE= +k8s.io/client-go v0.21.0 h1:n0zzzJsAQmJngpC0IhgFcApZyoGXPrDIAD601HD09ag= +k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= k8s.io/code-generator v0.18.0/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.18.8/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= k8s.io/code-generator v0.19.3/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= -k8s.io/code-generator v0.20.2/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg= +k8s.io/code-generator v0.21.0/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHDh6Q= k8s.io/component-base v0.18.8/go.mod h1:00frPRDas29rx58pPCxNkhUfPbwajlyyvu8ruNgSErU= k8s.io/component-base v0.19.3/go.mod h1:WhLWSIefQn8W8jxSLl5WNiR6z8oyMe/8Zywg7alOkRc= -k8s.io/component-base v0.20.2/go.mod h1:pzFtCiwe/ASD0iV7ySMu8SYVJjCapNM9bjvk7ptpKh0= -k8s.io/component-helpers v0.20.2/go.mod h1:qeM6iAWGqIr+WE8n2QW2OK9XkpZkPNTxAoEv9jl40/I= +k8s.io/component-base v0.21.0/go.mod h1:qvtjz6X0USWXbgmbfXR+Agik4RZ3jv2Bgr5QnZzdPYw= +k8s.io/component-helpers v0.21.0/go.mod h1:tezqefP7lxfvJyR+0a+6QtVrkZ/wIkyMLK4WcQ3Cj8U= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= 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.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ= -k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= +k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-aggregator v0.18.8 h1:8VQxblQqRInpJ+DS2aGgbdWq6xP8UG/jzV6v8cFccOc= k8s.io/kube-aggregator v0.18.8/go.mod h1:CyLoGZB+io8eEwnn+6RbV7QWJQhj8a3TBH8ZM8sLbhI= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= -k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd h1:sOHNzJIkytDF6qadMNKhhDRpc6ODik8lVC6nOur7B2c= -k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0= +k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= k8s.io/kubectl v0.19.3/go.mod h1:t5cscfrAuHUvEGNyNJjPKt+rGlaJzk8jrKYHXxEsANE= -k8s.io/kubectl v0.20.2 h1:mXExF6N4eQUYmlfXJmfWIheCBLF6/n4VnwQKbQki5iE= -k8s.io/kubectl v0.20.2/go.mod h1:/bchZw5fZWaGZxaRxxfDQKej/aDEtj/Tf9YSS4Jl0es= +k8s.io/kubectl v0.21.0 h1:WZXlnG/yjcE4LWO2g6ULjFxtzK6H1TKzsfaBFuVIhNg= +k8s.io/kubectl v0.21.0/go.mod h1:EU37NukZRXn1TpAkMUoy8Z/B2u6wjHDS4aInsDzVvks= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/metrics v0.19.3/go.mod h1:Eap/Lk1FiAIjkaArFuv41v+ph6dbDpVGwAg7jMI+4vg= -k8s.io/metrics v0.20.2/go.mod h1:yTck5nl5wt/lIeLcU6g0b8/AKJf2girwe0PQiaM4Mwk= +k8s.io/metrics v0.21.0/go.mod h1:L3Ji9EGPP1YBbfm9sPfEXSpnj8i24bfQbAFAsW0NueQ= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= @@ -1147,11 +1200,16 @@ rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.9/go.mod h1:dzAXnQbTRyDlZPJX2SUPEqvnB+j7AJjtlox7PEwigU0= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= +sigs.k8s.io/kustomize/api v0.8.5/go.mod h1:M377apnKT5ZHJS++6H4rQoCHmWtt6qTpp3mbe7p6OLY= +sigs.k8s.io/kustomize/cmd/config v0.9.7/go.mod h1:MvXCpHs77cfyxRmCNUQjIqCmZyYsbn5PyQpWiq44nW0= +sigs.k8s.io/kustomize/kustomize/v4 v4.0.5/go.mod h1:C7rYla7sI8EnxHE/xEhRBSHMNfcL91fx0uKmUlUhrBk= +sigs.k8s.io/kustomize/kyaml v0.10.15/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.0.2 h1:YHQV7Dajm86OuqnIR6zAelnDWBRjo+YhYV9PmGrh1s8= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8= +sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/proto/buoyant-cloud-api.proto b/proto/buoyant-cloud-api.proto new file mode 100644 index 0000000..abd337f --- /dev/null +++ b/proto/buoyant-cloud-api.proto @@ -0,0 +1,102 @@ +syntax = "proto3"; + +package buoyant.cloud; + +option go_package = "github.com/buoyantio/linkerd-buoyant/gen/bcloud"; + +import "google/protobuf/timestamp.proto"; + +// +// shared messages +// + +message Empty {} + +message Auth { + string agent_id = 1; + string agent_key = 2; +} + +message Workload { + oneof workload { + DaemonSet daemonset = 1; + Deployment deployment = 2; + StatefulSet statefulset = 3; + } +} + +message DaemonSet { + bytes daemon_set = 1; + repeated Pod pods = 2; +} + +message Deployment { + bytes deployment = 1; + repeated ReplicaSet replica_sets = 2; +} + +message StatefulSet { + bytes stateful_set = 1; + repeated Pod pods = 2; +} + +message ReplicaSet { + bytes replica_set = 1; + repeated Pod pods = 2; +} + +message Pod { + bytes pod = 1; +} + +// +// WorkloadStream messages +// + +message WorkloadMessage { + oneof message { + Auth auth = 1; + + AddWorkload added = 2; + UpdateWorkload updated = 3; + DeleteWorkload deleted = 4; + ListWorkloads list = 5; + } +} + +message AddWorkload { + Workload workload = 1; +} + +message DeleteWorkload { + Workload workload = 1; +} + +message UpdateWorkload { + Workload old_workload = 1; + Workload new_workload = 2; + google.protobuf.Timestamp timestamp = 3; +} + +message ListWorkloads { + repeated Workload workloads = 1; +} + +// +// AddEvent messages +// + +message Event { + Auth auth = 1; + bytes event = 2; + Workload owner = 3; +} + +// +// API +// + +service Api { + rpc WorkloadStream(stream WorkloadMessage) returns (Empty) {} + rpc AddEvent(Event) returns (Empty) {} +}