From c680c17988d8f1d80e54925f3cb98e236fd579a8 Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Tue, 15 Dec 2020 09:15:45 -0800 Subject: [PATCH 01/68] feat(ui): Support Argo Events in the UI. Fixes #888 Signed-off-by: Alex Collins --- .github/workflows/ci-build.yaml | 1 + .gitignore | 2 + .golangci.yml | 2 +- Makefile | 33 +- api/jsonschema/schema.json | 27 + api/openapi-spec/swagger.json | 103 + cmd/argo/commands/server.go | 16 +- docs/workflow-controller-configmap.yaml | 6 + go.mod | 16 +- go.sum | 235 +- .../argo-server-clusterole.yaml | 2 + manifests/install.yaml | 2 + manifests/namespace-install.yaml | 2 + .../argo-server-rbac/argo-server-role.yaml | 2 + manifests/quick-start-minimal.yaml | 5 + manifests/quick-start-mysql.yaml | 5 + manifests/quick-start-postgres.yaml | 5 + .../workflow-controller-configmap.yaml | 3 + pkg/apiclient/argo-kube-client.go | 18 +- pkg/apiclient/event/event.pb.go | 335 +- pkg/apiclient/event/event.pb.gw.go | 113 + pkg/apiclient/event/event.proto | 9 + pkg/apiclient/eventsource/eventsource.pb.go | 1833 +++++++++ .../eventsource/eventsource.pb.gw.go | 352 ++ pkg/apiclient/eventsource/eventsource.proto | 57 + .../eventsource/forwarder_overwrite.go | 10 + pkg/apiclient/sensor/forwarder_overwrite.go | 10 + pkg/apiclient/sensor/sensor.pb.go | 1832 +++++++++ pkg/apiclient/sensor/sensor.pb.gw.go | 352 ++ pkg/apiclient/sensor/sensor.proto | 57 + server/apiserver/argoserver.go | 44 +- server/auth/gatekeeper.go | 113 +- server/auth/gatekeeper_test.go | 28 +- server/event/event_server.go | 13 +- server/eventsource/event_source_server.go | 102 + server/sensor/sensor_server.go | 100 + server/types/clients.go | 17 + test/e2e/manifests/events/kustomization.yaml | 19 + test/e2e/manifests/minimal/kustomization.yaml | 13 +- .../mixins/workflow-controller-configmap.yaml | 5 + test/e2e/manifests/mysql/kustomization.yaml | 13 +- .../e2e/manifests/postgres/kustomization.yaml | 13 +- test/e2e/manifests/sso/kustomization.yaml | 13 +- ui/.yarnrc | 1 - ui/__mocks__/styleMock.js | 1 + ui/jest.config.js | 9 + ui/package.json | 17 +- ui/src/app/app-router.tsx | 153 + ui/src/app/app.tsx | 184 +- .../archived-workflow-details.tsx | 50 +- .../archived-workflow-list.tsx | 5 +- .../cluster-workflow-template-creator.tsx | 37 + .../cluster-workflow-template-details.tsx | 216 +- .../cluster-workflow-template-editor.tsx | 58 + .../cluster-workflow-template-list.tsx | 19 +- .../components/cron-workflow-creator.tsx | 38 + .../cron-workflow-details.tsx | 273 +- .../components/cron-workflow-editor.tsx | 85 + .../cron-workflow-list/cron-workflow-list.tsx | 26 +- .../components/cron-workflow-spec-editior.tsx | 89 + .../cron-workflow-status-viewer.tsx | 54 + .../events/components/events-container.tsx | 9 + .../events-details/build-graph.test.ts | 15 + .../components/events-details/build-graph.ts | 110 + .../components/events-details/event-page.scss | 30 + .../components/events-details/events-page.tsx | 305 ++ .../components/events-details/genres.ts | 9 + .../events/components/events-details/icons.ts | 50 + .../events/components/events-details/id.ts | 23 + ui/src/app/events/index.ts | 5 + ui/src/app/reports/components/reports.tsx | 11 +- ui/src/app/shared/components/base-page.tsx | 3 + ui/src/app/shared/components/button.tsx | 25 + ui/src/app/shared/components/chat-button.tsx | 32 + .../app/shared/components/checkbox-list.tsx | 16 + .../components/data-loader-dropdown.tsx | 3 +- .../shared/components/drop-down-button.tsx | 9 +- .../components/editors/key-value-editor.tsx | 64 + .../editors/labels-and-annotations-editor.tsx | 22 + .../components/editors/metadata-editor.tsx | 32 + .../editors/workflow-spec-editor.scss | 23 + .../editors/workflow-spec-editor.tsx | 265 ++ ui/src/app/shared/components/error-notice.tsx | 43 +- .../shared/components/filter-drop-down.tsx | 16 + .../components/graph/coffman-graham-sorter.ts | 48 + .../app/shared/components/graph/dfs-sorter.ts | 26 + .../shared/components/graph/fast-layout.ts | 56 + .../shared/components/graph/graph-panel.scss | 163 + .../shared/components/graph/graph-panel.tsx | 188 + ui/src/app/shared/components/graph/icon.tsx | 24 + ui/src/app/shared/components/graph/label.tsx | 33 + ui/src/app/shared/components/graph/layout.ts | 10 + .../shared/components/graph/pretty-layout.ts | 42 + ui/src/app/shared/components/graph/types.ts | 53 + ui/src/app/shared/components/icon.ts | 55 + ui/src/app/shared/components/icons.ts | 48 + ui/src/app/shared/components/link-button.tsx | 5 +- ui/src/app/shared/components/loading.tsx | 6 +- ui/src/app/shared/components/notice.tsx | 2 +- ui/src/app/shared/components/nudge.tsx | 2 +- ui/src/app/shared/components/number-input.tsx | 5 + .../object-editor/object-editor.tsx | 102 + ui/src/app/shared/components/object-parser.ts | 12 + ui/src/app/shared/components/query.tsx | 46 +- .../resource-editor/resource-editor.tsx | 165 +- .../components/tags-input/tags-input.tsx | 2 +- ui/src/app/shared/components/text-input.tsx | 4 + .../app/shared/components/toggle-button.tsx | 9 +- .../app/shared/components/upload-button.tsx | 18 + .../components/workflow-spec-panel/genres.ts | 21 + .../components/workflow-spec-panel/icons.ts | 25 + .../components/workflow-spec-panel/id.ts | 49 + .../workflow-spec-graph.ts | 173 + .../workflow-spec-panel.tsx | 27 + ui/src/app/shared/components/zero-state.tsx | 4 +- ui/src/app/shared/context.ts | 3 +- ui/src/app/shared/examples.ts | 37 +- ui/src/app/shared/history.test.ts | 31 + ui/src/app/shared/history.ts | 24 + ui/src/app/shared/list-watch.ts | 98 + ui/src/app/shared/retry-watch.ts | 58 + ui/src/app/shared/scoped-local-storage.ts | 32 + ui/src/app/shared/services/event-service.ts | 8 + .../shared/services/event-source-service.ts | 34 + ui/src/app/shared/services/index.ts | 14 +- ui/src/app/shared/services/requests.ts | 3 + ui/src/app/shared/services/sensor-service.ts | 31 + .../app/shared/services/workflows-service.ts | 46 +- ui/src/app/shared/template-resolution.ts | 4 +- ui/src/app/shared/utils.ts | 7 +- ui/src/app/shared/workflow-operations-map.ts | 5 +- ui/src/app/userinfo/components/user-info.tsx | 41 +- ui/src/app/webpack.config.js | 14 +- .../workflow-event-bindings-container.tsx | 9 + .../workflow-event-bindings-list/id.ts | 10 + .../workflow-event-bindings-list.tsx | 113 + ui/src/app/workflow-event-bindings/index.ts | 5 + .../components/workflow-template-creator.tsx | 38 + .../workflow-template-details.tsx | 214 +- .../components/workflow-template-editor.tsx | 58 + .../workflow-template-list.tsx | 173 +- .../app/workflows/components/events-panel.tsx | 203 +- .../submit-from-workflow-template-panel.tsx | 47 + .../components/submit-workflow-panel.tsx | 2 +- .../components/workflow-artifacts.tsx | 2 +- .../workflows/components/workflow-creator.tsx | 38 + .../components/workflow-dag/genres.ts | 11 + .../workflow-dag/graph/collapsible-node.ts | 4 - .../components/workflow-dag/icons.ts | 13 + .../workflow-dag-render-options-panel.tsx | 111 +- .../components/workflow-dag/workflow-dag.tsx | 507 +-- .../workflow-details/workflow-details.tsx | 484 +-- .../workflow-resource-panel.tsx | 24 +- .../workflows/components/workflow-editor.tsx | 47 + .../workflow-logs-viewer.scss | 17 +- .../workflow-logs-viewer.tsx | 188 +- .../workflow-node-info/workflow-node-info.tsx | 38 +- .../workflow-panel/workflow-panel.tsx | 2 +- .../workflow-timeline/workflow-timeline.tsx | 4 +- .../workflow-yaml-viewer.tsx | 143 +- .../workflows-list/workflows-list.tsx | 278 +- ui/src/models/cron-workflows.ts | 4 +- ui/src/models/event-source.ts | 79 + ui/src/models/events.ts | 18 +- ui/src/models/sensor.ts | 49 + ui/src/models/workflows.ts | 33 +- ui/tsconfig.json | 1 + ui/yarn.lock | 3263 ++++++++++++++++- util/logs/pods-logger.go | 91 + workflow/controller/controller_test.go | 11 +- 170 files changed, 14041 insertions(+), 2577 deletions(-) create mode 100644 pkg/apiclient/eventsource/eventsource.pb.go create mode 100644 pkg/apiclient/eventsource/eventsource.pb.gw.go create mode 100644 pkg/apiclient/eventsource/eventsource.proto create mode 100644 pkg/apiclient/eventsource/forwarder_overwrite.go create mode 100644 pkg/apiclient/sensor/forwarder_overwrite.go create mode 100644 pkg/apiclient/sensor/sensor.pb.go create mode 100644 pkg/apiclient/sensor/sensor.pb.gw.go create mode 100644 pkg/apiclient/sensor/sensor.proto create mode 100644 server/eventsource/event_source_server.go create mode 100644 server/sensor/sensor_server.go create mode 100644 server/types/clients.go create mode 100644 test/e2e/manifests/events/kustomization.yaml create mode 100644 ui/__mocks__/styleMock.js create mode 100644 ui/jest.config.js create mode 100644 ui/src/app/app-router.tsx create mode 100644 ui/src/app/cluster-workflow-templates/components/cluster-workflow-template-creator.tsx create mode 100644 ui/src/app/cluster-workflow-templates/components/cluster-workflow-template-editor.tsx create mode 100644 ui/src/app/cron-workflows/components/cron-workflow-creator.tsx create mode 100644 ui/src/app/cron-workflows/components/cron-workflow-editor.tsx create mode 100644 ui/src/app/cron-workflows/components/cron-workflow-spec-editior.tsx create mode 100644 ui/src/app/cron-workflows/components/cron-workflow-status-viewer.tsx create mode 100644 ui/src/app/events/components/events-container.tsx create mode 100644 ui/src/app/events/components/events-details/build-graph.test.ts create mode 100644 ui/src/app/events/components/events-details/build-graph.ts create mode 100644 ui/src/app/events/components/events-details/event-page.scss create mode 100644 ui/src/app/events/components/events-details/events-page.tsx create mode 100644 ui/src/app/events/components/events-details/genres.ts create mode 100644 ui/src/app/events/components/events-details/icons.ts create mode 100644 ui/src/app/events/components/events-details/id.ts create mode 100644 ui/src/app/events/index.ts create mode 100644 ui/src/app/shared/components/button.tsx create mode 100644 ui/src/app/shared/components/chat-button.tsx create mode 100644 ui/src/app/shared/components/checkbox-list.tsx create mode 100644 ui/src/app/shared/components/editors/key-value-editor.tsx create mode 100644 ui/src/app/shared/components/editors/labels-and-annotations-editor.tsx create mode 100644 ui/src/app/shared/components/editors/metadata-editor.tsx create mode 100644 ui/src/app/shared/components/editors/workflow-spec-editor.scss create mode 100644 ui/src/app/shared/components/editors/workflow-spec-editor.tsx create mode 100644 ui/src/app/shared/components/filter-drop-down.tsx create mode 100644 ui/src/app/shared/components/graph/coffman-graham-sorter.ts create mode 100644 ui/src/app/shared/components/graph/dfs-sorter.ts create mode 100644 ui/src/app/shared/components/graph/fast-layout.ts create mode 100644 ui/src/app/shared/components/graph/graph-panel.scss create mode 100644 ui/src/app/shared/components/graph/graph-panel.tsx create mode 100644 ui/src/app/shared/components/graph/icon.tsx create mode 100644 ui/src/app/shared/components/graph/label.tsx create mode 100644 ui/src/app/shared/components/graph/layout.ts create mode 100644 ui/src/app/shared/components/graph/pretty-layout.ts create mode 100644 ui/src/app/shared/components/graph/types.ts create mode 100644 ui/src/app/shared/components/icon.ts create mode 100644 ui/src/app/shared/components/icons.ts create mode 100644 ui/src/app/shared/components/number-input.tsx create mode 100644 ui/src/app/shared/components/object-editor/object-editor.tsx create mode 100644 ui/src/app/shared/components/object-parser.ts create mode 100644 ui/src/app/shared/components/text-input.tsx create mode 100644 ui/src/app/shared/components/upload-button.tsx create mode 100644 ui/src/app/shared/components/workflow-spec-panel/genres.ts create mode 100644 ui/src/app/shared/components/workflow-spec-panel/icons.ts create mode 100644 ui/src/app/shared/components/workflow-spec-panel/id.ts create mode 100644 ui/src/app/shared/components/workflow-spec-panel/workflow-spec-graph.ts create mode 100644 ui/src/app/shared/components/workflow-spec-panel/workflow-spec-panel.tsx create mode 100644 ui/src/app/shared/history.test.ts create mode 100644 ui/src/app/shared/history.ts create mode 100644 ui/src/app/shared/list-watch.ts create mode 100644 ui/src/app/shared/retry-watch.ts create mode 100644 ui/src/app/shared/scoped-local-storage.ts create mode 100644 ui/src/app/shared/services/event-service.ts create mode 100644 ui/src/app/shared/services/event-source-service.ts create mode 100644 ui/src/app/shared/services/sensor-service.ts create mode 100644 ui/src/app/workflow-event-bindings/components/workflow-event-bindings-container.tsx create mode 100644 ui/src/app/workflow-event-bindings/components/workflow-event-bindings-list/id.ts create mode 100644 ui/src/app/workflow-event-bindings/components/workflow-event-bindings-list/workflow-event-bindings-list.tsx create mode 100644 ui/src/app/workflow-event-bindings/index.ts create mode 100644 ui/src/app/workflow-templates/components/workflow-template-creator.tsx create mode 100644 ui/src/app/workflow-templates/components/workflow-template-editor.tsx create mode 100644 ui/src/app/workflows/components/submit-from-workflow-template-panel.tsx create mode 100644 ui/src/app/workflows/components/workflow-creator.tsx create mode 100644 ui/src/app/workflows/components/workflow-dag/genres.ts create mode 100644 ui/src/app/workflows/components/workflow-dag/icons.ts create mode 100644 ui/src/app/workflows/components/workflow-editor.tsx create mode 100644 ui/src/models/event-source.ts create mode 100644 ui/src/models/sensor.ts create mode 120000 ui/tsconfig.json create mode 100644 util/logs/pods-logger.go diff --git a/.github/workflows/ci-build.yaml b/.github/workflows/ci-build.yaml index f54c9e4d1008..354921ea87d3 100644 --- a/.github/workflows/ci-build.yaml +++ b/.github/workflows/ci-build.yaml @@ -193,6 +193,7 @@ jobs: run: | yarn --cwd ui install yarn --cwd ui build + yarn --cwd ui test yarn --cwd ui lint - name: Ensure nothing changed run: git diff --exit-code diff --git a/.gitignore b/.gitignore index 368ecbcb33d0..1099be781ae8 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,9 @@ git-ask-pass.sh /pkg/apiclient/clusterworkflowtemplate/cluster-workflow-template.swagger.json /pkg/apiclient/cronworkflow/cron-workflow.swagger.json /pkg/apiclient/event/event.swagger.json +/pkg/apiclient/eventsource/eventsource.swagger.json /pkg/apiclient/info/info.swagger.json +/pkg/apiclient/sensor/sensor.swagger.json /pkg/apiclient/workflow/workflow.swagger.json /pkg/apiclient/workflowarchive/workflow-archive.swagger.json /pkg/apiclient/workflowtemplate/workflow-template.swagger.json diff --git a/.golangci.yml b/.golangci.yml index 536543aff615..edb03c73f891 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -14,4 +14,4 @@ linters: - goimports linters-settings: goimports: - local-prefixes: github.com/argoproj/argo + local-prefixes: github.com/argoproj/argo/ diff --git a/Makefile b/Makefile index da9a93081f07..4e6711b9c5e2 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,11 @@ CONTROLLER_IMAGE_FILE := dist/controller-image.marker # perform static compilation STATIC_BUILD ?= true +ifeq ($(GIT_TREE_STATE),dirty) +STATIC_FILES ?= false +else STATIC_FILES ?= true +endif GOTEST ?= go test PROFILE ?= minimal # whether or not to start the Argo Service in TLS mode @@ -56,7 +60,7 @@ AUTH_MODE := hybrid ifeq ($(PROFILE),sso) AUTH_MODE := sso endif -ifeq ($(STATIC_FILES),false) +ifeq ($(CI),true) AUTH_MODE := client endif # Which mode to run in: @@ -64,7 +68,7 @@ endif # * `kubernetes` run the workflow-controller and argo-server on the Kubernetes cluster RUN_MODE := local K3D := $(shell if [[ "`which kubectl`" != '' ]] && [[ "`kubectl config current-context`" == "k3d-"* ]]; then echo true; else echo false; fi) -LOG_LEVEL := debug +LOG_LEVEL := info UPPERIO_DB_DEBUG := 0 NAMESPACED := true @@ -77,6 +81,7 @@ ALWAYS_OFFLOAD_NODE_STATUS := true endif override LDFLAGS += \ + -s -w \ -X github.com/argoproj/argo.version=$(VERSION) \ -X github.com/argoproj/argo.buildDate=${BUILD_DATE} \ -X github.com/argoproj/argo.gitCommit=${GIT_COMMIT} \ @@ -90,9 +95,9 @@ ifneq ($(GIT_TAG),) override LDFLAGS += -X github.com/argoproj/argo.gitTag=${GIT_TAG} endif -ARGOEXEC_PKGS := $(shell echo cmd/argoexec && go list -f '{{ join .Deps "\n" }}' ./cmd/argoexec/ | grep 'argoproj/argo' | cut -c 26-) -CLI_PKGS := $(shell echo cmd/argo && go list -f '{{ join .Deps "\n" }}' ./cmd/argo/ | grep 'argoproj/argo' | cut -c 26-) -CONTROLLER_PKGS := $(shell echo cmd/workflow-controller && go list -f '{{ join .Deps "\n" }}' ./cmd/workflow-controller/ | grep 'argoproj/argo' | cut -c 26-) +ARGOEXEC_PKGS := $(shell echo cmd/argoexec && go list -f '{{ join .Deps "\n" }}' ./cmd/argoexec/ | grep 'argoproj/argo/' | cut -c 26-) +CLI_PKGS := $(shell echo cmd/argo && go list -f '{{ join .Deps "\n" }}' ./cmd/argo/ | grep 'argoproj/argo/' | cut -c 26-) +CONTROLLER_PKGS := $(shell echo cmd/workflow-controller && go list -f '{{ join .Deps "\n" }}' ./cmd/workflow-controller/ | grep 'argoproj/argo/' | cut -c 26-) MANIFESTS := $(shell find manifests -mindepth 2 -type f) E2E_MANIFESTS := $(shell find test/e2e/manifests -mindepth 2 -type f) E2E_EXECUTOR ?= pns @@ -204,7 +209,7 @@ argo-server.key: .PHONY: cli-image cli-image: $(CLI_IMAGE_FILE) -$(CLI_IMAGE_FILE): $(CLI_PKGS) +$(CLI_IMAGE_FILE): $(CLI_PKGS) argo-server.crt argo-server.key $(call docker_build,argocli,argo,$(CLI_IMAGE_FILE)) .PHONY: clis @@ -257,7 +262,9 @@ codegen: \ pkg/apiclient/clusterworkflowtemplate/cluster-workflow-template.swagger.json \ pkg/apiclient/cronworkflow/cron-workflow.swagger.json \ pkg/apiclient/event/event.swagger.json \ + pkg/apiclient/eventsource/eventsource.swagger.json \ pkg/apiclient/info/info.swagger.json \ + pkg/apiclient/sensor/sensor.swagger.json \ pkg/apiclient/workflow/workflow.swagger.json \ pkg/apiclient/workflowarchive/workflow-archive.swagger.json \ pkg/apiclient/workflowtemplate/workflow-template.swagger.json \ @@ -329,9 +336,15 @@ pkg/apiclient/cronworkflow/cron-workflow.swagger.json: $(PROTO_BINARIES) $(TYPES pkg/apiclient/event/event.swagger.json: $(PROTO_BINARIES) $(TYPES) pkg/apiclient/event/event.proto $(call protoc,pkg/apiclient/event/event.proto) +pkg/apiclient/eventsource/eventsource.swagger.json: $(PROTO_BINARIES) $(TYPES) pkg/apiclient/eventsource/eventsource.proto + $(call protoc,pkg/apiclient/eventsource/eventsource.proto) + pkg/apiclient/info/info.swagger.json: $(PROTO_BINARIES) $(TYPES) pkg/apiclient/info/info.proto $(call protoc,pkg/apiclient/info/info.proto) +pkg/apiclient/sensor/sensor.swagger.json: $(PROTO_BINARIES) $(TYPES) pkg/apiclient/sensor/sensor.proto + $(call protoc,pkg/apiclient/sensor/sensor.proto) + pkg/apiclient/workflow/workflow.swagger.json: $(PROTO_BINARIES) $(TYPES) pkg/apiclient/workflow/workflow.proto $(call protoc,pkg/apiclient/workflow/workflow.proto) @@ -343,6 +356,7 @@ pkg/apiclient/workflowtemplate/workflow-template.swagger.json: $(PROTO_BINARIES) # generate other files for other CRDs manifests/base/crds/full/argoproj.io_workflows.yaml: $(GOPATH)/bin/controller-gen $(TYPES) + [ -e vendor ] || go mod vendor ./hack/crdgen.sh /usr/local/bin/kustomize: @@ -386,13 +400,13 @@ test: server/static/files.go dist/$(PROFILE).yaml: $(MANIFESTS) $(E2E_MANIFESTS) /usr/local/bin/kustomize mkdir -p dist + cd test/e2e/manifests/$(PROFILE) && kustomize edit set namespace $(KUBE_NAMESPACE) kustomize build --load_restrictor=none test/e2e/manifests/$(PROFILE) | sed 's/:latest/:$(VERSION)/' | sed 's/pns/$(E2E_EXECUTOR)/' > dist/$(PROFILE).yaml .PHONY: install install: dist/$(PROFILE).yaml - cat test/e2e/manifests/argo-ns.yaml | sed 's/argo/$(KUBE_NAMESPACE)/' > dist/argo-ns.yaml - kubectl apply -f dist/argo-ns.yaml - kubectl -n $(KUBE_NAMESPACE) apply -l app.kubernetes.io/part-of=argo --prune --force -f dist/$(PROFILE).yaml + kubectl create ns $(KUBE_NAMESPACE) --dry-run=client -o yaml | kubectl apply -f - + kubectl apply -l app.kubernetes.io/part-of=argo --prune --force -f dist/$(PROFILE).yaml .PHONY: pull-build-images pull-build-images: @@ -430,6 +444,7 @@ ifeq ($(RUN_MODE),kubernetes) kubectl -n $(KUBE_NAMESPACE) scale deploy/workflow-controller --replicas 1 kubectl -n $(KUBE_NAMESPACE) scale deploy/argo-server --replicas 1 endif + sleep 5s ;# time to allow pod that get deleted to go away kubectl -n $(KUBE_NAMESPACE) wait --for=condition=Ready pod --all -l app --timeout 2m ./hack/port-forward.sh # Check dex, minio, postgres and mysql are in hosts file diff --git a/api/jsonschema/schema.json b/api/jsonschema/schema.json index 9624b33c0a9e..89ee6e23728b 100644 --- a/api/jsonschema/schema.json +++ b/api/jsonschema/schema.json @@ -2451,6 +2451,33 @@ ], "type": "object" }, + "io.argoproj.workflow.v1alpha1.WorkflowEventBindingList": { + "description": "WorkflowEventBindingList is list of event resources", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.io.k8s.community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type": "string" + }, + "items": { + "items": { + "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.WorkflowEventBinding" + }, + "type": "array" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.io.k8s.community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta" + } + }, + "required": [ + "metadata", + "items" + ], + "type": "object" + }, "io.argoproj.workflow.v1alpha1.WorkflowEventBindingSpec": { "properties": { "event": { diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index f1585f8e660b..ce679799abdc 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -908,6 +908,82 @@ } } }, + "/api/v1/workflow-event-bindings/{namespace}": { + "get": { + "tags": [ + "EventService" + ], + "operationId": "ListWorkflowEventBindings", + "parameters": [ + { + "type": "string", + "name": "namespace", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "A selector to restrict the list of returned objects by their labels.\nDefaults to everything.\n+optional.", + "name": "listOptions.labelSelector", + "in": "query" + }, + { + "type": "string", + "description": "A selector to restrict the list of returned objects by their fields.\nDefaults to everything.\n+optional.", + "name": "listOptions.fieldSelector", + "in": "query" + }, + { + "type": "boolean", + "format": "boolean", + "description": "Watch for changes to the described resources and return them as a stream of\nadd, update, and remove notifications. Specify resourceVersion.\n+optional.", + "name": "listOptions.watch", + "in": "query" + }, + { + "type": "boolean", + "format": "boolean", + "description": "allowWatchBookmarks requests watch events with type \"BOOKMARK\".\nServers that do not implement bookmarks may ignore this flag and\nbookmarks are sent at the server's discretion. Clients should not\nassume bookmarks are returned at any specific interval, nor may they\nassume the server will send any BOOKMARK event during a session.\nIf this is not a watch, this field is ignored.\nIf the feature gate WatchBookmarks is not enabled in apiserver,\nthis field is ignored.\n+optional.", + "name": "listOptions.allowWatchBookmarks", + "in": "query" + }, + { + "type": "string", + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource.\nDefaults to changes from the beginning of history.\nWhen specified for list:\n- if unset, then the result is returned from remote storage based on quorum-read flag;\n- if it's 0, then we simply return what we currently have in cache, no guarantee;\n- if set to non zero, then the result is at least as fresh as given rv.\n+optional.", + "name": "listOptions.resourceVersion", + "in": "query" + }, + { + "type": "string", + "format": "int64", + "description": "Timeout for the list/watch call.\nThis limits the duration of the call, regardless of any activity or inactivity.\n+optional.", + "name": "listOptions.timeoutSeconds", + "in": "query" + }, + { + "type": "string", + "format": "int64", + "description": "limit is a maximum number of responses to return for a list call. If more items exist, the\nserver will set the `continue` field on the list metadata to a value that can be used with the\nsame initial query to retrieve the next set of results. Setting a limit may return fewer than\nthe requested amount of items (up to zero items) in the event all requested objects are\nfiltered out and clients should only use the presence of the continue field to determine whether\nmore results are available. Servers may choose not to support the limit argument and will return\nall of the available results. If limit is specified and the continue field is empty, clients may\nassume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing\na single list call without a limit - that is, no objects created, modified, or deleted after the\nfirst request is issued will be included in any subsequent continued requests. This is sometimes\nreferred to as a consistent snapshot, and ensures that a client that is using limit to receive\nsmaller chunks of a very large result can ensure they see all possible objects. If objects are\nupdated during a chunked list the version of the object that was present at the time the first list\nresult was calculated is returned.", + "name": "listOptions.limit", + "in": "query" + }, + { + "type": "string", + "description": "The continue option should be set when retrieving more results from the server. Since this value is\nserver defined, clients may only use the continue value from a previous query result with identical\nquery parameters (except for the value of continue) and the server may reject a continue value it\ndoes not recognize. If the specified continue value is no longer valid whether due to expiration\n(generally five to fifteen minutes) or a configuration change on the server, the server will\nrespond with a 410 ResourceExpired error together with a continue token. If the client needs a\nconsistent list, it must restart their list without the continue field. Otherwise, the client may\nsend another list request with the token received with the 410 error, the server will respond with\na list starting from the next key, but from the latest snapshot, which is inconsistent from the\nprevious list results - objects that are created, modified, or deleted after the first list request\nwill be included in the response, as long as their keys are after the \"next key\".\n\nThis field is not supported when watch is true. Clients may start a watch from the last\nresourceVersion value returned by the server and not miss any modifications.", + "name": "listOptions.continue", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.WorkflowEventBindingList" + } + } + } + } + }, "/api/v1/workflow-events/{namespace}": { "get": { "tags": [ @@ -4499,6 +4575,33 @@ } } }, + "io.argoproj.workflow.v1alpha1.WorkflowEventBindingList": { + "description": "WorkflowEventBindingList is list of event resources", + "type": "object", + "required": [ + "metadata", + "items" + ], + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.io.k8s.community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.WorkflowEventBinding" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.io.k8s.community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta" + } + } + }, "io.argoproj.workflow.v1alpha1.WorkflowEventBindingSpec": { "type": "object", "required": [ diff --git a/cmd/argo/commands/server.go b/cmd/argo/commands/server.go index bc124ff3d9b6..5404a2ea25a6 100644 --- a/cmd/argo/commands/server.go +++ b/cmd/argo/commands/server.go @@ -7,6 +7,8 @@ import ( "reflect" "time" + eventsource "github.com/argoproj/argo-events/pkg/client/eventsource/clientset/versioned" + sensor "github.com/argoproj/argo-events/pkg/client/sensor/clientset/versioned" "github.com/argoproj/pkg/errors" "github.com/argoproj/pkg/stats" log "github.com/sirupsen/logrus" @@ -20,6 +22,7 @@ import ( wfclientset "github.com/argoproj/argo/pkg/client/clientset/versioned" "github.com/argoproj/argo/server/apiserver" "github.com/argoproj/argo/server/auth" + "github.com/argoproj/argo/server/types" "github.com/argoproj/argo/util/help" ) @@ -54,10 +57,12 @@ See %s`, help.ArgoSever), config.QPS = 20.0 namespace := client.Namespace() - - kubeConfig := kubernetes.NewForConfigOrDie(config) - wfClientSet := wfclientset.NewForConfigOrDie(config) - + clients := &types.Clients{ + Workflow: wfclientset.NewForConfigOrDie(config), + EventSource: eventsource.NewForConfigOrDie(config), + Sensor: sensor.NewForConfigOrDie(config), + Kubernetes: kubernetes.NewForConfigOrDie(config), + } ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -101,8 +106,7 @@ See %s`, help.ArgoSever), TLSConfig: tlsConfig, HSTS: htst, Namespace: namespace, - WfClientSet: wfClientSet, - KubeClientset: kubeConfig, + Clients: clients, RestConfig: config, AuthModes: modes, ManagedNamespace: managedNamespace, diff --git a/docs/workflow-controller-configmap.yaml b/docs/workflow-controller-configmap.yaml index bcbd9809bc28..e512e0853e3c 100644 --- a/docs/workflow-controller-configmap.yaml +++ b/docs/workflow-controller-configmap.yaml @@ -40,12 +40,18 @@ data: # volumeName: kube-config-volume links: + # Adds a button to the workflow page. E.g. linking to you logging facility. - name: Example Workflow Link scope: workflow url: http://logging-facility?namespace=${metadata.namespace}&workflowName=${metadata.name}&startedAt=${status.startedAt}&finishedAt=${status.finishedAt} + # Adds a button next to the pod. E.g. linking to you logging facility but for the pod only. - name: Example Pod Link scope: pod url: http://logging-facility?namespace=${metadata.namespace}&podName=${metadata.name}&startedAt=${status.startedAt}&finishedAt=${status.finishedAt} + # Adds a button to the bottom right of every page to link to your organisation help or chat. + - name: Get help + scope: chat + url: http://my-chat # artifactRepository defines the default location to be used as the artifact repository for # container artifacts. diff --git a/go.mod b/go.mod index 69e0491b7f55..74b07bda1e97 100644 --- a/go.mod +++ b/go.mod @@ -8,10 +8,10 @@ require ( cloud.google.com/go/storage v1.6.0 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible github.com/aliyun/aliyun-oss-go-sdk v2.0.6+incompatible - github.com/antonmedv/expr v1.8.2 + github.com/antonmedv/expr v1.8.8 + github.com/argoproj/argo-events v1.1.0 github.com/argoproj/pkg v0.3.0 github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect - github.com/beorn7/perks v1.0.1 // indirect github.com/blushft/go-diagrams v0.0.0-20201006005127-c78c821223d9 github.com/colinmarc/hdfs v1.1.4-0.20180805212432-9746310a4d31 github.com/coreos/go-oidc v2.2.1+incompatible @@ -29,30 +29,23 @@ require ( github.com/gorilla/websocket v1.4.2 github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 github.com/grpc-ecosystem/grpc-gateway v1.14.6 - github.com/hashicorp/golang-lru v0.5.3 // indirect - github.com/imdario/mergo v0.3.8 // indirect github.com/imkira/go-interpol v1.1.0 // indirect - github.com/jcmturner/gofork v1.0.0 // indirect github.com/jstemmer/go-junit-report v0.9.1 - github.com/klauspost/compress v1.9.7 // indirect - github.com/lib/pq v1.3.0 // indirect github.com/mattn/goreman v0.3.5 github.com/minio/minio-go/v7 v7.0.2 github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.0.0 + github.com/prometheus/client_golang v1.1.0 github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.7.0 - github.com/prometheus/procfs v0.0.8 // indirect github.com/robfig/cron/v3 v3.0.1 github.com/satori/go.uuid v1.2.0 // indirect - github.com/sergi/go-diff v1.1.0 // indirect github.com/sirupsen/logrus v1.6.0 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/soheilhy/cmux v0.1.4 github.com/spf13/cobra v1.0.0 github.com/stretchr/testify v1.6.1 - github.com/tidwall/gjson v1.3.5 + github.com/tidwall/gjson v1.6.0 github.com/valyala/fasttemplate v1.1.0 github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonschema v1.2.0 @@ -65,7 +58,6 @@ require ( google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 google.golang.org/grpc v1.29.1 gopkg.in/go-playground/webhooks.v5 v5.15.0 - gopkg.in/jcmturner/goidentity.v2 v2.0.0 // indirect gopkg.in/jcmturner/gokrb5.v5 v5.3.0 gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect gopkg.in/square/go-jose.v2 v2.4.1 diff --git a/go.sum b/go.sum index 6ffb3b18efff..a5739ccb6788 100644 --- a/go.sum +++ b/go.sum @@ -32,16 +32,36 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0 h1:UDpwYIwla4jHGzZJaEJYx1tOejbgSoNqsAfHAUYe2r8= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-amqp-common-go/v3 v3.0.0/go.mod h1:SY08giD/XbhTz07tJdpw1SoxQXHPN30+DI3Z04SYqyg= +github.com/Azure/azure-event-hubs-go/v3 v3.3.0/go.mod h1:LSZw8Q6j0iylRjGk4g9BPd+FzS35+Eff5gvs+t37iOM= +github.com/Azure/azure-pipeline-go v0.1.8/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg= +github.com/Azure/azure-pipeline-go v0.1.9/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg= +github.com/Azure/azure-sdk-for-go v37.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-storage-blob-go v0.6.0/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y= +github.com/Azure/go-amqp v0.12.6/go.mod h1:qApuH6OFTSKZFmCOxccvAv5rLizBQf4v8pRmG138DPo= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3 h1:OZEIaBbMdUE/Js+BQKlpO81XlISgipr6yDJ+PSwsgi4= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= github.com/Azure/go-autorest/autorest/adal v0.5.0 h1:q2gDruN08/guU9vAjuPWff0+QIrpH6ediguzdAzXAUU= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1 h1:pZdL8o72rK+avFWl+p9nE8RWi1JInZrWJYlnpfXJwHk= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= +github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw= github.com/Azure/go-autorest/autorest/date v0.1.0 h1:YGrhWfrgtFs84+h0o46rJrlmsZtyZRg470CqAXTZaGM= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0 h1:Ww5g4zThfD/6cLb4z6xxgeyDa7QDkizMkJKe0ysZXp0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k= @@ -50,8 +70,12 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.0.0 h1:0GoNN3taZV6QI81IXgCbxMyEaJDXMSIjArYBCYzVVvs= @@ -63,8 +87,11 @@ github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2 h1:JCHLVE3B+kJd github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/sarama v1.26.1/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668AuWys/yU= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/UnnoTed/fileb0x v1.1.4/go.mod h1:X59xXT18tdNk/D6j+KZySratBsuKJauMtVuJ9cgOiZs= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/ahmetb/gen-crd-api-reference-docs v0.2.0/go.mod h1:P/XzJ+c2+khJKNKABcm2biRwk2QAuwbLf8DlXuaL7WM= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= @@ -81,11 +108,18 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= -github.com/antonmedv/expr v1.8.2 h1:BfkVHGudYqq7jp3Ji33kTn+qZ9D19t/Mndg0ag/Ycq4= -github.com/antonmedv/expr v1.8.2/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmHhwGEk8= +github.com/antonmedv/expr v1.8.8 h1:uVwIkIBNO2yn4vY2u2DQUqXTmv9jEEMCEcHa19G5weY= +github.com/antonmedv/expr v1.8.8/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmHhwGEk8= +github.com/apache/openwhisk-client-go v0.0.0-20190915054138-716c6f973eb2/go.mod h1:jLLKYP7+1+LFlIJW1n9U1gqeveLM1HIwa4ZHNOFxjPw= +github.com/apache/pulsar-client-go v0.1.1/go.mod h1:mlxC65KL1BLhGO2bnT9zWMttVzR2czVPb27D477YpyU= +github.com/ardielle/ardielle-go v1.5.2/go.mod h1:I4hy1n795cUhaVt/ojz83SNVCYIGsAFAONtv2Dr7HUI= +github.com/ardielle/ardielle-tools v1.5.4/go.mod h1:oZN+JRMnqGiIhrzkRN9l26Cej9dEx4jeNG6A+AdkShk= +github.com/argoproj/argo-events v1.1.0 h1:iUstsg9ZA+s3iJ5WO153xiYPbl2CWAP6ZHa5OUyAoTo= +github.com/argoproj/argo-events v1.1.0/go.mod h1:0oAbDQMRVd/vKxwbHCyLovRhfZzNtYii5v6FUqGW9M4= github.com/argoproj/pkg v0.3.0 h1:0xxNHc9duXZt1TlDVVsBzcGm8S/V5Bc3eNqawz3wFo8= github.com/argoproj/pkg v0.3.0/go.mod h1:F4TZgInLUEjzsWFB/BTJBsewoEy0ucnKSq6vmQiD/yc= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= @@ -94,10 +128,12 @@ github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 h1:zV3ejI06 github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/awalterschulze/gographviz v0.0.0-20200901124122-0eecad45bd71 h1:m3N1Fv5vE5IcxuTOGFGGV0grrVFHV8UY2SV0wSBXAC8= github.com/awalterschulze/gographviz v0.0.0-20200901124122-0eecad45bd71/go.mod h1:/ynarkO/43wP/JM2Okn61e8WFMtdbtA8he7GJxW+SFM= +github.com/aws/aws-sdk-go v1.30.7/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.33.16 h1:h/3BL2BQMEbS67BPoEo/5jD8IPGVrKBmoa4S9mBBntw= github.com/aws/aws-sdk-go v1.33.16/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= +github.com/beefsack/go-rate v0.0.0-20180408011153-efa7637bb9b6/go.mod h1:6YNgTHLutezwnBvyneBbwvB8C82y3dcoOj5EQJIdGXA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -107,14 +143,22 @@ github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/blushft/go-diagrams v0.0.0-20201006005127-c78c821223d9 h1:mV+hh0rMjzrhg7Jc/GKwpa+y/0BMHGOHdM9yY1GYyFI= github.com/blushft/go-diagrams v0.0.0-20201006005127-c78c821223d9/go.mod h1:nDeXEIaeDV+mAK1gBD3/RJH67DYPC0GdaznWN7sB07s= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= +github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/boynton/repl v0.0.0-20170116235056-348863958e3e/go.mod h1:Crc/GCZ3NXDVCio7Yr0o+SSrytpcFhLmVCIzi0s49t4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudevents/sdk-go/v2 v2.1.0/go.mod h1:3CTrpB4+u7Iaj6fd7E2Xvm5IxMdRoaAhqaRVnOr2rCU= +github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/colinmarc/hdfs v1.1.4-0.20180802165501-48eb8d6c34a9/go.mod h1:0DumPviB681UcSuJErAbDIOx6SIaJWj463TymfZG02I= github.com/colinmarc/hdfs v1.1.4-0.20180805212432-9746310a4d31 h1:ow7T77012NSZVW0uOWoQxz3yj9fHKYeZ4QmNrMtWMbM= github.com/colinmarc/hdfs v1.1.4-0.20180805212432-9746310a4d31/go.mod h1:vSBumefK4HA5uiRSwNP+3ofgrEoScpCS2MMWcWXEuQ4= github.com/corbym/gocrest v1.0.3 h1:gwEdq6RkTmq+09CTuM29DfKOCtZ7G7bcyxs3IZ6EVdU= @@ -144,26 +188,37 @@ github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dimfeld/httptreemux v5.0.1+incompatible/go.mod h1:rbUlSV+CCpv/SuqUTP/8Bk2O3LyUV436/yaRGkhP6Z0= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 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/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s= github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/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= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e h1:p1yVGRW3nmb85p1Sh1ZJSDm4A4iKLS5QNbvUHMgGu/M= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.12.0+incompatible h1:SIvoTSbsMEwuM3dzFirLwKc4BH6VXP5CNf+G1FfJVr4= +github.com/emicklei/go-restful v2.12.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/emitter-io/go/v2 v2.0.9/go.mod h1:St++epE1u/6ueCVw47xhu4shpkGNxKRVtkWv4Xi33mg= 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= @@ -176,11 +231,15 @@ github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 h1:Dddq github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= @@ -192,6 +251,8 @@ github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebK github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew= +github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/gizak/termui/v3 v3.1.0/go.mod h1:bXQEBkJpzxUAKf0+xq9MSWAvWZlE7c+aidmyFlkYTrY= github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= @@ -205,6 +266,7 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= 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= @@ -288,6 +350,8 @@ github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7 github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-openapi/validate v0.19.7 h1:fR4tP2xc+25pdo5Qvv4v6g+5QKFgNg8nrifTE7V8ibA= github.com/go-openapi/validate v0.19.7/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-resty/resty/v2 v2.3.0/go.mod h1:UpN9CgLZNsv4e9XG50UU8xdI0F43UQ4HmxLBDwaroHU= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= @@ -296,6 +360,7 @@ github.com/go-swagger/go-swagger v0.23.0 h1:WrzNj+tp0pK8B5K5Sf4Rab0xvrIINiX0rrgq github.com/go-swagger/go-swagger v0.23.0/go.mod h1:5AaV4Dx69cUjpFRTZnSHPr1Y7dKBVk6SvfIvkTEqwJs= github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0= github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0= +github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= @@ -322,6 +387,7 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -369,11 +435,14 @@ github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-github/v31 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= 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= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -392,13 +461,21 @@ github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= +github.com/googleapis/gnostic v0.4.0 h1:BXDUo8p/DaxC+4FJY/SSx3gvnx9C1VdHNgaUkiEL5mk= +github.com/googleapis/gnostic v0.4.0/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gophercloud/gophercloud v0.7.0 h1:vhmQQEM2SbnGCg2/3EzQnQZ3V7+UCGy9s8exQCprNYg= github.com/gophercloud/gophercloud v0.7.0/go.mod h1:gmC5oQqMDOMO1t1gq5DquX/yAU808e/4mzjjDA76+Ss= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.0.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -412,26 +489,46 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xC github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.12.2 h1:D0EVSTwQoQOyfY35QNSuPJA4jpZRtkoGYWQMB7XNg5o= github.com/grpc-ecosystem/grpc-gateway v1.12.2/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-uuid v0.0.0-20180228145832-27454136f036 h1:d8T6WIONl4rMCPcQ/eY3uSz3+e4/GaoflKjXrWMex1U= github.com/hashicorp/go-uuid v0.0.0-20180228145832-27454136f036/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/raft v1.1.1/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8= +github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk= +github.com/hokaccha/go-prettyjson v0.0.0-20190818114111-108c894c2c0e/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/iancoleman/strcase v0.1.1/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= -github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imkira/go-interpol v1.0.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jawher/mow.cli v1.0.4/go.mod h1:5hQj2V8g+qYmLUVWqu4Wuja1pI57M83EChYLVZ0sMKk= +github.com/jawher/mow.cli v1.1.0/go.mod h1:aNaQlc7ozF3vw6IJ2dHjp2ZFiA4ozMIYY6PyuRJwlUg= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jcmturner/gofork v0.0.0-20180107083740-2aebee971930/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= @@ -444,15 +541,19 @@ github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeY github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/joncalhoun/qson v0.0.0-20200422171543-84433dcd3da0/go.mod h1:DFXrEwSRX0p/aSvxE21319menCBFeQO0jXpRj7LEZUA= +github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -468,8 +569,9 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.7 h1:hYW1gP94JUmAhBtJ+LNz5My+gBobDxPR1iVuKug26aA= -github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.10.8 h1:eLeJ3dr/Y9+XRfJT4l+8ZjmtB5RPJhucH2HeCV5+IZY= +github.com/klauspost/compress v1.10.8/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.3 h1:CCtW0xUnWGVINKvE/WWOYKdsPV6mawAtvQuSl8guwQs= github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= @@ -494,6 +596,7 @@ github.com/labstack/echo v3.2.1+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cV github.com/labstack/gommon v0.2.7/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4= github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac/go.mod h1:Frd2bnT3w5FB5q49ENTfVlztJES+1k/7lyWX2+9gq/M= github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -516,11 +619,16 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -531,10 +639,13 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4= github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= +github.com/minio/minio-go v1.0.1-0.20190523192347-c6c2912aa552 h1:czBFVgFWckvUt4DmJ9Jp40KA3qAawEaC2fi7WEF84K4= +github.com/minio/minio-go v1.0.1-0.20190523192347-c6c2912aa552/go.mod h1:/haSOWG8hQNx2+JOfLJ9GKp61EAmgPwRVw/Sac0NzaM= github.com/minio/minio-go/v7 v7.0.2 h1:P/7wFd4KrRBHVo7AKdcqO+9ReoS+XpMjfRFoE5quH0E= github.com/minio/minio-go/v7 v7.0.2/go.mod h1:dJ80Mv2HeGkYLH1sqS/ksz07ON6csH3S6JUMSQ2zAns= github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b h1:9+ke9YJ9KGWw5ANXK6ozjoK47uI3uNbXv4YVINBnGm8= @@ -543,6 +654,10 @@ github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZX github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.0 h1:iDwIio/3gk2QtLLEsqU5lInaMzos0hDTz8a6lazSFVw= +github.com/mitchellh/mapstructure v1.3.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= @@ -555,13 +670,30 @@ github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8m github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nats-io/gnatsd v1.4.1/go.mod h1:nqco77VO78hLCJpIcVfygDP2rPGfsEHkGTUk94uh5DQ= +github.com/nats-io/go-nats v1.7.2/go.mod h1:+t7RHT5ApZebkrQdnn6AhQJmhJJiKAvJUio1PiiCtj0= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.4/go.mod h1:Jw1Z28soD/QasIA2uWjXyM9El1jly3YwyFOuR8tH1rg= +github.com/nats-io/nats-streaming-server v0.17.0/go.mod h1:ewPBEsmp62Znl3dcRsYtlcfwudxHEdYMtYqUQSt4fE0= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.4/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nats-io/stan.go v0.6.0/go.mod h1:eIcD5bi3pqbHT/xIIvXMwvzXYElgouBvaVRftaE+eac= +github.com/nicksnyder/go-i18n v1.10.1-0.20190510212457-b280125b035a/go.mod h1:e4Di5xjP9oTVrC6y3C7C0HoSYXjSbhh/dU0eUV32nB4= +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-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= +github.com/nsqio/go-nsq v1.0.8/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= 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.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= @@ -570,6 +702,7 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34= github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/getopt v0.0.0-20180729010549-6fdd0a2c7117/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= @@ -577,7 +710,12 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= +github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4 v2.4.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4 v2.5.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -590,28 +728,40 @@ github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prY github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU= github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/radovskyb/watcher v1.0.7/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg= +github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rivo/tview v0.0.0-20200219210816-cd38d7432498/go.mod h1:6lkG1x+13OShEf0EaOCaTQYyB7d5nSbb181KtjlS+84= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= +github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= @@ -639,14 +789,20 @@ github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= +github.com/slack-go/slack v0.6.5/go.mod h1:FGqNzJBmxIsZURAxh2a8D21AnOVvvXZvGligs4npPUM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3 h1:hBSHahWMEgzwRyS6dRpxY0XyjZsHyQ61s084wo5PJe0= +github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= @@ -672,6 +828,7 @@ github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= +github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= @@ -686,18 +843,23 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stripe/stripe-go v70.15.0+incompatible/go.mod h1:A1dQZmO/QypXmsL0T8axYZkSN/uA/T/A64pfKdBAMiY= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tidwall/gjson v1.3.5 h1:2oW9FBNu8qt9jy5URgrzsVx/T/KSn3qn/smJQ0crlDQ= -github.com/tidwall/gjson v1.3.5/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc= +github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.0.1 h1:WE4RBSZ1x6McVVC8S/Md+Qse8YUv6HRObAx6ke00NY8= +github.com/tidwall/pretty v1.0.1/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/sjson v1.1.1/go.mod h1:yvVuSnpEQv5cYIrO+AT6kw4QVfd5SDZoGIS7/5+fZFs= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -708,12 +870,15 @@ github.com/valyala/fasthttp v1.0.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4/go.mod h1:50wTf68f99/Zt14pr046Tgt3Lp2vLyFZKzbFXTOabXw= github.com/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy1Ocw4= github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/gozstd v1.7.0/go.mod h1:y5Ew47GLlP37EkTB+B4s7r6A5rdaeB7ftbl9zoYiIPQ= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/xanzy/go-gitlab v0.33.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -724,6 +889,7 @@ 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/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yahoo/athenz v1.8.55/go.mod h1:G7LLFUH7Z/r4QAB7FfudfuA7Am/eCzO1GlzBhDL6Kv0= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= @@ -751,12 +917,17 @@ go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 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.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190128193316-c7b33c32a30b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -772,8 +943,13 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200206161412-a0c6ece9d31a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -824,7 +1000,9 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180921000356-2f5d2388922f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -851,9 +1029,11 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/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= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -877,6 +1057,7 @@ golang.org/x/sys v0.0.0-20181019160139-8e24a49d80f8/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -889,20 +1070,26 @@ golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -912,6 +1099,8 @@ golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d h1:62ap6LNOjDU6uGmKXHJbSfciM golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c= +golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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= @@ -930,6 +1119,7 @@ golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190213192042-740235f6c0d8/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -948,10 +1138,13 @@ golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -970,6 +1163,7 @@ golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200313205530-4303120df7d8/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200317043434-63da46f3035e/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200408132156-9ee5ef7a2c0d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200630154851-b2d8b0336632 h1:fxWeLV4ol1icb47+btwfzuf8gOkJE/PPo9bLjSvZzA8= golang.org/x/tools v0.0.0-20200630154851-b2d8b0336632/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -977,6 +1171,7 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbO golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485 h1:OB/uP/Puiu5vS5QMRPrXCDWUPb+kt8f1KW8oQzFejQw= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -995,6 +1190,7 @@ google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/ google.golang.org/api v0.20.0 h1:jz2KixHX7EcCPiQrySzPdnYT7DbINAypCqKZ1Z7GM40= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= @@ -1021,6 +1217,7 @@ google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200317114155-1f3552e48f24 h1:IGPykv426z7LZSVPlaPufOyphngM4at5uZ7x5alaFvE= google.golang.org/genproto v0.0.0-20200317114155-1f3552e48f24/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200408120641-fbb3ad325eb7/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1037,6 +1234,7 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -1052,9 +1250,12 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= 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-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 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= @@ -1063,9 +1264,11 @@ gopkg.in/go-playground/webhooks.v5 v5.15.0 h1:vnD8c5hN/w8qs0K3fQvIDAeYAHBnCclJHP gopkg.in/go-playground/webhooks.v5 v5.15.0/go.mod h1:LZbya/qLVdbqDR1aKrGuWV6qbia2zCYSR5dpom2SInQ= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.41.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.54.0 h1:oM5ElzbIi7gwLnNbPX2M25ED1vSAK3B6dex50eS/6Fs= gopkg.in/ini.v1 v1.54.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw= @@ -1074,10 +1277,13 @@ gopkg.in/jcmturner/dnsutils.v1 v1.0.1 h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= gopkg.in/jcmturner/goidentity.v2 v2.0.0 h1:6Bmcdaxb0dD3HyHbo/MtJ2Q1wXLDuZJFwXZmuZvM+zw= gopkg.in/jcmturner/goidentity.v2 v2.0.0/go.mod h1:vCwK9HeXksMeUmQ4SxDd1tRz4LejrKh3KRVjQWhjvZI= +gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= gopkg.in/jcmturner/gokrb5.v5 v5.3.0 h1:RS1MYApX27Hx1Xw7NECs7XxGxxrm69/4OmaRuX9kwec= gopkg.in/jcmturner/gokrb5.v5 v5.3.0/go.mod h1:oQz8Wc5GsctOTgCVyKad1Vw4TCWz5G6gfIQr88RPv4k= +gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= gopkg.in/jcmturner/rpc.v0 v0.0.2 h1:wBTgrbL1qmLBUPsYVCqdJiI5aJgQhexmK+JkTHPUNJI= gopkg.in/jcmturner/rpc.v0 v0.0.2/go.mod h1:NzMq6cRzR9lipgw7WxRBHNx5N8SifBuaCQsOT1kWY/E= +gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= @@ -1116,27 +1322,39 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.17.2/go.mod h1:BS9fjjLc4CMuqfSO8vgbHPKMt5+SF0ET6u/RVDihTo4= +k8s.io/api v0.17.5/go.mod h1:0zV5/ungglgy2Rlm3QK8fbxkXVs+BSJWpJP/+8gUVLY= k8s.io/api v0.17.8 h1:8JHlbqJ3A6sGhoacXfu/sASSD+HWWqVq67qt9lyB0kU= k8s.io/api v0.17.8/go.mod h1:N++Llhs8kCixMUoCaXXAyMMPbo8dDVnh+IQ36xZV2/0= k8s.io/apiextensions-apiserver v0.17.0 h1:+XgcGxqaMztkbbvsORgCmHIb4uImHKvTjNyu7b8gRnA= k8s.io/apiextensions-apiserver v0.17.0/go.mod h1:XiIFUakZywkUl54fVXa7QTEHcqQz9HG55nHd1DCoHj8= +k8s.io/apiextensions-apiserver v0.17.2 h1:cP579D2hSZNuO/rZj9XFRzwJNYb41DbNANJb6Kolpss= +k8s.io/apiextensions-apiserver v0.17.2/go.mod h1:4KdMpjkEjjDI2pPfBA15OscyNldHWdBCfsWMDWAmSTs= k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.17.2/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.17.5/go.mod h1:ioIo1G/a+uONV7Tv+ZmCbMG1/a3kVw5YcDdncd8ugQ0= k8s.io/apimachinery v0.17.8 h1:zXvd8rYMAjRJXpILP9tdAiUnFIENM9EmHuE81apIoms= k8s.io/apimachinery v0.17.8/go.mod h1:Lg8zZ5iC/O8UjCqW6DNhcQG2m4TdjF9kwG3891OWbbA= k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/apiserver v0.17.2/go.mod h1:lBmw/TtQdtxvrTk0e2cgtOxHizXI+d0mmGQURIHQZlo= k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.17.2/go.mod h1:QAzRgsa0C2xl4/eVpeVAZMvikCn8Nm81yqVx3Kk9XYI= +k8s.io/client-go v0.17.5/go.mod h1:S8uZpBpjJJdEH/fEyxcqg7Rn0P5jH+ilkgBHjriSmNo= k8s.io/client-go v0.17.8 h1:cuZSfjqVrNjoZ3wViQHljFPyWMOcgxUjjmQs5Rifbxk= k8s.io/client-go v0.17.8/go.mod h1:SJsDS64AAtt9VZyeaQMb4Ck5etCitZ/FwajWdzua5eY= k8s.io/code-generator v0.17.0 h1:y+KWtDWNqlJzJu/kUy8goJZO0X71PGIpAHLX8a0JYk0= k8s.io/code-generator v0.17.0/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/code-generator v0.17.2/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= k8s.io/code-generator v0.17.5 h1:JKh5hYOFb0cTls9mce3ZC4DWh01/nLEgqj8OSJBpVRw= k8s.io/code-generator v0.17.5/go.mod h1:qdiSCSTKtS+3WtPelj2h57fylSQcPUlhMVm+TD9Dvqc= k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/component-base v0.17.2/go.mod h1:zMPW3g5aH7cHJpKYQ/ZsGMcgbsA/VyhEugF3QT1awLs= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6 h1:4s3/R4+OYYYUKptXPhZKjQ04WJ6EhQQVFdjOFvCazDk= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190822140433-26a664648505 h1:ZY6yclUKVbZ+SdWnkfY+Je5vrMpKOxmGeKRbsXVmqYM= k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.2.0/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= @@ -1158,6 +1376,7 @@ moul.io/http2curl v1.0.1-0.20190925090545-5cd742060b0e/go.mod h1:nejbQVfXh96n9dS rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/controller-runtime v0.5.4/go.mod h1:JZUwSMVbxDupo0lTJSSFP5pimEyxGynROImSsqIOx1A= sigs.k8s.io/controller-tools v0.2.9 h1:DEZuCFWANX2zlZVMlf/XmhSq0HzmGCZ/GTdPJig62ig= sigs.k8s.io/controller-tools v0.2.9/go.mod h1:ArP7w60JQKkZf7UU2oWTVnEhoNGA+sOMyuSuS+JFNDQ= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= diff --git a/manifests/cluster-install/argo-server-rbac/argo-server-clusterole.yaml b/manifests/cluster-install/argo-server-rbac/argo-server-clusterole.yaml index 37fcf1128a24..f954115b005c 100644 --- a/manifests/cluster-install/argo-server-rbac/argo-server-clusterole.yaml +++ b/manifests/cluster-install/argo-server-rbac/argo-server-clusterole.yaml @@ -47,6 +47,8 @@ rules: - apiGroups: - argoproj.io resources: + - eventsources + - sensors - workflows - workfloweventbindings - workflowtemplates diff --git a/manifests/install.yaml b/manifests/install.yaml index d4dd9e72c1c1..ccfd4bc39108 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -369,6 +369,8 @@ rules: - apiGroups: - argoproj.io resources: + - eventsources + - sensors - workflows - workfloweventbindings - workflowtemplates diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 900bfb52b5bf..c74c6b9b0780 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -276,6 +276,8 @@ rules: - apiGroups: - argoproj.io resources: + - eventsources + - sensors - workflows - workfloweventbindings - workflowtemplates diff --git a/manifests/namespace-install/argo-server-rbac/argo-server-role.yaml b/manifests/namespace-install/argo-server-rbac/argo-server-role.yaml index a23fa8a92085..546be634146b 100644 --- a/manifests/namespace-install/argo-server-rbac/argo-server-role.yaml +++ b/manifests/namespace-install/argo-server-rbac/argo-server-role.yaml @@ -47,6 +47,8 @@ rules: - apiGroups: - argoproj.io resources: + - eventsources + - sensors - workflows - workfloweventbindings - workflowtemplates diff --git a/manifests/quick-start-minimal.yaml b/manifests/quick-start-minimal.yaml index 1a9454a8d3f1..4479b320cedf 100644 --- a/manifests/quick-start-minimal.yaml +++ b/manifests/quick-start-minimal.yaml @@ -281,6 +281,8 @@ rules: - apiGroups: - argoproj.io resources: + - eventsources + - sensors - workflows - workfloweventbindings - workflowtemplates @@ -509,6 +511,9 @@ data: - name: Example Pod Link scope: pod url: http://logging-facility?namespace=${metadata.namespace}&podName=${metadata.name}&startedAt=${status.startedAt}&finishedAt=${status.finishedAt} + - name: Get help + scope: chat + url: https://argoproj.github.io/argo/ metricsConfig: | disableLegacy: true enabled: true diff --git a/manifests/quick-start-mysql.yaml b/manifests/quick-start-mysql.yaml index 85490527d737..0d922c998c5d 100644 --- a/manifests/quick-start-mysql.yaml +++ b/manifests/quick-start-mysql.yaml @@ -281,6 +281,8 @@ rules: - apiGroups: - argoproj.io resources: + - eventsources + - sensors - workflows - workfloweventbindings - workflowtemplates @@ -509,6 +511,9 @@ data: - name: Example Pod Link scope: pod url: http://logging-facility?namespace=${metadata.namespace}&podName=${metadata.name}&startedAt=${status.startedAt}&finishedAt=${status.finishedAt} + - name: Get help + scope: chat + url: https://argoproj.github.io/argo/ metricsConfig: | disableLegacy: true enabled: true diff --git a/manifests/quick-start-postgres.yaml b/manifests/quick-start-postgres.yaml index 23e2dfdf7f5c..4a6c4f339b00 100644 --- a/manifests/quick-start-postgres.yaml +++ b/manifests/quick-start-postgres.yaml @@ -281,6 +281,8 @@ rules: - apiGroups: - argoproj.io resources: + - eventsources + - sensors - workflows - workfloweventbindings - workflowtemplates @@ -509,6 +511,9 @@ data: - name: Example Pod Link scope: pod url: http://logging-facility?namespace=${metadata.namespace}&podName=${metadata.name}&startedAt=${status.startedAt}&finishedAt=${status.finishedAt} + - name: Get help + scope: chat + url: https://argoproj.github.io/argo/ metricsConfig: | disableLegacy: true enabled: true diff --git a/manifests/quick-start/base/overlays/workflow-controller-configmap.yaml b/manifests/quick-start/base/overlays/workflow-controller-configmap.yaml index 4a118d21dc98..4e5c289c88f9 100644 --- a/manifests/quick-start/base/overlays/workflow-controller-configmap.yaml +++ b/manifests/quick-start/base/overlays/workflow-controller-configmap.yaml @@ -24,6 +24,9 @@ data: - name: Example Pod Link scope: pod url: http://logging-facility?namespace=${metadata.namespace}&podName=${metadata.name}&startedAt=${status.startedAt}&finishedAt=${status.finishedAt} + - name: Get help + scope: chat + url: https://argoproj.github.io/argo/ kind: ConfigMap metadata: name: workflow-controller-configmap diff --git a/pkg/apiclient/argo-kube-client.go b/pkg/apiclient/argo-kube-client.go index db17109493b5..f76ec45d6625 100644 --- a/pkg/apiclient/argo-kube-client.go +++ b/pkg/apiclient/argo-kube-client.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + eventsource "github.com/argoproj/argo-events/pkg/client/eventsource/clientset/versioned" + sensor "github.com/argoproj/argo-events/pkg/client/sensor/clientset/versioned" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" @@ -14,10 +16,11 @@ import ( workflowpkg "github.com/argoproj/argo/pkg/apiclient/workflow" workflowarchivepkg "github.com/argoproj/argo/pkg/apiclient/workflowarchive" "github.com/argoproj/argo/pkg/apiclient/workflowtemplate" - "github.com/argoproj/argo/pkg/client/clientset/versioned" + workflow "github.com/argoproj/argo/pkg/client/clientset/versioned" "github.com/argoproj/argo/server/auth" clusterworkflowtmplserver "github.com/argoproj/argo/server/clusterworkflowtemplate" cronworkflowserver "github.com/argoproj/argo/server/cronworkflow" + "github.com/argoproj/argo/server/types" workflowserver "github.com/argoproj/argo/server/workflow" workflowtemplateserver "github.com/argoproj/argo/server/workflowtemplate" "github.com/argoproj/argo/util/help" @@ -36,7 +39,15 @@ func newArgoKubeClient(clientConfig clientcmd.ClientConfig, instanceIDService in if err != nil { return nil, nil, err } - wfClient, err := versioned.NewForConfig(restConfig) + wfClient, err := workflow.NewForConfig(restConfig) + if err != nil { + return nil, nil, err + } + eventSourceInterface, err := eventsource.NewForConfig(restConfig) + if err != nil { + return nil, nil, err + } + sensorInterface, err := sensor.NewForConfig(restConfig) if err != nil { return nil, nil, err } @@ -44,7 +55,8 @@ func newArgoKubeClient(clientConfig clientcmd.ClientConfig, instanceIDService in if err != nil { return nil, nil, err } - gatekeeper, err := auth.NewGatekeeper(auth.Modes{auth.Server: true}, wfClient, kubeClient, restConfig, nil, auth.DefaultClientForAuthorization, "unused") + clients := &types.Clients{Workflow: wfClient, EventSource: eventSourceInterface, Sensor: sensorInterface, Kubernetes: kubeClient} + gatekeeper, err := auth.NewGatekeeper(auth.Modes{auth.Server: true}, clients, restConfig, nil, auth.DefaultClientForAuthorization, "unused") if err != nil { return nil, nil, err } diff --git a/pkg/apiclient/event/event.pb.go b/pkg/apiclient/event/event.pb.go index 2f29528980fe..ddaf824cb523 100644 --- a/pkg/apiclient/event/event.pb.go +++ b/pkg/apiclient/event/event.pb.go @@ -13,6 +13,7 @@ import ( codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" io "io" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" math "math" math_bits "math/bits" ) @@ -138,37 +139,101 @@ func (m *EventResponse) XXX_DiscardUnknown() { var xxx_messageInfo_EventResponse proto.InternalMessageInfo +type ListWorkflowEventBindingsRequest struct { + Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` + ListOptions *v1.ListOptions `protobuf:"bytes,2,opt,name=listOptions,proto3" json:"listOptions,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListWorkflowEventBindingsRequest) Reset() { *m = ListWorkflowEventBindingsRequest{} } +func (m *ListWorkflowEventBindingsRequest) String() string { return proto.CompactTextString(m) } +func (*ListWorkflowEventBindingsRequest) ProtoMessage() {} +func (*ListWorkflowEventBindingsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_d80a0d2509a47d1c, []int{2} +} +func (m *ListWorkflowEventBindingsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListWorkflowEventBindingsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListWorkflowEventBindingsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListWorkflowEventBindingsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListWorkflowEventBindingsRequest.Merge(m, src) +} +func (m *ListWorkflowEventBindingsRequest) XXX_Size() int { + return m.Size() +} +func (m *ListWorkflowEventBindingsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListWorkflowEventBindingsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ListWorkflowEventBindingsRequest proto.InternalMessageInfo + +func (m *ListWorkflowEventBindingsRequest) GetNamespace() string { + if m != nil { + return m.Namespace + } + return "" +} + +func (m *ListWorkflowEventBindingsRequest) GetListOptions() *v1.ListOptions { + if m != nil { + return m.ListOptions + } + return nil +} + func init() { proto.RegisterType((*EventRequest)(nil), "event.EventRequest") proto.RegisterType((*EventResponse)(nil), "event.EventResponse") + proto.RegisterType((*ListWorkflowEventBindingsRequest)(nil), "event.ListWorkflowEventBindingsRequest") } func init() { proto.RegisterFile("pkg/apiclient/event/event.proto", fileDescriptor_d80a0d2509a47d1c) } var fileDescriptor_d80a0d2509a47d1c = []byte{ - // 347 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x91, 0xbf, 0x4a, 0x2b, 0x41, - 0x14, 0xc6, 0xd9, 0x5c, 0xee, 0xbd, 0x64, 0x4d, 0x10, 0x56, 0x8b, 0x10, 0x42, 0x0c, 0x8b, 0x45, - 0x10, 0x99, 0x21, 0x11, 0x0b, 0x63, 0xa7, 0x58, 0xd8, 0x6e, 0x3a, 0xbb, 0xc9, 0xe6, 0x38, 0x19, - 0xb3, 0x3b, 0x67, 0x9c, 0x99, 0x6c, 0x90, 0x90, 0xc6, 0xc2, 0x17, 0xf0, 0x21, 0x7c, 0x15, 0x4b, - 0xc1, 0x17, 0x90, 0xe0, 0x83, 0x48, 0x66, 0xb3, 0xf9, 0x53, 0xd9, 0x2c, 0x67, 0x3f, 0x0e, 0xdf, - 0xfc, 0xbe, 0xf3, 0xf9, 0x47, 0x6a, 0xcc, 0x29, 0x53, 0x22, 0x4e, 0x04, 0x48, 0x4b, 0x21, 0x5b, - 0x7f, 0x89, 0xd2, 0x68, 0x31, 0xf8, 0xeb, 0x7e, 0xea, 0x0d, 0x8e, 0xc8, 0x13, 0x58, 0xae, 0x52, - 0x26, 0x25, 0x5a, 0x66, 0x05, 0x4a, 0x93, 0x2f, 0xd5, 0xaf, 0xb9, 0xb0, 0xa3, 0xc9, 0x80, 0xc4, - 0x98, 0x52, 0xa6, 0x39, 0x2a, 0x8d, 0x0f, 0x6e, 0xa0, 0x2b, 0x7b, 0x43, 0xa7, 0xa8, 0xc7, 0xf7, - 0x09, 0x4e, 0x69, 0xd6, 0x61, 0x89, 0x1a, 0xb1, 0x0e, 0xe5, 0x20, 0x41, 0x33, 0x0b, 0xc3, 0xdc, - 0x24, 0x7c, 0xf3, 0xfc, 0xca, 0xcd, 0xf2, 0xb1, 0x08, 0x1e, 0x27, 0x60, 0x6c, 0xd0, 0xf0, 0xcb, - 0x92, 0xa5, 0x60, 0x14, 0x8b, 0xa1, 0xe6, 0xb5, 0xbc, 0x76, 0x39, 0xda, 0x08, 0xc1, 0xb1, 0x5f, - 0x1d, 0x0a, 0x13, 0x6b, 0x91, 0x0a, 0xc9, 0x2c, 0xea, 0x5a, 0xc9, 0x6d, 0xec, 0x8a, 0x41, 0xdf, - 0xff, 0xaf, 0xd8, 0x53, 0x82, 0x6c, 0x58, 0xfb, 0xd3, 0xf2, 0xda, 0x7b, 0xdd, 0x0b, 0xb2, 0x61, - 0x25, 0x05, 0xab, 0x1b, 0x88, 0x1a, 0x73, 0xb2, 0x64, 0x25, 0x05, 0x2b, 0x29, 0x58, 0xc9, 0xad, - 0x85, 0x34, 0x2a, 0x9c, 0xc2, 0x7d, 0xbf, 0xba, 0x02, 0x35, 0x0a, 0xa5, 0x81, 0xee, 0x4b, 0x81, - 0xde, 0x07, 0x9d, 0x89, 0x18, 0x82, 0xcc, 0xaf, 0x44, 0x10, 0x83, 0xc8, 0xc0, 0xc9, 0xc1, 0x01, - 0xc9, 0x6f, 0xba, 0x9d, 0xaf, 0x7e, 0xb8, 0x2b, 0xe6, 0x5e, 0xe1, 0xe5, 0xf3, 0xe7, 0xf7, 0x6b, - 0xe9, 0x3c, 0x3c, 0x71, 0xb7, 0xce, 0x3a, 0x79, 0x1b, 0x86, 0xce, 0xd6, 0xd1, 0xe7, 0x74, 0xb6, - 0x13, 0x72, 0xde, 0x2b, 0xc8, 0xae, 0x7a, 0xef, 0x8b, 0xa6, 0xf7, 0xb1, 0x68, 0x7a, 0x5f, 0x8b, - 0xa6, 0x77, 0x77, 0xfa, 0x5b, 0x2d, 0xdb, 0xad, 0x0f, 0xfe, 0xb9, 0x1a, 0xce, 0x7e, 0x02, 0x00, - 0x00, 0xff, 0xff, 0xab, 0x58, 0x8b, 0x7b, 0x13, 0x02, 0x00, 0x00, + // 471 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0xdd, 0x8a, 0x13, 0x31, + 0x14, 0x26, 0x15, 0x95, 0x4d, 0x77, 0x11, 0xa2, 0x17, 0xb5, 0x2c, 0xb5, 0x0c, 0x82, 0x8b, 0xda, + 0x84, 0xe9, 0x2a, 0xe8, 0x7a, 0xb7, 0xe2, 0x85, 0xb0, 0x22, 0x4c, 0x2f, 0x04, 0xef, 0xd2, 0xe9, + 0x71, 0x1a, 0x3b, 0x93, 0xc4, 0x24, 0x3b, 0xcb, 0xb2, 0xec, 0x8d, 0xaf, 0x20, 0x3e, 0x83, 0xaf, + 0xb2, 0x97, 0x8a, 0x2f, 0x20, 0xc5, 0x07, 0x91, 0x49, 0x33, 0x3b, 0x53, 0x54, 0x2a, 0xde, 0x0c, + 0x99, 0x93, 0xf3, 0xf3, 0x7d, 0xdf, 0xf9, 0x82, 0xef, 0xe8, 0x45, 0xc6, 0xb8, 0x16, 0x69, 0x2e, + 0x40, 0x3a, 0x06, 0xe5, 0xe5, 0x97, 0x6a, 0xa3, 0x9c, 0x22, 0x57, 0xfd, 0x4f, 0x7f, 0x37, 0x53, + 0x2a, 0xcb, 0xa1, 0x4a, 0x65, 0x5c, 0x4a, 0xe5, 0xb8, 0x13, 0x4a, 0xda, 0x55, 0x52, 0xff, 0xd1, + 0xe2, 0x89, 0xa5, 0x42, 0x55, 0xb7, 0x05, 0x4f, 0xe7, 0x42, 0x82, 0x39, 0x65, 0xa1, 0xb3, 0x65, + 0x05, 0x38, 0xce, 0xca, 0x98, 0x65, 0x20, 0xc1, 0x70, 0x07, 0xb3, 0x50, 0xf5, 0x3c, 0x13, 0x6e, + 0x7e, 0x3c, 0xa5, 0xa9, 0x2a, 0x18, 0x37, 0x99, 0xd2, 0x46, 0xbd, 0xf7, 0x87, 0xa6, 0xf4, 0x44, + 0x99, 0xc5, 0xbb, 0x5c, 0x9d, 0xb0, 0x32, 0xe6, 0xb9, 0x9e, 0xf3, 0xdf, 0x9a, 0x44, 0x5f, 0x10, + 0xde, 0x7e, 0x51, 0x41, 0x4c, 0xe0, 0xc3, 0x31, 0x58, 0x47, 0x76, 0xf1, 0x96, 0xe4, 0x05, 0x58, + 0xcd, 0x53, 0xe8, 0xa1, 0x21, 0xda, 0xdb, 0x4a, 0x9a, 0x00, 0xb9, 0x8b, 0x77, 0x66, 0xc2, 0xa6, + 0x46, 0x14, 0x42, 0x72, 0xa7, 0x4c, 0xaf, 0xe3, 0x33, 0xd6, 0x83, 0x64, 0x82, 0xaf, 0x6b, 0x7e, + 0x9a, 0x2b, 0x3e, 0xeb, 0x5d, 0x19, 0xa2, 0xbd, 0xee, 0xf8, 0x29, 0x6d, 0xb0, 0xd2, 0x1a, 0xab, + 0x3f, 0x50, 0xbd, 0xc8, 0x68, 0x85, 0x95, 0xd6, 0x58, 0x69, 0x8d, 0x95, 0xbe, 0x74, 0x50, 0x24, + 0x75, 0xa7, 0xe8, 0x06, 0xde, 0x09, 0x40, 0xad, 0x56, 0xd2, 0x42, 0xf4, 0x19, 0xe1, 0xe1, 0x91, + 0xb0, 0xee, 0x4d, 0x28, 0xf4, 0xb7, 0x87, 0x42, 0xce, 0x84, 0xcc, 0xec, 0xbf, 0xd1, 0x99, 0xe0, + 0x6e, 0x2e, 0xac, 0x7b, 0xad, 0xfd, 0x36, 0x3c, 0x99, 0xee, 0x38, 0xa6, 0xab, 0x75, 0xd0, 0xf6, + 0x3a, 0x1a, 0x9c, 0xd5, 0x3a, 0x68, 0x19, 0xd3, 0xa3, 0xa6, 0x30, 0x69, 0x77, 0x19, 0x7f, 0xeb, + 0x04, 0x49, 0x27, 0x60, 0x4a, 0x91, 0x02, 0x29, 0xf1, 0x76, 0x02, 0x29, 0x88, 0x12, 0x7c, 0x98, + 0xdc, 0xa4, 0x2b, 0x87, 0xb4, 0x75, 0xef, 0xdf, 0x5a, 0x0f, 0x06, 0x8e, 0xcf, 0x3e, 0x7e, 0xff, + 0xf9, 0xa9, 0xf3, 0x38, 0xba, 0xef, 0x9d, 0x53, 0xc6, 0x2b, 0x6f, 0x59, 0x76, 0x76, 0xc9, 0xe1, + 0x9c, 0x9d, 0xad, 0x89, 0x7f, 0x7e, 0x50, 0x2b, 0x46, 0x2e, 0x10, 0xbe, 0xfd, 0x57, 0x81, 0xc8, + 0xbd, 0x30, 0x70, 0x93, 0x84, 0xfd, 0x57, 0xff, 0xb5, 0xbc, 0x3f, 0xb5, 0xac, 0x46, 0x45, 0xfb, + 0x9e, 0xd2, 0x88, 0x3c, 0xa8, 0x29, 0xd5, 0xb5, 0x23, 0x8f, 0x67, 0x34, 0x0d, 0xe3, 0xdb, 0x1c, + 0x0f, 0x0f, 0x2e, 0x96, 0x03, 0xf4, 0x75, 0x39, 0x40, 0x3f, 0x96, 0x03, 0xf4, 0xf6, 0xe1, 0x26, + 0xe7, 0xb7, 0x9f, 0xe3, 0xf4, 0x9a, 0x77, 0xfa, 0xfe, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3b, + 0xfb, 0x21, 0x80, 0xac, 0x03, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -184,6 +249,7 @@ const _ = grpc.SupportPackageIsVersion4 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type EventServiceClient interface { ReceiveEvent(ctx context.Context, in *EventRequest, opts ...grpc.CallOption) (*EventResponse, error) + ListWorkflowEventBindings(ctx context.Context, in *ListWorkflowEventBindingsRequest, opts ...grpc.CallOption) (*v1alpha1.WorkflowEventBindingList, error) } type eventServiceClient struct { @@ -203,9 +269,19 @@ func (c *eventServiceClient) ReceiveEvent(ctx context.Context, in *EventRequest, return out, nil } +func (c *eventServiceClient) ListWorkflowEventBindings(ctx context.Context, in *ListWorkflowEventBindingsRequest, opts ...grpc.CallOption) (*v1alpha1.WorkflowEventBindingList, error) { + out := new(v1alpha1.WorkflowEventBindingList) + err := c.cc.Invoke(ctx, "/event.EventService/ListWorkflowEventBindings", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // EventServiceServer is the server API for EventService service. type EventServiceServer interface { ReceiveEvent(context.Context, *EventRequest) (*EventResponse, error) + ListWorkflowEventBindings(context.Context, *ListWorkflowEventBindingsRequest) (*v1alpha1.WorkflowEventBindingList, error) } // UnimplementedEventServiceServer can be embedded to have forward compatible implementations. @@ -215,6 +291,9 @@ type UnimplementedEventServiceServer struct { func (*UnimplementedEventServiceServer) ReceiveEvent(ctx context.Context, req *EventRequest) (*EventResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ReceiveEvent not implemented") } +func (*UnimplementedEventServiceServer) ListWorkflowEventBindings(ctx context.Context, req *ListWorkflowEventBindingsRequest) (*v1alpha1.WorkflowEventBindingList, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListWorkflowEventBindings not implemented") +} func RegisterEventServiceServer(s *grpc.Server, srv EventServiceServer) { s.RegisterService(&_EventService_serviceDesc, srv) @@ -238,6 +317,24 @@ func _EventService_ReceiveEvent_Handler(srv interface{}, ctx context.Context, de return interceptor(ctx, in, info, handler) } +func _EventService_ListWorkflowEventBindings_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListWorkflowEventBindingsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EventServiceServer).ListWorkflowEventBindings(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/event.EventService/ListWorkflowEventBindings", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EventServiceServer).ListWorkflowEventBindings(ctx, req.(*ListWorkflowEventBindingsRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _EventService_serviceDesc = grpc.ServiceDesc{ ServiceName: "event.EventService", HandlerType: (*EventServiceServer)(nil), @@ -246,6 +343,10 @@ var _EventService_serviceDesc = grpc.ServiceDesc{ MethodName: "ReceiveEvent", Handler: _EventService_ReceiveEvent_Handler, }, + { + MethodName: "ListWorkflowEventBindings", + Handler: _EventService_ListWorkflowEventBindings_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "pkg/apiclient/event/event.proto", @@ -331,6 +432,52 @@ func (m *EventResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ListWorkflowEventBindingsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListWorkflowEventBindingsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListWorkflowEventBindingsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.ListOptions != nil { + { + size, err := m.ListOptions.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvent(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Namespace) > 0 { + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintEvent(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintEvent(dAtA []byte, offset int, v uint64) int { offset -= sovEvent(v) base := offset @@ -378,6 +525,26 @@ func (m *EventResponse) Size() (n int) { return n } +func (m *ListWorkflowEventBindingsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Namespace) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + if m.ListOptions != nil { + l = m.ListOptions.Size() + n += 1 + l + sovEvent(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func sovEvent(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -592,6 +759,128 @@ func (m *EventResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *ListWorkflowEventBindingsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ListWorkflowEventBindingsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ListWorkflowEventBindingsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Namespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ListOptions", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ListOptions == nil { + m.ListOptions = &v1.ListOptions{} + } + if err := m.ListOptions.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvent(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthEvent + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthEvent + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipEvent(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/pkg/apiclient/event/event.pb.gw.go b/pkg/apiclient/event/event.pb.gw.go index 84975bb21578..a5e6f272c2db 100644 --- a/pkg/apiclient/event/event.pb.gw.go +++ b/pkg/apiclient/event/event.pb.gw.go @@ -123,6 +123,75 @@ func local_request_EventService_ReceiveEvent_0(ctx context.Context, marshaler ru } +var ( + filter_EventService_ListWorkflowEventBindings_0 = &utilities.DoubleArray{Encoding: map[string]int{"namespace": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_EventService_ListWorkflowEventBindings_0(ctx context.Context, marshaler runtime.Marshaler, client EventServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ListWorkflowEventBindingsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["namespace"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") + } + + protoReq.Namespace, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EventService_ListWorkflowEventBindings_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ListWorkflowEventBindings(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_EventService_ListWorkflowEventBindings_0(ctx context.Context, marshaler runtime.Marshaler, server EventServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ListWorkflowEventBindingsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["namespace"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") + } + + protoReq.Namespace, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) + } + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_EventService_ListWorkflowEventBindings_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.ListWorkflowEventBindings(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterEventServiceHandlerServer registers the http handlers for service EventService to "mux". // UnaryRPC :call EventServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -148,6 +217,26 @@ func RegisterEventServiceHandlerServer(ctx context.Context, mux *runtime.ServeMu }) + mux.Handle("GET", pattern_EventService_ListWorkflowEventBindings_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_EventService_ListWorkflowEventBindings_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EventService_ListWorkflowEventBindings_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -209,13 +298,37 @@ func RegisterEventServiceHandlerClient(ctx context.Context, mux *runtime.ServeMu }) + mux.Handle("GET", pattern_EventService_ListWorkflowEventBindings_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_EventService_ListWorkflowEventBindings_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EventService_ListWorkflowEventBindings_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } var ( pattern_EventService_ReceiveEvent_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4}, []string{"api", "v1", "events", "namespace", "discriminator"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_EventService_ListWorkflowEventBindings_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "workflow-event-bindings", "namespace"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( forward_EventService_ReceiveEvent_0 = runtime.ForwardResponseMessage + + forward_EventService_ListWorkflowEventBindings_0 = runtime.ForwardResponseMessage ) diff --git a/pkg/apiclient/event/event.proto b/pkg/apiclient/event/event.proto index ef229bbc3c6c..8ff4eb6efd80 100644 --- a/pkg/apiclient/event/event.proto +++ b/pkg/apiclient/event/event.proto @@ -2,6 +2,7 @@ syntax = "proto3"; option go_package = "github.com/argoproj/argo/pkg/apiclient/event"; import "google/api/annotations.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; import "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1/generated.proto"; package event; @@ -23,6 +24,11 @@ message EventRequest { message EventResponse { } +message ListWorkflowEventBindingsRequest { + string namespace = 1; + k8s.io.apimachinery.pkg.apis.meta.v1.ListOptions listOptions = 2; +} + service EventService { rpc ReceiveEvent (EventRequest) returns (EventResponse) { option (google.api.http) = { @@ -30,4 +36,7 @@ service EventService { body: "payload" }; } + rpc ListWorkflowEventBindings (ListWorkflowEventBindingsRequest) returns (github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.WorkflowEventBindingList) { + option (google.api.http).get = "/api/v1/workflow-event-bindings/{namespace}"; + } } \ No newline at end of file diff --git a/pkg/apiclient/eventsource/eventsource.pb.go b/pkg/apiclient/eventsource/eventsource.pb.go new file mode 100644 index 000000000000..4d065e5c4841 --- /dev/null +++ b/pkg/apiclient/eventsource/eventsource.pb.go @@ -0,0 +1,1833 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: pkg/apiclient/eventsource/eventsource.proto + +package eventsource + +import ( + context "context" + fmt "fmt" + v1alpha1 "github.com/argoproj/argo-events/pkg/apis/eventsource/v1alpha1" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + v11 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type ListEventSourcesRequest struct { + Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` + ListOptions *v1.ListOptions `protobuf:"bytes,2,opt,name=listOptions,proto3" json:"listOptions,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListEventSourcesRequest) Reset() { *m = ListEventSourcesRequest{} } +func (m *ListEventSourcesRequest) String() string { return proto.CompactTextString(m) } +func (*ListEventSourcesRequest) ProtoMessage() {} +func (*ListEventSourcesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b13fbf03f636aa35, []int{0} +} +func (m *ListEventSourcesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListEventSourcesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListEventSourcesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListEventSourcesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListEventSourcesRequest.Merge(m, src) +} +func (m *ListEventSourcesRequest) XXX_Size() int { + return m.Size() +} +func (m *ListEventSourcesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListEventSourcesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ListEventSourcesRequest proto.InternalMessageInfo + +func (m *ListEventSourcesRequest) GetNamespace() string { + if m != nil { + return m.Namespace + } + return "" +} + +func (m *ListEventSourcesRequest) GetListOptions() *v1.ListOptions { + if m != nil { + return m.ListOptions + } + return nil +} + +type EventSourcesLogsRequest struct { + Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` + // optional - only return entries for this event source + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // optional - only return entries for this event source type (e.g. `webhook`) + EventSourceType string `protobuf:"bytes,3,opt,name=eventSourceType,proto3" json:"eventSourceType,omitempty"` + // optional - only return entries for this event name (e.g. `example`) + EventName string `protobuf:"bytes,4,opt,name=eventName,proto3" json:"eventName,omitempty"` + // optional - only return entries where `msg` matches this regular expression + Grep string `protobuf:"bytes,5,opt,name=grep,proto3" json:"grep,omitempty"` + PodLogOptions *v11.PodLogOptions `protobuf:"bytes,6,opt,name=podLogOptions,proto3" json:"podLogOptions,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EventSourcesLogsRequest) Reset() { *m = EventSourcesLogsRequest{} } +func (m *EventSourcesLogsRequest) String() string { return proto.CompactTextString(m) } +func (*EventSourcesLogsRequest) ProtoMessage() {} +func (*EventSourcesLogsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b13fbf03f636aa35, []int{1} +} +func (m *EventSourcesLogsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventSourcesLogsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventSourcesLogsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *EventSourcesLogsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventSourcesLogsRequest.Merge(m, src) +} +func (m *EventSourcesLogsRequest) XXX_Size() int { + return m.Size() +} +func (m *EventSourcesLogsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_EventSourcesLogsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_EventSourcesLogsRequest proto.InternalMessageInfo + +func (m *EventSourcesLogsRequest) GetNamespace() string { + if m != nil { + return m.Namespace + } + return "" +} + +func (m *EventSourcesLogsRequest) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *EventSourcesLogsRequest) GetEventSourceType() string { + if m != nil { + return m.EventSourceType + } + return "" +} + +func (m *EventSourcesLogsRequest) GetEventName() string { + if m != nil { + return m.EventName + } + return "" +} + +func (m *EventSourcesLogsRequest) GetGrep() string { + if m != nil { + return m.Grep + } + return "" +} + +func (m *EventSourcesLogsRequest) GetPodLogOptions() *v11.PodLogOptions { + if m != nil { + return m.PodLogOptions + } + return nil +} + +// structured log entry +type LogEntry struct { + Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` + EventSourceName string `protobuf:"bytes,2,opt,name=eventSourceName,proto3" json:"eventSourceName,omitempty"` + // optional - the event source type (e.g. `webhook`) + EventSourceType string `protobuf:"bytes,3,opt,name=eventSourceType,proto3" json:"eventSourceType,omitempty"` + // optional - the event name (e.g. `example`) + EventName string `protobuf:"bytes,4,opt,name=eventName,proto3" json:"eventName,omitempty"` + Level string `protobuf:"bytes,5,opt,name=level,proto3" json:"level,omitempty"` + Time *v1.Time `protobuf:"bytes,6,opt,name=time,proto3" json:"time,omitempty"` + Msg string `protobuf:"bytes,7,opt,name=msg,proto3" json:"msg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LogEntry) Reset() { *m = LogEntry{} } +func (m *LogEntry) String() string { return proto.CompactTextString(m) } +func (*LogEntry) ProtoMessage() {} +func (*LogEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_b13fbf03f636aa35, []int{2} +} +func (m *LogEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *LogEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_LogEntry.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *LogEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_LogEntry.Merge(m, src) +} +func (m *LogEntry) XXX_Size() int { + return m.Size() +} +func (m *LogEntry) XXX_DiscardUnknown() { + xxx_messageInfo_LogEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_LogEntry proto.InternalMessageInfo + +func (m *LogEntry) GetNamespace() string { + if m != nil { + return m.Namespace + } + return "" +} + +func (m *LogEntry) GetEventSourceName() string { + if m != nil { + return m.EventSourceName + } + return "" +} + +func (m *LogEntry) GetEventSourceType() string { + if m != nil { + return m.EventSourceType + } + return "" +} + +func (m *LogEntry) GetEventName() string { + if m != nil { + return m.EventName + } + return "" +} + +func (m *LogEntry) GetLevel() string { + if m != nil { + return m.Level + } + return "" +} + +func (m *LogEntry) GetTime() *v1.Time { + if m != nil { + return m.Time + } + return nil +} + +func (m *LogEntry) GetMsg() string { + if m != nil { + return m.Msg + } + return "" +} + +type EventSourceWatchEvent struct { + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + Object *v1alpha1.EventSource `protobuf:"bytes,2,opt,name=object,proto3" json:"object,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EventSourceWatchEvent) Reset() { *m = EventSourceWatchEvent{} } +func (m *EventSourceWatchEvent) String() string { return proto.CompactTextString(m) } +func (*EventSourceWatchEvent) ProtoMessage() {} +func (*EventSourceWatchEvent) Descriptor() ([]byte, []int) { + return fileDescriptor_b13fbf03f636aa35, []int{3} +} +func (m *EventSourceWatchEvent) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventSourceWatchEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventSourceWatchEvent.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *EventSourceWatchEvent) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventSourceWatchEvent.Merge(m, src) +} +func (m *EventSourceWatchEvent) XXX_Size() int { + return m.Size() +} +func (m *EventSourceWatchEvent) XXX_DiscardUnknown() { + xxx_messageInfo_EventSourceWatchEvent.DiscardUnknown(m) +} + +var xxx_messageInfo_EventSourceWatchEvent proto.InternalMessageInfo + +func (m *EventSourceWatchEvent) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *EventSourceWatchEvent) GetObject() *v1alpha1.EventSource { + if m != nil { + return m.Object + } + return nil +} + +func init() { + proto.RegisterType((*ListEventSourcesRequest)(nil), "eventsource.ListEventSourcesRequest") + proto.RegisterType((*EventSourcesLogsRequest)(nil), "eventsource.EventSourcesLogsRequest") + proto.RegisterType((*LogEntry)(nil), "eventsource.LogEntry") + proto.RegisterType((*EventSourceWatchEvent)(nil), "eventsource.EventSourceWatchEvent") +} + +func init() { + proto.RegisterFile("pkg/apiclient/eventsource/eventsource.proto", fileDescriptor_b13fbf03f636aa35) +} + +var fileDescriptor_b13fbf03f636aa35 = []byte{ + // 628 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x4f, 0x6b, 0x14, 0x31, + 0x14, 0x27, 0xfd, 0xa7, 0x4d, 0x11, 0x6b, 0xb0, 0x74, 0x59, 0x4a, 0x69, 0x47, 0x0f, 0x6b, 0xa5, + 0x49, 0xb7, 0x2a, 0x78, 0x12, 0x11, 0x8a, 0x20, 0x6b, 0x95, 0x69, 0x41, 0xf0, 0x22, 0xd9, 0xe9, + 0x23, 0x3b, 0xdd, 0x99, 0xc9, 0x38, 0xc9, 0x0e, 0x2c, 0xe2, 0xa5, 0x27, 0x0f, 0x82, 0x88, 0x1f, + 0xc5, 0x2f, 0xe1, 0x51, 0xf0, 0x0b, 0xc8, 0xe2, 0xc5, 0x9b, 0x1f, 0x41, 0x92, 0x99, 0xed, 0x64, + 0x57, 0x07, 0x57, 0xe8, 0xed, 0xe5, 0x4d, 0xde, 0xef, 0xfd, 0x7e, 0x2f, 0xf9, 0x65, 0xf0, 0xed, + 0xb4, 0x2f, 0x18, 0x4f, 0xc3, 0x20, 0x0a, 0x21, 0xd1, 0x0c, 0x72, 0x48, 0xb4, 0x92, 0x83, 0x2c, + 0x00, 0x37, 0xa6, 0x69, 0x26, 0xb5, 0x24, 0x2b, 0x4e, 0xaa, 0xb9, 0x21, 0xa4, 0x14, 0x11, 0x98, + 0x62, 0xc6, 0x93, 0x44, 0x6a, 0xae, 0x43, 0x99, 0xa8, 0x62, 0x6b, 0xf3, 0x6e, 0xff, 0xbe, 0xa2, + 0xa1, 0x34, 0x5f, 0x63, 0x1e, 0xf4, 0xc2, 0x04, 0xb2, 0x21, 0x2b, 0x7b, 0x29, 0x16, 0x83, 0xe6, + 0x2c, 0x6f, 0x33, 0x01, 0x09, 0x64, 0x5c, 0xc3, 0x49, 0x59, 0xe5, 0x55, 0x55, 0x2c, 0x90, 0x19, + 0xfc, 0x6d, 0xcf, 0x53, 0x11, 0xea, 0xde, 0xa0, 0x4b, 0x03, 0x19, 0x33, 0x9e, 0x09, 0x99, 0x66, + 0xf2, 0xd4, 0x06, 0xbb, 0x05, 0xbb, 0xaa, 0x8b, 0x2b, 0x26, 0x6f, 0xf3, 0x28, 0xed, 0xf1, 0x3f, + 0xe0, 0xbc, 0xf7, 0x08, 0xaf, 0x77, 0x42, 0xa5, 0x0f, 0xcc, 0xe6, 0x23, 0xbb, 0x59, 0xf9, 0xf0, + 0x7a, 0x00, 0x4a, 0x93, 0x0d, 0xbc, 0x9c, 0xf0, 0x18, 0x54, 0xca, 0x03, 0x68, 0xa0, 0x2d, 0xd4, + 0x5a, 0xf6, 0xab, 0x04, 0x39, 0xc2, 0x2b, 0x51, 0xa8, 0xf4, 0xb3, 0xd4, 0xea, 0x6e, 0xcc, 0x6d, + 0xa1, 0xd6, 0xca, 0x7e, 0x9b, 0x16, 0x12, 0xa8, 0x2b, 0x9c, 0xa6, 0x7d, 0x61, 0x12, 0x8a, 0x1a, + 0xe1, 0x34, 0x6f, 0xd3, 0x4e, 0x55, 0xe8, 0xbb, 0x28, 0xde, 0x2f, 0x84, 0xd7, 0x5d, 0x2a, 0x1d, + 0x29, 0x66, 0xa4, 0x43, 0xf0, 0x82, 0x59, 0x58, 0x1e, 0xcb, 0xbe, 0x8d, 0x49, 0x0b, 0x5f, 0x85, + 0x0a, 0xec, 0x78, 0x98, 0x42, 0x63, 0xde, 0x7e, 0x9e, 0x4e, 0x1b, 0x6c, 0x9b, 0x3a, 0x34, 0x10, + 0x0b, 0x05, 0xf6, 0x79, 0xc2, 0x60, 0x8b, 0x0c, 0xd2, 0xc6, 0x62, 0x81, 0x6d, 0x62, 0xf2, 0x18, + 0x5f, 0x49, 0xe5, 0x49, 0x47, 0x8a, 0xf1, 0x00, 0x96, 0xec, 0x00, 0xb6, 0x9d, 0x01, 0x50, 0x73, + 0x86, 0x46, 0xee, 0x73, 0x77, 0xa3, 0x3f, 0x59, 0xe7, 0x9d, 0xcd, 0xe1, 0xcb, 0x1d, 0x29, 0x0e, + 0x12, 0x9d, 0x0d, 0xff, 0xa1, 0x71, 0x52, 0xcf, 0x61, 0x25, 0x77, 0x3a, 0x7d, 0x61, 0xca, 0xaf, + 0xe3, 0xc5, 0x08, 0x72, 0x88, 0x4a, 0xe9, 0xc5, 0x82, 0x3c, 0xc0, 0x0b, 0x3a, 0x8c, 0xa1, 0x94, + 0xbc, 0x33, 0xdb, 0x99, 0x1f, 0x87, 0x31, 0xf8, 0xb6, 0x8e, 0xac, 0xe2, 0xf9, 0x58, 0x89, 0xc6, + 0x25, 0x8b, 0x69, 0x42, 0xef, 0x03, 0xc2, 0x6b, 0xce, 0xb9, 0xbf, 0xe0, 0x3a, 0xe8, 0xd9, 0xb5, + 0x99, 0xbd, 0x36, 0xf4, 0x8b, 0x61, 0xd8, 0x98, 0x74, 0xf1, 0x92, 0xec, 0x9e, 0x42, 0xa0, 0xcb, + 0x5b, 0xf7, 0x84, 0x56, 0xa6, 0xa0, 0x63, 0x53, 0xd8, 0xe0, 0x55, 0x61, 0x82, 0x8a, 0x8d, 0xeb, + 0xea, 0xb1, 0x29, 0xa8, 0xd3, 0xd9, 0x2f, 0x91, 0xf7, 0x7f, 0xce, 0x63, 0xe2, 0xe4, 0x8f, 0x20, + 0xcb, 0xc3, 0x00, 0xc8, 0x67, 0x84, 0x57, 0xa7, 0xfd, 0x42, 0x6e, 0x4e, 0xc0, 0xd6, 0xd8, 0xa9, + 0x79, 0x78, 0x71, 0x2c, 0x4d, 0x0b, 0xef, 0xd6, 0xd9, 0xb7, 0x1f, 0x9f, 0xe6, 0x6e, 0x90, 0x6d, + 0xfb, 0x5e, 0xe4, 0xed, 0xc2, 0xf0, 0xbb, 0x45, 0x99, 0x62, 0x6f, 0xce, 0xef, 0xcd, 0x5b, 0xf2, + 0x0e, 0xe1, 0xd5, 0x69, 0x5b, 0x4d, 0xb1, 0xae, 0x71, 0x5d, 0x73, 0x6d, 0x52, 0x5b, 0x79, 0x51, + 0xbd, 0x7b, 0xb6, 0x39, 0x23, 0xbb, 0xe3, 0xe6, 0x4a, 0x67, 0xc0, 0xe3, 0x7a, 0x0e, 0x2c, 0x92, + 0x42, 0xed, 0x21, 0xf2, 0x11, 0xe1, 0x6b, 0xd5, 0xf1, 0xfe, 0xdf, 0x04, 0xbd, 0x3a, 0xc6, 0x15, + 0xa0, 0xb7, 0x67, 0x89, 0xed, 0x90, 0xd6, 0xac, 0xc4, 0xf6, 0xd0, 0xa3, 0x87, 0x5f, 0x46, 0x9b, + 0xe8, 0xeb, 0x68, 0x13, 0x7d, 0x1f, 0x6d, 0xa2, 0x97, 0xfb, 0x75, 0x2f, 0x2c, 0xab, 0xfd, 0x59, + 0x74, 0x97, 0xec, 0x6b, 0x7a, 0xe7, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x40, 0xfc, 0xee, 0x5b, + 0x50, 0x06, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// EventSourceServiceClient is the client API for EventSourceService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type EventSourceServiceClient interface { + ListEventSources(ctx context.Context, in *ListEventSourcesRequest, opts ...grpc.CallOption) (*v1alpha1.EventSourceList, error) + EventSourcesLogs(ctx context.Context, in *EventSourcesLogsRequest, opts ...grpc.CallOption) (EventSourceService_EventSourcesLogsClient, error) + WatchEventSources(ctx context.Context, in *ListEventSourcesRequest, opts ...grpc.CallOption) (EventSourceService_WatchEventSourcesClient, error) +} + +type eventSourceServiceClient struct { + cc *grpc.ClientConn +} + +func NewEventSourceServiceClient(cc *grpc.ClientConn) EventSourceServiceClient { + return &eventSourceServiceClient{cc} +} + +func (c *eventSourceServiceClient) ListEventSources(ctx context.Context, in *ListEventSourcesRequest, opts ...grpc.CallOption) (*v1alpha1.EventSourceList, error) { + out := new(v1alpha1.EventSourceList) + err := c.cc.Invoke(ctx, "/eventsource.EventSourceService/ListEventSources", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *eventSourceServiceClient) EventSourcesLogs(ctx context.Context, in *EventSourcesLogsRequest, opts ...grpc.CallOption) (EventSourceService_EventSourcesLogsClient, error) { + stream, err := c.cc.NewStream(ctx, &_EventSourceService_serviceDesc.Streams[0], "/eventsource.EventSourceService/EventSourcesLogs", opts...) + if err != nil { + return nil, err + } + x := &eventSourceServiceEventSourcesLogsClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type EventSourceService_EventSourcesLogsClient interface { + Recv() (*LogEntry, error) + grpc.ClientStream +} + +type eventSourceServiceEventSourcesLogsClient struct { + grpc.ClientStream +} + +func (x *eventSourceServiceEventSourcesLogsClient) Recv() (*LogEntry, error) { + m := new(LogEntry) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *eventSourceServiceClient) WatchEventSources(ctx context.Context, in *ListEventSourcesRequest, opts ...grpc.CallOption) (EventSourceService_WatchEventSourcesClient, error) { + stream, err := c.cc.NewStream(ctx, &_EventSourceService_serviceDesc.Streams[1], "/eventsource.EventSourceService/WatchEventSources", opts...) + if err != nil { + return nil, err + } + x := &eventSourceServiceWatchEventSourcesClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type EventSourceService_WatchEventSourcesClient interface { + Recv() (*EventSourceWatchEvent, error) + grpc.ClientStream +} + +type eventSourceServiceWatchEventSourcesClient struct { + grpc.ClientStream +} + +func (x *eventSourceServiceWatchEventSourcesClient) Recv() (*EventSourceWatchEvent, error) { + m := new(EventSourceWatchEvent) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// EventSourceServiceServer is the server API for EventSourceService service. +type EventSourceServiceServer interface { + ListEventSources(context.Context, *ListEventSourcesRequest) (*v1alpha1.EventSourceList, error) + EventSourcesLogs(*EventSourcesLogsRequest, EventSourceService_EventSourcesLogsServer) error + WatchEventSources(*ListEventSourcesRequest, EventSourceService_WatchEventSourcesServer) error +} + +// UnimplementedEventSourceServiceServer can be embedded to have forward compatible implementations. +type UnimplementedEventSourceServiceServer struct { +} + +func (*UnimplementedEventSourceServiceServer) ListEventSources(ctx context.Context, req *ListEventSourcesRequest) (*v1alpha1.EventSourceList, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListEventSources not implemented") +} +func (*UnimplementedEventSourceServiceServer) EventSourcesLogs(req *EventSourcesLogsRequest, srv EventSourceService_EventSourcesLogsServer) error { + return status.Errorf(codes.Unimplemented, "method EventSourcesLogs not implemented") +} +func (*UnimplementedEventSourceServiceServer) WatchEventSources(req *ListEventSourcesRequest, srv EventSourceService_WatchEventSourcesServer) error { + return status.Errorf(codes.Unimplemented, "method WatchEventSources not implemented") +} + +func RegisterEventSourceServiceServer(s *grpc.Server, srv EventSourceServiceServer) { + s.RegisterService(&_EventSourceService_serviceDesc, srv) +} + +func _EventSourceService_ListEventSources_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListEventSourcesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EventSourceServiceServer).ListEventSources(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/eventsource.EventSourceService/ListEventSources", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EventSourceServiceServer).ListEventSources(ctx, req.(*ListEventSourcesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _EventSourceService_EventSourcesLogs_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(EventSourcesLogsRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(EventSourceServiceServer).EventSourcesLogs(m, &eventSourceServiceEventSourcesLogsServer{stream}) +} + +type EventSourceService_EventSourcesLogsServer interface { + Send(*LogEntry) error + grpc.ServerStream +} + +type eventSourceServiceEventSourcesLogsServer struct { + grpc.ServerStream +} + +func (x *eventSourceServiceEventSourcesLogsServer) Send(m *LogEntry) error { + return x.ServerStream.SendMsg(m) +} + +func _EventSourceService_WatchEventSources_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(ListEventSourcesRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(EventSourceServiceServer).WatchEventSources(m, &eventSourceServiceWatchEventSourcesServer{stream}) +} + +type EventSourceService_WatchEventSourcesServer interface { + Send(*EventSourceWatchEvent) error + grpc.ServerStream +} + +type eventSourceServiceWatchEventSourcesServer struct { + grpc.ServerStream +} + +func (x *eventSourceServiceWatchEventSourcesServer) Send(m *EventSourceWatchEvent) error { + return x.ServerStream.SendMsg(m) +} + +var _EventSourceService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "eventsource.EventSourceService", + HandlerType: (*EventSourceServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ListEventSources", + Handler: _EventSourceService_ListEventSources_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "EventSourcesLogs", + Handler: _EventSourceService_EventSourcesLogs_Handler, + ServerStreams: true, + }, + { + StreamName: "WatchEventSources", + Handler: _EventSourceService_WatchEventSources_Handler, + ServerStreams: true, + }, + }, + Metadata: "pkg/apiclient/eventsource/eventsource.proto", +} + +func (m *ListEventSourcesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListEventSourcesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListEventSourcesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.ListOptions != nil { + { + size, err := m.ListOptions.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEventsource(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Namespace) > 0 { + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintEventsource(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *EventSourcesLogsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *EventSourcesLogsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventSourcesLogsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.PodLogOptions != nil { + { + size, err := m.PodLogOptions.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEventsource(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + if len(m.Grep) > 0 { + i -= len(m.Grep) + copy(dAtA[i:], m.Grep) + i = encodeVarintEventsource(dAtA, i, uint64(len(m.Grep))) + i-- + dAtA[i] = 0x2a + } + if len(m.EventName) > 0 { + i -= len(m.EventName) + copy(dAtA[i:], m.EventName) + i = encodeVarintEventsource(dAtA, i, uint64(len(m.EventName))) + i-- + dAtA[i] = 0x22 + } + if len(m.EventSourceType) > 0 { + i -= len(m.EventSourceType) + copy(dAtA[i:], m.EventSourceType) + i = encodeVarintEventsource(dAtA, i, uint64(len(m.EventSourceType))) + i-- + dAtA[i] = 0x1a + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintEventsource(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } + if len(m.Namespace) > 0 { + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintEventsource(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *LogEntry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *LogEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *LogEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintEventsource(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0x3a + } + if m.Time != nil { + { + size, err := m.Time.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEventsource(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + if len(m.Level) > 0 { + i -= len(m.Level) + copy(dAtA[i:], m.Level) + i = encodeVarintEventsource(dAtA, i, uint64(len(m.Level))) + i-- + dAtA[i] = 0x2a + } + if len(m.EventName) > 0 { + i -= len(m.EventName) + copy(dAtA[i:], m.EventName) + i = encodeVarintEventsource(dAtA, i, uint64(len(m.EventName))) + i-- + dAtA[i] = 0x22 + } + if len(m.EventSourceType) > 0 { + i -= len(m.EventSourceType) + copy(dAtA[i:], m.EventSourceType) + i = encodeVarintEventsource(dAtA, i, uint64(len(m.EventSourceType))) + i-- + dAtA[i] = 0x1a + } + if len(m.EventSourceName) > 0 { + i -= len(m.EventSourceName) + copy(dAtA[i:], m.EventSourceName) + i = encodeVarintEventsource(dAtA, i, uint64(len(m.EventSourceName))) + i-- + dAtA[i] = 0x12 + } + if len(m.Namespace) > 0 { + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintEventsource(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *EventSourceWatchEvent) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *EventSourceWatchEvent) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventSourceWatchEvent) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Object != nil { + { + size, err := m.Object.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEventsource(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Type) > 0 { + i -= len(m.Type) + copy(dAtA[i:], m.Type) + i = encodeVarintEventsource(dAtA, i, uint64(len(m.Type))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintEventsource(dAtA []byte, offset int, v uint64) int { + offset -= sovEventsource(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ListEventSourcesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Namespace) + if l > 0 { + n += 1 + l + sovEventsource(uint64(l)) + } + if m.ListOptions != nil { + l = m.ListOptions.Size() + n += 1 + l + sovEventsource(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *EventSourcesLogsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Namespace) + if l > 0 { + n += 1 + l + sovEventsource(uint64(l)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovEventsource(uint64(l)) + } + l = len(m.EventSourceType) + if l > 0 { + n += 1 + l + sovEventsource(uint64(l)) + } + l = len(m.EventName) + if l > 0 { + n += 1 + l + sovEventsource(uint64(l)) + } + l = len(m.Grep) + if l > 0 { + n += 1 + l + sovEventsource(uint64(l)) + } + if m.PodLogOptions != nil { + l = m.PodLogOptions.Size() + n += 1 + l + sovEventsource(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *LogEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Namespace) + if l > 0 { + n += 1 + l + sovEventsource(uint64(l)) + } + l = len(m.EventSourceName) + if l > 0 { + n += 1 + l + sovEventsource(uint64(l)) + } + l = len(m.EventSourceType) + if l > 0 { + n += 1 + l + sovEventsource(uint64(l)) + } + l = len(m.EventName) + if l > 0 { + n += 1 + l + sovEventsource(uint64(l)) + } + l = len(m.Level) + if l > 0 { + n += 1 + l + sovEventsource(uint64(l)) + } + if m.Time != nil { + l = m.Time.Size() + n += 1 + l + sovEventsource(uint64(l)) + } + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovEventsource(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *EventSourceWatchEvent) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Type) + if l > 0 { + n += 1 + l + sovEventsource(uint64(l)) + } + if m.Object != nil { + l = m.Object.Size() + n += 1 + l + sovEventsource(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovEventsource(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozEventsource(x uint64) (n int) { + return sovEventsource(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ListEventSourcesRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ListEventSourcesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ListEventSourcesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Namespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ListOptions", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ListOptions == nil { + m.ListOptions = &v1.ListOptions{} + } + if err := m.ListOptions.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEventsource(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthEventsource + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthEventsource + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *EventSourcesLogsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: EventSourcesLogsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventSourcesLogsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Namespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EventSourceType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EventSourceType = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EventName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EventName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Grep", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Grep = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PodLogOptions", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.PodLogOptions == nil { + m.PodLogOptions = &v11.PodLogOptions{} + } + if err := m.PodLogOptions.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEventsource(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthEventsource + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthEventsource + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *LogEntry) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: LogEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LogEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Namespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EventSourceName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EventSourceName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EventSourceType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EventSourceType = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EventName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EventName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Level", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Level = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Time", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Time == nil { + m.Time = &v1.Time{} + } + if err := m.Time.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msg = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEventsource(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthEventsource + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthEventsource + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *EventSourceWatchEvent) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: EventSourceWatchEvent: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventSourceWatchEvent: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Type = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Object", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEventsource + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEventsource + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEventsource + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Object == nil { + m.Object = &v1alpha1.EventSource{} + } + if err := m.Object.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEventsource(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthEventsource + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthEventsource + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipEventsource(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEventsource + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEventsource + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEventsource + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthEventsource + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupEventsource + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthEventsource + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthEventsource = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowEventsource = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupEventsource = fmt.Errorf("proto: unexpected end of group") +) diff --git a/pkg/apiclient/eventsource/eventsource.pb.gw.go b/pkg/apiclient/eventsource/eventsource.pb.gw.go new file mode 100644 index 000000000000..0d6b1bc0e4d4 --- /dev/null +++ b/pkg/apiclient/eventsource/eventsource.pb.gw.go @@ -0,0 +1,352 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: pkg/apiclient/eventsource/eventsource.proto + +/* +Package eventsource is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package eventsource + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage + +var ( + filter_EventSourceService_ListEventSources_0 = &utilities.DoubleArray{Encoding: map[string]int{"namespace": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_EventSourceService_ListEventSources_0(ctx context.Context, marshaler runtime.Marshaler, client EventSourceServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ListEventSourcesRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["namespace"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") + } + + protoReq.Namespace, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EventSourceService_ListEventSources_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ListEventSources(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_EventSourceService_ListEventSources_0(ctx context.Context, marshaler runtime.Marshaler, server EventSourceServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ListEventSourcesRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["namespace"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") + } + + protoReq.Namespace, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) + } + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_EventSourceService_ListEventSources_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.ListEventSources(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_EventSourceService_EventSourcesLogs_0 = &utilities.DoubleArray{Encoding: map[string]int{"namespace": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_EventSourceService_EventSourcesLogs_0(ctx context.Context, marshaler runtime.Marshaler, client EventSourceServiceClient, req *http.Request, pathParams map[string]string) (EventSourceService_EventSourcesLogsClient, runtime.ServerMetadata, error) { + var protoReq EventSourcesLogsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["namespace"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") + } + + protoReq.Namespace, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EventSourceService_EventSourcesLogs_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + stream, err := client.EventSourcesLogs(ctx, &protoReq) + if err != nil { + return nil, metadata, err + } + header, err := stream.Header() + if err != nil { + return nil, metadata, err + } + metadata.HeaderMD = header + return stream, metadata, nil + +} + +var ( + filter_EventSourceService_WatchEventSources_0 = &utilities.DoubleArray{Encoding: map[string]int{"namespace": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_EventSourceService_WatchEventSources_0(ctx context.Context, marshaler runtime.Marshaler, client EventSourceServiceClient, req *http.Request, pathParams map[string]string) (EventSourceService_WatchEventSourcesClient, runtime.ServerMetadata, error) { + var protoReq ListEventSourcesRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["namespace"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") + } + + protoReq.Namespace, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EventSourceService_WatchEventSources_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + stream, err := client.WatchEventSources(ctx, &protoReq) + if err != nil { + return nil, metadata, err + } + header, err := stream.Header() + if err != nil { + return nil, metadata, err + } + metadata.HeaderMD = header + return stream, metadata, nil + +} + +// RegisterEventSourceServiceHandlerServer registers the http handlers for service EventSourceService to "mux". +// UnaryRPC :call EventSourceServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +func RegisterEventSourceServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server EventSourceServiceServer) error { + + mux.Handle("GET", pattern_EventSourceService_ListEventSources_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_EventSourceService_ListEventSources_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EventSourceService_ListEventSources_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_EventSourceService_EventSourcesLogs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + err := status.Error(codes.Unimplemented, "streaming calls are not yet supported in the in-process transport") + _, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + }) + + mux.Handle("GET", pattern_EventSourceService_WatchEventSources_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + err := status.Error(codes.Unimplemented, "streaming calls are not yet supported in the in-process transport") + _, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + }) + + return nil +} + +// RegisterEventSourceServiceHandlerFromEndpoint is same as RegisterEventSourceServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterEventSourceServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterEventSourceServiceHandler(ctx, mux, conn) +} + +// RegisterEventSourceServiceHandler registers the http handlers for service EventSourceService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterEventSourceServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterEventSourceServiceHandlerClient(ctx, mux, NewEventSourceServiceClient(conn)) +} + +// RegisterEventSourceServiceHandlerClient registers the http handlers for service EventSourceService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "EventSourceServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "EventSourceServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "EventSourceServiceClient" to call the correct interceptors. +func RegisterEventSourceServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client EventSourceServiceClient) error { + + mux.Handle("GET", pattern_EventSourceService_ListEventSources_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_EventSourceService_ListEventSources_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EventSourceService_ListEventSources_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_EventSourceService_EventSourcesLogs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_EventSourceService_EventSourcesLogs_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EventSourceService_EventSourcesLogs_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_EventSourceService_WatchEventSources_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_EventSourceService_WatchEventSources_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EventSourceService_WatchEventSources_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_EventSourceService_ListEventSources_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "event-sources", "namespace"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_EventSourceService_EventSourcesLogs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"api", "v1", "stream", "event-sources", "namespace", "logs"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_EventSourceService_WatchEventSources_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"api", "v1", "stream", "event-sources", "namespace"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_EventSourceService_ListEventSources_0 = runtime.ForwardResponseMessage + + forward_EventSourceService_EventSourcesLogs_0 = runtime.ForwardResponseStream + + forward_EventSourceService_WatchEventSources_0 = runtime.ForwardResponseStream +) diff --git a/pkg/apiclient/eventsource/eventsource.proto b/pkg/apiclient/eventsource/eventsource.proto new file mode 100644 index 000000000000..ee3df329286d --- /dev/null +++ b/pkg/apiclient/eventsource/eventsource.proto @@ -0,0 +1,57 @@ +syntax = "proto3"; +option go_package = "github.com/argoproj/argo/pkg/apiclient/eventsource"; + +import "google/api/annotations.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/api/core/v1/generated.proto"; +import "github.com/argoproj/argo-events/pkg/apis/eventsource/v1alpha1/generated.proto"; + +package eventsource; + +message ListEventSourcesRequest { + string namespace = 1; + k8s.io.apimachinery.pkg.apis.meta.v1.ListOptions listOptions = 2; +} + +message EventSourcesLogsRequest { + string namespace = 1; + // optional - only return entries for this event source + string name = 2; + // optional - only return entries for this event source type (e.g. `webhook`) + string eventSourceType = 3; + // optional - only return entries for this event name (e.g. `example`) + string eventName = 4; + // optional - only return entries where `msg` matches this regular expression + string grep = 5; + k8s.io.api.core.v1.PodLogOptions podLogOptions = 6; +} + +// structured log entry +message LogEntry { + string namespace = 1; + string eventSourceName = 2; + // optional - the event source type (e.g. `webhook`) + string eventSourceType = 3; + // optional - the event name (e.g. `example`) + string eventName = 4; + string level = 5; + k8s.io.apimachinery.pkg.apis.meta.v1.Time time = 6; + string msg = 7; +} + +message EventSourceWatchEvent { + string type = 1; + github.com.argoproj.argo_events.pkg.apis.eventsource.v1alpha1.EventSource object = 2; +} + +service EventSourceService { + rpc ListEventSources (ListEventSourcesRequest) returns (github.com.argoproj.argo_events.pkg.apis.eventsource.v1alpha1.EventSourceList) { + option (google.api.http).get = "/api/v1/event-sources/{namespace}"; + } + rpc EventSourcesLogs (EventSourcesLogsRequest) returns (stream LogEntry) { + option (google.api.http).get = "/api/v1/stream/event-sources/{namespace}/logs"; + } + rpc WatchEventSources (ListEventSourcesRequest) returns (stream EventSourceWatchEvent) { + option (google.api.http).get = "/api/v1/stream/event-sources/{namespace}"; + } +} \ No newline at end of file diff --git a/pkg/apiclient/eventsource/forwarder_overwrite.go b/pkg/apiclient/eventsource/forwarder_overwrite.go new file mode 100644 index 000000000000..107af0fde858 --- /dev/null +++ b/pkg/apiclient/eventsource/forwarder_overwrite.go @@ -0,0 +1,10 @@ +package eventsource + +import ( + "github.com/argoproj/pkg/grpc/http" +) + +func init() { + forward_EventSourceService_EventSourcesLogs_0 = http.StreamForwarder + forward_EventSourceService_WatchEventSources_0 = http.StreamForwarder +} diff --git a/pkg/apiclient/sensor/forwarder_overwrite.go b/pkg/apiclient/sensor/forwarder_overwrite.go new file mode 100644 index 000000000000..65b9d63d13df --- /dev/null +++ b/pkg/apiclient/sensor/forwarder_overwrite.go @@ -0,0 +1,10 @@ +package sensor + +import ( + "github.com/argoproj/pkg/grpc/http" +) + +func init() { + forward_SensorService_SensorsLogs_0 = http.StreamForwarder + forward_SensorService_WatchSensors_0 = http.StreamForwarder +} diff --git a/pkg/apiclient/sensor/sensor.pb.go b/pkg/apiclient/sensor/sensor.pb.go new file mode 100644 index 000000000000..4ab7eb1a62a2 --- /dev/null +++ b/pkg/apiclient/sensor/sensor.pb.go @@ -0,0 +1,1832 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: pkg/apiclient/sensor/sensor.proto + +package sensor + +import ( + context "context" + fmt "fmt" + v1alpha1 "github.com/argoproj/argo-events/pkg/apis/sensor/v1alpha1" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + v11 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type ListSensorsRequest struct { + Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` + ListOptions *v1.ListOptions `protobuf:"bytes,2,opt,name=listOptions,proto3" json:"listOptions,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListSensorsRequest) Reset() { *m = ListSensorsRequest{} } +func (m *ListSensorsRequest) String() string { return proto.CompactTextString(m) } +func (*ListSensorsRequest) ProtoMessage() {} +func (*ListSensorsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_78ba963e1c6b5b55, []int{0} +} +func (m *ListSensorsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListSensorsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListSensorsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListSensorsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListSensorsRequest.Merge(m, src) +} +func (m *ListSensorsRequest) XXX_Size() int { + return m.Size() +} +func (m *ListSensorsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListSensorsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ListSensorsRequest proto.InternalMessageInfo + +func (m *ListSensorsRequest) GetNamespace() string { + if m != nil { + return m.Namespace + } + return "" +} + +func (m *ListSensorsRequest) GetListOptions() *v1.ListOptions { + if m != nil { + return m.ListOptions + } + return nil +} + +type SensorsLogsRequest struct { + Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` + // optional - only return entries for this sensor name + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // optional - only return entries for this trigger + TriggerName string `protobuf:"bytes,3,opt,name=triggerName,proto3" json:"triggerName,omitempty"` + // option - only return entries where `msg` contains this regular expressions + Grep string `protobuf:"bytes,4,opt,name=grep,proto3" json:"grep,omitempty"` + PodLogOptions *v11.PodLogOptions `protobuf:"bytes,5,opt,name=podLogOptions,proto3" json:"podLogOptions,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SensorsLogsRequest) Reset() { *m = SensorsLogsRequest{} } +func (m *SensorsLogsRequest) String() string { return proto.CompactTextString(m) } +func (*SensorsLogsRequest) ProtoMessage() {} +func (*SensorsLogsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_78ba963e1c6b5b55, []int{1} +} +func (m *SensorsLogsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SensorsLogsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SensorsLogsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SensorsLogsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SensorsLogsRequest.Merge(m, src) +} +func (m *SensorsLogsRequest) XXX_Size() int { + return m.Size() +} +func (m *SensorsLogsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_SensorsLogsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_SensorsLogsRequest proto.InternalMessageInfo + +func (m *SensorsLogsRequest) GetNamespace() string { + if m != nil { + return m.Namespace + } + return "" +} + +func (m *SensorsLogsRequest) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *SensorsLogsRequest) GetTriggerName() string { + if m != nil { + return m.TriggerName + } + return "" +} + +func (m *SensorsLogsRequest) GetGrep() string { + if m != nil { + return m.Grep + } + return "" +} + +func (m *SensorsLogsRequest) GetPodLogOptions() *v11.PodLogOptions { + if m != nil { + return m.PodLogOptions + } + return nil +} + +// structured log entry +type LogEntry struct { + Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` + SensorName string `protobuf:"bytes,2,opt,name=sensorName,proto3" json:"sensorName,omitempty"` + // optional - any trigger name + TriggerName string `protobuf:"bytes,3,opt,name=triggerName,proto3" json:"triggerName,omitempty"` + Level string `protobuf:"bytes,5,opt,name=level,proto3" json:"level,omitempty"` + Time *v1.Time `protobuf:"bytes,6,opt,name=time,proto3" json:"time,omitempty"` + Msg string `protobuf:"bytes,7,opt,name=msg,proto3" json:"msg,omitempty"` + // optional - trigger dependency name + DependencyName string `protobuf:"bytes,8,opt,name=dependencyName,proto3" json:"dependencyName,omitempty"` + // optional - Cloud Event context + EventContext string `protobuf:"bytes,9,opt,name=eventContext,proto3" json:"eventContext,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LogEntry) Reset() { *m = LogEntry{} } +func (m *LogEntry) String() string { return proto.CompactTextString(m) } +func (*LogEntry) ProtoMessage() {} +func (*LogEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_78ba963e1c6b5b55, []int{2} +} +func (m *LogEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *LogEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_LogEntry.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *LogEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_LogEntry.Merge(m, src) +} +func (m *LogEntry) XXX_Size() int { + return m.Size() +} +func (m *LogEntry) XXX_DiscardUnknown() { + xxx_messageInfo_LogEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_LogEntry proto.InternalMessageInfo + +func (m *LogEntry) GetNamespace() string { + if m != nil { + return m.Namespace + } + return "" +} + +func (m *LogEntry) GetSensorName() string { + if m != nil { + return m.SensorName + } + return "" +} + +func (m *LogEntry) GetTriggerName() string { + if m != nil { + return m.TriggerName + } + return "" +} + +func (m *LogEntry) GetLevel() string { + if m != nil { + return m.Level + } + return "" +} + +func (m *LogEntry) GetTime() *v1.Time { + if m != nil { + return m.Time + } + return nil +} + +func (m *LogEntry) GetMsg() string { + if m != nil { + return m.Msg + } + return "" +} + +func (m *LogEntry) GetDependencyName() string { + if m != nil { + return m.DependencyName + } + return "" +} + +func (m *LogEntry) GetEventContext() string { + if m != nil { + return m.EventContext + } + return "" +} + +type SensorWatchEvent struct { + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + Object *v1alpha1.Sensor `protobuf:"bytes,2,opt,name=object,proto3" json:"object,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SensorWatchEvent) Reset() { *m = SensorWatchEvent{} } +func (m *SensorWatchEvent) String() string { return proto.CompactTextString(m) } +func (*SensorWatchEvent) ProtoMessage() {} +func (*SensorWatchEvent) Descriptor() ([]byte, []int) { + return fileDescriptor_78ba963e1c6b5b55, []int{3} +} +func (m *SensorWatchEvent) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SensorWatchEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SensorWatchEvent.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SensorWatchEvent) XXX_Merge(src proto.Message) { + xxx_messageInfo_SensorWatchEvent.Merge(m, src) +} +func (m *SensorWatchEvent) XXX_Size() int { + return m.Size() +} +func (m *SensorWatchEvent) XXX_DiscardUnknown() { + xxx_messageInfo_SensorWatchEvent.DiscardUnknown(m) +} + +var xxx_messageInfo_SensorWatchEvent proto.InternalMessageInfo + +func (m *SensorWatchEvent) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *SensorWatchEvent) GetObject() *v1alpha1.Sensor { + if m != nil { + return m.Object + } + return nil +} + +func init() { + proto.RegisterType((*ListSensorsRequest)(nil), "sensor.ListSensorsRequest") + proto.RegisterType((*SensorsLogsRequest)(nil), "sensor.SensorsLogsRequest") + proto.RegisterType((*LogEntry)(nil), "sensor.LogEntry") + proto.RegisterType((*SensorWatchEvent)(nil), "sensor.SensorWatchEvent") +} + +func init() { proto.RegisterFile("pkg/apiclient/sensor/sensor.proto", fileDescriptor_78ba963e1c6b5b55) } + +var fileDescriptor_78ba963e1c6b5b55 = []byte{ + // 642 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0x5d, 0x6b, 0xd4, 0x4c, + 0x14, 0x26, 0xfd, 0xd8, 0xb7, 0x3b, 0xdb, 0xbe, 0x94, 0xc1, 0x8b, 0xb0, 0xd6, 0xa5, 0x8d, 0xa2, + 0xb5, 0xd0, 0x99, 0x6e, 0xf5, 0x42, 0x10, 0x44, 0xd4, 0xa2, 0x17, 0x4b, 0x95, 0x54, 0x50, 0xbc, + 0x91, 0x69, 0xf6, 0x30, 0x9b, 0x36, 0x99, 0x89, 0x33, 0xd3, 0xe0, 0x22, 0x82, 0x78, 0x23, 0x78, + 0xab, 0xd7, 0xfe, 0x1b, 0xc1, 0x4b, 0xc1, 0x3f, 0x20, 0xc5, 0x1f, 0x22, 0x33, 0xc9, 0x36, 0x59, + 0x77, 0xa5, 0x0b, 0x5e, 0xe5, 0xcc, 0x99, 0xf3, 0xf1, 0x3c, 0x39, 0xcf, 0x19, 0xb4, 0x91, 0x1d, + 0x73, 0xca, 0xb2, 0x38, 0x4a, 0x62, 0x10, 0x86, 0x6a, 0x10, 0x5a, 0xaa, 0xf2, 0x43, 0x32, 0x25, + 0x8d, 0xc4, 0x8d, 0xe2, 0xd4, 0x5e, 0xe3, 0x52, 0xf2, 0x04, 0x6c, 0x34, 0x65, 0x42, 0x48, 0xc3, + 0x4c, 0x2c, 0x85, 0x2e, 0xa2, 0xda, 0x37, 0x8f, 0x6f, 0x69, 0x12, 0x4b, 0x7b, 0x9b, 0xb2, 0x68, + 0x10, 0x0b, 0x50, 0x43, 0x5a, 0x16, 0xd7, 0x34, 0x05, 0xc3, 0x68, 0xde, 0xa5, 0x1c, 0x04, 0x28, + 0x66, 0xa0, 0x5f, 0x66, 0x05, 0x55, 0x16, 0x8d, 0xa4, 0x82, 0x69, 0x31, 0x8f, 0x78, 0x6c, 0x06, + 0x27, 0x87, 0x24, 0x92, 0x29, 0x65, 0x8a, 0xcb, 0x4c, 0xc9, 0x23, 0x67, 0x6c, 0x43, 0x0e, 0xc2, + 0xe8, 0xaa, 0x4b, 0x89, 0x3e, 0xef, 0xb2, 0x24, 0x1b, 0xb0, 0x89, 0x4a, 0xc1, 0x07, 0x0f, 0xe1, + 0x5e, 0xac, 0xcd, 0x81, 0x8b, 0xd3, 0x21, 0xbc, 0x3a, 0x01, 0x6d, 0xf0, 0x1a, 0x6a, 0x0a, 0x96, + 0x82, 0xce, 0x58, 0x04, 0xbe, 0xb7, 0xee, 0x6d, 0x36, 0xc3, 0xca, 0x81, 0x0f, 0x50, 0x2b, 0x89, + 0xb5, 0x79, 0x9c, 0x39, 0xb6, 0xfe, 0xdc, 0xba, 0xb7, 0xd9, 0xda, 0xed, 0x92, 0x02, 0x38, 0xa9, + 0xd3, 0x25, 0xd9, 0x31, 0xb7, 0x0e, 0x4d, 0x2c, 0x5d, 0x92, 0x77, 0x49, 0xaf, 0x4a, 0x0c, 0xeb, + 0x55, 0x82, 0xaf, 0x1e, 0xc2, 0x25, 0x8a, 0x9e, 0xe4, 0x33, 0x22, 0xc1, 0x68, 0xc1, 0x1e, 0x1c, + 0x84, 0x66, 0xe8, 0x6c, 0xbc, 0x8e, 0x5a, 0x46, 0xc5, 0x9c, 0x83, 0xda, 0xb7, 0x57, 0xf3, 0xee, + 0xaa, 0xee, 0xb2, 0x59, 0x5c, 0x41, 0xe6, 0x2f, 0x14, 0x59, 0xd6, 0xc6, 0x0f, 0xd1, 0x4a, 0x26, + 0xfb, 0x3d, 0xc9, 0x47, 0xac, 0x16, 0x1d, 0xab, 0x8d, 0x1a, 0x2b, 0x62, 0xc7, 0x61, 0x39, 0x3c, + 0xa9, 0x07, 0x86, 0xe3, 0x79, 0xc1, 0x97, 0x39, 0xb4, 0xd4, 0x93, 0x7c, 0x4f, 0x18, 0x35, 0x3c, + 0x07, 0x7d, 0x07, 0xa1, 0x62, 0x3e, 0xfb, 0x15, 0x87, 0x9a, 0x67, 0x06, 0x26, 0x17, 0xd0, 0x62, + 0x02, 0x39, 0x24, 0x0e, 0x6d, 0x33, 0x2c, 0x0e, 0xf8, 0x0e, 0x5a, 0x30, 0x71, 0x0a, 0x7e, 0xc3, + 0x51, 0xd8, 0x9a, 0x6d, 0x30, 0x4f, 0xe3, 0x14, 0x42, 0x97, 0x87, 0x57, 0xd1, 0x7c, 0xaa, 0xb9, + 0xff, 0x9f, 0xab, 0x69, 0x4d, 0x7c, 0x15, 0xfd, 0xdf, 0x87, 0x0c, 0x44, 0x1f, 0x44, 0x34, 0x74, + 0x60, 0x96, 0xdc, 0xe5, 0x1f, 0x5e, 0x1c, 0xa0, 0x65, 0xa7, 0xc0, 0xfb, 0x52, 0x18, 0x78, 0x6d, + 0xfc, 0xa6, 0x8b, 0x1a, 0xf3, 0x05, 0xef, 0x3c, 0xb4, 0x5a, 0x0c, 0xfa, 0x19, 0x33, 0xd1, 0x60, + 0xcf, 0xde, 0xd9, 0x91, 0x98, 0x61, 0x36, 0xfa, 0x47, 0xce, 0xc6, 0xcf, 0x51, 0x43, 0x1e, 0x1e, + 0x41, 0x64, 0x4a, 0x85, 0xdd, 0x25, 0x95, 0xec, 0xc9, 0x48, 0xf6, 0xce, 0x78, 0x59, 0xc8, 0xbe, + 0x22, 0x55, 0x6e, 0xeb, 0x48, 0xf6, 0xa4, 0xe8, 0x17, 0x96, 0xf5, 0x76, 0x3f, 0xce, 0xa3, 0x95, + 0xc2, 0x75, 0x00, 0x2a, 0x8f, 0x23, 0xc0, 0x9f, 0x3d, 0xd4, 0xaa, 0xed, 0x01, 0x6e, 0x8f, 0x4a, + 0x4c, 0x2e, 0x47, 0xfb, 0xc1, 0xbf, 0xe2, 0xb0, 0x35, 0x83, 0xcb, 0xef, 0x7f, 0xfc, 0xfa, 0x34, + 0x77, 0x09, 0x5f, 0x74, 0x9b, 0x9e, 0x77, 0xcb, 0x55, 0xd5, 0xf4, 0xcd, 0x99, 0x40, 0xde, 0x62, + 0x81, 0x5a, 0xb5, 0x9d, 0xa8, 0x50, 0x4d, 0x2e, 0x4a, 0x7b, 0xf5, 0x0c, 0x71, 0x29, 0xbe, 0x80, + 0xba, 0x0e, 0xd7, 0xf1, 0xb5, 0xb3, 0x0e, 0x46, 0x01, 0x4b, 0xa7, 0x35, 0xa2, 0x89, 0xe4, 0x7a, + 0xc7, 0xc3, 0x0a, 0x2d, 0xbb, 0xa1, 0xcc, 0xf2, 0x1b, 0xfc, 0x71, 0x30, 0xd5, 0x30, 0x83, 0x2d, + 0xd7, 0xf8, 0x0a, 0x0e, 0xce, 0x6f, 0xbc, 0xe3, 0xdd, 0xbb, 0xfd, 0xed, 0xb4, 0xe3, 0x7d, 0x3f, + 0xed, 0x78, 0x3f, 0x4f, 0x3b, 0xde, 0x8b, 0xed, 0xbf, 0x3d, 0x6d, 0x74, 0xda, 0xb3, 0x7c, 0xd8, + 0x70, 0xcf, 0xd8, 0x8d, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xec, 0xc7, 0x23, 0x9c, 0xb5, 0x05, + 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// SensorServiceClient is the client API for SensorService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type SensorServiceClient interface { + ListSensors(ctx context.Context, in *ListSensorsRequest, opts ...grpc.CallOption) (*v1alpha1.SensorList, error) + SensorsLogs(ctx context.Context, in *SensorsLogsRequest, opts ...grpc.CallOption) (SensorService_SensorsLogsClient, error) + WatchSensors(ctx context.Context, in *ListSensorsRequest, opts ...grpc.CallOption) (SensorService_WatchSensorsClient, error) +} + +type sensorServiceClient struct { + cc *grpc.ClientConn +} + +func NewSensorServiceClient(cc *grpc.ClientConn) SensorServiceClient { + return &sensorServiceClient{cc} +} + +func (c *sensorServiceClient) ListSensors(ctx context.Context, in *ListSensorsRequest, opts ...grpc.CallOption) (*v1alpha1.SensorList, error) { + out := new(v1alpha1.SensorList) + err := c.cc.Invoke(ctx, "/sensor.SensorService/ListSensors", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sensorServiceClient) SensorsLogs(ctx context.Context, in *SensorsLogsRequest, opts ...grpc.CallOption) (SensorService_SensorsLogsClient, error) { + stream, err := c.cc.NewStream(ctx, &_SensorService_serviceDesc.Streams[0], "/sensor.SensorService/SensorsLogs", opts...) + if err != nil { + return nil, err + } + x := &sensorServiceSensorsLogsClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type SensorService_SensorsLogsClient interface { + Recv() (*LogEntry, error) + grpc.ClientStream +} + +type sensorServiceSensorsLogsClient struct { + grpc.ClientStream +} + +func (x *sensorServiceSensorsLogsClient) Recv() (*LogEntry, error) { + m := new(LogEntry) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *sensorServiceClient) WatchSensors(ctx context.Context, in *ListSensorsRequest, opts ...grpc.CallOption) (SensorService_WatchSensorsClient, error) { + stream, err := c.cc.NewStream(ctx, &_SensorService_serviceDesc.Streams[1], "/sensor.SensorService/WatchSensors", opts...) + if err != nil { + return nil, err + } + x := &sensorServiceWatchSensorsClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type SensorService_WatchSensorsClient interface { + Recv() (*SensorWatchEvent, error) + grpc.ClientStream +} + +type sensorServiceWatchSensorsClient struct { + grpc.ClientStream +} + +func (x *sensorServiceWatchSensorsClient) Recv() (*SensorWatchEvent, error) { + m := new(SensorWatchEvent) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// SensorServiceServer is the server API for SensorService service. +type SensorServiceServer interface { + ListSensors(context.Context, *ListSensorsRequest) (*v1alpha1.SensorList, error) + SensorsLogs(*SensorsLogsRequest, SensorService_SensorsLogsServer) error + WatchSensors(*ListSensorsRequest, SensorService_WatchSensorsServer) error +} + +// UnimplementedSensorServiceServer can be embedded to have forward compatible implementations. +type UnimplementedSensorServiceServer struct { +} + +func (*UnimplementedSensorServiceServer) ListSensors(ctx context.Context, req *ListSensorsRequest) (*v1alpha1.SensorList, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListSensors not implemented") +} +func (*UnimplementedSensorServiceServer) SensorsLogs(req *SensorsLogsRequest, srv SensorService_SensorsLogsServer) error { + return status.Errorf(codes.Unimplemented, "method SensorsLogs not implemented") +} +func (*UnimplementedSensorServiceServer) WatchSensors(req *ListSensorsRequest, srv SensorService_WatchSensorsServer) error { + return status.Errorf(codes.Unimplemented, "method WatchSensors not implemented") +} + +func RegisterSensorServiceServer(s *grpc.Server, srv SensorServiceServer) { + s.RegisterService(&_SensorService_serviceDesc, srv) +} + +func _SensorService_ListSensors_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListSensorsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SensorServiceServer).ListSensors(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/sensor.SensorService/ListSensors", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SensorServiceServer).ListSensors(ctx, req.(*ListSensorsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _SensorService_SensorsLogs_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(SensorsLogsRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(SensorServiceServer).SensorsLogs(m, &sensorServiceSensorsLogsServer{stream}) +} + +type SensorService_SensorsLogsServer interface { + Send(*LogEntry) error + grpc.ServerStream +} + +type sensorServiceSensorsLogsServer struct { + grpc.ServerStream +} + +func (x *sensorServiceSensorsLogsServer) Send(m *LogEntry) error { + return x.ServerStream.SendMsg(m) +} + +func _SensorService_WatchSensors_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(ListSensorsRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(SensorServiceServer).WatchSensors(m, &sensorServiceWatchSensorsServer{stream}) +} + +type SensorService_WatchSensorsServer interface { + Send(*SensorWatchEvent) error + grpc.ServerStream +} + +type sensorServiceWatchSensorsServer struct { + grpc.ServerStream +} + +func (x *sensorServiceWatchSensorsServer) Send(m *SensorWatchEvent) error { + return x.ServerStream.SendMsg(m) +} + +var _SensorService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "sensor.SensorService", + HandlerType: (*SensorServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ListSensors", + Handler: _SensorService_ListSensors_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "SensorsLogs", + Handler: _SensorService_SensorsLogs_Handler, + ServerStreams: true, + }, + { + StreamName: "WatchSensors", + Handler: _SensorService_WatchSensors_Handler, + ServerStreams: true, + }, + }, + Metadata: "pkg/apiclient/sensor/sensor.proto", +} + +func (m *ListSensorsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListSensorsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListSensorsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.ListOptions != nil { + { + size, err := m.ListOptions.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSensor(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Namespace) > 0 { + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintSensor(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *SensorsLogsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SensorsLogsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SensorsLogsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.PodLogOptions != nil { + { + size, err := m.PodLogOptions.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSensor(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if len(m.Grep) > 0 { + i -= len(m.Grep) + copy(dAtA[i:], m.Grep) + i = encodeVarintSensor(dAtA, i, uint64(len(m.Grep))) + i-- + dAtA[i] = 0x22 + } + if len(m.TriggerName) > 0 { + i -= len(m.TriggerName) + copy(dAtA[i:], m.TriggerName) + i = encodeVarintSensor(dAtA, i, uint64(len(m.TriggerName))) + i-- + dAtA[i] = 0x1a + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintSensor(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } + if len(m.Namespace) > 0 { + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintSensor(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *LogEntry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *LogEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *LogEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.EventContext) > 0 { + i -= len(m.EventContext) + copy(dAtA[i:], m.EventContext) + i = encodeVarintSensor(dAtA, i, uint64(len(m.EventContext))) + i-- + dAtA[i] = 0x4a + } + if len(m.DependencyName) > 0 { + i -= len(m.DependencyName) + copy(dAtA[i:], m.DependencyName) + i = encodeVarintSensor(dAtA, i, uint64(len(m.DependencyName))) + i-- + dAtA[i] = 0x42 + } + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintSensor(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0x3a + } + if m.Time != nil { + { + size, err := m.Time.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSensor(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + if len(m.Level) > 0 { + i -= len(m.Level) + copy(dAtA[i:], m.Level) + i = encodeVarintSensor(dAtA, i, uint64(len(m.Level))) + i-- + dAtA[i] = 0x2a + } + if len(m.TriggerName) > 0 { + i -= len(m.TriggerName) + copy(dAtA[i:], m.TriggerName) + i = encodeVarintSensor(dAtA, i, uint64(len(m.TriggerName))) + i-- + dAtA[i] = 0x1a + } + if len(m.SensorName) > 0 { + i -= len(m.SensorName) + copy(dAtA[i:], m.SensorName) + i = encodeVarintSensor(dAtA, i, uint64(len(m.SensorName))) + i-- + dAtA[i] = 0x12 + } + if len(m.Namespace) > 0 { + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintSensor(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *SensorWatchEvent) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SensorWatchEvent) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SensorWatchEvent) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Object != nil { + { + size, err := m.Object.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSensor(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Type) > 0 { + i -= len(m.Type) + copy(dAtA[i:], m.Type) + i = encodeVarintSensor(dAtA, i, uint64(len(m.Type))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintSensor(dAtA []byte, offset int, v uint64) int { + offset -= sovSensor(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ListSensorsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Namespace) + if l > 0 { + n += 1 + l + sovSensor(uint64(l)) + } + if m.ListOptions != nil { + l = m.ListOptions.Size() + n += 1 + l + sovSensor(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *SensorsLogsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Namespace) + if l > 0 { + n += 1 + l + sovSensor(uint64(l)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovSensor(uint64(l)) + } + l = len(m.TriggerName) + if l > 0 { + n += 1 + l + sovSensor(uint64(l)) + } + l = len(m.Grep) + if l > 0 { + n += 1 + l + sovSensor(uint64(l)) + } + if m.PodLogOptions != nil { + l = m.PodLogOptions.Size() + n += 1 + l + sovSensor(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *LogEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Namespace) + if l > 0 { + n += 1 + l + sovSensor(uint64(l)) + } + l = len(m.SensorName) + if l > 0 { + n += 1 + l + sovSensor(uint64(l)) + } + l = len(m.TriggerName) + if l > 0 { + n += 1 + l + sovSensor(uint64(l)) + } + l = len(m.Level) + if l > 0 { + n += 1 + l + sovSensor(uint64(l)) + } + if m.Time != nil { + l = m.Time.Size() + n += 1 + l + sovSensor(uint64(l)) + } + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovSensor(uint64(l)) + } + l = len(m.DependencyName) + if l > 0 { + n += 1 + l + sovSensor(uint64(l)) + } + l = len(m.EventContext) + if l > 0 { + n += 1 + l + sovSensor(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *SensorWatchEvent) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Type) + if l > 0 { + n += 1 + l + sovSensor(uint64(l)) + } + if m.Object != nil { + l = m.Object.Size() + n += 1 + l + sovSensor(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovSensor(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozSensor(x uint64) (n int) { + return sovSensor(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ListSensorsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ListSensorsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ListSensorsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Namespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ListOptions", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ListOptions == nil { + m.ListOptions = &v1.ListOptions{} + } + if err := m.ListOptions.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSensor(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthSensor + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthSensor + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SensorsLogsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SensorsLogsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SensorsLogsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Namespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TriggerName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TriggerName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Grep", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Grep = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PodLogOptions", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.PodLogOptions == nil { + m.PodLogOptions = &v11.PodLogOptions{} + } + if err := m.PodLogOptions.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSensor(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthSensor + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthSensor + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *LogEntry) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: LogEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LogEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Namespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SensorName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SensorName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TriggerName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TriggerName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Level", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Level = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Time", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Time == nil { + m.Time = &v1.Time{} + } + if err := m.Time.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msg = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DependencyName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DependencyName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EventContext", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EventContext = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSensor(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthSensor + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthSensor + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SensorWatchEvent) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SensorWatchEvent: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SensorWatchEvent: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Type = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Object", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSensor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSensor + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSensor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Object == nil { + m.Object = &v1alpha1.Sensor{} + } + if err := m.Object.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSensor(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthSensor + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthSensor + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipSensor(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSensor + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSensor + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSensor + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthSensor + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupSensor + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthSensor + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthSensor = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowSensor = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupSensor = fmt.Errorf("proto: unexpected end of group") +) diff --git a/pkg/apiclient/sensor/sensor.pb.gw.go b/pkg/apiclient/sensor/sensor.pb.gw.go new file mode 100644 index 000000000000..8fe2b617846c --- /dev/null +++ b/pkg/apiclient/sensor/sensor.pb.gw.go @@ -0,0 +1,352 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: pkg/apiclient/sensor/sensor.proto + +/* +Package sensor is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package sensor + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage + +var ( + filter_SensorService_ListSensors_0 = &utilities.DoubleArray{Encoding: map[string]int{"namespace": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_SensorService_ListSensors_0(ctx context.Context, marshaler runtime.Marshaler, client SensorServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ListSensorsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["namespace"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") + } + + protoReq.Namespace, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SensorService_ListSensors_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ListSensors(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_SensorService_ListSensors_0(ctx context.Context, marshaler runtime.Marshaler, server SensorServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ListSensorsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["namespace"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") + } + + protoReq.Namespace, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) + } + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_SensorService_ListSensors_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.ListSensors(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_SensorService_SensorsLogs_0 = &utilities.DoubleArray{Encoding: map[string]int{"namespace": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_SensorService_SensorsLogs_0(ctx context.Context, marshaler runtime.Marshaler, client SensorServiceClient, req *http.Request, pathParams map[string]string) (SensorService_SensorsLogsClient, runtime.ServerMetadata, error) { + var protoReq SensorsLogsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["namespace"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") + } + + protoReq.Namespace, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SensorService_SensorsLogs_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + stream, err := client.SensorsLogs(ctx, &protoReq) + if err != nil { + return nil, metadata, err + } + header, err := stream.Header() + if err != nil { + return nil, metadata, err + } + metadata.HeaderMD = header + return stream, metadata, nil + +} + +var ( + filter_SensorService_WatchSensors_0 = &utilities.DoubleArray{Encoding: map[string]int{"namespace": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_SensorService_WatchSensors_0(ctx context.Context, marshaler runtime.Marshaler, client SensorServiceClient, req *http.Request, pathParams map[string]string) (SensorService_WatchSensorsClient, runtime.ServerMetadata, error) { + var protoReq ListSensorsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["namespace"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") + } + + protoReq.Namespace, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SensorService_WatchSensors_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + stream, err := client.WatchSensors(ctx, &protoReq) + if err != nil { + return nil, metadata, err + } + header, err := stream.Header() + if err != nil { + return nil, metadata, err + } + metadata.HeaderMD = header + return stream, metadata, nil + +} + +// RegisterSensorServiceHandlerServer registers the http handlers for service SensorService to "mux". +// UnaryRPC :call SensorServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +func RegisterSensorServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server SensorServiceServer) error { + + mux.Handle("GET", pattern_SensorService_ListSensors_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_SensorService_ListSensors_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_SensorService_ListSensors_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_SensorService_SensorsLogs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + err := status.Error(codes.Unimplemented, "streaming calls are not yet supported in the in-process transport") + _, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + }) + + mux.Handle("GET", pattern_SensorService_WatchSensors_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + err := status.Error(codes.Unimplemented, "streaming calls are not yet supported in the in-process transport") + _, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + }) + + return nil +} + +// RegisterSensorServiceHandlerFromEndpoint is same as RegisterSensorServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterSensorServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterSensorServiceHandler(ctx, mux, conn) +} + +// RegisterSensorServiceHandler registers the http handlers for service SensorService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterSensorServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterSensorServiceHandlerClient(ctx, mux, NewSensorServiceClient(conn)) +} + +// RegisterSensorServiceHandlerClient registers the http handlers for service SensorService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "SensorServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "SensorServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "SensorServiceClient" to call the correct interceptors. +func RegisterSensorServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client SensorServiceClient) error { + + mux.Handle("GET", pattern_SensorService_ListSensors_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_SensorService_ListSensors_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_SensorService_ListSensors_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_SensorService_SensorsLogs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_SensorService_SensorsLogs_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_SensorService_SensorsLogs_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_SensorService_WatchSensors_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_SensorService_WatchSensors_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_SensorService_WatchSensors_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_SensorService_ListSensors_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "sensors", "namespace"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_SensorService_SensorsLogs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"api", "v1", "stream", "sensors", "namespace", "logs"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_SensorService_WatchSensors_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"api", "v1", "stream", "sensors", "namespace"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_SensorService_ListSensors_0 = runtime.ForwardResponseMessage + + forward_SensorService_SensorsLogs_0 = runtime.ForwardResponseStream + + forward_SensorService_WatchSensors_0 = runtime.ForwardResponseStream +) diff --git a/pkg/apiclient/sensor/sensor.proto b/pkg/apiclient/sensor/sensor.proto new file mode 100644 index 000000000000..4d3febca280d --- /dev/null +++ b/pkg/apiclient/sensor/sensor.proto @@ -0,0 +1,57 @@ +syntax = "proto3"; +option go_package = "github.com/argoproj/argo/pkg/apiclient/sensor"; + +import "google/api/annotations.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/api/core/v1/generated.proto"; +import "github.com/argoproj/argo-events/pkg/apis/sensor/v1alpha1/generated.proto"; + +package sensor; + +message ListSensorsRequest { + string namespace = 1; + k8s.io.apimachinery.pkg.apis.meta.v1.ListOptions listOptions = 2; +} + +message SensorsLogsRequest { + string namespace = 1; + // optional - only return entries for this sensor name + string name = 2; + // optional - only return entries for this trigger + string triggerName = 3; + // option - only return entries where `msg` contains this regular expressions + string grep = 4; + k8s.io.api.core.v1.PodLogOptions podLogOptions = 5; +} + +// structured log entry +message LogEntry { + string namespace = 1; + string sensorName = 2; + // optional - any trigger name + string triggerName = 3; + string level = 5; + k8s.io.apimachinery.pkg.apis.meta.v1.Time time = 6; + string msg = 7; + // optional - trigger dependency name + string dependencyName = 8; + // optional - Cloud Event context + string eventContext = 9; +} + +message SensorWatchEvent { + string type = 1; + github.com.argoproj.argo_events.pkg.apis.sensor.v1alpha1.Sensor object = 2; +} + +service SensorService { + rpc ListSensors (ListSensorsRequest) returns (github.com.argoproj.argo_events.pkg.apis.sensor.v1alpha1.SensorList) { + option (google.api.http).get = "/api/v1/sensors/{namespace}"; + } + rpc SensorsLogs (SensorsLogsRequest) returns (stream LogEntry) { + option (google.api.http).get = "/api/v1/stream/sensors/{namespace}/logs"; + } + rpc WatchSensors (ListSensorsRequest) returns (stream SensorWatchEvent) { + option (google.api.http).get = "/api/v1/stream/sensors/{namespace}"; + } +} \ No newline at end of file diff --git a/server/apiserver/argoserver.go b/server/apiserver/argoserver.go index 66412d02c244..9e496db92b9b 100644 --- a/server/apiserver/argoserver.go +++ b/server/apiserver/argoserver.go @@ -16,7 +16,6 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials" "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "github.com/argoproj/argo" @@ -25,12 +24,13 @@ import ( clusterwftemplatepkg "github.com/argoproj/argo/pkg/apiclient/clusterworkflowtemplate" cronworkflowpkg "github.com/argoproj/argo/pkg/apiclient/cronworkflow" eventpkg "github.com/argoproj/argo/pkg/apiclient/event" + eventsourcepkg "github.com/argoproj/argo/pkg/apiclient/eventsource" infopkg "github.com/argoproj/argo/pkg/apiclient/info" + sensorpkg "github.com/argoproj/argo/pkg/apiclient/sensor" workflowpkg "github.com/argoproj/argo/pkg/apiclient/workflow" workflowarchivepkg "github.com/argoproj/argo/pkg/apiclient/workflowarchive" workflowtemplatepkg "github.com/argoproj/argo/pkg/apiclient/workflowtemplate" "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" - "github.com/argoproj/argo/pkg/client/clientset/versioned" "github.com/argoproj/argo/server/artifacts" "github.com/argoproj/argo/server/auth" "github.com/argoproj/argo/server/auth/sso" @@ -38,8 +38,11 @@ import ( "github.com/argoproj/argo/server/clusterworkflowtemplate" "github.com/argoproj/argo/server/cronworkflow" "github.com/argoproj/argo/server/event" + "github.com/argoproj/argo/server/eventsource" "github.com/argoproj/argo/server/info" + "github.com/argoproj/argo/server/sensor" "github.com/argoproj/argo/server/static" + "github.com/argoproj/argo/server/types" "github.com/argoproj/argo/server/workflow" "github.com/argoproj/argo/server/workflowarchive" "github.com/argoproj/argo/server/workflowtemplate" @@ -63,8 +66,7 @@ type argoServer struct { hsts bool namespace string managedNamespace string - kubeClientset *kubernetes.Clientset - wfClientSet *versioned.Clientset + clients *types.Clients gatekeeper auth.Gatekeeper oAuth2Service sso.Interface configController config.Controller @@ -75,13 +77,12 @@ type argoServer struct { } type ArgoServerOpts struct { - BaseHRef string - TLSConfig *tls.Config - Namespace string - KubeClientset *kubernetes.Clientset - WfClientSet *versioned.Clientset - RestConfig *rest.Config - AuthModes auth.Modes + BaseHRef string + TLSConfig *tls.Config + Namespace string + Clients *types.Clients + RestConfig *rest.Config + AuthModes auth.Modes // config map name ConfigName string ManagedNamespace string @@ -92,14 +93,14 @@ type ArgoServerOpts struct { } func NewArgoServer(opts ArgoServerOpts) (*argoServer, error) { - configController := config.NewController(opts.Namespace, opts.ConfigName, opts.KubeClientset, emptyConfigFunc) + configController := config.NewController(opts.Namespace, opts.ConfigName, opts.Clients.Kubernetes, emptyConfigFunc) ssoIf := sso.NullSSO if opts.AuthModes[auth.SSO] { c, err := configController.Get() if err != nil { return nil, err } - ssoIf, err = sso.New(c.(*Config).SSO, opts.KubeClientset.CoreV1().Secrets(opts.Namespace), opts.BaseHRef, opts.TLSConfig != nil) + ssoIf, err = sso.New(c.(*Config).SSO, opts.Clients.Kubernetes.CoreV1().Secrets(opts.Namespace), opts.BaseHRef, opts.TLSConfig != nil) if err != nil { return nil, err } @@ -107,7 +108,7 @@ func NewArgoServer(opts ArgoServerOpts) (*argoServer, error) { } else { log.Info("SSO disabled") } - gatekeeper, err := auth.NewGatekeeper(opts.AuthModes, opts.WfClientSet, opts.KubeClientset, opts.RestConfig, ssoIf, auth.DefaultClientForAuthorization, opts.Namespace) + gatekeeper, err := auth.NewGatekeeper(opts.AuthModes, opts.Clients, opts.RestConfig, ssoIf, auth.DefaultClientForAuthorization, opts.Namespace) if err != nil { return nil, err } @@ -117,8 +118,7 @@ func NewArgoServer(opts ArgoServerOpts) (*argoServer, error) { hsts: opts.HSTS, namespace: opts.Namespace, managedNamespace: opts.ManagedNamespace, - wfClientSet: opts.WfClientSet, - kubeClientset: opts.KubeClientset, + clients: opts.Clients, gatekeeper: gatekeeper, oAuth2Service: ssoIf, configController: configController, @@ -148,7 +148,7 @@ func (as *argoServer) Run(ctx context.Context, port int, browserOpenFunc func(st var wfArchive = sqldb.NullWorkflowArchive persistence := config.Persistence if persistence != nil { - session, tableName, err := sqldb.CreateDBSession(as.kubeClientset, as.namespace, persistence) + session, tableName, err := sqldb.CreateDBSession(as.clients.Kubernetes, as.namespace, persistence) if err != nil { log.Fatal(err) } @@ -162,8 +162,8 @@ func (as *argoServer) Run(ctx context.Context, port int, browserOpenFunc func(st // disable the archiving - and still read old records wfArchive = sqldb.NewWorkflowArchive(session, persistence.GetClusterName(), as.managedNamespace, instanceIDService) } - eventRecorderManager := events.NewEventRecorderManager(as.kubeClientset) - artifactRepositories := artifactrepositories.New(as.kubeClientset, as.managedNamespace, &config.ArtifactRepository) + eventRecorderManager := events.NewEventRecorderManager(as.clients.Kubernetes) + artifactRepositories := artifactrepositories.New(as.clients.Kubernetes, as.managedNamespace, &config.ArtifactRepository) artifactServer := artifacts.NewArtifactServer(as.gatekeeper, hydrator.New(offloadRepo), wfArchive, instanceIDService, artifactRepositories) eventServer := event.NewController(instanceIDService, eventRecorderManager, as.eventQueueSize, as.eventWorkerCount) grpcServer := as.newGRPCServer(instanceIDService, offloadRepo, wfArchive, eventServer, config.Links) @@ -237,6 +237,8 @@ func (as *argoServer) newGRPCServer(instanceIDService instanceid.Service, offloa infopkg.RegisterInfoServiceServer(grpcServer, info.NewInfoServer(as.managedNamespace, links)) eventpkg.RegisterEventServiceServer(grpcServer, eventServer) + eventsourcepkg.RegisterEventSourceServiceServer(grpcServer, eventsource.NewEventSourceServer()) + sensorpkg.RegisterSensorServiceServer(grpcServer, sensor.NewSensorServer()) workflowpkg.RegisterWorkflowServiceServer(grpcServer, workflow.NewWorkflowServer(instanceIDService, offloadNodeStatusRepo)) workflowtemplatepkg.RegisterWorkflowTemplateServiceServer(grpcServer, workflowtemplate.NewWorkflowTemplateServer(instanceIDService)) cronworkflowpkg.RegisterCronWorkflowServiceServer(grpcServer, cronworkflow.NewCronWorkflowServer(instanceIDService)) @@ -266,7 +268,7 @@ func (as *argoServer) newHTTPServer(ctx context.Context, port int, artifactServe dialOpts = append(dialOpts, grpc.WithInsecure()) } - webhookInterceptor := webhook.Interceptor(as.kubeClientset) + webhookInterceptor := webhook.Interceptor(as.clients.Kubernetes) // HTTP 1.1+JSON Server // grpc-ecosystem/grpc-gateway is used to proxy HTTP requests to the corresponding gRPC call @@ -281,6 +283,8 @@ func (as *argoServer) newHTTPServer(ctx context.Context, port int, artifactServe ) mustRegisterGWHandler(infopkg.RegisterInfoServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dialOpts) mustRegisterGWHandler(eventpkg.RegisterEventServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dialOpts) + mustRegisterGWHandler(eventsourcepkg.RegisterEventSourceServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dialOpts) + mustRegisterGWHandler(sensorpkg.RegisterSensorServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dialOpts) mustRegisterGWHandler(workflowpkg.RegisterWorkflowServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dialOpts) mustRegisterGWHandler(workflowtemplatepkg.RegisterWorkflowTemplateServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dialOpts) mustRegisterGWHandler(cronworkflowpkg.RegisterCronWorkflowServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dialOpts) diff --git a/server/auth/gatekeeper.go b/server/auth/gatekeeper.go index 00403413ae61..1531a88c2369 100644 --- a/server/auth/gatekeeper.go +++ b/server/auth/gatekeeper.go @@ -9,6 +9,8 @@ import ( "strconv" "github.com/antonmedv/expr" + eventsource "github.com/argoproj/argo-events/pkg/client/eventsource/clientset/versioned" + sensor "github.com/argoproj/argo-events/pkg/client/sensor/clientset/versioned" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" log "github.com/sirupsen/logrus" "google.golang.org/grpc" @@ -20,10 +22,11 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" - "github.com/argoproj/argo/pkg/client/clientset/versioned" + workflow "github.com/argoproj/argo/pkg/client/clientset/versioned" "github.com/argoproj/argo/server/auth/serviceaccount" "github.com/argoproj/argo/server/auth/sso" "github.com/argoproj/argo/server/auth/types" + servertypes "github.com/argoproj/argo/server/types" "github.com/argoproj/argo/util/kubeconfig" "github.com/argoproj/argo/workflow/common" ) @@ -31,9 +34,11 @@ import ( type ContextKey string const ( - WfKey ContextKey = "versioned.Interface" - KubeKey ContextKey = "kubernetes.Interface" - ClaimsKey ContextKey = "types.Claims" + WfKey ContextKey = "workflow.Interface" + SensorKey ContextKey = "sensor.Interface" + EventSourceKey ContextKey = "eventsource.Interface" + KubeKey ContextKey = "kubernetes.Interface" + ClaimsKey ContextKey = "types.Claims" ) //go:generate mockery -name Gatekeeper @@ -44,13 +49,12 @@ type Gatekeeper interface { StreamServerInterceptor() grpc.StreamServerInterceptor } -type ClientForAuthorization func(authorization string) (*rest.Config, versioned.Interface, kubernetes.Interface, error) +type ClientForAuthorization func(authorization string) (*rest.Config, *servertypes.Clients, error) type gatekeeper struct { Modes Modes // global clients, not to be used if there are better ones - wfClient versioned.Interface - kubeClient kubernetes.Interface + clients *servertypes.Clients restConfig *rest.Config ssoIf sso.Interface clientForAuthorization ClientForAuthorization @@ -58,11 +62,11 @@ type gatekeeper struct { namespace string } -func NewGatekeeper(modes Modes, wfClient versioned.Interface, kubeClient kubernetes.Interface, restConfig *rest.Config, ssoIf sso.Interface, clientForAuthorization ClientForAuthorization, namespace string) (Gatekeeper, error) { +func NewGatekeeper(modes Modes, clients *servertypes.Clients, restConfig *rest.Config, ssoIf sso.Interface, clientForAuthorization ClientForAuthorization, namespace string) (Gatekeeper, error) { if len(modes) == 0 { return nil, fmt.Errorf("must specify at least one auth mode") } - return &gatekeeper{modes, wfClient, kubeClient, restConfig, ssoIf, clientForAuthorization, namespace}, nil + return &gatekeeper{modes, clients, restConfig, ssoIf, clientForAuthorization, namespace}, nil } func (s *gatekeeper) UnaryServerInterceptor() grpc.UnaryServerInterceptor { @@ -88,15 +92,28 @@ func (s *gatekeeper) StreamServerInterceptor() grpc.StreamServerInterceptor { } func (s *gatekeeper) Context(ctx context.Context) (context.Context, error) { - wfClient, kubeClient, claims, err := s.getClients(ctx) + clients, claims, err := s.getClients(ctx) if err != nil { return nil, err } - return context.WithValue(context.WithValue(context.WithValue(ctx, WfKey, wfClient), KubeKey, kubeClient), ClaimsKey, claims), nil + ctx = context.WithValue(ctx, WfKey, clients.Workflow) + ctx = context.WithValue(ctx, EventSourceKey, clients.EventSource) + ctx = context.WithValue(ctx, SensorKey, clients.Sensor) + ctx = context.WithValue(ctx, KubeKey, clients.Kubernetes) + ctx = context.WithValue(ctx, ClaimsKey, claims) + return ctx, nil } -func GetWfClient(ctx context.Context) versioned.Interface { - return ctx.Value(WfKey).(versioned.Interface) +func GetWfClient(ctx context.Context) workflow.Interface { + return ctx.Value(WfKey).(workflow.Interface) +} + +func GetEventSourceClient(ctx context.Context) eventsource.Interface { + return ctx.Value(EventSourceKey).(eventsource.Interface) +} + +func GetSensorClient(ctx context.Context) sensor.Interface { + return ctx.Value(SensorKey).(sensor.Interface) } func GetKubeClient(ctx context.Context) kubernetes.Interface { @@ -126,48 +143,48 @@ func getAuthHeader(md metadata.MD) string { return "" } -func (s gatekeeper) getClients(ctx context.Context) (versioned.Interface, kubernetes.Interface, *types.Claims, error) { +func (s gatekeeper) getClients(ctx context.Context) (*servertypes.Clients, *types.Claims, error) { md, _ := metadata.FromIncomingContext(ctx) authorization := getAuthHeader(md) mode, valid := s.Modes.GetMode(authorization) if !valid { - return nil, nil, nil, status.Error(codes.Unauthenticated, "token not valid for running mode") + return nil, nil, status.Error(codes.Unauthenticated, "token not valid for running mode") } switch mode { case Client: - restConfig, wfClient, kubeClient, err := s.clientForAuthorization(authorization) + restConfig, clients, err := s.clientForAuthorization(authorization) if err != nil { - return nil, nil, nil, status.Error(codes.Unauthenticated, err.Error()) + return nil, nil, status.Error(codes.Unauthenticated, err.Error()) } claims, _ := serviceaccount.ClaimSetFor(restConfig) - return wfClient, kubeClient, claims, nil + return clients, claims, nil case Server: claims, _ := serviceaccount.ClaimSetFor(s.restConfig) - return s.wfClient, s.kubeClient, claims, nil + return s.clients, claims, nil case SSO: claims, err := s.ssoIf.Authorize(authorization) if err != nil { - return nil, nil, nil, status.Error(codes.Unauthenticated, err.Error()) + return nil, nil, status.Error(codes.Unauthenticated, err.Error()) } if s.ssoIf.IsRBACEnabled() { - v, k, err := s.rbacAuthorization(claims) + clients, err := s.rbacAuthorization(claims) if err != nil { log.WithError(err).Error("failed to perform RBAC authorization") - return nil, nil, nil, status.Error(codes.PermissionDenied, "not allowed") + return nil, nil, status.Error(codes.PermissionDenied, "not allowed") } - return v, k, claims, nil + return clients, claims, nil } else { - return s.wfClient, s.kubeClient, claims, nil + return s.clients, claims, nil } default: panic("this should never happen") } } -func (s *gatekeeper) rbacAuthorization(claims *types.Claims) (versioned.Interface, kubernetes.Interface, error) { - list, err := s.kubeClient.CoreV1().ServiceAccounts(s.namespace).List(metav1.ListOptions{}) +func (s *gatekeeper) rbacAuthorization(claims *types.Claims) (*servertypes.Clients, error) { + list, err := s.clients.Kubernetes.CoreV1().ServiceAccounts(s.namespace).List(metav1.ListOptions{}) if err != nil { - return nil, nil, fmt.Errorf("failed to list SSO RBAC service accounts: %w", err) + return nil, fmt.Errorf("failed to list SSO RBAC service accounts: %w", err) } var serviceAccounts []corev1.ServiceAccount for _, serviceAccount := range list.Items { @@ -186,65 +203,73 @@ func (s *gatekeeper) rbacAuthorization(claims *types.Claims) (versioned.Interfac rule := serviceAccount.Annotations[common.AnnotationKeyRBACRule] data, err := json.Marshal(claims) if err != nil { - return nil, nil, fmt.Errorf("failed to marshall claims: %w", err) + return nil, fmt.Errorf("failed to marshall claims: %w", err) } v := make(map[string]interface{}) err = json.Unmarshal(data, &v) if err != nil { - return nil, nil, fmt.Errorf("failed to unmarshall claims: %w", err) + return nil, fmt.Errorf("failed to unmarshall claims: %w", err) } result, err := expr.Eval(rule, v) if err != nil { - return nil, nil, fmt.Errorf("failed to evaluate rule: %w", err) + return nil, fmt.Errorf("failed to evaluate rule: %w", err) } allow, ok := result.(bool) if !ok { - return nil, nil, fmt.Errorf("failed to evaluate rule: not a boolean") + return nil, fmt.Errorf("failed to evaluate rule: not a boolean") } if !allow { continue } authorization, err := s.authorizationForServiceAccount(serviceAccount.Name) if err != nil { - return nil, nil, err + return nil, err } - _, wfClient, kubeClient, err := s.clientForAuthorization(authorization) + _, clients, err := s.clientForAuthorization(authorization) if err != nil { - return nil, nil, err + return nil, err } log.WithFields(log.Fields{"serviceAccount": serviceAccount.Name, "subject": claims.Subject}).Info("selected SSO RBAC service account for user") - return wfClient, kubeClient, nil + return clients, nil } - return nil, nil, fmt.Errorf("no service account rule matches") + return nil, fmt.Errorf("no service account rule matches") } func (s *gatekeeper) authorizationForServiceAccount(serviceAccountName string) (string, error) { - serviceAccount, err := s.kubeClient.CoreV1().ServiceAccounts(s.namespace).Get(serviceAccountName, metav1.GetOptions{}) + serviceAccount, err := s.clients.Kubernetes.CoreV1().ServiceAccounts(s.namespace).Get(serviceAccountName, metav1.GetOptions{}) if err != nil { return "", fmt.Errorf("failed to get service account: %w", err) } if len(serviceAccount.Secrets) == 0 { return "", fmt.Errorf("expected at least one secret for SSO RBAC service account: %w", err) } - secret, err := s.kubeClient.CoreV1().Secrets(s.namespace).Get(serviceAccount.Secrets[0].Name, metav1.GetOptions{}) + secret, err := s.clients.Kubernetes.CoreV1().Secrets(s.namespace).Get(serviceAccount.Secrets[0].Name, metav1.GetOptions{}) if err != nil { return "", fmt.Errorf("failed to get service account secret: %w", err) } return "Bearer " + string(secret.Data["token"]), nil } -func DefaultClientForAuthorization(authorization string) (*rest.Config, versioned.Interface, kubernetes.Interface, error) { +func DefaultClientForAuthorization(authorization string) (*rest.Config, *servertypes.Clients, error) { restConfig, err := kubeconfig.GetRestConfig(authorization) if err != nil { - return nil, nil, nil, fmt.Errorf("failed to create REST config: %w", err) + return nil, nil, fmt.Errorf("failed to create REST config: %w", err) + } + wfClient, err := workflow.NewForConfig(restConfig) + if err != nil { + return nil, nil, fmt.Errorf("failure to create workflow client: %w", err) + } + eventSourceClient, err := eventsource.NewForConfig(restConfig) + if err != nil { + return nil, nil, fmt.Errorf("failure to create event source client: %w", err) } - wfClient, err := versioned.NewForConfig(restConfig) + sensorClient, err := sensor.NewForConfig(restConfig) if err != nil { - return nil, nil, nil, fmt.Errorf("failure to create workflow client: %w", err) + return nil, nil, fmt.Errorf("failure to create sensor client: %w", err) } kubeClient, err := kubernetes.NewForConfig(restConfig) if err != nil { - return nil, nil, nil, fmt.Errorf("failure to create kubernetes client: %w", err) + return nil, nil, fmt.Errorf("failure to create kubernetes client: %w", err) } - return restConfig, wfClient, kubeClient, nil + return restConfig, &servertypes.Clients{Workflow: wfClient, EventSource: eventSourceClient, Sensor: sensorClient, Kubernetes: kubeClient}, nil } diff --git a/server/auth/gatekeeper_test.go b/server/auth/gatekeeper_test.go index 54267ea654c6..19e125cbc694 100644 --- a/server/auth/gatekeeper_test.go +++ b/server/auth/gatekeeper_test.go @@ -13,14 +13,13 @@ import ( "gopkg.in/square/go-jose.v2/jwt" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" kubefake "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/rest" - "github.com/argoproj/argo/pkg/client/clientset/versioned" fakewfclientset "github.com/argoproj/argo/pkg/client/clientset/versioned/fake" ssomocks "github.com/argoproj/argo/server/auth/sso/mocks" "github.com/argoproj/argo/server/auth/types" + servertypes "github.com/argoproj/argo/server/types" "github.com/argoproj/argo/workflow/common" ) @@ -57,29 +56,30 @@ func TestServer_GetWFClient(t *testing.T) { }, }, ) - var clientForAuthorization ClientForAuthorization = func(authorization string) (*rest.Config, versioned.Interface, kubernetes.Interface, error) { - return &rest.Config{}, &fakewfclientset.Clientset{}, &kubefake.Clientset{}, nil + var clientForAuthorization ClientForAuthorization = func(authorization string) (*rest.Config, *servertypes.Clients, error) { + return &rest.Config{}, &servertypes.Clients{Workflow: &fakewfclientset.Clientset{}, Kubernetes: &kubefake.Clientset{}}, nil } + clients := &servertypes.Clients{Workflow: wfClient, Kubernetes: kubeClient} t.Run("None", func(t *testing.T) { - _, err := NewGatekeeper(Modes{}, wfClient, kubeClient, nil, nil, clientForAuthorization, "") + _, err := NewGatekeeper(Modes{}, clients, nil, nil, clientForAuthorization, "") assert.Error(t, err) }) t.Run("Invalid", func(t *testing.T) { - g, err := NewGatekeeper(Modes{Client: true}, wfClient, kubeClient, nil, nil, clientForAuthorization, "") + g, err := NewGatekeeper(Modes{Client: true}, clients, nil, nil, clientForAuthorization, "") if assert.NoError(t, err) { _, err := g.Context(x("invalid")) assert.Error(t, err) } }) t.Run("NotAllowed", func(t *testing.T) { - g, err := NewGatekeeper(Modes{SSO: true}, wfClient, kubeClient, nil, nil, clientForAuthorization, "") + g, err := NewGatekeeper(Modes{SSO: true}, clients, nil, nil, clientForAuthorization, "") if assert.NoError(t, err) { _, err := g.Context(x("Bearer ")) assert.Error(t, err) } }) t.Run("Client", func(t *testing.T) { - g, err := NewGatekeeper(Modes{Client: true}, wfClient, kubeClient, &rest.Config{Username: "my-username"}, nil, clientForAuthorization, "") + g, err := NewGatekeeper(Modes{Client: true}, clients, &rest.Config{Username: "my-username"}, nil, clientForAuthorization, "") assert.NoError(t, err) ctx, err := g.Context(x("Bearer ")) if assert.NoError(t, err) { @@ -89,7 +89,7 @@ func TestServer_GetWFClient(t *testing.T) { } }) t.Run("Server", func(t *testing.T) { - g, err := NewGatekeeper(Modes{Server: true}, wfClient, kubeClient, &rest.Config{Username: "my-username"}, nil, clientForAuthorization, "") + g, err := NewGatekeeper(Modes{Server: true}, clients, &rest.Config{Username: "my-username"}, nil, clientForAuthorization, "") assert.NoError(t, err) ctx, err := g.Context(x("")) if assert.NoError(t, err) { @@ -102,7 +102,7 @@ func TestServer_GetWFClient(t *testing.T) { ssoIf := &ssomocks.Interface{} ssoIf.On("Authorize", mock.Anything, mock.Anything).Return(&types.Claims{Claims: jwt.Claims{Subject: "my-sub"}}, nil) ssoIf.On("IsRBACEnabled").Return(false) - g, err := NewGatekeeper(Modes{SSO: true}, wfClient, kubeClient, nil, ssoIf, clientForAuthorization, "my-ns") + g, err := NewGatekeeper(Modes{SSO: true}, clients, nil, ssoIf, clientForAuthorization, "my-ns") if assert.NoError(t, err) { ctx, err := g.Context(x("Bearer v2:whatever")) if assert.NoError(t, err) { @@ -121,11 +121,11 @@ func TestServer_GetWFClient(t *testing.T) { ssoIf := &ssomocks.Interface{} ssoIf.On("Authorize", mock.Anything, mock.Anything).Return(&types.Claims{Groups: []string{"my-group", "other-group"}}, nil) ssoIf.On("IsRBACEnabled").Return(true) - g, err := NewGatekeeper(Modes{SSO: true}, wfClient, kubeClient, nil, ssoIf, clientForAuthorization, "my-ns") + g, err := NewGatekeeper(Modes{SSO: true}, clients, nil, ssoIf, clientForAuthorization, "my-ns") if assert.NoError(t, err) { ctx, err := g.Context(x("Bearer v2:whatever")) if assert.NoError(t, err) { - assert.NotEqual(t, wfClient, GetWfClient(ctx)) + assert.NotEqual(t, clients, GetWfClient(ctx)) assert.NotEqual(t, kubeClient, GetKubeClient(ctx)) if assert.NotNil(t, GetClaims(ctx)) { assert.Equal(t, []string{"my-group", "other-group"}, GetClaims(ctx).Groups) @@ -138,7 +138,7 @@ func TestServer_GetWFClient(t *testing.T) { ssoIf := &ssomocks.Interface{} ssoIf.On("Authorize", mock.Anything, mock.Anything).Return(&types.Claims{Groups: []string{"other-group"}}, nil) ssoIf.On("IsRBACEnabled").Return(true) - g, err := NewGatekeeper(Modes{SSO: true}, wfClient, kubeClient, nil, ssoIf, clientForAuthorization, "my-ns") + g, err := NewGatekeeper(Modes{SSO: true}, clients, nil, ssoIf, clientForAuthorization, "my-ns") if assert.NoError(t, err) { _, err := g.Context(x("Bearer v2:whatever")) if assert.NoError(t, err) { @@ -150,7 +150,7 @@ func TestServer_GetWFClient(t *testing.T) { ssoIf := &ssomocks.Interface{} ssoIf.On("Authorize", mock.Anything, mock.Anything).Return(&types.Claims{}, nil) ssoIf.On("IsRBACEnabled").Return(true) - g, err := NewGatekeeper(Modes{SSO: true}, wfClient, kubeClient, nil, ssoIf, clientForAuthorization, "my-ns") + g, err := NewGatekeeper(Modes{SSO: true}, clients, nil, ssoIf, clientForAuthorization, "my-ns") if assert.NoError(t, err) { _, err := g.Context(x("Bearer v2:whatever")) assert.EqualError(t, err, "rpc error: code = PermissionDenied desc = not allowed") diff --git a/server/event/event_server.go b/server/event/event_server.go index 5adcdfd91089..7bb94b366c7e 100644 --- a/server/event/event_server.go +++ b/server/event/event_server.go @@ -5,10 +5,11 @@ import ( "sync" log "github.com/sirupsen/logrus" - "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" eventpkg "github.com/argoproj/argo/pkg/apiclient/event" + wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo/server/auth" "github.com/argoproj/argo/server/event/dispatch" "github.com/argoproj/argo/util/instanceid" @@ -82,6 +83,14 @@ func (s *Controller) ReceiveEvent(ctx context.Context, req *eventpkg.EventReques case s.operationQueue <- *operation: return &eventpkg.EventResponse{}, nil default: - return nil, errors.NewServiceUnavailable("operation queue full") + return nil, apierrors.NewServiceUnavailable("operation queue full") } } + +func (s *Controller) ListWorkflowEventBindings(ctx context.Context, in *eventpkg.ListWorkflowEventBindingsRequest) (*wfv1.WorkflowEventBindingList, error) { + listOptions := metav1.ListOptions{} + if in.ListOptions != nil { + listOptions = *in.ListOptions + } + return auth.GetWfClient(ctx).ArgoprojV1alpha1().WorkflowEventBindings(in.Namespace).List(listOptions) +} diff --git a/server/eventsource/event_source_server.go b/server/eventsource/event_source_server.go new file mode 100644 index 000000000000..27484218c7a2 --- /dev/null +++ b/server/eventsource/event_source_server.go @@ -0,0 +1,102 @@ +package eventsource + +import ( + "context" + "encoding/json" + "fmt" + "regexp" + + esv1 "github.com/argoproj/argo-events/pkg/apis/eventsource/v1alpha1" + corev1 "k8s.io/api/core/v1" + apierr "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/watch" + + eventsourcepkg "github.com/argoproj/argo/pkg/apiclient/eventsource" + "github.com/argoproj/argo/server/auth" + "github.com/argoproj/argo/util/logs" +) + +type eventSourceServer struct{} + +func (e *eventSourceServer) ListEventSources(ctx context.Context, in *eventsourcepkg.ListEventSourcesRequest) (*esv1.EventSourceList, error) { + client := auth.GetEventSourceClient(ctx) + list, err := client.ArgoprojV1alpha1().EventSources(in.Namespace).List(metav1.ListOptions{}) + if err != nil { + return nil, err + } + return list, nil +} + +func (e *eventSourceServer) EventSourcesLogs(in *eventsourcepkg.EventSourcesLogsRequest, svr eventsourcepkg.EventSourceService_EventSourcesLogsServer) error { + listOptions := metav1.ListOptions{LabelSelector: "eventsource-name"} + if in.Name != "" { + listOptions.LabelSelector += "=" + in.Name + } + grep, err := regexp.Compile(in.Grep) + if err != nil { + return err + } + return logs.LogPods( + svr.Context(), + in.Namespace, + listOptions, + in.PodLogOptions, + func(pod *corev1.Pod, data []byte) error { + now := metav1.Now() + e := &eventsourcepkg.LogEntry{ + Namespace: pod.Namespace, + EventSourceName: pod.Labels["eventsource-name"], + Level: "info", + Time: &now, + Msg: string(data), + } + _ = json.Unmarshal(data, e) + if in.EventSourceType != "" && in.EventSourceType != e.EventSourceType { + return nil + } + if in.EventName != "" && in.EventName != e.EventName { + return nil + } + if !grep.MatchString(e.Msg) { + return nil + } + return svr.Send(e) + }, + ) +} + +func (e *eventSourceServer) WatchEventSources(in *eventsourcepkg.ListEventSourcesRequest, srv eventsourcepkg.EventSourceService_WatchEventSourcesServer) error { + ctx := srv.Context() + listOptions := metav1.ListOptions{} + if in.ListOptions != nil { + listOptions = *in.ListOptions + } + eventSourceInterface := auth.GetEventSourceClient(ctx).ArgoprojV1alpha1().EventSources(in.Namespace) + watcher, err := watch.NewRetryWatcher(listOptions.ResourceVersion, eventSourceInterface) + if err != nil { + return err + } + for { + select { + case <-ctx.Done(): + return nil + case event, ok := <-watcher.ResultChan(): + if !ok { + return fmt.Errorf("failed to read event") + } + es, ok := event.Object.(*esv1.EventSource) + if !ok { + return apierr.FromObject(event.Object) + } + err := srv.Send(&eventsourcepkg.EventSourceWatchEvent{Type: string(event.Type), Object: es}) + if err != nil { + return err + } + } + } +} + +func NewEventSourceServer() eventsourcepkg.EventSourceServiceServer { + return &eventSourceServer{} +} diff --git a/server/sensor/sensor_server.go b/server/sensor/sensor_server.go new file mode 100644 index 000000000000..cbe1e36be419 --- /dev/null +++ b/server/sensor/sensor_server.go @@ -0,0 +1,100 @@ +package sensor + +import ( + "context" + "encoding/json" + "fmt" + "regexp" + + esv1 "github.com/argoproj/argo-events/pkg/apis/sensor/v1alpha1" + sv1 "github.com/argoproj/argo-events/pkg/apis/sensor/v1alpha1" + corev1 "k8s.io/api/core/v1" + apierr "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/watch" + + sensorpkg "github.com/argoproj/argo/pkg/apiclient/sensor" + "github.com/argoproj/argo/server/auth" + "github.com/argoproj/argo/util/logs" +) + +type sensorServer struct{} + +func (s *sensorServer) ListSensors(ctx context.Context, in *sensorpkg.ListSensorsRequest) (*sv1.SensorList, error) { + client := auth.GetSensorClient(ctx) + list, err := client.ArgoprojV1alpha1().Sensors(in.Namespace).List(metav1.ListOptions{}) + if err != nil { + return nil, err + } + return list, nil +} + +func (s *sensorServer) SensorsLogs(in *sensorpkg.SensorsLogsRequest, svr sensorpkg.SensorService_SensorsLogsServer) error { + listOptions := metav1.ListOptions{LabelSelector: "sensor-name"} + if in.Name != "" { + listOptions.LabelSelector += "=" + in.Name + } + grep, err := regexp.Compile(in.Grep) + if err != nil { + return err + } + return logs.LogPods( + svr.Context(), + in.Namespace, + listOptions, + in.PodLogOptions, + func(pod *corev1.Pod, data []byte) error { + now := metav1.Now() + e := &sensorpkg.LogEntry{ + Namespace: pod.Namespace, + SensorName: pod.Labels["sensor-name"], + Level: "info", + Time: &now, + Msg: string(data), + } + _ = json.Unmarshal(data, e) + if in.TriggerName != "" && in.TriggerName != e.TriggerName { + return nil + } + + if !grep.MatchString(e.Msg) { + return nil + } + return svr.Send(e) + }, + ) +} + +func (e *sensorServer) WatchSensors(in *sensorpkg.ListSensorsRequest, srv sensorpkg.SensorService_WatchSensorsServer) error { + ctx := srv.Context() + listOptions := metav1.ListOptions{} + if in.ListOptions != nil { + listOptions = *in.ListOptions + } + eventSourceInterface := auth.GetSensorClient(ctx).ArgoprojV1alpha1().Sensors(in.Namespace) + watcher, err := watch.NewRetryWatcher(listOptions.ResourceVersion, eventSourceInterface) + if err != nil { + return err + } + for { + select { + case <-ctx.Done(): + return nil + case event, ok := <-watcher.ResultChan(): + if !ok { + return fmt.Errorf("failed to read event") + } + es, ok := event.Object.(*esv1.Sensor) + if !ok { + return apierr.FromObject(event.Object) + } + err := srv.Send(&sensorpkg.SensorWatchEvent{Type: string(event.Type), Object: es}) + if err != nil { + return err + } + } + } +} +func NewSensorServer() sensorpkg.SensorServiceServer { + return &sensorServer{} +} diff --git a/server/types/clients.go b/server/types/clients.go new file mode 100644 index 000000000000..e357e086d412 --- /dev/null +++ b/server/types/clients.go @@ -0,0 +1,17 @@ +package types + +import ( + "k8s.io/client-go/kubernetes" + + eventsource "github.com/argoproj/argo-events/pkg/client/eventsource/clientset/versioned" + sensor "github.com/argoproj/argo-events/pkg/client/sensor/clientset/versioned" + + workflow "github.com/argoproj/argo/pkg/client/clientset/versioned" +) + +type Clients struct { + Workflow workflow.Interface + Sensor sensor.Interface + EventSource eventsource.Interface + Kubernetes kubernetes.Interface +} diff --git a/test/e2e/manifests/events/kustomization.yaml b/test/e2e/manifests/events/kustomization.yaml new file mode 100644 index 000000000000..4669ae56dec5 --- /dev/null +++ b/test/e2e/manifests/events/kustomization.yaml @@ -0,0 +1,19 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- ../../../../manifests/quick-start/minimal +- https://raw.githubusercontent.com/argoproj/argo-events/stable/manifests/install.yaml +- https://raw.githubusercontent.com/argoproj/argo-events/stable/examples/eventbus/native.yaml +- https://raw.githubusercontent.com/argoproj/argo-events/stable/examples/event-sources/calendar.yaml +- https://raw.githubusercontent.com/argoproj/argo-events/stable/examples/sensors/calendar.yaml + +patchesStrategicMerge: +- ../mixins/argo-server-deployment.yaml +- ../mixins/workflow-controller-configmap.yaml +- ../mixins/workflow-controller-deployment.yaml +- ../mixins/cluster-workflow-template-rbac.yaml + +commonLabels: + app.kubernetes.io/part-of: argo +namespace: argo diff --git a/test/e2e/manifests/minimal/kustomization.yaml b/test/e2e/manifests/minimal/kustomization.yaml index 67314bc19167..e01b93121ae9 100644 --- a/test/e2e/manifests/minimal/kustomization.yaml +++ b/test/e2e/manifests/minimal/kustomization.yaml @@ -2,13 +2,14 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - - ../../../../manifests/quick-start/minimal +- ../../../../manifests/quick-start/minimal patchesStrategicMerge: - - ../mixins/argo-server-deployment.yaml - - ../mixins/workflow-controller-configmap.yaml - - ../mixins/workflow-controller-deployment.yaml - - ../mixins/cluster-workflow-template-rbac.yaml +- ../mixins/argo-server-deployment.yaml +- ../mixins/workflow-controller-configmap.yaml +- ../mixins/workflow-controller-deployment.yaml +- ../mixins/cluster-workflow-template-rbac.yaml commonLabels: - "app.kubernetes.io/part-of": "argo" + app.kubernetes.io/part-of: argo +namespace: argo diff --git a/test/e2e/manifests/mixins/workflow-controller-configmap.yaml b/test/e2e/manifests/mixins/workflow-controller-configmap.yaml index e6a3d6f83684..f5a9b9173457 100644 --- a/test/e2e/manifests/mixins/workflow-controller-configmap.yaml +++ b/test/e2e/manifests/mixins/workflow-controller-configmap.yaml @@ -4,6 +4,11 @@ metadata: name: workflow-controller-configmap data: containerRuntimeExecutor: pns + workflowDefaults: | + spec: + activeDeadlineSeconds: 300 + ttlStrategy: + secondsAfterCompletion: 600 executor: | imagePullPolicy: IfNotPresent resources: diff --git a/test/e2e/manifests/mysql/kustomization.yaml b/test/e2e/manifests/mysql/kustomization.yaml index 7c7e873be54b..ebf915807616 100644 --- a/test/e2e/manifests/mysql/kustomization.yaml +++ b/test/e2e/manifests/mysql/kustomization.yaml @@ -2,13 +2,14 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - - ../../../../manifests/quick-start/mysql +- ../../../../manifests/quick-start/mysql patchesStrategicMerge: - - ../mixins/argo-server-deployment.yaml - - ../mixins/workflow-controller-configmap.yaml - - ../mixins/workflow-controller-deployment.yaml - - ../mixins/cluster-workflow-template-rbac.yaml +- ../mixins/argo-server-deployment.yaml +- ../mixins/workflow-controller-configmap.yaml +- ../mixins/workflow-controller-deployment.yaml +- ../mixins/cluster-workflow-template-rbac.yaml commonLabels: - "app.kubernetes.io/part-of": "argo" + app.kubernetes.io/part-of: argo +namespace: argo diff --git a/test/e2e/manifests/postgres/kustomization.yaml b/test/e2e/manifests/postgres/kustomization.yaml index 2108ccc27de4..9ee763062f00 100644 --- a/test/e2e/manifests/postgres/kustomization.yaml +++ b/test/e2e/manifests/postgres/kustomization.yaml @@ -2,13 +2,14 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - - ../../../../manifests/quick-start/postgres +- ../../../../manifests/quick-start/postgres patchesStrategicMerge: - - ../mixins/argo-server-deployment.yaml - - ../mixins/workflow-controller-configmap.yaml - - ../mixins/workflow-controller-deployment.yaml - - ../mixins/cluster-workflow-template-rbac.yaml +- ../mixins/argo-server-deployment.yaml +- ../mixins/workflow-controller-configmap.yaml +- ../mixins/workflow-controller-deployment.yaml +- ../mixins/cluster-workflow-template-rbac.yaml commonLabels: - "app.kubernetes.io/part-of": "argo" + app.kubernetes.io/part-of: argo +namespace: argo diff --git a/test/e2e/manifests/sso/kustomization.yaml b/test/e2e/manifests/sso/kustomization.yaml index aab7b7d9f415..8a201a739ab8 100644 --- a/test/e2e/manifests/sso/kustomization.yaml +++ b/test/e2e/manifests/sso/kustomization.yaml @@ -2,13 +2,14 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - - ../../../../manifests/quick-start/sso +- ../../../../manifests/quick-start/sso patchesStrategicMerge: - - ../mixins/argo-server-deployment.yaml - - ../mixins/workflow-controller-configmap.yaml - - ../mixins/workflow-controller-deployment.yaml - - ../mixins/cluster-workflow-template-rbac.yaml +- ../mixins/argo-server-deployment.yaml +- ../mixins/workflow-controller-configmap.yaml +- ../mixins/workflow-controller-deployment.yaml +- ../mixins/cluster-workflow-template-rbac.yaml commonLabels: - "app.kubernetes.io/part-of": "argo" + app.kubernetes.io/part-of: argo +namespace: argo diff --git a/ui/.yarnrc b/ui/.yarnrc index 79ed41f3a46e..1df49d7b45fa 100644 --- a/ui/.yarnrc +++ b/ui/.yarnrc @@ -1,4 +1,3 @@ --add.ignore-optional true --install.ignore-optional true ---install.frozen-lockfile true --install.non-interactive true diff --git a/ui/__mocks__/styleMock.js b/ui/__mocks__/styleMock.js new file mode 100644 index 000000000000..a0995453769c --- /dev/null +++ b/ui/__mocks__/styleMock.js @@ -0,0 +1 @@ +module.exports = {}; \ No newline at end of file diff --git a/ui/jest.config.js b/ui/jest.config.js new file mode 100644 index 000000000000..f2f6784cdf78 --- /dev/null +++ b/ui/jest.config.js @@ -0,0 +1,9 @@ +module.exports = { + preset: 'ts-jest', + "transformIgnorePatterns": [ + "node_modules/(?!(argo-ui)/)" + ], + "moduleNameMapper": { + "\\.(css|scss)$": "/__mocks__/styleMock.js" + }, +}; \ No newline at end of file diff --git a/ui/package.json b/ui/package.json index 87886ef76a89..107846fb44de 100644 --- a/ui/package.json +++ b/ui/package.json @@ -6,13 +6,12 @@ "src" ], "scripts": { - "build": "webpack -p --config ./src/app/webpack.config.js", + "build": "NODE_ENV=production webpack -p --config ./src/app/webpack.config.js", "start": "webpack-dev-server --config ./src/app/webpack.config.js", - "lint": "tslint --fix -p ./src/app" + "lint": "tslint --fix -p ./src/app && ./node_modules/.bin/ts-prune -p src/app/tsconfig.json -i src/models/index.ts", + "test": "jest" }, "dependencies": { - "@fortawesome/fontawesome-free": "^5.12.0", - "@types/dagre": "^0.7.44", "argo-ui": "https://github.com/argoproj/argo-ui.git", "chart.js": "^2.9.4", "chartjs-plugin-annotation": "^0.5.7", @@ -38,9 +37,14 @@ "swagger-ui-react": "^3.29.0" }, "devDependencies": { + "@babel/core": "^7.0.0-0", + "@babel/preset-env": "^7.12.1", + "@fortawesome/fontawesome-free": "^5.12.0", "@types/chart.js": "^2.9.24", "@types/classnames": "^2.2.3", + "@types/dagre": "^0.7.44", "@types/history": "^4.6.2", + "@types/jest": "^26.0.15", "@types/js-yaml": "^3.12.1", "@types/prop-types": "^15.5.2", "@types/react": "^16.8.5", @@ -49,11 +53,14 @@ "@types/react-router-dom": "^4.2.3", "@types/superagent": "^3.5.7", "@types/swagger-ui-react": "^3.23.2", + "babel-jest": "^26.6.3", + "babel-loader": "^8.2.2", "copy-webpack-plugin": "^4.3.1", "copyfiles": "^1.2.0", "file-loader": "^6.0.0", "glob": "^7.1.2", "html-webpack-plugin": "^3.2.0", + "jest": "^26.6.3", "monaco-editor-webpack-plugin": "^1.9.0", "node-sass": "^4.14.1", "prettier": "^1.19.1", @@ -62,8 +69,10 @@ "sass-loader": "^6.0.6", "source-map-loader": "^0.2.4", "style-loader": "^0.20.1", + "ts-jest": "^26.4.4", "ts-loader": "^7.0.4", "ts-node": "^4.1.0", + "ts-prune": "^0.8.4", "tslint": "^5.9.1", "tslint-config-prettier": "^1.18.0", "tslint-plugin-prettier": "^2.1.0", diff --git a/ui/src/app/app-router.tsx b/ui/src/app/app-router.tsx new file mode 100644 index 000000000000..557eb172cb0a --- /dev/null +++ b/ui/src/app/app-router.tsx @@ -0,0 +1,153 @@ +import {Layout, Notifications, NotificationsManager, NotificationType, Popup, PopupManager, PopupProps} from 'argo-ui'; +import * as H from 'history'; + +import * as React from 'react'; +import {useEffect, useState} from 'react'; +import {Redirect, Route, Router, Switch} from 'react-router'; +import {Version} from '../models'; +import apidocs from './apidocs'; +import archivedWorkflows from './archived-workflows'; +import clusterWorkflowTemplates from './cluster-workflow-templates'; +import cronWorkflows from './cron-workflows'; +import events from './events'; +import help from './help'; +import login from './login'; +import reports from './reports'; +import {uiUrl} from './shared/base'; +import {ChatButton} from './shared/components/chat-button'; +import ErrorBoundary from './shared/components/error-boundary'; +import {services} from './shared/services'; +import {Utils} from './shared/utils'; +import userinfo from './userinfo'; +import workflowEventBindings from './workflow-event-bindings'; +import workflowTemplates from './workflow-templates'; +import workflows from './workflows'; + +const eventsUrl = uiUrl('events'); +const workflowsUrl = uiUrl('workflows'); +const workflowsEventBindingsUrl = uiUrl('workflow-event-bindings'); +const workflowTemplatesUrl = uiUrl('workflow-templates'); +const clusterWorkflowTemplatesUrl = uiUrl('cluster-workflow-templates'); +const cronWorkflowsUrl = uiUrl('cron-workflows'); +const archivedWorkflowsUrl = uiUrl('archived-workflows'); +const helpUrl = uiUrl('help'); +const apiDocsUrl = uiUrl('apidocs'); +const userInfoUrl = uiUrl('userinfo'); +const loginUrl = uiUrl('login'); +const timelineUrl = uiUrl('timeline'); +const reportsUrl = uiUrl('reports'); + +export const AppRouter = ({popupManager, history, notificationsManager}: {popupManager: PopupManager; history: H.History; notificationsManager: NotificationsManager}) => { + const [popupProps, setPopupProps] = useState(); + const [version, setVersion] = useState(); + const [namespace, setNamespace] = useState(); + const setError = (error: Error) => { + notificationsManager.show({ + content: 'Failed to load version/info ' + error, + type: NotificationType.Error + }); + }; + Utils.onNamespaceChange = setNamespace; + useEffect(() => { + const sub = popupManager.popupProps.subscribe(setPopupProps); + return () => sub.unsubscribe(); + }, [popupManager]); + useEffect(() => { + services.info + .getInfo() + .then(info => setNamespace(info.managedNamespace || Utils.getCurrentNamespace() || '')) + .then(() => services.info.getVersion()) + .then(setVersion) + .catch(setError); + }, []); + + return ( + <> + {popupProps && } + + <>{version ? version.version : 'unknown'}}> + + + + + + + + + + + + + + + + + + + {namespace && } + + + + + + + ); +}; diff --git a/ui/src/app/app.tsx b/ui/src/app/app.tsx index cfe510f41b47..8b61cca0c353 100644 --- a/ui/src/app/app.tsx +++ b/ui/src/app/app.tsx @@ -1,124 +1,28 @@ +import {NavigationManager, NotificationsManager, PopupManager} from 'argo-ui'; + import {createBrowserHistory} from 'history'; import * as PropTypes from 'prop-types'; import * as React from 'react'; -import {Redirect, Route, Router, Switch} from 'react-router'; - -import {Layout, NavigationManager, Notifications, NotificationsManager, Popup, PopupManager, PopupProps} from 'argo-ui'; -import {uiUrl} from './shared/base'; +import {AppRouter} from './app-router'; import {ContextApis, Provider} from './shared/context'; -import {NotificationType} from 'argo-ui/src/index'; -import {Version} from '../models'; -import apidocs from './apidocs'; -import archivedWorkflows from './archived-workflows'; -import clusterWorkflowTemplates from './cluster-workflow-templates'; -import cronWorkflows from './cron-workflows'; -import help from './help'; -import login from './login'; -import reports from './reports'; -import ErrorBoundary from './shared/components/error-boundary'; -import {services} from './shared/services'; -import {Utils} from './shared/utils'; -import userinfo from './userinfo'; -import workflowTemplates from './workflow-templates'; -import workflows from './workflows'; - -const workflowsUrl = uiUrl('workflows'); -const workflowTemplatesUrl = uiUrl('workflow-templates'); -const clusterWorkflowTemplatesUrl = uiUrl('cluster-workflow-templates'); -const cronWorkflowsUrl = uiUrl('cron-workflows'); -const archivedWorkflowsUrl = uiUrl('archived-workflows'); -const helpUrl = uiUrl('help'); -const apiDocsUrl = uiUrl('apidocs'); -const userInfoUrl = uiUrl('userinfo'); -const loginUrl = uiUrl('login'); -const timelineUrl = uiUrl('timeline'); -const reportsUrl = uiUrl('reports'); - -export const history = createBrowserHistory(); - -const navItems = [ - { - title: 'Timeline', - path: workflowsUrl, - iconClassName: 'fa fa-stream' - }, - { - title: 'Workflow Templates', - path: workflowTemplatesUrl, - iconClassName: 'fa fa-window-maximize' - }, - { - title: 'Cluster Workflow Templates', - path: clusterWorkflowTemplatesUrl, - iconClassName: 'fa fa-window-restore' - }, - { - title: 'Cron Workflows', - path: cronWorkflowsUrl, - iconClassName: 'fa fa-clock' - }, - { - title: 'Archived Workflows', - path: archivedWorkflowsUrl, - iconClassName: 'fa fa-archive' - }, - { - title: 'Reports', - path: reportsUrl, - iconClassName: 'fa fa-chart-bar' - }, - { - title: 'User', - path: userInfoUrl, - iconClassName: 'fa fa-user-alt' - }, - { - title: 'API Docs', - path: apiDocsUrl, - iconClassName: 'fa fa-code' - }, - { - title: 'Help', - path: helpUrl, - iconClassName: 'fa fa-question-circle' - } -]; +const history = createBrowserHistory(); -export class App extends React.Component<{}, {version?: Version; popupProps: PopupProps; namespace?: string}> { +export class App extends React.Component<{}> { public static childContextTypes = { history: PropTypes.object, apis: PropTypes.object }; - private popupManager: PopupManager; - private notificationsManager: NotificationsManager; - private navigationManager: NavigationManager; + private readonly popupManager: PopupManager; + private readonly notificationsManager: NotificationsManager; + private readonly navigationManager: NavigationManager; constructor(props: {}) { super(props); - this.state = {popupProps: null}; this.popupManager = new PopupManager(); this.notificationsManager = new NotificationsManager(); this.navigationManager = new NavigationManager(history); - Utils.onNamespaceChange = namespace => { - this.setState({namespace}); - }; - } - - public componentDidMount() { - this.popupManager.popupProps.subscribe(popupProps => this.setState({popupProps})); - services.info - .getVersion() - .then(version => this.setState({version})) - .then(() => services.info.getInfo()) - .then(info => this.setState({namespace: info.managedNamespace || Utils.getCurrentNamespace() || ''})) - .catch(error => { - this.notificationsManager.show({ - content: 'Failed to load ' + error, - type: NotificationType.Error - }); - }); } public render() { @@ -130,81 +34,11 @@ export class App extends React.Component<{}, {version?: Version; popupProps: Pop }; return ( - {this.state.popupProps && } - - <>{this.state.version ? this.state.version.version : 'unknown'}}> - - - - - - - - - - {this.state.namespace && ( - - - - )} - {this.state.namespace && ( - - - - )} - {this.state.namespace && ( - - - - )} - {this.state.namespace && ( - - - - )} - {this.state.namespace && ( - - - - )} - - - - - - - - - - - - - - + ); } - private get archivedWorkflowsUrl() { - return archivedWorkflowsUrl + '/' + (this.state.namespace || ''); - } - - private get cronWorkflowsUrl() { - return cronWorkflowsUrl + '/' + (this.state.namespace || ''); - } - - private get workflowTemplatesUrl() { - return workflowTemplatesUrl + '/' + (this.state.namespace || ''); - } - - private get workflowsUrl() { - return workflowsUrl + '/' + (this.state.namespace || ''); - } - - private get reportsUrl() { - return reportsUrl + '/' + (this.state.namespace || ''); - } - public getChildContext() { return { history, diff --git a/ui/src/app/archived-workflows/components/archived-workflow-details/archived-workflow-details.tsx b/ui/src/app/archived-workflows/components/archived-workflow-details/archived-workflow-details.tsx index 3ba7dcc6d581..177b3b258420 100644 --- a/ui/src/app/archived-workflows/components/archived-workflow-details/archived-workflow-details.tsx +++ b/ui/src/app/archived-workflows/components/archived-workflow-details/archived-workflow-details.tsx @@ -2,24 +2,23 @@ import {NotificationType, Page, SlidingPanel} from 'argo-ui'; import * as classNames from 'classnames'; import * as React from 'react'; import {RouteComponentProps} from 'react-router'; -import {Link, Workflow} from '../../../../models'; +import {execSpec, Link, Workflow} from '../../../../models'; import {uiUrl} from '../../../shared/base'; import {BasePage} from '../../../shared/components/base-page'; import {ErrorNotice} from '../../../shared/components/error-notice'; import {Loading} from '../../../shared/components/loading'; import {ResourceEditor} from '../../../shared/components/resource-editor/resource-editor'; import {services} from '../../../shared/services'; -import { - WorkflowArtifacts, - WorkflowLogsViewer, - WorkflowNodeInfo, - WorkflowPanel, - WorkflowParametersPanel, - WorkflowSummaryPanel, - WorkflowTimeline, - WorkflowYamlViewer -} from '../../../workflows/components'; +import {WorkflowArtifacts} from '../../../workflows/components/workflow-artifacts'; + import {WorkflowResourcePanel} from '../../../workflows/components/workflow-details/workflow-resource-panel'; +import {WorkflowLogsViewer} from '../../../workflows/components/workflow-logs-viewer/workflow-logs-viewer'; +import {WorkflowNodeInfo} from '../../../workflows/components/workflow-node-info/workflow-node-info'; +import {WorkflowPanel} from '../../../workflows/components/workflow-panel/workflow-panel'; +import {WorkflowParametersPanel} from '../../../workflows/components/workflow-parameters-panel'; +import {WorkflowSummaryPanel} from '../../../workflows/components/workflow-summary-panel'; +import {WorkflowTimeline} from '../../../workflows/components/workflow-timeline/workflow-timeline'; +import {WorkflowYamlViewer} from '../../../workflows/components/workflow-yaml-viewer/workflow-yaml-viewer'; require('../../../workflows/components/workflow-details/workflow-details.scss'); @@ -30,6 +29,10 @@ interface State { } export class ArchivedWorkflowDetails extends BasePage, State> { + private get namespace() { + return this.props.match.params.namespace; + } + private get uid() { return this.props.match.params.uid; } @@ -71,7 +74,14 @@ export class ArchivedWorkflowDetails extends BasePage, services.info .getInfo() .then(info => this.setState({links: info.links})) - .then(() => services.archivedWorkflows.get(this.uid).then(workflow => this.setState({error: null, workflow}))) + .then(() => + services.archivedWorkflows.get(this.uid).then(workflow => + this.setState({ + error: null, + workflow + }) + ) + ) .catch(error => this.setState({error})); } @@ -107,11 +117,15 @@ export class ArchivedWorkflowDetails extends BasePage, items }, breadcrumbs: [ + {title: 'Archived Workflows', path: uiUrl('archived-workflows')}, { - title: 'Archived Workflows', - path: uiUrl('archived-workflows/') + title: this.namespace, + path: uiUrl('archived-workflows/' + this.namespace) }, - {title: this.uid} + { + title: this.uid, + path: uiUrl('archived-workflows/' + this.namespace + '/' + this.uid) + } ], tools: (
@@ -134,7 +148,7 @@ export class ArchivedWorkflowDetails extends BasePage, private renderArchivedWorkflowDetails() { if (this.state.error) { - return ; + return ; } if (!this.state.workflow) { return ; @@ -145,10 +159,10 @@ export class ArchivedWorkflowDetails extends BasePage,
- {this.state.workflow.spec.arguments && this.state.workflow.spec.arguments.parameters && ( + {execSpec(this.state.workflow).arguments && execSpec(this.state.workflow).arguments.parameters && (
Parameters
- +
)}
Artifacts
diff --git a/ui/src/app/archived-workflows/components/archived-workflow-list/archived-workflow-list.tsx b/ui/src/app/archived-workflows/components/archived-workflow-list/archived-workflow-list.tsx index 774d9b4d772a..ff907bd1895b 100644 --- a/ui/src/app/archived-workflows/components/archived-workflow-list/archived-workflow-list.tsx +++ b/ui/src/app/archived-workflows/components/archived-workflow-list/archived-workflow-list.tsx @@ -60,7 +60,10 @@ export class ArchivedWorkflowList extends BasePage, Sta
diff --git a/ui/src/app/cluster-workflow-templates/components/cluster-workflow-template-creator.tsx b/ui/src/app/cluster-workflow-templates/components/cluster-workflow-template-creator.tsx new file mode 100644 index 000000000000..da8ab460c97a --- /dev/null +++ b/ui/src/app/cluster-workflow-templates/components/cluster-workflow-template-creator.tsx @@ -0,0 +1,37 @@ +import * as React from 'react'; +import {useState} from 'react'; +import {ClusterWorkflowTemplate} from '../../../models'; +import {Button} from '../../shared/components/button'; +import {ErrorNotice} from '../../shared/components/error-notice'; +import {ExampleManifests} from '../../shared/components/example-manifests'; +import {UploadButton} from '../../shared/components/upload-button'; +import {exampleClusterWorkflowTemplate} from '../../shared/examples'; +import {services} from '../../shared/services'; +import {ClusterWorkflowTemplateEditor} from './cluster-workflow-template-editor'; + +export const ClusterWorkflowTemplateCreator = ({onCreate}: {onCreate: (workflow: ClusterWorkflowTemplate) => void}) => { + const [template, setTemplate] = useState(exampleClusterWorkflowTemplate()); + const [error, setError] = useState(); + return ( + <> +
+ + +
+ + +
+ . +
+ + ); +}; diff --git a/ui/src/app/cluster-workflow-templates/components/cluster-workflow-template-details/cluster-workflow-template-details.tsx b/ui/src/app/cluster-workflow-templates/components/cluster-workflow-template-details/cluster-workflow-template-details.tsx index 863c542db969..7f3983872fb9 100644 --- a/ui/src/app/cluster-workflow-templates/components/cluster-workflow-template-details/cluster-workflow-template-details.tsx +++ b/ui/src/app/cluster-workflow-templates/components/cluster-workflow-template-details/cluster-workflow-template-details.tsx @@ -1,127 +1,129 @@ import {NotificationType, Page} from 'argo-ui'; import {SlidingPanel} from 'argo-ui/src/index'; import * as React from 'react'; +import {useContext, useEffect, useState} from 'react'; import {RouteComponentProps} from 'react-router'; -import * as models from '../../../../models'; +import {ClusterWorkflowTemplate} from '../../../../models'; import {uiUrl} from '../../../shared/base'; -import {BasePage} from '../../../shared/components/base-page'; import {ErrorNotice} from '../../../shared/components/error-notice'; import {Loading} from '../../../shared/components/loading'; -import {Consumer} from '../../../shared/context'; +import {Context} from '../../../shared/context'; +import {historyUrl} from '../../../shared/history'; import {services} from '../../../shared/services'; import {Utils} from '../../../shared/utils'; import {SubmitWorkflowPanel} from '../../../workflows/components/submit-workflow-panel'; -import {ClusterWorkflowTemplateSummaryPanel} from '../cluster-workflow-template-summary-panel'; +import {ClusterWorkflowTemplateEditor} from '../cluster-workflow-template-editor'; require('../../../workflows/components/workflow-details/workflow-details.scss'); -interface State { - namespace?: string; - template?: models.ClusterWorkflowTemplate; - error?: Error; -} +export const ClusterWorkflowTemplateDetails = ({history, location, match}: RouteComponentProps) => { + // boiler-plate + const {navigation, notifications} = useContext(Context); + const queryParams = new URLSearchParams(location.search); -export class ClusterWorkflowTemplateDetails extends BasePage, State> { - private get name() { - return this.props.match.params.name; - } + const name = match.params.name; + const [namespace, setNamespace] = useState(); + const [sidePanel, setSidePanel] = useState(queryParams.get('sidePanel') === 'true'); + const [tab, setTab] = useState(queryParams.get('tab')); - private get sidePanel() { - return this.queryParam('sidePanel'); - } + const [error, setError] = useState(); + const [template, setTemplate] = useState(); + const [edited, setEdited] = useState(false); - private set sidePanel(sidePanel) { - this.setQueryParams({sidePanel}); - } + useEffect(() => setEdited(true), [template]); + useEffect(() => { + history.push(historyUrl('cluster-workflow-templates/{name}', {name, sidePanel, tab})); + }, [name, sidePanel, tab]); - constructor(props: RouteComponentProps, context: any) { - super(props, context); - this.state = {}; - } - - public componentDidMount(): void { + useEffect(() => { services.clusterWorkflowTemplate - .get(this.name) - .then(template => this.setState({error: null, template})) - .then(() => services.info.getInfo()) - .then(info => this.setState({namespace: info.managedNamespace || Utils.getCurrentNamespace() || 'default'})) - .catch(error => this.setState({error})); - } - - public render() { - return ( - - {ctx => ( - (this.sidePanel = 'new') - }, - { - title: 'Delete', - iconClassName: 'fa fa-trash', - action: () => this.deleteClusterWorkflowTemplate() - } - ] - }, - breadcrumbs: [ - { - title: 'Cluster Workflow Template', - path: uiUrl('cluster-workflow-templates') - }, - {title: this.name} - ] - }}> -
-
{this.renderClusterWorkflowTemplate()}
-
- {this.state.template && ( - (this.sidePanel = null)}> - t.name)} - parameters={this.state.template.spec.arguments.parameters || []} - /> - - )} -
- )} -
- ); - } + .get(name) + .then(setTemplate) + .then(() => setEdited(false)) // set back to false + .then(() => setError(null)) + .catch(setError); + }, [name]); - private renderClusterWorkflowTemplate() { - if (this.state.error) { - return ; - } - if (!this.state.template) { - return ; - } - return this.setState({template})} />; - } + useEffect(() => { + services.info + .getInfo() + .then(info => setNamespace(Utils.getNamespace(info.managedNamespace))) + .then(() => setError(null)) + .catch(setError); + }, []); - private deleteClusterWorkflowTemplate() { - if (!confirm('Are you sure you want to delete this cluster workflow template?\nThere is no undo.')) { - return; - } - services.clusterWorkflowTemplate - .delete(this.name) - .catch(e => { - this.appContext.apis.notifications.show({ - content: 'Failed to delete cluster workflow template ' + e, - type: NotificationType.Error - }); - }) - .then(() => { - document.location.href = uiUrl('cluster-workflow-templates'); - }); - } -} + return ( + setSidePanel(true) + }, + { + title: 'Update', + iconClassName: 'fa fa-save', + disabled: !edited, + action: () => { + services.clusterWorkflowTemplate + .update(template, name) + .then(setTemplate) + .then(() => + notifications.show({ + content: 'Updated', + type: NotificationType.Success + }) + ) + .then(() => setError(null)) + .catch(setError); + } + }, + { + title: 'Delete', + iconClassName: 'fa fa-trash', + disabled: edited, + action: () => { + if (!confirm('Are you sure you want to delete this cluster workflow template?\nThere is no undo.')) { + return; + } + services.clusterWorkflowTemplate + .delete(name) + .then(() => navigation.goto(uiUrl('cluster-workflow-templates'))) + .then(() => setError(null)) + .catch(setError); + } + } + ] + } + }}> + <> + + {!template ? ( + + ) : ( + + )} + + {template && ( + setSidePanel(null)} isNarrow={true}> + t.name)} + parameters={template.spec.arguments.parameters || []} + /> + + )} + + ); +}; diff --git a/ui/src/app/cluster-workflow-templates/components/cluster-workflow-template-editor.tsx b/ui/src/app/cluster-workflow-templates/components/cluster-workflow-template-editor.tsx new file mode 100644 index 000000000000..6109b7a95f60 --- /dev/null +++ b/ui/src/app/cluster-workflow-templates/components/cluster-workflow-template-editor.tsx @@ -0,0 +1,58 @@ +import * as React from 'react'; + +import {Tabs} from 'argo-ui'; +import {WorkflowTemplate} from '../../../models'; +import {LabelsAndAnnotationsEditor} from '../../shared/components/editors/labels-and-annotations-editor'; +import {MetadataEditor} from '../../shared/components/editors/metadata-editor'; +import {WorkflowSpecEditor} from '../../shared/components/editors/workflow-spec-editor'; +import {ObjectEditor} from '../../shared/components/object-editor/object-editor'; + +export const ClusterWorkflowTemplateEditor = ({ + onChange, + template, + onError, + onTabSelected, + selectedTabKey +}: { + template: WorkflowTemplate; + onChange: (template: WorkflowTemplate) => void; + onError: (error: Error) => void; + onTabSelected?: (tab: string) => void; + selectedTabKey?: string; +}) => { + return ( + onChange({...template, spec})} onError={onError} /> + }, + { + key: 'metadata', + title: 'MetaData', + content: onChange({...template, metadata})} /> + }, + { + key: 'workflow-metadata', + title: 'Workflow MetaData', + content: ( + onChange({...template, spec: {...template.spec, workflowMetadata}})} + /> + ) + }, + { + key: 'manifest', + title: 'Manifest', + content: onChange({...x})} /> + } + ]} + /> + ); +}; diff --git a/ui/src/app/cluster-workflow-templates/components/cluster-workflow-template-list/cluster-workflow-template-list.tsx b/ui/src/app/cluster-workflow-templates/components/cluster-workflow-template-list/cluster-workflow-template-list.tsx index b9677c78a894..a2d3a8c5e425 100644 --- a/ui/src/app/cluster-workflow-templates/components/cluster-workflow-template-list/cluster-workflow-template-list.tsx +++ b/ui/src/app/cluster-workflow-templates/components/cluster-workflow-template-list/cluster-workflow-template-list.tsx @@ -7,12 +7,11 @@ import {BasePage} from '../../../shared/components/base-page'; import {ErrorNotice} from '../../../shared/components/error-notice'; import {ExampleManifests} from '../../../shared/components/example-manifests'; import {Loading} from '../../../shared/components/loading'; -import {ResourceEditor} from '../../../shared/components/resource-editor/resource-editor'; import {Timestamp} from '../../../shared/components/timestamp'; import {ZeroState} from '../../../shared/components/zero-state'; import {Consumer} from '../../../shared/context'; -import {exampleClusterWorkflowTemplate} from '../../../shared/examples'; import {services} from '../../../shared/services'; +import {ClusterWorkflowTemplateCreator} from '../cluster-workflow-template-creator'; require('./cluster-workflow-template-list.scss'); @@ -59,19 +58,7 @@ export class ClusterWorkflowTemplateList extends BasePage {this.renderTemplates()} (this.sidePanel = null)}> - - services.clusterWorkflowTemplate.create(wfTmpl).then(wf => ctx.navigation.goto(uiUrl(`cluster-workflow-templates/${wf.metadata.name}`))) - } - /> -

- . -

+ ctx.navigation.goto(uiUrl(`cluster-workflow-templates/${wf.metadata.name}`))} />
)} @@ -88,7 +75,7 @@ export class ClusterWorkflowTemplateList extends BasePage; + return ; } if (!this.state.templates) { return ; diff --git a/ui/src/app/cron-workflows/components/cron-workflow-creator.tsx b/ui/src/app/cron-workflows/components/cron-workflow-creator.tsx new file mode 100644 index 000000000000..45bb2629d39b --- /dev/null +++ b/ui/src/app/cron-workflows/components/cron-workflow-creator.tsx @@ -0,0 +1,38 @@ +import * as React from 'react'; +import {useState} from 'react'; +import {CronWorkflow} from '../../../models'; +import {Button} from '../../shared/components/button'; +import {ErrorNotice} from '../../shared/components/error-notice'; +import {ExampleManifests} from '../../shared/components/example-manifests'; +import {UploadButton} from '../../shared/components/upload-button'; +import {exampleCronWorkflow} from '../../shared/examples'; +import {services} from '../../shared/services'; +import {Utils} from '../../shared/utils'; +import {CronWorkflowEditor} from './cron-workflow-editor'; + +export const CronWorkflowCreator = ({onCreate, namespace}: {namespace: string; onCreate: (cronWorkflow: CronWorkflow) => void}) => { + const [cronWorkflow, setCronWorkflow] = useState(exampleCronWorkflow(Utils.getNamespace(namespace))); + const [error, setError] = useState(); + return ( + <> +
+ + +
+ + +

+ . +

+ + ); +}; diff --git a/ui/src/app/cron-workflows/components/cron-workflow-details/cron-workflow-details.tsx b/ui/src/app/cron-workflows/components/cron-workflow-details/cron-workflow-details.tsx index 048ac62c1496..646b21081627 100644 --- a/ui/src/app/cron-workflows/components/cron-workflow-details/cron-workflow-details.tsx +++ b/ui/src/app/cron-workflows/components/cron-workflow-details/cron-workflow-details.tsx @@ -1,159 +1,154 @@ import {NotificationType, Page} from 'argo-ui'; import * as React from 'react'; +import {useContext, useEffect, useState} from 'react'; import {RouteComponentProps} from 'react-router'; import {CronWorkflow} from '../../../../models'; import {uiUrl} from '../../../shared/base'; -import {BasePage} from '../../../shared/components/base-page'; import {ErrorNotice} from '../../../shared/components/error-notice'; import {Loading} from '../../../shared/components/loading'; +import {Context} from '../../../shared/context'; +import {historyUrl} from '../../../shared/history'; import {services} from '../../../shared/services'; -import {CronWorkflowSummaryPanel} from '../cron-workflow-summary-panel'; +import {CronWorkflowEditor} from '../cron-workflow-editor'; require('../../../workflows/components/workflow-details/workflow-details.scss'); -interface State { - cronWorkflow?: CronWorkflow; - error?: Error; -} +export const CronWorkflowDetails = ({match, location, history}: RouteComponentProps) => { + // boiler-plate + const {navigation, notifications} = useContext(Context); + const queryParams = new URLSearchParams(location.search); -export class CronWorkflowDetails extends BasePage, State> { - private get namespace() { - return this.props.match.params.namespace || ''; - } + const [namespace] = useState(match.params.namespace); + const [name] = useState(match.params.name); + const [tab, setTab] = useState(queryParams.get('tab')); - private get name() { - return this.props.match.params.name; - } + const [cronWorkflow, setCronWorkflow] = useState(); + const [edited, setEdited] = useState(false); + const [error, setError] = useState(); - constructor(props: RouteComponentProps, context: any) { - super(props, context); - this.state = {}; - } + useEffect( + () => + history.push( + historyUrl('cron-workflows/{namespace}/{name}', { + namespace, + name, + tab + }) + ), + [namespace, name, tab] + ); - public componentDidMount(): void { + useEffect(() => { services.cronWorkflows - .get(this.name, this.namespace) - .then(cronWf => this.setState({error: null, cronWorkflow: cronWf})) - .catch(error => this.setState({error})); - } + .get(name, namespace) + .then(setCronWorkflow) + .then(() => setEdited(false)) + .then(() => setError(null)) + .catch(setError); + }, [namespace, name]); - public render() { - const suspendButton = - this.state.cronWorkflow && !this.state.cronWorkflow.spec.suspend - ? { - title: 'Suspend', - iconClassName: 'fa fa-pause', - action: () => this.suspendCronWorkflow(), - disabled: !this.state.cronWorkflow - } - : { - title: 'Resume', - iconClassName: 'fa fa-play', - action: () => this.resumeCronWorkflow(), - disabled: !this.state.cronWorkflow || !this.state.cronWorkflow.spec.suspend - }; - return ( - this.submitCronWorkflow() - }, - { - title: 'Delete', - iconClassName: 'fa fa-trash', - action: () => this.deleteCronWorkflow() - }, - suspendButton - ] - }, - breadcrumbs: [ + useEffect(() => setEdited(true), [cronWorkflow]); + + const suspendButton = + cronWorkflow && !cronWorkflow.spec.suspend + ? { + title: 'Suspend', + iconClassName: 'fa fa-pause', + action: () => + services.cronWorkflows + .suspend(name, namespace) + .then(setCronWorkflow) + .then(() => setEdited(false)) + .then(() => setError(null)) + .catch(setError), + disabled: !cronWorkflow || edited + } + : { + title: 'Resume', + iconClassName: 'fa fa-play', + action: () => + services.cronWorkflows + .resume(name, namespace) + .then(setCronWorkflow) + .then(() => setEdited(false)) + .then(() => setError(null)) + .catch(setError), + disabled: !cronWorkflow || !cronWorkflow.spec.suspend || edited + }; + return ( + + services.workflows + .submit('cronwf', name, namespace) + .then(wf => navigation.goto(uiUrl(`workflows/${wf.metadata.namespace}/${wf.metadata.name}`))) + .then(() => setError(null)) + .catch(setError) + }, { - title: 'Cron Workflows', - path: uiUrl('cron-workflows') + title: 'Update', + iconClassName: 'fa fa-save', + disabled: !edited, + action: () => { + // magic - we get the latest from the server and then apply the changes from the rendered version to this + return services.cronWorkflows + .get(name, namespace) + .then(latest => + services.cronWorkflows.update( + { + ...latest, + spec: cronWorkflow.spec, + metadata: {...cronWorkflow.metadata, resourceVersion: latest.metadata.resourceVersion} + }, + cronWorkflow.metadata.name, + cronWorkflow.metadata.namespace + ) + ) + .then(setCronWorkflow) + .then(() => notifications.show({content: 'Updated', type: NotificationType.Success})) + .then(() => setError(null)) + .catch(setError); + } }, - {title: this.namespace + '/' + this.name} + { + title: 'Delete', + iconClassName: 'fa fa-trash', + disabled: edited, + action: () => { + if (!confirm('Are you sure you want to delete this cron workflow?\nThere is no undo.')) { + return; + } + services.cronWorkflows + .delete(name, namespace) + .then(() => navigation.goto(uiUrl('cron-workflows/' + namespace))) + .then(() => setError(null)) + .catch(setError); + } + }, + suspendButton ] - }}> -
-
{this.renderCronWorkflow()}
-
-
- ); - } - - private renderCronWorkflow() { - if (this.state.error) { - return ; - } - if (!this.state.cronWorkflow) { - return ; - } - return this.setState({cronWorkflow})} />; - } - - private async submitCronWorkflow() { - try { - const submitted = await services.workflows.submit('cronwf', this.name, this.namespace); - - try { - document.location.href = uiUrl(`workflows/${submitted.metadata.namespace}/${submitted.metadata.name}`); - } catch (e) { - this.appContext.apis.notifications.show({ - content: 'Failed redirect to newly submitted cron workflow ' + e, - type: NotificationType.Error - }); - } - } catch (e) { - this.appContext.apis.notifications.show({ - content: 'Failed to submit cron workflow ' + e, - type: NotificationType.Error - }); - } - } - - private deleteCronWorkflow() { - if (!confirm('Are you sure you want to delete this cron workflow?\nThere is no undo.')) { - return; - } - services.cronWorkflows - .delete(this.name, this.namespace) - .catch(e => { - this.appContext.apis.notifications.show({ - content: 'Failed to delete cron workflow ' + e, - type: NotificationType.Error - }); - }) - .then(() => { - document.location.href = uiUrl('cron-workflows'); - }); - } - - private suspendCronWorkflow() { - services.cronWorkflows - .suspend(this.name, this.namespace) - .then((updated: CronWorkflow) => this.setState({cronWorkflow: updated})) - .catch(e => { - this.appContext.apis.notifications.show({ - content: 'Failed to suspend cron workflow ' + e, - type: NotificationType.Error - }); - }); - } - - private resumeCronWorkflow() { - services.cronWorkflows - .resume(this.name, this.namespace) - .then((updated: CronWorkflow) => this.setState({cronWorkflow: updated})) - .catch(e => { - this.appContext.apis.notifications.show({ - content: 'Failed to resume cron workflow ' + e, - type: NotificationType.Error - }); - }); - } -} + } + }}> + <> + + {!cronWorkflow ? ( + + ) : ( + + )} + +
+ ); +}; diff --git a/ui/src/app/cron-workflows/components/cron-workflow-editor.tsx b/ui/src/app/cron-workflows/components/cron-workflow-editor.tsx new file mode 100644 index 000000000000..5449f3476652 --- /dev/null +++ b/ui/src/app/cron-workflows/components/cron-workflow-editor.tsx @@ -0,0 +1,85 @@ +import * as React from 'react'; + +import {Tabs} from 'argo-ui'; +import {CronWorkflow} from '../../../models'; +import {LabelsAndAnnotationsEditor} from '../../shared/components/editors/labels-and-annotations-editor'; +import {MetadataEditor} from '../../shared/components/editors/metadata-editor'; +import {WorkflowSpecEditor} from '../../shared/components/editors/workflow-spec-editor'; +import {ObjectEditor} from '../../shared/components/object-editor/object-editor'; +import {CronWorkflowSpecEditor} from './cron-workflow-spec-editior'; +import {CronWorkflowStatusViewer} from './cron-workflow-status-viewer'; + +export const CronWorkflowEditor = ({ + selectedTabKey, + onTabSelected, + onError, + onChange, + cronWorkflow +}: { + cronWorkflow: CronWorkflow; + onChange: (cronWorkflow: CronWorkflow) => void; + onError: (error: Error) => void; + onTabSelected?: (tab: string) => void; + selectedTabKey?: string; +}) => { + return ( + + } + ] + : []), + { + key: 'cron', + title: 'Cron', + content: onChange({...cronWorkflow, spec})} /> + }, + { + key: 'metadata', + title: 'MetaData', + content: onChange({...cronWorkflow, metadata})} /> + }, + { + key: 'workflow', + title: 'Workflow', + content: ( + onChange({...cronWorkflow, spec: {...cronWorkflow.spec, workflowSpec}})} + onError={onError} + /> + ) + }, + { + key: 'workflow-metadata', + title: 'Workflow MetaData', + content: ( + + onChange({ + ...cronWorkflow, + spec: {...cronWorkflow.spec, workflowMetadata} + }) + } + /> + ) + }, + { + key: 'manifest', + title: 'Manifest', + content: onChange({...x})} /> + } + ]} + /> + ); +}; diff --git a/ui/src/app/cron-workflows/components/cron-workflow-list/cron-workflow-list.tsx b/ui/src/app/cron-workflows/components/cron-workflow-list/cron-workflow-list.tsx index a4907791849a..c564d4d9caab 100644 --- a/ui/src/app/cron-workflows/components/cron-workflow-list/cron-workflow-list.tsx +++ b/ui/src/app/cron-workflows/components/cron-workflow-list/cron-workflow-list.tsx @@ -9,14 +9,13 @@ import {ErrorNotice} from '../../../shared/components/error-notice'; import {ExampleManifests} from '../../../shared/components/example-manifests'; import {Loading} from '../../../shared/components/loading'; import {NamespaceFilter} from '../../../shared/components/namespace-filter'; -import {ResourceEditor} from '../../../shared/components/resource-editor/resource-editor'; import {Timestamp} from '../../../shared/components/timestamp'; import {ZeroState} from '../../../shared/components/zero-state'; import {Consumer} from '../../../shared/context'; import {getNextScheduledTime} from '../../../shared/cron'; -import {exampleCronWorkflow} from '../../../shared/examples'; import {services} from '../../../shared/services'; import {Utils} from '../../../shared/utils'; +import {CronWorkflowCreator} from '../cron-workflow-creator'; require('./cron-workflow-list.scss'); @@ -59,7 +58,10 @@ export class CronWorkflowList extends BasePage, State> , State>
{this.renderCronWorkflows()}
(this.sidePanel = null)}> - - services.cronWorkflows - .create(cronWf, cronWf.metadata.namespace || this.namespace) - .then(res => ctx.navigation.goto(uiUrl(`cron-workflows/${res.metadata.namespace}/${res.metadata.name}`))) - } - upload={true} - editing={true} - kind='CronWorkflow' + onCreate={cronWorkflow => ctx.navigation.goto(uiUrl('cron-workflows/' + cronWorkflow.metadata.namespace + '/' + cronWorkflow.metadata.name))} /> -

- . -

)} @@ -112,7 +102,7 @@ export class CronWorkflowList extends BasePage, State> private renderCronWorkflows() { if (this.state.error) { - return ; + return ; } if (!this.state.cronWorkflows) { return ; diff --git a/ui/src/app/cron-workflows/components/cron-workflow-spec-editior.tsx b/ui/src/app/cron-workflows/components/cron-workflow-spec-editior.tsx new file mode 100644 index 000000000000..94c11f502e9b --- /dev/null +++ b/ui/src/app/cron-workflows/components/cron-workflow-spec-editior.tsx @@ -0,0 +1,89 @@ +import {Checkbox, Select} from 'argo-ui'; +import * as React from 'react'; +import {ConcurrencyPolicy, CronWorkflowSpec} from '../../../models'; +import {NumberInput} from '../../shared/components/number-input'; +import {TextInput} from '../../shared/components/text-input'; + +export const CronWorkflowSpecEditor = ({onChange, spec}: {spec: CronWorkflowSpec; onChange: (spec: CronWorkflowSpec) => void}) => { + return ( +
+
+
+
Schedule
+
+ onChange({...spec, schedule})} /> +
+
+
+
Timezone
+
+ onChange({...spec, timezone})} /> +
+
+
+
Concurrency Policy
+
+ { diff --git a/ui/src/app/shared/components/drop-down-button.tsx b/ui/src/app/shared/components/drop-down-button.tsx index fe755a38ee82..f205b22ee137 100644 --- a/ui/src/app/shared/components/drop-down-button.tsx +++ b/ui/src/app/shared/components/drop-down-button.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import {ReactNode, useState} from 'react'; +import {Button} from './button'; require('./drop-down-button.scss'); @@ -7,15 +8,15 @@ export const DropDownButton = ({onClick, items, children}: {onClick: () => void; const [dropped, setDropped] = useState(false); return (
setDropped(true)} onMouseLeave={() => setDropped(false)}> - +
{items.map(option => (
- +
))}
diff --git a/ui/src/app/shared/components/editors/key-value-editor.tsx b/ui/src/app/shared/components/editors/key-value-editor.tsx new file mode 100644 index 000000000000..6493e278fbbf --- /dev/null +++ b/ui/src/app/shared/components/editors/key-value-editor.tsx @@ -0,0 +1,64 @@ +import * as React from 'react'; +import {TextInput} from '../text-input'; + +interface KeyValues { + [key: string]: string; +} + +export const KeyValueEditor = ({onChange, keyValues, hide}: {keyValues: KeyValues; onChange: (value: KeyValues) => void; hide?: (key: string) => boolean}) => { + const [name, setName] = React.useState(''); + const [value, setValue] = React.useState(''); + const deleteItem = (k: string) => { + delete keyValues[k]; + onChange(keyValues); + }; + const addItem = () => { + if (!name || !value) { + return; + } + keyValues[name] = value; + onChange(keyValues); + setName(''); + setValue(''); + }; + return ( + <> + {Object.entries(keyValues) + .filter(([k]) => hide === undefined || !hide(k)) + .map(([k, v]) => ( +
+
{k}
+
{v}
+
+ +
+
+ ))} +
{ + if (e.key === 'Enter') { + addItem(); + } + }}> +
+ +
+
+ +
+
+ +
+
+ + ); +}; + +KeyValueEditor.defaultProps = { + keyValues: {} +}; diff --git a/ui/src/app/shared/components/editors/labels-and-annotations-editor.tsx b/ui/src/app/shared/components/editors/labels-and-annotations-editor.tsx new file mode 100644 index 000000000000..7c734a6b17b4 --- /dev/null +++ b/ui/src/app/shared/components/editors/labels-and-annotations-editor.tsx @@ -0,0 +1,22 @@ +import * as React from 'react'; +import {kubernetes} from '../../../../models'; +import {KeyValueEditor} from './key-value-editor'; + +export const LabelsAndAnnotationsEditor = ({value, onChange}: {value: kubernetes.ObjectMeta; onChange: (value: kubernetes.ObjectMeta) => void}) => { + return ( + <> +
+
Labels
+ onChange({...value, labels})} /> +
+
+
Annotations
+ onChange({...value, annotations})} + hide={key => key === 'kubectl.kubernetes.io/last-applied-configuration'} + /> +
+ + ); +}; diff --git a/ui/src/app/shared/components/editors/metadata-editor.tsx b/ui/src/app/shared/components/editors/metadata-editor.tsx new file mode 100644 index 000000000000..2ed00b2deb06 --- /dev/null +++ b/ui/src/app/shared/components/editors/metadata-editor.tsx @@ -0,0 +1,32 @@ +import * as React from 'react'; +import {kubernetes} from '../../../../models'; +import {TextInput} from '../text-input'; +import {LabelsAndAnnotationsEditor} from './labels-and-annotations-editor'; + +export const MetadataEditor = ({onChange, value}: {value: kubernetes.ObjectMeta; onChange: (value: kubernetes.ObjectMeta) => void}) => { + return ( + <> +
+
+
Name
+
+ onChange({...value, name})} value={value.name} readOnly={!!value.creationTimestamp} /> +
+
+
+
Generate Name
+
+ onChange({...value, generateName})} value={value.generateName} readOnly={!!value.creationTimestamp} /> +
+
+
+
Namespace
+
+ onChange({...value, namespace})} value={value.namespace} readOnly={!!value.creationTimestamp} /> +
+
+
+ + + ); +}; diff --git a/ui/src/app/shared/components/editors/workflow-spec-editor.scss b/ui/src/app/shared/components/editors/workflow-spec-editor.scss new file mode 100644 index 000000000000..9f3c1e257121 --- /dev/null +++ b/ui/src/app/shared/components/editors/workflow-spec-editor.scss @@ -0,0 +1,23 @@ +@import 'node_modules/argo-ui/src/styles/config'; + +.object-palette { + margin: 10px; + padding: 10px; + display: inline-block; + background-color: white; + box-shadow: 1px 1px 3px $argo-color-gray-5; + text-align: center; + + a { + padding: 10px; + color: $argo-color-gray-6; + border: 1px solid transparent; + border-radius: 5px; + font-size: 150%; + + &.active { + background-color: $argo-color-gray-3; + border: 1px solid $argo-color-gray-4; + } + } +} \ No newline at end of file diff --git a/ui/src/app/shared/components/editors/workflow-spec-editor.tsx b/ui/src/app/shared/components/editors/workflow-spec-editor.tsx new file mode 100644 index 000000000000..56e8e83d6d54 --- /dev/null +++ b/ui/src/app/shared/components/editors/workflow-spec-editor.tsx @@ -0,0 +1,265 @@ +import {SlidingPanel} from 'argo-ui'; +import * as React from 'react'; +import {WorkflowSpec} from '../../../../models'; +import {exampleTemplate, randomSillyName} from '../../examples'; +import {Button} from '../button'; +import {ObjectEditor} from '../object-editor/object-editor'; +import {icons} from '../workflow-spec-panel/icons'; +import {idForTemplate, onExitId, stepGroupOf, stepOf, taskOf, templateOf, typeOf} from '../workflow-spec-panel/id'; +import {WorkflowSpecPanel} from '../workflow-spec-panel/workflow-spec-panel'; + +require('./workflow-spec-editor.scss'); + +const type = (id: string) => { + const types: {[key: string]: string} = { + Step: 'io.argoproj.workflow.v1alpha1.WorkflowStep', + Template: 'io.argoproj.workflow.v1alpha1.Template', + Task: 'io.argoproj.workflow.v1alpha1.DagTask', + Workflow: 'io.argoproj.workflow.v1alpha1.WorkflowSpec' + }; + return types[typeOf(id)]; +}; + +export const WorkflowSpecEditor = (props: {value: T; onChange: (value: T) => void; onError: (error: Error) => void}) => { + const [selectedId, setSelectedId] = React.useState(); + + const object = (id: string) => { + const template = (name: string) => props.value.templates.filter(t => !!t).find(t => t.name === name); + switch (typeOf(id)) { + case 'Artifacts': + return props.value.arguments.artifacts; + case 'OnExit': + return props.value.onExit; + case 'Parameters': + return props.value.arguments.parameters; + case 'Step': { + const {templateName, i, j} = stepOf(id); + return template(templateName).steps[i][j]; + } + case 'StepGroup': { + const {templateName, i} = stepGroupOf(id); + return template(templateName).steps[i]; + } + case 'Task': { + const {templateName, taskName} = taskOf(id); + return template(templateName).dag.tasks.find(task => task.name === taskName); + } + case 'Template': + return template(templateOf(id).templateName); + case 'WorkflowTemplateRef': + return props.value.workflowTemplateRef; + } + }; + const setObject = (id: string, value: any) => { + switch (typeOf(id)) { + case 'Artifacts': + props.value.arguments.artifacts = value; + break; + case 'OnExit': + props.value.onExit = value; + break; + case 'Parameters': + props.value.arguments.parameters = value; + break; + case 'Step': + { + const {templateName, i, j} = stepOf(id); + props.value.templates.find(t => t.name === templateName).steps[i][j] = value; + } + break; + case 'StepGroup': + { + const {templateName, i} = stepGroupOf(id); + props.value.templates.find(t => t.name === templateName).steps[i] = value; + } + break; + case 'Task': + { + const {templateName, taskName} = taskOf(id); + const tasks = props.value.templates.find(t => t.name === templateName).dag.tasks; + const i = tasks.findIndex(t => t.name === taskName); + tasks[i] = value; + } + break; + case 'Template': + { + const {templateName} = templateOf(id); + const i = props.value.templates.findIndex(t => t.name === templateName); + props.value.templates[i] = value; + } + break; + case 'WorkflowTemplateRef': + props.value.workflowTemplateRef = value; + break; + } + }; + const deleteObject = (id: string) => { + switch (typeOf(id)) { + case 'Artifacts': + delete props.value.arguments.artifacts; + break; + case 'OnExit': + delete props.value.onExit; + break; + case 'Parameters': + delete props.value.arguments.parameters; + break; + case 'Step': + { + const {templateName, i, j} = stepOf(id); + props.value.templates.find(t => t.name === templateName).steps[i].splice(j, 1); + } + break; + case 'StepGroup': + { + const {templateName, i} = stepGroupOf(id); + props.value.templates.find(t => t.name === templateName).steps.splice(i, 1); + } + break; + case 'Task': + { + const {templateName, taskName} = taskOf(id); + const tasks = props.value.templates.find(t => t.name === templateName).dag.tasks; + const i = tasks.findIndex(t => t.name === taskName); + tasks.splice(i, 1); + } + break; + case 'Template': + { + const {templateName} = templateOf(id); + const i = props.value.templates.findIndex(t => t.name === templateName); + props.value.templates.splice(i, 1); + } + break; + case 'WorkflowTemplateRef': + delete props.value.workflowTemplateRef; + break; + } + }; + const anyContainerOrScriptTemplate = () => props.value.templates.find(t => t.container || t.script); + const bestTemplateName = () => (anyContainerOrScriptTemplate() || {name: 'TBD'}).name; + return ( +
+
+
+ +
+
+
+ { + const templateName = randomSillyName(); + props.value.templates.push(exampleTemplate(templateName)); + props.onChange(props.value); + setSelectedId(idForTemplate(templateName)); + }}> + {' '} + + { + const templateName = randomSillyName(); + props.value.templates.push({ + name: templateName, + inputs: { + parameters: [{name: 'message', value: '{{workflow.parameters.message}}'}] + }, + script: { + image: 'docker/whalesay:latest', + command: ['sh'], + source: 'echo {{inputs.parameters.message}}' + } + }); + props.onChange(props.value); + setSelectedId(idForTemplate(templateName)); + }}> + + + { + const templateName = randomSillyName(); + props.value.templates.push({ + name: templateName, + dag: { + tasks: [ + { + name: 'main', + template: bestTemplateName() + } + ] + } + }); + props.onChange(props.value); + setSelectedId(idForTemplate(templateName)); + }}> + + + { + const templateName = randomSillyName(); + props.value.templates.push({ + name: templateName, + steps: [ + [ + { + name: 'main', + template: bestTemplateName() + } + ] + ] + }); + props.onChange(props.value); + setSelectedId(idForTemplate(templateName)); + }}> + + + { + props.value.onExit = bestTemplateName(); + props.onChange(props.value); + setSelectedId(onExitId); + }}> + + +
+
+
+ setSelectedId(null)} isNarrow={true}> + {selectedId && object(selectedId) ? ( + <> +

{selectedId}

+ setObject(selectedId, value)} + buttons={ + <> + + + + } + /> + + ) : ( + <> +

Specification

+ + + )} +
+
+ ); +}; diff --git a/ui/src/app/shared/components/error-notice.tsx b/ui/src/app/shared/components/error-notice.tsx index 2b50e73db1bf..23c187444e4d 100644 --- a/ui/src/app/shared/components/error-notice.tsx +++ b/ui/src/app/shared/components/error-notice.tsx @@ -7,13 +7,20 @@ import {PhaseIcon} from './phase-icon'; // If the error was a HTTP error (i.e. from super-agent), rather than just an unhelpful "Internal Server Error", // it will display any message in the body. export const ErrorNotice = (props: {style?: CSSProperties; error: Error & {response?: {body: {message?: string}}}; onReload?: () => void; reloadAfterSeconds?: number}) => { + if (!props.error) { + return null; + } + const [error, setError] = useState(props.error); // allow us to close the error panel - in case it does not get automatically closed // This timer code is based on https://stackoverflow.com/questions/57137094/implementing-a-countdown-timer-in-react-with-hooks const reloadAfterSeconds = props.reloadAfterSeconds || 120; - const reload = props.onReload || document.location.reload; + const reload = props.onReload; const [timeLeft, setTimeLeft] = useState(reloadAfterSeconds); - const canAutoReload = reload !== document.location.reload; // we cannot automatically call `document.location.reload` - if (canAutoReload) { + // we cannot automatically call `document.location.reload` + if (reload) { useEffect(() => { + if (!error) { + return; + } if (!timeLeft) { reload(); setTimeLeft(reloadAfterSeconds); @@ -22,16 +29,30 @@ export const ErrorNotice = (props: {style?: CSSProperties; error: Error & {respo setTimeLeft(timeLeft - 1); }, 1000); return () => clearInterval(intervalId); - }, [timeLeft]); + }, [timeLeft, error]); + } + if (!error) { + return null; } return ( - - {props.error.message || 'Unknown error. Open your browser error console for more information.'} - {props.error.response && props.error.response.body && props.error.response.body.message && ': ' + props.error.response.body.message}:{' '} - reload()}> - Reload - {' '} - {canAutoReload && `${timeLeft}s`} + + + {error.message || 'Unknown error. Open your browser error console for more information.'} + {props.error.response && error.response.body && error.response.body.message && ': ' + error.response.body.message} + + {reload && ( + + reload()}> + Reload + {' '} + {timeLeft}s + + )} + + setError(null)}> + + + ); }; diff --git a/ui/src/app/shared/components/filter-drop-down.tsx b/ui/src/app/shared/components/filter-drop-down.tsx new file mode 100644 index 000000000000..4d24d421d899 --- /dev/null +++ b/ui/src/app/shared/components/filter-drop-down.tsx @@ -0,0 +1,16 @@ +import {DropDown} from 'argo-ui/src/components/dropdown/dropdown'; +import * as React from 'react'; +import {CheckboxList} from './checkbox-list'; + +export const FilterDropDown = (props: {values: {[label: string]: boolean}; onChange: (label: string, checked: boolean) => void}) => ( + ( +
props.values.size ? ' top-bar__filter--selected' : '')}> + + +
+ )}> + props.onChange(label, checked)} /> +
+); diff --git a/ui/src/app/shared/components/graph/coffman-graham-sorter.ts b/ui/src/app/shared/components/graph/coffman-graham-sorter.ts new file mode 100644 index 000000000000..fa778cce9c7f --- /dev/null +++ b/ui/src/app/shared/components/graph/coffman-graham-sorter.ts @@ -0,0 +1,48 @@ +import {DfsSorter} from './dfs-sorter'; +import {Graph, Node} from './types'; + +export class CoffmanGrahamSorter { + private graph: Graph; + private width: number = 9999; + + constructor(g: Graph) { + this.graph = g; + } + + public sort() { + // normally you should remove transitive here, but this is expensive, and we don't expect to find any + // this.graph.removeTransitives(); + const nodes = new DfsSorter(this.graph).sort(); + const layers = new Array(); + const levels = new Map(); + + nodes.forEach(n => { + let dependantLevel = -1; + this.graph.incomingEdges(n).forEach(dependant => { + const l = levels.get(dependant); + if (l === null) { + throw new Error('dependency order'); + } + if (l > dependantLevel) { + dependantLevel = l; + } + }); + let level = -1; + if (dependantLevel < layers.length - 1) { + for (let i = dependantLevel + 1; i < layers.length; i++) { + if (layers[i].length < this.width) { + level = i; + break; + } + } + } + if (level === -1) { + layers.push(new Array(0)); + level = layers.length - 1; + } + layers[level].push(n); + levels.set(n, level); + }); + return layers; + } +} diff --git a/ui/src/app/shared/components/graph/dfs-sorter.ts b/ui/src/app/shared/components/graph/dfs-sorter.ts new file mode 100644 index 000000000000..aa3d4c518163 --- /dev/null +++ b/ui/src/app/shared/components/graph/dfs-sorter.ts @@ -0,0 +1,26 @@ +import {Graph, Node} from './types'; + +export class DfsSorter { + private graph: Graph; + private sorted: Node[] = []; + private discovered: Set = new Set(); + + constructor(g: Graph) { + this.graph = g; + } + + public sort() { + // Pre-order DFS sort + this.graph.nodes.forEach((_, n) => this.visit(n)); + return this.sorted.reverse(); + } + + private visit(n: Node) { + if (this.discovered.has(n)) { + return; + } + this.graph.outgoingEdges(n).forEach(outgoing => this.visit(outgoing)); + this.discovered.add(n); + this.sorted.push(n); + } +} diff --git a/ui/src/app/shared/components/graph/fast-layout.ts b/ui/src/app/shared/components/graph/fast-layout.ts new file mode 100644 index 000000000000..82ce670c4ef8 --- /dev/null +++ b/ui/src/app/shared/components/graph/fast-layout.ts @@ -0,0 +1,56 @@ +import {CoffmanGrahamSorter} from './coffman-graham-sorter'; +import {Edge, Graph, Node} from './types'; + +const minSize = 1; +export const layoutGraphFast = (graph: Graph, nodeSize: number, horizontal: boolean, hidden: (id: Node) => boolean) => { + const gap = nodeSize * 1.25; + const layers = new CoffmanGrahamSorter(graph).sort(); + + // we have a lot of logic here about laying it out with suitable gaps - but what if we + // would just translate it somehow? + if (horizontal) { + graph.width = layers.length * gap * 2; + graph.height = 0; + } else { + graph.width = 0; + graph.height = layers.length * gap * 2; + } + layers.forEach(level => { + if (horizontal) { + graph.height = Math.max(graph.height, level.length * gap * 2); + } else { + graph.width = Math.max(graph.width, level.length * gap * 2); + } + }); + layers.forEach((level, i) => { + level.forEach((node, j) => { + const l = horizontal ? minSize : graph.width / 2 - level.length * gap; + const t = !horizontal ? minSize : graph.height / 2 - level.length * gap; + const label = graph.nodes.get(node); + label.x = (horizontal ? i : j) * gap * 2 + l; + label.y = (horizontal ? j : i) * gap * 2 + t; + }); + }); + graph.edges.forEach((label, e) => { + if (graph.nodes.has(e.v) && graph.nodes.has(e.w)) { + label.points = generateEdge(graph, e, nodeSize, horizontal, hidden); + } + }); +}; + +const generateEdge = (graph: Graph, edge: Edge, nodeSize: number, horizontal: boolean, hiddenNode: (id: Node) => boolean) => { + // `h` and `v` move the arrow heads to next to the node, otherwise they would be behind it + const h = horizontal ? nodeSize / 2 : 0; + const v = !horizontal ? nodeSize / 2 : 0; + return [ + { + // for hidden nodes, we want to size them zero + x: graph.nodes.get(edge.v).x + (hiddenNode(edge.v) ? minSize : h), + y: graph.nodes.get(edge.v).y + (hiddenNode(edge.v) ? minSize : v) + }, + { + x: graph.nodes.get(edge.w).x - (hiddenNode(edge.w) ? minSize : h), + y: graph.nodes.get(edge.w).y - (hiddenNode(edge.w) ? minSize : v) + } + ]; +}; diff --git a/ui/src/app/shared/components/graph/graph-panel.scss b/ui/src/app/shared/components/graph/graph-panel.scss new file mode 100644 index 000000000000..5d64af5af2bc --- /dev/null +++ b/ui/src/app/shared/components/graph/graph-panel.scss @@ -0,0 +1,163 @@ +@import 'node_modules/argo-ui/src/styles/config'; + +@keyframes pulse { + 0% { + transform: scale(1); + } + 25% { + transform: scale(1.3); + } + 50% { + transform: scale(1); + } + 75% { + transform: scale(1.1); + } + 100% { + transform: scale(1); + } +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +.graph-options-panel { + margin: 10px; + padding: 10px; + display: inline-block; + background-color: white; + box-shadow: 1px 1px 3px $argo-color-gray-5; + + a { + padding: 10px; + color: $argo-color-gray-6; + border: 1px solid transparent; + border-radius: 5px; + + &.active { + background-color: $argo-color-gray-3; + border: 1px solid $argo-color-gray-4; + } + } +} + +.graph { + overflow: scroll; + text-align: center; + + .group { + rect { + fill: transparent; + stroke: $argo-color-gray-4; + stroke-dasharray: 4; + } + } + + text { + text-anchor: middle; + dominant-baseline: central; + + &.node-label { + fill: $argo-color-gray-8; + } + } + + .node { + cursor: pointer; + + text { + fill: $argo-color-gray-1; + + &.icon { + font-family: "Font Awesome 5 Free", serif; + } + } + + .bg { + fill: $argo-color-gray-6; + } + + &.Warning, &.Pending { + .bg { + fill: $argo-status-warning-color; + } + } + + &.Suspended { + .bg { + fill: $argo-status-warning-color; + } + + animation: pulse 2s linear infinite; + } + + &.Skipped, &.Omitted { + .bg { + fill: $argo-color-gray-6; + } + } + + &.Running { + .bg { + fill: $argo-running-color; + } + + text.icon { + animation: spin 1s linear infinite; + } + } + + &.Succeeded { + .bg { + fill: $argo-success-color; + } + } + + &.Error, &.Failed { + .bg { + fill: $argo-failed-color; + } + } + + &.selected { + .bg { + stroke: $argo-color-yellow; + } + } + + path.icon { + fill: transparent; + stroke: $argo-color-gray-2; + } + } + + .edge { + text { + fill: $argo-color-gray-8; + } + + .line { + fill: transparent; + stroke: $argo-color-gray-4; + } + + .edge-label { + transform: rotate(-22.5deg); + } + + &.arrow .line { + marker-end: url(#arrow); + } + + &.related .line { + stroke-dasharray: 2; + } + } + + .arrow { + fill: $argo-color-gray-4; + } +} \ No newline at end of file diff --git a/ui/src/app/shared/components/graph/graph-panel.tsx b/ui/src/app/shared/components/graph/graph-panel.tsx new file mode 100644 index 000000000000..e5fc39516c4f --- /dev/null +++ b/ui/src/app/shared/components/graph/graph-panel.tsx @@ -0,0 +1,188 @@ +import * as React from 'react'; +import {useEffect} from 'react'; +import {ScopedLocalStorage} from '../../scoped-local-storage'; +import {FilterDropDown} from '../filter-drop-down'; +import {Icon} from '../icon'; +import {GraphIcon} from './icon'; +import {formatLabel} from './label'; +import {layout} from './layout'; +import {Graph, Node} from './types'; + +require('./graph-panel.scss'); + +type IconShape = 'rect' | 'circle'; + +interface NodeGenres { + [type: string]: boolean; +} + +interface NodeClassNames { + [type: string]: boolean; +} + +interface Props { + graph: Graph; + storageScope: string; // the scope of storage, similar graphs should use the same vaulue + options?: React.ReactNode; // add to the option panel + classNames?: string; + nodeGenres: NodeGenres; + nodeClassNames?: NodeClassNames; + nodeSize?: number; // default "64" + horizontal?: boolean; // default "false" + hideNodeTypes?: boolean; // default "false" + defaultIconShape?: IconShape; // default "rect" + iconShapes?: {[type: string]: Icon}; + selectedNode?: Node; + onNodeSelect?: (id: Node) => void; +} + +export const GraphPanel = (props: Props) => { + const storage = new ScopedLocalStorage('graph/' + props.storageScope); + const [nodeSize, setNodeSize] = React.useState(storage.getItem('nodeSize', props.nodeSize)); + const [horizontal, setHorizontal] = React.useState(storage.getItem('horizontal', props.horizontal)); + const [fast, setFast] = React.useState(storage.getItem('fast', false)); + const [nodeGenres, setNodeGenres] = React.useState(storage.getItem('nodeGenres', props.nodeGenres)); + const [nodeClassNames, setNodeClassNames] = React.useState(storage.getItem('nodeClassNames', props.nodeClassNames)); + + useEffect(() => storage.setItem('nodeSize', nodeSize, props.nodeSize), [nodeSize]); + useEffect(() => storage.setItem('horizontal', horizontal, props.horizontal), [horizontal]); + useEffect(() => storage.setItem('fast', fast, false), [fast]); + useEffect(() => storage.setItem('nodeGenres', nodeGenres, props.nodeGenres), [nodeGenres]); + useEffect(() => storage.setItem('nodeClassNames', nodeClassNames, props.nodeClassNames), [nodeClassNames]); + + const visible = (id: Node) => { + const label = props.graph.nodes.get(id); + return ( + nodeGenres[label.genre] && + (!nodeClassNames || Object.entries(nodeClassNames).find(([className, checked]) => checked && (label.classNames || '').split(' ').includes(className))) + ); + }; + + layout(props.graph, nodeSize, horizontal, id => !visible(id), fast); + const width = props.graph.width; + const height = props.graph.height; + + return ( +
+
+ { + setNodeGenres(v => { + v[label] = checked; + return Object.assign({}, v); + }); + }} + /> + {nodeClassNames && ( + { + setNodeClassNames(v => { + v[label] = checked; + return Object.assign({}, v); + }); + }} + /> + )} + setHorizontal(s => !s)} title='Horizontal/vertical layout'> + + + setNodeSize(s => s * 1.2)} title='Zoom in'> + + + setNodeSize(s => s / 1.2)} title='Zoom out'> + + + setFast(s => !s)} title='Use faster, but less pretty renderer' className={fast ? 'active' : ''}> + + + {props.options} +
+
+ {props.graph.nodes.size === 0 ? ( +

Nothing to show

+ ) : ( + + + + + + + + {Array.from(props.graph.nodeGroups).map(([g, nodes]) => { + const r: {x1: number; y1: number; x2: number; y2: number} = { + x1: width, + y1: height, + x2: 0, + y2: 0 + }; + nodes.forEach(n => { + const l = props.graph.nodes.get(n); + r.x1 = Math.min(r.x1, l.x); + r.y1 = Math.min(r.y1, l.y); + r.x2 = Math.max(r.x2, l.x); + r.y2 = Math.max(r.y2, l.y); + }); + return ( + + + + ); + })} + {Array.from(props.graph.edges) + .filter(([, label]) => label.points) + .map(([e, label]) => ( + + (j === 0 ? `M ${p.x} ${p.y} ` : `L ${p.x} ${p.y}`)).join(' ')} + className='line' + strokeWidth={nodeSize / 32} + /> + + + {formatLabel(label.label)} + + + + ))} + {Array.from(props.graph.nodes) + .filter(([n, label]) => label.x !== null && visible(n)) + .map(([n, label]) => ( + + {n} + props.onNodeSelect && props.onNodeSelect(n)}> + {((props.iconShapes || {})[label.genre] || props.defaultIconShape) === 'circle' ? ( + + ) : ( + + )} + + {props.hideNodeTypes || ( + + {label.genre} + + )} + + + + {formatLabel(label.label)} + + + + ))} + + + )} +
+
+ ); +}; + +GraphPanel.defaultProps = { + nodeSize: 64 +}; diff --git a/ui/src/app/shared/components/graph/icon.tsx b/ui/src/app/shared/components/graph/icon.tsx new file mode 100644 index 000000000000..ead5b9fb7e0d --- /dev/null +++ b/ui/src/app/shared/components/graph/icon.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import {Icon} from '../icon'; +import {icons} from '../icons'; + +export const GraphIcon = ({nodeSize, progress, icon}: {icon: Icon; progress?: number; nodeSize: number}) => { + if (!progress) { + return ( + + {icons[icon]} + + ); + } + const radius = nodeSize / 4; + const offset = (2 * Math.PI * 3) / 4; + const theta0 = offset; + // clip the line to min 5% max 95% so something always renders + const theta1 = 2 * Math.PI * Math.max(0.05, Math.min(0.95, progress)) + offset; + const start = {x: radius * Math.cos(theta0), y: radius * Math.sin(theta0)}; + const end = {x: radius * Math.cos(theta1), y: radius * Math.sin(theta1)}; + const theta = theta1 - theta0; + const largeArcFlag = theta > Math.PI ? 1 : 0; + const sweepFlag = 1; + return ; +}; diff --git a/ui/src/app/shared/components/graph/label.tsx b/ui/src/app/shared/components/graph/label.tsx new file mode 100644 index 000000000000..44ae66bc5c81 --- /dev/null +++ b/ui/src/app/shared/components/graph/label.tsx @@ -0,0 +1,33 @@ +import * as React from 'react'; + +export const formatLabel = (label: string) => { + if (!label) { + return; + } + const maxPerLine = 14; + if (label.length <= maxPerLine) { + return {label}; + } + if (label.length <= maxPerLine * 2) { + return ( + <> + + {label.substr(0, label.length / 2)} + + + {label.substr(label.length / 2)} + + + ); + } + return ( + <> + + {label.substr(0, maxPerLine - 2)}.. + + + {label.substr(label.length + 1 - maxPerLine)} + + + ); +}; diff --git a/ui/src/app/shared/components/graph/layout.ts b/ui/src/app/shared/components/graph/layout.ts new file mode 100644 index 000000000000..bb5cd34f8d15 --- /dev/null +++ b/ui/src/app/shared/components/graph/layout.ts @@ -0,0 +1,10 @@ +import {layoutGraphFast} from './fast-layout'; +import {layoutGraphPretty} from './pretty-layout'; +import {Graph, Node} from './types'; + +export const layout = (graph: Graph, nodeSize: number, horizontal: boolean, hidden: (id: Node) => boolean, fast: boolean) => { + // TODO - we should not re-layout the graph if options have not changed + // if (Array.from(graph.nodes).find(([, l]) => l.x === undefined)) { + (fast ? layoutGraphFast : layoutGraphPretty)(graph, nodeSize, horizontal, hidden); + // } +}; diff --git a/ui/src/app/shared/components/graph/pretty-layout.ts b/ui/src/app/shared/components/graph/pretty-layout.ts new file mode 100644 index 000000000000..3573d8819edc --- /dev/null +++ b/ui/src/app/shared/components/graph/pretty-layout.ts @@ -0,0 +1,42 @@ +import * as dagre from 'dagre'; +import {Graph, Node} from './types'; + +const minSize = 1; +export const layoutGraphPretty = (graph: Graph, nodeSize: number, horizontal: boolean, hidden: (id: Node) => boolean) => { + const gap = nodeSize * 1.25; + const g = new dagre.graphlib.Graph(); + g.setGraph({rankdir: horizontal ? 'LR' : 'TB', ranksep: gap, nodesep: gap, edgesep: gap}); + g.setDefaultEdgeLabel(() => ({})); + graph.nodes.forEach((label, id) => + g.setNode(id, { + width: hidden(id) ? minSize : nodeSize, + height: hidden(id) ? minSize : nodeSize + }) + ); + graph.edges.forEach((label, e) => { + if (graph.nodes.has(e.v) && graph.nodes.has(e.w)) { + g.setEdge(e.v, e.w); + } + }); + + dagre.layout(g); + + graph.width = 0; + graph.height = 0; + graph.nodes.forEach((label, id) => { + graph.nodes.get(id).x = g.node(id).x; + graph.nodes.get(id).y = g.node(id).y; + graph.width = Math.max(graph.width, label.x + nodeSize); + graph.height = Math.max(graph.height, label.y + nodeSize); + }); + graph.edges.forEach((label, e) => { + if (graph.nodes.has(e.v) && graph.nodes.has(e.w)) { + const points = g.edge(e).points; + graph.edges.get(e).points = points; + points.forEach(p => { + graph.width = Math.max(graph.width, p.x + nodeSize); + graph.height = Math.max(graph.height, p.y + nodeSize); + }); + } + }); +}; diff --git a/ui/src/app/shared/components/graph/types.ts b/ui/src/app/shared/components/graph/types.ts new file mode 100644 index 000000000000..f997de8bae8e --- /dev/null +++ b/ui/src/app/shared/components/graph/types.ts @@ -0,0 +1,53 @@ +import {Icon} from '../icon'; + +export type Node = string; +type NodeGroup = string; + +export interface NodeLabel { + label: string; // the label of the node - placed below the icon + genre: string; // the class or type of the node, displayed below the icon + icon?: Icon; + classNames?: string; + progress?: number; // progress between 0..1 + x?: number; + y?: number; +} + +interface EdgeLabel { + label?: string; + classNames?: string; + points?: {x: number; y: number}[]; +} + +export interface Edge { + v: string; + w: string; +} + +export class Graph { + public nodes: Map = new Map(); + public edges: Map = new Map(); + public nodeGroups: Map> = new Map(); + public width?: number; + public height?: number; + + public outgoingEdges(v: Node) { + const edges: Node[] = []; + this.edges.forEach((_, e) => { + if (v === e.v) { + edges.push(e.w); + } + }); + return edges; + } + + public incomingEdges(w: Node) { + const edges: Node[] = []; + this.edges.forEach((_, e) => { + if (e.w === w) { + edges.push(e.v); + } + }); + return edges; + } +} diff --git a/ui/src/app/shared/components/icon.ts b/ui/src/app/shared/components/icon.ts new file mode 100644 index 000000000000..4bc58f75e432 --- /dev/null +++ b/ui/src/app/shared/components/icon.ts @@ -0,0 +1,55 @@ +export type Icon = + | 'arrow-left' + | 'arrow-right' + | 'bell' + | 'box' + | 'calendar' + | 'cloud' + | 'circle' + | 'circle-notch' + | 'clock' + | 'code' + | 'comment' + | 'code-branch' + | 'credit-card' + | 'check' + | 'database' + | 'envelope' + | 'edit' + | 'ellipsis-h' + | 'file' + | 'file-alt' + | 'file-code' + | 'filter' + | 'forward' + | 'grip-vertical' + | 'hdd' + | 'info-circle' + | 'keyboard' + | 'link' + | 'list' + | 'microchip' + | 'play' + | 'play-circle' + | 'plus-circle' + | 'puzzle-piece' + | 'pause' + | 'pause-circle' + | 'plus' + | 'redo-alt' + | 'save' + | 'sign-out-alt' + | 'sitemap' + | 'stream' + | 'square' + | 'sync-alt' + | 'tasks' + | 'trash' + | 'th' + | 'times' + | 'times-circle' + | 'toggle-off' + | 'toggle-on' + | 'undo-alt' + | 'window-restore' + | 'window-maximize'; diff --git a/ui/src/app/shared/components/icons.ts b/ui/src/app/shared/components/icons.ts new file mode 100644 index 000000000000..06de703741ff --- /dev/null +++ b/ui/src/app/shared/components/icons.ts @@ -0,0 +1,48 @@ +export const icons: {[key: string]: string} = { + 'arrow-right': '\uf061', + 'bell': '\uf0f3', + 'box': '\uf466', + 'calendar': '\uf133', + 'cloud': '\uf0c2', + 'circle': '\uf111', + 'circle-notch': '\uf1ce', + 'clock': '\uf017', + 'code': '\uf121', + 'comment': '\uf075', + 'code-branch': '\uf126', + 'credit-card': '\uf09d', + 'check': '\uf00c', + 'database': '\uf1c0', + 'envelope': '\uf0e0', + 'ellipsis-h': '\uf141', + 'file': '\uf15b', + 'file-alt': '\uf15c', + 'file-code': '\uf1c9', + 'filter': '\uf0b0', + 'forward': '\uf04e', + 'grip-vertical': '\uf58e', + 'hdd': '\uf0a0', + 'keyboard': '\uf11c', + 'link': '\uf0c1', + 'list': '\uf03a', + 'microchip': '\uf2db', + 'play': '\uf04b', + 'play-circle': '\uf144', + 'puzzle-piece': '\uf12e', + 'pause': '\uf04c', + 'pause-circle': '\uf28b', + 'redo-alt': '\uf2f9', + 'save': '\uf0c7', + 'sign-out-alt': '\uf2f5', + 'sitemap': '\uf0e8', + 'stream': '\uf550', + 'square': '\uf0c8', + 'sync-alt': '\uf2f1', + 'tasks': '\uf0ae', + 'th': '\uf00a', + 'times': '\uf00d', + 'times-circle': '\uf057', + 'undo-alt': '\uf2ea', + 'window-restore': '\uf2d2', + 'window-maximize': '\uf2d0' +}; diff --git a/ui/src/app/shared/components/link-button.tsx b/ui/src/app/shared/components/link-button.tsx index bffffaef046a..dad0212ac4ca 100644 --- a/ui/src/app/shared/components/link-button.tsx +++ b/ui/src/app/shared/components/link-button.tsx @@ -1,8 +1,9 @@ import * as React from 'react'; import {ReactNode} from 'react'; +import {Button} from './button'; export const LinkButton = (props: {to: string; children?: ReactNode}) => ( - + ); diff --git a/ui/src/app/shared/components/loading.tsx b/ui/src/app/shared/components/loading.tsx index e3029521435f..31f75903428f 100644 --- a/ui/src/app/shared/components/loading.tsx +++ b/ui/src/app/shared/components/loading.tsx @@ -1,4 +1,8 @@ import * as React from 'react'; import {MockupList} from '../../../../node_modules/argo-ui'; -export const Loading = () => ; +export const Loading = () => ( +
+ +
+); diff --git a/ui/src/app/shared/components/notice.tsx b/ui/src/app/shared/components/notice.tsx index 05f5757b02a2..ac4c139d0bd7 100644 --- a/ui/src/app/shared/components/notice.tsx +++ b/ui/src/app/shared/components/notice.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import {CSSProperties, ReactNode} from 'react'; export const Notice = (props: {style?: CSSProperties; children: ReactNode}) => ( -
+
{props.children}
); diff --git a/ui/src/app/shared/components/nudge.tsx b/ui/src/app/shared/components/nudge.tsx index fff19dc40ad9..c40be0800e40 100644 --- a/ui/src/app/shared/components/nudge.tsx +++ b/ui/src/app/shared/components/nudge.tsx @@ -10,7 +10,7 @@ export class Nudge extends React.Component<{key: string}, {closed: boolean}> { public render() { return ( !this.state.closed && ( - + {this.props.children} this.close()}> diff --git a/ui/src/app/shared/components/number-input.tsx b/ui/src/app/shared/components/number-input.tsx new file mode 100644 index 000000000000..c041c0831f70 --- /dev/null +++ b/ui/src/app/shared/components/number-input.tsx @@ -0,0 +1,5 @@ +import * as React from 'react'; +import {TextInput} from './text-input'; + +export const NumberInput = ({onChange, value, placeholder, readOnly}: {value: number; onChange: (value: number) => void; readOnly?: boolean; placeholder?: string}) => + readOnly ? <>{value} : onChange(parseInt(x, 10))} placeholder={placeholder} />; diff --git a/ui/src/app/shared/components/object-editor/object-editor.tsx b/ui/src/app/shared/components/object-editor/object-editor.tsx new file mode 100644 index 000000000000..2ad1f108ad45 --- /dev/null +++ b/ui/src/app/shared/components/object-editor/object-editor.tsx @@ -0,0 +1,102 @@ +import {languages} from 'monaco-editor/esm/vs/editor/editor.api'; +import * as React from 'react'; +import {createRef, useEffect, useState} from 'react'; +import MonacoEditor from 'react-monaco-editor'; +import {uiUrl} from '../../base'; +import {ScopedLocalStorage} from '../../scoped-local-storage'; +import {ErrorNotice} from '../error-notice'; +import {parse, stringify} from '../object-parser'; +import {ToggleButton} from '../toggle-button'; + +interface Props { + type: string; + value: T; + buttons?: React.ReactNode; + onChange?: (value: T) => void; +} + +const defaultLang = 'yaml'; + +export const ObjectEditor = ({type, value, buttons, onChange}: Props) => { + const storage = new ScopedLocalStorage('object-editor'); + const [error, setError] = useState(); + const [lang, setLang] = useState(storage.getItem('lang', defaultLang)); + const [text, setText] = useState(stringify(value, lang)); + + useEffect(() => storage.setItem('lang', lang, defaultLang), [lang]); + useEffect(() => setText(stringify(parse(text), lang)), [lang]); + if (onChange) { + useEffect(() => { + try { + onChange(parse(text)); + } catch (e) { + setError(e); + } + }, [text]); + } + + useEffect(() => { + if (type && lang === 'json') { + const uri = uiUrl('assets/jsonschema/schema.json'); + fetch(uri) + .then(res => res.json()) + .then(swagger => { + // adds auto-completion to JSON only + languages.json.jsonDefaults.setDiagnosticsOptions({ + validate: true, + schemas: [ + { + uri, + fileMatch: ['*'], + schema: { + $id: 'http://workflows.argoproj.io/' + type + '.json', + $ref: '#/definitions/' + type, + $schema: 'http://json-schema.org/draft-07/schema', + definitions: swagger.definitions + } + } + ] + }); + }) + .catch(setError); + } + }, [lang, type]); + + const editor = createRef(); + + return ( + <> +
+ setLang(lang === 'yaml' ? 'json' : 'yaml')}> + YAML + + {buttons} +
+ +
setText(editor.current.editor.getModel().getValue())}> + +
+
+ + ); +}; diff --git a/ui/src/app/shared/components/object-parser.ts b/ui/src/app/shared/components/object-parser.ts new file mode 100644 index 000000000000..d5cec314858a --- /dev/null +++ b/ui/src/app/shared/components/object-parser.ts @@ -0,0 +1,12 @@ +import jsyaml = require('js-yaml'); + +export function parse(value: string) { + if (value.startsWith('{')) { + return JSON.parse(value); + } + return jsyaml.load(value); +} + +export function stringify(value: T, type: string) { + return type === 'yaml' ? jsyaml.dump(value, {noRefs: true}) : JSON.stringify(value, null, ' '); +} diff --git a/ui/src/app/shared/components/query.tsx b/ui/src/app/shared/components/query.tsx index 5cc428862419..bff4a55aac6e 100644 --- a/ui/src/app/shared/components/query.tsx +++ b/ui/src/app/shared/components/query.tsx @@ -1,48 +1,10 @@ -import * as PropTypes from 'prop-types'; import * as React from 'react'; -import {BehaviorSubject, Observable} from 'rxjs'; -import {AppContext, Consumer} from '../context'; +import {Consumer} from '../context'; +/** + * @deprecated Use React hooks instead. + */ export const Query = (props: {children: (params: URLSearchParams) => React.ReactNode}) => ( {ctx => props.children(new URLSearchParams(ctx.history.location.search))} ); - -export interface ObservableQueryProps { - children: (params: Observable) => React.ReactNode; -} - -export class ObservableQuery extends React.Component { - public static contextTypes = { - router: PropTypes.object - }; - - private search: BehaviorSubject; - private stopListen: () => void; - - constructor(props: ObservableQueryProps) { - super(props); - } - - public componentWillMount() { - this.search = new BehaviorSubject(this.appContext.router.history.location.search); - this.stopListen = this.appContext.router.history.listen(location => { - this.search.next(location.search); - }); - } - - public componentWillUnmount() { - if (this.stopListen) { - this.stopListen(); - this.stopListen = null; - } - } - - public render() { - return this.props.children(this.search.map(search => new URLSearchParams(search))); - } - - private get appContext(): AppContext { - return this.context as AppContext; - } -} diff --git a/ui/src/app/shared/components/resource-editor/resource-editor.tsx b/ui/src/app/shared/components/resource-editor/resource-editor.tsx index e3d8ab27b665..8a7c4efa80c0 100644 --- a/ui/src/app/shared/components/resource-editor/resource-editor.tsx +++ b/ui/src/app/shared/components/resource-editor/resource-editor.tsx @@ -1,166 +1,75 @@ +import * as kubernetes from 'argo-ui/src/models/kubernetes'; import * as React from 'react'; -import MonacoEditor from 'react-monaco-editor'; -import {uiUrl} from '../../base'; - -import {languages} from 'monaco-editor/esm/vs/editor/editor.api'; +import {Button} from '../button'; import {ErrorNotice} from '../error-notice'; -import {ToggleButton} from '../toggle-button'; -import {parse, stringify} from './resource'; - -require('./resource.scss'); +import {ObjectEditor} from '../object-editor/object-editor'; +import {UploadButton} from '../upload-button'; interface Props { - kind: string; + kind?: string; upload?: boolean; namespace?: string; title?: string; value: T; - readonly?: boolean; editing?: boolean; onSubmit?: (value: T) => Promise; } -interface State { +interface State { editing: boolean; - lang: string; - value: string; + value: T; error?: Error; } -const LOCAL_STORAGE_KEY = 'ResourceEditorLang'; - -export class ResourceEditor extends React.Component, State> { - private set lang(lang: string) { - try { - this.setState(state => ({lang, error: null, value: stringify(parse(state.value), lang)})); - } catch (error) { - this.setState({error}); - } - } - - private static saveLang(newLang: string) { - localStorage.setItem(LOCAL_STORAGE_KEY, newLang); - } - - private static loadLang(): string { - const stored = localStorage.getItem(LOCAL_STORAGE_KEY); - if (stored !== null) { - if (stored === 'yaml' || stored === 'json') { - return stored; - } - } - return 'yaml'; - } - +export class ResourceEditor extends React.Component, State> { constructor(props: Readonly>) { super(props); - const storedLang = ResourceEditor.loadLang(); - this.state = {editing: this.props.editing, lang: storedLang, value: stringify(this.props.value, storedLang)}; - } - - public componentDidMount() { - const uri = uiUrl('assets/openapi-spec/swagger.json'); - fetch(uri) - .then(res => res.json()) - .then(swagger => { - // adds auto-completion to JSON only - languages.json.jsonDefaults.setDiagnosticsOptions({ - validate: true, - schemas: [ - { - uri, - fileMatch: ['*'], - schema: { - $id: 'http://workflows.argoproj.io/' + this.props.kind + '.json', - $ref: '#/definitions/io.argoproj.workflow.v1alpha1.' + this.props.kind, - $schema: 'http://json-schema.org/draft-07/schema', - definitions: swagger.definitions - } - } - ] - }); - }) - .catch(error => this.setState({error})); - } - - public componentDidUpdate(prevProps: Props) { - if (prevProps.value !== this.props.value) { - this.setState(state => ({value: stringify(this.props.value, state.lang)})); - } - } - - public handleFiles(files: FileList) { - files[0] - .text() - .then(value => stringify(parse(value), this.state.lang)) - .then(value => this.setState({error: null, value})) - .catch(error => this.setState(error)); + this.state = {editing: this.props.editing, value: this.props.value}; } public render() { return ( <> {this.props.title &&

{this.props.title}

} - {!this.props.readonly && this.renderButtons()} {this.state.error && } -
- this.setState({value})} - options={{ - readOnly: this.props.readonly || !this.state.editing, - extraEditorClassName: 'resource', - minimap: {enabled: false}, - lineNumbers: 'off', - renderIndentGuides: false - }} - /> -
- {this.renderWarning()} + this.setState({value})} + /> ); } - private changeLang() { - const newLang = this.state.lang === 'yaml' ? 'json' : 'yaml'; - this.lang = newLang; - ResourceEditor.saveLang(newLang); - } - private renderButtons() { return ( -
- {(this.state.editing && ( + <> + {this.state.editing ? ( <> - this.changeLang()}> - YAML - - {this.props.upload && ( - + {this.props.upload && onUpload={value => this.setState({value})} onError={error => this.setState({error})} />} + {this.props.onSubmit && ( + )} - - )) || ( - + ) : ( + this.props.onSubmit && ( + + ) )} -
+ ); } private submit() { try { - const value = parse(this.state.value); - if (!value.metadata.namespace && this.props.namespace) { + const value = this.state.value; + if (value.metadata && !value.metadata.namespace && this.props.namespace) { value.metadata.namespace = this.props.namespace; } this.props @@ -171,14 +80,4 @@ export class ResourceEditor extends React.Component, State> { this.setState({error}); } } - - private renderWarning() { - return ( -
- {' '} - {this.state.lang === 'json' ? <>Full auto-completion enabled. : <>Basic completion for YAML. Switch to JSON for full auto-completion.}{' '} - Learn how to get auto-completion in your IDE. -
- ); - } } diff --git a/ui/src/app/shared/components/tags-input/tags-input.tsx b/ui/src/app/shared/components/tags-input/tags-input.tsx index 369b652f48b8..2cb741e03026 100644 --- a/ui/src/app/shared/components/tags-input/tags-input.tsx +++ b/ui/src/app/shared/components/tags-input/tags-input.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import {Autocomplete, AutocompleteApi, AutocompleteOption} from 'argo-ui'; -export interface TagsInputProps { +interface TagsInputProps { tags: string[]; autocomplete?: (AutocompleteOption | string)[]; onChange?: (tags: string[]) => void; diff --git a/ui/src/app/shared/components/text-input.tsx b/ui/src/app/shared/components/text-input.tsx new file mode 100644 index 000000000000..1f506a1621b5 --- /dev/null +++ b/ui/src/app/shared/components/text-input.tsx @@ -0,0 +1,4 @@ +import * as React from 'react'; + +export const TextInput = ({placeholder, value, onChange, readOnly}: {value: string; onChange: (value: string) => void; readOnly?: boolean; placeholder?: string}) => + readOnly ? <>{value} : onChange(e.target.value)} placeholder={placeholder} />; diff --git a/ui/src/app/shared/components/toggle-button.tsx b/ui/src/app/shared/components/toggle-button.tsx index 9f0285faa82d..6010b2314e19 100644 --- a/ui/src/app/shared/components/toggle-button.tsx +++ b/ui/src/app/shared/components/toggle-button.tsx @@ -1,8 +1,9 @@ import * as React from 'react'; import {ReactNode} from 'react'; +import {Button} from './button'; -export const ToggleButton = (props: {toggled: boolean; onToggle: () => void; children: ReactNode; title?: string}) => ( - +export const ToggleButton = ({title, children, onToggle, toggled}: {toggled: boolean; onToggle: () => void; children: ReactNode; title?: string}) => ( + ); diff --git a/ui/src/app/shared/components/upload-button.tsx b/ui/src/app/shared/components/upload-button.tsx new file mode 100644 index 000000000000..80b00afad3fb --- /dev/null +++ b/ui/src/app/shared/components/upload-button.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; +import {parse} from './object-parser'; + +export const UploadButton = (props: {onUpload: (value: T) => void; onError: (error: Error) => void}) => { + const handleFiles = (files: FileList) => { + files[0] + .text() + .then(value => props.onUpload(parse(value) as T)) + .catch(props.onError); + }; + + return ( + + ); +}; diff --git a/ui/src/app/shared/components/workflow-spec-panel/genres.ts b/ui/src/app/shared/components/workflow-spec-panel/genres.ts new file mode 100644 index 000000000000..a9149878bf8f --- /dev/null +++ b/ui/src/app/shared/components/workflow-spec-panel/genres.ts @@ -0,0 +1,21 @@ +export const genres: {[genre: string]: boolean} = { + 'artifacts': true, + 'container': true, + 'dag': true, + 'depends': true, + 'task': true, + 'items': true, + 'on-exit': true, + 'param': true, + 'params': true, + 'resource': true, + 'script': true, + 'sequence': true, + 'step': true, + 'steps': true, + 'group': false, // step-group + 'suspend': true, + 'tmpl-ref': true, + 'when': true, + 'workflow': true +}; diff --git a/ui/src/app/shared/components/workflow-spec-panel/icons.ts b/ui/src/app/shared/components/workflow-spec-panel/icons.ts new file mode 100644 index 000000000000..c23533950ad0 --- /dev/null +++ b/ui/src/app/shared/components/workflow-spec-panel/icons.ts @@ -0,0 +1,25 @@ +import {Icon} from '../icon'; + +export const icons: {[genre: string]: Icon} = { + artifact: 'database', + artifacts: 'database', + dag: 'sitemap', + depends: 'filter', + container: 'box', + onExit: 'sign-out-alt', + parameters: 'keyboard', + resource: 'file-code', + script: 'file-alt', + step: 'check', + steps: 'tasks', + stepGroup: 'list', + suspend: 'pause-circle', + task: 'square', + templateRef: 'window-maximize', + clusterTemplateRef: 'window-restore', + when: 'filter', + withItems: 'sync-alt', + withParam: 'sync-alt', + withSequence: 'sync-alt', + workflow: 'stream' +}; diff --git a/ui/src/app/shared/components/workflow-spec-panel/id.ts b/ui/src/app/shared/components/workflow-spec-panel/id.ts new file mode 100644 index 000000000000..62fcfade7a11 --- /dev/null +++ b/ui/src/app/shared/components/workflow-spec-panel/id.ts @@ -0,0 +1,49 @@ +/* + * Artifacts + * OnExit + * Parameters + * StepGroup/{templateName}/{i} + * Step/{templateName}/{i}/{j} + * Task/{templateName}/{taskName} + * Template/{templateName} + * Workflow + * WorkflowTemplateRef + */ + +type Type = 'Workflow' | 'WorkflowTemplateRef' | 'Template' | 'StepGroup' | 'Step' | 'Task' | 'OnExit' | 'Parameters' | 'TemplateRef' | 'Artifacts'; + +export const workflowId: Type = 'Workflow'; +export const parametersId: Type = 'Parameters'; +export const artifactsId: Type = 'Artifacts'; +export const onExitId: Type = 'OnExit'; +export const workflowTemplateRefId: Type = 'WorkflowTemplateRef'; + +export const typeOf = (id: string): Type => id.split('/')[0] as Type; + +export const idForStepGroup = (templateName: string, i: number) => 'StepGroup/' + templateName + '/' + i; + +// TODO - we assume that template names are unique, but they may not be and that'll produce weird bugs +export const stepGroupOf = (id: string) => ({ + templateName: id.split('/')[1], + i: parseInt(id.split('/')[2], 10) +}); + +export const idForSteps = (templateName: string, i: number, j: number) => 'Step/' + templateName + '/' + i + '/' + j; +export const stepOf = (id: string) => ({ + templateName: id.split('/')[1], + i: parseInt(id.split('/')[2], 10), + j: parseInt(id.split('/')[3], 10) +}); + +export const idForTemplate = (templateName: string) => 'Template/' + templateName; +export const templateOf = (id: string) => ({ + templateName: id.split('/')[1] +}); + +export const idForTask = (templateName: string, taskName: string) => 'Task/' + templateName + '/' + taskName; +export const taskOf = (id: string) => ({ + templateName: id.split('/')[1], + taskName: id.split('/')[2] +}); + +export const idForTemplateRef = (templateName: string, template: string) => 'TemplateRef/' + templateName + '/' + template; diff --git a/ui/src/app/shared/components/workflow-spec-panel/workflow-spec-graph.ts b/ui/src/app/shared/components/workflow-spec-panel/workflow-spec-graph.ts new file mode 100644 index 000000000000..5f725c27df30 --- /dev/null +++ b/ui/src/app/shared/components/workflow-spec-panel/workflow-spec-graph.ts @@ -0,0 +1,173 @@ +import {Sequence, TemplateRef, WorkflowSpec} from '../../../../models'; +import {Graph} from '../graph/types'; +import {icons} from './icons'; +import {artifactsId, idForStepGroup, idForSteps, idForTask, idForTemplate, idForTemplateRef, onExitId, parametersId, workflowId, workflowTemplateRefId} from './id'; + +function addCommonDependencies( + x: {withItems?: string[]; withParam?: string; withSequence?: Sequence; template?: string; when?: string; templateRef?: TemplateRef; onExit?: string; depends?: string}, + id: string, + g: Graph +) { + if (x.withItems) { + const itemsId = id + '#withItems'; + g.nodes.set(itemsId, { + label: JSON.stringify(x.withItems), + genre: 'items', + icon: icons.withItems + }); + g.edges.set({v: itemsId, w: id}, {label: 'loop', classNames: 'related'}); + } + if (x.withParam) { + const paramId = id + '#withParam'; + g.nodes.set(paramId, { + label: x.withParam, + genre: 'param', + icon: icons.withParam + }); + g.edges.set({v: paramId, w: id}, {label: 'loop', classNames: 'related'}); + } + if (x.withSequence) { + const sequenceId = id + '#withSequence'; + g.nodes.set(sequenceId, { + label: x.withSequence.count ? '0..' + x.withSequence.count : x.withSequence.start + '..' + x.withSequence.end, + genre: 'sequence', + icon: icons.withSequence + }); + g.edges.set({v: sequenceId, w: id}, {label: 'loop', classNames: 'related'}); + } + if (x.template) { + g.edges.set({v: idForTemplate(x.template), w: id}, {classNames: 'related'}); + } + if (x.when) { + const whenId = id + '#when'; + g.nodes.set(whenId, {icon: icons.when, label: x.when, genre: 'when'}); + g.edges.set({v: whenId, w: id}, {label: 'when', classNames: 'related'}); + } + if (x.depends) { + const dependsId = id + '#depends'; + g.nodes.set(dependsId, {icon: icons.depends, label: x.depends, genre: 'depends'}); + g.edges.set({v: dependsId, w: id}, {label: 'depends'}); + } + if (x.templateRef) { + const templateRefId = idForTemplateRef(x.templateRef.name, x.templateRef.template); + g.nodes.set(templateRefId, { + label: x.templateRef.name, + genre: 'tmpl-ref', + icon: x.templateRef.clusterScope ? icons.clusterTemplateRef : icons.templateRef + }); + g.edges.set({v: templateRefId, w: id}, {}); + } + if (x.onExit) { + const exitId = id + '#onExit'; + g.nodes.set(exitId, {label: 'on-exit', genre: 'on-exit', icon: icons.onExit}); + g.edges.set({v: 'Template/' + x.onExit, w: exitId}, {classNames: 'related'}); + g.edges.set({v: id, w: exitId}, {}); + } +} + +export const workflowSpecGraph = (s: WorkflowSpec): Graph => { + const g = new Graph(); + g.nodes.set(workflowId, {label: 'workflow', genre: 'workflow', icon: icons.workflow}); + if (s.entrypoint) { + g.edges.set({v: idForTemplate(s.entrypoint), w: workflowId}, {label: 'entrypoint'}); + } + if (s.arguments) { + if (s.arguments.parameters) { + g.nodes.set(parametersId, { + icon: icons.parameters, + label: s.arguments.parameters.map(x => x.name).join(','), + genre: 'params' + }); + g.edges.set({v: parametersId, w: workflowId}, {classNames: 'related'}); + } + if (s.arguments.artifacts) { + g.nodes.set(artifactsId, { + icon: icons.artifacts, + label: s.arguments.artifacts.map(x => x.name).join(','), + genre: 'artifacts' + }); + g.edges.set({v: artifactsId, w: workflowId}, {classNames: 'related'}); + } + } + if (s.onExit) { + g.nodes.set(onExitId, {label: 'on-exit', genre: 'on-exit', icon: icons.onExit}); + g.edges.set({v: idForTemplate(s.onExit), w: onExitId}, {}); + g.edges.set({v: workflowId, w: onExitId}, {classNames: 'related'}); + } + if (s.workflowTemplateRef) { + g.nodes.set(workflowTemplateRefId, { + label: s.workflowTemplateRef.name, + genre: 'tmpl-ref', + icon: s.workflowTemplateRef.clusterScope ? icons.clusterTemplateRef : icons.templateRef + }); + g.edges.set({v: workflowTemplateRefId, w: 'Workflow'}, {}); + } + (s.templates || []).forEach(template => { + const type = template.dag + ? 'dag' + : template.steps + ? 'steps' + : template.container + ? 'container' + : template.script + ? 'script' + : template.resource + ? 'resource' + : template.suspend + ? 'suspend' + : 'unknown'; + const templateId = idForTemplate(template.name); + g.nodes.set(templateId, {label: template.name, genre: type, icon: icons[type]}); + if (template.dag) { + const inDegree: {[id: string]: boolean} = {}; + template.dag.tasks.filter(task => !!task.dependencies).forEach(task => task.dependencies.forEach(w => (inDegree[w] = true))); + g.nodeGroups.set(templateId, new Set()); + template.dag.tasks.forEach(task => { + const taskId = idForTask(template.name, task.name); + g.nodes.set(taskId, { + label: task.name, + genre: 'task', + icon: icons.task + }); + // root node? + if (!inDegree[task.name]) { + g.edges.set({v: taskId, w: templateId}, {}); + } + if (task.dependencies) { + task.dependencies.forEach(dependencyName => { + g.edges.set({v: idForTask(template.name, dependencyName), w: taskId}, {}); + }); + } + addCommonDependencies(task, taskId, g); + g.nodeGroups.get(templateId).add(taskId); + }); + } else if (template.steps) { + template.steps.forEach((group, i) => { + const groupId = idForStepGroup(template.name, i); + g.nodes.set(groupId, {label: 'group ' + i, genre: 'group', icon: icons.stepGroup}); + g.nodeGroups.set(groupId, new Set()); + const firstGroup = i === 0; + const lastGroup = i === template.steps.length - 1; + if (lastGroup) { + g.edges.set({v: groupId, w: templateId}, {}); + } + const lastGroupId = idForStepGroup(template.name, i - 1); + group.forEach((step, j) => { + const stepId = idForSteps(template.name, i, j); + g.nodes.set(stepId, { + label: step.name + (step.template ? ': ' + step.template : ''), + genre: 'step', + icon: icons.step + }); + g.edges.set({v: stepId, w: groupId}, {}); + g.nodeGroups.get(groupId).add(stepId); + if (!firstGroup) { + g.edges.set({v: lastGroupId, w: stepId}, {}); + } + addCommonDependencies(step, stepId, g); + }); + }); + } + }); + return g; +}; diff --git a/ui/src/app/shared/components/workflow-spec-panel/workflow-spec-panel.tsx b/ui/src/app/shared/components/workflow-spec-panel/workflow-spec-panel.tsx new file mode 100644 index 000000000000..0b5009d68304 --- /dev/null +++ b/ui/src/app/shared/components/workflow-spec-panel/workflow-spec-panel.tsx @@ -0,0 +1,27 @@ +import * as React from 'react'; +import {WorkflowSpec} from '../../../../models'; +import {GraphPanel} from '../graph/graph-panel'; +import {genres} from './genres'; +import {workflowSpecGraph} from './workflow-spec-graph'; + +export const WorkflowSpecPanel = ({spec, selectedId, onSelect}: {spec: WorkflowSpec; selectedId?: string; onSelect?: (id: string) => void}) => { + return ( + onSelect && onSelect(id)} + horizontal={true} + nodeGenres={genres} + iconShapes={{ + when: 'circle', + withItems: 'circle', + withParam: 'circle', + withSequence: 'circle', + container: 'circle', + script: 'circle', + resource: 'circle' + }} + /> + ); +}; diff --git a/ui/src/app/shared/components/zero-state.tsx b/ui/src/app/shared/components/zero-state.tsx index be37a7ab63f7..633f63593f0b 100644 --- a/ui/src/app/shared/components/zero-state.tsx +++ b/ui/src/app/shared/components/zero-state.tsx @@ -2,9 +2,9 @@ import * as React from 'react'; import {ReactNode} from 'react'; // https://designsystem.quickbooks.com/pattern/zero-states/ -export const ZeroState = (props: {title: string; children: ReactNode}) => ( +export const ZeroState = (props: {title?: string; children: ReactNode}) => (
-

{props.title}

+

{props.title || 'Nothing to show'}

{props.children}
); diff --git a/ui/src/app/shared/context.ts b/ui/src/app/shared/context.ts index 895cb2076b9a..b1500143548a 100644 --- a/ui/src/app/shared/context.ts +++ b/ui/src/app/shared/context.ts @@ -11,4 +11,5 @@ export interface ContextApis { history: History; } -export const {Provider, Consumer} = React.createContext(null); +export const Context = React.createContext(null); +export const {Provider, Consumer} = Context; diff --git a/ui/src/app/shared/examples.ts b/ui/src/app/shared/examples.ts index 563e5a424ffc..768878db3cda 100644 --- a/ui/src/app/shared/examples.ts +++ b/ui/src/app/shared/examples.ts @@ -1,6 +1,6 @@ import {ClusterWorkflowTemplate, CronWorkflow, Template, Workflow, WorkflowTemplate} from '../../models'; -const randomSillyName = () => { +export const randomSillyName = () => { const adjectives = ['wonderful', 'fantastic', 'awesome', 'delightful', 'lovely', 'sparkly', 'omniscient']; const nouns = ['rhino', 'python', 'bear', 'dragon', 'octopus', 'tiger', 'whale', 'poochenheimer']; const random = (array: string[]) => array[Math.floor(Math.random() * array.length)]; @@ -14,25 +14,26 @@ const labels = {example: 'true'}; const ttlStrategy = {secondsAfterCompletion: 5 * 60}; const podGC = {strategy: 'OnPodCompletion'}; -const templates: Template[] = [ - { - name: entrypoint, - inputs: { - parameters: [{name: 'message', value: '{{workflow.parameters.message}}'}] - }, - container: { - name: 'main', - image: 'argoproj/argosay:v2', - command: ['/argosay'], - args: ['echo', '{{inputs.parameters.message}}'] - } +export const exampleTemplate = (name: string): Template => ({ + name, + inputs: { + parameters: [{name: 'message', value: '{{workflow.parameters.message}}'}] + }, + container: { + name: 'main', + image: 'argoproj/argosay:v2', + command: ['/argosay'], + args: ['echo', '{{inputs.parameters.message}}'] } -]; +}); + +const templates: Template[] = [exampleTemplate(entrypoint)]; -export const exampleWorkflow = (): Workflow => { +export const exampleWorkflow = (namespace: string): Workflow => { return { metadata: { name: randomSillyName(), + namespace, labels }, spec: { @@ -59,9 +60,10 @@ export const exampleClusterWorkflowTemplate = (): ClusterWorkflowTemplate => ({ } }); -export const exampleWorkflowTemplate = (): WorkflowTemplate => ({ +export const exampleWorkflowTemplate = (namespace: string): WorkflowTemplate => ({ metadata: { name: randomSillyName(), + namespace, labels }, spec: { @@ -74,9 +76,10 @@ export const exampleWorkflowTemplate = (): WorkflowTemplate => ({ } }); -export const exampleCronWorkflow = (): CronWorkflow => ({ +export const exampleCronWorkflow = (namespace: string): CronWorkflow => ({ metadata: { name: randomSillyName(), + namespace, labels }, spec: { diff --git a/ui/src/app/shared/history.test.ts b/ui/src/app/shared/history.test.ts new file mode 100644 index 000000000000..addd90866532 --- /dev/null +++ b/ui/src/app/shared/history.test.ts @@ -0,0 +1,31 @@ +/** + * @jest-environment jsdom + */ +import {historyUrl} from './history'; +import {Utils} from './utils'; + +describe('history URL', () => { + test('namespace', () => { + expect(historyUrl('foo/{namespace}', {namespace: 'my-ns'})).toBe('/foo/my-ns?'); + expect(Utils.getCurrentNamespace()).toBe('my-ns'); + }); + + test('path parameter', () => { + expect(historyUrl('foo/{bar}', {bar: 'baz'})).toBe('/foo/baz?'); + }); + + test('null/undefined path parameter', () => { + expect(historyUrl('foo/{bar}', {bar: null})).toBe('/foo/?'); + expect(historyUrl('foo/{bar}', {})).toBe('/foo/?'); + expect(historyUrl('foo/{bar}/{baz}', {})).toBe('/foo//?'); + }); + + test('query parameter', () => { + expect(historyUrl('foo', {bar: 'baz'})).toBe('/foo?bar=baz'); + }); + + test('falsey query parameter', () => { + expect(historyUrl('foo', {bar: false})).toBe('/foo?'); + expect(historyUrl('foo', {bar: null})).toBe('/foo?'); + }); +}); diff --git a/ui/src/app/shared/history.ts b/ui/src/app/shared/history.ts new file mode 100644 index 000000000000..961e8e23669c --- /dev/null +++ b/ui/src/app/shared/history.ts @@ -0,0 +1,24 @@ +import {uiUrl} from './base'; +import {Utils} from './utils'; + +/** + * Return a URL suitable to use with `history.push(..)`. Optionally saving the "namespace" parameter as the current namespace. + * Only "truthy" values are put into the query parameters. I.e. "falsey" values include null, undefined, false, "", 0. + */ +export const historyUrl = (path: string, params: {[key: string]: any}) => { + const queryParams: string[] = []; + Object.entries(params) + .filter(([, v]) => v !== null) + .forEach(([k, v]) => { + const searchValue = '{' + k + '}'; + if (path.includes(searchValue)) { + path = path.replace(searchValue, v != null ? v : ''); + } else if (v) { + queryParams.push(k + '=' + v); + } + if (k === 'namespace') { + Utils.setCurrentNamespace(v); + } + }); + return uiUrl(path.replace(/{[^}]*}/g, '')) + '?' + queryParams.join('&'); +}; diff --git a/ui/src/app/shared/list-watch.ts b/ui/src/app/shared/list-watch.ts new file mode 100644 index 000000000000..f272e0ee1b89 --- /dev/null +++ b/ui/src/app/shared/list-watch.ts @@ -0,0 +1,98 @@ +import * as kubernetes from 'argo-ui/src/models/kubernetes'; +import {Observable} from 'rxjs'; +import {RetryWatch} from './retry-watch'; + +interface Resource { + metadata: kubernetes.ObjectMeta; +} + +type Type = 'ADDED' | 'MODIFIED' | 'DELETED' | 'ERROR'; +type Sorter = (a: Resource, b: Resource) => number; + +// put the youngest at the start of the list +export const sortByYouth: Sorter = (a: Resource, b: Resource) => b.metadata.creationTimestamp.localeCompare(a.metadata.creationTimestamp); + +const reconnectAfterMs = 3000; + +/** + * ListWatch allows you to start watching for changes, automatically reconnecting on error. + */ +export class ListWatch { + private readonly list: () => Promise<{metadata: kubernetes.ListMeta; items: T[]}>; + private readonly onLoad: (metadata: kubernetes.ListMeta) => void; + private readonly onChange: (items: T[], item?: T, type?: Type) => void; + private readonly onError: (error: Error) => void; + private readonly sorter: (a: T, b: T) => number; + private items: T[]; + private retryWatch: RetryWatch; + private timeout: any; + + constructor( + list: () => Promise<{metadata: kubernetes.ListMeta; items: T[]}>, + watch: (resourceVersion: string) => Observable>, + onLoad: (metadata: kubernetes.ListMeta) => void, // called when the list is loaded + onOpen: () => void, // called, when watches is re-established after error, so should clear any errors + onChange: (items: T[], item?: T, type?: Type) => void, // called whenever items change, any users that changes state should use [...items] + onError: (error: Error) => void, // called on any error + sorter: Sorter = sortByYouth // show the youngest first by default + ) { + this.onLoad = onLoad; + this.list = list; + this.onChange = onChange; + this.onError = onError; + this.sorter = sorter; + this.retryWatch = new RetryWatch( + watch, + onOpen, + e => { + this.items = mergeItem(e.object, e.type, this.items).sort(sorter); + onChange(this.items, e.object, e.type); + }, + onError + ); + } + + // Start watching + // Idempotent. + public start() { + this.list() + .then(x => { + this.items = (x.items || []).sort(this.sorter); + this.onLoad(x.metadata); + this.onChange(this.items); + this.retryWatch.start(x.metadata.resourceVersion); + }) + .catch(e => { + clearTimeout(this.timeout); + this.onError(e); + this.timeout = setTimeout(() => this.start(), reconnectAfterMs); + }); + } + + // Stop watching. + // Must invoke on component unload. + // Idempotent. + public stop() { + clearTimeout(this.timeout); + this.retryWatch.stop(); + } +} + +/** + * This is used to update (or delete) and item in a the list. + */ +const mergeItem = (item: T, type: Type, items: T[]): T[] => { + const index = items.findIndex(x => x.metadata.namespace === item.metadata.namespace && x.metadata.name === item.metadata.name); + if (type === 'DELETED') { + if (index > -1) { + items.splice(index, 1); + } + } else if (type !== 'ERROR') { + if (index > -1) { + items[index] = item; + } else { + items.push(item); + } + } + return items; +}; diff --git a/ui/src/app/shared/retry-watch.ts b/ui/src/app/shared/retry-watch.ts new file mode 100644 index 000000000000..1a989501b16c --- /dev/null +++ b/ui/src/app/shared/retry-watch.ts @@ -0,0 +1,58 @@ +import * as kubernetes from 'argo-ui/src/models/kubernetes'; +import {Observable, Subscription} from 'rxjs'; + +interface Resource { + metadata: kubernetes.ObjectMeta; +} + +const reconnectAfterMs = 5000; + +/** + * RetryWatch allows you to watch for changes, automatically reconnecting on error. + */ +export class RetryWatch { + private readonly watch: (resourceVersion: string) => Observable>; + private readonly onOpen: () => void; + private readonly onItem: (event: kubernetes.WatchEvent) => void; + private readonly onError: (error: Error) => void; + private subscription: Subscription; + private timeout: any; // should be `number` + + constructor( + watch: (resourceVersion: string) => Observable>, + onOpen: () => void, // called when watches (re-)established after error, so should clear any errors + onEvent: (event: kubernetes.WatchEvent) => void, // called whenever item is received, + onError: (error: Error) => void + ) { + this.watch = watch; + this.onOpen = onOpen; + this.onItem = onEvent; + this.onError = onError; + } + + public start(resourceVersion: string) { + this.stop(); + this.subscription = this.watch(resourceVersion).subscribe( + next => { + if (next) { + this.onItem(next); + } else { + this.onOpen(); + } + }, + e => { + clearTimeout(this.timeout); + this.onError(e); + this.timeout = setTimeout(() => this.start('0'), reconnectAfterMs); + } + ); + } + + // Must invoke on component unload. + public stop() { + clearTimeout(this.timeout); + if (this.subscription) { + this.subscription.unsubscribe(); + } + } +} diff --git a/ui/src/app/shared/scoped-local-storage.ts b/ui/src/app/shared/scoped-local-storage.ts new file mode 100644 index 000000000000..f64c8bb95818 --- /dev/null +++ b/ui/src/app/shared/scoped-local-storage.ts @@ -0,0 +1,32 @@ +export class ScopedLocalStorage { + private readonly scope: string; + + constructor(scope: string) { + this.scope = scope; + } + + // get the item from storage, returning default if there are any problems + public getItem(key: string, defaultValue: T) { + const value = localStorage.getItem(this.scope + '/' + key) || JSON.stringify(defaultValue); + try { + const x = JSON.parse(value); + if (typeof x === typeof defaultValue) { + return x; + } + } catch (ignored) { + // noop + } + return defaultValue; + } + + // set the item, or clear it if default value + public setItem(key: string, value: T, defaultValue: T) { + const x = this.scope + '/' + key; + const y = JSON.stringify(value); + if (JSON.stringify(defaultValue) !== y) { + localStorage.setItem(x, y); + } else { + localStorage.removeItem(x); + } + } +} diff --git a/ui/src/app/shared/services/event-service.ts b/ui/src/app/shared/services/event-service.ts new file mode 100644 index 000000000000..ed24876b1896 --- /dev/null +++ b/ui/src/app/shared/services/event-service.ts @@ -0,0 +1,8 @@ +import {WorkflowEventBindingList} from '../../../models'; +import requests from './requests'; + +export class EventService { + public listWorkflowEventBindings(namespace: string) { + return requests.get(`api/v1/workflow-event-bindings/${namespace}`).then(res => res.body as WorkflowEventBindingList); + } +} diff --git a/ui/src/app/shared/services/event-source-service.ts b/ui/src/app/shared/services/event-source-service.ts new file mode 100644 index 000000000000..a6fce59e07a7 --- /dev/null +++ b/ui/src/app/shared/services/event-source-service.ts @@ -0,0 +1,34 @@ +import {EventSourceList, EventSourceWatchEvent, LogEntry} from '../../../models/event-source'; +import requests from './requests'; + +export class EventSourceService { + public list(namespace: string) { + return requests.get(`api/v1/event-sources/${namespace}`).then(res => res.body as EventSourceList); + } + + public watch(namespace: string, resourceVersion: string) { + return requests + .loadEventSource(`api/v1/stream/event-sources/${namespace}?listOptions.resourceVersion=${resourceVersion}`) + .map(line => line && (JSON.parse(line).result as EventSourceWatchEvent)); + } + + public eventSourcesLogs(namespace: string, name = '', eventSourceType = '', eventName = '', grep = '', tailLines = -1) { + const params = ['podLogOptions.follow=true']; + if (name) { + params.push('name=' + name); + } + if (eventSourceType) { + params.push('eventSourceType=' + eventSourceType); + } + if (eventName) { + params.push('eventName=' + eventName); + } + if (grep) { + params.push('grep=' + grep); + } + if (tailLines >= 0) { + params.push('podLogOptions.tailLines=' + tailLines); + } + return requests.loadEventSource(`api/v1/stream/event-sources/${namespace}/logs?${params.join('&')}`).map(line => line && (JSON.parse(line).result as LogEntry)); + } +} diff --git a/ui/src/app/shared/services/index.ts b/ui/src/app/shared/services/index.ts index f77cd6dea309..d7afa1201e26 100644 --- a/ui/src/app/shared/services/index.ts +++ b/ui/src/app/shared/services/index.ts @@ -1,12 +1,18 @@ import {ArchivedWorkflowsService} from './archived-workflows-service'; import {ClusterWorkflowTemplateService} from './cluster-workflow-template-service'; import {CronWorkflowService} from './cron-workflow-service'; +import {EventService} from './event-service'; +import {EventSourceService} from './event-source-service'; import {InfoService} from './info-service'; +import {SensorService} from './sensor-service'; import {WorkflowTemplateService} from './workflow-template-service'; import {WorkflowsService} from './workflows-service'; -export interface Services { +interface Services { info: InfoService; + sensor: SensorService; + event: EventService; + eventSource: EventSourceService; workflows: WorkflowsService; workflowTemplate: WorkflowTemplateService; clusterWorkflowTemplate: ClusterWorkflowTemplateService; @@ -14,14 +20,14 @@ export interface Services { cronWorkflows: CronWorkflowService; } -export * from './workflows-service'; -export * from './responses'; - export const services: Services = { info: new InfoService(), workflows: new WorkflowsService(), workflowTemplate: new WorkflowTemplateService(), clusterWorkflowTemplate: new ClusterWorkflowTemplateService(), + event: new EventService(), + eventSource: new EventSourceService(), + sensor: new SensorService(), archivedWorkflows: new ArchivedWorkflowsService(), cronWorkflows: new CronWorkflowService() }; diff --git a/ui/src/app/shared/services/requests.ts b/ui/src/app/shared/services/requests.ts index fbfb44615d2d..becac4ae63b5 100644 --- a/ui/src/app/shared/services/requests.ts +++ b/ui/src/app/shared/services/requests.ts @@ -42,6 +42,9 @@ export default { loadEventSource(url: string): Observable { return Observable.create((observer: Observer) => { const eventSource = new EventSource(url); + // an null event is the best way I could find to get an event whenever we open the event source + // otherwise, you'd have to wait for your first message (which maybe some time) + eventSource.onopen = () => observer.next(null); eventSource.onmessage = x => observer.next(x.data); eventSource.onerror = x => observer.error(x); return () => { diff --git a/ui/src/app/shared/services/sensor-service.ts b/ui/src/app/shared/services/sensor-service.ts new file mode 100644 index 000000000000..5de58a5f754a --- /dev/null +++ b/ui/src/app/shared/services/sensor-service.ts @@ -0,0 +1,31 @@ +import {LogEntry, SensorList, SensorWatchEvent} from '../../../models/sensor'; +import requests from './requests'; + +export class SensorService { + public list(namespace: string) { + return requests.get(`api/v1/sensors/${namespace}`).then(res => res.body as SensorList); + } + + public watch(namespace: string, resourceVersion: string) { + return requests + .loadEventSource(`api/v1/stream/sensors/${namespace}?listOptions.resourceVersion=${resourceVersion}`) + .map(line => line && (JSON.parse(line).result as SensorWatchEvent)); + } + + public sensorsLogs(namespace: string, name = '', triggerName = '', grep = '', tailLines = -1) { + const params = ['podLogOptions.follow=true']; + if (name) { + params.push('name=' + name); + } + if (grep) { + params.push('grep=' + grep); + } + if (triggerName) { + params.push('triggerName=' + triggerName); + } + if (tailLines >= 0) { + params.push('podLogOptions.tailLines=' + tailLines); + } + return requests.loadEventSource(`api/v1/stream/sensors/${namespace}/logs?${params.join('&')}`).map(line => line && (JSON.parse(line).result as LogEntry)); + } +} diff --git a/ui/src/app/shared/services/workflows-service.ts b/ui/src/app/shared/services/workflows-service.ts index fdc7646447c9..4542abed464a 100644 --- a/ui/src/app/shared/services/workflows-service.ts +++ b/ui/src/app/shared/services/workflows-service.ts @@ -1,6 +1,6 @@ import {Observable} from 'rxjs'; import * as models from '../../../models'; -import {Event, NodeStatus, Workflow, WorkflowList} from '../../../models'; +import {Event, LogEntry, NodeStatus, Workflow, WorkflowList} from '../../../models'; import {SubmitOpts} from '../../../models/submit-opts'; import {Pagination} from '../pagination'; import requests from './requests'; @@ -28,6 +28,7 @@ export class WorkflowsService { 'items.metadata.uid', 'items.metadata.name', 'items.metadata.namespace', + 'items.metadata.creationTimestamp', 'items.metadata.labels', 'items.status.phase', 'items.status.finishedAt', @@ -38,11 +39,13 @@ export class WorkflowsService { ] ) { const params = this.queryParams({phases, labels}); - if (pagination.offset) { - params.push(`listOptions.continue=${pagination.offset}`); - } - if (pagination.limit) { - params.push(`listOptions.limit=${pagination.limit}`); + if (pagination) { + if (pagination.offset) { + params.push(`listOptions.continue=${pagination.offset}`); + } + if (pagination.limit) { + params.push(`listOptions.limit=${pagination.limit}`); + } } params.push(`fields=${fields.join(',')}`); return requests.get(`api/v1/workflows/${namespace}?${params.join('&')}`).then(res => res.body as WorkflowList); @@ -60,11 +63,11 @@ export class WorkflowsService { resourceVersion?: string; }): Observable> { const url = `api/v1/workflow-events/${filter.namespace || ''}?${this.queryParams(filter).join('&')}`; - return requests.loadEventSource(url).map(data => JSON.parse(data).result as models.kubernetes.WatchEvent); + return requests.loadEventSource(url).map(data => data && (JSON.parse(data).result as models.kubernetes.WatchEvent)); } public watchEvents(namespace: string, fieldSelector: string): Observable { - return requests.loadEventSource(`api/v1/stream/events/${namespace}?listOptions.fieldSelector=${fieldSelector}`).map(data => JSON.parse(data).result as Event); + return requests.loadEventSource(`api/v1/stream/events/${namespace}?listOptions.fieldSelector=${fieldSelector}`).map(data => data && (JSON.parse(data).result as Event)); } public watchFields(filter: { @@ -79,6 +82,7 @@ export class WorkflowsService { 'result.object.metadata.name', 'result.object.metadata.namespace', 'result.object.metadata.resourceVersion', + 'result.object.metadata.creationTimestamp', 'result.object.metadata.uid', 'result.object.status.finishedAt', 'result.object.status.phase', @@ -91,7 +95,7 @@ export class WorkflowsService { ]; params.push(`fields=${fields.join(',')}`); const url = `api/v1/workflow-events/${filter.namespace || ''}?${params.join('&')}`; - return requests.loadEventSource(url).map(data => JSON.parse(data).result as models.kubernetes.WatchEvent); + return requests.loadEventSource(url).map(data => data && (JSON.parse(data).result as models.kubernetes.WatchEvent)); } public retry(name: string, namespace: string) { @@ -129,12 +133,15 @@ export class WorkflowsService { .then(res => res.body as Workflow); } - public getContainerLogsFromCluster(workflow: Workflow, nodeId: string, container: string): Observable { - const podLogsURL = `api/v1/workflows/${workflow.metadata.namespace}/${workflow.metadata.name}/${nodeId}/log?logOptions.container=${container}&logOptions.follow=true`; + public getContainerLogsFromCluster(workflow: Workflow, nodeId: string, container: string): Observable { + const namespace = workflow.metadata.namespace; + const name = workflow.metadata.name; + const podLogsURL = `api/v1/workflows/${namespace}/${name}/log?logOptions.container=${container}&logOptions.follow=true${nodeId ? `&podName=${nodeId}` : ''}`; return requests .loadEventSource(podLogsURL) - .map(line => JSON.parse(line).result.content) - .filter(isString) + .filter(line => !!line) + .map(line => JSON.parse(line).result as LogEntry) + .filter(e => isString(e.content)) .catch(() => { // When an error occurs on an observable, RxJS is hard-coded to unsubscribe from the stream. In the case // that the connection to the server was interrupted while the node is still pending or running, this is not @@ -152,11 +159,15 @@ export class WorkflowsService { }); } - public async isWorkflowNodePendingOrRunning(workflow: Workflow, nodeId: string) { + public async isWorkflowNodePendingOrRunning(workflow: Workflow, nodeId?: string) { // We always refresh the workflow rather than inspecting the state locally since it doubles // as a check to determine whether or not the API is currently reachable const updatedWorkflow = await this.get(workflow.metadata.namespace, workflow.metadata.name); - return this.isNodePendingOrRunning(updatedWorkflow.status.nodes[nodeId]); + const node = updatedWorkflow.status.nodes[nodeId]; + if (!node) { + return !updatedWorkflow.status || ['Pending', 'Running'].includes(updatedWorkflow.status.phase); + } + return this.isNodePendingOrRunning(node); } public getContainerLogsFromArtifact(workflow: Workflow, nodeId: string, container: string, archived: boolean) { @@ -168,10 +179,11 @@ export class WorkflowsService { return Observable.fromPromise(requests.get(this.getArtifactLogsUrl(workflow, nodeId, container, archived))); }) - .mergeMap(r => r.text.split('\n')); + .mergeMap(r => r.text.split('\n')) + .map(content => ({content} as LogEntry)); } - public getContainerLogs(workflow: Workflow, nodeId: string, container: string, archived: boolean): Observable { + public getContainerLogs(workflow: Workflow, nodeId: string, container: string, archived: boolean): Observable { const getLogsFromArtifact = () => this.getContainerLogsFromArtifact(workflow, nodeId, container, archived); // If our workflow is archived, don't even bother inspecting the cluster for logs since it's likely diff --git a/ui/src/app/shared/template-resolution.ts b/ui/src/app/shared/template-resolution.ts index 8e2c1ab42e7a..9f8aca752b79 100644 --- a/ui/src/app/shared/template-resolution.ts +++ b/ui/src/app/shared/template-resolution.ts @@ -1,5 +1,5 @@ import * as models from '../../models'; -import {ResourceScope, WorkflowStep} from '../../models'; +import {execSpec, ResourceScope, WorkflowStep} from '../../models'; export function getResolvedTemplates(workflow: models.Workflow, node: models.NodeStatus): models.Template { let tmpTemplate = { @@ -16,7 +16,7 @@ export function getResolvedTemplates(workflow: models.Workflow, node: models.Nod if (templRef.StorageNeeded) { tmpl = workflow.status.storedTemplates[templRef.StoredTemplateName]; } else if (tmpTemplate.template) { - tmpl = (workflow.status.storedWorkflowTemplateSpec || workflow.spec).templates.find(item => item.name === tmpTemplate.template); + tmpl = execSpec(workflow).templates.find(item => item.name === tmpTemplate.template); } if (!tmpl) { const name = templRef.StoredTemplateName || tmpTemplate.template; diff --git a/ui/src/app/shared/utils.ts b/ui/src/app/shared/utils.ts index 70980b91b34c..56105f4bd9d2 100644 --- a/ui/src/app/shared/utils.ts +++ b/ui/src/app/shared/utils.ts @@ -75,7 +75,7 @@ export const Utils = { }, setCurrentNamespace(value: string): void { - if (value) { + if (value != null) { localStorage.setItem('current_namespace', value); this.onNamespaceChange(value); } @@ -83,5 +83,10 @@ export const Utils = { getCurrentNamespace(): string { return localStorage.getItem('current_namespace'); + }, + + // return a namespace, never return null/undefined, defaults to "deafult" + getNamespace(namespace: string): string { + return namespace || localStorage.getItem('current_namespace') || 'default'; } }; diff --git a/ui/src/app/shared/workflow-operations-map.ts b/ui/src/app/shared/workflow-operations-map.ts index c5049399367a..28804bb32ac9 100644 --- a/ui/src/app/shared/workflow-operations-map.ts +++ b/ui/src/app/shared/workflow-operations-map.ts @@ -1,12 +1,13 @@ import {NodePhase, Workflow} from '../../models'; import {services} from './services'; +import {WorkflowDeleteResponse} from './services/responses'; import {Utils} from './utils'; export type OperationDisabled = { [action in WorkflowOperationName]: boolean; }; -export type WorkflowOperationName = 'RETRY' | 'RESUBMIT' | 'SUSPEND' | 'RESUME' | 'STOP' | 'TERMINATE' | 'DELETE'; +type WorkflowOperationName = 'RETRY' | 'RESUBMIT' | 'SUSPEND' | 'RESUME' | 'STOP' | 'TERMINATE' | 'DELETE'; export interface WorkflowOperation { title: WorkflowOperationName; @@ -15,7 +16,7 @@ export interface WorkflowOperation { disabled: (wf: Workflow) => boolean; } -export type WorkflowOperationAction = (wf: Workflow) => Promise; +export type WorkflowOperationAction = (wf: Workflow) => Promise; export interface WorkflowOperations { [name: string]: WorkflowOperation; diff --git a/ui/src/app/userinfo/components/user-info.tsx b/ui/src/app/userinfo/components/user-info.tsx index 626098dda544..67a56749df02 100644 --- a/ui/src/app/userinfo/components/user-info.tsx +++ b/ui/src/app/userinfo/components/user-info.tsx @@ -5,6 +5,7 @@ import {GetUserInfoResponse} from '../../../models'; import {uiUrl} from '../../shared/base'; import {BasePage} from '../../shared/components/base-page'; import {ErrorNotice} from '../../shared/components/error-notice'; +import {Notice} from '../../shared/components/notice'; import {services} from '../../shared/services'; import {CliHelp} from './cli-help'; @@ -29,27 +30,25 @@ export class UserInfo extends BasePage, State> { public render() { return ( -
- {this.state.error && } -
-

- User Info -

- {this.state.userInfo && ( - <> -

Issuer: {this.state.userInfo.issuer || '-'}

-

Subject: {this.state.userInfo.subject || '-'}

-

Groups: {(this.state.userInfo.groups && this.state.userInfo.groups.length > 0 && this.state.userInfo.groups.join(', ')) || '-'}

-

Email: {this.state.userInfo.email || '-'}

-

Email Verified: {this.state.userInfo.emailVerified || '-'}

- - )} - - Login / Logout - -
- -
+ {} + +

+ User Info +

+ {this.state.userInfo && ( + <> +

Issuer: {this.state.userInfo.issuer || '-'}

+

Subject: {this.state.userInfo.subject || '-'}

+

Groups: {(this.state.userInfo.groups && this.state.userInfo.groups.length > 0 && this.state.userInfo.groups.join(', ')) || '-'}

+

Email: {this.state.userInfo.email || '-'}

+

Email Verified: {this.state.userInfo.emailVerified || '-'}

+ + )} + + Login / Logout + +
+
); } diff --git a/ui/src/app/webpack.config.js b/ui/src/app/webpack.config.js index 73a7eacc8026..61d761836662 100644 --- a/ui/src/app/webpack.config.js +++ b/ui/src/app/webpack.config.js @@ -8,6 +8,8 @@ const path = require("path"); const isProd = process.env.NODE_ENV === "production"; +console.log("isProd=", isProd) + const config = { mode: isProd ? "production" : "development", entry: { @@ -18,7 +20,7 @@ const config = { path: __dirname + "/../../dist/app" }, - devtool: "source-map", + devtool: "", resolve: { extensions: [".ts", ".tsx", ".js", ".json", ".ttf"] @@ -28,15 +30,15 @@ const config = { rules: [ { test: /\.tsx?$/, - loaders: [...(isProd ? [] : ["react-hot-loader/webpack"]), `ts-loader?allowTsInNodeModules=true&configFile=${path.resolve("./src/app/tsconfig.json")}`] + loaders: [...(isProd ? [] : ["react-hot-loader/webpack"]), `ts-loader?transpileOnly=${!isProd}&allowTsInNodeModules=true&configFile=${path.resolve("./src/app/tsconfig.json")}`] }, { enforce: 'pre', exclude: [ - /node_modules\/react-paginate/, + /node_modules\/reyaract-paginate/, /node_modules\/monaco-editor/, ], test: /\.js$/, - loaders: [...(isProd ? ['babel-loader'] : []), 'source-map-loader'], + loaders: [...(isProd ? ['babel-loader'] : [])], }, { test: /\.scss$/, loader: "style-loader!raw-loader!sass-loader" @@ -66,6 +68,8 @@ const config = { from: "node_modules/@fortawesome/fontawesome-free/webfonts", to: "assets/fonts" }, { from: "../api/openapi-spec/swagger.json", to: "assets/openapi-spec/swagger.json" + }, { + from: "../api/jsonschema/schema.json", to: "assets/jsonschema/schema.json" }, { from: 'node_modules/monaco-editor/min/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf', to: "." }]), @@ -76,7 +80,7 @@ const config = { disableDotRule: true }, proxy: { - "/api": { + "/api/v1": { "target": isProd ? "" : "http://localhost:2746", "secure": false }, diff --git a/ui/src/app/workflow-event-bindings/components/workflow-event-bindings-container.tsx b/ui/src/app/workflow-event-bindings/components/workflow-event-bindings-container.tsx new file mode 100644 index 000000000000..197e69b93889 --- /dev/null +++ b/ui/src/app/workflow-event-bindings/components/workflow-event-bindings-container.tsx @@ -0,0 +1,9 @@ +import * as React from 'react'; +import {Route, RouteComponentProps, Switch} from 'react-router'; +import {WorkflowEventBindingsList} from './workflow-event-bindings-list/workflow-event-bindings-list'; + +export const WorkflowEventBindingsContainer = (props: RouteComponentProps) => ( + + + +); diff --git a/ui/src/app/workflow-event-bindings/components/workflow-event-bindings-list/id.ts b/ui/src/app/workflow-event-bindings/components/workflow-event-bindings-list/id.ts new file mode 100644 index 000000000000..7fe5a31128ad --- /dev/null +++ b/ui/src/app/workflow-event-bindings/components/workflow-event-bindings-list/id.ts @@ -0,0 +1,10 @@ +type Type = 'WorkflowEventBinding' | 'WorkflowTemplate'; + +export const ID = { + join: (type: Type, namespace: string, name: string) => type + '/' + namespace + '/' + name, + split: (id: string) => ({ + type: id.split('/')[0] as Type, + namespace: id.split('/')[1], + name: id.split('/')[2] + }) +}; diff --git a/ui/src/app/workflow-event-bindings/components/workflow-event-bindings-list/workflow-event-bindings-list.tsx b/ui/src/app/workflow-event-bindings/components/workflow-event-bindings-list/workflow-event-bindings-list.tsx new file mode 100644 index 000000000000..643ff87713da --- /dev/null +++ b/ui/src/app/workflow-event-bindings/components/workflow-event-bindings-list/workflow-event-bindings-list.tsx @@ -0,0 +1,113 @@ +import {Page, SlidingPanel} from 'argo-ui'; +import * as React from 'react'; +import {useContext, useEffect, useState} from 'react'; +import {RouteComponentProps} from 'react-router-dom'; +import {WorkflowEventBinding} from '../../../../models'; +import {uiUrl} from '../../../shared/base'; +import {ErrorNotice} from '../../../shared/components/error-notice'; +import {GraphPanel} from '../../../shared/components/graph/graph-panel'; +import {Graph} from '../../../shared/components/graph/types'; +import {Loading} from '../../../shared/components/loading'; +import {NamespaceFilter} from '../../../shared/components/namespace-filter'; +import {ResourceEditor} from '../../../shared/components/resource-editor/resource-editor'; +import {ZeroState} from '../../../shared/components/zero-state'; +import {Context} from '../../../shared/context'; +import {historyUrl} from '../../../shared/history'; +import {services} from '../../../shared/services'; +import {ID} from './id'; + +export const WorkflowEventBindingsList = ({match, location, history}: RouteComponentProps) => { + // boiler-plate + const ctx = useContext(Context); + const queryParams = new URLSearchParams(location.search); + + // state for URL and query parameters + const [namespace, setNamespace] = useState(match.params.namespace || ''); + const [selectedWorkflowEventBinding, setSelectedWorkflowEventBinding] = useState(queryParams.get('selectedWorkflowEventBinding')); + useEffect(() => history.push(historyUrl('workflow-event-bindings/{namespace}', {namespace, selectedWorkflowEventBinding})), [namespace, selectedWorkflowEventBinding]); + + // internal state + const [error, setError] = useState(); + const [workflowEventBindings, setWorkflowEventBindings] = useState(); + + const selected = (workflowEventBindings || []).find(x => x.metadata.namespace + '/' + x.metadata.name === selectedWorkflowEventBinding); + + const g = new Graph(); + (workflowEventBindings || []).forEach(web => { + const bindingId = ID.join('WorkflowEventBinding', web.metadata.namespace, web.metadata.name); + g.nodes.set(bindingId, {label: web.spec.event.selector, genre: 'event', icon: 'cloud'}); + if (web.spec.submit) { + const templateName = web.spec.submit.workflowTemplateRef.name; + const templateId = ID.join('WorkflowTemplate', web.metadata.namespace, templateName); + g.nodes.set(templateId, {label: templateName, genre: 'template', icon: 'window-maximize'}); + g.edges.set({v: bindingId, w: templateId}, {}); + } + }); + + useEffect(() => { + services.event + .listWorkflowEventBindings(namespace) + .then(list => setWorkflowEventBindings(list.items || [])) + .then(() => setError(null)) + .catch(setError); + }, [namespace]); + + return ( + ] + }}> + + {!workflowEventBindings ? ( + + ) : workflowEventBindings.length === 0 ? ( + +

+ Workflow event bindings allow you to trigger workflows when a webhook event is received. For example, start a build on a Git commit, or start a machine + learning pipeline from a remote system. +

+

+ Once you've created a a workflow event binding, you can test it from the CLI using curl, for example: +

+

+ + curl '{document.location.protocol}://{document.location.host}/api/v1/events/{namespace}/-' -H 'Content-Type: application/json' -H 'Authorization: + $ARGO_TOKEN' -d '{}' + +

+

+ You'll probably find it easiest to experiment and test using the graphical interface to the API - look for "EventService. +

+

+ Learn more +

+
+ ) : ( + <> + { + const x = ID.split(id); + if (x.type === 'WorkflowTemplate') { + ctx.navigation.goto(uiUrl('workflow-templates/' + x.namespace + '/' + x.name)); + } else { + setSelectedWorkflowEventBinding(x.namespace + '/' + x.name); + } + }} + /> + setSelectedWorkflowEventBinding(null)}> + {selected && } + + + )} +
+ ); +}; diff --git a/ui/src/app/workflow-event-bindings/index.ts b/ui/src/app/workflow-event-bindings/index.ts new file mode 100644 index 000000000000..98f8f6360e7f --- /dev/null +++ b/ui/src/app/workflow-event-bindings/index.ts @@ -0,0 +1,5 @@ +import {WorkflowEventBindingsContainer} from './components/workflow-event-bindings-container'; + +export default { + component: WorkflowEventBindingsContainer +}; diff --git a/ui/src/app/workflow-templates/components/workflow-template-creator.tsx b/ui/src/app/workflow-templates/components/workflow-template-creator.tsx new file mode 100644 index 000000000000..863dbe4dd5bc --- /dev/null +++ b/ui/src/app/workflow-templates/components/workflow-template-creator.tsx @@ -0,0 +1,38 @@ +import * as React from 'react'; +import {useState} from 'react'; +import {WorkflowTemplate} from '../../../models'; +import {Button} from '../../shared/components/button'; +import {ErrorNotice} from '../../shared/components/error-notice'; +import {ExampleManifests} from '../../shared/components/example-manifests'; +import {UploadButton} from '../../shared/components/upload-button'; +import {exampleWorkflowTemplate} from '../../shared/examples'; +import {services} from '../../shared/services'; +import {Utils} from '../../shared/utils'; +import {WorkflowTemplateEditor} from './workflow-template-editor'; + +export const WorkflowTemplateCreator = ({namespace, onCreate}: {namespace: string; onCreate: (workflow: WorkflowTemplate) => void}) => { + const [template, setTemplate] = useState(exampleWorkflowTemplate(Utils.getNamespace(namespace))); + const [error, setError] = useState(); + return ( + <> +
+ + +
+ + +

+ . +

+ + ); +}; diff --git a/ui/src/app/workflow-templates/components/workflow-template-details/workflow-template-details.tsx b/ui/src/app/workflow-templates/components/workflow-template-details/workflow-template-details.tsx index 5d8c39d2df94..521183d9627e 100644 --- a/ui/src/app/workflow-templates/components/workflow-template-details/workflow-template-details.tsx +++ b/ui/src/app/workflow-templates/components/workflow-template-details/workflow-template-details.tsx @@ -1,127 +1,121 @@ import {NotificationType, Page} from 'argo-ui'; import {SlidingPanel} from 'argo-ui/src/index'; import * as React from 'react'; +import {useContext, useEffect, useState} from 'react'; import {RouteComponentProps} from 'react-router'; -import * as models from '../../../../models'; +import {WorkflowTemplate} from '../../../../models'; import {uiUrl} from '../../../shared/base'; -import {BasePage} from '../../../shared/components/base-page'; import {ErrorNotice} from '../../../shared/components/error-notice'; import {Loading} from '../../../shared/components/loading'; -import {Consumer} from '../../../shared/context'; +import {Context} from '../../../shared/context'; +import {historyUrl} from '../../../shared/history'; import {services} from '../../../shared/services'; import {SubmitWorkflowPanel} from '../../../workflows/components/submit-workflow-panel'; -import {WorkflowTemplateSummaryPanel} from '../workflow-template-summary-panel'; +import {WorkflowTemplateEditor} from '../workflow-template-editor'; -require('../../../workflows/components/workflow-details/workflow-details.scss'); +export const WorkflowTemplateDetails = ({history, location, match}: RouteComponentProps) => { + // boiler-plate + const {notifications, navigation} = useContext(Context); + const queryParams = new URLSearchParams(location.search); -interface State { - template?: models.WorkflowTemplate; - error?: Error; -} + // state for URL and query parameters + const namespace = match.params.namespace; + const name = match.params.name; + const [sidePanel, setSidePanel] = useState(queryParams.get('sidePanel') === 'true'); + const [tab, setTab] = useState(queryParams.get('tab')); -export class WorkflowTemplateDetails extends BasePage, State> { - private get namespace() { - return this.props.match.params.namespace || ''; - } + useEffect( + () => + history.push( + historyUrl('workflow-templates/{namespace}/{name}', { + namespace, + name, + sidePanel, + tab + }) + ), + [namespace, name, sidePanel, tab] + ); - private get name() { - return this.props.match.params.name; - } + const [error, setError] = useState(); + const [template, setTemplate] = useState(); + const [edited, setEdited] = useState(false); - private get sidePanel() { - return this.queryParam('sidePanel'); - } + useEffect(() => setEdited(true), [template]); - private set sidePanel(sidePanel) { - this.setQueryParams({sidePanel}); - } - - constructor(props: RouteComponentProps, context: any) { - super(props, context); - this.state = {}; - } - - public componentDidMount(): void { + useEffect(() => { services.workflowTemplate - .get(this.name, this.namespace) - .then(template => this.setState({error: null, template})) - .catch(error => this.setState({error})); - } - - public render() { - return ( - - {ctx => ( - (this.sidePanel = 'new') - }, - { - title: 'Delete', - iconClassName: 'fa fa-trash', - action: () => this.deleteWorkflowTemplate() - } - ] - }, - breadcrumbs: [ - { - title: 'Workflow Template', - path: uiUrl('workflow-templates') - }, - {title: this.namespace + '/' + this.name} - ] - }}> -
-
{this.renderWorkflowTemplate()}
-
- {this.state.template && ( - (this.sidePanel = null)}> - t.name)} - parameters={this.state.template.spec.arguments.parameters || []} - /> - - )} -
- )} -
- ); - } + .get(name, namespace) + .then(setTemplate) + .then(() => setEdited(false)) // set back to false + .then(() => setError(null)) + .catch(setError); + }, [name, namespace]); - private renderWorkflowTemplate() { - if (this.state.error) { - return ; - } - if (!this.state.template) { - return ; - } - return this.setState({template})} />; - } - - private deleteWorkflowTemplate() { - if (!confirm('Are you sure you want to delete this workflow template?\nThere is no undo.')) { - return; - } - services.workflowTemplate - .delete(this.name, this.namespace) - .catch(e => { - this.appContext.apis.notifications.show({ - content: 'Failed to delete workflow template ' + e, - type: NotificationType.Error - }); - }) - .then(() => { - document.location.href = uiUrl('workflow-templates'); - }); - } -} + return ( + setSidePanel(true) + }, + { + title: 'Update', + iconClassName: 'fa fa-save', + disabled: !edited, + action: () => + services.workflowTemplate + .update(template, name, namespace) + .then(setTemplate) + .then(() => notifications.show({content: 'Updated', type: NotificationType.Success})) + .then(() => setEdited(false)) + .then(() => setError(null)) + .catch(setError) + }, + { + title: 'Delete', + iconClassName: 'fa fa-trash', + disabled: edited, + action: () => { + if (!confirm('Are you sure you want to delete this workflow template?\nThere is no undo.')) { + return; + } + services.workflowTemplate + .delete(name, namespace) + .then(() => navigation.goto(uiUrl('workflow-templates/' + namespace))) + .then(() => setError(null)) + .catch(setError); + } + } + ] + } + }}> + <> + + {!template ? : } + + {template && ( + setSidePanel(null)} isNarrow={true}> + t.name)} + parameters={template.spec.arguments.parameters || []} + /> + + )} + + ); +}; diff --git a/ui/src/app/workflow-templates/components/workflow-template-editor.tsx b/ui/src/app/workflow-templates/components/workflow-template-editor.tsx new file mode 100644 index 000000000000..6920d4122469 --- /dev/null +++ b/ui/src/app/workflow-templates/components/workflow-template-editor.tsx @@ -0,0 +1,58 @@ +import * as React from 'react'; + +import {Tabs} from 'argo-ui'; +import {WorkflowTemplate} from '../../../models'; +import {LabelsAndAnnotationsEditor} from '../../shared/components/editors/labels-and-annotations-editor'; +import {MetadataEditor} from '../../shared/components/editors/metadata-editor'; +import {WorkflowSpecEditor} from '../../shared/components/editors/workflow-spec-editor'; +import {ObjectEditor} from '../../shared/components/object-editor/object-editor'; + +export const WorkflowTemplateEditor = ({ + onChange, + onError, + onTabSelected, + selectedTabKey, + template +}: { + template: WorkflowTemplate; + onChange: (template: WorkflowTemplate) => void; + onError: (error: Error) => void; + onTabSelected?: (tab: string) => void; + selectedTabKey?: string; +}) => { + return ( + onChange({...template, spec})} onError={onError} /> + }, + { + key: 'metadata', + title: 'MetaData', + content: onChange({...template, metadata})} /> + }, + { + key: 'workflow-metadata', + title: 'Workflow MetaData', + content: ( + onChange({...template, spec: {...template.spec, workflowMetadata}})} + /> + ) + }, + { + key: 'manifest', + title: 'Manifest', + content: onChange({...x})} /> + } + ]} + /> + ); +}; diff --git a/ui/src/app/workflow-templates/components/workflow-template-list/workflow-template-list.tsx b/ui/src/app/workflow-templates/components/workflow-template-list/workflow-template-list.tsx index c27e770d5b83..d2c6fe9c223a 100644 --- a/ui/src/app/workflow-templates/components/workflow-template-list/workflow-template-list.tsx +++ b/ui/src/app/workflow-templates/components/workflow-template-list/workflow-template-list.tsx @@ -1,132 +1,86 @@ import {Page, SlidingPanel} from 'argo-ui'; import * as React from 'react'; +import {useContext, useEffect, useState} from 'react'; import {Link, RouteComponentProps} from 'react-router-dom'; -import * as models from '../../../../models'; +import {WorkflowTemplate} from '../../../../models'; import {uiUrl} from '../../../shared/base'; -import {BasePage} from '../../../shared/components/base-page'; import {ErrorNotice} from '../../../shared/components/error-notice'; import {ExampleManifests} from '../../../shared/components/example-manifests'; import {Loading} from '../../../shared/components/loading'; import {NamespaceFilter} from '../../../shared/components/namespace-filter'; -import {ResourceEditor} from '../../../shared/components/resource-editor/resource-editor'; import {Timestamp} from '../../../shared/components/timestamp'; import {ZeroState} from '../../../shared/components/zero-state'; -import {Consumer} from '../../../shared/context'; -import {exampleWorkflowTemplate} from '../../../shared/examples'; +import {Context} from '../../../shared/context'; +import {historyUrl} from '../../../shared/history'; import {services} from '../../../shared/services'; -import {Utils} from '../../../shared/utils'; +import {WorkflowTemplateCreator} from '../workflow-template-creator'; require('./workflow-template-list.scss'); -interface State { - namespace: string; - templates?: models.WorkflowTemplate[]; - error?: Error; -} +const learnMore = Learn more; -export class WorkflowTemplateList extends BasePage, State> { - private get namespace() { - return this.state.namespace; - } +export const WorkflowTemplateList = ({match, location, history}: RouteComponentProps) => { + // boiler-plate + const queryParams = new URLSearchParams(location.search); + const {navigation} = useContext(Context); - private set namespace(namespace: string) { - this.fetchWorkflowTemplates(namespace); - } + // state for URL and query parameters + const [namespace, setNamespace] = useState(match.params.namespace || ''); + const [sidePanel, setSidePanel] = useState(queryParams.get('sidePanel') === 'true'); + useEffect( + () => + history.push( + historyUrl('workflow-templates/{namespace}', { + namespace, + sidePanel + }) + ), + [namespace, sidePanel] + ); - private get sidePanel() { - return this.queryParam('sidePanel'); - } + // internal state + const [error, setError] = useState(); + const [templates, setTemplates] = useState(); - private set sidePanel(sidePanel) { - this.setQueryParams({sidePanel}); - } - - constructor(props: RouteComponentProps, context: any) { - super(props, context); - this.state = {namespace: this.props.match.params.namespace || ''}; - } - - public componentDidMount(): void { - this.fetchWorkflowTemplates(this.namespace); - } - - public render() { - return ( - - {ctx => ( - (this.sidePanel = 'new') - } - ] - }, - tools: [ (this.namespace = namespace)} />] - }}> - {this.renderTemplates()} - (this.sidePanel = null)}> - - services.workflowTemplate - .create(wfTmpl, wfTmpl.metadata.namespace) - .then(wf => ctx.navigation.goto(uiUrl(`workflow-templates/${wf.metadata.namespace}/${wf.metadata.name}`))) - } - editing={true} - /> -

- . -

-
-
- )} -
- ); - } - - private saveHistory() { - this.url = uiUrl('workflow-templates/' + this.namespace || ''); - Utils.setCurrentNamespace(this.namespace); - } - - private fetchWorkflowTemplates(namespace: string): void { + useEffect(() => { services.workflowTemplate .list(namespace) - .then(templates => this.setState({error: null, namespace, templates}, this.saveHistory)) - .catch(error => this.setState({error})); - } + .then(setTemplates) + .then(() => setError(null)) + .catch(setError); + }, [namespace]); - private renderTemplates() { - if (this.state.error) { - return ; - } - if (!this.state.templates) { - return ; - } - const learnMore = Learn more; - if (this.state.templates.length === 0) { - return ( + return ( + setSidePanel(true) + } + ] + }, + tools: [] + }}> + + {!templates ? ( + + ) : templates.length === 0 ? (

You can create new templates here or using the CLI.

. {learnMore}.

- ); - } - return ( -
-
+ ) : ( + <>
@@ -134,7 +88,7 @@ export class WorkflowTemplateList extends BasePage, Sta
NAMESPACE
CREATED
- {this.state.templates.map(t => ( + {templates.map(t => ( , Sta

Workflow templates are reusable templates you can create new workflows from. . {learnMore}.

-
-
- ); - } -} + + )} + setSidePanel(false)}> + navigation.goto(uiUrl(`workflow-templates/${wf.metadata.namespace}/${wf.metadata.name}`))} /> + + + ); +}; diff --git a/ui/src/app/workflows/components/events-panel.tsx b/ui/src/app/workflows/components/events-panel.tsx index 615e4dc4ccfa..244faf14e01f 100644 --- a/ui/src/app/workflows/components/events-panel.tsx +++ b/ui/src/app/workflows/components/events-panel.tsx @@ -1,149 +1,92 @@ import * as React from 'react'; -import {Subscription} from 'rxjs'; +import {useEffect, useState} from 'react'; import {Event} from '../../../models'; import {ErrorNotice} from '../../shared/components/error-notice'; import {Notice} from '../../shared/components/notice'; import {Timestamp} from '../../shared/components/timestamp'; import {ToggleButton} from '../../shared/components/toggle-button'; +import {ListWatch} from '../../shared/list-watch'; import {services} from '../../shared/services'; -interface Props { - namespace: string; - name: string; - kind: string; -} +export const EventsPanel = ({namespace, name, kind}: {namespace: string; name: string; kind: string}) => { + const [showAll, setShowAll] = useState(false); + const [hideNormal, setHideNormal] = useState(false); + const [events, setEvents] = useState(); + const [error, setError] = useState(); -interface State { - showAll: boolean; - hideNormal: boolean; - events?: Event[]; - error?: Error; -} - -export class EventsPanel extends React.Component { - private get fieldSelector() { + useEffect(() => { const fieldSelectors: string[] = []; - if (!this.showAll) { - fieldSelectors.push('involvedObject.kind=' + this.props.kind); - fieldSelectors.push('involvedObject.name=' + this.props.name); + if (!showAll) { + fieldSelectors.push('involvedObject.kind=' + kind); + fieldSelectors.push('involvedObject.name=' + name); } - if (this.hideNormal) { + if (hideNormal) { fieldSelectors.push('type!=Normal'); } - return fieldSelectors.join(','); - } - - private set showAll(showAll: boolean) { - this.setState({showAll, events: undefined}, () => this.fetchEvents()); - } - - private get showAll() { - return this.state.showAll; - } - - private set hideNormal(hideNormal: boolean) { - this.setState({hideNormal, events: undefined}, () => this.fetchEvents()); - } - - private get hideNormal() { - return this.state.hideNormal; - } - - private subscription?: Subscription; - - constructor(props: Readonly) { - super(props); - this.state = {showAll: false, hideNormal: false}; - } + const fieldSelector = fieldSelectors.join(','); - public componentDidMount() { - this.fetchEvents(); - } - - public componentWillUnmount() { - if (this.subscription) { - this.subscription.unsubscribe(); - } - } - - public render() { - return ( - <> -
- (this.showAll = !this.showAll)} title='Show all events in the namespace'> - Show All - - (this.hideNormal = !this.hideNormal)} title='Hide normal events'> - Hide normal - -
- {this.renderEvents()} - + const lw = new ListWatch( + // no list function, so we fake it + () => Promise.resolve({metadata: {}, items: []}), + () => + // ListWatch can only handle Kubernetes Watch Event - so we fake it + services.workflows.watchEvents(namespace, fieldSelector).map( + x => + x && { + type: 'ADDED', + object: x + } + ), + () => setError(null), + () => setError(null), + items => setEvents([...items]), + setError ); - } - - private fetchEvents() { - if (this.subscription) { - this.subscription.unsubscribe(); - } - this.subscription = services.workflows - .watchEvents(this.props.namespace, this.fieldSelector) - .map(event => { - const events = this.state.events || []; - const index = events.findIndex(item => item.metadata.uid === event.metadata.uid); - if (index > -1 && event.metadata.resourceVersion === events[index].metadata.resourceVersion) { - return events; - } - if (index > -1) { - events[index] = event; - } else { - events.unshift(event); - } - return events; - }) - .subscribe( - events => this.setState({events}), - error => this.setState({error}) - ); - } + lw.start(); + return () => lw.stop(); + }, [showAll, hideNormal]); - private renderEvents() { - if (this.state.error) { - return ; - } - if (!this.state.events || this.state.events.length === 0) { - return ( - + return ( + <> +
+ setShowAll(!showAll)} title='Show all events in the namespace'> + Show All + + setHideNormal(!hideNormal)} title='Hide normal events'> + Hide normal + +
+ + {!events || events.length === 0 ? ( + Waiting for events. Still waiting for data? Try changing the filters. - ); - } - return ( -
-
-
Type
-
Last Seen
-
Reason
-
Object
-
Message
-
- {this.state.events.map(e => ( -
-
- {e.type === 'Normal' ? : } -
-
- -
-
{e.reason}
- -
- {e.involvedObject.kind}/{e.involvedObject.name} -
-
{e.message}
+ ) : ( +
+
+
Type
+
Last Seen
+
Reason
+
Object
+
Message
- ))} -
- ); - } -} + {events.map(e => ( +
+
+ {e.type === 'Normal' ? : } +
+
+ +
+
{e.reason}
+
+ {e.involvedObject.kind}/{e.involvedObject.name} +
+
{e.message}
+
+ ))} +
+ )} + + ); +}; diff --git a/ui/src/app/workflows/components/submit-from-workflow-template-panel.tsx b/ui/src/app/workflows/components/submit-from-workflow-template-panel.tsx new file mode 100644 index 000000000000..3189467eff3b --- /dev/null +++ b/ui/src/app/workflows/components/submit-from-workflow-template-panel.tsx @@ -0,0 +1,47 @@ +import * as React from 'react'; +import {useState} from 'react'; +import {WorkflowTemplate} from '../../../models'; +import {Button} from '../../shared/components/button'; +import {DataLoaderDropdown} from '../../shared/components/data-loader-dropdown'; +import {ErrorNotice} from '../../shared/components/error-notice'; +import {services} from '../../shared/services'; +import {SubmitWorkflowPanel} from './submit-workflow-panel'; + +export const SubmitFromWorkflowTemplatePanel = ({namespace}: {namespace: string}) => { + const [error, setError] = useState(); + const [workflowTemplate, setWorkflowTemplate] = useState(); + + return ( + <> + + {!workflowTemplate ? ( + services.workflowTemplate.list(namespace).then(list => list.map(x => x.metadata.name))} + onChange={name => { + services.workflowTemplate + .get(name, namespace) + .then(setWorkflowTemplate) + .catch(setError); + }} + placeholder='Select workflow template...' + /> + ) : ( + <> +
+ +
+ t.name) || []} + parameters={(workflowTemplate.spec.arguments || {}).parameters} + /> + + )} + + ); +}; diff --git a/ui/src/app/workflows/components/submit-workflow-panel.tsx b/ui/src/app/workflows/components/submit-workflow-panel.tsx index 8e84c0d32e1a..61f3201ae2c2 100644 --- a/ui/src/app/workflows/components/submit-workflow-panel.tsx +++ b/ui/src/app/workflows/components/submit-workflow-panel.tsx @@ -28,7 +28,7 @@ export class SubmitWorkflowPanel extends React.Component { super(props); this.state = { entrypoint: this.props.entrypoint || (this.props.entrypoints.length > 0 && this.props.entrypoints[0]), - parameters: this.props.parameters, + parameters: this.props.parameters || [], labels: ['submit-from-ui=true'] }; } diff --git a/ui/src/app/workflows/components/workflow-artifacts.tsx b/ui/src/app/workflows/components/workflow-artifacts.tsx index 1012579aea5b..6148119fefd0 100644 --- a/ui/src/app/workflows/components/workflow-artifacts.tsx +++ b/ui/src/app/workflows/components/workflow-artifacts.tsx @@ -40,7 +40,7 @@ export const WorkflowArtifacts = (props: Props) => {
{artifacts.map(artifact => ( -
+
diff --git a/ui/src/app/workflows/components/workflow-creator.tsx b/ui/src/app/workflows/components/workflow-creator.tsx new file mode 100644 index 000000000000..38204af65cad --- /dev/null +++ b/ui/src/app/workflows/components/workflow-creator.tsx @@ -0,0 +1,38 @@ +import * as React from 'react'; +import {useState} from 'react'; +import {Workflow} from '../../../models'; +import {Button} from '../../shared/components/button'; +import {ErrorNotice} from '../../shared/components/error-notice'; +import {ExampleManifests} from '../../shared/components/example-manifests'; +import {UploadButton} from '../../shared/components/upload-button'; +import {exampleWorkflow} from '../../shared/examples'; +import {services} from '../../shared/services'; +import {Utils} from '../../shared/utils'; +import {WorkflowEditor} from './workflow-editor'; + +export const WorkflowCreator = ({namespace, onCreate}: {namespace: string; onCreate: (workflow: Workflow) => void}) => { + const [workflow, setWorkflow] = useState(exampleWorkflow(Utils.getNamespace(namespace))); + const [error, setError] = useState(); + return ( + <> +
+ + +
+ + +
+ . +
+ + ); +}; diff --git a/ui/src/app/workflows/components/workflow-dag/genres.ts b/ui/src/app/workflows/components/workflow-dag/genres.ts new file mode 100644 index 000000000000..55214110e66f --- /dev/null +++ b/ui/src/app/workflows/components/workflow-dag/genres.ts @@ -0,0 +1,11 @@ +export const genres = { + Pod: true, + Steps: true, + DAG: true, + Retry: true, + Skipped: true, + Suspend: true, + TaskGroup: false, + StepGroup: false, + Collapsed: true +}; diff --git a/ui/src/app/workflows/components/workflow-dag/graph/collapsible-node.ts b/ui/src/app/workflows/components/workflow-dag/graph/collapsible-node.ts index b79ca43038a2..6d5bc40c0900 100644 --- a/ui/src/app/workflows/components/workflow-dag/graph/collapsible-node.ts +++ b/ui/src/app/workflows/components/workflow-dag/graph/collapsible-node.ts @@ -26,7 +26,3 @@ export function getNodeParent(id: string): string { export function getMessage(id: string): string { return (JSON.parse(id) as CollapsedNode).message; } - -export function getType(id: string): NodeType { - return (JSON.parse(id) as CollapsedNode).type; -} diff --git a/ui/src/app/workflows/components/workflow-dag/icons.ts b/ui/src/app/workflows/components/workflow-dag/icons.ts new file mode 100644 index 000000000000..01598e3064e4 --- /dev/null +++ b/ui/src/app/workflows/components/workflow-dag/icons.ts @@ -0,0 +1,13 @@ +import {Icon} from '../../../shared/components/icon'; + +export const icons: {[key: string]: Icon} = { + Collapsed: 'ellipsis-h', + Error: 'times', + Failed: 'times', + Omitted: 'forward', + Pending: 'clock', + Running: 'circle-notch', + Skipped: 'forward', + Succeeded: 'check', + Suspended: 'pause' +}; diff --git a/ui/src/app/workflows/components/workflow-dag/workflow-dag-render-options-panel.tsx b/ui/src/app/workflows/components/workflow-dag/workflow-dag-render-options-panel.tsx index 7fb1984668f5..e9efee3166e3 100644 --- a/ui/src/app/workflows/components/workflow-dag/workflow-dag-render-options-panel.tsx +++ b/ui/src/app/workflows/components/workflow-dag/workflow-dag-render-options-panel.tsx @@ -1,7 +1,3 @@ -import {Checkbox} from 'argo-ui/src/components/checkbox'; -import {DropDown} from 'argo-ui/src/components/dropdown/dropdown'; -import {TopBarFilter} from 'argo-ui/src/index'; -import * as classNames from 'classnames'; import * as React from 'react'; import {WorkflowDagRenderOptions} from './workflow-dag'; @@ -11,100 +7,8 @@ export class WorkflowDagRenderOptionsPanel extends React.Component = { - items: [ - {content: () => Phase}, - {value: 'phase:Pending', label: 'Pending'}, - {value: 'phase:Running', label: 'Running'}, - {value: 'phase:Succeeded', label: 'Succeeded'}, - {value: 'phase:Skipped', label: 'Skipped'}, - {value: 'phase:Failed', label: 'Failed'}, - {value: 'phase:Error', label: 'Error'}, - {content: () => Type}, - {value: 'type:Pod', label: 'Pod'}, - {value: 'type:Steps', label: 'Steps'}, - {value: 'type:DAG', label: 'DAG'}, - {value: 'type:Retry', label: 'Retry'}, - {value: 'type:Skipped', label: 'Skipped'}, - {value: 'type:Suspend', label: 'Suspend'}, - {value: 'type:TaskGroup', label: 'TaskGroup'}, - {value: 'type:StepGroup', label: 'StepGroup'} - ], - selectedValues: this.props.nodesToDisplay, - selectionChanged: items => { - this.props.onChange({ - ...this.workflowDagRenderOptions, - nodesToDisplay: items - }); - } - }; return ( -
- ( -
-