From 9d5e8298b6b3f448204cc9fea868b6f302a64fe0 Mon Sep 17 00:00:00 2001 From: rosstimothy <39066650+rosstimothy@users.noreply.github.com> Date: Wed, 13 Nov 2024 15:08:20 -0500 Subject: [PATCH 01/11] Improve backoff on host uuid file creation contention (#48903) Aims to reduce flakiness in tests by using a linear backoff during contention instead of sleeping for a constant amount of time. The goal is to eliminate failures in CI while not causing any additional backoff than needed in real life scenarios. --- lib/utils/hostid/hostid_unix.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/utils/hostid/hostid_unix.go b/lib/utils/hostid/hostid_unix.go index 027a08de614ef..df43aa4ab851f 100644 --- a/lib/utils/hostid/hostid_unix.go +++ b/lib/utils/hostid/hostid_unix.go @@ -27,6 +27,7 @@ import ( "github.com/google/uuid" "github.com/gravitational/trace" + "github.com/gravitational/teleport/api/utils/retryutils" "github.com/gravitational/teleport/lib/utils" ) @@ -49,6 +50,16 @@ func ReadOrCreateFile(dataDir string) (string, error) { hostUUIDFileLock := GetPath(dataDir) + ".lock" const iterationLimit = 3 + backoff, err := retryutils.NewRetryV2(retryutils.RetryV2Config{ + First: 100 * time.Millisecond, + Driver: retryutils.NewLinearDriver(100 * time.Millisecond), + Max: time.Second, + Jitter: retryutils.FullJitter, + }) + if err != nil { + return "", trace.Wrap(err) + } + for i := 0; i < iterationLimit; i++ { if read, err := ReadFile(dataDir); err == nil { return read, nil @@ -57,7 +68,7 @@ func ReadOrCreateFile(dataDir string) (string, error) { } // Checking error instead of the usual uuid.New() in case uuid generation - // fails due to not enough randomness. It's been known to happen happen when + // fails due to not enough randomness. It's been known to happen when // Teleport starts very early in the node initialization cycle and /dev/urandom // isn't ready yet. rawID, err := uuid.NewRandom() @@ -91,12 +102,14 @@ func ReadOrCreateFile(dataDir string) (string, error) { id, err := writeFile(rawID.String()) if err != nil { if errors.Is(err, utils.ErrUnsuccessfulLockTry) { - time.Sleep(10 * time.Millisecond) + backoff.Inc() + <-backoff.After() continue } return "", trace.Wrap(err) } + backoff.Reset() return id, nil } From 2865e8ec294c14cf36932c6dff73cd71371f6f86 Mon Sep 17 00:00:00 2001 From: Steven Martin Date: Wed, 13 Nov 2024 15:34:34 -0500 Subject: [PATCH 02/11] docs: update troubleshooting for enterprise info (#48882) * docs: update troubleshooting for enterprise info * docs: update troubleshooting Co-authored-by: Paul Gottschling * docs: update troubleshooting.mdx Co-authored-by: Paul Gottschling --------- Co-authored-by: Paul Gottschling --- docs/pages/admin-guides/management/admin/troubleshooting.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/pages/admin-guides/management/admin/troubleshooting.mdx b/docs/pages/admin-guides/management/admin/troubleshooting.mdx index 2e6feac238dad..2f4db10fd9ccc 100644 --- a/docs/pages/admin-guides/management/admin/troubleshooting.mdx +++ b/docs/pages/admin-guides/management/admin/troubleshooting.mdx @@ -184,7 +184,8 @@ through the [Teleport support portal](https://support.goteleport.com). If you need help, please ask on our [community forum](https://github.com/gravitational/teleport/discussions). You can also open an [issue on GitHub](https://github.com/gravitational/teleport/issues). -For more information about custom features, or to try the [self-hosted Enterprise edition](../../deploy-a-cluster/deploy-a-cluster.mdx) of Teleport, reach out to us at [sales](https://goteleport.com/signup/enterprise/). +For more information about Enterprise features reach out to [the Teleport sales team](https://goteleport.com/signup/enterprise/). +You can also sign up for a [free trial](https://goteleport.com/signup) of Teleport Enterprise. From 268d9ca07bdd6d7f663298f4c621c3a73521bc9a Mon Sep 17 00:00:00 2001 From: Zac Bergquist Date: Wed, 13 Nov 2024 14:20:49 -0700 Subject: [PATCH 03/11] docs: update FAQ (#48810) Re-order some of the questions to move related topics closer together, and add a new FAQ that explains how roles are embedded in certificates. --- docs/pages/core-concepts.mdx | 28 ++++++------- docs/pages/faq.mdx | 80 +++++++++++++++++++++--------------- 2 files changed, 62 insertions(+), 46 deletions(-) diff --git a/docs/pages/core-concepts.mdx b/docs/pages/core-concepts.mdx index c7afd7338db53..011377dbe4285 100644 --- a/docs/pages/core-concepts.mdx +++ b/docs/pages/core-concepts.mdx @@ -39,7 +39,7 @@ Read our guides to how [authorization](reference/architecture/authorization.mdx) ### Teleport Proxy Service The **Teleport Proxy Service** allows for secure access to resources in your -infrastructure from the public internet without the need for a VPN. +infrastructure from the public internet without the need for a VPN. It establishes reverse tunnels to the **Teleport Auth Service** and **Teleport Services**, which can run in private networks. This means that, in the Proxy @@ -47,7 +47,7 @@ Service's minimal configuration, you can expose only port `443` to the internet and run the rest of your infrastructure in private networks. You can also configure clients to bypass Proxy Service instances and connect to -resources with Teleport-issued certificates directly. +resources with Teleport-issued certificates directly. Read our guide to [how the Teleport Proxy Service works](reference/architecture/proxy.mdx). @@ -73,7 +73,7 @@ Service](./enroll-resources/application-access/introduction.mdx). ### Teleport Database Service Proxies TCP traffic in the native protocols of popular databases, including -PostgreSQL and MySQL. +PostgreSQL and MySQL. Read more about the [Teleport Database Service](./enroll-resources/database-access/database-access.mdx). @@ -92,7 +92,7 @@ Proxies HTTP traffic to the Kubernetes API server. Read more about the [Teleport Kubernetes Service](./enroll-resources/kubernetes-access/introduction.mdx) -### Teleport SSH Service +### Teleport SSH Service An SSH server implementation that allows users to execute commands on remote machines while taking advantage of Teleport's built-in access controls, @@ -104,7 +104,7 @@ Read more about the [Teleport SSH Service](./enroll-resources/server-access/intr Allows machines and services—called bot users—to communicate securely with resources in your infrastructure by automatically provisioning and renewing -credentials. +credentials. Bot users can connect to resources in your infrastructure without relying on static credentials (e.g., certificates and private keys) that become more @@ -131,7 +131,7 @@ on GitHub. You can find a detailed comparison of the features available in each Teleport edition in [Frequently Asked -Questions](./faq.mdx#how-is-open-source-different-from-enterprise). +Questions](./faq.mdx#how-is-teleports-community-edition-different-from-enterprise). ### Teleport Enterprise Cloud @@ -193,7 +193,7 @@ Ultimately, a Teleport user is the subject of a certificate issued by the **Teleport Auth Service**. The Auth Service verifies that a client or service attempting to connect has a valid Teleport-issued certificate. It then uses the subject of the certificate—including its username and Teleport roles—to -authorize the user. +authorize the user. Read more about [local users](reference/access-controls/authentication.mdx) and how [SSO authentication works in Teleport](admin-guides/access-controls/sso/sso.mdx). @@ -201,21 +201,21 @@ authentication works in Teleport](admin-guides/access-controls/sso/sso.mdx). ### Authentication connector An authentication connector is a **configuration resource** that allows users to -authenticate to Teleport via a Single Sign-On (SSO) solution. +authenticate to Teleport via a Single Sign-On (SSO) solution. See our guide to [Authentication Options](reference/access-controls/authentication.mdx). ### Trusted clusters -Teleport allows you to configure a **trusted cluster relationship** between a -**root cluster** and one or more **leaf clusters** that trust the root cluster -certificate authority. The trust relationship between the root and leaf clusters -enables users authenticated in the root cluster to access resources +Teleport allows you to configure a **trusted cluster relationship** between a +**root cluster** and one or more **leaf clusters** that trust the root cluster +certificate authority. The trust relationship between the root and leaf clusters +enables users authenticated in the root cluster to access resources in leaf cluster. The root and leaf cluster operate independently with their own users, roles, and resources, but the trust relationship allows users with certain roles in the root cluster to be mapped to roles and permissions defined in the leaf cluster. For more information about how to configure a trust relationship between clusters, -see [Configure Trusted Clusters](admin-guides/management/admin/trustedclusters.mdx). -For an overview of the architecture used in a trusted cluster relationship, see +see [Configure Trusted Clusters](admin-guides/management/admin/trustedclusters.mdx). +For an overview of the architecture used in a trusted cluster relationship, see [Trusted Cluster Architecture](reference/architecture/trustedclusters.mdx). diff --git a/docs/pages/faq.mdx b/docs/pages/faq.mdx index 30ff025784be6..717c211f34c96 100644 --- a/docs/pages/faq.mdx +++ b/docs/pages/faq.mdx @@ -15,32 +15,24 @@ Fortune 500 companies. It has been through several security audits from nationally recognized technology security companies, so we are comfortable with the stability of Teleport from a security perspective. -## Can Teleport be deployed in agentless mode? - -Yes. All Teleport services support agentless mode, where the service proxies -traffic to an upstream infrastructure resource not available on `localhost`. +## Can I connect to nodes behind a firewall? -With Teleport in agentless mode, you can easily control access to SSH servers, -Kubernetes clusters, desktops, databases, and internal applications without -running any additional software on your servers. Agentless mode supports session -recordings and audit logs for deep understanding into user behavior. +Yes, Teleport supports reverse SSH tunnels out of the box. To configure +behind-firewall clusters, see [Configure Trusted Clusters](admin-guides/management/admin/trustedclusters.mdx). -For capabilities such as kernel-level logging and user provisioning, we -recommend Teleport as a drop in replacement for OpenSSH. Since Teleport replaces -the OpenSSH agent while preserving OpenSSH's functionality, you get more -functionality without a net addition of an agent on your system. +## How is Teleport's Community Edition different from Enterprise? -## Can I use OpenSSH with a Teleport cluster? +Teleport provides two editions: -Yes, this question comes up often and is related to the previous one. Take a -look at [Using OpenSSH Guide](enroll-resources/server-access/openssh/openssh-agentless.mdx). +- Teleport Enterprise +- Teleport Community Edition -## Can I connect to nodes behind a firewall? +Here is a detailed breakdown of the differences between Teleport's editions. -Yes, Teleport supports reverse SSH tunnels out of the box. To configure -behind-firewall clusters, see [Configure Trusted Clusters](admin-guides/management/admin/trustedclusters.mdx). +(!docs/pages/includes/edition-comparison.mdx!) ## Should we use Teleport Enterprise or Teleport Community Edition for connecting resources to our Teleport cluster? + (!docs/pages/includes/ent-vs-community-faq.mdx!) ## Can individual agents create reverse tunnels to the Proxy Service without creating a new cluster? @@ -58,6 +50,26 @@ Yes, Teleport supports tunnel multiplexing on a single port. Set the setting in the `proxy_service` configuration. Teleport will automatically use multiplexing with that configuration. +## Can Teleport be deployed in agentless mode? + +Yes. All Teleport services support agentless mode, where the service proxies +traffic to an upstream infrastructure resource not available on `localhost`. + +With Teleport in agentless mode, you can easily control access to SSH servers, +Kubernetes clusters, desktops, databases, and internal applications without +running any additional software on your servers. Agentless mode supports session +recordings and audit logs for deep understanding into user behavior. + +For capabilities such as kernel-level logging and user provisioning, we +recommend Teleport as a drop in replacement for OpenSSH. Since Teleport replaces +the OpenSSH agent while preserving OpenSSH's functionality, you get more +functionality without a net addition of an agent on your system. + +## Can I use OpenSSH with a Teleport cluster? + +Yes, this question comes up often and is related to the previous one. Take a +look at [Using OpenSSH Guide](enroll-resources/server-access/openssh/openssh-agentless.mdx). + ## Can I copy files from one Teleport node to another? Yes, Teleport supports [Headless WebAuthn authentication](admin-guides/access-controls/guides/headless.mdx), @@ -69,7 +81,7 @@ are not logged in to Teleport or may not have access to a browser. If your host machine is joined to an Active Directory domain, you might find user lookups take a lot longer than you expect. The number of Active Directory accounts that must be scanned to perform a user lookup can cause tsh to hang waiting to get information about the current user. -To fix this issue, you can use environment variables to set default account information for your +To fix this issue, you can use environment variables to set default account information for your Teleport user. If you are experiencing long lookup times on Windows, do the following: - Either set the `TELEPORT_USER` environment variable or set the `--user` flag to the name of your Teleport user. @@ -79,18 +91,6 @@ Teleport user. If you are experiencing long lookup times on Windows, do the foll You can set these environment variables globally in Windows so that you don't have to set them every time you run `tsh`. -## How is Open Source different from Enterprise? - -Teleport provides three editions: - -- Teleport Enterprise -- Teleport Enterprise Cloud -- Teleport Community Edition - -Here is a detailed breakdown of the differences between Teleport's editions. - -(!docs/pages/includes/edition-comparison.mdx!) - ## Which version of Teleport is supported? Teleport releases a new major version approximately every 4 months, and provides @@ -125,6 +125,19 @@ Please refer to our [Networking](./reference/networking.mdx) guide. Teleport offers this feature for the Enterprise (Cloud) and Enterprise (Self-Hosted) versions of Teleport. +## Why do changes to a user's role set only take effect on the log next login? + +A Teleport user's assigned roles are embedded in the client certificate they +receive upon logging on. This certificate remains valid and can be used until +its expiry, even if the user's role set has changed. + +To get a new certificate with the new role set, the user will need to log out +and log back in. + +Revocation of Teleport access should be done with Teleport's +[session and identity locks](./admin-guides/access-controls/guides/locking.mdx), +not by removing roles. + ## Does Teleport support provisioning users via SCIM? Teleport supports [SCIM](https://scim.cloud/) provisioning for Okta via the @@ -148,7 +161,10 @@ Service and Auth Service, as well as agents running other Teleport Services. Teleport requires a minimum of TLS version 1.2. -This means that when applications and clients establish or accept TLS connections with Teleport processes, they must use TLS 1.2 or a higher protocol version. Teleport enforces this requirement in all operations that involve TLS connections. +This means that when applications and clients establish or accept TLS +connections with Teleport processes, they must use TLS 1.2 or a higher protocol +version. Teleport enforces this requirement in all operations that involve TLS +connections. ## Can I suppress warnings about available upgrades? From 9f3ef20456518380d7ec45f07d54cb5625c19e52 Mon Sep 17 00:00:00 2001 From: Vadym Popov Date: Wed, 13 Nov 2024 17:03:03 -0500 Subject: [PATCH 04/11] [teleport-update] Add teleport-update to build and archive (#48839) * Add teleport-update to build and archive * Add teleport-update to install scripts * Add build flags without buildmode pie * Add helper message for install.sh script * Exclude teleport-update from darwin platform * Add teleport-update to rpm and deb packages * Remove teleport-update from deb, rpm packages Add comment for the buildflags --- Makefile | 10 ++++++++-- assets/install-scripts/install.sh | 5 ++++- build.assets/install | 2 +- lib/web/scripts/node-join/install.sh | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 2f945dfe92e3f..7012ac04e823d 100644 --- a/Makefile +++ b/Makefile @@ -48,9 +48,12 @@ GO_LDFLAGS ?= -w -s $(KUBECTL_SETVERSION) ifeq ("$(TELEPORT_DEBUG)","true") BUILDFLAGS ?= $(ADDFLAGS) -gcflags=all="-N -l" BUILDFLAGS_TBOT ?= $(ADDFLAGS) -gcflags=all="-N -l" +BUILDFLAGS_TELEPORT_UPDATE ?= $(ADDFLAGS) -gcflags=all="-N -l" else BUILDFLAGS ?= $(ADDFLAGS) -ldflags '$(GO_LDFLAGS)' -trimpath -buildmode=pie BUILDFLAGS_TBOT ?= $(ADDFLAGS) -ldflags '$(GO_LDFLAGS)' -trimpath +# teleport-update builds with disabled cgo, buildmode=pie is not required. +BUILDFLAGS_TELEPORT_UPDATE ?= $(ADDFLAGS) -ldflags '$(GO_LDFLAGS)' -trimpath endif GO_ENV_OS := $(shell go env GOOS) @@ -240,7 +243,8 @@ endif # On Windows only build tsh. On all other platforms build teleport, tctl, # and tsh. -BINS_default = teleport tctl tsh tbot fdpass-teleport +BINS_default = teleport tctl tsh tbot fdpass-teleport teleport-update +BINS_darwin = teleport tctl tsh tbot fdpass-teleport BINS_windows = tsh tctl BINS = $(or $(BINS_$(OS)),$(BINS_default)) BINARIES = $(addprefix $(BUILDDIR)/,$(BINS)) @@ -312,6 +316,8 @@ endif CGOFLAG = CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ BUILDFLAGS = $(ADDFLAGS) -ldflags '-w -s $(KUBECTL_SETVERSION)' -trimpath -buildmode=pie BUILDFLAGS_TBOT = $(ADDFLAGS) -ldflags '-w -s $(KUBECTL_SETVERSION)' -trimpath +# teleport-update builds with disabled cgo, buildmode=pie is not required. +BUILDFLAGS_TELEPORT_UPDATE = $(ADDFLAGS) -ldflags '-w -s $(KUBECTL_SETVERSION)' -trimpath endif ifeq ("$(OS)","darwin") @@ -397,7 +403,7 @@ $(BUILDDIR)/tbot: .PHONY: $(BUILDDIR)/teleport-update $(BUILDDIR)/teleport-update: - GOOS=$(OS) GOARCH=$(ARCH) CGO_ENABLED=0 go build -o $(BUILDDIR)/teleport-update $(BUILDFLAGS) ./tool/teleport-update + GOOS=$(OS) GOARCH=$(ARCH) CGO_ENABLED=0 go build -o $(BUILDDIR)/teleport-update $(BUILDFLAGS_TELEPORT_UPDATE) ./tool/teleport-update TELEPORT_ARGS ?= start .PHONY: teleport-hot-reload diff --git a/assets/install-scripts/install.sh b/assets/install-scripts/install.sh index 9381051da484a..d105e2ee9bcfa 100755 --- a/assets/install-scripts/install.sh +++ b/assets/install-scripts/install.sh @@ -207,7 +207,7 @@ install_via_zypper() { } -# download .tar.gz file via curl/wget, unzip it and run the install sript +# download .tar.gz file via curl/wget, unzip it and run the install script install_via_curl() { TEMP_DIR=$(mktemp -d -t teleport-XXXXXXXXXX) @@ -387,6 +387,9 @@ install_teleport() { if type fdpass-teleport &>/dev/null; then echo " fdpass-teleport - Teleport Machine ID client." fi + if type teleport-update &>/dev/null; then + echo " teleport-update - Teleport auto-update agent." + fi } # The suffix is "-ent" if we are installing a commercial edition of Teleport and diff --git a/build.assets/install b/build.assets/install index 691c627d192ce..eb52ec7d99959 100755 --- a/build.assets/install +++ b/build.assets/install @@ -14,7 +14,7 @@ VARDIR=/var/lib/teleport echo "Starting Teleport installation..." cd $(dirname $0) mkdir -p $VARDIR $BINDIR -cp -f teleport tctl tsh tbot $BINDIR/ || exit 1 +cp -f teleport tctl tsh tbot teleport-update $BINDIR/ || exit 1 # # What operating system is the user running? diff --git a/lib/web/scripts/node-join/install.sh b/lib/web/scripts/node-join/install.sh index 3151fb5c89885..29ed2ee8cb73a 100755 --- a/lib/web/scripts/node-join/install.sh +++ b/lib/web/scripts/node-join/install.sh @@ -17,7 +17,7 @@ SYSTEMD_UNIT_PATH="/lib/systemd/system/teleport.service" TARGET_PORT_DEFAULT=443 TELEPORT_ARCHIVE_PATH='{{.packageName}}' TELEPORT_BINARY_DIR="/usr/local/bin" -TELEPORT_BINARY_LIST="teleport tctl tsh" +TELEPORT_BINARY_LIST="teleport tctl tsh teleport-update" TELEPORT_CONFIG_PATH="/etc/teleport.yaml" TELEPORT_DATA_DIR="/var/lib/teleport" TELEPORT_DOCS_URL="https://goteleport.com/docs/" From ac2d3fdce552f0231b1660e47ae4c9ae713be325 Mon Sep 17 00:00:00 2001 From: Hugo Shaka Date: Wed, 13 Nov 2024 17:18:58 -0500 Subject: [PATCH 05/11] Make teleport container do a graceful shutdown (#48893) * Container image should try a graceful shutdown by default * Make grace termination period configurable in teleport-kube-agent * re-render docs --- build.assets/charts/Dockerfile | 9 +++++ build.assets/charts/Dockerfile-distroless | 3 ++ .../charts/Dockerfile-distroless-fips | 3 ++ .../zz_generated.teleport-kube-agent.mdx | 15 ++++++++ .../templates/statefulset.yaml | 3 ++ .../__snapshot__/statefulset_test.yaml.snap | 34 +++++++++++++++++++ .../tests/statefulset_test.yaml | 10 ++++++ .../teleport-kube-agent/values.schema.json | 5 +++ .../chart/teleport-kube-agent/values.yaml | 10 ++++++ 9 files changed, 92 insertions(+) diff --git a/build.assets/charts/Dockerfile b/build.assets/charts/Dockerfile index f7306f99aa1cb..30991434a1caf 100644 --- a/build.assets/charts/Dockerfile +++ b/build.assets/charts/Dockerfile @@ -1,3 +1,8 @@ +# DEPRECATED: Images from this dockerfile are not published for v15 and above +# https://goteleport.com/docs/changelog/#heavy-container-images-are-discontinued +# Teleport images are built from Dockerfile-distroless +# TODO(hugoShaka): cleanup the Makefile docker/image targets and remove this file. + # Stage to build the image, without FIPS entrypoint argument FROM ubuntu:20.04 AS teleport @@ -67,6 +72,10 @@ RUN --mount=target=/ctx \ # Used to track whether a Teleport agent was installed using this method. ENV TELEPORT_INSTALL_METHOD_DOCKERFILE=true +# Attempt a graceful shutdown by default +# See https://goteleport.com/docs/reference/signals/ for signal reference. +STOPSIGNAL SIGQUIT + # By setting this entry point, we expose make target as command. ENTRYPOINT ["/usr/bin/dumb-init", "teleport", "start", "-c", "/etc/teleport/teleport.yaml"] diff --git a/build.assets/charts/Dockerfile-distroless b/build.assets/charts/Dockerfile-distroless index 7497240a6acf6..c57265c488405 100644 --- a/build.assets/charts/Dockerfile-distroless +++ b/build.assets/charts/Dockerfile-distroless @@ -30,4 +30,7 @@ FROM $BASE_IMAGE COPY --from=teleport /opt/staging / COPY --from=staging /opt/staging/root / COPY --from=staging /opt/staging/status /var/lib/dpkg/status.d +# Attempt a graceful shutdown by default +# See https://goteleport.com/docs/reference/signals/ for signal reference. +STOPSIGNAL SIGQUIT ENTRYPOINT ["/usr/bin/dumb-init", "/usr/local/bin/teleport", "start", "-c", "/etc/teleport/teleport.yaml"] diff --git a/build.assets/charts/Dockerfile-distroless-fips b/build.assets/charts/Dockerfile-distroless-fips index b6594eb266c70..482704bf1e8be 100644 --- a/build.assets/charts/Dockerfile-distroless-fips +++ b/build.assets/charts/Dockerfile-distroless-fips @@ -30,4 +30,7 @@ FROM $BASE_IMAGE COPY --from=teleport /opt/staging / COPY --from=staging /opt/staging/root / COPY --from=staging /opt/staging/status /var/lib/dpkg/status.d +# Attempt a graceful shutdown by default +# See https://goteleport.com/docs/reference/signals/ for signal reference. +STOPSIGNAL SIGQUIT ENTRYPOINT ["/usr/bin/dumb-init", "/usr/local/bin/teleport", "start", "-c", "/etc/teleport/teleport.yaml", "--fips"] diff --git a/docs/pages/includes/helm-reference/zz_generated.teleport-kube-agent.mdx b/docs/pages/includes/helm-reference/zz_generated.teleport-kube-agent.mdx index 1ebd25154c1f9..c7fb92710685e 100644 --- a/docs/pages/includes/helm-reference/zz_generated.teleport-kube-agent.mdx +++ b/docs/pages/includes/helm-reference/zz_generated.teleport-kube-agent.mdx @@ -631,6 +631,21 @@ teleportConfig: "*":"*" ``` +## `terminationGracePeriodSeconds` + +| Type | Default | +|------|---------| +| `integer` | `30` | + +`terminationGracePeriodSeconds` is the time the pod has to do a graceful shutdown. +If teleport has not existed after this delay, the process gets killed. +Teleport will wait until every connection backed by the agent is over before exiting. +If you want to reduce the disruption of rolling out agents at the price of a slower rollout, you can increase this +value to an hour. + +See the [Kubernetes Pod Lifecycle docs](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination) +for more details. + ## `tls` `tls` contains settings for mounting your own TLS material in the agent pod. diff --git a/examples/chart/teleport-kube-agent/templates/statefulset.yaml b/examples/chart/teleport-kube-agent/templates/statefulset.yaml index 5018a8c38e6d1..3105debacb4e2 100644 --- a/examples/chart/teleport-kube-agent/templates/statefulset.yaml +++ b/examples/chart/teleport-kube-agent/templates/statefulset.yaml @@ -49,6 +49,9 @@ spec: {{- if .Values.podSecurityContext }} securityContext: {{- toYaml .Values.podSecurityContext | nindent 8}} {{- end }} + {{- if .Values.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} + {{- end }} {{- if or .Values.affinity (gt (int $replicaCount) 1) }} affinity: {{- if .Values.affinity }} diff --git a/examples/chart/teleport-kube-agent/tests/__snapshot__/statefulset_test.yaml.snap b/examples/chart/teleport-kube-agent/tests/__snapshot__/statefulset_test.yaml.snap index 3a7ced7542085..d6ce26457c58a 100644 --- a/examples/chart/teleport-kube-agent/tests/__snapshot__/statefulset_test.yaml.snap +++ b/examples/chart/teleport-kube-agent/tests/__snapshot__/statefulset_test.yaml.snap @@ -63,6 +63,7 @@ sets Pod annotations when specified: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -135,6 +136,7 @@ sets Pod labels when specified: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -231,6 +233,7 @@ sets StatefulSet labels when specified: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -335,6 +338,7 @@ should add insecureSkipProxyTLSVerify to args when set in values: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -407,6 +411,7 @@ should add volumeClaimTemplate for data volume when using StatefulSet and action securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -499,6 +504,7 @@ should add volumeClaimTemplate for data volume when using StatefulSet and is Fre securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -581,6 +587,7 @@ should add volumeMount for data volume when using StatefulSet: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -653,6 +660,7 @@ should expose diag port: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -725,6 +733,7 @@ should generate Statefulset when storage is disabled and mode is a Upgrade: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -811,6 +820,7 @@ should have multiple replicas when replicaCount is set (using .replicaCount, dep securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -895,6 +905,7 @@ should have multiple replicas when replicaCount is set (using highAvailability.r securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -967,6 +978,7 @@ should have one replica when replicaCount is not set: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -1039,6 +1051,7 @@ should install Statefulset when storage is disabled and mode is a Fresh Install: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -1115,6 +1128,7 @@ should mount extraVolumes and extraVolumeMounts: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -1193,6 +1207,7 @@ should mount jamfCredentialsSecret if it already exists and when role is jamf: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -1273,6 +1288,7 @@ should mount jamfCredentialsSecret.name when role is jamf: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -1355,6 +1371,7 @@ should mount tls.existingCASecretName and set environment when set in values: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -1439,6 +1456,7 @@ should mount tls.existingCASecretName and set extra environment when set in valu securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -1516,6 +1534,7 @@ should not add emptyDir for data when using StatefulSet: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -1626,6 +1645,7 @@ should provision initContainer correctly when set in values: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -1718,6 +1738,7 @@ should set affinity when set in values: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -1790,6 +1811,7 @@ should set default serviceAccountName when not set in values: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -1875,6 +1897,7 @@ should set environment when extraEnv set in values: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -1947,6 +1970,7 @@ should set image and tag correctly: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -2019,6 +2043,7 @@ should set imagePullPolicy when set in values: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -2093,6 +2118,7 @@ should set nodeSelector if set in values: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -2177,6 +2203,7 @@ should set preferred affinity when more than one replica is used: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -2249,6 +2276,7 @@ should set probeTimeoutSeconds when set in values: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -2331,6 +2359,7 @@ should set required affinity when highAvailability.requireAntiAffinity is set: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -2410,6 +2439,7 @@ should set resources when set in values: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -2482,6 +2512,7 @@ should set serviceAccountName when set in values: securityContext: fsGroup: 9807 serviceAccountName: teleport-kube-agent-sa + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -2554,6 +2585,7 @@ should set storage.requests when set in values and action is an Upgrade: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -2626,6 +2658,7 @@ should set storage.storageClassName when set in values and action is an Upgrade: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 volumes: - configMap: name: RELEASE-NAME @@ -2698,6 +2731,7 @@ should set tolerations when set in values: securityContext: fsGroup: 9807 serviceAccountName: RELEASE-NAME + terminationGracePeriodSeconds: 30 tolerations: - effect: NoExecute key: dedicated diff --git a/examples/chart/teleport-kube-agent/tests/statefulset_test.yaml b/examples/chart/teleport-kube-agent/tests/statefulset_test.yaml index c346bffe3425d..5e0b2bd0d98a5 100644 --- a/examples/chart/teleport-kube-agent/tests/statefulset_test.yaml +++ b/examples/chart/teleport-kube-agent/tests/statefulset_test.yaml @@ -814,3 +814,13 @@ tests: hostnames: - "foo.remote" - "bar.remote" + - it: should set the terminationGracePeriodSeconds when specified + template: statefulset.yaml + values: + - ../.lint/stateful.yaml + set: + terminationGracePeriodSeconds: 3600 + asserts: + - equal: + path: spec.template.spec.terminationGracePeriodSeconds + value: 3600 \ No newline at end of file diff --git a/examples/chart/teleport-kube-agent/values.schema.json b/examples/chart/teleport-kube-agent/values.schema.json index e189523378733..46b600c888319 100644 --- a/examples/chart/teleport-kube-agent/values.schema.json +++ b/examples/chart/teleport-kube-agent/values.schema.json @@ -252,6 +252,11 @@ "type": "object", "default": {} }, + "terminationGracePeriodSeconds": { + "$id": "#/properties/terminationGracePeriodSeconds", + "type": "integer", + "default": 30 + }, "tls": { "$id": "#/properties/tls", "type": "object", diff --git a/examples/chart/teleport-kube-agent/values.yaml b/examples/chart/teleport-kube-agent/values.yaml index 0286db419342f..66f7e6c33db3f 100644 --- a/examples/chart/teleport-kube-agent/values.yaml +++ b/examples/chart/teleport-kube-agent/values.yaml @@ -538,6 +538,16 @@ insecureSkipProxyTLSVerify: false # ``` teleportConfig: {} +# terminationGracePeriodSeconds(integer) -- is the time the pod has to do a graceful shutdown. +# If teleport has not existed after this delay, the process gets killed. +# Teleport will wait until every connection backed by the agent is over before exiting. +# If you want to reduce the disruption of rolling out agents at the price of a slower rollout, you can increase this +# value to an hour. +# +# See the [Kubernetes Pod Lifecycle docs](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination) +# for more details. +terminationGracePeriodSeconds: 30 + # tls -- contains settings for mounting your own TLS material in the agent pod. # The agent does not expose a TLS server, so this is only used to trust CAs. tls: From ba943d2b3d13d7a51ea4069ebf4af17aa0456f91 Mon Sep 17 00:00:00 2001 From: Hugo Shaka Date: Wed, 13 Nov 2024 17:42:49 -0500 Subject: [PATCH 06/11] implement autoupdate_agent_rollout reconciler (#48241) * implement autoupdate_agent_rollout reconciler * address edoardo's feedback * address edoardo's feedback pt.2 * fixup! address edoardo's feedback * lint --- lib/autoupdate/rolloutcontroller/client.go | 46 ++ .../rolloutcontroller/client_test.go | 189 ++++++ .../rolloutcontroller/reconciler.go | 235 ++++++++ .../rolloutcontroller/reconciler_test.go | 567 ++++++++++++++++++ 4 files changed, 1037 insertions(+) create mode 100644 lib/autoupdate/rolloutcontroller/client.go create mode 100644 lib/autoupdate/rolloutcontroller/client_test.go create mode 100644 lib/autoupdate/rolloutcontroller/reconciler.go create mode 100644 lib/autoupdate/rolloutcontroller/reconciler_test.go diff --git a/lib/autoupdate/rolloutcontroller/client.go b/lib/autoupdate/rolloutcontroller/client.go new file mode 100644 index 0000000000000..4dead0f9dee19 --- /dev/null +++ b/lib/autoupdate/rolloutcontroller/client.go @@ -0,0 +1,46 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package rolloutcontroller + +import ( + "context" + + autoupdatepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1" +) + +// Client is the subset of the Teleport client RPCs the controller needs. +type Client interface { + // GetAutoUpdateConfig gets the AutoUpdateConfig singleton resource. + GetAutoUpdateConfig(ctx context.Context) (*autoupdatepb.AutoUpdateConfig, error) + + // GetAutoUpdateVersion gets the AutoUpdateVersion singleton resource. + GetAutoUpdateVersion(ctx context.Context) (*autoupdatepb.AutoUpdateVersion, error) + + // GetAutoUpdateAgentRollout gets the AutoUpdateAgentRollout singleton resource. + GetAutoUpdateAgentRollout(ctx context.Context) (*autoupdatepb.AutoUpdateAgentRollout, error) + + // CreateAutoUpdateAgentRollout creates the AutoUpdateAgentRollout singleton resource. + CreateAutoUpdateAgentRollout(ctx context.Context, rollout *autoupdatepb.AutoUpdateAgentRollout) (*autoupdatepb.AutoUpdateAgentRollout, error) + + // UpdateAutoUpdateAgentRollout updates the AutoUpdateAgentRollout singleton resource. + UpdateAutoUpdateAgentRollout(ctx context.Context, rollout *autoupdatepb.AutoUpdateAgentRollout) (*autoupdatepb.AutoUpdateAgentRollout, error) + + // DeleteAutoUpdateAgentRollout deletes the AutoUpdateAgentRollout singleton resource. + DeleteAutoUpdateAgentRollout(ctx context.Context) error +} diff --git a/lib/autoupdate/rolloutcontroller/client_test.go b/lib/autoupdate/rolloutcontroller/client_test.go new file mode 100644 index 0000000000000..ba204ffb77db3 --- /dev/null +++ b/lib/autoupdate/rolloutcontroller/client_test.go @@ -0,0 +1,189 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package rolloutcontroller + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + + "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1" +) + +// mockClient is a mock implementation if the Client interface for testing purposes. +// This is used to precisely check which calls are made by the Reconciler during tests. +// Use newMockClient to create one from stubs. Once the test is over, you must call +// mockClient.checkIfEmpty to validate all expected calls were made. +type mockClient struct { + getAutoUpdateConfig *getHandler[*autoupdate.AutoUpdateConfig] + getAutoUpdateVersion *getHandler[*autoupdate.AutoUpdateVersion] + getAutoUpdateAgentRollout *getHandler[*autoupdate.AutoUpdateAgentRollout] + createAutoUpdateAgentRollout *createUpdateHandler[*autoupdate.AutoUpdateAgentRollout] + updateAutoUpdateAgentRollout *createUpdateHandler[*autoupdate.AutoUpdateAgentRollout] + deleteAutoUpdateAgentRollout *deleteHandler +} + +func (m mockClient) GetAutoUpdateConfig(ctx context.Context) (*autoupdate.AutoUpdateConfig, error) { + return m.getAutoUpdateConfig.handle(ctx) +} + +func (m mockClient) GetAutoUpdateVersion(ctx context.Context) (*autoupdate.AutoUpdateVersion, error) { + return m.getAutoUpdateVersion.handle(ctx) +} + +func (m mockClient) GetAutoUpdateAgentRollout(ctx context.Context) (*autoupdate.AutoUpdateAgentRollout, error) { + return m.getAutoUpdateAgentRollout.handle(ctx) +} + +func (m mockClient) CreateAutoUpdateAgentRollout(ctx context.Context, rollout *autoupdate.AutoUpdateAgentRollout) (*autoupdate.AutoUpdateAgentRollout, error) { + return m.createAutoUpdateAgentRollout.handle(ctx, rollout) +} + +func (m mockClient) UpdateAutoUpdateAgentRollout(ctx context.Context, rollout *autoupdate.AutoUpdateAgentRollout) (*autoupdate.AutoUpdateAgentRollout, error) { + return m.updateAutoUpdateAgentRollout.handle(ctx, rollout) +} + +func (m mockClient) DeleteAutoUpdateAgentRollout(ctx context.Context) error { + return m.deleteAutoUpdateAgentRollout.handle(ctx) +} + +func (m mockClient) checkIfEmpty(t *testing.T) { + require.True(t, m.getAutoUpdateConfig.isEmpty(), "Get autoupdate_config mock not empty") + require.True(t, m.getAutoUpdateVersion.isEmpty(), "Get autoupdate_version mock not empty") + require.True(t, m.getAutoUpdateAgentRollout.isEmpty(), "Get autoupdate_agent_rollout mock not empty") + require.True(t, m.createAutoUpdateAgentRollout.isEmpty(), "Create autoupdate_agent_rollout mock not empty") + require.True(t, m.updateAutoUpdateAgentRollout.isEmpty(), "Update autoupdate_agent_rollout mock not empty") + require.True(t, m.deleteAutoUpdateAgentRollout.isEmpty(), "Delete autoupdate_agent_rollout mock not empty") +} + +func newMockClient(t *testing.T, stubs mockClientStubs) *mockClient { + // Fail early if there's a mismatch + require.Equal(t, len(stubs.createRolloutAnswers), len(stubs.createRolloutExpects), "invalid stubs, create validations and answers slices are not the same length") + require.Equal(t, len(stubs.updateRolloutAnswers), len(stubs.updateRolloutExpects), "invalid stubs, update validations and answers slices are not the same length") + + return &mockClient{ + getAutoUpdateConfig: &getHandler[*autoupdate.AutoUpdateConfig]{t, stubs.configAnswers}, + getAutoUpdateVersion: &getHandler[*autoupdate.AutoUpdateVersion]{t, stubs.versionAnswers}, + getAutoUpdateAgentRollout: &getHandler[*autoupdate.AutoUpdateAgentRollout]{t, stubs.rolloutAnswers}, + createAutoUpdateAgentRollout: &createUpdateHandler[*autoupdate.AutoUpdateAgentRollout]{t, stubs.createRolloutExpects, stubs.createRolloutAnswers}, + updateAutoUpdateAgentRollout: &createUpdateHandler[*autoupdate.AutoUpdateAgentRollout]{t, stubs.updateRolloutExpects, stubs.updateRolloutAnswers}, + deleteAutoUpdateAgentRollout: &deleteHandler{t, stubs.deleteRolloutAnswers}, + } +} + +type mockClientStubs struct { + configAnswers []callAnswer[*autoupdate.AutoUpdateConfig] + versionAnswers []callAnswer[*autoupdate.AutoUpdateVersion] + rolloutAnswers []callAnswer[*autoupdate.AutoUpdateAgentRollout] + createRolloutAnswers []callAnswer[*autoupdate.AutoUpdateAgentRollout] + createRolloutExpects []require.ValueAssertionFunc + updateRolloutAnswers []callAnswer[*autoupdate.AutoUpdateAgentRollout] + updateRolloutExpects []require.ValueAssertionFunc + deleteRolloutAnswers []error +} + +type callAnswer[T any] struct { + result T + err error +} + +// getHandler is used in a mock client to answer get resource requests during tests. +// It takes a list of answers and errors and will return them when invoked. +// If there are no stubs left it fails the test. +type getHandler[T proto.Message] struct { + t *testing.T + answers []callAnswer[T] +} + +func (h *getHandler[T]) handle(_ context.Context) (T, error) { + if len(h.answers) == 0 { + require.Fail(h.t, "no answers left") + } + + entry := h.answers[0] + h.answers = h.answers[1:] + + // We need to deep copy because the reconciler might do updates in place. + // We don't want the original resource to be edited as this would mess with other tests. + return proto.Clone(entry.result).(T), entry.err +} + +// isEmpty returns true only if all stubs were consumed +func (h *getHandler[T]) isEmpty() bool { + return len(h.answers) == 0 +} + +// createUpdateHandler is used in a mock client to answer create or update resource requests during tests (any request whose arity is 2). +// It first validates the input using the provided validation function, then it returns the predefined answer and error. +// If there are no stubs left it fails the test. +type createUpdateHandler[T proto.Message] struct { + t *testing.T + expect []require.ValueAssertionFunc + answers []callAnswer[T] +} + +func (h *createUpdateHandler[T]) handle(_ context.Context, object T) (T, error) { + if len(h.expect) == 0 { + require.Fail(h.t, "not expecting more calls") + } + h.expect[0](h.t, object) + h.expect = h.expect[1:] + + if len(h.answers) == 0 { + require.Fail(h.t, "no answers left") + } + + entry := h.answers[0] + h.answers = h.answers[1:] + + // We need to deep copy because the reconciler might do updates in place. + // We don't want the original resource to be edited as this would mess with other tests. + return proto.Clone(entry.result).(T), entry.err +} + +// isEmpty returns true only if all stubs were consumed +func (h *createUpdateHandler[T]) isEmpty() bool { + return len(h.answers) == 0 && len(h.expect) == 0 +} + +// deleteHandler is used in a mock client to answer delete resource requests during tests. +// It takes a list of errors and returns them when invoked. +// If there are no stubs left it fails the test. +type deleteHandler struct { + t *testing.T + answers []error +} + +func (h *deleteHandler) handle(_ context.Context) error { + if len(h.answers) == 0 { + require.Fail(h.t, "no answers left") + } + + entry := h.answers[0] + h.answers = h.answers[1:] + + return entry +} + +// isEmpty returns true only if all stubs were consumed +func (h *deleteHandler) isEmpty() bool { + return len(h.answers) == 0 +} diff --git a/lib/autoupdate/rolloutcontroller/reconciler.go b/lib/autoupdate/rolloutcontroller/reconciler.go new file mode 100644 index 0000000000000..78989c4ec4a6b --- /dev/null +++ b/lib/autoupdate/rolloutcontroller/reconciler.go @@ -0,0 +1,235 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package rolloutcontroller + +import ( + "context" + "log/slog" + "sync" + "time" + + "github.com/gravitational/trace" + + "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1" + update "github.com/gravitational/teleport/api/types/autoupdate" +) + +const ( + reconciliationTimeout = 30 * time.Second + defaultConfigMode = update.AgentsUpdateModeEnabled + defaultStrategy = update.AgentsStrategyHaltOnError + maxConflictRetry = 3 +) + +// Reconciler reconciles the AutoUpdateAgentRollout singleton based on the content of the AutoUpdateVersion and +// AutoUpdateConfig singletons. This reconciler is not based on the services.GenericReconciler because: +// - we reconcile 2 resources with one +// - both input and output are singletons, we don't need the multi resource logic nor stream/paginated APIs +type Reconciler struct { + clt Client + log *slog.Logger + + // mutex ensures we only run one reconciliation at a time + mutex sync.Mutex +} + +// Reconcile the AutoUpdateAgentRollout singleton. The reconciliation can fail because of a conflict (multiple auths +// are racing), in this case we retry the reconciliation immediately. +func (r *Reconciler) Reconcile(ctx context.Context) error { + r.mutex.Lock() + defer r.mutex.Unlock() + + ctx, cancel := context.WithTimeout(ctx, reconciliationTimeout) + defer cancel() + tries := 0 + var err error + for tries < maxConflictRetry { + tries++ + select { + case <-ctx.Done(): + return ctx.Err() + default: + err = r.tryReconcile(ctx) + switch { + case err == nil: + return nil + case trace.IsCompareFailed(err), trace.IsNotFound(err): + // The resource changed since we last saw it + // We must have raced against another auth + // Let's retry the reconciliation + r.log.DebugContext(ctx, "retrying reconciliation", "error", err) + default: + // error is non-nil and non-retryable + return trace.Wrap(err, "failed to reconcile rollout") + } + } + } + return trace.CompareFailed("compare failed, tried %d times, last error: %s", tries, err) +} + +// tryReconcile tries to reconcile the AutoUpdateAgentRollout singleton. +// This function should be nilpotent if the AutoUpdateAgentRollout is already up-to-date. +// The creation/update/deletion can fail with a trace.CompareFailedError or trace.NotFoundError +// if the resource change while we were computing it. +// The caller must handle those error and retry the reconciliation. +func (r *Reconciler) tryReconcile(ctx context.Context) error { + // get autoupdate_config + var config *autoupdate.AutoUpdateConfig + if c, err := r.clt.GetAutoUpdateConfig(ctx); err == nil { + config = c + } else if !trace.IsNotFound(err) { + return trace.Wrap(err, "getting autoupdate_config") + } + + // get autoupdate_version + var version *autoupdate.AutoUpdateVersion + if v, err := r.clt.GetAutoUpdateVersion(ctx); err == nil { + version = v + } else if !trace.IsNotFound(err) { + return trace.Wrap(err, "getting autoupdate version") + } + + // get autoupdate_agent_rollout + rolloutExists := true + existingRollout, err := r.clt.GetAutoUpdateAgentRollout(ctx) + if err != nil && !trace.IsNotFound(err) { + return trace.Wrap(err, "getting autoupdate_agent_rollout") + } + if trace.IsNotFound(err) { + // rollout doesn't exist yet, we'll need to call Create instead of Update. + rolloutExists = false + } + + // if autoupdate_version does not exist or does not contain spec.agents, we should not configure a rollout + if version.GetSpec().GetAgents() == nil { + if !rolloutExists { + // the rollout doesn't exist, nothing to do + return nil + } + // the rollout exists, we must delete it + return r.clt.DeleteAutoUpdateAgentRollout(ctx) + } + + // compute what the spec should look like + newSpec, err := r.buildRolloutSpec(config.GetSpec().GetAgents(), version.GetSpec().GetAgents()) + if err != nil { + return trace.Wrap(err, "mutating rollout") + } + + // if there are no existing rollout, we create a new one + if !rolloutExists { + rollout, err := update.NewAutoUpdateAgentRollout(newSpec) + if err != nil { + return trace.Wrap(err, "validating new rollout") + } + _, err = r.clt.CreateAutoUpdateAgentRollout(ctx, rollout) + return trace.Wrap(err, "creating rollout") + } + + // there was an existing rollout, we must figure if something changed + specChanged := existingRollout.GetSpec().GetStartVersion() != newSpec.GetStartVersion() || + existingRollout.GetSpec().GetTargetVersion() != newSpec.GetTargetVersion() || + existingRollout.GetSpec().GetAutoupdateMode() != newSpec.GetAutoupdateMode() || + existingRollout.GetSpec().GetStrategy() != newSpec.GetStrategy() || + existingRollout.GetSpec().GetSchedule() != newSpec.GetSchedule() + + // TODO: reconcile the status here when we'll add group support. + // Even if the spec does not change, we might still have to update the status: + // - sync groups with the ones from the user config + // - progress the rollout across groups + + // if nothing changed, no need to update the resource + if !specChanged { + r.log.DebugContext(ctx, "rollout unchanged") + return nil + } + + // something changed, we replace the old spec with the new one, validate and update the resource + // we don't create a new resource to keep the revision ID and + existingRollout.Spec = newSpec + err = update.ValidateAutoUpdateAgentRollout(existingRollout) + if err != nil { + return trace.Wrap(err, "validating mutated rollout") + } + _, err = r.clt.UpdateAutoUpdateAgentRollout(ctx, existingRollout) + return trace.Wrap(err, "updating rollout") +} + +func (r *Reconciler) buildRolloutSpec(config *autoupdate.AutoUpdateConfigSpecAgents, version *autoupdate.AutoUpdateVersionSpecAgents) (*autoupdate.AutoUpdateAgentRolloutSpec, error) { + // reconcile mode + mode, err := getMode(config.GetMode(), version.GetMode()) + if err != nil { + return nil, trace.Wrap(err, "computing agent update mode") + } + + strategy := config.GetStrategy() + if strategy == "" { + strategy = defaultStrategy + } + + return &autoupdate.AutoUpdateAgentRolloutSpec{ + StartVersion: version.GetStartVersion(), + TargetVersion: version.GetTargetVersion(), + Schedule: version.GetSchedule(), + AutoupdateMode: mode, + Strategy: strategy, + }, nil + +} + +// agentModeCode maps agents mode to integers. +// When config and version modes don't match, the lowest integer takes precedence. +var ( + agentModeCode = map[string]int{ + update.AgentsUpdateModeDisabled: 0, + update.AgentsUpdateModeSuspended: 1, + update.AgentsUpdateModeEnabled: 2, + } + codeToAgentMode = map[int]string{ + 0: update.AgentsUpdateModeDisabled, + 1: update.AgentsUpdateModeSuspended, + 2: update.AgentsUpdateModeEnabled, + } +) + +// getMode merges the agent modes coming from the version and config resources into a single mode. +// "disabled" takes precedence over "suspended", which takes precedence over "enabled". +func getMode(configMode, versionMode string) (string, error) { + if configMode == "" { + configMode = defaultConfigMode + } + if versionMode == "" { + return "", trace.BadParameter("version mode empty") + } + + configCode, ok := agentModeCode[configMode] + if !ok { + return "", trace.BadParameter("unsupported agent config mode: %v", configMode) + } + versionCode, ok := agentModeCode[versionMode] + if !ok { + return "", trace.BadParameter("unsupported agent version mode: %v", versionMode) + } + + // The lowest code takes precedence + if configCode <= versionCode { + return codeToAgentMode[configCode], nil + } + return codeToAgentMode[versionCode], nil +} diff --git a/lib/autoupdate/rolloutcontroller/reconciler_test.go b/lib/autoupdate/rolloutcontroller/reconciler_test.go new file mode 100644 index 0000000000000..340451d8da46d --- /dev/null +++ b/lib/autoupdate/rolloutcontroller/reconciler_test.go @@ -0,0 +1,567 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package rolloutcontroller + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/uuid" + "github.com/gravitational/trace" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/testing/protocmp" + + "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1" + update "github.com/gravitational/teleport/api/types/autoupdate" + apiutils "github.com/gravitational/teleport/api/utils" + "github.com/gravitational/teleport/lib/backend" + "github.com/gravitational/teleport/lib/utils" +) + +// rolloutEquals returns a require.ValueAssertionFunc that checks the rollout is identical. +// The comparison does not take into account the proto internal state. +func rolloutEquals(expected *autoupdate.AutoUpdateAgentRollout) require.ValueAssertionFunc { + return func(t require.TestingT, i interface{}, _ ...interface{}) { + require.IsType(t, &autoupdate.AutoUpdateAgentRollout{}, i) + actual := i.(*autoupdate.AutoUpdateAgentRollout) + require.Empty(t, cmp.Diff(expected, actual, protocmp.Transform())) + } +} + +// cancelContext wraps a require.ValueAssertionFunc so that the given context is canceled before checking the assertion. +// This is used to test how the reconciler behaves when its context is canceled. +func cancelContext(assertionFunc require.ValueAssertionFunc, cancel func()) require.ValueAssertionFunc { + return func(t require.TestingT, i interface{}, i2 ...interface{}) { + cancel() + assertionFunc(t, i, i2...) + } +} + +// withRevisionID creates a deep copy of an agent rollout and sets the revisionID in its metadata. +// This is used to test the conditional update retry logic. +func withRevisionID(original *autoupdate.AutoUpdateAgentRollout, revision string) *autoupdate.AutoUpdateAgentRollout { + revisioned := apiutils.CloneProtoMsg(original) + revisioned.Metadata.Revision = revision + return revisioned +} + +func TestGetMode(t *testing.T) { + t.Parallel() + tests := []struct { + name string + configMode string + versionMode string + expected string + checkErr require.ErrorAssertionFunc + }{ + { + name: "config and version equal", + configMode: update.AgentsUpdateModeEnabled, + versionMode: update.AgentsUpdateModeEnabled, + expected: update.AgentsUpdateModeEnabled, + checkErr: require.NoError, + }, + { + name: "config suspends, version enables", + configMode: update.AgentsUpdateModeSuspended, + versionMode: update.AgentsUpdateModeEnabled, + expected: update.AgentsUpdateModeSuspended, + checkErr: require.NoError, + }, + { + name: "config enables, version suspends", + configMode: update.AgentsUpdateModeEnabled, + versionMode: update.AgentsUpdateModeSuspended, + expected: update.AgentsUpdateModeSuspended, + checkErr: require.NoError, + }, + { + name: "config suspends, version disables", + configMode: update.AgentsUpdateModeSuspended, + versionMode: update.AgentsUpdateModeDisabled, + expected: update.AgentsUpdateModeDisabled, + checkErr: require.NoError, + }, + { + name: "version enables, no config", + configMode: "", + versionMode: update.AgentsUpdateModeEnabled, + expected: update.AgentsUpdateModeEnabled, + checkErr: require.NoError, + }, + { + name: "config enables, no version", + configMode: update.AgentsUpdateModeEnabled, + versionMode: "", + expected: "", + checkErr: require.Error, + }, + { + name: "unknown mode", + configMode: "this in not a mode", + versionMode: update.AgentsUpdateModeEnabled, + expected: "", + checkErr: require.Error, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := getMode(tt.configMode, tt.versionMode) + tt.checkErr(t, err) + require.Equal(t, tt.expected, result) + }) + } +} + +func TestTryReconcile(t *testing.T) { + t.Parallel() + log := utils.NewSlogLoggerForTests() + ctx := context.Background() + // Test setup: creating fixtures + configOK, err := update.NewAutoUpdateConfig(&autoupdate.AutoUpdateConfigSpec{ + Tools: &autoupdate.AutoUpdateConfigSpecTools{ + Mode: update.ToolsUpdateModeEnabled, + }, + Agents: &autoupdate.AutoUpdateConfigSpecAgents{ + Mode: update.AgentsUpdateModeEnabled, + Strategy: update.AgentsStrategyHaltOnError, + }, + }) + require.NoError(t, err) + + configNoAgent, err := update.NewAutoUpdateConfig(&autoupdate.AutoUpdateConfigSpec{ + Tools: &autoupdate.AutoUpdateConfigSpecTools{ + Mode: update.ToolsUpdateModeEnabled, + }, + }) + require.NoError(t, err) + + versionOK, err := update.NewAutoUpdateVersion(&autoupdate.AutoUpdateVersionSpec{ + Tools: &autoupdate.AutoUpdateVersionSpecTools{ + TargetVersion: "1.2.3", + }, + Agents: &autoupdate.AutoUpdateVersionSpecAgents{ + StartVersion: "1.2.3", + TargetVersion: "1.2.4", + Schedule: update.AgentsScheduleImmediate, + Mode: update.AgentsUpdateModeEnabled, + }, + }) + require.NoError(t, err) + + versionNoAgent, err := update.NewAutoUpdateVersion(&autoupdate.AutoUpdateVersionSpec{ + Tools: &autoupdate.AutoUpdateVersionSpecTools{ + TargetVersion: "1.2.3", + }, + }) + require.NoError(t, err) + + upToDateRollout, err := update.NewAutoUpdateAgentRollout(&autoupdate.AutoUpdateAgentRolloutSpec{ + StartVersion: "1.2.3", + TargetVersion: "1.2.4", + Schedule: update.AgentsScheduleImmediate, + AutoupdateMode: update.AgentsUpdateModeEnabled, + Strategy: update.AgentsStrategyHaltOnError, + }) + require.NoError(t, err) + + outOfDateRollout, err := update.NewAutoUpdateAgentRollout(&autoupdate.AutoUpdateAgentRolloutSpec{ + StartVersion: "1.2.2", + TargetVersion: "1.2.3", + Schedule: update.AgentsScheduleImmediate, + AutoupdateMode: update.AgentsUpdateModeEnabled, + Strategy: update.AgentsStrategyHaltOnError, + }) + require.NoError(t, err) + + tests := []struct { + name string + config *autoupdate.AutoUpdateConfig + version *autoupdate.AutoUpdateVersion + existingRollout *autoupdate.AutoUpdateAgentRollout + createExpect *autoupdate.AutoUpdateAgentRollout + updateExpect *autoupdate.AutoUpdateAgentRollout + deleteExpect bool + }{ + { + name: "config and version exist, no existing rollout", + // rollout should be created + config: configOK, + version: versionOK, + createExpect: upToDateRollout, + }, + { + name: "version exist, no existing rollout nor config", + // rollout should be created + version: versionOK, + createExpect: upToDateRollout, + }, + { + name: "version exist, no existing rollout, config exist but doesn't contain agent section", + // rollout should be created + config: configNoAgent, + version: versionOK, + createExpect: upToDateRollout, + }, + { + name: "config exist, no existing rollout nor version", + // rollout should not be created as there is no version + config: configOK, + }, + { + name: "config exist, no existing rollout, version exist but doesn't contain agent section", + // rollout should not be created as there is no version + config: configOK, + version: versionNoAgent, + }, + { + name: "no existing rollout, config, nor version", + // rollout should not be created as there is no version + }, + { + name: "existing out-of-date rollout, config and version exist", + // rollout should be updated + config: configOK, + version: versionOK, + existingRollout: outOfDateRollout, + updateExpect: upToDateRollout, + }, + { + name: "existing up-to-date rollout, config and version exist", + // rollout should not be updated as its spec is already good + config: configOK, + version: versionOK, + existingRollout: upToDateRollout, + }, + { + name: "existing rollout and config but no version", + // rollout should be deleted as there is no version + config: configOK, + existingRollout: upToDateRollout, + deleteExpect: true, + }, + { + name: "existing rollout but no config nor version", + // rollout should be deleted as there is no version + existingRollout: upToDateRollout, + deleteExpect: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + // Test setup: creating a fake client answering fixtures + var stubs mockClientStubs + + if tt.config != nil { + stubs.configAnswers = []callAnswer[*autoupdate.AutoUpdateConfig]{{tt.config, nil}} + } else { + stubs.configAnswers = []callAnswer[*autoupdate.AutoUpdateConfig]{{nil, trace.NotFound("no config")}} + } + + if tt.version != nil { + stubs.versionAnswers = []callAnswer[*autoupdate.AutoUpdateVersion]{{tt.version, nil}} + } else { + stubs.versionAnswers = []callAnswer[*autoupdate.AutoUpdateVersion]{{nil, trace.NotFound("no version")}} + } + + if tt.existingRollout != nil { + stubs.rolloutAnswers = []callAnswer[*autoupdate.AutoUpdateAgentRollout]{{tt.existingRollout, nil}} + } else { + stubs.rolloutAnswers = []callAnswer[*autoupdate.AutoUpdateAgentRollout]{{nil, trace.NotFound("no rollout")}} + } + + if tt.createExpect != nil { + stubs.createRolloutAnswers = []callAnswer[*autoupdate.AutoUpdateAgentRollout]{{tt.createExpect, nil}} + stubs.createRolloutExpects = []require.ValueAssertionFunc{rolloutEquals(tt.createExpect)} + } + + if tt.updateExpect != nil { + stubs.updateRolloutAnswers = []callAnswer[*autoupdate.AutoUpdateAgentRollout]{{tt.updateExpect, nil}} + stubs.updateRolloutExpects = []require.ValueAssertionFunc{rolloutEquals(tt.updateExpect)} + } + + if tt.deleteExpect { + stubs.deleteRolloutAnswers = []error{nil} + } + + client := newMockClient(t, stubs) + + // Test execution: Running the reconciliation + + reconciler := &Reconciler{ + clt: client, + log: log, + } + + require.NoError(t, reconciler.tryReconcile(ctx)) + // Test validation: Checking that the mock client is now empty + + client.checkIfEmpty(t) + }) + } +} + +func TestReconciler_Reconcile(t *testing.T) { + log := utils.NewSlogLoggerForTests() + ctx := context.Background() + // Test setup: creating fixtures + config, err := update.NewAutoUpdateConfig(&autoupdate.AutoUpdateConfigSpec{ + Tools: &autoupdate.AutoUpdateConfigSpecTools{ + Mode: update.ToolsUpdateModeEnabled, + }, + Agents: &autoupdate.AutoUpdateConfigSpecAgents{ + Mode: update.AgentsUpdateModeEnabled, + Strategy: update.AgentsStrategyHaltOnError, + }, + }) + require.NoError(t, err) + version, err := update.NewAutoUpdateVersion(&autoupdate.AutoUpdateVersionSpec{ + Tools: &autoupdate.AutoUpdateVersionSpecTools{ + TargetVersion: "1.2.3", + }, + Agents: &autoupdate.AutoUpdateVersionSpecAgents{ + StartVersion: "1.2.3", + TargetVersion: "1.2.4", + Schedule: update.AgentsScheduleImmediate, + Mode: update.AgentsUpdateModeEnabled, + }, + }) + require.NoError(t, err) + upToDateRollout, err := update.NewAutoUpdateAgentRollout(&autoupdate.AutoUpdateAgentRolloutSpec{ + StartVersion: "1.2.3", + TargetVersion: "1.2.4", + Schedule: update.AgentsScheduleImmediate, + AutoupdateMode: update.AgentsUpdateModeEnabled, + Strategy: update.AgentsStrategyHaltOnError, + }) + require.NoError(t, err) + + outOfDateRollout, err := update.NewAutoUpdateAgentRollout(&autoupdate.AutoUpdateAgentRolloutSpec{ + StartVersion: "1.2.2", + TargetVersion: "1.2.3", + Schedule: update.AgentsScheduleImmediate, + AutoupdateMode: update.AgentsUpdateModeEnabled, + Strategy: update.AgentsStrategyHaltOnError, + }) + require.NoError(t, err) + + // Those tests are not written in table format because the fixture setup it too complex and this would harm + // readability. + t.Run("reconciliation has nothing to do, should exit", func(t *testing.T) { + // Test setup: build mock client + stubs := mockClientStubs{ + configAnswers: []callAnswer[*autoupdate.AutoUpdateConfig]{{config, nil}}, + versionAnswers: []callAnswer[*autoupdate.AutoUpdateVersion]{{version, nil}}, + rolloutAnswers: []callAnswer[*autoupdate.AutoUpdateAgentRollout]{{upToDateRollout, nil}}, + } + + client := newMockClient(t, stubs) + reconciler := &Reconciler{ + clt: client, + log: log, + } + + // Test execution: run the reconciliation loop + require.NoError(t, reconciler.Reconcile(ctx)) + + // Test validation: check that all the expected calls were received + client.checkIfEmpty(t) + }) + + t.Run("reconciliation succeeds on first try, should exit", func(t *testing.T) { + stubs := mockClientStubs{ + configAnswers: []callAnswer[*autoupdate.AutoUpdateConfig]{{config, nil}}, + versionAnswers: []callAnswer[*autoupdate.AutoUpdateVersion]{{version, nil}}, + rolloutAnswers: []callAnswer[*autoupdate.AutoUpdateAgentRollout]{{outOfDateRollout, nil}}, + updateRolloutExpects: []require.ValueAssertionFunc{rolloutEquals(upToDateRollout)}, + updateRolloutAnswers: []callAnswer[*autoupdate.AutoUpdateAgentRollout]{{upToDateRollout, nil}}, + } + + client := newMockClient(t, stubs) + reconciler := &Reconciler{ + clt: client, + log: log, + } + + // Test execution: run the reconciliation loop + require.NoError(t, reconciler.Reconcile(ctx)) + + // Test validation: check that all the expected calls were received + client.checkIfEmpty(t) + }) + + t.Run("reconciliation faces conflict on first try, should retry and see that there's nothing left to do", func(t *testing.T) { + stubs := mockClientStubs{ + // because of the retry, we expect 2 GETs on every resource + configAnswers: []callAnswer[*autoupdate.AutoUpdateConfig]{{config, nil}, {config, nil}}, + versionAnswers: []callAnswer[*autoupdate.AutoUpdateVersion]{{version, nil}, {version, nil}}, + rolloutAnswers: []callAnswer[*autoupdate.AutoUpdateAgentRollout]{{outOfDateRollout, nil}, {upToDateRollout, nil}}, + // Single update expected, because there's nothing to do after the retry + updateRolloutExpects: []require.ValueAssertionFunc{rolloutEquals(upToDateRollout)}, + updateRolloutAnswers: []callAnswer[*autoupdate.AutoUpdateAgentRollout]{{nil, trace.Wrap(backend.ErrIncorrectRevision)}}, + } + + client := newMockClient(t, stubs) + reconciler := &Reconciler{ + clt: client, + log: log, + } + + // Test execution: run the reconciliation loop + require.NoError(t, reconciler.Reconcile(ctx)) + + // Test validation: check that all the expected calls were received + client.checkIfEmpty(t) + }) + + t.Run("reconciliation faces conflict on first try, should retry and update a second time", func(t *testing.T) { + rev1, err := uuid.NewUUID() + require.NoError(t, err) + rev2, err := uuid.NewUUID() + require.NoError(t, err) + rev3, err := uuid.NewUUID() + require.NoError(t, err) + + stubs := mockClientStubs{ + // because of the retry, we expect 2 GETs on every resource + configAnswers: []callAnswer[*autoupdate.AutoUpdateConfig]{{config, nil}, {config, nil}}, + versionAnswers: []callAnswer[*autoupdate.AutoUpdateVersion]{{version, nil}, {version, nil}}, + rolloutAnswers: []callAnswer[*autoupdate.AutoUpdateAgentRollout]{ + {withRevisionID(outOfDateRollout, rev1.String()), nil}, + {withRevisionID(outOfDateRollout, rev2.String()), nil}}, + // Two updates expected, one with the old revision, then a second one with the new + updateRolloutExpects: []require.ValueAssertionFunc{ + rolloutEquals(withRevisionID(upToDateRollout, rev1.String())), + rolloutEquals(withRevisionID(upToDateRollout, rev2.String())), + }, + // We mimic a race and reject the first update because of the outdated revision + updateRolloutAnswers: []callAnswer[*autoupdate.AutoUpdateAgentRollout]{ + {nil, trace.Wrap(backend.ErrIncorrectRevision)}, + {withRevisionID(upToDateRollout, rev3.String()), nil}, + }, + } + + client := newMockClient(t, stubs) + reconciler := &Reconciler{ + clt: client, + log: log, + } + + // Test execution: run the reconciliation loop + require.NoError(t, reconciler.Reconcile(ctx)) + + // Test validation: check that all the expected calls were received + client.checkIfEmpty(t) + }) + + t.Run("reconciliation faces missing rollout on first try, should retry and create the rollout", func(t *testing.T) { + stubs := mockClientStubs{ + // because of the retry, we expect 2 GETs on every resource + configAnswers: []callAnswer[*autoupdate.AutoUpdateConfig]{{config, nil}, {config, nil}}, + versionAnswers: []callAnswer[*autoupdate.AutoUpdateVersion]{{version, nil}, {version, nil}}, + rolloutAnswers: []callAnswer[*autoupdate.AutoUpdateAgentRollout]{ + {outOfDateRollout, nil}, + {nil, trace.NotFound("no rollout")}}, + // One update expected on the first try, the second try should create + updateRolloutExpects: []require.ValueAssertionFunc{ + rolloutEquals(upToDateRollout), + }, + // We mimic the fact the rollout got deleted in the meantime + updateRolloutAnswers: []callAnswer[*autoupdate.AutoUpdateAgentRollout]{ + {nil, trace.NotFound("no rollout")}, + }, + // One create expected on the second try + createRolloutExpects: []require.ValueAssertionFunc{ + rolloutEquals(upToDateRollout), + }, + createRolloutAnswers: []callAnswer[*autoupdate.AutoUpdateAgentRollout]{ + {upToDateRollout, nil}, + }, + } + + client := newMockClient(t, stubs) + reconciler := &Reconciler{ + clt: client, + log: log, + } + + // Test execution: run the reconciliation loop + require.NoError(t, reconciler.Reconcile(ctx)) + + // Test validation: check that all the expected calls were received + client.checkIfEmpty(t) + }) + + t.Run("reconciliation meets a hard unexpected failure on first try, should exit in error", func(t *testing.T) { + stubs := mockClientStubs{ + configAnswers: []callAnswer[*autoupdate.AutoUpdateConfig]{{config, nil}}, + versionAnswers: []callAnswer[*autoupdate.AutoUpdateVersion]{{version, nil}}, + rolloutAnswers: []callAnswer[*autoupdate.AutoUpdateAgentRollout]{{outOfDateRollout, nil}}, + updateRolloutExpects: []require.ValueAssertionFunc{rolloutEquals(upToDateRollout)}, + updateRolloutAnswers: []callAnswer[*autoupdate.AutoUpdateAgentRollout]{ + {nil, trace.ConnectionProblem(trace.Errorf("io/timeout"), "the DB fell on the floor")}, + }, + } + + client := newMockClient(t, stubs) + reconciler := &Reconciler{ + clt: client, + log: log, + } + + // Test execution: run the reconciliation loop + require.ErrorContains(t, reconciler.Reconcile(ctx), "the DB fell on the floor") + + // Test validation: check that all the expected calls were received + client.checkIfEmpty(t) + }) + + t.Run("reconciliation faces conflict on first try, should retry but context is expired so it bails out", func(t *testing.T) { + cancelableCtx, cancel := context.WithCancel(ctx) + // just in case + t.Cleanup(cancel) + + stubs := mockClientStubs{ + // we expect a single GET because the context expires before the second retry + configAnswers: []callAnswer[*autoupdate.AutoUpdateConfig]{{config, nil}}, + versionAnswers: []callAnswer[*autoupdate.AutoUpdateVersion]{{version, nil}}, + rolloutAnswers: []callAnswer[*autoupdate.AutoUpdateAgentRollout]{{outOfDateRollout, nil}}, + // Single update expected, because there's nothing to do after the retry. + // We wrap the update validation function into a context canceler, so the context is done after the first update + updateRolloutExpects: []require.ValueAssertionFunc{cancelContext(rolloutEquals(upToDateRollout), cancel)}, + // return a retryable error + updateRolloutAnswers: []callAnswer[*autoupdate.AutoUpdateAgentRollout]{{nil, trace.Wrap(backend.ErrIncorrectRevision)}}, + } + + client := newMockClient(t, stubs) + reconciler := &Reconciler{ + clt: client, + log: log, + } + + // Test execution: run the reconciliation loop + require.ErrorContains(t, reconciler.Reconcile(cancelableCtx), "canceled") + + // Test validation: check that all the expected calls were received + client.checkIfEmpty(t) + }) +} From 5b74d41ee484c3daaa4afa57a99882ac63568d7f Mon Sep 17 00:00:00 2001 From: Lisa Kim Date: Wed, 13 Nov 2024 19:08:54 -0800 Subject: [PATCH 07/11] Web: add a tooltip summary for aws oidc configure step (#46934) --- .../Integrations/Enroll/AwsOidc/AwsOidc.tsx | 9 +- .../AwsOidc/ConfigureAwsOidcSummary.tsx | 87 +++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 web/packages/teleport/src/Integrations/Enroll/AwsOidc/ConfigureAwsOidcSummary.tsx diff --git a/web/packages/teleport/src/Integrations/Enroll/AwsOidc/AwsOidc.tsx b/web/packages/teleport/src/Integrations/Enroll/AwsOidc/AwsOidc.tsx index a1c4a62b18512..88993d48efcac 100644 --- a/web/packages/teleport/src/Integrations/Enroll/AwsOidc/AwsOidc.tsx +++ b/web/packages/teleport/src/Integrations/Enroll/AwsOidc/AwsOidc.tsx @@ -37,6 +37,7 @@ import { AwsOidcPolicyPreset } from 'teleport/services/integrations'; import { FinishDialog } from './FinishDialog'; import { useAwsOidcIntegration } from './useAwsOidcIntegration'; +import { ConfigureAwsOidcSummary } from './ConfigureAwsOidcSummary'; export function AwsOidc() { const { @@ -161,7 +162,13 @@ export function AwsOidc() { {scriptUrl && ( <> - Step 2 + + Step 2 + + diff --git a/web/packages/teleport/src/Integrations/Enroll/AwsOidc/ConfigureAwsOidcSummary.tsx b/web/packages/teleport/src/Integrations/Enroll/AwsOidc/ConfigureAwsOidcSummary.tsx new file mode 100644 index 0000000000000..aecd67c00d114 --- /dev/null +++ b/web/packages/teleport/src/Integrations/Enroll/AwsOidc/ConfigureAwsOidcSummary.tsx @@ -0,0 +1,87 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import React from 'react'; +import styled from 'styled-components'; +import { Flex, Box, H3, Text } from 'design'; +import TextEditor from 'shared/components/TextEditor'; +import { ToolTipInfo } from 'shared/components/ToolTip'; + +import useStickyClusterId from 'teleport/useStickyClusterId'; + +export function ConfigureAwsOidcSummary({ + roleName, + integrationName, +}: { + roleName: string; + integrationName: string; +}) { + const { clusterId } = useStickyClusterId(); + + const json = `{ + "name": ${roleName}, + "description": "Used by Teleport to provide access to AWS resources.", + "trust_policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "sts:AssumeRoleWithWebIdentity", + "Principal": { + "Federated": "":oidc-provider/${roleName}", + }, + "Condition": { + "StringEquals": { + "${clusterId}:aud": "discover.teleport", + } + } + } + ] + }, + "tags": { + "teleport.dev/cluster": "${clusterId}", + "teleport.dev/integration": "${integrationName}", + "teleport.dev/origin": "integration_awsoidc" + } +}`; + + return ( + +

Running the command in AWS CloudShell does the following:

+ 1. Configures an AWS IAM OIDC Identity Provider (IdP) + + 2. Configures an IAM role named "{roleName}" to trust the IdP: + + + + + + +
+ ); +} + +const EditorWrapper = styled(Flex)` + height: 300px; + margin-top: ${p => p.theme.space[3]}px; + width: 700px; +`; From 083644f6aeedd36968d2db5a902ff4d1d0081168 Mon Sep 17 00:00:00 2001 From: Tiago Silva Date: Thu, 14 Nov 2024 11:44:33 +0000 Subject: [PATCH 08/11] [entraid] Add docs to setup integration for air gapped clusters (#48571) * [entraid] Add docs to setup integration for air gapped clusters This PR adds docs for Teleport Entra Id integration for air gapped clusters where internet access to their proxies isn't available. This guide also adds a manual step for users that do not want Teleport to automatically setup Azure Entra ID Applications. Signed-off-by: Tiago Silva * fix spell issues * Update docs/pages/admin-guides/teleport-policy/integrations/entra-id.mdx Co-authored-by: Roman Tkachenko * Apply suggestions from code review Co-authored-by: Roman Tkachenko * handle code review comments Signed-off-by: Tiago Silva * handle code review comments --------- Signed-off-by: Tiago Silva Co-authored-by: Roman Tkachenko --- docs/cspell.json | 1 + .../teleport-policy/integrations/entra-id.mdx | 448 +++++++++++++++++- 2 files changed, 447 insertions(+), 2 deletions(-) diff --git a/docs/cspell.json b/docs/cspell.json index 6628e917a3909..e5a4ada8bdd9b 100644 --- a/docs/cspell.json +++ b/docs/cspell.json @@ -59,6 +59,7 @@ "Elastcsearch", "Elasticvue", "Entra", + "entraid", "Exadata", "Exfiltrate", "Exrch", diff --git a/docs/pages/admin-guides/teleport-policy/integrations/entra-id.mdx b/docs/pages/admin-guides/teleport-policy/integrations/entra-id.mdx index da9b9e7feff9b..dd6d30a6c1243 100644 --- a/docs/pages/admin-guides/teleport-policy/integrations/entra-id.mdx +++ b/docs/pages/admin-guides/teleport-policy/integrations/entra-id.mdx @@ -42,11 +42,67 @@ Check the [Teleport Policy page](../teleport-policy.mdx) for details on how to set up Access Graph. - The node running the Access Graph service must be reachable from the Teleport Auth Service. - Your user must have privileged administrator permissions in the Azure account +- For OIDC setup, the Teleport cluster must be publicly accessible from the internet. +- For air gapped clusters, `tctl` must be v16.4.7 or later. To verify that Access Graph is set up correctly for your cluster, sign in to the Teleport Web UI and navigate to the Management tab. If enabled, the Access Graph menu item will appear in the Permission Management section. -## Step 1/3. Start Integration onboarding +## Step 1/3. Choose a setup method + +To begin onboarding, select your preferred setup method. Teleport offers various methods based on your cluster +configuration and user requirements. + +### Automatic setup with Teleport as an OIDC Provider for Entra ID + + +This method is recommended and is required if you are a Teleport Enterprise (Cloud) customer. + + +This method is suitable for Teleport clusters that are publicly accessible and lack Azure credentials on Auth +Service nodes or pods. + +In this setup, Teleport is configured as an OpenID Connect (OIDC) identity provider, establishing a trusted +connection with an Entra ID application created during setup. This trust allows Teleport to authenticate using +the Entra ID application, accessing permissions tied to it without requiring additional credentials or managed +identities. + +**Requirements:** +- Direct bidirectional connectivity between Teleport and Azure is necessary for Azure to validate the OIDC +tokens issued by Teleport. + +### Automatic setup with system credentials for Entra ID authentication + +Designed for air-gapped Teleport clusters that are not publicly accessible, this setup accommodates environments +where Azure cannot validate OIDC tokens issued by Teleport. + +Instead, Teleport relies on Azure credentials available on the VMs where Teleport Auth Service is running. +These credentials must have the following Entra ID permissions: + +- `Application.Read.All` +- `Directory.Read.All` +- `Policy.Read.All` + +**Requirements:** +- Unidirectional connectivity from Teleport to Azure infrastructure. + +### Manual setup + +This setup describes how to manually configure Entra ID integration without relying on automated scripts +to setup Entra ID Application. + +This guide covers the +[**Automatic Setup with Teleport as OIDC Provider for Entra ID**](./entra-id.mdx#automatic-setup-with-teleport-as-an-oidc-provider-for-entra-id) +and [**Automatic Setup with System Credentials**](./entra-id.mdx#automatic-setup-with-system-credentials-for-entra-id-authentication) +setup but has a limitation of not being possible to enable the [Teleport Policy](../teleport-policy.mdx) integration. + +## Step 2/3. Configure the Entra ID integration + + + + + +### Start integration onboarding To start the onboarding process, access the Teleport Web UI, navigate to the "Access Management" tab, and choose "Enroll New Integration", then pick "Microsoft Entra ID". @@ -59,7 +115,7 @@ In the onboarding wizard, choose a Teleport user that will be assigned as the de ![First step of the Entra ID integration onboarding](../../../../img/access-graph/entra-id/integration-wizard-step-1.png) -## Step 2/3. Grant permissions in Azure and finish onboarding +### Grant permissions in Azure and finish onboarding The wizard will now provide you with a script that will set up the necessary permissions in Azure. @@ -90,6 +146,394 @@ Back in the Teleport Web UI, fill out the required data and click "Finish". ![Second step of the Entra ID integration onboarding with required fields filled in](../../../../img/access-graph/entra-id/integration-wizard-step-2-filled.png) + + + + +### Assign permissions to the Azure identity of your Auth Service VMs + +To set up the Azure Identity with the necessary permissions: + +- `Application.Read.All` +- `Directory.Read.All` +- `Policy.Read.All` + +Go to your Azure Dashboard, find the identities linked to your Teleport Auth Service VMs, +and copy the `Object (principal) ID`. Paste this value into ``. + +After obtaining the Principal ID, open the [Azure Cloud Shell](https://portal.azure.com/#cloudshell/) +in PowerShell mode and run the following script to assign the required permissions to ``. + +
+ +```powershell + +# Connect to Microsoft Graph with the required scopes for directory and app role assignment permissions. +Connect-MgGraph -Scopes 'Directory.ReadWrite.All', 'AppRoleAssignment.ReadWrite.All' + +# Retrieve the managed identity's service principal object using its unique principal ID (UUID). +$managedIdentity = Get-MgServicePrincipal -ServicePrincipalId '' + +# Set the Microsoft Graph enterprise application object. +# This is a service principal object representing Microsoft Graph in Azure AD with a specific app ID. +$graphSPN = Get-MgServicePrincipal -Filter "AppId eq '00000003-0000-0000-c000-000000000000'" + +# Define the permission scopes that we want to assign to the managed identity. +# These are Microsoft Graph API permissions required by the managed identity. +$permissions = @( + "Application.Read.All" # Permission to read applications in the directory + "Directory.Read.All" # Permission to read directory data + "Policy.Read.All" # Permission to read policies within the directory +) + +# Filter and find the app roles in the Microsoft Graph service principal that match the defined permissions. +# Only include roles where "AllowedMemberTypes" includes "Application" (suitable for managed identities). +$appRoles = $graphSPN.AppRoles | + Where-Object Value -in $permissions | + Where-Object AllowedMemberTypes -contains "Application" + +# Iterate over each app role to assign it to the managed identity. +foreach ($appRole in $appRoles) { + # Define the parameters for the role assignment, including the managed identity's principal ID, + # the Microsoft Graph service principal's resource ID, and the specific app role ID. + $bodyParam = @{ + PrincipalId = $managedIdentity.Id # The ID of the managed identity (service principal) + ResourceId = $graphSPN.Id # The ID of the Microsoft Graph service principal + AppRoleId = $appRole.Id # The ID of the app role being assigned + } + + # Create a new app role assignment for the managed identity, granting it the specified permissions. + New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $managedIdentity.Id -BodyParameter $bodyParam +} + +``` + +
+ +Your identity principal `` now has the necessary permissions to list Applications, +Directories, and Policies. + + +### Set up Entra ID and Teleport resources + +The Teleport `tctl` command provides an interactive guide to set up and configure Entra ID integration for air-gapped clusters. + +To use it, ensure you have `tctl` version v16.4.7 or later and select a default list of Access List owners. +These specified Teleport users will become the owners of Access Lists imported by the Entra ID integration. +`` must be an existing Teleport user. +If you prefer multiple Access List owners, repeat the flag with each user, e.g., `--default-owner=owner1 --default-owner=owner2`. + +You'll also need to provide the Teleport Auth Service address as ``. +For clusters running in multiplex mode, this address will be the same as your proxy address. + +If your Teleport license does not include [Teleport Policy](../teleport-policy.mdx), include the `--no-access-graph` flag. + +```code +# Disable Access Graph integration if your license supports Teleport Policy with --no-access-graph flag. +$ tctl plugins install entraid \ + --default-owner= \ + --default-owner=someOtherOwner@teleport.sh \ + --use-system-credentials \ + --auth-server +``` + +Follow the detailed instructions provided by the `tctl plugins install entraid` guide to install and configure the Entra ID plugin. +This guide will walk you through each step required to enable Entra ID integration within your Teleport environment. +Be sure to follow each step in the `tctl plugins install entraid` guide closely to complete the installation and configuration. + +
+ + + +### Assign permissions to the Azure identity of your Auth Service VMs + +This step configures the Azure Identity on your Auth Service machine with the required Entra ID permissions. + + +Follow this step only if you want to use system-available credentials to authenticate Teleport with Entra ID. +If you intend to use Teleport as an OIDC provider for Entra ID, you can skip this step. + + + +- `Application.Read.All` +- `Directory.Read.All` +- `Policy.Read.All` + +Go to your Azure Dashboard, find the identities linked to your Teleport Auth Service VMs, +and copy the `Object (principal) ID`. Paste this value into ``. + +After obtaining the Principal ID, open the [Azure Cloud Shell](https://portal.azure.com/#cloudshell/) +in PowerShell mode and run the following script to assign the required permissions to ``. + +
+ +```powershell + +# Connect to Microsoft Graph with the required scopes for directory and app role assignment permissions. +Connect-MgGraph -Scopes 'Directory.ReadWrite.All', 'AppRoleAssignment.ReadWrite.All' + +# Retrieve the managed identity's service principal object using its unique principal ID (UUID). +$managedIdentity = Get-MgServicePrincipal -ServicePrincipalId '' + +# Set the Microsoft Graph enterprise application object. +# This is a service principal object representing Microsoft Graph in Azure AD with a specific app ID. +$graphSPN = Get-MgServicePrincipal -Filter "AppId eq '00000003-0000-0000-c000-000000000000'" + +# Define the permission scopes that we want to assign to the managed identity. +# These are Microsoft Graph API permissions required by the managed identity. +$permissions = @( + "Application.Read.All" # Permission to read applications in the directory + "Directory.Read.All" # Permission to read directory data + "Policy.Read.All" # Permission to read policies within the directory +) + +# Filter and find the app roles in the Microsoft Graph service principal that match the defined permissions. +# Only include roles where "AllowedMemberTypes" includes "Application" (suitable for managed identities). +$appRoles = $graphSPN.AppRoles | + Where-Object Value -in $permissions | + Where-Object AllowedMemberTypes -contains "Application" + +# Iterate over each app role to assign it to the managed identity. +foreach ($appRole in $appRoles) { + # Define the parameters for the role assignment, including the managed identity's principal ID, + # the Microsoft Graph service principal's resource ID, and the specific app role ID. + $bodyParam = @{ + PrincipalId = $managedIdentity.Id # The ID of the managed identity (service principal) + ResourceId = $graphSPN.Id # The ID of the Microsoft Graph service principal + AppRoleId = $appRole.Id # The ID of the app role being assigned + } + + # Create a new app role assignment for the managed identity, granting it the specified permissions. + New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $managedIdentity.Id -BodyParameter $bodyParam +} + +``` + +
+ +Your identity principal `` now has the necessary permissions to list Applications, +Directories, and Policies. + + +### Set up an Entra ID application + +In this step, you will manually configure an Entra ID Enterprise Application to be used by the Teleport Auth Connector. + +We provide a PowerShell script that creates the specified application, assigns the token signing request, and sets up the necessary SAML parameters. + +To proceed, you need to define the following parameters: + +- ``: The Entra ID Application name, typically set to `Teleport your.cluster.address`. +- ``: Your Teleport Proxy address. +- ``: The Teleport Auth Connector name, usually set to `entra-id`. + +Once these parameters are defined, open the [Azure Cloud Shell](https://portal.azure.com/#cloudshell/) in +PowerShell mode, or use the session created in the previous step. + +
+ +```powershell +# Connect to Microsoft Graph with required scopes for application creation and app role assignment permissions. +Connect-MgGraph -Scopes "Application.ReadWrite.All", "AppRoleAssignment.ReadWrite.All" + +# Import the Microsoft Graph module for managing applications. +Import-Module Microsoft.Graph.Applications + +# Define application parameters, including the display name. +$params = @{ + displayName = '' # Set the display name of the new application. +} + +# Set the SAML application template ID. +# This ID corresponds to a non-gallery SAML application template. +$applicationTemplateId = "8adf8e6e-67b2-4cf2-a259-e3dc5476c621" + +# Instantiate the application template to create a new application and its service principal. +$app = Invoke-MgInstantiateApplicationTemplate -ApplicationTemplateId $applicationTemplateId -BodyParameter $params + +# Extract the Application ID, Object ID, and Service Principal ID of the newly created application. +$appId = $app.Application.AppId # The unique identifier for the application (client ID). +$objectId = $app.Application.Id # The unique object ID for the application in Azure AD. +$servicePrincipal = $app.ServicePrincipal.Id # The unique object ID for the service principal. + +# Define parameters for the token signing certificate used for SAML. +$principalTokenSigningCertificateParams = @{ + displayName = "CN=azure-sso" # Common Name (CN) for the SAML token signing certificate. +} + +# Add a token signing certificate to the service principal, which is required for SAML authentication. +$cert = Add-MgServicePrincipalTokenSigningCertificate -ServicePrincipalId $servicePrincipal -BodyParameter $principalTokenSigningCertificateParams + +# Extract the thumbprint of the certificate, which will be used to configure SAML. +$thumbprint = $cert.Thumbprint + +# Set additional SAML-specific properties for the service principal. +$updateServicePrincipalParams = @{ + preferredSingleSignOnMode = "saml" # Set SAML as the single sign-on mode. + preferredTokenSigningKeyThumbprint = $thumbprint # Use the thumbprint of the added certificate for token signing. + appRoleAssignmentRequired = $false # Allow app access without explicit app role assignments. +} + +# Update the service principal with the SAML configuration. +Update-MgServicePrincipal -ServicePrincipalId $servicePrincipal -BodyParameter $updateServicePrincipalParams + +# Define the URL for the proxy (Teleport Auth Service address). +# This URL will be used as the Redirect URI and Identifier URI. +$proxyURL = 'https://'.TrimEnd("/").TrimEnd(":443") # Remove the default 443 port for standard formatting. +$acsURL = $proxyURL+'/v1/webapi/saml/acs/' + +# Define web properties, including the redirect URI for SAML authentication. +$web = @{ + redirectUris = @($acsURL) # Set the application's redirect URI. +} + +# Update the application with the web properties and identifier URI. +# This enables SAML-based authentication and includes security group claims. +Update-MgApplication -ApplicationId $objectId -Web $web -IdentifierUris @($acsURL) +# Define optional claims for the application to include group membership claims. +$optionalClaims = [Microsoft.Graph.PowerShell.Models.MicrosoftGraphOptionalClaims]::DeserializeFromDictionary(@{ + AccessToken = @( + @{ Name = 'groups' } + ) + IdToken = @( + @{ Name = 'groups' } + ) + Saml2Token = @( + @{ Name = 'groups' } + ) +}) + +Update-MgApplication -ApplicationId $objectId -GroupMembershipClaims "SecurityGroup" -OptionalClaims $optionalClaims + + +# Retrieve the tenant ID for display purposes. +$tenant = Get-AzTenant + +# Output the Application ID, Tenant ID, and additional information for reference. +Write-Output "-------------------------------------------------------" "Copy and paste the following details:" "Application ID (Client ID): $appId" "Tenant ID: $tenant" "-------------------------------------------------------" + +``` + +
+ +If your cluster is publicly accessible from the internet and you prefer or need to use OIDC rather +than Auth Service system credentials, you can configure Teleport as an OIDC provider for the Entra +ID application. If you have already assigned the necessary permissions to your Auth Service's Azure +Identity, you may skip the following section. + +To configure Federated credentials for your application, run the following script in the same +Azure Cloud Shell terminal used previously. + +
+ +```powershell + +# Define the subject for the federated identity credential. This is a constant defined in Teleport. +$subject = "teleport-azure" + +# Define the accepted audiences for the credential. It's a constant value. +$audiences = @("api://AzureADTokenExchange") + +# Set the issuer to the Teleport cluster proxy URL. +$issuer = $proxyURL + +# Define a unique name for the federated identity credential. This name is used for identification within the application. +$name = "teleport-oidc" + +# Create a new federated identity credential for the application in Microsoft Graph. +$credential = New-MgApplicationFederatedIdentityCredential -ApplicationId $objectId -Subject $subject -Audiences $audiences -Issuer $issuer -Name $name + + +# Configure the required permissions for the application. + +# Retrieve the managed identity's service principal object using its unique principal ID (UUID). +$managedIdentity = Get-MgServicePrincipal -ServicePrincipalId $servicePrincipal + + +# Set the Microsoft Graph enterprise application object. +# This is a service principal object representing Microsoft Graph in Azure AD with a specific app ID. +$graphSPN = Get-MgServicePrincipal -Filter "AppId eq '00000003-0000-0000-c000-000000000000'" + +# Define the permission scopes that we want to assign to the managed identity. +# These are Microsoft Graph API permissions required by the managed identity. +$permissions = @( + "Application.Read.All" # Permission to read applications in the directory + "Directory.Read.All" # Permission to read directory data + "Policy.Read.All" # Permission to read policies within the directory +) + +# Filter and find the app roles in the Microsoft Graph service principal that match the defined permissions. +# Only include roles where "AllowedMemberTypes" includes "Application" (suitable for managed identities). +$appRoles = $graphSPN.AppRoles | + Where-Object Value -in $permissions | + Where-Object AllowedMemberTypes -contains "Application" + +# Iterate over each app role to assign it to the managed identity. +foreach ($appRole in $appRoles) { + # Define the parameters for the role assignment, including the managed identity's principal ID, + # the Microsoft Graph service principal's resource ID, and the specific app role ID. + $bodyParam = @{ + PrincipalId = $managedIdentity.Id # The ID of the managed identity (service principal) + ResourceId = $graphSPN.Id # The ID of the Microsoft Graph service principal + AppRoleId = $appRole.Id # The ID of the app role being assigned + } + + # Create a new app role assignment for the managed identity, granting it the specified permissions. + New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $managedIdentity.Id -BodyParameter $bodyParam +} + +``` + +
+ +### Set up Teleport resources + +The Teleport `tctl` command provides an interactive guide to set up and configure Entra ID integration for air-gapped clusters. + +To use it, ensure you have `tctl` version v16.4.7 or later and select a default list of Access List owners. +These specified Teleport users will become the owners of Access Lists imported by the Entra ID integration. +`` must be an existing Teleport user. +If you prefer multiple Access List owners, repeat the flag with each user, e.g., `--default-owner=owner1 --default-owner=owner2`. + +You'll also need to provide the Teleport Auth Service address as ``. +For clusters running in multiplex mode, this address will be the same as your proxy address. + +If you chose to use Teleport as the OIDC provider for Entra ID in the previous step, remove the `--use-system-credentials` +flag from the command below. + + +Currently, when using manual mode, it is not possible to operate without the `--no-access-graph` flag. + + +```code +# enable Access Graph integration if your license supports Teleport Policy. +$ tctl plugins install entraid \ + --default-owner= \ + --default-owner=someOtherOwner@teleport.sh \ + --auth-connector-name="" \ + --use-system-credentials \ + --no-access-graph \ + --manual-setup \ + --auth-server + +``` + +Follow the detailed instructions provided by the `tctl plugins install entraid` guide to install and configure the Entra ID plugin. +
+
+ ## Step 3/3. Analyze Entra ID directory in Teleport Access Graph Shortly after the integration onboarding is finished, From 063403796683e49650d28365a29d6131a4d4faf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Smoli=C5=84ski?= Date: Thu, 14 Nov 2024 12:56:49 +0100 Subject: [PATCH 09/11] AWSOIDC integration: Align CreateAWSConfigForIntegration (#48812) --- .../awsoidc/credprovider/credentialscache.go | 14 +- .../credprovider/credentialscache_test.go | 3 + .../integration_config_provider.go | 30 ++- .../integration_config_provider_test.go | 187 ++++++++++++++++++ 4 files changed, 229 insertions(+), 5 deletions(-) create mode 100644 lib/integrations/awsoidc/credprovider/integration_config_provider_test.go diff --git a/lib/integrations/awsoidc/credprovider/credentialscache.go b/lib/integrations/awsoidc/credprovider/credentialscache.go index bf333b657dd2d..2711d0126b2ce 100644 --- a/lib/integrations/awsoidc/credprovider/credentialscache.go +++ b/lib/integrations/awsoidc/credprovider/credentialscache.go @@ -150,13 +150,21 @@ func (cc *CredentialsCache) SetGenerateOIDCTokenFn(fn GenerateOIDCTokenFn) { // credentials, or an error if no credentials have been generated yet or the // last generated credentials have expired. func (cc *CredentialsCache) Retrieve(ctx context.Context) (aws.Credentials, error) { + select { + case <-cc.gotFirstCredsOrErr: + case <-ctx.Done(): + return aws.Credentials{}, ctx.Err() + } + creds, err := cc.retrieve(ctx) + return creds, trace.Wrap(err) +} + +func (cc *CredentialsCache) retrieve(ctx context.Context) (aws.Credentials, error) { cc.credsOrErrMu.RLock() defer cc.credsOrErrMu.RUnlock() - if cc.credsOrErr.err != nil { cc.log.WarnContext(ctx, "Returning error to AWS client", errorValue(cc.credsOrErr.err)) } - return cc.credsOrErr.creds, cc.credsOrErr.err } @@ -185,7 +193,7 @@ func (cc *CredentialsCache) Run(ctx context.Context) { } func (cc *CredentialsCache) refreshIfNeeded(ctx context.Context) { - credsFromCache, err := cc.Retrieve(ctx) + credsFromCache, err := cc.retrieve(ctx) if err == nil && credsFromCache.HasKeys() && cc.clock.Now().Add(refreshBeforeExpirationPeriod).Before(credsFromCache.Expires) { diff --git a/lib/integrations/awsoidc/credprovider/credentialscache_test.go b/lib/integrations/awsoidc/credprovider/credentialscache_test.go index 169c99e626a7c..6384bed0b8db0 100644 --- a/lib/integrations/awsoidc/credprovider/credentialscache_test.go +++ b/lib/integrations/awsoidc/credprovider/credentialscache_test.go @@ -20,6 +20,7 @@ import ( "context" "errors" "sync" + "sync/atomic" "testing" "time" @@ -40,6 +41,7 @@ type fakeSTSClient struct { clock clockwork.Clock err error sync.Mutex + called int32 } func (f *fakeSTSClient) setError(err error) { @@ -55,6 +57,7 @@ func (f *fakeSTSClient) getError() error { } func (f *fakeSTSClient) AssumeRoleWithWebIdentity(ctx context.Context, params *sts.AssumeRoleWithWebIdentityInput, optFns ...func(*sts.Options)) (*sts.AssumeRoleWithWebIdentityOutput, error) { + atomic.AddInt32(&f.called, 1) if err := f.getError(); err != nil { return nil, err } diff --git a/lib/integrations/awsoidc/credprovider/integration_config_provider.go b/lib/integrations/awsoidc/credprovider/integration_config_provider.go index a98ba7a2b55ff..204ab121cc133 100644 --- a/lib/integrations/awsoidc/credprovider/integration_config_provider.go +++ b/lib/integrations/awsoidc/credprovider/integration_config_provider.go @@ -33,10 +33,33 @@ import ( "github.com/gravitational/teleport/lib/modules" ) +// Options represents additional options for configuring the AWS credentials provider. +type Options struct { + // WaitForFirstInit indicates whether to wait for the initial credential + // generation before returning from CreateAWSConfigForIntegration. + WaitForFirstInit bool +} + +// Option is a function that modifies the Options struct for the AWS configuration. +type Option func(*Options) + +// WithWaitForFirstInit configures the provider to wait until the first set of +// credentials is generated before proceeding. This is useful in cases where +// immediate credential availability is necessary. +func WithWaitForFirstInit(wait bool) Option { + return func(o *Options) { + o.WaitForFirstInit = wait + } +} + // CreateAWSConfigForIntegration returns a new AWS credentials provider that // uses the AWS OIDC integration to generate temporary credentials. // The provider will periodically refresh the credentials before they expire. -func CreateAWSConfigForIntegration(ctx context.Context, config Config) (*aws.Config, error) { +func CreateAWSConfigForIntegration(ctx context.Context, config Config, option ...Option) (*aws.Config, error) { + options := Options{} + for _, opt := range option { + opt(&options) + } if err := config.checkAndSetDefaults(); err != nil { return nil, trace.Wrap(err) } @@ -52,7 +75,10 @@ func CreateAWSConfigForIntegration(ctx context.Context, config Config) (*aws.Con return nil, trace.Wrap(err) } go credCache.Run(ctx) - credCache.WaitForFirstCredsOrErr(ctx) + + if options.WaitForFirstInit { + credCache.WaitForFirstCredsOrErr(ctx) + } awsCfg, err := newAWSConfig(ctx, config.Region, awsConfig.WithCredentialsProvider(credCache)) if err != nil { diff --git a/lib/integrations/awsoidc/credprovider/integration_config_provider_test.go b/lib/integrations/awsoidc/credprovider/integration_config_provider_test.go new file mode 100644 index 0000000000000..03af684ce602b --- /dev/null +++ b/lib/integrations/awsoidc/credprovider/integration_config_provider_test.go @@ -0,0 +1,187 @@ +// Teleport +// Copyright (C) 2024 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package credprovider + +import ( + "context" + "crypto" + "sync/atomic" + "testing" + + "github.com/gravitational/trace" + "github.com/jonboulle/clockwork" + "github.com/stretchr/testify/require" + + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/api/utils/keys" + "github.com/gravitational/teleport/lib/auth/testauthority" + "github.com/gravitational/teleport/lib/backend/memory" + "github.com/gravitational/teleport/lib/integrations/awsoidc" + "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/local" +) + +const ( + integrationName = "test-integration1" + awsRegion = " eu-central-1" + testUser = "test-user" +) + +func TestCreateAWSConfigForIntegration(t *testing.T) { + deps := newDepsMock(t) + ctx := context.Background() + + t.Run("should auto init credentials during retrieve call", func(t *testing.T) { + stsClient := &fakeSTSClient{clock: clockwork.NewFakeClock()} + config, err := CreateAWSConfigForIntegration(ctx, Config{ + Region: awsRegion, + IntegrationName: integrationName, + IntegrationGetter: deps, + AWSOIDCTokenGenerator: deps, + STSClient: stsClient, + }) + require.NoError(t, err) + require.Equal(t, int32(0), atomic.LoadInt32(&stsClient.called)) + + creds, err := config.Credentials.Retrieve(ctx) + require.NoError(t, err) + require.NotEmpty(t, creds.SecretAccessKey) + }) + + t.Run("should init creds before retrieve call", func(t *testing.T) { + stsClient := &fakeSTSClient{clock: clockwork.NewFakeClock()} + config, err := CreateAWSConfigForIntegration(ctx, Config{ + Region: awsRegion, + IntegrationName: integrationName, + IntegrationGetter: deps, + AWSOIDCTokenGenerator: deps, + STSClient: stsClient, + }, WithWaitForFirstInit(true)) + require.NoError(t, err) + require.Equal(t, int32(1), atomic.LoadInt32(&stsClient.called)) + + creds, err := config.Credentials.Retrieve(ctx) + require.NoError(t, err) + require.NotEmpty(t, creds.SecretAccessKey) + }) +} + +type depsMock struct { + *local.CA + *local.ClusterConfigurationService + *local.IntegrationsService + *local.PresenceService + proxies []types.Server +} + +func (d *depsMock) GenerateOIDCTokenFn(ctx context.Context, integration string) (string, error) { + token, err := awsoidc.GenerateAWSOIDCToken(ctx, d, d, awsoidc.GenerateAWSOIDCTokenRequest{ + Integration: integrationName, + Username: testUser, + Subject: types.IntegrationAWSOIDCSubject, + }) + return token, trace.Wrap(err) +} + +func (d *depsMock) GenerateAWSOIDCToken(ctx context.Context, integration string) (string, error) { + token, err := awsoidc.GenerateAWSOIDCToken(ctx, d, d, awsoidc.GenerateAWSOIDCTokenRequest{ + Integration: integration, + Username: "test-user", + Subject: types.IntegrationAWSOIDCSubject, + }) + return token, trace.Wrap(err) +} + +func (d *depsMock) GetJWTSigner(ctx context.Context, ca types.CertAuthority) (crypto.Signer, error) { + ca, err := d.CA.GetCertAuthority(ctx, ca.GetID(), true) + if err != nil { + return nil, err + } + if len(ca.GetTrustedJWTKeyPairs()) == 0 { + return nil, trace.BadParameter("no JWT keys found") + } + return keys.ParsePrivateKey(ca.GetTrustedJWTKeyPairs()[0].PrivateKey) +} + +func (d *depsMock) GetProxies() ([]types.Server, error) { + return d.proxies, nil +} + +func (d *depsMock) GetClusterName(opts ...services.MarshalOption) (types.ClusterName, error) { + return types.NewClusterName(types.ClusterNameSpecV2{ClusterName: "teleport.example.com", ClusterID: "cluster-id"}) +} + +func newDepsMock(t *testing.T) *depsMock { + ctx := context.Background() + var out depsMock + b, err := memory.New(memory.Config{ + Clock: clockwork.NewFakeClock(), + }) + require.NoError(t, err) + t.Cleanup(func() { + require.NoError(t, b.Close()) + }) + out.CA = local.NewCAService(b) + out.ClusterConfigurationService, err = local.NewClusterConfigurationService(b) + require.NoError(t, err) + out.IntegrationsService, err = local.NewIntegrationsService(b) + require.NoError(t, err) + out.PresenceService = local.NewPresenceService(b) + + ca := newCertAuthority(t, types.OIDCIdPCA, "teleport.example.com") + require.NoError(t, err) + + err = out.CA.CreateCertAuthority(ctx, ca) + require.NoError(t, err) + + oidcIntegration, err := types.NewIntegrationAWSOIDC( + types.Metadata{Name: integrationName}, + &types.AWSOIDCIntegrationSpecV1{ + RoleARN: "arn:aws:iam::111111111111:role/test-role", + }, + ) + require.NoError(t, err) + + _, err = out.IntegrationsService.CreateIntegration(context.Background(), oidcIntegration) + require.NoError(t, err) + + out.proxies = []types.Server{ + &types.ServerV2{Spec: types.ServerSpecV2{ + PublicAddrs: []string{"teleport.example.com"}, + }}, + } + return &out +} + +func newCertAuthority(t *testing.T, caType types.CertAuthType, domain string) types.CertAuthority { + t.Helper() + publicKey, privateKey, err := testauthority.New().GenerateJWT() + require.NoError(t, err) + ca, err := types.NewCertAuthority(types.CertAuthoritySpecV2{ + Type: caType, + ClusterName: domain, + ActiveKeys: types.CAKeySet{ + JWT: []*types.JWTKeyPair{{ + PublicKey: publicKey, + PrivateKey: privateKey, + PrivateKeyType: types.PrivateKeyType_RAW, + }}, + }, + }) + require.NoError(t, err) + return ca +} From 8299ab5a5510bc05ae563493aabdad50dc41c96e Mon Sep 17 00:00:00 2001 From: Lisa Kim Date: Thu, 14 Nov 2024 04:33:23 -0800 Subject: [PATCH 10/11] Teleterm: fix incorrect cluster URI when fetching kube namespaces on a leaf cluster (access request) (#48786) * Use tc.SiteName over cluster.Name * Teleterm: fix fetching namespaces with incorrect cluster URI If you add a root and leaf kube cluster,and on leaf Teleport cluster, listing namespaces for root kube cluster was referring to incorrect Teleport cluster URI * Teleterm: fix re-ordering of selected namespaces when done selecting Web UI still has this weird re-ordering because web UI still stores resource ids in a map which doesn't preserve order * Add requested length test * Address CR * Address CRs --- .../go/teleport/lib/teleterm/v1/service.pb.go | 1376 ++++++++--------- .../ts/teleport/lib/teleterm/v1/service_pb.ts | 14 +- .../apiserver/handler/handler_kubes.go | 12 +- lib/teleterm/daemon/daemon.go | 17 +- proto/teleport/lib/teleterm/v1/service.proto | 3 +- .../RequestCheckout/KubeNamespaceSelector.tsx | 82 +- .../RequestCheckout/RequestCheckout.story.tsx | 2 +- .../RequestCheckout/RequestCheckout.test.tsx | 2 +- .../RequestCheckout/RequestCheckout.tsx | 12 +- .../AccessRequests/NewRequest/index.ts | 1 - .../AccessRequests/NewRequest/kube.ts | 5 - .../AccessRequestCheckout.tsx | 4 +- .../useAccessRequestCheckout.test.tsx | 288 +++- .../useAccessRequestCheckout.ts | 41 +- .../accessRequestsService.ts | 36 +- web/packages/teleterm/src/ui/uri.ts | 14 + 16 files changed, 1019 insertions(+), 890 deletions(-) diff --git a/gen/proto/go/teleport/lib/teleterm/v1/service.pb.go b/gen/proto/go/teleport/lib/teleterm/v1/service.pb.go index f52626e328def..decb858b1d2ef 100644 --- a/gen/proto/go/teleport/lib/teleterm/v1/service.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/v1/service.pb.go @@ -1501,7 +1501,6 @@ type ListKubernetesResourcesResponse struct { unknownFields protoimpl.UnknownFields Resources []*KubeResource `protobuf:"bytes,1,rep,name=resources,proto3" json:"resources,omitempty"` - NextKey string `protobuf:"bytes,2,opt,name=next_key,json=nextKey,proto3" json:"next_key,omitempty"` } func (x *ListKubernetesResourcesResponse) Reset() { @@ -1541,13 +1540,6 @@ func (x *ListKubernetesResourcesResponse) GetResources() []*KubeResource { return nil } -func (x *ListKubernetesResourcesResponse) GetNextKey() string { - if x != nil { - return x.NextKey - } - return "" -} - // CredentialInfo holds fields related to a user's WebAuthn credential. type CredentialInfo struct { state protoimpl.MessageState @@ -4540,730 +4532,730 @@ var file_teleport_lib_teleterm_v1_service_proto_rawDesc = []byte{ 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x31, 0x0a, 0x14, 0x6b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x6b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x4e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x82, 0x01, 0x0a, 0x1f, 0x4c, 0x69, 0x73, - 0x74, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x09, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x26, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x78, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x2c, 0x0a, - 0x0e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xad, 0x01, 0x0a, 0x19, - 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x06, 0x70, 0x72, 0x6f, - 0x6d, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, - 0x73, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x12, - 0x4a, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, - 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, - 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x22, 0x9b, 0x04, 0x0a, 0x18, - 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x65, 0x0a, 0x04, 0x69, 0x6e, 0x69, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x4f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, - 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, - 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x49, 0x6e, 0x69, 0x74, 0x48, 0x00, 0x52, 0x04, 0x69, 0x6e, 0x69, 0x74, 0x12, - 0x63, 0x0a, 0x03, 0x70, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x4f, 0x2e, 0x74, + 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x77, 0x0a, 0x1f, 0x4c, 0x69, 0x73, 0x74, + 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x09, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x08, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x6b, 0x65, + 0x79, 0x22, 0x2c, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, + 0xad, 0x01, 0x0a, 0x19, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, + 0x06, 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x6c, 0x65, 0x73, 0x73, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x52, 0x06, 0x70, 0x72, 0x6f, + 0x6d, 0x70, 0x74, 0x12, 0x4a, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, + 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x22, + 0x9b, 0x04, 0x0a, 0x18, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x65, 0x0a, 0x04, + 0x69, 0x6e, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x4f, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, + 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x69, 0x74, 0x48, 0x00, 0x52, 0x04, 0x69, + 0x6e, 0x69, 0x74, 0x12, 0x63, 0x0a, 0x03, 0x70, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x4f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, + 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x50, 0x49, 0x4e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x48, 0x00, 0x52, 0x03, 0x70, 0x69, 0x6e, 0x12, 0x78, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x56, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, - 0x73, 0x73, 0x50, 0x49, 0x4e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, - 0x03, 0x70, 0x69, 0x6e, 0x12, 0x78, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x56, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x73, 0x73, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x1a, 0x3f, 0x0a, 0x1c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, + 0x69, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, + 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x55, 0x72, 0x69, 0x1a, 0x30, 0x0a, 0x1c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x50, 0x49, 0x4e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x70, 0x69, 0x6e, 0x1a, 0x3b, 0x0a, 0x23, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xdf, 0x01, + 0x0a, 0x13, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4d, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, - 0x64, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x6f, 0x67, - 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x43, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x48, 0x00, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x1a, 0x3f, - 0x0a, 0x1c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, - 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x69, 0x74, 0x12, 0x1f, - 0x0a, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x1a, - 0x30, 0x0a, 0x1c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, - 0x6c, 0x65, 0x73, 0x73, 0x50, 0x49, 0x4e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x10, 0x0a, 0x03, 0x70, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x69, - 0x6e, 0x1a, 0x3b, 0x0a, 0x23, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, - 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x09, - 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xdf, 0x01, 0x0a, 0x13, 0x46, 0x69, - 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, - 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x4d, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, - 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x46, 0x69, 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x44, 0x69, 0x72, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x55, 0x72, 0x69, 0x4a, - 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0x36, 0x0a, 0x14, 0x46, - 0x69, 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x67, 0x72, - 0x65, 0x73, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, - 0x61, 0x67, 0x65, 0x22, 0xf7, 0x02, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, - 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x55, 0x72, 0x69, 0x12, 0x4a, 0x0a, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, - 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x6f, 0x63, - 0x61, 0x6c, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x48, 0x00, 0x52, 0x05, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x12, 0x44, 0x0a, 0x03, 0x73, 0x73, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x53, 0x73, 0x6f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, - 0x48, 0x00, 0x52, 0x03, 0x73, 0x73, 0x6f, 0x1a, 0x53, 0x0a, 0x0b, 0x4c, 0x6f, 0x63, 0x61, 0x6c, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x1a, 0x55, 0x0a, 0x09, - 0x53, 0x73, 0x6f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x23, - 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4e, - 0x61, 0x6d, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x27, 0x0a, - 0x11, 0x41, 0x64, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, - 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x55, 0x0a, - 0x14, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x08, 0x63, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61, 0x66, - 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, - 0x22, 0x31, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, - 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, - 0x64, 0x62, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x64, 0x62, - 0x55, 0x72, 0x69, 0x22, 0x31, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, - 0x61, 0x73, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x14, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0xad, 0x01, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x1d, 0x0a, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x72, 0x69, 0x12, 0x1f, - 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, - 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x36, - 0x0a, 0x17, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x75, 0x62, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x15, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x55, 0x0a, - 0x14, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x08, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x08, 0x67, 0x61, 0x74, 0x65, - 0x77, 0x61, 0x79, 0x73, 0x22, 0x37, 0x0a, 0x14, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x47, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, + 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, + 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x75, + 0x72, 0x69, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x55, 0x72, 0x69, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, + 0x36, 0x0a, 0x14, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x50, + 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x63, 0x65, + 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x70, 0x65, 0x72, + 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x22, 0xf7, 0x02, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x12, 0x4a, 0x0a, 0x05, 0x6c, 0x6f, 0x63, + 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x48, 0x00, 0x52, 0x05, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x12, 0x44, 0x0a, 0x03, 0x73, 0x73, 0x6f, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, + 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, + 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x53, 0x73, 0x6f, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x48, 0x00, 0x52, 0x03, 0x73, 0x73, 0x6f, 0x1a, 0x53, 0x0a, 0x0b, 0x4c, + 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, + 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x1a, 0x55, 0x0a, 0x09, 0x53, 0x73, 0x6f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x23, 0x0a, + 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, + 0x73, 0x22, 0x27, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x4c, 0x69, + 0x73, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x22, 0x55, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x08, 0x63, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x08, + 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, + 0x4c, 0x65, 0x61, 0x66, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, + 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, + 0x72, 0x55, 0x72, 0x69, 0x22, 0x31, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, + 0x62, 0x61, 0x73, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x15, 0x0a, 0x06, 0x64, 0x62, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x64, 0x62, 0x55, 0x72, 0x69, 0x22, 0x31, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x44, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0xad, 0x01, 0x0a, 0x14, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x72, + 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, + 0x72, 0x69, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, + 0x73, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x72, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, + 0x72, 0x74, 0x12, 0x36, 0x0a, 0x17, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x75, 0x62, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x15, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x4c, 0x69, + 0x73, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x22, 0x55, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x08, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x08, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x22, 0x37, 0x0a, 0x14, 0x52, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1f, 0x0a, 0x0b, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x75, 0x72, 0x69, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x55, 0x72, + 0x69, 0x22, 0x81, 0x01, 0x0a, 0x26, 0x53, 0x65, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x55, 0x72, 0x69, 0x22, 0x81, 0x01, - 0x0a, 0x26, 0x53, 0x65, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x54, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x53, 0x75, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x67, 0x61, 0x74, 0x65, - 0x77, 0x61, 0x79, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x67, - 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x55, 0x72, 0x69, 0x12, 0x36, 0x0a, 0x17, 0x74, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x5f, 0x73, 0x75, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x74, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x53, 0x75, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, - 0x65, 0x22, 0x5c, 0x0a, 0x1a, 0x53, 0x65, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4c, - 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x1f, 0x0a, 0x0b, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x55, 0x72, 0x69, - 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x22, - 0xd6, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, + 0x09, 0x52, 0x0a, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x55, 0x72, 0x69, 0x12, 0x36, 0x0a, + 0x17, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x75, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x5c, 0x0a, 0x1a, 0x53, 0x65, 0x74, 0x47, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x75, + 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x55, 0x72, 0x69, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x6f, + 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, + 0x6f, 0x72, 0x74, 0x22, 0xd6, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, + 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x73, + 0x6f, 0x72, 0x74, 0x5f, 0x62, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, + 0x72, 0x74, 0x42, 0x79, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x61, + 0x73, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x73, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, + 0x12, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, + 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x0a, + 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, + 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x39, 0x0a, 0x16, 0x47, + 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1b, 0x0a, 0x09, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x6f, 0x72, 0x74, 0x5f, - 0x62, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x72, 0x74, 0x42, 0x79, - 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x61, 0x73, 0x5f, 0x72, 0x6f, - 0x6c, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x41, 0x73, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x12, 0x47, 0x65, 0x74, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x38, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x20, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, - 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, - 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, - 0x74, 0x61, 0x72, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x39, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x41, 0x75, - 0x74, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, - 0x72, 0x69, 0x22, 0x40, 0x0a, 0x24, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x73, 0x68, 0x64, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x22, 0x27, 0x0a, 0x25, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x73, - 0x68, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xdf, 0x01, - 0x0a, 0x28, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, - 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, - 0x6f, 0x74, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, - 0x72, 0x55, 0x72, 0x69, 0x12, 0x3c, 0x0a, 0x1a, 0x68, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, - 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, 0x68, 0x65, 0x61, 0x64, 0x6c, 0x65, - 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x12, 0x4b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, - 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, - 0x2b, 0x0a, 0x29, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, - 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4e, 0x0a, 0x22, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, - 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x6f, - 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x22, 0x4c, 0x0a, 0x23, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, - 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x65, 0x72, 0x74, 0x73, 0x5f, 0x72, 0x65, 0x6c, - 0x6f, 0x61, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x63, 0x65, 0x72, - 0x74, 0x73, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x22, 0x53, 0x0a, 0x27, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, - 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x6c, - 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x22, - 0x4e, 0x0a, 0x28, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x22, - 0x53, 0x0a, 0x27, 0x57, 0x61, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x4a, - 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, - 0x6f, 0x74, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, - 0x72, 0x55, 0x72, 0x69, 0x22, 0x64, 0x0a, 0x28, 0x57, 0x61, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, - 0x4e, 0x6f, 0x64, 0x65, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x38, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x20, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x4e, 0x0a, 0x22, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, - 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, - 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x6f, 0x6f, 0x74, - 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x22, 0x25, 0x0a, 0x23, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, - 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x4f, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, - 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x74, - 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, - 0x72, 0x69, 0x22, 0x3a, 0x0a, 0x24, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x4e, 0x61, - 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xea, - 0x02, 0x0a, 0x1b, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, - 0x0a, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x12, - 0x14, 0x0a, 0x05, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, - 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x73, - 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, - 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x16, - 0x0a, 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x39, 0x0a, 0x07, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x62, - 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x6f, 0x72, 0x74, 0x42, 0x79, 0x52, 0x06, 0x73, 0x6f, 0x72, 0x74, 0x42, - 0x79, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x61, 0x73, 0x5f, 0x72, - 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x41, 0x73, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x69, 0x6e, - 0x6e, 0x65, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, - 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x2f, 0x0a, 0x13, 0x69, 0x6e, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x37, 0x0a, 0x06, 0x53, - 0x6f, 0x72, 0x74, 0x42, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x64, 0x65, 0x73, 0x63, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x44, 0x65, 0x73, 0x63, 0x12, 0x14, - 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, - 0x69, 0x65, 0x6c, 0x64, 0x22, 0x84, 0x01, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x69, - 0x66, 0x69, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, - 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x78, 0x74, 0x4b, 0x65, 0x79, 0x22, 0xb1, 0x02, 0x0a, 0x11, - 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x12, 0x40, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, - 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x44, - 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x48, 0x00, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, - 0x61, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, - 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x48, 0x00, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, - 0x34, 0x0a, 0x04, 0x6b, 0x75, 0x62, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x48, 0x00, 0x52, - 0x04, 0x6b, 0x75, 0x62, 0x65, 0x12, 0x31, 0x0a, 0x03, 0x61, 0x70, 0x70, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, - 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, - 0x70, 0x48, 0x00, 0x52, 0x03, 0x61, 0x70, 0x70, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, - 0x69, 0x72, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, - 0x3c, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, - 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, - 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x22, 0x72, 0x0a, - 0x1a, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, - 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x10, 0x75, - 0x73, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x22, 0x40, 0x0a, 0x24, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x54, 0x73, 0x68, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, + 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x27, 0x0a, 0x25, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x54, 0x73, 0x68, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0xdf, 0x01, 0x0a, 0x28, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x65, 0x61, 0x64, + 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, + 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, + 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x12, 0x3c, 0x0a, 0x1a, 0x68, 0x65, 0x61, 0x64, + 0x6c, 0x65, 0x73, 0x73, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, 0x68, 0x65, + 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x4b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, - 0x52, 0x0f, 0x75, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, - 0x73, 0x22, 0x95, 0x01, 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, - 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x2e, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x22, 0x2b, 0x0a, 0x29, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x65, 0x61, + 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x4e, 0x0a, 0x22, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, + 0x22, 0x4c, 0x0a, 0x23, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x65, 0x72, 0x74, 0x73, + 0x5f, 0x72, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0d, 0x63, 0x65, 0x72, 0x74, 0x73, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x22, 0x53, + 0x0a, 0x27, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, + 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, 0x6f, + 0x74, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x55, 0x72, 0x69, 0x22, 0x4e, 0x0a, 0x28, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, + 0x64, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x06, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x73, 0x22, 0x53, 0x0a, 0x27, 0x57, 0x61, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, + 0x6f, 0x64, 0x65, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, + 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, + 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x22, 0x64, 0x0a, 0x28, 0x57, 0x61, 0x69, 0x74, + 0x46, 0x6f, 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, + 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x4e, + 0x0a, 0x22, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, + 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, + 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x22, 0x25, + 0x0a, 0x23, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, + 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4f, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, + 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x22, 0x3a, 0x0a, 0x24, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, + 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x22, 0xea, 0x02, 0x0a, 0x1b, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x69, + 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, - 0x55, 0x72, 0x69, 0x12, 0x54, 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x66, - 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, - 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x0f, 0x75, 0x73, 0x65, 0x72, 0x50, 0x72, - 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x22, 0x75, 0x0a, 0x1d, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x10, 0x75, 0x73, - 0x65, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, - 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x72, 0x69, 0x12, 0x14, 0x0a, 0x05, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x05, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, + 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, + 0x1b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x39, 0x0a, 0x07, 0x73, 0x6f, + 0x72, 0x74, 0x5f, 0x62, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6f, 0x72, 0x74, 0x42, 0x79, 0x52, 0x06, 0x73, + 0x6f, 0x72, 0x74, 0x42, 0x79, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, + 0x61, 0x73, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, + 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x73, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x1f, 0x0a, + 0x0b, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0a, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x2f, + 0x0a, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x69, 0x6e, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, + 0x37, 0x0a, 0x06, 0x53, 0x6f, 0x72, 0x74, 0x42, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x73, 0x5f, + 0x64, 0x65, 0x73, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x44, 0x65, + 0x73, 0x63, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x22, 0x84, 0x01, 0x0a, 0x1c, 0x4c, 0x69, 0x73, + 0x74, 0x55, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x09, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, + 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x6b, 0x65, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x78, 0x74, 0x4b, 0x65, 0x79, 0x22, + 0xb1, 0x02, 0x0a, 0x11, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x40, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x48, 0x00, 0x52, 0x08, 0x64, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x48, 0x00, 0x52, 0x06, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x12, 0x34, 0x0a, 0x04, 0x6b, 0x75, 0x62, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x75, 0x62, + 0x65, 0x48, 0x00, 0x52, 0x04, 0x6b, 0x75, 0x62, 0x65, 0x12, 0x31, 0x0a, 0x03, 0x61, 0x70, 0x70, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x41, 0x70, 0x70, 0x48, 0x00, 0x52, 0x03, 0x61, 0x70, 0x70, 0x12, 0x29, 0x0a, 0x10, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x22, 0x3c, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, + 0x69, 0x22, 0x72, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x54, 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x73, 0x52, 0x0f, 0x75, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x73, 0x22, 0x95, 0x01, 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, - 0x0f, 0x75, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, - 0x22, 0xf2, 0x01, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6e, 0x63, 0x65, 0x73, 0x12, 0x64, 0x0a, 0x13, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, - 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, - 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, - 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x12, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x50, - 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x79, 0x0a, 0x1c, 0x75, 0x6e, - 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, - 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x37, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, - 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, + 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x12, 0x54, 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f, + 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, + 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x0f, 0x75, 0x73, + 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x22, 0x75, 0x0a, + 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, + 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x73, 0x52, 0x0f, 0x75, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x73, 0x22, 0xf2, 0x01, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x64, 0x0a, 0x13, 0x63, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x50, + 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x12, 0x63, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x79, + 0x0a, 0x1c, 0x75, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x1a, 0x75, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x72, - 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x1a, 0x75, 0x6e, 0x69, 0x66, 0x69, - 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, - 0x65, 0x6e, 0x63, 0x65, 0x73, 0x22, 0x9b, 0x01, 0x0a, 0x1c, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, - 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x57, 0x65, 0x62, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x5f, 0x77, 0x65, 0x62, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x64, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x57, 0x65, 0x62, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x57, 0x65, 0x62, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, 0x6f, - 0x74, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, - 0x55, 0x72, 0x69, 0x22, 0x80, 0x01, 0x0a, 0x1d, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x57, 0x65, 0x62, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x12, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x30, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x64, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x2a, 0x97, 0x01, 0x0a, 0x12, 0x50, 0x61, 0x73, 0x73, 0x77, - 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x12, 0x23, 0x0a, - 0x1f, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x50, 0x52, - 0x4f, 0x4d, 0x50, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, - 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x45, - 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x4d, 0x50, 0x54, 0x5f, 0x50, 0x49, 0x4e, 0x10, 0x01, 0x12, - 0x1b, 0x0a, 0x17, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, - 0x50, 0x52, 0x4f, 0x4d, 0x50, 0x54, 0x5f, 0x54, 0x41, 0x50, 0x10, 0x02, 0x12, 0x22, 0x0a, 0x1e, - 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, - 0x4d, 0x50, 0x54, 0x5f, 0x43, 0x52, 0x45, 0x44, 0x45, 0x4e, 0x54, 0x49, 0x41, 0x4c, 0x10, 0x03, - 0x2a, 0x8a, 0x01, 0x0a, 0x15, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, - 0x72, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x23, 0x46, 0x49, - 0x4c, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x44, 0x49, 0x52, 0x45, - 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, - 0x44, 0x10, 0x00, 0x12, 0x24, 0x0a, 0x20, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, - 0x53, 0x46, 0x45, 0x52, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x44, - 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x46, 0x49, 0x4c, - 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, - 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x50, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x02, 0x2a, 0xcd, 0x01, - 0x0a, 0x1b, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, - 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2d, 0x0a, - 0x29, 0x48, 0x45, 0x41, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, - 0x54, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, - 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x29, 0x0a, 0x25, - 0x48, 0x45, 0x41, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, - 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x50, 0x45, - 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x28, 0x0a, 0x24, 0x48, 0x45, 0x41, 0x44, 0x4c, - 0x45, 0x53, 0x53, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x49, - 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x45, 0x4e, 0x49, 0x45, 0x44, 0x10, - 0x02, 0x12, 0x2a, 0x0a, 0x26, 0x48, 0x45, 0x41, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x41, 0x55, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x22, 0x9b, 0x01, 0x0a, 0x1c, 0x41, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x57, 0x65, 0x62, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x77, 0x65, 0x62, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x57, 0x65, 0x62, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x0e, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x57, 0x65, 0x62, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x28, 0x0a, + 0x10, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, + 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x22, 0x80, 0x01, 0x0a, 0x1d, 0x41, 0x75, 0x74, 0x68, + 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x57, 0x65, 0x62, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x12, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x2a, 0x97, 0x01, 0x0a, 0x12, 0x50, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x50, 0x72, 0x6f, 0x6d, 0x70, + 0x74, 0x12, 0x23, 0x0a, 0x1f, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x45, 0x53, + 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x4d, 0x50, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, + 0x52, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x4d, 0x50, 0x54, 0x5f, 0x50, 0x49, + 0x4e, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x4c, + 0x45, 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x4d, 0x50, 0x54, 0x5f, 0x54, 0x41, 0x50, 0x10, 0x02, + 0x12, 0x22, 0x0a, 0x1e, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x45, 0x53, 0x53, + 0x5f, 0x50, 0x52, 0x4f, 0x4d, 0x50, 0x54, 0x5f, 0x43, 0x52, 0x45, 0x44, 0x45, 0x4e, 0x54, 0x49, + 0x41, 0x4c, 0x10, 0x03, 0x2a, 0x8a, 0x01, 0x0a, 0x15, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x66, 0x65, 0x72, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, + 0x0a, 0x23, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, + 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x24, 0x0a, 0x20, 0x46, 0x49, 0x4c, 0x45, 0x5f, + 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, + 0x4f, 0x4e, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x01, 0x12, 0x22, 0x0a, + 0x1e, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x44, + 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x50, 0x4c, 0x4f, 0x41, 0x44, 0x10, + 0x02, 0x2a, 0xcd, 0x01, 0x0a, 0x1b, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x2d, 0x0a, 0x29, 0x48, 0x45, 0x41, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, - 0x54, 0x45, 0x5f, 0x41, 0x50, 0x50, 0x52, 0x4f, 0x56, 0x45, 0x44, 0x10, 0x03, 0x32, 0x81, 0x28, - 0x0a, 0x0f, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x12, 0xa0, 0x01, 0x0a, 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x73, 0x68, 0x64, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x12, 0x3e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, - 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x73, 0x68, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x3f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, - 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x73, 0x68, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x74, - 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x29, 0x0a, 0x25, 0x48, 0x45, 0x41, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x41, 0x55, 0x54, + 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, + 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x28, 0x0a, 0x24, 0x48, + 0x45, 0x41, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, + 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x45, 0x4e, + 0x49, 0x45, 0x44, 0x10, 0x02, 0x12, 0x2a, 0x0a, 0x26, 0x48, 0x45, 0x41, 0x44, 0x4c, 0x45, 0x53, + 0x53, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, + 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x50, 0x50, 0x52, 0x4f, 0x56, 0x45, 0x44, 0x10, + 0x03, 0x32, 0x81, 0x28, 0x0a, 0x0f, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xa0, 0x01, 0x0a, 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x54, 0x73, 0x68, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x4c, - 0x65, 0x61, 0x66, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x31, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61, 0x66, 0x43, - 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, - 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x85, - 0x01, 0x0a, 0x14, 0x53, 0x74, 0x61, 0x72, 0x74, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, - 0x57, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x73, 0x68, 0x64, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, - 0x57, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x48, - 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x57, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7c, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x32, 0x2e, 0x74, 0x65, + 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x73, 0x68, 0x64, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2d, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, - 0x61, 0x73, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, + 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a, 0x10, 0x4c, + 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61, 0x66, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, + 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4c, + 0x65, 0x61, 0x66, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, + 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x85, 0x01, 0x0a, 0x14, 0x53, 0x74, 0x61, 0x72, 0x74, 0x48, 0x65, 0x61, 0x64, + 0x6c, 0x65, 0x73, 0x73, 0x57, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x35, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x48, 0x65, 0x61, 0x64, + 0x6c, 0x65, 0x73, 0x73, 0x57, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, + 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, + 0x61, 0x72, 0x74, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x57, 0x61, 0x74, 0x63, 0x68, + 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7c, 0x0a, 0x11, 0x4c, 0x69, + 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, + 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, - 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x73, 0x12, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, - 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, - 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x88, - 0x02, 0x01, 0x12, 0x7c, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x74, 0x65, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, + 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, + 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, + 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x12, 0x7c, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x79, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, - 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x74, 0x0a, 0x13, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, - 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x79, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x82, 0x01, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x82, 0x01, 0x0a, 0x13, 0x52, 0x65, 0x76, 0x69, 0x65, - 0x77, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, - 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x82, 0x01, 0x0a, 0x13, - 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, - 0x6c, 0x65, 0x73, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, - 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, - 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x6c, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x62, 0x0a, 0x0a, 0x41, 0x73, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x2b, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x73, 0x73, 0x75, 0x6d, 0x65, - 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x85, 0x01, 0x0a, 0x14, 0x50, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x2e, + 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x74, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x82, 0x01, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, - 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x50, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x8e, 0x01, 0x0a, - 0x17, 0x47, 0x65, 0x74, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x65, 0x64, 0x41, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x12, 0x38, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, + 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x82, 0x01, 0x0a, 0x13, 0x52, + 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, + 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, + 0x76, 0x69, 0x65, 0x77, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x65, 0x64, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, - 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, - 0x74, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x65, 0x64, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x4c, 0x69, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x8e, 0x01, - 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x38, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, - 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, - 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5c, - 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2b, 0x2e, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x82, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0a, 0x41, 0x73, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x6f, + 0x6c, 0x65, 0x12, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, + 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x73, + 0x73, 0x75, 0x6d, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x85, 0x01, 0x0a, 0x14, 0x50, 0x72, 0x6f, + 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, + 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x8e, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x65, + 0x64, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x12, 0x38, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x68, 0x0a, 0x0d, - 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2e, 0x2e, + 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x75, 0x67, 0x67, 0x65, + 0x73, 0x74, 0x65, 0x64, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x65, 0x64, 0x41, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x8e, 0x01, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, + 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x38, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, - 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, + 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x75, 0x62, + 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x12, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x43, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6d, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, - 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x68, 0x0a, 0x0d, 0x52, 0x65, 0x6d, - 0x6f, 0x76, 0x65, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x2e, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x12, 0x68, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, + 0x72, 0x12, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6d, 0x0a, 0x0c, 0x4c, 0x69, + 0x73, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x47, 0x61, 0x74, 0x65, - 0x77, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x86, 0x01, 0x0a, 0x1f, 0x53, 0x65, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, - 0x61, 0x79, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x40, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x54, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, - 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x6e, 0x0a, 0x13, - 0x53, 0x65, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, - 0x6f, 0x72, 0x74, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, - 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x65, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, - 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x6b, 0x0a, 0x0f, - 0x47, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, - 0x30, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x75, - 0x74, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x26, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, - 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x5c, 0x0a, 0x0a, 0x47, 0x65, 0x74, - 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, - 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x58, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, - 0x12, 0x26, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x80, 0x01, 0x0a, 0x11, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, - 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x12, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, - 0x6c, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, - 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x28, 0x01, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x06, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x12, 0x27, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0d, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x2e, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x68, 0x0a, + 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x2e, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x86, 0x01, 0x0a, 0x1f, 0x53, 0x65, 0x74, 0x47, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x40, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x12, 0x6e, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4c, 0x6f, + 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x6f, 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x65, - 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x30, - 0x01, 0x12, 0x6e, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4c, 0x6f, 0x63, + 0x61, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x12, 0x6b, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x12, 0x30, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, + 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, + 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x2e, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x5c, 0x0a, + 0x0a, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2b, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0xac, 0x01, 0x0a, 0x21, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x65, 0x61, 0x64, - 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x42, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, - 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x43, 0x2e, 0x74, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x58, 0x0a, 0x05, 0x4c, + 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x26, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x80, 0x01, 0x0a, 0x11, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x12, 0x32, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, + 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x06, 0x4c, 0x6f, 0x67, 0x6f, + 0x75, 0x74, 0x12, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, + 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, + 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, + 0x46, 0x69, 0x6c, 0x65, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x46, 0x69, 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, + 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x46, + 0x69, 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x67, 0x72, + 0x65, 0x73, 0x73, 0x30, 0x01, 0x12, 0x6e, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x55, + 0x73, 0x61, 0x67, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xac, 0x01, 0x0a, 0x21, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x42, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x9a, 0x01, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, - 0x12, 0x3c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, - 0x74, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, - 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa9, 0x01, - 0x0a, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, - 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x12, 0x41, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, + 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x43, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x9a, 0x01, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, + 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x3c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, + 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, - 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x42, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, - 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa9, 0x01, 0x0a, 0x20, 0x57, 0x61, + 0x70, 0x75, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0xa9, 0x01, 0x0a, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, + 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x41, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, + 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x42, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa9, 0x01, + 0x0a, 0x20, 0x57, 0x61, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x4a, 0x6f, + 0x69, 0x6e, 0x12, 0x41, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, + 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x61, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, - 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x4a, 0x6f, 0x69, 0x6e, 0x12, 0x41, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x61, 0x69, 0x74, 0x46, 0x6f, - 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, - 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x42, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x61, 0x69, - 0x74, 0x46, 0x6f, 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, - 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x9a, 0x01, 0x0a, 0x1b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, - 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x3c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, - 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, - 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, - 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x9d, 0x01, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x3d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, - 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, - 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, - 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x3e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, - 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, - 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, - 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x85, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x69, - 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x35, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x69, - 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, - 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7f, 0x0a, 0x12, 0x47, 0x65, - 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, - 0x12, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, - 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, - 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x88, 0x01, 0x0a, 0x15, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, - 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x36, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x42, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, - 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, - 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x88, 0x01, 0x0a, 0x15, 0x41, 0x75, 0x74, 0x68, 0x65, - 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x57, 0x65, 0x62, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x12, 0x36, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, - 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x57, 0x65, 0x62, 0x44, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x57, 0x65, 0x62, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x42, 0x54, 0x5a, 0x52, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6c, 0x69, 0x62, - 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x72, 0x6d, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x57, 0x61, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, + 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x4a, 0x6f, 0x69, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x9a, 0x01, 0x0a, 0x1b, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, + 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x3c, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x9d, 0x01, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, + 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, + 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, + 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x85, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x55, + 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, + 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, + 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7f, + 0x0a, 0x12, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x73, 0x12, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x88, 0x01, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x36, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, + 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x37, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x88, 0x01, 0x0a, 0x15, 0x41, + 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x57, 0x65, 0x62, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x36, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x57, 0x65, 0x62, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x57, 0x65, 0x62, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x54, 0x5a, 0x52, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2f, 0x76, 0x31, + 0x3b, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( diff --git a/gen/proto/ts/teleport/lib/teleterm/v1/service_pb.ts b/gen/proto/ts/teleport/lib/teleterm/v1/service_pb.ts index f40c72d14ee5c..a2801abdca9d1 100644 --- a/gen/proto/ts/teleport/lib/teleterm/v1/service_pb.ts +++ b/gen/proto/ts/teleport/lib/teleterm/v1/service_pb.ts @@ -428,10 +428,6 @@ export interface ListKubernetesResourcesResponse { * @generated from protobuf field: repeated teleport.lib.teleterm.v1.KubeResource resources = 1; */ resources: KubeResource[]; - /** - * @generated from protobuf field: string next_key = 2; - */ - nextKey: string; } /** * CredentialInfo holds fields related to a user's WebAuthn credential. @@ -2537,14 +2533,12 @@ export const ListKubernetesResourcesRequest = new ListKubernetesResourcesRequest class ListKubernetesResourcesResponse$Type extends MessageType { constructor() { super("teleport.lib.teleterm.v1.ListKubernetesResourcesResponse", [ - { no: 1, name: "resources", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => KubeResource }, - { no: 2, name: "next_key", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + { no: 1, name: "resources", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => KubeResource } ]); } create(value?: PartialMessage): ListKubernetesResourcesResponse { const message = globalThis.Object.create((this.messagePrototype!)); message.resources = []; - message.nextKey = ""; if (value !== undefined) reflectionMergePartial(this, message, value); return message; @@ -2557,9 +2551,6 @@ class ListKubernetesResourcesResponse$Type extends MessageType; + fetchKubeNamespaces( + search: string, + kubeCluster: PendingListItem + ): Promise; savedResourceItems: PendingListItem[]; - bulkToggleKubeResources: ( + updateNamespacesForKubeCluster: ( resources: PendingKubeResourceItem[], resource: PendingListItem ) => void; @@ -57,7 +58,9 @@ export function KubeNamespaceSelector({ const currKubeClustersNamespaceItems = savedResourceItems.filter( resource => - resource.kind === 'namespace' && resource.id === kubeClusterItem.id + resource.kind === 'namespace' && + resource.id === kubeClusterItem.id && + resource.clusterName === kubeClusterItem.clusterName ) as PendingKubeResourceItem[]; const [selectedOpts, setSelectedOpts] = useState(() => @@ -75,22 +78,12 @@ export function KubeNamespaceSelector({ switch (actionMeta.action) { case 'clear': - bulkToggleKubeResources( - currKubeClustersNamespaceItems, - kubeClusterItem - ); + updateNamespacesForKubeCluster([], kubeClusterItem); return; case 'remove-value': - bulkToggleKubeResources( - [ - { - kind: 'namespace', - id: kubeClusterItem.id, - subResourceName: actionMeta.removedValue.value, - clusterName: kubeClusterItem.clusterName, - name: actionMeta.removedValue.value, - }, - ], + const selectedOptions = options || []; + updateNamespacesForKubeCluster( + selectedOptions.map(o => optionToKubeNamespace(o)), kubeClusterItem ); return; @@ -98,40 +91,29 @@ export function KubeNamespaceSelector({ } const handleMenuClose = () => { + const selectedOptions = selectedOpts || []; setIsMenuOpen(false); - - const currNamespaces = currKubeClustersNamespaceItems.map( - n => n.subResourceName - ); - const selectedNamespaceIds = selectedOpts.map(o => o.value); - const toKeep = selectedNamespaceIds.filter(id => - currNamespaces.includes(id) - ); - - const toInsert = selectedNamespaceIds.filter(o => !toKeep.includes(o)); - const toRemove = currNamespaces.filter(n => !toKeep.includes(n)); - - if (!toInsert.length && !toRemove.length) { - return; - } - - bulkToggleKubeResources( - [...toRemove, ...toInsert].map(namespace => ({ - kind: 'namespace', - id: kubeClusterItem.id, - subResourceName: namespace, - clusterName: kubeClusterItem.clusterName, - name: namespace, - })), + updateNamespacesForKubeCluster( + selectedOptions.map(o => optionToKubeNamespace(o)), kubeClusterItem ); }; + function optionToKubeNamespace( + selectedOption: Option + ): PendingKubeResourceItem { + const namespace = selectedOption.value; + return { + kind: 'namespace', + id: kubeClusterItem.id, + subResourceName: namespace, + clusterName: kubeClusterItem.clusterName, + name: namespace, + }; + } + async function handleLoadOptions(input: string) { - const namespaces = await fetchKubeNamespaces({ - kubeCluster: kubeClusterItem.id, - search: input, - }); + const namespaces = await fetchKubeNamespaces(input, kubeClusterItem); return namespaces.map(namespace => ({ kind: 'namespace', @@ -141,10 +123,10 @@ export function KubeNamespaceSelector({ } return ( - + null, + updateNamespacesForKubeCluster: () => null, createAttempt: { status: '' }, fetchResourceRequestRolesAttempt: { status: '' }, isResourceRequest: false, diff --git a/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/RequestCheckout.test.tsx b/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/RequestCheckout.test.tsx index 21a4dcccc23eb..23599a83f6964 100644 --- a/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/RequestCheckout.test.tsx +++ b/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/RequestCheckout.test.tsx @@ -175,5 +175,5 @@ const props: RequestCheckoutWithSliderProps = { startTime: null, onStartTimeChange: () => null, fetchKubeNamespaces: () => null, - bulkToggleKubeResources: () => null, + updateNamespacesForKubeCluster: () => null, }; diff --git a/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/RequestCheckout.tsx b/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/RequestCheckout.tsx index c6b999527cbf0..1ac5859a9274b 100644 --- a/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/RequestCheckout.tsx +++ b/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/RequestCheckout.tsx @@ -55,7 +55,6 @@ import { AccessDurationRequest } from '../../AccessDuration'; import { checkSupportForKubeResources, isKubeClusterWithNamespaces, - type KubeNamespaceRequest, } from '../kube'; import { ReviewerOption } from './types'; @@ -170,7 +169,7 @@ export function RequestCheckout({ startTime, onStartTimeChange, fetchKubeNamespaces, - bulkToggleKubeResources, + updateNamespacesForKubeCluster, }: RequestCheckoutProps) { const [reason, setReason] = useState(''); @@ -241,7 +240,7 @@ export function RequestCheckout({ function customRow(item: T) { if (item.kind === 'kube_cluster') { return ( - + ({ alignItems="center" > + {showClusterNameColumn && {item.clusterName}} {getPrettyResourceKind(item.kind)} {item.name} @@ -265,7 +265,7 @@ export function RequestCheckout({ kubeClusterItem={item} savedResourceItems={pendingAccessRequests} fetchKubeNamespaces={fetchKubeNamespaces} - bulkToggleKubeResources={bulkToggleKubeResources} + updateNamespacesForKubeCluster={updateNamespacesForKubeCluster} /> @@ -934,8 +934,8 @@ export type RequestCheckoutProps = Header?: () => JSX.Element; startTime: Date; onStartTimeChange(t?: Date): void; - fetchKubeNamespaces(p: KubeNamespaceRequest): Promise; - bulkToggleKubeResources( + fetchKubeNamespaces(search: string, kubeCluster: T): Promise; + updateNamespacesForKubeCluster( kubeResources: PendingKubeResourceItem[], kubeCluster: T ): void; diff --git a/web/packages/shared/components/AccessRequests/NewRequest/index.ts b/web/packages/shared/components/AccessRequests/NewRequest/index.ts index 9074113221b16..61c58603809d1 100644 --- a/web/packages/shared/components/AccessRequests/NewRequest/index.ts +++ b/web/packages/shared/components/AccessRequests/NewRequest/index.ts @@ -20,5 +20,4 @@ export * from './RequestCheckout'; export * from './ResourceList'; export type { ResourceMap, RequestableResourceKind } from './resource'; export { getEmptyResourceState } from './resource'; -export type { KubeNamespaceRequest } from './kube'; export { isKubeClusterWithNamespaces } from './kube'; diff --git a/web/packages/shared/components/AccessRequests/NewRequest/kube.ts b/web/packages/shared/components/AccessRequests/NewRequest/kube.ts index 299c19bec91f7..cd40f11de1ec4 100644 --- a/web/packages/shared/components/AccessRequests/NewRequest/kube.ts +++ b/web/packages/shared/components/AccessRequests/NewRequest/kube.ts @@ -20,11 +20,6 @@ import { Attempt } from 'shared/hooks/useAttemptNext'; import { PendingListItem } from './RequestCheckout'; -export type KubeNamespaceRequest = { - kubeCluster: string; - search: string; -}; - /** * Returns true if the item is a kube cluster or is a namespace * of the item. diff --git a/web/packages/teleterm/src/ui/AccessRequestCheckout/AccessRequestCheckout.tsx b/web/packages/teleterm/src/ui/AccessRequestCheckout/AccessRequestCheckout.tsx index dbcc521911839..b268277eeee4a 100644 --- a/web/packages/teleterm/src/ui/AccessRequestCheckout/AccessRequestCheckout.tsx +++ b/web/packages/teleterm/src/ui/AccessRequestCheckout/AccessRequestCheckout.tsx @@ -104,7 +104,7 @@ export function AccessRequestCheckout() { startTime, onStartTimeChange, fetchKubeNamespaces, - bulkToggleKubeResources, + updateNamespacesForKubeCluster, } = useAccessRequestCheckout(); const isRoleRequest = pendingAccessRequests[0]?.kind === 'role'; @@ -284,7 +284,7 @@ export function AccessRequestCheckout() { startTime={startTime} onStartTimeChange={onStartTimeChange} fetchKubeNamespaces={fetchKubeNamespaces} - bulkToggleKubeResources={bulkToggleKubeResources} + updateNamespacesForKubeCluster={updateNamespacesForKubeCluster} /> )} diff --git a/web/packages/teleterm/src/ui/AccessRequestCheckout/useAccessRequestCheckout.test.tsx b/web/packages/teleterm/src/ui/AccessRequestCheckout/useAccessRequestCheckout.test.tsx index fb1c3285ee53f..0abc41d0e2f46 100644 --- a/web/packages/teleterm/src/ui/AccessRequestCheckout/useAccessRequestCheckout.test.tsx +++ b/web/packages/teleterm/src/ui/AccessRequestCheckout/useAccessRequestCheckout.test.tsx @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import { renderHook, waitFor } from '@testing-library/react'; +import { renderHook, waitFor, act } from '@testing-library/react'; import { makeRootCluster, @@ -29,7 +29,9 @@ import { MockAppContextProvider } from 'teleterm/ui/fixtures/MockAppContextProvi import { mapRequestToKubeNamespaceUri } from '../services/workspacesService/accessRequestsService'; -import useAccessRequestCheckout from './useAccessRequestCheckout'; +import useAccessRequestCheckout, { + PendingListKubeClusterWithOriginalItem, +} from './useAccessRequestCheckout'; test('fetching requestable roles for servers uses UUID, not hostname', async () => { const server = makeServer(); @@ -135,18 +137,21 @@ test(`fetching requestable roles for a kube cluster's namespaces only creates re await appContext.workspacesService .getWorkspaceAccessRequestsService(rootClusterUri) - .addOrRemoveKubeNamespaces([ - mapRequestToKubeNamespaceUri({ - clusterUri: rootClusterUri, - id: kube1.name, - name: 'namespace1', - }), - mapRequestToKubeNamespaceUri({ - clusterUri: rootClusterUri, - id: kube1.name, - name: 'namespace2', - }), - ]); + .updateNamespacesForKubeCluster( + [ + mapRequestToKubeNamespaceUri({ + clusterUri: rootClusterUri, + id: kube1.name, + name: 'namespace1', + }), + mapRequestToKubeNamespaceUri({ + clusterUri: rootClusterUri, + id: kube1.name, + name: 'namespace2', + }), + ], + kube1.uri + ); jest.spyOn(appContext.tshd, 'getRequestableRoles'); @@ -187,6 +192,10 @@ test(`fetching requestable roles for a kube cluster's namespaces only creates re test('after creating an access request, pending requests and specifiable fields are reset', async () => { const kube = makeKube(); + const kube2 = makeKube({ + name: 'kube2', + uri: `${rootClusterUri}/kubes/kube2`, + }); const cluster = makeRootCluster(); const appContext = new MockAppContext(); appContext.clustersService.setState(draftState => { @@ -199,6 +208,12 @@ test('after creating an access request, pending requests and specifiable fields kind: 'kube', resource: kube, }); + await appContext.workspacesService + .getWorkspaceAccessRequestsService(rootClusterUri) + .addOrRemoveResource({ + kind: 'kube', + resource: kube2, + }); let mockedCreateAccessRequestFn = jest.spyOn( appContext.tshd, @@ -215,71 +230,220 @@ test('after creating an access request, pending requests and specifiable fields wrapper, }); - await waitFor(() => { - result.current.setSelectedReviewers([{ value: 'bob', label: 'bob' }]); - expect(result.current.selectedReviewers).toEqual([ - { value: 'bob', label: 'bob' }, - ]); - }); + await act(() => + result.current.setSelectedReviewers([{ value: 'bob', label: 'bob' }]) + ); + expect(result.current.selectedReviewers).toEqual([ + { value: 'bob', label: 'bob' }, + ]); - await waitFor(() => { - result.current.setSelectedResourceRequestRoles(['apple', 'banana']); - expect(result.current.selectedResourceRequestRoles).toEqual([ - 'apple', - 'banana', - ]); - }); + await act(() => + result.current.setSelectedResourceRequestRoles(['apple', 'banana']) + ); + expect(result.current.selectedResourceRequestRoles).toEqual([ + 'apple', + 'banana', + ]); - await waitFor(async () => { - await result.current.createRequest({ + await act(() => + result.current.createRequest({ suggestedReviewers: result.current.selectedReviewers.map(r => r.value), - }); - expect(mockedCreateAccessRequestFn).toHaveBeenCalledWith({ - rootClusterUri: '/clusters/teleport-local', - resourceIds: [ - { - clusterName: 'teleport-local', - kind: 'kube_cluster', - name: kube.name, - subResourceName: '', - }, - ], - roles: ['apple', 'banana'], - suggestedReviewers: ['bob'], - }); + }) + ); + + expect(mockedCreateAccessRequestFn).toHaveBeenCalledWith({ + rootClusterUri: '/clusters/teleport-local', + resourceIds: [ + { + clusterName: 'teleport-local', + kind: 'kube_cluster', + name: kube.name, + subResourceName: '', + }, + { + clusterName: 'teleport-local', + kind: 'kube_cluster', + name: kube2.name, + subResourceName: '', + }, + ], + roles: ['apple', 'banana'], + suggestedReviewers: ['bob'], }); + expect(result.current.requestedCount).toBe(2); // Call create again, should've cleared reviewers and previous roles. mockedCreateAccessRequestFn.mockClear(); + // A successful create would've cleared all selected resources, + // so we add it back here to allow creating again. await waitFor(async () => { - // A successful create would've cleared all selected resources, - // so we add it back here to allow creating again. expect(result.current.pendingAccessRequests).toHaveLength(0); - await appContext.workspacesService + }); + await act(() => + appContext.workspacesService .getWorkspaceAccessRequestsService(rootClusterUri) .addOrRemoveResource({ kind: 'kube', resource: kube, - }); - }); + }) + ); - await waitFor(async () => { - await result.current.createRequest({ + await act(() => + result.current.createRequest({ suggestedReviewers: result.current.selectedReviewers.map(r => r.value), + }) + ); + expect(mockedCreateAccessRequestFn).toHaveBeenCalledWith({ + rootClusterUri: '/clusters/teleport-local', + resourceIds: [ + { + clusterName: 'teleport-local', + kind: 'kube_cluster', + name: kube.name, + subResourceName: '', + }, + ], + // These fields gotten cleared after the first create. + roles: [], + suggestedReviewers: [], + }); +}); + +test('updating kube namespaces', async () => { + const kube1 = makeKube(); + + const cluster = makeRootCluster(); + const appContext = new MockAppContext(); + appContext.clustersService.setState(draftState => { + draftState.clusters.set(rootClusterUri, cluster); + }); + await appContext.workspacesService.setActiveWorkspace(rootClusterUri); + await appContext.workspacesService + .getWorkspaceAccessRequestsService(rootClusterUri) + .addOrRemoveResource({ + kind: 'kube', + resource: kube1, }); - expect(mockedCreateAccessRequestFn).toHaveBeenCalledWith({ - rootClusterUri: '/clusters/teleport-local', - resourceIds: [ + + const wrapper = ({ children }) => ( + + {children} + + ); + + let { result } = renderHook(useAccessRequestCheckout, { + wrapper, + }); + + const kubeItem: PendingListKubeClusterWithOriginalItem = { + kind: 'kube_cluster', + clusterName: 'local', + id: kube1.name, + name: kube1.name, + originalItem: { + kind: 'kube', + resource: { + uri: kube1.uri, + }, + }, + }; + + // Test order of request are retained. + await act(() => + result.current.updateNamespacesForKubeCluster( + [ { - clusterName: 'teleport-local', - kind: 'kube_cluster', - name: kube.name, - subResourceName: '', + kind: 'namespace', + clusterName: 'local', + id: kube1.name, + name: 'n3', + subResourceName: 'n3', + }, + { + kind: 'namespace', + clusterName: 'local', + id: kube1.name, + name: 'n2', + subResourceName: 'n2', + }, + { + kind: 'namespace', + clusterName: 'local', + id: kube1.name, + name: 'n1', + subResourceName: 'n1', }, ], - // These fields gotten cleared after the first create. - roles: [], - suggestedReviewers: [], - }); - }); + kubeItem + ) + ); + let savedRequestIds = result.current.pendingAccessRequests + .filter(r => r.kind === 'namespace') + .map(r => r.subResourceName); + expect(savedRequestIds).toEqual(['n3', 'n2', 'n1']); + + // Test order of request are retained a second time. + await act(() => + result.current.updateNamespacesForKubeCluster( + [ + { + kind: 'namespace', + clusterName: 'local', + id: kube1.name, + name: 'n2', + subResourceName: 'n2', + }, + { + kind: 'namespace', + clusterName: 'local', + id: kube1.name, + name: 'n1', + subResourceName: 'n1', + }, + { + kind: 'namespace', + clusterName: 'local', + id: kube1.name, + name: 'n3', + subResourceName: 'n3', + }, + ], + kubeItem + ) + ); + savedRequestIds = result.current.pendingAccessRequests + .filter(r => r.kind === 'namespace') + .map(r => r.subResourceName); + expect(savedRequestIds).toEqual(['n2', 'n1', 'n3']); + + // Test empty request clears request. + await act(() => result.current.updateNamespacesForKubeCluster([], kubeItem)); + savedRequestIds = result.current.pendingAccessRequests + .filter(r => r.kind === 'namespace') + .map(r => r.subResourceName); + expect(savedRequestIds).toEqual([]); + + // Test invalid request. + await expect( + async () => + await result.current.updateNamespacesForKubeCluster( + [ + { + kind: 'namespace', + clusterName: 'local', + id: kube1.name, + name: 'n2', + subResourceName: 'n2', + }, + { + kind: 'namespace', + clusterName: 'local', + id: 'some-id-of-different-kube-cluster-which-is-invalid', + name: 'n1', + subResourceName: 'n1', + }, + ], + kubeItem + ) + ).rejects.toThrow(); }); diff --git a/web/packages/teleterm/src/ui/AccessRequestCheckout/useAccessRequestCheckout.ts b/web/packages/teleterm/src/ui/AccessRequestCheckout/useAccessRequestCheckout.ts index 2d756ced4e197..5d110a9b46b9c 100644 --- a/web/packages/teleterm/src/ui/AccessRequestCheckout/useAccessRequestCheckout.ts +++ b/web/packages/teleterm/src/ui/AccessRequestCheckout/useAccessRequestCheckout.ts @@ -26,7 +26,6 @@ import { PendingListItem, PendingKubeResourceItem, isKubeClusterWithNamespaces, - KubeNamespaceRequest, RequestableResourceKind, } from 'shared/components/AccessRequests/NewRequest'; import { useSpecifiableFields } from 'shared/components/AccessRequests/NewRequest/useSpecifiableFields'; @@ -56,17 +55,6 @@ export default function useAccessRequestCheckout() { const ctx = useAppContext(); useWorkspaceServiceState(); ctx.clustersService.useState(); - /** - * @deprecated Do not use it here. This value comes from the cluster selector next to the search - * bar. Changing the cluster should not affect the request checkout in any way. - * clusterUri is kept here just to not break existing code that depends on it. - * See https://github.com/gravitational/teleport/issues/48510. - * - * Instead, in most cases you want to use rootClusterUri or the cluster URI derived from a URI of - * a resource that you're operating on. - */ - const clusterUri = - ctx.workspacesService?.getActiveWorkspace()?.localClusterUri; const rootClusterUri = ctx.workspacesService?.getRootClusterUri(); const { @@ -269,18 +257,19 @@ export default function useAccessRequestCheckout() { ); } - async function bulkToggleKubeResources( + function updateNamespacesForKubeCluster( items: PendingKubeResourceItem[], kubeCluster: PendingListKubeClusterWithOriginalItem ) { - await workspaceAccessRequest.addOrRemoveKubeNamespaces( + workspaceAccessRequest.updateNamespacesForKubeCluster( items.map(item => mapRequestToKubeNamespaceUri({ id: item.id, name: item.subResourceName, clusterUri: kubeCluster.originalItem.resource.uri, }) - ) + ), + kubeCluster.originalItem.resource.uri ); } @@ -338,8 +327,7 @@ export default function useAccessRequestCheckout() { ctx.clustersService.createAccessRequest(params).then(({ response }) => { return { accessRequest: response.request, - requestedCount: - pendingAccessRequestsWithoutParentResource.filter.length, + requestedCount: pendingAccessRequestsWithoutParentResource.length, }; }) ).catch(e => { @@ -419,19 +407,19 @@ export default function useAccessRequestCheckout() { } } - async function fetchKubeNamespaces({ - kubeCluster, - search, - }: KubeNamespaceRequest): Promise { + async function fetchKubeNamespaces( + search: string, + kubeCluster: PendingListKubeClusterWithOriginalItem + ): Promise { const { response } = await ctx.tshd.listKubernetesResources({ searchKeywords: search, limit: 50, useSearchAsRoles: true, nextKey: '', resourceType: 'namespace', - clusterUri: clusterUri, + clusterUri: kubeCluster.originalItem.resource.uri, predicateExpression: '', - kubernetesCluster: kubeCluster, + kubernetesCluster: kubeCluster.id, kubernetesNamespace: '', }); return response.resources.map(i => i.name); @@ -475,7 +463,7 @@ export default function useAccessRequestCheckout() { startTime, onStartTimeChange, fetchKubeNamespaces, - bulkToggleKubeResources, + updateNamespacesForKubeCluster, }; } @@ -502,7 +490,10 @@ type PendingListItemWithOriginalItem = Omit & } ); -type PendingListKubeClusterWithOriginalItem = Omit & { +export type PendingListKubeClusterWithOriginalItem = Omit< + PendingListItem, + 'kind' +> & { kind: Extract; originalItem: Extract; }; diff --git a/web/packages/teleterm/src/ui/services/workspacesService/accessRequestsService.ts b/web/packages/teleterm/src/ui/services/workspacesService/accessRequestsService.ts index e408e8244de68..0377e6dcc5cd3 100644 --- a/web/packages/teleterm/src/ui/services/workspacesService/accessRequestsService.ts +++ b/web/packages/teleterm/src/ui/services/workspacesService/accessRequestsService.ts @@ -99,7 +99,10 @@ export class AccessRequestsService { }); } - async addOrRemoveKubeNamespaces(namespaceUris: KubeResourceNamespaceUri[]) { + updateNamespacesForKubeCluster( + namespaceUris: KubeResourceNamespaceUri[], + kubeClusterUri: string + ) { this.setState(draftState => { if (draftState.pending.kind !== 'resource') { throw new Error('Cannot add a kube namespace to a role access request'); @@ -107,26 +110,21 @@ export class AccessRequestsService { const { resources } = draftState.pending; - namespaceUris.forEach(resourceUri => { - const requestedResource = resources.get( - routing.getKubeUri( - routing.parseKubeResourceNamespaceUri(resourceUri).params - ) - ); - if (!requestedResource || requestedResource.kind !== 'kube') { - throw new Error('Cannot add a kube namespace to a non-kube resource'); - } - const kubeResource = requestedResource.resource; - - if (!kubeResource.namespaces) { - kubeResource.namespaces = new Set(); - } - if (kubeResource.namespaces.has(resourceUri)) { - kubeResource.namespaces.delete(resourceUri); - } else { - kubeResource.namespaces.add(resourceUri); + // Validate each namespace uri's. + namespaceUris.forEach(namespaceUri => { + if (!routing.belongsToKube(kubeClusterUri, namespaceUri)) { + throw new Error( + 'Only namespace belonging to the same requested kube cluster can be updated' + ); } }); + + const kubeRequestedResource = resources.get(kubeClusterUri); + // This will always be true, since we validated each namespace + // URIs before this. Check is required to access namespace field + if (kubeRequestedResource.kind === 'kube') { + kubeRequestedResource.resource.namespaces = new Set(namespaceUris); + } }); } diff --git a/web/packages/teleterm/src/ui/uri.ts b/web/packages/teleterm/src/ui/uri.ts index 09aa634596773..7ee57263b8761 100644 --- a/web/packages/teleterm/src/ui/uri.ts +++ b/web/packages/teleterm/src/ui/uri.ts @@ -131,6 +131,12 @@ export const routing = { return routing.getClusterUri(params); }, + ensureKubeUri(uri: KubeResourceNamespaceUri) { + const { kubeId, rootClusterId, leafClusterId } = + routing.parseKubeResourceNamespaceUri(uri).params; + return routing.getKubeUri({ kubeId, rootClusterId, leafClusterId }); + }, + parseKubeUri(uri: string) { return routing.parseUri(uri, paths.kube); }, @@ -297,6 +303,14 @@ export const routing = { return resourceRootClusterUri === rootClusterUri; }, + + belongsToKube( + kubeClusterUri: KubeUri, + namespaceUri: KubeResourceNamespaceUri + ) { + const kubeUri = routing.ensureKubeUri(namespaceUri); + return kubeUri === kubeClusterUri; + }, }; export function isAppUri(uri: string): uri is AppUri { From 5aa9b4cfedc974bc2c13b33240eb2a6e7c5e1445 Mon Sep 17 00:00:00 2001 From: Ryan Clark Date: Thu, 14 Nov 2024 13:52:47 +0100 Subject: [PATCH 11/11] Add a button to view access path audit events in Policy (#48892) --- .../src/Audit/EventList/EventList.tsx | 21 ++++-- .../EventList/ViewInPolicyButton.test.tsx | 74 +++++++++++++++++++ .../Audit/EventList/ViewInPolicyButton.tsx | 72 ++++++++++++++++++ web/packages/teleport/src/config.ts | 10 +++ 4 files changed, 169 insertions(+), 8 deletions(-) create mode 100644 web/packages/teleport/src/Audit/EventList/ViewInPolicyButton.test.tsx create mode 100644 web/packages/teleport/src/Audit/EventList/ViewInPolicyButton.tsx diff --git a/web/packages/teleport/src/Audit/EventList/EventList.tsx b/web/packages/teleport/src/Audit/EventList/EventList.tsx index 391ea93626f4c..f01abe10e96c4 100644 --- a/web/packages/teleport/src/Audit/EventList/EventList.tsx +++ b/web/packages/teleport/src/Audit/EventList/EventList.tsx @@ -17,7 +17,7 @@ */ import React, { useState } from 'react'; -import { ButtonBorder } from 'design'; +import { ButtonBorder, Flex } from 'design'; import Table, { Cell } from 'design/DataTable'; import { dateTimeMatcher } from 'design/utils/match'; @@ -28,6 +28,8 @@ import EventDialog from '../EventDialog'; import renderTypeCell from './EventTypeCell'; +import { ViewInPolicyButton } from './ViewInPolicyButton'; + export default function EventList(props: Props) { const { events = [], fetchMore, fetchStatus, pageSize = 50 } = props; const [detailsToShow, setDetailsToShow] = useState(); @@ -84,13 +86,16 @@ export const renderActionCell = ( onShowDetails: (e: Event) => void ) => ( - onShowDetails(event)} - width="87px" - > - Details - + + + onShowDetails(event)} + width="87px" + > + Details + + ); diff --git a/web/packages/teleport/src/Audit/EventList/ViewInPolicyButton.test.tsx b/web/packages/teleport/src/Audit/EventList/ViewInPolicyButton.test.tsx new file mode 100644 index 0000000000000..1a58ab6cadb4e --- /dev/null +++ b/web/packages/teleport/src/Audit/EventList/ViewInPolicyButton.test.tsx @@ -0,0 +1,74 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { screen } from '@testing-library/react'; + +import { MemoryRouter } from 'react-router'; + +import { render } from 'design/utils/testing'; + +import { ViewInPolicyButton } from 'teleport/Audit/EventList/ViewInPolicyButton'; +import { RawEvents } from 'teleport/services/audit'; +import cfg from 'teleport/config'; + +import makeEvent from '../../services/audit/makeEvent'; + +test('should not render if the event is not in the list of supported events', () => { + const event: RawEvents['TOK005E'] = { + code: 'TOK005E', + event: 'okta.assignment.cleanup', + name: '3x_0GLrBqnzIjqaXH2ho1G3H07_7NnneUVxPZ_q1Ji4', + source: 'user-assignment-creator', + time: '2024-11-13T13:32:11.397Z', + uid: '4b9dde0c-4f1e-45d0-9a59-d970f7d28f16', + user: 'sasha', + }; + + render(); + + expect(screen.queryByRole('link')).not.toBeInTheDocument(); +}); + +test('should render a link for access path changes', () => { + const event: RawEvents['TAG001I'] = { + affected_resource_name: '2k6sycjspmhaib', + affected_resource_source: 'TELEPORT', + affected_resource_kind: 'server', + user: '', + change_id: 'f6be68d1-fa5d-4ff7-ad0b-5c1447e251a0', + code: 'TAG001I', + event: 'access_graph.access_path_changed', + time: '2024-11-13T13:53:29.983Z', + uid: '22c49326-2b72-4503-bd62-dac5ac610be6', + }; + + render( + + + + ); + + const link = screen.getByRole('link'); + + expect(link).toBeInTheDocument(); + + expect(link).toHaveProperty( + 'href', + `http://localhost${cfg.getAccessGraphCrownJewelAccessPathUrl(event.change_id)}` + ); +}); diff --git a/web/packages/teleport/src/Audit/EventList/ViewInPolicyButton.tsx b/web/packages/teleport/src/Audit/EventList/ViewInPolicyButton.tsx new file mode 100644 index 0000000000000..d1f4fc5522270 --- /dev/null +++ b/web/packages/teleport/src/Audit/EventList/ViewInPolicyButton.tsx @@ -0,0 +1,72 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import React, { useMemo } from 'react'; + +import { ButtonBorder } from 'design'; +import { NavLink } from 'react-router-dom'; + +import cfg from 'teleport/config'; + +import { + Event, + EventCode, + eventCodes, + RawEvents, +} from 'teleport/services/audit'; + +const VIEW_IN_POLICY_EVENTS: EventCode[] = [ + eventCodes.ACCESS_GRAPH_PATH_CHANGED, +]; + +function getUrlForEvent(event: RawEvents[C]) { + switch (event.code) { + case eventCodes.ACCESS_GRAPH_PATH_CHANGED: + return cfg.getAccessGraphCrownJewelAccessPathUrl(event.change_id); + } + + // eslint-disable-next-line no-console + console.warn( + 'Unsupported event code for "View in Policy" button', + event.code + ); +} + +export function ViewInPolicyButton({ event }: { event: Event }) { + const shouldShow = VIEW_IN_POLICY_EVENTS.includes(event.code); + + const url = useMemo( + () => shouldShow && getUrlForEvent(event.raw), + [shouldShow, event] + ); + + if (!shouldShow || !url) { + return null; + } + + return ( + + View in Policy + + ); +} diff --git a/web/packages/teleport/src/config.ts b/web/packages/teleport/src/config.ts index e71bac834017a..010d1c66078b7 100644 --- a/web/packages/teleport/src/config.ts +++ b/web/packages/teleport/src/config.ts @@ -205,6 +205,12 @@ const cfg = { oidcHandler: '/v1/webapi/oidc/*', samlHandler: '/v1/webapi/saml/*', githubHandler: '/v1/webapi/github/*', + + // Access Graph is part of enterprise, but we need to generate links in the audit log, + // which is in OSS. + accessGraph: { + crownJewelAccessPath: '/web/accessgraph/crownjewels/access/:id', + }, }, api: { @@ -1180,6 +1186,10 @@ const cfg = { return generatePath(cfg.api.notificationStatePath, { clusterId }); }, + getAccessGraphCrownJewelAccessPathUrl(id: string) { + return generatePath(cfg.routes.accessGraph.crownJewelAccessPath, { id }); + }, + init(backendConfig = {}) { mergeDeep(this, backendConfig); },