From 690301549829600936809e791bd19e1bd8fbd655 Mon Sep 17 00:00:00 2001 From: Thomas Hallgren Date: Thu, 2 Jan 2025 23:12:25 +0100 Subject: [PATCH 1/9] Disregard rollout rules concerning auto-inject during shutdown. When the traffic-manager shuts down, it must uninstall agents unconditionally, without concerns about the "inject" annotation. Signed-off-by: Thomas Hallgren --- cmd/traffic/cmd/manager/mutator/watcher.go | 28 ++++++++++++++-------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/cmd/traffic/cmd/manager/mutator/watcher.go b/cmd/traffic/cmd/manager/mutator/watcher.go index 1d0e73a71c..4b7987b452 100644 --- a/cmd/traffic/cmd/manager/mutator/watcher.go +++ b/cmd/traffic/cmd/manager/mutator/watcher.go @@ -6,6 +6,7 @@ import ( "slices" "strings" "sync" + "sync/atomic" "time" "github.com/google/go-cmp/cmp" @@ -104,15 +105,17 @@ func (c *configWatcher) isRolloutNeeded(ctx context.Context, wl k8sapi.Workload, // Annotation controls injection, so no explicit rollout is needed unless the deployment was added before the // traffic-manager or the traffic-manager already received an injection event but failed due to the lack // of an agent config. - if c.receivedPrematureInjectEvent(wl) { - dlog.Debugf(ctx, "Rollout of %s.%s is necessary. Pod template has inject annotation %s and a premature injection event was received", - wl.GetName(), wl.GetNamespace(), ia) - return true - } - if wl.GetCreationTimestamp().After(c.startedAt) { - dlog.Debugf(ctx, "Rollout of %s.%s is not necessary. Pod template has inject annotation %s", - wl.GetName(), wl.GetNamespace(), ia) - return false + if !c.terminating.Load() { + if c.receivedPrematureInjectEvent(wl) { + dlog.Debugf(ctx, "Rollout of %s.%s is necessary. Pod template has inject annotation %s and a premature injection event was received", + wl.GetName(), wl.GetNamespace(), ia) + return true + } + if wl.GetCreationTimestamp().After(c.startedAt) { + dlog.Debugf(ctx, "Rollout of %s.%s is not necessary. Pod template has inject annotation %s", + wl.GetName(), wl.GetNamespace(), ia) + return false + } } } podLabels := podMeta.GetLabels() @@ -457,6 +460,7 @@ type configWatcher struct { informers *xsync.MapOf[string, *informersWithCancel] startedAt time.Time rolloutDisabled bool + terminating atomic.Bool self Map // For extension } @@ -630,7 +634,11 @@ func (c *configWatcher) startWatchers(ctx context.Context, iwc *informersWithCan func (c *configWatcher) StartWatchers(ctx context.Context) error { c.startedAt = time.Now() - ctx, c.cancel = context.WithCancel(ctx) + ctx, cancel := context.WithCancel(ctx) + c.cancel = func() { + c.terminating.Store(true) + cancel() + } var errs []error c.informers.Range(func(ns string, iwc *informersWithCancel) bool { if err := c.startWatchers(ctx, iwc); err != nil { From c56d774fd3f01af28b59ceafd1ca50aa47ea883f Mon Sep 17 00:00:00 2001 From: Thomas Hallgren Date: Tue, 31 Dec 2024 04:36:02 +0100 Subject: [PATCH 2/9] Don't have telepresence connected when running genyaml test. Signed-off-by: Thomas Hallgren --- integration_test/agent_injector_disabled_test.go | 2 -- integration_test/manual_agent_test.go | 7 +++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/integration_test/agent_injector_disabled_test.go b/integration_test/agent_injector_disabled_test.go index fc4a50455b..941a31e678 100644 --- a/integration_test/agent_injector_disabled_test.go +++ b/integration_test/agent_injector_disabled_test.go @@ -81,7 +81,5 @@ func (s *agentInjectorDisabledSuite) Test_VersionWithAgentInjectorDisabled() { } func (s *agentInjectorDisabledSuite) Test_ManualAgent() { - s.TelepresenceConnect(s.Context()) - defer itest.TelepresenceQuitOk(s.Context()) testManualAgent(&s.Suite, s.NamespacePair) } diff --git a/integration_test/manual_agent_test.go b/integration_test/manual_agent_test.go index 63d21b0785..daf2991c91 100644 --- a/integration_test/manual_agent_test.go +++ b/integration_test/manual_agent_test.go @@ -17,8 +17,8 @@ import ( "github.com/telepresenceio/telepresence/v2/pkg/agentconfig" ) -func (s *connectedSuite) Test_ManualAgent() { - testManualAgent(&s.Suite, s.NamespacePair) +func (s *notConnectedSuite) Test_ManualAgent() { + testManualAgent(&s.Suite, s) } func testManualAgent(s *itest.Suite, nsp itest.NamespacePair) { @@ -141,6 +141,9 @@ func testManualAgent(s *itest.Suite, nsp itest.NamespacePair) { err = nsp.RolloutStatusWait(ctx, "deploy/"+ac.WorkloadName) require.NoError(err) + nsp.TelepresenceConnect(ctx) + defer itest.TelepresenceQuitOk(ctx) + stdout = itest.TelepresenceOk(ctx, "list") require.Regexp(regexp.MustCompile(`.*`+ac.WorkloadName+`\s*:\s*ready to intercept \(traffic-agent already installed\).*`), stdout) From dd95d1549099c841c388bdc13e5f1a016c936aee Mon Sep 17 00:00:00 2001 From: Thomas Hallgren Date: Mon, 30 Dec 2024 23:54:35 +0100 Subject: [PATCH 3/9] Remove the dormant container during intercept with --replace. There's no need to have a dormant container because the traffic-agent can serve as the replacement itself. That way, there's no need to redirect ports either, which means that there's no need to rename ports or use an init-container. An annotation is added to the pod to cater for when multiple injections happen due to replace-policy, so that injections that follow the one when an app-container is removed can reproduce the traffic-agent container, taking its ports, mounts, and environment into account. Closes #3758 Signed-off-by: Thomas Hallgren --- CHANGELOG.yml | 10 ++ cmd/traffic/cmd/agent/agent.go | 42 ++++-- cmd/traffic/cmd/agent/server.go | 2 +- .../cmd/manager/mutator/agent_injector.go | 130 +++++++++--------- cmd/traffic/cmd/manager/mutator/watcher.go | 23 ++-- docs/release-notes.md | 12 ++ docs/release-notes.mdx | 10 ++ integration_test/container_test.go | 18 +-- integration_test/intercept_flags_test.go | 4 +- pkg/agentconfig/container.go | 82 +++++++++-- pkg/agentconfig/sidecar.go | 1 + pkg/client/cli/cmd/genyaml.go | 2 +- pkg/forwarder/tcp.go | 12 +- pkg/forwarder/udp.go | 5 + 14 files changed, 220 insertions(+), 133 deletions(-) diff --git a/CHANGELOG.yml b/CHANGELOG.yml index 0da741bb45..69fe80ba4a 100644 --- a/CHANGELOG.yml +++ b/CHANGELOG.yml @@ -44,6 +44,16 @@ items: values: `. ``` docs: install/manager#static-versus-dynamic-namespace-selection + - type: feature + title: Removal of the dormant container during intercept with --replace. + body: |- + During a `telepresence intercept --replace operation`, the previously injected dormant container has been + removed. The Traffic Agent now directly serves as the replacement container, eliminating the need to forward + traffic to the original application container. This simplification offers several advantages when using the + `--replace` flag: + + - **Removal of the init-container:** The need for a separate init-container is no longer necessary. + - **Elimination of port renames:** Port renames within the intercepted pod are no longer required. - type: change title: Drop deprecated current-cluster-id command. body: >- diff --git a/cmd/traffic/cmd/agent/agent.go b/cmd/traffic/cmd/agent/agent.go index 460c0b99e0..b7ed492208 100644 --- a/cmd/traffic/cmd/agent/agent.go +++ b/cmd/traffic/cmd/agent/agent.go @@ -163,31 +163,43 @@ func sidecar(ctx context.Context, s State, info *rpc.AgentInfo) error { // Group the container's intercepts by agent port icStates := make(map[agentconfig.PortAndProto][]*agentconfig.Intercept, len(cn.Intercepts)) for _, ic := range cn.Intercepts { - k := agentconfig.PortAndProto{Port: ic.AgentPort, Proto: ic.Protocol} + ap := ic.AgentPort + if cn.Replace { + // Listen to replaced container's original port. + ap = ic.ContainerPort + } + k := agentconfig.PortAndProto{Port: ap, Proto: ic.Protocol} icStates[k] = append(icStates[k], ic) } for pp, ics := range icStates { ic := ics[0] // They all have the same protocol container port, so the first one will do. - var cp uint16 - if ic.TargetPortNumeric { - // We must differentiate between connections originating from the agent's forwarder to the container - // port and those from other sources. The former should not be routed back, while the latter should - // always be routed to the agent. We do this by using a proxy port that will be recognized by the - // iptables filtering in our init-container. - cp = ac.ProxyPort(ic) - } else { - cp = ic.ContainerPort - } lisAddr, err := pp.Addr() if err != nil { return err } - // Redirect non-intercepted traffic to the pod, so that injected sidecars that hijack the ports for - // incoming connections will continue to work. - targetHost := s.PodIP() - fwd := forwarder.NewInterceptor(lisAddr, targetHost, cp) + var fwd forwarder.Interceptor + var cp uint16 + if !cn.Replace { + if ic.TargetPortNumeric { + // We must differentiate between connections originating from the agent's forwarder to the container + // port and those from other sources. The former should not be routed back, while the latter should + // always be routed to the agent. We do this by using a proxy port that will be recognized by the + // iptables filtering in our init-container. + cp = ac.ProxyPort(ic) + } else { + cp = ic.ContainerPort + } + // Redirect non-intercepted traffic to the pod, so that injected sidecars that hijack the ports for + // incoming connections will continue to work. + targetHost := s.PodIP() + fwd = forwarder.NewInterceptor(lisAddr, targetHost, cp) + } else { + fwd = forwarder.NewInterceptor(lisAddr, "", 0) + cp = ic.ContainerPort + } + dgroup.ParentGroup(ctx).Go(fmt.Sprintf("forward-%s", iputil.JoinHostPort(cn.Name, cp)), func(ctx context.Context) error { return fwd.Serve(tunnel.WithPool(ctx, tunnel.NewPool()), nil) }) diff --git a/cmd/traffic/cmd/agent/server.go b/cmd/traffic/cmd/agent/server.go index a75ddc5a04..49b90111cb 100644 --- a/cmd/traffic/cmd/agent/server.go +++ b/cmd/traffic/cmd/agent/server.go @@ -118,7 +118,7 @@ func (s *state) ReportMetrics(ctx context.Context, metrics *rpc.TunnelMetrics) { mCtx, mCancel := context.WithTimeout(context.WithoutCancel(ctx), time.Second) defer mCancel() _, err := s.manager.ReportMetrics(mCtx, metrics) - if err != nil { + if err != nil && status.Code(err) != codes.Canceled { dlog.Errorf(ctx, "ReportMetrics failed: %v", err) } }() diff --git a/cmd/traffic/cmd/manager/mutator/agent_injector.go b/cmd/traffic/cmd/manager/mutator/agent_injector.go index 25559a44a0..5cb0cc8e40 100644 --- a/cmd/traffic/cmd/manager/mutator/agent_injector.go +++ b/cmd/traffic/cmd/manager/mutator/agent_injector.go @@ -10,6 +10,8 @@ import ( "sync" "sync/atomic" + "github.com/go-json-experiment/json" + "github.com/go-json-experiment/json/jsontext" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" admission "k8s.io/api/admission/v1" @@ -190,15 +192,17 @@ func (a *agentInjector) Inject(ctx context.Context, req *admission.AdmissionRequ } var patches PatchOps + var annotations map[string]string config := scx.AgentConfig() - patches = disableAppContainer(ctx, pod, config, patches) patches = addInitContainer(pod, config, patches) - patches = addAgentContainer(ctx, pod, config, patches) + patches, annotations = addAgentContainer(ctx, pod, config, patches) patches = addPullSecrets(pod, config, patches) patches = addAgentVolumes(pod, config, patches) patches = hidePorts(pod, config, patches) - patches = addPodAnnotations(ctx, pod, patches) + annotations[agentconfig.InjectAnnotation] = "enabled" + patches = addPodAnnotations(pod, annotations, patches) patches = addPodLabels(ctx, pod, config, patches) + patches = maybeRemoveAppContainer(pod, config, patches) if config.APIPort != 0 { tpEnv := make(map[string]string) @@ -209,6 +213,16 @@ func (a *agentInjector) Inject(ctx context.Context, req *admission.AdmissionRequ // Create patch operations to add the traffic-agent sidecar if len(patches) > 0 { dlog.Infof(ctx, "Injecting %d patches into pod %s.%s", len(patches), pod.Name, pod.Namespace) + if dlog.MaxLogLevel(ctx) >= dlog.LogLevelDebug { + cns := strings.Builder{} + for i, cn := range pod.Spec.Containers { + cns.WriteString(fmt.Sprintf("%d %s\n", i, cn.Name)) + } + dlog.Debugf(ctx, "Containers \n%s", cns.String()) + if pj, err := json.Marshal(patches, jsontext.WithIndent(" ")); err == nil { + dlog.Debugf(ctx, "\n%s", string(pj)) + } + } } else { dlog.Infof(ctx, "Pod %s.%s was left untouched", pod.Name, pod.Namespace) } @@ -224,61 +238,27 @@ func (a *agentInjector) Uninstall(ctx context.Context) { func needInitContainer(config *agentconfig.Sidecar) bool { for _, cc := range config.Containers { - for _, ic := range cc.Intercepts { - if ic.Headless || ic.TargetPortNumeric { - return true + if !cc.Replace { + for _, ic := range cc.Intercepts { + if ic.Headless || ic.TargetPortNumeric { + return true + } } } } return false } -const sleeperImage = "alpine:latest" - -var sleeperArgs = []string{"sleep", "infinity"} //nolint:gochecknoglobals // constant - -func disableAppContainer(ctx context.Context, pod *core.Pod, config *agentconfig.Sidecar, patches PatchOps) PatchOps { -podContainers: - for i, pc := range pod.Spec.Containers { +func maybeRemoveAppContainer(pod *core.Pod, config *agentconfig.Sidecar, patches PatchOps) PatchOps { + // Extremely important to remove in reverse order, or one may affect the index of the next removal. + cns := pod.Spec.Containers + for i := len(cns) - 1; i >= 0; i-- { for _, cc := range config.Containers { - if cc.Name == pc.Name && cc.Replace { - if pc.Image == sleeperImage && slices.Equal(pc.Args, sleeperArgs) { - continue podContainers - } - patches = append(patches, PatchOperation{ - Op: "replace", - Path: fmt.Sprintf("/spec/containers/%d/image", i), - Value: sleeperImage, - }) - argsOp := "add" - if len(pc.Args) > 0 { - argsOp = "replace" - } + if cc.Name == cns[i].Name && cc.Replace { patches = append(patches, PatchOperation{ - Op: argsOp, - Path: fmt.Sprintf("/spec/containers/%d/args", i), - Value: sleeperArgs, + Op: "remove", + Path: fmt.Sprintf("/spec/containers/%d", i), }) - if pc.StartupProbe != nil { - patches = append(patches, PatchOperation{ - Op: "remove", - Path: fmt.Sprintf("/spec/containers/%d/startupProbe", i), - }) - } - if pc.LivenessProbe != nil { - patches = append(patches, PatchOperation{ - Op: "remove", - Path: fmt.Sprintf("/spec/containers/%d/livenessProbe", i), - }) - } - if pc.ReadinessProbe != nil { - patches = append(patches, PatchOperation{ - Op: "remove", - Path: fmt.Sprintf("/spec/containers/%d/readinessProbe", i), - }) - } - dlog.Debugf(ctx, "Disabled container %s", pc.Name) - continue podContainers } } } @@ -417,8 +397,18 @@ func compareVolumeMounts(a, b []core.VolumeMount) bool { return eq } -func containerEqual(a, b *core.Container) bool { +func containerEqual(ctx context.Context, a, b *core.Container) bool { // skips contain defaults assigned by Kubernetes that are not zero values + if dlog.MaxLogLevel(ctx) >= dlog.LogLevelDebug { + diff := cmp.Diff(a, b, + cmp.Comparer(compareProbes), + cmp.Comparer(compareVolumeMounts), + cmpopts.IgnoreFields(core.Container{}, "ImagePullPolicy", "Resources", "TerminationMessagePath", "TerminationMessagePolicy")) + if diff != "" { + dlog.Debug(ctx, diff) + } + return diff == "" + } return cmp.Equal(a, b, cmp.Comparer(compareProbes), cmp.Comparer(compareVolumeMounts), @@ -431,26 +421,26 @@ func addAgentContainer( pod *core.Pod, config *agentconfig.Sidecar, patches PatchOps, -) PatchOps { - acn := agentconfig.AgentContainer(ctx, pod, config) +) (PatchOps, map[string]string) { + acn, replaceAnnotations := agentconfig.AgentContainer(ctx, pod, config) if acn == nil { - return patches + return patches, replaceAnnotations } refPodName := pod.Name + "." + pod.Namespace for i := range pod.Spec.Containers { pcn := &pod.Spec.Containers[i] if pcn.Name == agentconfig.ContainerName { - if containerEqual(pcn, acn) { + if containerEqual(ctx, pcn, acn) { dlog.Infof(ctx, "Pod %s already has container %s and it isn't modified", refPodName, agentconfig.ContainerName) - return patches + return patches, replaceAnnotations } dlog.Debugf(ctx, "Pod %s already has container %s but it is modified", refPodName, agentconfig.ContainerName) return append(patches, PatchOperation{ Op: "replace", Path: "/spec/containers/" + strconv.Itoa(i), Value: acn, - }) + }), replaceAnnotations } } @@ -458,7 +448,7 @@ func addAgentContainer( Op: "add", Path: "/spec/containers/-", Value: acn, - }) + }), replaceAnnotations } // addAgentContainer creates a patch operation to add the traffic-agent container. @@ -499,7 +489,9 @@ func addPullSecrets( // addTPEnv adds telepresence specific environment variables to all interceptable app containers. func addTPEnv(pod *core.Pod, config *agentconfig.Sidecar, env map[string]string, patches PatchOps) PatchOps { agentconfig.EachContainer(pod, config, func(app *core.Container, cc *agentconfig.Container) { - patches = addContainerTPEnv(pod, app, env, patches) + if !cc.Replace { + patches = addContainerTPEnv(pod, app, env, patches) + } }) return patches } @@ -556,12 +548,14 @@ func addContainerTPEnv(pod *core.Pod, cn *core.Container, env map[string]string, // the same replacement on all references to that port from the probes of the container. func hidePorts(pod *core.Pod, config *agentconfig.Sidecar, patches PatchOps) PatchOps { agentconfig.EachContainer(pod, config, func(app *core.Container, cc *agentconfig.Container) { - for _, ic := range agentconfig.PortUniqueIntercepts(cc) { - if ic.Headless || ic.TargetPortNumeric { - // Rely on iptables mapping instead of port renames - continue + if !cc.Replace { + for _, ic := range agentconfig.PortUniqueIntercepts(cc) { + if ic.Headless || ic.TargetPortNumeric { + // Rely on iptables mapping instead of port renames + continue + } + patches = hideContainerPorts(pod, app, bool(cc.Replace), ic.ContainerPortName, patches) } - patches = hideContainerPorts(pod, app, bool(cc.Replace), ic.ContainerPortName, patches) } }) return patches @@ -616,7 +610,7 @@ func hideContainerPorts(pod *core.Pod, app *core.Container, isReplace bool, port return patches } -func addPodAnnotations(_ context.Context, pod *core.Pod, patches PatchOps) PatchOps { +func addPodAnnotations(pod *core.Pod, anns map[string]string, patches PatchOps) PatchOps { op := "replace" changed := false am := pod.Annotations @@ -627,9 +621,11 @@ func addPodAnnotations(_ context.Context, pod *core.Pod, patches PatchOps) Patch am = maps.Copy(am) } - if _, ok := pod.Annotations[agentconfig.InjectAnnotation]; !ok { - changed = true - am[agentconfig.InjectAnnotation] = "enabled" + for k, v := range anns { + if _, ok := pod.Annotations[k]; !ok { + changed = true + am[k] = v + } } if changed { diff --git a/cmd/traffic/cmd/manager/mutator/watcher.go b/cmd/traffic/cmd/manager/mutator/watcher.go index 4b7987b452..aeef5ef6c7 100644 --- a/cmd/traffic/cmd/manager/mutator/watcher.go +++ b/cmd/traffic/cmd/manager/mutator/watcher.go @@ -30,6 +30,7 @@ import ( "github.com/telepresenceio/telepresence/v2/pkg/agentmap" "github.com/telepresenceio/telepresence/v2/pkg/informer" "github.com/telepresenceio/telepresence/v2/pkg/k8sapi" + "github.com/telepresenceio/telepresence/v2/pkg/maps" "github.com/telepresenceio/telepresence/v2/pkg/workload" ) @@ -198,8 +199,8 @@ func isRolloutNeededForPod(ctx context.Context, ac *agentconfig.Sidecar, name, n return fmt.Sprintf("Rollout of %s.%s is necessary. An agent is desired but the pod %s doesn't have one", name, namespace, pod.GetName()) } - desiredAc := agentconfig.AgentContainer(ctx, pod, ac) - if !containerEqual(podAc, desiredAc) { + desiredAc, anns := agentconfig.AgentContainer(ctx, pod, ac) + if !(containerEqual(ctx, podAc, desiredAc) && maps.Equal(anns, pod.ObjectMeta.Annotations)) { return fmt.Sprintf("Rollout of %s.%s is necessary. The desired agent is not equal to the existing agent in pod %s", name, namespace, pod.GetName()) } @@ -224,22 +225,14 @@ func isRolloutNeededForPod(ctx context.Context, ac *agentconfig.Sidecar, name, n break } } - if found == nil { - return fmt.Sprintf("Rollout of %s.%s is necessary. The desired pod should contain container %s", - name, namespace, cn.Name) - } if cn.Replace { - // Ensure that the replaced container is disabled - if !(found.Image == sleeperImage && slices.Equal(found.Args, sleeperArgs)) { - return fmt.Sprintf("Rollout of %s.%s is necessary. The desired pod's container %s should be disabled", - name, namespace, cn.Name) - } - } else { - // Ensure that the replaced container is not disabled - if found.Image == sleeperImage && slices.Equal(found.Args, sleeperArgs) { - return fmt.Sprintf("Rollout of %s.%s is necessary. The desired pod's container %s should not be disabled", + if found != nil { + return fmt.Sprintf("Rollout of %s.%s is necessary. The %s container must be replaced", name, namespace, cn.Name) } + } else if found == nil { + return fmt.Sprintf("Rollout of %s.%s is necessary. The %s container should not be replaced", + name, namespace, cn.Name) } } return "" diff --git a/docs/release-notes.md b/docs/release-notes.md index 3769757cc6..df85a17f93 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -20,6 +20,18 @@ namespaceSelector: ``` +##
feature
Removal of the dormant container during intercept with --replace.
+
+ +During a `telepresence intercept --replace operation`, the previously injected dormant container has been +removed. The Traffic Agent now directly serves as the replacement container, eliminating the need to forward +traffic to the original application container. This simplification offers several advantages when using the +`--replace` flag: + +- **Removal of the init-container:** The need for a separate init-container is no longer necessary. +- **Elimination of port renames:** Port renames within the intercepted pod are no longer required. +
+ ##
change
Drop deprecated current-cluster-id command.
diff --git a/docs/release-notes.mdx b/docs/release-notes.mdx index 16edc47f5a..195248368e 100644 --- a/docs/release-notes.mdx +++ b/docs/release-notes.mdx @@ -24,6 +24,16 @@ namespaceSelector: values: `. ``` + + Removal of the dormant container during intercept with --replace. + During a `telepresence intercept --replace operation`, the previously injected dormant container has been +removed. The Traffic Agent now directly serves as the replacement container, eliminating the need to forward +traffic to the original application container. This simplification offers several advantages when using the +`--replace` flag: + +- **Removal of the init-container:** The need for a separate init-container is no longer necessary. +- **Elimination of port renames:** Port renames within the intercepted pod are no longer required. + Drop deprecated current-cluster-id command. The clusterID was deprecated some time ago, and replaced by the ID of the namespace where the traffic-manager is installed. diff --git a/integration_test/container_test.go b/integration_test/container_test.go index af2f9bc00c..c0ebf1f2f3 100644 --- a/integration_test/container_test.go +++ b/integration_test/container_test.go @@ -140,21 +140,9 @@ func (s *connectedSuite) Test_InterceptsContainerAndReplace() { Items []core.Pod `json:"items"` }{} require.NoError(json.Unmarshal([]byte(stdout), &items)) - pods := items.Items - var echoContainer *core.Container - for pi := range pods { - cns := pods[pi].Spec.Containers - for ci := range cns { - container := &cns[ci] - if container.Name == "echo" { - echoContainer = container - break - } - } - } - require.NotNil(echoContainer) - require.Equal(echoContainer.Image, "alpine:latest") - require.True(slices.Equal(echoContainer.Args, []string{"sleep", "infinity"})) + require.False(slices.ContainsFunc(items.Items, func(pod core.Pod) bool { + return slices.ContainsFunc(pod.Spec.Containers, func(container core.Container) bool { return container.Name == "echo" }) + })) // Intercept again, this time without the --container flag itest.TelepresenceOk(ctx, "leave", svc) diff --git a/integration_test/intercept_flags_test.go b/integration_test/intercept_flags_test.go index 7b7189d200..f652685af7 100644 --- a/integration_test/intercept_flags_test.go +++ b/integration_test/intercept_flags_test.go @@ -59,10 +59,10 @@ func (s *interceptFlagSuite) TearDownSuite() { // Test_ContainerReplace tests that: // // - Two containers in a pod can be intercepted in sequence. One with replace, and one without. -// - Containers can be intercepted interchangeably with or without --replace +// - Containers can be intercepted interchangeably with or without --replace // - Volumes are mounted // - Intercept responses are produced from the intercept handlers -// - Responses after the intercepts end are from the cluster +// - Responses after the intercept ends are from the cluster func (s *interceptFlagSuite) Test_ContainerReplace() { ctx := s.Context() diff --git a/pkg/agentconfig/container.go b/pkg/agentconfig/container.go index 07de961ec8..ed4cf40cdd 100644 --- a/pkg/agentconfig/container.go +++ b/pkg/agentconfig/container.go @@ -19,21 +19,28 @@ func AgentContainer( ctx context.Context, pod *core.Pod, config *Sidecar, -) *core.Container { +) (*core.Container, map[string]string) { ports := make([]core.ContainerPort, 0, 5) - for _, cc := range config.Containers { - for _, ic := range PortUniqueIntercepts(cc) { - ports = append(ports, core.ContainerPort{ - Name: ic.ContainerPortName, - ContainerPort: int32(ic.AgentPort), - Protocol: ic.Protocol, - }) + confCns := ConfiguredContainers(ctx, pod, config) + + eachConfiguredContainer(confCns, config, func(app *core.Container, cc *Container) { + if cc.Replace { + // Simply inherit the ports of the replaced container + ports = append(ports, app.Ports...) + } else { + for _, ic := range PortUniqueIntercepts(cc) { + ports = append(ports, core.ContainerPort{ + Name: ic.ContainerPortName, + ContainerPort: int32(ic.AgentPort), + Protocol: ic.Protocol, + }) + } } - } + }) evs := make([]core.EnvVar, 0, len(config.Containers)*5) efs := make([]core.EnvFromSource, 0, len(config.Containers)*3) - EachContainer(pod, config, func(app *core.Container, cc *Container) { + eachConfiguredContainer(confCns, config, func(app *core.Container, cc *Container) { evs = appendAppContainerEnv(app, cc, evs) efs = appendAppContainerEnvFrom(app, cc, efs) }) @@ -71,7 +78,7 @@ func AgentContainer( dlog.Errorf(ctx, "unable to parse agent version from image name %s", config.AgentImage) } } - EachContainer(pod, config, func(app *core.Container, cc *Container) { + eachConfiguredContainer(confCns, config, func(app *core.Container, cc *Container) { var volPaths []string volPaths, mounts = appendAppContainerVolumeMounts(app, cc, mounts, pod.ObjectMeta.Annotations, agentVersion) if len(volPaths) > 0 { @@ -130,6 +137,18 @@ func AgentContainer( efs = nil } + replaceAnnotations := make(map[string]string) + eachConfiguredContainer(confCns, config, func(app *core.Container, cc *Container) { + if cc.Replace { + cnJson, err := json.Marshal(app) + if err != nil { + dlog.Errorf(ctx, "unable to marshal container %s.%s/%s to json: %v", config.WorkloadName, config.Namespace, app.Name, err) + } else { + replaceAnnotations[ReplacedContainerAnnotationPrefix+cc.Name] = string(cnJson) + } + } + }) + ac := &core.Container{ Name: ContainerName, Image: config.AgentImage, @@ -158,15 +177,15 @@ func AgentContainer( appSc, err = firstAppSecurityContext(pod, config) if err != nil { dlog.Error(ctx, err) - return nil + return nil, nil } } ac.SecurityContext = appSc - return ac + return ac, replaceAnnotations } -// Find security context of the first container (with both intercepts and a set security context) and ensure +// Find the security context of the first container (with both intercepts and a set security context) and ensure // that any env interpolations in it are prefixed with the env-prefix of the corresponding config container. func firstAppSecurityContext(pod *core.Pod, config *Sidecar) (*core.SecurityContext, error) { cns := pod.Spec.Containers @@ -313,6 +332,41 @@ func appendSecretVolume(env dos.Env, annotation, volumeName string, pod *core.Po return volumes } +// ConfiguredContainers will find each container in the given config and match it against a container +// in the pod using its name. The returned slice is guaranteed to use the same index as the Sidecar.Containers slice. +func ConfiguredContainers(ctx context.Context, pod *core.Pod, config *Sidecar) []*core.Container { + cns := pod.Spec.Containers + result := make([]*core.Container, len(config.Containers)) + for ci, cc := range config.Containers { + for i := range cns { + app := &cns[i] + if app.Name == ContainerName { + // The pod might hold JSON of replaced containers from an earlier patch + annName := ReplacedContainerAnnotationPrefix + cc.Name + if appJson, ok := pod.ObjectMeta.Annotations[annName]; ok { + var cn core.Container + err := json.Unmarshal([]byte(appJson), &cn) + if err != nil { + dlog.Errorf(ctx, "failed to unmarshal container annotation %s: %v", annName, err) + } + result[ci] = &cn + break + } + } else if app.Name == cc.Name { + result[ci] = app + break + } + } + } + return result +} + +func eachConfiguredContainer(configureContainers []*core.Container, config *Sidecar, f func(*core.Container, *Container)) { + for i, cn := range configureContainers { + f(cn, config.Containers[i]) + } +} + // EachContainer will find each container in the given config and match it against a container // in the pod using its name. The given function is called once for each match. func EachContainer(pod *core.Pod, config *Sidecar, f func(*core.Container, *Container)) { diff --git a/pkg/agentconfig/sidecar.go b/pkg/agentconfig/sidecar.go index 44ecd7c4d4..e09fbd4292 100644 --- a/pkg/agentconfig/sidecar.go +++ b/pkg/agentconfig/sidecar.go @@ -47,6 +47,7 @@ const ( InjectIgnoreVolumeMounts = DomainPrefix + "inject-ignore-volume-mounts" TerminatingTLSSecretAnnotation = DomainPrefix + "inject-terminating-tls-secret" OriginatingTLSSecretAnnotation = DomainPrefix + "inject-originating-tls-secret" + ReplacedContainerAnnotationPrefix = DomainPrefix + "replaced-container." LegacyTerminatingTLSSecretAnnotation = "getambassador.io/inject-terminating-tls-secret" LegacyOriginatingTLSSecretAnnotation = "getambassador.io/inject-originating-tls-secret" WorkloadNameLabel = "telepresence.io/workloadName" diff --git a/pkg/client/cli/cmd/genyaml.go b/pkg/client/cli/cmd/genyaml.go index 85ae13f9db..614ec6fb1f 100644 --- a/pkg/client/cli/cmd/genyaml.go +++ b/pkg/client/cli/cmd/genyaml.go @@ -361,7 +361,7 @@ func (g *genContainerInfo) run(cmd *cobra.Command, kubeFlags map[string]string) } podTpl := wl.GetPodTemplate() - agentContainer := agentconfig.AgentContainer( + agentContainer, _ := agentconfig.AgentContainer( ctx, &core.Pod{ TypeMeta: meta.TypeMeta{ diff --git a/pkg/forwarder/tcp.go b/pkg/forwarder/tcp.go index 57fe46336f..d43aeaa19b 100644 --- a/pkg/forwarder/tcp.go +++ b/pkg/forwarder/tcp.go @@ -97,6 +97,15 @@ func (f *tcp) forwardConn(clientConn *net.TCPConn) error { return f.interceptConn(ctx, clientConn, intercept) } + defer dlog.Debug(ctx, "Done forwarding") + defer clientConn.Close() + + if targetPort == 0 { + dlog.Debug(ctx, "Forwarding to /dev/null") + _, _ = io.Copy(io.Discard, clientConn) + return nil + } + targetAddr, err := net.ResolveTCPAddr("tcp", iputil.JoinHostPort(targetHost, targetPort)) if err != nil { return fmt.Errorf("error on resolve(%s): %w", iputil.JoinHostPort(targetHost, targetPort), err) @@ -105,9 +114,6 @@ func (f *tcp) forwardConn(clientConn *net.TCPConn) error { ctx = dlog.WithField(ctx, "target", targetAddr.String()) dlog.Debug(ctx, "Forwarding...") - defer dlog.Debug(ctx, "Done forwarding") - - defer clientConn.Close() targetConn, err := net.DialTCP("tcp", nil, targetAddr) if err != nil { diff --git a/pkg/forwarder/udp.go b/pkg/forwarder/udp.go index 9b5b5709b7..59ff3ddeea 100644 --- a/pkg/forwarder/udp.go +++ b/pkg/forwarder/udp.go @@ -82,6 +82,11 @@ func (f *udp) forward(ctx context.Context, conn *net.UDPConn, intercept *manager f.interceptConn(ctx, conn, intercept) return nil } + + if f.targetPort == 0 { + dlog.Debug(ctx, "Forwarding to /dev/null") + return nil + } return f.forwardConn(ctx, conn) } From d05ae466c8f9c79cf1b4de2c080c01cf80a5e23b Mon Sep 17 00:00:00 2001 From: Thomas Hallgren Date: Wed, 1 Jan 2025 14:44:14 +0100 Subject: [PATCH 4/9] Get rid of some more net.IP usage in favor of netip.Addr. The `tunnel.ConnID` still used the `net.IP`. This commit changes the constructor to use `netip.AddrPort` for host and destination instead of separate combos of `net.IP` and `uint16`. Signed-off-by: Thomas Hallgren --- cmd/traffic/cmd/agent/agent.go | 13 +-- cmd/traffic/cmd/agent/state_test.go | 7 +- cmd/traffic/cmd/agentinit/agent_init.go | 22 +++-- cmd/traffic/cmd/manager/cluster/info.go | 6 +- cmd/traffic/cmd/manager/service.go | 8 +- cmd/traffic/cmd/manager/state/state.go | 14 +-- integration_test/itest/cluster.go | 6 +- pkg/agentconfig/portandproto.go | 13 +-- pkg/authenticator/mocks/clientconfig_mock.go | 2 +- .../mocks/credentialsresolver_mock.go | 2 +- pkg/client/cli/intercept/state.go | 3 +- pkg/client/remotefs/bridge.go | 16 ++-- pkg/client/remotefs/ftp.go | 21 ++--- pkg/client/remotefs/mounter.go | 4 +- pkg/client/remotefs/sftp.go | 13 +-- pkg/client/rootd/dns/server.go | 16 ++-- pkg/client/rootd/stream_creator.go | 18 ++-- pkg/client/userd/trafficmgr/mount.go | 15 ++- pkg/client/userd/trafficmgr/podaccess.go | 13 ++- pkg/forwarder/interceptor.go | 23 +++-- pkg/forwarder/tcp.go | 48 ++++++---- pkg/forwarder/udp.go | 34 ++++--- pkg/iputil/parse.go | 29 ++---- pkg/routing/routing_darwin.go | 9 +- pkg/tunnel/connid.go | 92 +++++++++---------- pkg/tunnel/dialer.go | 2 +- pkg/tunnel/stream_test.go | 6 +- pkg/tunnel/udplistener.go | 2 +- pkg/vif/stack.go | 10 +- 29 files changed, 236 insertions(+), 231 deletions(-) diff --git a/cmd/traffic/cmd/agent/agent.go b/cmd/traffic/cmd/agent/agent.go index b7ed492208..5e6b05046f 100644 --- a/cmd/traffic/cmd/agent/agent.go +++ b/cmd/traffic/cmd/agent/agent.go @@ -95,11 +95,11 @@ func sftpServer(ctx context.Context, sftpPortCh chan<- uint16) error { _ = l.Close() }() - _, sftpPort, err := iputil.SplitToIPPort(l.Addr()) + ap, err := iputil.SplitToIPPort(l.Addr()) if err != nil { return err } - sftpPortCh <- sftpPort + sftpPortCh <- ap.Port() dlog.Infof(ctx, "Listening at: %s", l.Addr()) for { @@ -174,11 +174,6 @@ func sidecar(ctx context.Context, s State, info *rpc.AgentInfo) error { for pp, ics := range icStates { ic := ics[0] // They all have the same protocol container port, so the first one will do. - lisAddr, err := pp.Addr() - if err != nil { - return err - } - var fwd forwarder.Interceptor var cp uint16 if !cn.Replace { @@ -194,9 +189,9 @@ func sidecar(ctx context.Context, s State, info *rpc.AgentInfo) error { // Redirect non-intercepted traffic to the pod, so that injected sidecars that hijack the ports for // incoming connections will continue to work. targetHost := s.PodIP() - fwd = forwarder.NewInterceptor(lisAddr, targetHost, cp) + fwd = forwarder.NewInterceptor(pp, targetHost, cp) } else { - fwd = forwarder.NewInterceptor(lisAddr, "", 0) + fwd = forwarder.NewInterceptor(pp, "", 0) cp = ic.ContainerPort } diff --git a/cmd/traffic/cmd/agent/state_test.go b/cmd/traffic/cmd/agent/state_test.go index d21412abee..52f22c3cf7 100644 --- a/cmd/traffic/cmd/agent/state_test.go +++ b/cmd/traffic/cmd/agent/state_test.go @@ -2,13 +2,13 @@ package agent_test import ( "context" - "net" "path/filepath" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + core "k8s.io/api/core/v1" "github.com/datawire/dlib/dlog" rpc "github.com/telepresenceio/telepresence/rpc/v2/manager" @@ -23,10 +23,7 @@ const ( ) func makeFS(t *testing.T, ctx context.Context) (forwarder.Interceptor, agent.State) { - lAddr, err := net.ResolveTCPAddr("tcp", ":1111") - assert.NoError(t, err) - - f := forwarder.NewInterceptor(lAddr, appHost, appPort) + f := forwarder.NewInterceptor(agentconfig.PortAndProto{Proto: core.ProtocolTCP, Port: 1111}, appHost, appPort) go func() { if err := f.Serve(context.Background(), nil); err != nil { dlog.Error(ctx, err) diff --git a/cmd/traffic/cmd/agentinit/agent_init.go b/cmd/traffic/cmd/agentinit/agent_init.go index d95a23ca10..22d7e68375 100644 --- a/cmd/traffic/cmd/agentinit/agent_init.go +++ b/cmd/traffic/cmd/agentinit/agent_init.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "net" + "net/netip" "os" "path/filepath" "strconv" @@ -19,7 +20,6 @@ import ( "github.com/datawire/dlib/dlog" "github.com/telepresenceio/telepresence/v2/pkg/agentconfig" "github.com/telepresenceio/telepresence/v2/pkg/dos" - "github.com/telepresenceio/telepresence/v2/pkg/iputil" "github.com/telepresenceio/telepresence/v2/pkg/version" ) @@ -45,7 +45,7 @@ func loadConfig(ctx context.Context) (*config, error) { return &c, nil } -func (c *config) configureIptables(ctx context.Context, iptables *iptables.IPTables, loopback, localHostCIDR, podIP string) error { +func (c *config) configureIptables(ctx context.Context, iptables *iptables.IPTables, loopback string, localHostCIDR netip.Prefix, podIP netip.Addr) error { // These iptables rules implement routing such that a packet directed to the appPort will hit the agentPort instead. // If there's no mesh this is simply request -> agent -> app (or intercept) // However, if there's a service mesh we want to make sure we don't bypass the mesh, so the traffic @@ -114,8 +114,8 @@ func (c *config) configureIptables(ctx context.Context, iptables *iptables.IPTab // loop it back into the agent. dlog.Debugf(ctx, "output DNAT %s:%d -> %s:%d", podIP, ac.ProxyPort(ic), podIP, ic.ContainerPort) err = iptables.AppendUnique(nat, outputChain, - "-p", lcProto, "-d", podIP, "--dport", strconv.Itoa(int(ac.ProxyPort(ic))), - "-j", "DNAT", "--to-destination", net.JoinHostPort(podIP, strconv.Itoa(int(ic.ContainerPort)))) + "-p", lcProto, "-d", podIP.String(), "--dport", strconv.Itoa(int(ac.ProxyPort(ic))), + "-j", "DNAT", "--to-destination", netip.AddrPortFrom(podIP, ic.ContainerPort).String()) if err != nil { return fmt.Errorf("failed to append rule to %s: %w", outputChain, err) } @@ -155,7 +155,7 @@ func (c *config) configureIptables(ctx context.Context, iptables *iptables.IPTab err = iptables.Insert(nat, "OUTPUT", 1, "-o", loopback, "-p", lcProto, - "!", "-d", localHostCIDR, + "!", "-d", localHostCIDR.String(), "-m", "owner", "--uid-owner", agentUID, "-j", outputChain) if err != nil { @@ -213,11 +213,15 @@ func Main(ctx context.Context, args ...string) error { return err } proto := iptables.ProtocolIPv4 - localhostCIDR := "127.0.0.1/32" - podIP := os.Getenv("POD_IP") - if len(iputil.Parse(podIP)) == 16 { + localhostCIDR := netip.PrefixFrom(netip.AddrFrom4([4]byte{127, 0, 0, 1}), 32) + podIP, err := netip.ParseAddr(os.Getenv("POD_IP")) + if err != nil { + dlog.Error(ctx, err) + return err + } + if podIP.Is6() { proto = iptables.ProtocolIPv6 - localhostCIDR = "::1/128" + localhostCIDR = netip.PrefixFrom(netip.IPv6Loopback(), 128) } it, err := iptables.NewWithProtocol(proto) if err != nil { diff --git a/cmd/traffic/cmd/manager/cluster/info.go b/cmd/traffic/cmd/manager/cluster/info.go index a53e7fb6ef..b19ed3e84f 100644 --- a/cmd/traffic/cmd/manager/cluster/info.go +++ b/cmd/traffic/cmd/manager/cluster/info.go @@ -348,7 +348,11 @@ func getInjectorSvcIP(ctx context.Context, env *managerutil.Env, client v1.CoreV break } } - return iputil.Parse(sc.Spec.ClusterIP), p, nil + ip, err := netip.ParseAddr(sc.Spec.ClusterIP) + if err != nil { + return nil, 0, err + } + return ip.AsSlice(), p, nil } func (oi *info) watchPodSubnets(ctx context.Context) { diff --git a/cmd/traffic/cmd/manager/service.go b/cmd/traffic/cmd/manager/service.go index c86f93516d..94a6e3f89b 100644 --- a/cmd/traffic/cmd/manager/service.go +++ b/cmd/traffic/cmd/manager/service.go @@ -3,6 +3,7 @@ package manager import ( "context" "fmt" + "net/netip" "slices" "sort" "time" @@ -26,7 +27,6 @@ import ( "github.com/telepresenceio/telepresence/v2/cmd/traffic/cmd/manager/mutator" "github.com/telepresenceio/telepresence/v2/cmd/traffic/cmd/manager/state" "github.com/telepresenceio/telepresence/v2/pkg/dnsproxy" - "github.com/telepresenceio/telepresence/v2/pkg/iputil" "github.com/telepresenceio/telepresence/v2/pkg/tunnel" "github.com/telepresenceio/telepresence/v2/pkg/version" "github.com/telepresenceio/telepresence/v2/pkg/workload" @@ -314,11 +314,15 @@ func (s *service) WatchAgentPods(session *rpc.SessionInfo, stream rpc.Manager_Wa agentNames = make([]string, len(agm)) i := 0 for _, a := range agm { + aip, err := netip.ParseAddr(a.PodIp) + if err != nil { + dlog.Errorf(ctx, "error parsing agent pod ip %q: %v", a.PodIp, err) + } agents[i] = &rpc.AgentPodInfo{ WorkloadName: a.Name, PodName: a.PodName, Namespace: a.Namespace, - PodIp: iputil.Parse(a.PodIp), + PodIp: aip.AsSlice(), ApiPort: a.ApiPort, Intercepted: isIntercepted(a.Name, a.Namespace), } diff --git a/cmd/traffic/cmd/manager/state/state.go b/cmd/traffic/cmd/manager/state/state.go index e65064f370..851bd1ec73 100644 --- a/cmd/traffic/cmd/manager/state/state.go +++ b/cmd/traffic/cmd/manager/state/state.go @@ -3,7 +3,7 @@ package state import ( "context" "fmt" - "net" + "net/netip" "os" "slices" "strings" @@ -27,7 +27,6 @@ import ( "github.com/telepresenceio/telepresence/v2/cmd/traffic/cmd/manager/watchable" "github.com/telepresenceio/telepresence/v2/pkg/agentconfig" "github.com/telepresenceio/telepresence/v2/pkg/dnsproxy" - "github.com/telepresenceio/telepresence/v2/pkg/iputil" "github.com/telepresenceio/telepresence/v2/pkg/k8sapi" "github.com/telepresenceio/telepresence/v2/pkg/log" "github.com/telepresenceio/telepresence/v2/pkg/tunnel" @@ -778,7 +777,7 @@ func (s *state) Tunnel(ctx context.Context, stream tunnel.Stream) error { peerID := tunnel.GetSession(m) peerSession, _ = s.sessions.Load(peerID) } else { - peerSession, err = s.getAgentForDial(ctx, sessionID, stream.ID().Destination()) + peerSession, err = s.getAgentForDial(ctx, sessionID, stream.ID().DestinationAddr()) if err != nil { return err } @@ -801,7 +800,7 @@ func (s *state) Tunnel(ctx context.Context, stream tunnel.Stream) error { return nil } -func (s *state) getAgentForDial(ctx context.Context, clientSessionID string, podIP net.IP) (SessionState, error) { +func (s *state) getAgentForDial(ctx context.Context, clientSessionID string, podIP netip.Addr) (SessionState, error) { agentKey, err := s.getAgentIdForDial(ctx, clientSessionID, podIP) if err != nil || agentKey == "" { return nil, err @@ -810,10 +809,13 @@ func (s *state) getAgentForDial(ctx context.Context, clientSessionID string, pod return agent, nil } -func (s *state) getAgentIdForDial(ctx context.Context, clientSessionID string, podIP net.IP) (string, error) { +func (s *state) getAgentIdForDial(ctx context.Context, clientSessionID string, podIP netip.Addr) (string, error) { // An agent with a podIO matching the given podIP has precedence agents := s.agents.LoadAllMatching(func(key string, ai *rpc.AgentInfo) bool { - return podIP.Equal(iputil.Parse(ai.PodIp)) + if aip, err := netip.ParseAddr(ai.PodIp); err == nil { + return podIP == aip + } + return false }) for agentID := range agents { dlog.Debugf(ctx, "selecting agent for dial based on podIP %s", podIP) diff --git a/integration_test/itest/cluster.go b/integration_test/itest/cluster.go index 0155d1bb83..6a9b81efa1 100644 --- a/integration_test/itest/cluster.go +++ b/integration_test/itest/cluster.go @@ -7,6 +7,7 @@ import ( "io" "net" "net/http" + "net/netip" "os" "path/filepath" "reflect" @@ -211,8 +212,9 @@ func (s *cluster) Initialize(ctx context.Context) context.Context { } else { output, err := Output(ctx, "kubectl", "--namespace", "kube-system", "get", "svc", "kube-dns", "-o", "jsonpath={.spec.clusterIP}") if err == nil { - ip := iputil.Parse(strings.TrimSpace(output)) - if len(ip) == 16 { + ip, err := netip.ParseAddr(strings.TrimSpace(output)) + assert.NoError(t, err) + if ip.Is6() { dlog.Info(ctx, "Using IPv6 because the kube-dns.kube-system has an IPv6 IP") s.ipv6 = true } diff --git a/pkg/agentconfig/portandproto.go b/pkg/agentconfig/portandproto.go index 69ebd28942..51d34c1b91 100644 --- a/pkg/agentconfig/portandproto.go +++ b/pkg/agentconfig/portandproto.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "math" - "net" "strconv" "strings" @@ -59,17 +58,7 @@ func NewPortAndProto(s string) (PortAndProto, error) { return pp, err } -func (pp *PortAndProto) Addr() (addr net.Addr, err error) { - as := fmt.Sprintf(":%d", pp.Port) - if pp.Proto == core.ProtocolTCP { - addr, err = net.ResolveTCPAddr("tcp", as) - } else { - addr, err = net.ResolveUDPAddr("udp", as) - } - return -} - -func (pp *PortAndProto) String() string { +func (pp PortAndProto) String() string { if pp.Proto == core.ProtocolTCP { return strconv.Itoa(int(pp.Port)) } diff --git a/pkg/authenticator/mocks/clientconfig_mock.go b/pkg/authenticator/mocks/clientconfig_mock.go index 3566d4c1be..f20ebc9a11 100644 --- a/pkg/authenticator/mocks/clientconfig_mock.go +++ b/pkg/authenticator/mocks/clientconfig_mock.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: k8s.io/client-go/tools/clientcmd (interfaces: ClientConfig) +// SourceAddr: k8s.io/client-go/tools/clientcmd (interfaces: ClientConfig) // Package mock_authenticator is a generated GoMock package. package mock_authenticator diff --git a/pkg/authenticator/mocks/credentialsresolver_mock.go b/pkg/authenticator/mocks/credentialsresolver_mock.go index a254157c51..7f16eeeed7 100644 --- a/pkg/authenticator/mocks/credentialsresolver_mock.go +++ b/pkg/authenticator/mocks/credentialsresolver_mock.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/telepresenceio/telepresence/v2/pkg/authenticator (interfaces: ExecCredentialsResolver) +// SourceAddr: github.com/telepresenceio/telepresence/v2/pkg/authenticator (interfaces: ExecCredentialsResolver) // Package mock_authenticator is a generated GoMock package. package mock_authenticator diff --git a/pkg/client/cli/intercept/state.go b/pkg/client/cli/intercept/state.go index c5dd47a9a3..4d0813f897 100644 --- a/pkg/client/cli/intercept/state.go +++ b/pkg/client/cli/intercept/state.go @@ -25,7 +25,6 @@ import ( "github.com/telepresenceio/telepresence/v2/pkg/dos" "github.com/telepresenceio/telepresence/v2/pkg/errcat" "github.com/telepresenceio/telepresence/v2/pkg/ioutil" - "github.com/telepresenceio/telepresence/v2/pkg/iputil" "github.com/telepresenceio/telepresence/v2/pkg/proc" ) @@ -96,7 +95,7 @@ func (s *state) CreateRequest(ctx context.Context) (*connector.CreateInterceptRe } spec.TargetPort = int32(s.localPort) - if iputil.Parse(s.Address) == nil { + if _, err = netip.ParseAddr(s.Address); err != nil { return nil, fmt.Errorf("--address %s is not a valid IP address", s.Address) } spec.TargetHost = s.Address diff --git a/pkg/client/remotefs/bridge.go b/pkg/client/remotefs/bridge.go index a033238cb4..db13e359c5 100644 --- a/pkg/client/remotefs/bridge.go +++ b/pkg/client/remotefs/bridge.go @@ -4,13 +4,13 @@ import ( "context" "fmt" "net" + "net/netip" "github.com/datawire/dlib/dgroup" "github.com/datawire/dlib/dlog" "github.com/telepresenceio/telepresence/rpc/v2/manager" client2 "github.com/telepresenceio/telepresence/v2/pkg/client" "github.com/telepresenceio/telepresence/v2/pkg/ipproto" - "github.com/telepresenceio/telepresence/v2/pkg/iputil" "github.com/telepresenceio/telepresence/v2/pkg/tunnel" ) @@ -28,15 +28,15 @@ func NewBridgeMounter(sessionID string, managerClient manager.ManagerClient, loc } } -func (m *bridgeMounter) Start(ctx context.Context, _, _, _, _ string, podIP net.IP, port uint16, _ bool) error { - ctx = dgroup.WithGoroutineName(ctx, iputil.JoinIpPort(podIP, port)) +func (m *bridgeMounter) Start(ctx context.Context, _, _, _, _ string, podAddrPort netip.AddrPort, _ bool) error { + ctx = dgroup.WithGoroutineName(ctx, podAddrPort.String()) lc := &net.ListenConfig{} la := fmt.Sprintf(":%d", m.localPort) l, err := lc.Listen(ctx, "tcp", la) if err != nil { return err } - dlog.Debugf(ctx, "Remote mount bridge listening at %s, will forward to %s", la, iputil.JoinIpPort(podIP, port)) + dlog.Debugf(ctx, "Remote mount bridge listening at %s, will forward to %s", la, podAddrPort) go func() { for { conn, err := l.Accept() @@ -48,7 +48,7 @@ func (m *bridgeMounter) Start(ctx context.Context, _, _, _, _ string, podIP net. return } go func() { - if err := m.dispatchToTunnel(ctx, conn, podIP, port); err != nil { + if err := m.dispatchToTunnel(ctx, conn, podAddrPort); err != nil { dlog.Error(ctx, err) } }() @@ -57,13 +57,13 @@ func (m *bridgeMounter) Start(ctx context.Context, _, _, _, _ string, podIP net. return nil } -func (m *bridgeMounter) dispatchToTunnel(ctx context.Context, conn net.Conn, podIP net.IP, port uint16) error { +func (m *bridgeMounter) dispatchToTunnel(ctx context.Context, conn net.Conn, podAddrPort netip.AddrPort) error { tcpAddr, ok := conn.LocalAddr().(*net.TCPAddr) if !ok { return fmt.Errorf("address %s is not a TCP address", conn.LocalAddr()) } - dlog.Debugf(ctx, "Opening bridge between %s and %s", tcpAddr, iputil.JoinIpPort(podIP, port)) - id := tunnel.NewConnID(ipproto.TCP, tcpAddr.IP, podIP, uint16(tcpAddr.Port), port) + dlog.Debugf(ctx, "Opening bridge between %s and %s", tcpAddr, podAddrPort) + id := tunnel.NewConnID(ipproto.TCP, tcpAddr.AddrPort(), podAddrPort) ms, err := m.managerClient.Tunnel(ctx) if err != nil { return fmt.Errorf("failed to establish tunnel: %v", err) diff --git a/pkg/client/remotefs/ftp.go b/pkg/client/remotefs/ftp.go index c9dca0b271..afc42380d1 100644 --- a/pkg/client/remotefs/ftp.go +++ b/pkg/client/remotefs/ftp.go @@ -2,7 +2,6 @@ package remotefs import ( "context" - "net" "net/netip" "strings" "sync" @@ -14,7 +13,6 @@ import ( "github.com/telepresenceio/go-fuseftp/rpc" "github.com/telepresenceio/telepresence/v2/pkg/agentconfig" "github.com/telepresenceio/telepresence/v2/pkg/client" - "github.com/telepresenceio/telepresence/v2/pkg/iputil" ) type ftpMounter struct { @@ -27,25 +25,24 @@ func NewFTPMounter(client rpc.FuseFTPClient, iceptWG *sync.WaitGroup) Mounter { return &ftpMounter{client: client, iceptWG: iceptWG} } -func (m *ftpMounter) Start(ctx context.Context, workload, container, clientMountPoint, mountPoint string, podIP net.IP, port uint16, ro bool) error { +func (m *ftpMounter) Start(ctx context.Context, workload, container, clientMountPoint, mountPoint string, podAddrPort netip.AddrPort, ro bool) error { // The FTPClient and the NewHost must be controlled by the intercept context and not by the pod context that // is passed as a parameter, because those services will survive pod changes. - addr := netip.MustParseAddrPort(iputil.JoinIpPort(podIP, port)) roTxt := "" if ro { roTxt = " read-only" } if m.id == nil { cfg := client.GetConfig(ctx) - dlog.Infof(ctx, "Mounting FTP file system for container %s[%s] (address %s)%s at %q", workload, container, addr, roTxt, clientMountPoint) + dlog.Infof(ctx, "Mounting FTP file system for container %s[%s] (address %s)%s at %q", workload, container, podAddrPort, roTxt, clientMountPoint) // FTPs remote mount is already relative to the agentconfig.ExportsMountPoint rmp := strings.TrimPrefix(mountPoint, agentconfig.ExportsMountPoint) cc, cancel := context.WithTimeout(ctx, 3*time.Second) mountId, err := m.client.Mount(cc, &rpc.MountRequest{ MountPoint: clientMountPoint, FtpServer: &rpc.AddressAndPort{ - Ip: podIP, - Port: int32(port), + Ip: podAddrPort.Addr().AsSlice(), + Port: int32(podAddrPort.Port()), }, ReadTimeout: durationpb.New(cfg.Timeouts().Get(client.TimeoutFtpReadWrite)), Directory: rmp, @@ -64,21 +61,21 @@ func (m *ftpMounter) Start(ctx context.Context, workload, container, clientMount <-ctx.Done() ctx, cancel := context.WithTimeout(context.WithoutCancel(ctx), cfg.Timeouts().Get(client.TimeoutFtpShutdown)) defer cancel() - dlog.Debugf(ctx, "Unmounting FTP file system for container %s[%s] (address %s) at %q", workload, container, addr, clientMountPoint) + dlog.Debugf(ctx, "Unmounting FTP file system for container %s[%s] (address %s) at %q", workload, container, podAddrPort, clientMountPoint) if _, err = m.client.Unmount(ctx, m.id); err != nil { dlog.Errorf(ctx, "Unmount of %s failed: %v", clientMountPoint, err) } }() - dlog.Infof(ctx, "File system for container %s[%s] (address %s) successfully mounted%s at %q", workload, container, addr, roTxt, clientMountPoint) + dlog.Infof(ctx, "File system for container %s[%s] (address %s) successfully mounted%s at %q", workload, container, podAddrPort, roTxt, clientMountPoint) return nil } // Assign a new address to the FTP client. This kills any open connections but leaves the FUSE driver intact - dlog.Infof(ctx, "Switching remote address to %s for FTP file system for workload container %s[%s] at %q", addr, workload, container, clientMountPoint) + dlog.Infof(ctx, "Switching remote address to %s for FTP file system for workload container %s[%s] at %q", podAddrPort, workload, container, clientMountPoint) _, err := m.client.SetFtpServer(ctx, &rpc.SetFtpServerRequest{ FtpServer: &rpc.AddressAndPort{ - Ip: podIP, - Port: int32(port), + Ip: podAddrPort.Addr().AsSlice(), + Port: int32(podAddrPort.Port()), }, Id: m.id, }) diff --git a/pkg/client/remotefs/mounter.go b/pkg/client/remotefs/mounter.go index a804fabcac..b57c006959 100644 --- a/pkg/client/remotefs/mounter.go +++ b/pkg/client/remotefs/mounter.go @@ -2,7 +2,7 @@ package remotefs import ( "context" - "net" + "net/netip" ) // A Mounter is responsible for mounting a remote filesystem in a local directory or drive letter. @@ -10,5 +10,5 @@ type Mounter interface { // Start mounts the remote directory given by mountPoint on the local directory or drive letter // given ty clientMountPoint. The podIP and port is the address to the remote FTP or SFTP server. // The id is just used for logging purposes. - Start(ctx context.Context, workload, container, clientMountPoint, mountPoint string, podIP net.IP, port uint16, ro bool) error + Start(ctx context.Context, workload, container, clientMountPoint, mountPoint string, podAddrPort netip.AddrPort, ro bool) error } diff --git a/pkg/client/remotefs/sftp.go b/pkg/client/remotefs/sftp.go index 1ca3b4535b..baafeea025 100644 --- a/pkg/client/remotefs/sftp.go +++ b/pkg/client/remotefs/sftp.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net" + "net/netip" "runtime" "sync" "time" @@ -14,7 +15,6 @@ import ( "github.com/datawire/dlib/dgroup" "github.com/datawire/dlib/dlog" "github.com/telepresenceio/telepresence/v2/pkg/dpipe" - "github.com/telepresenceio/telepresence/v2/pkg/iputil" "github.com/telepresenceio/telepresence/v2/pkg/proc" ) @@ -28,8 +28,9 @@ func NewSFTPMounter(iceptWG, podWG *sync.WaitGroup) Mounter { return &sftpMounter{iceptWG: iceptWG, podWG: podWG} } -func (m *sftpMounter) Start(ctx context.Context, workload, container, clientMountPoint, mountPoint string, podIP net.IP, port uint16, ro bool) error { - ctx = dgroup.WithGoroutineName(ctx, iputil.JoinIpPort(podIP, port)) +func (m *sftpMounter) Start(ctx context.Context, workload, container, clientMountPoint, mountPoint string, podAddrPort netip.AddrPort, ro bool) error { + ctx = dgroup.WithGoroutineName(ctx, podAddrPort.String()) + podIP := podAddrPort.Addr().Unmap() // The mount is terminated and restarted when the intercept pod changes, so we // must set up a wait/done pair here to ensure that this happens synchronously @@ -83,7 +84,7 @@ func (m *sftpMounter) Start(ctx context.Context, workload, container, clientMoun sshfsArgs = append(sshfsArgs, "-o", "ro") } - useIPv6 := len(podIP) == 16 + useIPv6 := podIP.Is6() if useIPv6 { // Must use stdin/stdout because sshfs is not capable of connecting with IPv6 sshfsArgs = append(sshfsArgs, @@ -93,7 +94,7 @@ func (m *sftpMounter) Start(ctx context.Context, workload, container, clientMoun ) } else { sshfsArgs = append(sshfsArgs, - "-o", fmt.Sprintf("directport=%d", port), + "-o", fmt.Sprintf("directport=%d", podAddrPort.Port()), fmt.Sprintf("%s:%s", podIP.String(), mountPoint), // what to mount clientMountPoint, // where to mount it ) @@ -108,7 +109,7 @@ func (m *sftpMounter) Start(ctx context.Context, workload, container, clientMoun var err error if useIPv6 { var conn net.Conn - if conn, err = net.Dial("tcp6", iputil.JoinIpPort(podIP, port)); err == nil { + if conn, err = net.Dial("tcp6", podAddrPort.String()); err == nil { defer conn.Close() err = dpipe.DPipe(ctx, conn, exe, sshfsArgs...) } diff --git a/pkg/client/rootd/dns/server.go b/pkg/client/rootd/dns/server.go index f9efbb1f64..b969781274 100644 --- a/pkg/client/rootd/dns/server.go +++ b/pkg/client/rootd/dns/server.go @@ -433,7 +433,7 @@ func mappingsMap(mappings []*client.DNSMapping) map[string]string { mm := make(map[string]string, l) for _, m := range mappings { al := m.AliasFor - if ip := iputil.Parse(al); ip == nil { + if _, err := netip.ParseAddr(al); err != nil { al += "." } mm[strings.ToLower(m.Name+".")] = strings.ToLower(al) @@ -523,11 +523,11 @@ func (s *Server) flushDNS() { // splitToUDPAddr splits the given address into an UDPAddr. It's // an error if the address is based on a hostname rather than an IP. func splitToUDPAddr(netAddr net.Addr) (*net.UDPAddr, error) { - ip, port, err := iputil.SplitToIPPort(netAddr) + ap, err := iputil.SplitToIPPort(netAddr) if err != nil { return nil, err } - return &net.UDPAddr{IP: ip, Port: int(port)}, nil + return net.UDPAddrFromAddrPort(ap), nil } // RequestCount returns the number of requests that this server has received. @@ -954,18 +954,18 @@ func (s *Server) resolveMapping(q *dns.Question) (dnsproxy.RRs, int, error) { if !ok { return nil, dns.RcodeNameError, errNoMapping } - if ip := iputil.Parse(mappingAlias); ip != nil { + if ip, err := netip.ParseAddr(mappingAlias); err == nil { // The name resolves to an A or AAAA record known by this DNS server. var rrs dnsproxy.RRs - if q.Qtype == dns.TypeA && len(ip) == 4 { + if q.Qtype == dns.TypeA && ip.Is4() { rrs = dnsproxy.RRs{&dns.A{ Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: dnsTTL}, - A: ip, + A: ip.AsSlice(), }} - } else if q.Qtype == dns.TypeAAAA && len(ip) == 16 { + } else if q.Qtype == dns.TypeAAAA && ip.Is6() { rrs = dnsproxy.RRs{&dns.AAAA{ Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: dnsTTL}, - AAAA: ip, + AAAA: ip.AsSlice(), }} } return rrs, dns.RcodeSuccess, nil diff --git a/pkg/client/rootd/stream_creator.go b/pkg/client/rootd/stream_creator.go index 184a3a069b..929be1729c 100644 --- a/pkg/client/rootd/stream_creator.go +++ b/pkg/client/rootd/stream_creator.go @@ -3,7 +3,6 @@ package rootd import ( "context" "fmt" - "net" "net/netip" "time" @@ -24,9 +23,8 @@ func (s *Session) isForDNS(ip netip.Addr, port uint16) bool { // checkRecursion checks that the given IP is not contained in any of the subnets // that the VIF is configured with. When that's the case, the VIF is somehow receiving // requests that originate from the cluster and dispatching it leads to infinite recursion. -func checkRecursion(p int, ip net.IP, sn netip.Prefix) (err error) { - a, _ := netip.AddrFromSlice(ip) - if sn.Contains(a) && a != sn.Masked().Addr() { +func checkRecursion(p int, ip netip.Addr, sn netip.Prefix) (err error) { + if sn.Contains(ip) && ip != sn.Masked().Addr() { err = fmt.Errorf("refusing recursive %s %s dispatch from pod subnet %s", ipproto.String(p), ip, sn) } return err @@ -49,18 +47,18 @@ func (s *Session) streamCreator(ctx context.Context) tunnel.StreamCreator { return func(c context.Context, id tunnel.ConnID) (tunnel.Stream, error) { p := id.Protocol() - srcIp := id.Source() + srcIp := id.SourceAddr() for _, podSn := range s.podSubnets { if err := checkRecursion(p, srcIp, podSn); err != nil { return nil, err } } - destAddr, _ := netip.AddrFromSlice(id.Destination()) + destAddr := id.DestinationAddr() if p == ipproto.UDP { if s.isForDNS(destAddr, id.DestinationPort()) { - pipeId := tunnel.NewConnID(p, id.Source(), s.dnsLocalAddr.IP, id.SourcePort(), uint16(s.dnsLocalAddr.Port)) - dlog.Tracef(c, "Intercept DNS %s to %s", id, pipeId.DestinationAddr()) + pipeId := tunnel.NewConnID(p, id.Source(), s.dnsLocalAddr.AddrPort()) + dlog.Tracef(c, "Intercept DNS %s to %s", id, pipeId.Destination()) from, to := tunnel.NewPipe(pipeId, s.session.SessionId) tunnel.NewDialerTTL(to, func() {}, dnsConnTTL, nil, nil).Start(c) return from, nil @@ -106,12 +104,12 @@ func (s *Session) streamCreator(ctx context.Context) tunnel.StreamCreator { } // Replace the virtual IP with the original destination IP. This will ensure that the agent // dials the original destination when the tunnel is established. - id = tunnel.NewConnID(id.Protocol(), id.Source(), a.destinationIP.AsSlice(), id.SourcePort(), id.DestinationPort()) + id = tunnel.NewConnID(id.Protocol(), id.Source(), netip.AddrPortFrom(a.destinationIP, id.DestinationPort())) dlog.Debugf(c, "Opening proxy-via %s tunnel for id %s", a.workload, id) } else { dlog.Debugf(c, "Translating proxy-via %s to %s", destAddr, a.destinationIP) destAddr = a.destinationIP - id = tunnel.NewConnID(id.Protocol(), id.Source(), destAddr.AsSlice(), id.SourcePort(), id.DestinationPort()) + id = tunnel.NewConnID(id.Protocol(), id.Source(), netip.AddrPortFrom(destAddr, id.DestinationPort())) } } diff --git a/pkg/client/userd/trafficmgr/mount.go b/pkg/client/userd/trafficmgr/mount.go index 005cb2fb98..725e65e2c0 100644 --- a/pkg/client/userd/trafficmgr/mount.go +++ b/pkg/client/userd/trafficmgr/mount.go @@ -3,6 +3,7 @@ package trafficmgr import ( "context" "fmt" + "net/netip" "sync" "google.golang.org/grpc/codes" @@ -13,7 +14,6 @@ import ( "github.com/telepresenceio/telepresence/v2/pkg/client" "github.com/telepresenceio/telepresence/v2/pkg/client/remotefs" "github.com/telepresenceio/telepresence/v2/pkg/client/userd" - "github.com/telepresenceio/telepresence/v2/pkg/iputil" ) func (pa *podAccess) shouldMount() bool { @@ -25,7 +25,12 @@ func (pa *podAccess) shouldMount() bool { func (pa *podAccess) startMount(ctx context.Context, iceptWG, podWG *sync.WaitGroup) { var fuseftp rpc.FuseFTPClient useFtp := client.GetConfig(ctx).Intercept().UseFtp - var port int32 + addr, err := netip.ParseAddr(pa.podIP) + if err != nil { + dlog.Errorf(ctx, "error parsing pod IP address %q: %v", pa.podIP, err) + return + } + var port uint16 mountCtx := ctx if useFtp { if pa.ftpPort == 0 { @@ -42,13 +47,13 @@ func (pa *podAccess) startMount(ctx context.Context, iceptWG, podWG *sync.WaitGr dlog.Errorf(ctx, "Client is configured to perform remote mounts using FTP, but the fuseftp server was unable to start") return } - port = pa.ftpPort + port = uint16(pa.ftpPort) } else { if pa.sftpPort == 0 { dlog.Errorf(ctx, "Client is configured to perform remote mounts using SFTP, but only FTP is provided by the traffic-agent") return } - port = pa.sftpPort + port = uint16(pa.sftpPort) } m := *pa.mounter @@ -64,7 +69,7 @@ func (pa *podAccess) startMount(ctx context.Context, iceptWG, podWG *sync.WaitGr } *pa.mounter = m } - err := m.Start(mountCtx, pa.workload, pa.container, pa.clientMountPoint, pa.mountPoint, iputil.Parse(pa.podIP), uint16(port), pa.readOnly) + err = m.Start(mountCtx, pa.workload, pa.container, pa.clientMountPoint, pa.mountPoint, netip.AddrPortFrom(addr, port), pa.readOnly) if err != nil && ctx.Err() == nil { dlog.Error(ctx, err) } diff --git a/pkg/client/userd/trafficmgr/podaccess.go b/pkg/client/userd/trafficmgr/podaccess.go index 231c881769..effdf65c2d 100644 --- a/pkg/client/userd/trafficmgr/podaccess.go +++ b/pkg/client/userd/trafficmgr/podaccess.go @@ -108,8 +108,12 @@ func (pa *podAccess) ensureAccess(ctx context.Context, rd daemon.DaemonClient) e // An agent port-forward to the pod with a designated to the podIP is necessary to // mount or port-forward to localhost. dlog.Debugf(ctx, "Waiting for root-daemon to receive agent IP %s", pa.podIP) + ip, err := netip.ParseAddr(pa.podIP) + if err != nil { + return err + } rsp, err := rd.WaitForAgentIP(ctx, &daemon.WaitForAgentIPRequest{ - Ip: iputil.Parse(pa.podIP), + Ip: ip.AsSlice(), Timeout: durationpb.New(10 * time.Second), }) switch status.Code(err) { @@ -134,12 +138,7 @@ func (pa *podAccess) workerPortForward(ctx context.Context, port string, wg *syn dlog.Errorf(ctx, "malformed extra port %q: %v", port, err) return } - addr, err := pp.Addr() - if err != nil { - dlog.Errorf(ctx, "unable to resolve extra port %q: %v", port, err) - return - } - f := forwarder.NewInterceptor(addr, pa.podIP, pp.Port) + f := forwarder.NewInterceptor(pp, pa.podIP, pp.Port) err = f.Serve(ctx, nil) if err != nil && ctx.Err() == nil { dlog.Errorf(ctx, "port-forwarder failed with %v", err) diff --git a/pkg/forwarder/interceptor.go b/pkg/forwarder/interceptor.go index 7c72e21d51..6ce9c63ee2 100644 --- a/pkg/forwarder/interceptor.go +++ b/pkg/forwarder/interceptor.go @@ -4,11 +4,14 @@ import ( "context" "fmt" "io" - "net" + "net/netip" "sync" + core "k8s.io/api/core/v1" + "github.com/datawire/dlib/dlog" "github.com/telepresenceio/telepresence/rpc/v2/manager" + "github.com/telepresenceio/telepresence/v2/pkg/agentconfig" "github.com/telepresenceio/telepresence/v2/pkg/iputil" "github.com/telepresenceio/telepresence/v2/pkg/restapi" "github.com/telepresenceio/telepresence/v2/pkg/tunnel" @@ -18,7 +21,7 @@ type Interceptor interface { io.Closer InterceptId() string InterceptInfo() *restapi.InterceptInfo - Serve(context.Context, chan<- net.Addr) error + Serve(context.Context, chan<- netip.AddrPort) error SetIntercepting(*manager.InterceptInfo) SetStreamProvider(tunnel.ClientStreamProvider) Target() (string, uint16) @@ -29,7 +32,7 @@ type interceptor struct { lCtx context.Context lCancel context.CancelFunc - listenAddr net.Addr + listenPort uint16 tCtx context.Context tCancel context.CancelFunc @@ -40,14 +43,14 @@ type interceptor struct { intercept *manager.InterceptInfo } -func NewInterceptor(addr net.Addr, targetHost string, targetPort uint16) Interceptor { - switch addr := addr.(type) { - case *net.TCPAddr: - return newTCP(addr, targetHost, targetPort) - case *net.UDPAddr: - return newUDP(addr, targetHost, targetPort) +func NewInterceptor(from agentconfig.PortAndProto, targetHost string, targetPort uint16) Interceptor { + switch from.Proto { + case core.ProtocolTCP: + return newTCP(from.Port, targetHost, targetPort) + case core.ProtocolUDP: + return newUDP(from.Port, targetHost, targetPort) default: - panic(fmt.Errorf("unsupported net.Addr type %T", addr)) + panic(fmt.Errorf("unsupported protocodl %s", from.Proto)) } } diff --git a/pkg/forwarder/tcp.go b/pkg/forwarder/tcp.go index d43aeaa19b..b4d63ffdaa 100644 --- a/pkg/forwarder/tcp.go +++ b/pkg/forwarder/tcp.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "net" + "net/netip" "time" "github.com/datawire/dlib/dlog" @@ -18,30 +19,31 @@ type tcp struct { interceptor } -func newTCP(listen net.Addr, targetHost string, targetPort uint16) Interceptor { +func newTCP(listenPort uint16, targetHost string, targetPort uint16) Interceptor { return &tcp{ interceptor: interceptor{ - listenAddr: listen, + listenPort: listenPort, targetHost: targetHost, targetPort: targetPort, }, } } -func (f *tcp) Serve(ctx context.Context, initCh chan<- net.Addr) error { +func (f *tcp) Serve(ctx context.Context, initCh chan<- netip.AddrPort) error { listener, err := f.listen(ctx) if err != nil { return err } defer listener.Close() + la := listener.Addr().(*net.TCPAddr) if initCh != nil { - initCh <- listener.Addr() + initCh <- la.AddrPort() close(initCh) } - dlog.Debugf(ctx, "Forwarding from %s", f.listenAddr.String()) - defer dlog.Debugf(ctx, "Done forwarding from %s", f.listenAddr.String()) + dlog.Debugf(ctx, "Forwarding from %s", la) + defer dlog.Debugf(ctx, "Done forwarding from %s", la) go func() { <-ctx.Done() @@ -76,14 +78,14 @@ func (f *tcp) listen(ctx context.Context) (*net.TCPListener, error) { // Set up listener lifetime (same as the overall forwarder lifetime) f.lCtx, f.lCancel = context.WithCancel(ctx) - f.lCtx = dlog.WithField(f.lCtx, "lis", f.listenAddr.String()) + f.lCtx = dlog.WithField(f.lCtx, "lis", f.listenPort) // Set up target lifetime f.tCtx, f.tCancel = context.WithCancel(f.lCtx) - listenAddr := f.listenAddr + listenPort := f.listenPort f.mu.Unlock() - return net.ListenTCP("tcp", listenAddr.(*net.TCPAddr)) + return net.ListenTCP("tcp", &net.TCPAddr{Port: int(listenPort)}) } func (f *tcp) forwardConn(clientConn *net.TCPConn) error { @@ -151,24 +153,32 @@ func (f *tcp) forwardConn(clientConn *net.TCPConn) error { } func (f *tcp) interceptConn(ctx context.Context, conn net.Conn, iCept *manager.InterceptInfo) error { - addr := conn.RemoteAddr() - dlog.Debugf(ctx, "Accept got connection from %s", addr) - defer dlog.Debugf(ctx, "Done serving connection from %s", addr) + spec := iCept.Spec + return f.rerouteConn( + ctx, + conn, + iCept.ClientSession.SessionId, + netip.AddrPortFrom(iputil.Parse(spec.TargetHost), uint16(spec.TargetPort)), + time.Duration(spec.RoundtripLatency), + time.Duration(spec.DialTimeout)) +} - srcIp, srcPort, err := iputil.SplitToIPPort(addr) +func (f *tcp) rerouteConn(ctx context.Context, conn net.Conn, clientSession string, dst netip.AddrPort, latency, timeout time.Duration) error { + srcAddr := conn.RemoteAddr() + dlog.Debugf(ctx, "Accept got connection from %s", srcAddr) + defer dlog.Debugf(ctx, "Done serving connection from %s", srcAddr) + + src, err := iputil.SplitToIPPort(conn.RemoteAddr()) if err != nil { - return fmt.Errorf("failed to parse intercept source address %s: %w", addr, err) + return fmt.Errorf("failed to parse intercept source address %s: %w", srcAddr, err) } - spec := iCept.Spec - destIp := iputil.Parse(spec.TargetHost) - clientSession := iCept.ClientSession.SessionId - id := tunnel.NewConnID(ipproto.Parse(addr.Network()), srcIp, destIp, srcPort, uint16(spec.TargetPort)) + id := tunnel.NewConnID(ipproto.Parse(srcAddr.Network()), src, dst) ctx, cancel := context.WithCancel(ctx) f.mu.Lock() sp := f.streamProvider f.mu.Unlock() - s, err := sp.CreateClientStream(ctx, clientSession, id, time.Duration(spec.RoundtripLatency), time.Duration(spec.DialTimeout)) + s, err := sp.CreateClientStream(ctx, clientSession, id, latency, timeout) if err != nil { cancel() return err diff --git a/pkg/forwarder/udp.go b/pkg/forwarder/udp.go index 59ff3ddeea..067aa6bc8d 100644 --- a/pkg/forwarder/udp.go +++ b/pkg/forwarder/udp.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net" + "net/netip" "time" "github.com/datawire/dlib/dlog" @@ -16,20 +17,20 @@ type udp struct { interceptor } -func newUDP(listen *net.UDPAddr, targetHost string, targetPort uint16) Interceptor { +func newUDP(listenPort uint16, targetHost string, targetPort uint16) Interceptor { return &udp{ interceptor: interceptor{ - listenAddr: listen, + listenPort: listenPort, targetHost: targetHost, targetPort: targetPort, }, } } -func (f *udp) Serve(ctx context.Context, initCh chan<- net.Addr) error { +func (f *udp) Serve(ctx context.Context, initCh chan<- netip.AddrPort) error { // Set up listener lifetime (same as the overall forwarder lifetime) f.mu.Lock() - la := f.listenAddr.(*net.UDPAddr) + lp := f.listenPort ctx, f.lCancel = context.WithCancel(ctx) f.lCtx = ctx @@ -42,7 +43,7 @@ func (f *udp) Serve(ctx context.Context, initCh chan<- net.Addr) error { close(initCh) } f.lCancel() - dlog.Infof(ctx, "Done forwarding udp from %s", la) + dlog.Infof(ctx, "Done forwarding udp from :%d", lp) }() for first := true; ; first = false { @@ -54,18 +55,19 @@ func (f *udp) Serve(ctx context.Context, initCh chan<- net.Addr) error { return nil } lc := net.ListenConfig{} - pc, err := lc.ListenPacket(ctx, la.Network(), la.String()) + pc, err := lc.ListenPacket(ctx, "udp", fmt.Sprintf(":%d", lp)) if err != nil { return err } if first { // The address to listen to is likely to change the first time around, because it may // be ":0", so let's ensure that the same address is used next time - la = pc.LocalAddr().(*net.UDPAddr) - f.listenAddr = la + la := pc.LocalAddr().(*net.UDPAddr) + lp = uint16(la.Port) + f.listenPort = lp dlog.Infof(ctx, "Forwarding udp from %s", la) if initCh != nil { - initCh <- la + initCh <- la.AddrPort() close(initCh) initCh = nil } @@ -123,7 +125,7 @@ func ForwardUDP(ctx context.Context, conn *net.UDPConn, targetAddr *net.UDPAddr) id := tunnel.ConnIDFromUDP(rr.Addr, targetAddr) dlog.Tracef(ctx, "<- SRC udp %s, len %d", id, len(rr.Payload)) h, _, err := targets.GetOrCreate(ctx, id, func(ctx context.Context, release func()) (tunnel.Handler, error) { - tc, err := net.DialUDP("udp", nil, id.DestinationAddr().(*net.UDPAddr)) + tc, err := net.DialUDP("udp", nil, net.UDPAddrFromAddrPort(id.Destination())) if err != nil { return nil, err } @@ -186,7 +188,7 @@ func (u *udpHandler) forward(ctx context.Context) { dlog.Tracef(ctx, "<- TRG udp %s, len %d", u.id, len(rr.Payload)) pn := len(rr.Payload) for n := 0; n < pn; { - wn, err := u.replyWith.WriteTo(rr.Payload[n:], u.id.SourceAddr()) + wn, err := u.replyWith.WriteTo(rr.Payload[n:], net.UDPAddrFromAddrPort(u.id.Source())) if err != nil { dlog.Errorf(ctx, "!! SRC udp %s write: %v", u.id, err) return @@ -200,12 +202,14 @@ func (u *udpHandler) forward(ctx context.Context) { func (f *udp) interceptConn(ctx context.Context, conn *net.UDPConn, iCept *manager.InterceptInfo) { spec := iCept.Spec - dest := &net.UDPAddr{IP: iputil.Parse(spec.TargetHost), Port: int(spec.TargetPort)} - + dest := netip.AddrPortFrom(iputil.Parse(spec.TargetHost), uint16(spec.TargetPort)) dlog.Infof(ctx, "Forwarding udp from %s to %s %s", conn.LocalAddr(), spec.Client, dest) defer dlog.Infof(ctx, "Done forwarding udp from %s to %s %s", conn.LocalAddr(), spec.Client, dest) - d := tunnel.NewUDPListener(conn, dest, func(ctx context.Context, id tunnel.ConnID) (tunnel.Stream, error) { - return f.streamProvider.CreateClientStream(ctx, iCept.ClientSession.SessionId, id, time.Duration(spec.RoundtripLatency), time.Duration(spec.DialTimeout)) + d := tunnel.NewUDPListener(conn, net.UDPAddrFromAddrPort(dest), func(ctx context.Context, id tunnel.ConnID) (tunnel.Stream, error) { + f.mu.Lock() + sp := f.streamProvider + f.mu.Unlock() + return sp.CreateClientStream(ctx, iCept.ClientSession.SessionId, id, time.Duration(spec.RoundtripLatency), time.Duration(spec.DialTimeout)) }) d.Start(ctx) <-d.Done() diff --git a/pkg/iputil/parse.go b/pkg/iputil/parse.go index 9ad24b71c9..9a66c51fe2 100644 --- a/pkg/iputil/parse.go +++ b/pkg/iputil/parse.go @@ -2,33 +2,24 @@ package iputil import ( "fmt" - "math" "net" - "strconv" + "net/netip" ) // Parse is like net.ParseIP but converts an IPv4 in 16 byte form to its 4 byte form. -func Parse(ipStr string) (ip net.IP) { - if ip = net.ParseIP(ipStr); ip != nil { - if ip4 := ip.To4(); ip4 != nil { - ip = ip4 - } +func Parse(ipStr string) (ip netip.Addr) { + if ip, err := netip.ParseAddr(ipStr); err == nil { + return ip.Unmap() } return } // SplitToIPPort splits the given address into an IP and a port number. It's -// an error if the address is based on a hostname rather than an IP. -func SplitToIPPort(netAddr net.Addr) (net.IP, uint16, error) { - addr := netAddr.String() - host, portStr, err := net.SplitHostPort(addr) - if err != nil { - return nil, 0, fmt.Errorf("address %q is not an IP and a port", addr) +// an error if the address is based on a hostname rather than an IP. +func SplitToIPPort(netAddr net.Addr) (netip.AddrPort, error) { + ipAddr, ok := netAddr.(interface{ AddrPort() netip.AddrPort }) + if !ok { + return netip.AddrPort{}, fmt.Errorf("address %q is not an IP:port address", netAddr) } - ip := Parse(host) - p, err := strconv.ParseUint(portStr, 10, 16) - if err != nil || ip == nil { - return nil, 0, fmt.Errorf("address %q does not have an integer port <= to %d", addr, math.MaxUint16) - } - return ip, uint16(p), nil + return ipAddr.AddrPort(), nil } diff --git a/pkg/routing/routing_darwin.go b/pkg/routing/routing_darwin.go index b33168a6b5..2156b7b68f 100644 --- a/pkg/routing/routing_darwin.go +++ b/pkg/routing/routing_darwin.go @@ -14,7 +14,6 @@ import ( "golang.org/x/sys/unix" "github.com/datawire/dlib/dexec" - "github.com/telepresenceio/telepresence/v2/pkg/iputil" ) const ( @@ -157,9 +156,11 @@ func getOsRoute(ctx context.Context, routedNet netip.Prefix) (*Route, error) { } ones := routedNet.Bits() if match := maskRe.FindStringSubmatch(string(out)); match != nil { - ip := iputil.Parse(match[1]) - mask := net.IPv4Mask(ip[0], ip[1], ip[2], ip[3]) - ones, _ = mask.Size() + if addr, err := netip.ParseAddr(match[1]); err == nil { + ip := addr.As4() + mask := net.IPv4Mask(ip[0], ip[1], ip[2], ip[3]) + ones, _ = mask.Size() + } } routed := netip.PrefixFrom(ip, ones) isDefault := false diff --git a/pkg/tunnel/connid.go b/pkg/tunnel/connid.go index b61f12b4d0..6298149cc3 100644 --- a/pkg/tunnel/connid.go +++ b/pkg/tunnel/connid.go @@ -4,9 +4,9 @@ import ( "encoding/binary" "fmt" "net" + "net/netip" "github.com/telepresenceio/telepresence/v2/pkg/ipproto" - "github.com/telepresenceio/telepresence/v2/pkg/iputil" ) // A ConnID is a compact and immutable representation of protocol, source IP, source port, destination IP and destination port which @@ -14,24 +14,26 @@ import ( type ConnID string func ConnIDFromUDP(src, dst *net.UDPAddr) ConnID { - return NewConnID(ipproto.UDP, src.IP, dst.IP, uint16(src.Port), uint16(dst.Port)) + return NewConnID(ipproto.UDP, src.AddrPort(), dst.AddrPort()) } // NewConnID returns a new ConnID for the given values. -func NewConnID(proto int, src, dst net.IP, srcPort, dstPort uint16) ConnID { - src4 := src.To4() - dst4 := dst.To4() - if src4 != nil && dst4 != nil { - // These are not NOOPs because a IPv4 can be represented using a 16 byte net.IP. Here - // we ensure that the 4 byte form is used. - src = src4 - dst = dst4 - } else { - src = src.To16() - dst = dst.To16() +func NewConnID(proto int, src, dst netip.AddrPort) ConnID { + srcAddr := src.Addr() + dstAddr := dst.Addr() + if srcAddr.Is4In6() { + if dstAddr.Is4() { + srcAddr = srcAddr.Unmap() + } else if dstAddr.Is4In6() { + srcAddr = srcAddr.Unmap() + dstAddr = dstAddr.Unmap() + } + } else if srcAddr.Is4() && dstAddr.Is4In6() { + dstAddr = dstAddr.Unmap() } - ls := len(src) - ld := len(dst) + + ls := srcAddr.BitLen() / 8 + ld := dstAddr.BitLen() / 8 if ls == 0 { panic("invalid source IP") } @@ -39,12 +41,12 @@ func NewConnID(proto int, src, dst net.IP, srcPort, dstPort uint16) ConnID { panic("invalid destination IP") } bs := make([]byte, ls+ld+5) - copy(bs, src) - binary.BigEndian.PutUint16(bs[ls:], srcPort) + copy(bs, srcAddr.AsSlice()) + binary.BigEndian.PutUint16(bs[ls:], src.Port()) ls += 2 - copy(bs[ls:], dst) + copy(bs[ls:], dstAddr.AsSlice()) ls += ld - binary.BigEndian.PutUint16(bs[ls:], dstPort) + binary.BigEndian.PutUint16(bs[ls:], dst.Port()) ls += 2 bs[ls] = byte(proto) return ConnID(bs) @@ -69,21 +71,18 @@ func (id ConnID) IsDestinationIPv4() bool { return id.areBothIPv4() || net.IP(id[18:34]).To4() != nil } -// Source returns the source IP. -func (id ConnID) Source() net.IP { - if id.areBothIPv4() { - return net.IP(id[0:4]) - } - return iputil.Normalize(net.IP(id[0:16])) +// Source returns the source address and port. +func (id ConnID) Source() netip.AddrPort { + return netip.AddrPortFrom(id.SourceAddr(), id.SourcePort()) } -// SourceAddr returns the *net.TCPAddr or *net.UDPAddr that corresponds to the -// source IP and port of this instance. -func (id ConnID) SourceAddr() net.Addr { - if id.Protocol() == ipproto.TCP { - return &net.TCPAddr{IP: id.Source(), Port: int(id.SourcePort())} +// SourceAddr returns the source IP. +func (id ConnID) SourceAddr() netip.Addr { + b := []byte(id) + if id.areBothIPv4() { + return netip.AddrFrom4(*(*[4]byte)(b[0:4])) } - return &net.UDPAddr{IP: id.Source(), Port: int(id.SourcePort())} + return netip.AddrFrom16(*(*[16]byte)(b[0:16])).Unmap() } // SourcePort returns the source port. @@ -94,21 +93,18 @@ func (id ConnID) SourcePort() uint16 { return binary.BigEndian.Uint16([]byte(id)[16:]) } -// Destination returns the destination IP. -func (id ConnID) Destination() net.IP { - if id.areBothIPv4() { - return net.IP(id[6:10]) - } - return iputil.Normalize(net.IP(id[18:34])) +// Destination returns the destination address and port. +func (id ConnID) Destination() netip.AddrPort { + return netip.AddrPortFrom(id.DestinationAddr(), id.DestinationPort()) } -// DestinationAddr returns the *net.TCPAddr or *net.UDPAddr that corresponds to the -// destination IP and port of this instance. -func (id ConnID) DestinationAddr() net.Addr { - if id.Protocol() == ipproto.TCP { - return &net.TCPAddr{IP: id.Destination(), Port: int(id.DestinationPort())} +// DestinationAddr returns the destination IP. +func (id ConnID) DestinationAddr() netip.Addr { + b := []byte(id) + if id.areBothIPv4() { + return netip.AddrFrom4(*(*[4]byte)(b[6:10])) } - return &net.UDPAddr{IP: id.Destination(), Port: int(id.DestinationPort())} + return netip.AddrFrom16(*(*[16]byte)(b[18:34])).Unmap() } // DestinationPort returns the destination port. @@ -186,15 +182,13 @@ func (id ConnID) DestinationNetwork() string { // Reply returns a copy of this ConnID with swapped source and destination properties. func (id ConnID) Reply() ConnID { - return NewConnID(id.Protocol(), id.Destination(), id.Source(), id.DestinationPort(), id.SourcePort()) + return NewConnID(id.Protocol(), id.Destination(), id.Source()) } // ReplyString returns a formatted string suitable for logging showing the destination:destinationPort -> source:sourcePort. func (id ConnID) ReplyString() string { return fmt.Sprintf("%s %s -> %s", - ipproto.String(id.Protocol()), - iputil.JoinIpPort(id.Destination(), id.DestinationPort()), - iputil.JoinIpPort(id.Source(), id.SourcePort())) + ipproto.String(id.Protocol()), id.Destination(), id.Source()) } // String returns a formatted string suitable for logging showing the source:sourcePort -> destination:destinationPort. @@ -203,7 +197,5 @@ func (id ConnID) String() string { return "bogus ConnID" } return fmt.Sprintf("%s %s -> %s", - ipproto.String(id.Protocol()), - iputil.JoinIpPort(id.Source(), id.SourcePort()), - iputil.JoinIpPort(id.Destination(), id.DestinationPort())) + ipproto.String(id.Protocol()), id.Source(), id.Destination()) } diff --git a/pkg/tunnel/dialer.go b/pkg/tunnel/dialer.go index 8fffe93fc4..3b7b1ba2be 100644 --- a/pkg/tunnel/dialer.go +++ b/pkg/tunnel/dialer.go @@ -119,7 +119,7 @@ func (h *dialer) Start(ctx context.Context) { dlog.Tracef(ctx, " CONN %s, dialing", id) d := net.Dialer{Timeout: h.stream.DialTimeout()} - conn, err := d.DialContext(ctx, id.DestinationProtocolString(), id.DestinationAddr().String()) + conn, err := d.DialContext(ctx, id.DestinationProtocolString(), id.Destination().String()) if err != nil { dlog.Errorf(ctx, "!! CONN %s, failed to establish connection: %v", id, err) if err = h.stream.Send(ctx, NewMessage(DialReject, nil)); err != nil { diff --git a/pkg/tunnel/stream_test.go b/pkg/tunnel/stream_test.go index b2a0206eba..96c5e1c01f 100644 --- a/pkg/tunnel/stream_test.go +++ b/pkg/tunnel/stream_test.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "net" + "net/netip" "sync" "testing" "time" @@ -17,7 +18,6 @@ import ( "github.com/datawire/dlib/dlog" "github.com/telepresenceio/telepresence/rpc/v2/manager" "github.com/telepresenceio/telepresence/v2/pkg/ipproto" - "github.com/telepresenceio/telepresence/v2/pkg/iputil" "github.com/telepresenceio/telepresence/v2/pkg/log" ) @@ -112,7 +112,7 @@ func TestStream_Connect(t *testing.T) { defer cancel() tunnel := newBidi(10, ctx.Done()) - id := NewConnID(ipproto.TCP, iputil.Parse("127.0.0.1"), iputil.Parse("192.168.0.1"), 1001, 8080) + id := NewConnID(ipproto.TCP, netip.AddrPortFrom(netip.AddrFrom4([4]byte{127, 0, 0, 1}), 1001), netip.AddrPortFrom(netip.AddrFrom4([4]byte{192, 168, 0, 1}), 8080)) si := uuid.New().String() wg := sync.WaitGroup{} @@ -213,7 +213,7 @@ func TestStream_Xfer(t *testing.T) { ctx, cancel := testContext(t, 30*time.Second) defer cancel() - id := NewConnID(ipproto.TCP, iputil.Parse("127.0.0.1"), iputil.Parse("192.168.0.1"), 1001, 8080) + id := NewConnID(ipproto.TCP, netip.AddrPortFrom(netip.AddrFrom4([4]byte{127, 0, 0, 1}), 1001), netip.AddrPortFrom(netip.AddrFrom4([4]byte{192, 168, 0, 1}), 8080)) si := uuid.New().String() b := make([]byte, 0x1000) for i := range b { diff --git a/pkg/tunnel/udplistener.go b/pkg/tunnel/udplistener.go index 42223f781c..90b30bc698 100644 --- a/pkg/tunnel/udplistener.go +++ b/pkg/tunnel/udplistener.go @@ -107,7 +107,7 @@ func (p *udpStream) getStream() Stream { } func (p *udpStream) reply(data []byte) (int, error) { - return p.conn.WriteTo(data, p.ID.SourceAddr()) + return p.conn.WriteTo(data, net.UDPAddrFromAddrPort(p.ID.Source())) } func (p *udpStream) startDisconnect(ctx context.Context, s string) { diff --git a/pkg/vif/stack.go b/pkg/vif/stack.go index a864500af8..de60ae55ee 100644 --- a/pkg/vif/stack.go +++ b/pkg/vif/stack.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net" + "net/netip" "time" "gvisor.dev/gvisor/pkg/tcpip" @@ -215,8 +216,15 @@ func setUDPHandler(ctx context.Context, s *stack.Stack, streamCreator tunnel.Str s.SetTransportProtocolHandler(udp.ProtocolNumber, f.HandlePacket) } +func tcpAddrToAddr(addr tcpip.Address) netip.Addr { + if addr.BitLen() == 32 { + return netip.AddrFrom4(addr.As4()) + } + return netip.AddrFrom16(addr.As16()) +} + func newConnID(proto tcpip.TransportProtocolNumber, id stack.TransportEndpointID) tunnel.ConnID { - return tunnel.NewConnID(int(proto), id.RemoteAddress.AsSlice(), id.LocalAddress.AsSlice(), id.RemotePort, id.LocalPort) + return tunnel.NewConnID(int(proto), netip.AddrPortFrom(tcpAddrToAddr(id.RemoteAddress), id.RemotePort), netip.AddrPortFrom(tcpAddrToAddr(id.LocalAddress), id.LocalPort)) } func dispatchToStream(ctx context.Context, id tunnel.ConnID, conn net.Conn, streamCreator tunnel.StreamCreator) { From 2edeb1929234311ab5541a9f7f1a0c6b613d75b6 Mon Sep 17 00:00:00 2001 From: Thomas Hallgren Date: Tue, 31 Dec 2024 15:24:54 +0100 Subject: [PATCH 5/9] Update docs for `--replace` flag. Signed-off-by: Thomas Hallgren --- docs/reference/intercepts/cli.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/docs/reference/intercepts/cli.md b/docs/reference/intercepts/cli.md index c112f01f8c..abc4db7f5b 100644 --- a/docs/reference/intercepts/cli.md +++ b/docs/reference/intercepts/cli.md @@ -359,15 +359,12 @@ Using Deployment echo-easy ## Replacing a running workload -By default, your application keeps running as Telepresence intercepts it, even if it doesn't receive -any traffic (or receives only a subset, as with personal intercepts). This can pose a problem for applications that are active -even when they're not receiving requests. For instance, if your application consumes from a message queue as soon as it -starts up, intercepting it won't stop the pod from consuming from the queue. +By default, your application container continues to run while Telepresence intercepts its traffic. This can cause issues +for applications with ongoing background activities, such as consuming from a message queue. -To work around this issue, `telepresence intercept` allows you to pass in a `--replace` flag that will stop every -application container from running on your pod. When you pass in `--replace`, Telepresence will restart your application -with a dummy application container that sleeps infinitely, and instead just place a traffic agent to redirect traffic to -your local machine. The application container will be restored as soon as you leave the intercept. +To address this, the `telepresence intercept` command provides the `--replace` flag. When used, the Traffic Agent +replaces the application container within the pod. This ensures that the application itself is not running and avoids +unintended side effects. The original application container is automatically restored once the intercept session ends. ```console $ telepresence intercept my-service --port 8080 --replace @@ -381,4 +378,4 @@ $ telepresence intercept my-service --port 8080 --replace ``` > [!NOTE] -> Sidecars will not be stopped. Only the container serving the intercepted port will be removed from the pod. +> Sidecars will not be stopped. Only the targeted container will be removed from the pod. From e420058aea6eaf31d2dff6282da029c378926241 Mon Sep 17 00:00:00 2001 From: Thomas Hallgren Date: Wed, 1 Jan 2025 14:44:14 +0100 Subject: [PATCH 6/9] One single invocation of intercept can now intercept multiple ports. It is now possible to intercept multiple ports with one single invocation of `telepresence intercept` by just repeating the `--port` flag. Signed-off-by: Thomas Hallgren --- CHANGELOG.yml | 5 + cmd/traffic/cmd/manager/service.go | 22 +- cmd/traffic/cmd/manager/state/intercept.go | 269 ++- cmd/traffic/cmd/manager/state/state.go | 87 +- docs/reference/intercepts/cli.md | 20 +- docs/release-notes.md | 6 + docs/release-notes.mdx | 4 + integration_test/multiple_intercepts_test.go | 6 +- .../testdata/k8s/echo-double-one-unnamed.yaml | 2 + integration_test/workspace_watch_test.go | 1 - pkg/agentconfig/portandproto.go | 4 +- pkg/agentconfig/portidentifier.go | 14 +- pkg/agentconfig/portmapping.go | 65 + pkg/agentmap/generator.go | 52 +- pkg/client/cli/intercept/command.go | 25 +- pkg/client/cli/intercept/info.go | 86 +- pkg/client/cli/intercept/result.go | 4 +- pkg/client/cli/intercept/state.go | 30 +- pkg/client/userd/trafficmgr/intercept.go | 115 +- rpc/manager/manager.pb.go | 1909 +++++++++-------- rpc/manager/manager.proto | 33 +- 21 files changed, 1600 insertions(+), 1159 deletions(-) create mode 100644 pkg/agentconfig/portmapping.go diff --git a/CHANGELOG.yml b/CHANGELOG.yml index 69fe80ba4a..b4f8cca54f 100644 --- a/CHANGELOG.yml +++ b/CHANGELOG.yml @@ -27,6 +27,11 @@ items: - version: 2.22.0 date: (TBD) notes: + - type: feature + title: One single invocation of the Telepresence intercept command can now intercept multiple ports. + body: >- + It is now possible to intercept multiple ports with one single invocation of `telepresence intercept` by just + repeating the `--port` flag. - type: feature title: Unify how Traffic Manager selects namespaces body: |- diff --git a/cmd/traffic/cmd/manager/service.go b/cmd/traffic/cmd/manager/service.go index 94a6e3f89b..1b1d50a46d 100644 --- a/cmd/traffic/cmd/manager/service.go +++ b/cmd/traffic/cmd/manager/service.go @@ -458,9 +458,8 @@ func (s *service) WatchIntercepts(session *rpc.SessionInfo, stream rpc.Manager_W var sessionDone <-chan struct{} var filter func(id string, info *rpc.InterceptInfo) bool if sessionID == "" { - // No sessonID; watch everything filter = func(id string, info *rpc.InterceptInfo) bool { - return true + return info.Disposition != rpc.InterceptDispositionType_REMOVED && !state.IsChildIntercept(info.Spec) } } else { var err error @@ -469,7 +468,7 @@ func (s *service) WatchIntercepts(session *rpc.SessionInfo, stream rpc.Manager_W } if agent := s.state.GetAgent(sessionID); agent != nil { - // sessionID refers to an agent session + // sessionID refers to an agent session. Include everything for the agent, including pod-port children. filter = func(id string, info *rpc.InterceptInfo) bool { if info.Spec.Namespace != agent.Namespace || info.Spec.Agent != agent.Name { // Don't return intercepts for different agents. @@ -493,9 +492,11 @@ func (s *service) WatchIntercepts(session *rpc.SessionInfo, stream rpc.Manager_W } } } else { - // sessionID refers to a client session + // sessionID refers to a client session. filter = func(id string, info *rpc.InterceptInfo) bool { - return info.ClientSession.SessionId == sessionID && info.Disposition != rpc.InterceptDispositionType_REMOVED + return info.ClientSession.SessionId == sessionID && + info.Disposition != rpc.InterceptDispositionType_REMOVED && + !state.IsChildIntercept(info.Spec) } } } @@ -590,7 +591,6 @@ func (s *service) EnsureAgent(ctx context.Context, request *rpc.EnsureAgentReque // CreateIntercept lets a client create an intercept. func (s *service) CreateIntercept(ctx context.Context, ciReq *rpc.CreateInterceptRequest) (*rpc.InterceptInfo, error) { ctx = managerutil.WithSessionInfo(ctx, ciReq.GetSession()) - sessionID := ciReq.GetSession().GetSessionId() spec := ciReq.InterceptSpec dlog.Debugf(ctx, "CreateIntercept %s called", ciReq.InterceptSpec.Name) @@ -605,13 +605,13 @@ func (s *service) CreateIntercept(ctx context.Context, ciReq *rpc.CreateIntercep } } - client, interceptInfo, err := s.state.AddIntercept(ctx, sessionID, s.clusterInfo.ID(), ciReq) + client, interceptInfo, err := s.state.AddIntercept(ctx, ciReq) if err != nil { return nil, err } if ciReq.InterceptSpec.Replace { - err := s.state.AddInterceptFinalizer(interceptInfo.Id, s.state.RestoreAppContainer) + err = s.state.AddInterceptFinalizer(interceptInfo.Id, s.state.RestoreAppContainer) if err != nil { // The intercept's been created but we can't finalize it... dlog.Errorf(ctx, "Failed to add finalizer for %s: %v", interceptInfo.Id, err) @@ -685,7 +685,11 @@ func (s *service) ReviewIntercept(ctx context.Context, rIReq *rpc.ReviewIntercep sessionID := rIReq.GetSession().GetSessionId() ceptID := rIReq.Id - dlog.Debugf(ctx, "ReviewIntercept called: %s - %s", ceptID, rIReq.Disposition) + if rIReq.Disposition == rpc.InterceptDispositionType_AGENT_ERROR { + dlog.Errorf(ctx, "ReviewIntercept called: %s - %s: %s", ceptID, rIReq.Disposition, rIReq.Message) + } else { + dlog.Debugf(ctx, "ReviewIntercept called: %s - %s", ceptID, rIReq.Disposition) + } agent := s.state.GetActiveAgent(sessionID) if agent == nil { diff --git a/cmd/traffic/cmd/manager/state/intercept.go b/cmd/traffic/cmd/manager/state/intercept.go index ec55124a2a..625f717e4b 100644 --- a/cmd/traffic/cmd/manager/state/intercept.go +++ b/cmd/traffic/cmd/manager/state/intercept.go @@ -13,6 +13,8 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" core "k8s.io/api/core/v1" events "k8s.io/api/events/v1" k8sErrors "k8s.io/apimachinery/pkg/api/errors" @@ -22,7 +24,7 @@ import ( "github.com/datawire/dlib/derror" "github.com/datawire/dlib/dlog" - managerrpc "github.com/telepresenceio/telepresence/rpc/v2/manager" + rpc "github.com/telepresenceio/telepresence/rpc/v2/manager" "github.com/telepresenceio/telepresence/v2/cmd/traffic/cmd/manager/managerutil" "github.com/telepresenceio/telepresence/v2/cmd/traffic/cmd/manager/mutator" "github.com/telepresenceio/telepresence/v2/pkg/agentconfig" @@ -45,8 +47,8 @@ import ( // with the ones in the returned PreparedIntercept. func (s *state) PrepareIntercept( ctx context.Context, - cr *managerrpc.CreateInterceptRequest, -) (pi *managerrpc.PreparedIntercept, err error) { + cr *rpc.CreateInterceptRequest, +) (pi *rpc.PreparedIntercept, err error) { defer func() { if r := recover(); r != nil { err = derror.PanicToError(r) @@ -54,12 +56,12 @@ func (s *state) PrepareIntercept( } }() - interceptError := func(err error) (*managerrpc.PreparedIntercept, error) { + interceptError := func(err error) (*rpc.PreparedIntercept, error) { if _, ok := status.FromError(err); ok { return nil, err } dlog.Errorf(ctx, "PrepareIntercept error %v", err) - return &managerrpc.PreparedIntercept{Error: err.Error(), ErrorCategory: int32(errcat.GetCategory(err))}, nil + return &rpc.PreparedIntercept{Error: err.Error(), ErrorCategory: int32(errcat.GetCategory(err))}, nil } spec := cr.InterceptSpec @@ -80,10 +82,66 @@ func (s *state) PrepareIntercept( if err != nil { return interceptError(err) } - return &managerrpc.PreparedIntercept{ + uniqueContainerPorts := make(map[agentconfig.PortAndProto]struct{}) + uniqueContainerPorts[agentconfig.PortAndProto{Proto: ic.Protocol, Port: ic.ContainerPort}] = struct{}{} + + var podPorts []string + if len(spec.PodPorts) > 0 { + podPorts = make([]string, len(spec.PodPorts)) + uniqueTargets := make(map[agentconfig.PortAndProto]struct{}) + uniqueTargets[agentconfig.PortAndProto{Proto: ic.Protocol, Port: uint16(spec.TargetPort)}] = struct{}{} + for i, pms := range spec.PodPorts { + pm := agentconfig.PortMapping(pms) + _, pmIc, err := findIntercept2(ac, spec.ServiceName, spec.ContainerName, pm.From()) + if err != nil { + return interceptError(err) + } + + to := pm.To() + if _, ok := uniqueTargets[to]; ok { + return interceptError(errcat.User.Newf("multiple port definitions targeting %s", to)) + } + uniqueTargets[to] = struct{}{} + + from := agentconfig.PortAndProto{Proto: pmIc.Protocol, Port: pmIc.ContainerPort} + if _, ok := uniqueContainerPorts[from]; ok { + return interceptError(errcat.User.Newf("multiple port definitions using container port %s", from)) + } + uniqueContainerPorts[from] = struct{}{} + + // Return the resolved numeric container port. + podPorts[i] = fmt.Sprintf("%d:%s", pmIc.ContainerPort, to) + } + } + + // Validate that there's no port conflict with other intercepts using the same agent. + otherIcs := s.intercepts.LoadAllMatching(func(s string, info *rpc.InterceptInfo) bool { + return info.Disposition == rpc.InterceptDispositionType_ACTIVE && info.Spec.Agent == ac.AgentName && info.Spec.Namespace == ac.Namespace + }) + + if spec.Mechanism != "http" { + // Intercept is global, so it will conflict with any other intercept using the same port and protocol. + for _, otherIc := range otherIcs { + oSpec := otherIc.Spec // Validate that there's no port conflict + for cp := range uniqueContainerPorts { + if cp.Port == uint16(oSpec.ContainerPort) && string(cp.Proto) == oSpec.Protocol { + name := oSpec.Name + client := oSpec.Client + if IsChildIntercept(oSpec) { + if cps := strings.Fields(client); len(cps) == 4 { + name = cps[2] + client = cps[3] + } + } + return interceptError(errcat.User.Newf("container port %d is already intercepted by %s, intercept %s", cp.Port, client, name)) + } + } + } + } + + return &rpc.PreparedIntercept{ Namespace: ac.Namespace, ServiceUid: string(ic.ServiceUID), - ServiceName: ic.ServiceName, ServicePortName: ic.ServicePortName, ContainerName: cn.Name, Protocol: string(ic.Protocol), @@ -91,10 +149,143 @@ func (s *state) PrepareIntercept( ServicePort: int32(ic.ServicePort), AgentImage: ac.AgentImage, WorkloadKind: ac.WorkloadKind, + PodPorts: podPorts, }, nil } -func (s *state) EnsureAgent(ctx context.Context, n, ns string) (as []*managerrpc.AgentInfo, err error) { +func (s *state) AddIntercept(ctx context.Context, cir *rpc.CreateInterceptRequest) (*rpc.ClientInfo, *rpc.InterceptInfo, error) { + s.mu.Lock() + defer s.mu.Unlock() + + clientSession := cir.Session + sessionID := clientSession.SessionId + client := s.GetClient(sessionID) + if client == nil { + return nil, nil, status.Errorf(codes.NotFound, "session %q not found", sessionID) + } + + spec := cir.InterceptSpec + interceptID := fmt.Sprintf("%s:%s", sessionID, spec.Name) + ret, is, err := s.addIntercept(interceptID, cir) + if err != nil { + return nil, nil, err + } + + // Add one child intercept for each pod-port. + for _, pms := range spec.PodPorts { + pm := agentconfig.PortMapping(pms) + from, to, err := pm.FromNumberAndTo() + if err != nil { + // Did PrepareIntercept create an invalid pod_port? + return nil, nil, status.Errorf(codes.Internal, "invalid pod_port %q: %v", pm, err) + } + pmCir := proto.Clone(cir).(*rpc.CreateInterceptRequest) + pmSpec := pmCir.InterceptSpec + pmSpec.Name = fmt.Sprintf("%s-%d-%s", spec.Name, from, strings.ToLower(string(to.Proto))) + pmSpec.PodPorts = nil + pmSpec.LocalPorts = nil + + // This intercept targets a pod-port (container port) directly. The name of the container + // is not necessary, because container ports must be unique within the pod. + pmSpec.ServiceUid = "" + pmSpec.ServicePortName = "" + pmSpec.ServicePort = 0 + pmSpec.Protocol = string(to.Proto) + pmSpec.ContainerPort = int32(from) + pmSpec.PortIdentifier = pm.From().String() + pmSpec.TargetPort = int32(pm.To().Port) + + // The Client field helps IsChildIntercept identify the child. + pmSpec.Client = fmt.Sprintf("child %s %s %s", pm, spec.Name, spec.Client) + + pmInterceptID := fmt.Sprintf("%s:%s", sessionID, pmSpec.Name) + _, _, err = s.addIntercept(pmInterceptID, pmCir) + if err != nil { + return nil, nil, err + } + + // Add finalizer to the interceptState of the parent intercept. + is.addFinalizer(func(_ context.Context, _ *rpc.InterceptInfo) error { + if _, loaded := s.intercepts.LoadAndDelete(pmInterceptID); loaded { + s.interceptStates.Delete(pmInterceptID) + } + return nil + }) + } + return client, ret, nil +} + +func IsChildIntercept(spec *rpc.InterceptSpec) bool { + return strings.HasPrefix(spec.Client, "child ") +} + +func (s *state) addIntercept(id string, cir *rpc.CreateInterceptRequest) (*rpc.InterceptInfo, *interceptState, error) { + cept := s.self.NewInterceptInfo(id, cir) + + // Wrap each potential-state-change in a + // + // if cept.Disposition == rpc.InterceptDispositionType_WAITING { … } + // + // so that we don't need to worry about different state-changes stomping on each-other. + if cept.Disposition == rpc.InterceptDispositionType_WAITING { + if errCode, errMsg := s.checkAgentsForIntercept(cept); errCode != 0 { + cept.Disposition = errCode + cept.Message = errMsg + } + } + + if existingValue, hasConflict := s.intercepts.LoadOrStore(id, cept); hasConflict { + if existingValue.Disposition != rpc.InterceptDispositionType_REMOVED { + return nil, nil, status.Errorf(codes.AlreadyExists, "Intercept named %q already exists", cept.Spec.Name) + } + s.intercepts.Store(id, cept) + } + + is := newInterceptState(id) + s.interceptStates.Store(id, is) + return cept, is, nil +} + +func (s *state) NewInterceptInfo(interceptID string, ciReq *rpc.CreateInterceptRequest) *rpc.InterceptInfo { + return &rpc.InterceptInfo{ + Spec: ciReq.InterceptSpec, + Disposition: rpc.InterceptDispositionType_WAITING, + Message: "Waiting for Agent approval", + Id: interceptID, + ClientSession: ciReq.Session, + ModifiedAt: timestamppb.Now(), + } +} + +func (s *state) AddInterceptFinalizer(interceptID string, finalizer InterceptFinalizer) error { + is, ok := s.interceptStates.Load(interceptID) + if !ok { + return status.Errorf(codes.NotFound, "no such intercept %s", interceptID) + } + is.addFinalizer(finalizer) + return nil +} + +// getAgentsInterceptedByClient returns the session IDs for each agent that are currently +// intercepted by the client with the given client session ID. +func (s *state) getAgentsInterceptedByClient(clientSessionID string) map[string]*rpc.AgentInfo { + intercepts := s.intercepts.LoadAllMatching(func(_ string, ii *rpc.InterceptInfo) bool { + return ii.ClientSession.SessionId == clientSessionID + }) + if len(intercepts) == 0 { + return nil + } + return s.agents.LoadAllMatching(func(_ string, ai *rpc.AgentInfo) bool { + for _, ii := range intercepts { + if ai.Name == ii.Spec.Agent && ai.Namespace == ii.Spec.Namespace { + return true + } + } + return false + }) +} + +func (s *state) EnsureAgent(ctx context.Context, n, ns string) (as []*rpc.AgentInfo, err error) { var wl k8sapi.Workload wl, err = agentmap.GetWorkload(ctx, n, ns, "") if err != nil { @@ -112,14 +303,14 @@ func (s *state) ValidateCreateAgent(context.Context, k8sapi.Workload, agentconfi } // sortAgents will sort the given AgentInfo based on pod name. -func sortAgents(as []*managerrpc.AgentInfo) { +func sortAgents(as []*rpc.AgentInfo) { sort.Slice(as, func(i, j int) bool { return as[i].PodName < as[j].PodName }) } -func (s *state) ensureAgent(parentCtx context.Context, wl k8sapi.Workload, extended bool, spec *managerrpc.InterceptSpec) ( - ac *agentconfig.Sidecar, as []*managerrpc.AgentInfo, err error, +func (s *state) ensureAgent(parentCtx context.Context, wl k8sapi.Workload, extended bool, spec *rpc.InterceptSpec) ( + ac *agentconfig.Sidecar, as []*rpc.AgentInfo, err error, ) { if agentmap.TrafficManagerSelector.Matches(labels.Set(wl.GetLabels())) { msg := fmt.Sprintf("deployment %s.%s is the Telepresence Traffic Manager. It can not have a traffic-agent", wl.GetName(), wl.GetNamespace()) @@ -134,10 +325,10 @@ func (s *state) ensureAgent(parentCtx context.Context, wl k8sapi.Workload, exten } if sce != nil { ac = sce.AgentConfig() - am := s.agents.LoadAllMatching(func(_ string, ai *managerrpc.AgentInfo) bool { + am := s.agents.LoadAllMatching(func(_ string, ai *rpc.AgentInfo) bool { return ai.Name == ac.AgentName && ai.Namespace == ac.Namespace }) - as = make([]*managerrpc.AgentInfo, len(am)) + as = make([]*rpc.AgentInfo, len(am)) i := 0 for _, found := range am { as[i] = found @@ -174,7 +365,7 @@ func (s *state) ensureAgent(parentCtx context.Context, wl k8sapi.Workload, exten return ac, as, nil } -func (s *state) isExtended(spec *managerrpc.InterceptSpec) bool { +func (s *state) isExtended(spec *rpc.InterceptSpec) bool { return spec.Mechanism != "tcp" } @@ -195,7 +386,7 @@ func (s *state) dropAgentConfig( return mutator.GetMap(ctx).Delete(ctx, wl.GetName(), wl.GetNamespace()) } -func (s *state) RestoreAppContainer(ctx context.Context, ii *managerrpc.InterceptInfo) (err error) { +func (s *state) RestoreAppContainer(ctx context.Context, ii *rpc.InterceptInfo) (err error) { dlog.Debugf(ctx, "Restoring app container for %s", ii.Id) spec := ii.Spec n := spec.Agent @@ -244,7 +435,7 @@ func updateSidecar(sce agentconfig.SidecarExt, cm *core.ConfigMap, n string) (bo } func (s *state) waitForAgentDepartures(ctx context.Context, wl k8sapi.Workload) error { - filter := func(s string, info *managerrpc.AgentInfo) bool { + filter := func(s string, info *rpc.AgentInfo) bool { return info.Kind == wl.GetKind() && info.Name == wl.GetName() && info.Namespace == wl.GetNamespace() } if len(s.agents.LoadAllMatching(filter)) == 0 { @@ -281,7 +472,7 @@ func (s *state) getOrCreateAgentConfig( ctx context.Context, wl k8sapi.Workload, extended bool, - spec *managerrpc.InterceptSpec, + spec *rpc.InterceptSpec, dryRun bool, ) (sce agentconfig.SidecarExt, err error) { enabled, err := checkInterceptAnnotations(wl) @@ -449,9 +640,9 @@ func watchFailedInjectionEvents(ctx context.Context, name, namespace string) (<- return ec, nil } -func (s *state) waitForAgents(ctx context.Context, name, namespace string, failedCreateCh <-chan *events.Event) ([]*managerrpc.AgentInfo, error) { +func (s *state) waitForAgents(ctx context.Context, name, namespace string, failedCreateCh <-chan *events.Event) ([]*rpc.AgentInfo, error) { dlog.Debugf(ctx, "Waiting for agent %s.%s", name, namespace) - snapshotCh := s.WatchAgents(ctx, func(sessionID string, agent *managerrpc.AgentInfo) bool { + snapshotCh := s.WatchAgents(ctx, func(sessionID string, agent *rpc.AgentInfo) bool { return agent.Name == name && agent.Namespace == namespace }) failedContainerRx := regexp.MustCompile(`restarting failed container (\S+) in pod ([0-9A-Za-z_-]+)_` + namespace) @@ -518,7 +709,7 @@ func (s *state) waitForAgents(ctx context.Context, name, namespace string, faile if len(snapshot.State) == 0 { continue } - as := make([]*managerrpc.AgentInfo, 0, len(snapshot.State)) + as := make([]*rpc.AgentInfo, 0, len(snapshot.State)) for _, a := range snapshot.State { if mm.IsBlacklisted(a.PodName, a.Namespace) { dlog.Debugf(ctx, "Pod %s.%s is blacklisted", a.PodName, a.Namespace) @@ -589,11 +780,17 @@ func unmarshalConfigMapEntry(y string, name, namespace string) (agentconfig.Side } // findIntercept finds the intercept configuration that matches the given InterceptSpec's service/service port or container port. -func findIntercept(ac *agentconfig.Sidecar, spec *managerrpc.InterceptSpec) (foundCN *agentconfig.Container, foundIC *agentconfig.Intercept, err error) { - pi := agentconfig.PortIdentifier(spec.PortIdentifier) +func findIntercept(ac *agentconfig.Sidecar, spec *rpc.InterceptSpec) (foundCN *agentconfig.Container, foundIC *agentconfig.Intercept, err error) { + return findIntercept2(ac, spec.ServiceName, spec.ContainerName, agentconfig.PortIdentifier(spec.PortIdentifier)) +} + +// findIntercept finds the intercept configuration that matches the given InterceptSpec's service/service port or container port. +func findIntercept2(ac *agentconfig.Sidecar, serviceName, containerName string, pi agentconfig.PortIdentifier) ( + foundCN *agentconfig.Container, foundIC *agentconfig.Intercept, err error, +) { for _, cn := range ac.Containers { for _, ic := range cn.Intercepts { - if !(spec.ServiceName == "" || spec.ServiceName == ic.ServiceName) { + if !(serviceName == "" || serviceName == ic.ServiceName) { continue } if pi != "" { @@ -607,9 +804,9 @@ func findIntercept(ac *agentconfig.Sidecar, spec *managerrpc.InterceptSpec) (fou } if foundIC == nil { foundCN = cn - if spec.ContainerName != "" { + if containerName != "" { for _, cx := range ac.Containers { - if cx.Name == spec.ContainerName { + if cx.Name == containerName { foundCN = cx break } @@ -620,22 +817,22 @@ func findIntercept(ac *agentconfig.Sidecar, spec *managerrpc.InterceptSpec) (fou } var msg string switch { - case spec.ServiceName == "" && pi == "": + case serviceName == "" && pi == "": msg = fmt.Sprintf("%s %s.%s has multiple interceptable ports.\n"+ "Please specify the service and/or port you want to intercept "+ "by passing the --service= and/or --port= flag.", ac.WorkloadKind, ac.WorkloadName, ac.Namespace) - case spec.ServiceName == "": + case serviceName == "": msg = fmt.Sprintf("%s %s.%s has multiple interceptable services with port %s.\n"+ "Please specify the service you want to intercept by passing the --service= flag.", ac.WorkloadKind, ac.WorkloadName, ac.Namespace, pi) case pi == "": msg = fmt.Sprintf("%s %s.%s has multiple interceptable ports in service %s.\n"+ "Please specify the port you want to intercept by passing the --port= flag.", - ac.WorkloadKind, ac.WorkloadName, ac.Namespace, spec.ServiceName) + ac.WorkloadKind, ac.WorkloadName, ac.Namespace, serviceName) default: msg = fmt.Sprintf("%s %s.%s intercept config is broken. Service %s, port %s is declared more than once\n", - ac.WorkloadKind, ac.WorkloadName, ac.Namespace, spec.ServiceName, pi) + ac.WorkloadKind, ac.WorkloadName, ac.Namespace, serviceName, pi) } return nil, nil, errcat.User.New(msg) } @@ -645,11 +842,11 @@ func findIntercept(ac *agentconfig.Sidecar, spec *managerrpc.InterceptSpec) (fou } ss := "" - if spec.ServiceName != "" { + if serviceName != "" { if pi != "" { - ss = fmt.Sprintf(" matching service %s, port %s", spec.ServiceName, pi) + ss = fmt.Sprintf(" matching service %s, port %s", serviceName, pi) } else { - ss = fmt.Sprintf(" matching service %s", spec.ServiceName) + ss = fmt.Sprintf(" matching service %s", serviceName) } } else if pi != "" { ss = fmt.Sprintf(" matching port %s", pi) @@ -657,18 +854,18 @@ func findIntercept(ac *agentconfig.Sidecar, spec *managerrpc.InterceptSpec) (fou return nil, nil, errcat.User.Newf("%s %s.%s has no interceptable port%s", ac.WorkloadKind, ac.WorkloadName, ac.Namespace, ss) } -type InterceptFinalizer func(ctx context.Context, interceptInfo *managerrpc.InterceptInfo) error +type InterceptFinalizer func(ctx context.Context, interceptInfo *rpc.InterceptInfo) error type interceptState struct { sync.Mutex - lastInfoCh chan *managerrpc.InterceptInfo + lastInfoCh chan *rpc.InterceptInfo finalizers []InterceptFinalizer interceptID string } func newInterceptState(interceptID string) *interceptState { is := &interceptState{ - lastInfoCh: make(chan *managerrpc.InterceptInfo), + lastInfoCh: make(chan *rpc.InterceptInfo), interceptID: interceptID, } return is @@ -680,7 +877,7 @@ func (is *interceptState) addFinalizer(finalizer InterceptFinalizer) { is.finalizers = append(is.finalizers, finalizer) } -func (is *interceptState) terminate(ctx context.Context, interceptInfo *managerrpc.InterceptInfo) { +func (is *interceptState) terminate(ctx context.Context, interceptInfo *rpc.InterceptInfo) { is.Lock() defer is.Unlock() for i := len(is.finalizers) - 1; i >= 0; i-- { diff --git a/cmd/traffic/cmd/manager/state/state.go b/cmd/traffic/cmd/manager/state/state.go index 851bd1ec73..fe54e9c9c1 100644 --- a/cmd/traffic/cmd/manager/state/state.go +++ b/cmd/traffic/cmd/manager/state/state.go @@ -36,7 +36,7 @@ import ( type State interface { AddAgent(*rpc.AgentInfo, time.Time) string AddClient(*rpc.ClientInfo, time.Time) string - AddIntercept(context.Context, string, string, *rpc.CreateInterceptRequest) (*rpc.ClientInfo, *rpc.InterceptInfo, error) + AddIntercept(context.Context, *rpc.CreateInterceptRequest) (*rpc.ClientInfo, *rpc.InterceptInfo, error) AddInterceptFinalizer(string, InterceptFinalizer) error AddSessionConsumptionMetrics(metrics *rpc.TunnelMetrics) AgentsLookupDNS(context.Context, string, *rpc.DNSRequest) (dnsproxy.RRs, int, error) @@ -63,7 +63,7 @@ type State interface { GetInterceptActiveStatus() *prometheus.GaugeVec HasAgent(name, namespace string) bool MarkSession(*rpc.RemainRequest, time.Time) bool - NewInterceptInfo(string, *rpc.SessionInfo, *rpc.CreateInterceptRequest) *rpc.InterceptInfo + NewInterceptInfo(string, *rpc.CreateInterceptRequest) *rpc.InterceptInfo PostLookupDNSResponse(context.Context, *rpc.DNSAgentResponse) EnsureAgent(context.Context, string, string) ([]*rpc.AgentInfo, error) PrepareIntercept(context.Context, *rpc.CreateInterceptRequest) (*rpc.PreparedIntercept, error) @@ -543,89 +543,6 @@ func (s *state) WatchWorkloads(ctx context.Context, sessionID string) (ch <-chan // Intercepts ////////////////////////////////////////////////////////////////////////////////////// -func (s *state) AddIntercept(ctx context.Context, sessionID, managerID string, cir *rpc.CreateInterceptRequest) (client *rpc.ClientInfo, ret *rpc.InterceptInfo, err error) { - s.mu.Lock() - defer s.mu.Unlock() - - client = s.GetClient(sessionID) - if client == nil { - return nil, nil, status.Errorf(codes.NotFound, "session %q not found", sessionID) - } - - spec := cir.InterceptSpec - interceptID := fmt.Sprintf("%s:%s", sessionID, spec.Name) - installID := client.GetInstallId() - clientSession := rpc.SessionInfo{ - SessionId: sessionID, - ManagerInstallId: managerID, - InstallId: &installID, - } - - cept := s.self.NewInterceptInfo(interceptID, &clientSession, cir) - - // Wrap each potential-state-change in a - // - // if cept.Disposition == rpc.InterceptDispositionType_WAITING { … } - // - // so that we don't need to worry about different state-changes stomping on eachother. - if cept.Disposition == rpc.InterceptDispositionType_WAITING { - if errCode, errMsg := s.checkAgentsForIntercept(cept); errCode != 0 { - cept.Disposition = errCode - cept.Message = errMsg - } - } - - if existingValue, hasConflict := s.intercepts.LoadOrStore(cept.Id, cept); hasConflict { - if existingValue.Disposition != rpc.InterceptDispositionType_REMOVED { - return nil, nil, status.Errorf(codes.AlreadyExists, "Intercept named %q already exists", spec.Name) - } else { - s.intercepts.Store(cept.Id, cept) - } - } - - s.interceptStates.Store(interceptID, newInterceptState(cept.Id)) - return client, cept, nil -} - -func (s *state) NewInterceptInfo(interceptID string, session *rpc.SessionInfo, ciReq *rpc.CreateInterceptRequest) *rpc.InterceptInfo { - return &rpc.InterceptInfo{ - Spec: ciReq.InterceptSpec, - Disposition: rpc.InterceptDispositionType_WAITING, - Message: "Waiting for Agent approval", - Id: interceptID, - ClientSession: session, - ModifiedAt: timestamppb.Now(), - } -} - -func (s *state) AddInterceptFinalizer(interceptID string, finalizer InterceptFinalizer) error { - is, ok := s.interceptStates.Load(interceptID) - if !ok { - return status.Errorf(codes.NotFound, "no such intercept %s", interceptID) - } - is.addFinalizer(finalizer) - return nil -} - -// getAgentsInterceptedByClient returns the session IDs for each agent that are currently -// intercepted by the client with the given client session ID. -func (s *state) getAgentsInterceptedByClient(clientSessionID string) map[string]*rpc.AgentInfo { - intercepts := s.intercepts.LoadAllMatching(func(_ string, ii *rpc.InterceptInfo) bool { - return ii.ClientSession.SessionId == clientSessionID - }) - if len(intercepts) == 0 { - return nil - } - return s.agents.LoadAllMatching(func(_ string, ai *rpc.AgentInfo) bool { - for _, ii := range intercepts { - if ai.Name == ii.Spec.Agent && ai.Namespace == ii.Spec.Namespace { - return true - } - } - return false - }) -} - // getAgentsInNamespace returns the session IDs the agents in the given namespace. func (s *state) getAgentsInNamespace(namespace string) map[string]*rpc.AgentInfo { return s.agents.LoadAllMatching(func(_ string, ii *rpc.AgentInfo) bool { diff --git a/docs/reference/intercepts/cli.md b/docs/reference/intercepts/cli.md index abc4db7f5b..8de626f79a 100644 --- a/docs/reference/intercepts/cli.md +++ b/docs/reference/intercepts/cli.md @@ -111,32 +111,22 @@ intercepted ## Intercepting multiple ports It is possible to intercept more than one service and/or service port that are using the same workload. You do this -by creating more than one intercept that identify the same workload using the `--workload` flag. +by repeating the `--port` flag. Let's assume that we have a service `multi-echo` with the two ports `http` and `grpc`. They are both targeting the same `multi-echo` deployment. ```console -$ telepresence intercept multi-echo-http --workload multi-echo --port 8080:http +$ telepresence intercept multi-echo-http --workload multi-echo --port 8080:http --port 8443:grpc Using Deployment multi-echo intercepted Intercept name : multi-echo-http State : ACTIVE Workload kind : Deployment - Destination : 127.0.0.1:8080 - Service Port Identifier: http + Intercepting : 10.1.54.120 -> 127.0.0.1 + 8080 -> 8080 TCP + 8443 -> 8443 TCP Volume Mount Point : /tmp/telfs-893700837 - Intercepting : all TCP requests -$ telepresence intercept multi-echo-grpc --workload multi-echo --port 8443:grpc --mechanism tcp -Using Deployment multi-echo -intercepted - Intercept name : multi-echo-grpc - State : ACTIVE - Workload kind : Deployment - Destination : 127.0.0.1:8443 - Service Port Identifier: extra - Volume Mount Point : /tmp/telfs-1277723591 - Intercepting : all TCP requests ``` ## Port-forwarding an intercepted container's sidecars diff --git a/docs/release-notes.md b/docs/release-notes.md index df85a17f93..95c478a368 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,12 @@ [comment]: # (Code generated by relnotesgen. DO NOT EDIT.) # Telepresence Release Notes ## Version 2.22.0 +##
feature
One single invocation of the Telepresence intercept command can now intercept multiple ports.
+
+ +It is now possible to intercept multiple ports with one single invocation of `telepresence intercept` by just repeating the `--port` flag. +
+ ##
feature
[Unify how Traffic Manager selects namespaces](install/manager#static-versus-dynamic-namespace-selection)
diff --git a/docs/release-notes.mdx b/docs/release-notes.mdx index 195248368e..0c31b9ff7f 100644 --- a/docs/release-notes.mdx +++ b/docs/release-notes.mdx @@ -8,6 +8,10 @@ import { Note, Title, Body } from '@site/src/components/ReleaseNotes' # Telepresence Release Notes ## Version 2.22.0 + + One single invocation of the Telepresence intercept command can now intercept multiple ports. + It is now possible to intercept multiple ports with one single invocation of `telepresence intercept` by just repeating the `--port` flag. + Unify how Traffic Manager selects namespaces The definition of what namespaces that a Traffic Manager would manage use was scattered into several Helm diff --git a/integration_test/multiple_intercepts_test.go b/integration_test/multiple_intercepts_test.go index 7161d8cd8a..13a815662a 100644 --- a/integration_test/multiple_intercepts_test.go +++ b/integration_test/multiple_intercepts_test.go @@ -132,7 +132,11 @@ func (s *multipleInterceptsSuite) Test_Intercepts() { } func (s *multipleInterceptsSuite) Test_ReportsPortConflict() { - _, stderr, err := itest.Telepresence(s.Context(), "intercept", "--mount", "false", "--port", strconv.Itoa(s.servicePort[1]), "dummy-name") + ctx := s.Context() + svc := fmt.Sprintf("%s-%d", s.Name(), 0) + itest.TelepresenceOk(ctx, "leave", svc) + defer itest.TelepresenceOk(ctx, "intercept", "--mount", "false", "--port", strconv.Itoa(s.servicePort[0]), svc) + _, stderr, err := itest.Telepresence(s.Context(), "intercept", "--mount", "false", "--port", strconv.Itoa(s.servicePort[1]), svc) s.Error(err) s.Contains(stderr, fmt.Sprintf("Port 127.0.0.1:%d is already in use by intercept %s-1", s.servicePort[1], s.Name())) } diff --git a/integration_test/testdata/k8s/echo-double-one-unnamed.yaml b/integration_test/testdata/k8s/echo-double-one-unnamed.yaml index afeda74664..b462dce565 100644 --- a/integration_test/testdata/k8s/echo-double-one-unnamed.yaml +++ b/integration_test/testdata/k8s/echo-double-one-unnamed.yaml @@ -12,6 +12,8 @@ spec: app: echo-double-one-unnamed template: metadata: + annotations: + telepresence.getambassador.io/inject-container-ports: all labels: app: echo-double-one-unnamed spec: diff --git a/integration_test/workspace_watch_test.go b/integration_test/workspace_watch_test.go index e4f3a7875c..c674b971db 100644 --- a/integration_test/workspace_watch_test.go +++ b/integration_test/workspace_watch_test.go @@ -40,7 +40,6 @@ func (s *notConnectedSuite) Test_WorkspaceListener() { return } spec := ir.InterceptSpec - spec.ServiceName = pi.ServiceName spec.ServicePort = pi.ServicePort spec.ServicePortName = pi.ServicePortName spec.ServiceUid = pi.ServiceUid diff --git a/pkg/agentconfig/portandproto.go b/pkg/agentconfig/portandproto.go index 51d34c1b91..fda01ccde9 100644 --- a/pkg/agentconfig/portandproto.go +++ b/pkg/agentconfig/portandproto.go @@ -36,7 +36,7 @@ func ParseProtocol(protocol string) (core.Protocol, error) { case core.ProtocolUDP, core.ProtocolTCP: return pr, nil default: - return "", fmt.Errorf("unsupported protocol: %s", pr) + return core.ProtocolTCP, fmt.Errorf("unsupported protocol: %s", pr) } } @@ -58,6 +58,8 @@ func NewPortAndProto(s string) (PortAndProto, error) { return pp, err } +// String will consistently yield the identifier without the protocol suffix when the protocol is TCP +// and otherwise always use the suffix "/UDP". func (pp PortAndProto) String() string { if pp.Proto == core.ProtocolTCP { return strconv.Itoa(int(pp.Port)) diff --git a/pkg/agentconfig/portidentifier.go b/pkg/agentconfig/portidentifier.go index 8c62adf0f4..cef09538d8 100644 --- a/pkg/agentconfig/portidentifier.go +++ b/pkg/agentconfig/portidentifier.go @@ -80,6 +80,18 @@ func (spi PortIdentifier) ProtoAndNameOrNumber() (core.Protocol, string, uint16) return p, s, 0 } +// String will consistently yield the identifier without the protocol suffix when the protocol is TCP +// and otherwise always use the suffix "/UDP". func (spi PortIdentifier) String() string { - return string(spi) + p, s, n := spi.ProtoAndNameOrNumber() + switch { + case s == "" && p == core.ProtocolTCP: + return strconv.Itoa(int(n)) + case s != "" && p == core.ProtocolTCP: + return s + case s == "": + return fmt.Sprintf("%d/%s", n, p) + default: + return fmt.Sprintf("%s/%s", s, p) + } } diff --git a/pkg/agentconfig/portmapping.go b/pkg/agentconfig/portmapping.go new file mode 100644 index 0000000000..6a1ba68e09 --- /dev/null +++ b/pkg/agentconfig/portmapping.go @@ -0,0 +1,65 @@ +package agentconfig + +import ( + "strconv" + "strings" +) + +type PortMapping string + +func (p PortMapping) String() string { + return string(p) +} + +func (p PortMapping) From() PortIdentifier { + from, _, _ := p.FromAndTo() + return from +} + +func (p PortMapping) To() PortAndProto { + _, toAndProto, _ := p.FromAndTo() + return toAndProto +} + +func (p PortMapping) Validate() error { + _, _, err := p.FromAndTo() + return err +} + +// FromAndTo returns the identifier for the source port and the PortAndProto of the destination port. +// An error is returned if the port-mapping syntax is invalid. +func (p PortMapping) FromAndTo() (from PortIdentifier, to PortAndProto, err error) { + ps := string(p) + if sepIdx := strings.Index(ps, ":"); sepIdx > 0 { + to, err = NewPortAndProto(ps[sepIdx+1:]) + if err == nil { + from, err = NewPortIdentifier(string(to.Proto), ps[:sepIdx]) + } + } else { + to, err = NewPortAndProto(ps) + if err == nil { + from = PortIdentifier(ps) + } + } + return +} + +// FromNumberAndTo returns source port number and the PortAndProto of the destination port. +// An error is returned if the source port is symbolic or if the port-mapping syntax is invalid. +func (p PortMapping) FromNumberAndTo() (from uint16, to PortAndProto, err error) { + ps := string(p) + if sepIdx := strings.Index(ps, ":"); sepIdx > 0 { + to, err = NewPortAndProto(ps[sepIdx+1:]) + if err == nil { + var fi uint64 + fi, err = strconv.ParseUint(ps[:sepIdx], 10, 16) + from = uint16(fi) + } + } else { + to, err = NewPortAndProto(ps) + if err == nil { + from = to.Port + } + } + return +} diff --git a/pkg/agentmap/generator.go b/pkg/agentmap/generator.go index 16a9d9eca1..d6010f0886 100644 --- a/pkg/agentmap/generator.go +++ b/pkg/agentmap/generator.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "slices" + "strconv" "strings" core "k8s.io/api/core/v1" @@ -57,17 +58,48 @@ type BasicGeneratorConfig struct { SecurityContext *core.SecurityContext } +func portsFromContainerPortsAnnotation(wl k8sapi.Workload) (ports []agentconfig.PortIdentifier, err error) { + pod := wl.GetPodTemplate() + cpa := pod.GetAnnotations()[ContainerPortsAnnotation] + switch cpa { + case "": + return nil, nil + case "all": + cns := pod.Spec.Containers + for i := range cns { + for _, pn := range cns[i].Ports { + pi := pn.Name + if pi == "" { + pi = strconv.Itoa(int(pn.ContainerPort)) + } + if pn.Protocol != core.ProtocolTCP { + pi += "/" + string(pn.Protocol) + } + ports = append(ports, agentconfig.PortIdentifier(pi)) + } + } + default: + ports, err = portsFromAnnotationValue(wl, ContainerPortsAnnotation, cpa) + } + return ports, err +} + func portsFromAnnotation(wl k8sapi.Workload, annotation string) (ports []agentconfig.PortIdentifier, err error) { if cpa := wl.GetPodTemplate().GetAnnotations()[annotation]; cpa != "" { - cps := strings.Split(cpa, ",") - ports = make([]agentconfig.PortIdentifier, len(cps)) - for i, cp := range cps { - pi := agentconfig.PortIdentifier(cp) - if err = pi.Validate(); err != nil { - return nil, fmt.Errorf("unable to parse annotation %s of workload %s.%s: %w", annotation, wl.GetName(), wl.GetNamespace(), err) - } - ports[i] = pi + ports, err = portsFromAnnotationValue(wl, annotation, cpa) + } + return ports, err +} + +func portsFromAnnotationValue(wl k8sapi.Workload, annotation, value string) (ports []agentconfig.PortIdentifier, err error) { + cps := strings.Split(value, ",") + ports = make([]agentconfig.PortIdentifier, len(cps)) + for i, cp := range cps { + pi := agentconfig.PortIdentifier(cp) + if err = pi.Validate(); err != nil { + return nil, fmt.Errorf("unable to parse annotation %s of workload %s.%s: %w", annotation, wl.GetName(), wl.GetNamespace(), err) } + ports[i] = pi } return ports, nil } @@ -133,7 +165,7 @@ func (cfg *BasicGeneratorConfig) Generate( ccs = appendAgentContainerConfigs(ctx, svcImpl, pod, ports, agentPortNumberFunc, ccs, existingConfig, cfg.AppProtocolStrategy, ignoredVolumeMounts) } - ports, err = portsFromAnnotation(wl, ContainerPortsAnnotation) + ports, err = portsFromContainerPortsAnnotation(wl) if err != nil { return nil, err } @@ -144,7 +176,7 @@ func (cfg *BasicGeneratorConfig) Generate( } // Append other containers even though they aren't directly interceptable. They might be fronted by a - // dispatching container that is, or they might be an ingest candidates. + // dispatching container that is, or they might be candidates for `ingest`. for i := range cns { cn := &cns[i] if cn.Name == agentconfig.ContainerName { diff --git a/pkg/client/cli/intercept/command.go b/pkg/client/cli/intercept/command.go index 0c23b22b59..444335494f 100644 --- a/pkg/client/cli/intercept/command.go +++ b/pkg/client/cli/intercept/command.go @@ -30,12 +30,12 @@ type Command struct { EnvFlags env.Flags DockerFlags docker.Flags MountFlags mount.Flags - Name string // Command[0] || `${Command[0]}-${--namespace}` // which depends on a combinationof --workload and --namespace - AgentName string // --workload || Command[0] // only valid if !localOnly - Port string // --port - ServiceName string // --service - ContainerName string // --container - Address string // --address + Name string // Command[0] || `${Command[0]}-${--namespace}` // which depends on a combinationof --workload and --namespace + AgentName string // --workload || Command[0] // only valid if !localOnly + Ports []string // --port + ServiceName string // --service + ContainerName string // --container + Address string // --address Replace bool // whether --replace was passed @@ -55,11 +55,10 @@ type Command struct { func (c *Command) AddFlags(cmd *cobra.Command) { flagSet := cmd.Flags() flagSet.StringVarP(&c.AgentName, "workload", "w", "", "Name of workload (Deployment, ReplicaSet, StatefulSet, Rollout) to intercept, if different from ") - flagSet.StringVarP(&c.Port, "port", "p", "", ``+ - `Local port to forward to. If intercepting a service with multiple ports, `+ - `use :, where the identifier is the port name or port number. `+ + flagSet.StringSliceVarP(&c.Ports, "port", "p", nil, ``+ + `Local ports to forward to. Use : to uniquely identify service ports, where the is the port name or number. `+ `With --docker-run and a daemon that doesn't run in docker', use : or `+ - `::.`, + `::.`, ) flagSet.StringVar(&c.Address, "address", "127.0.0.1", ``+ @@ -73,7 +72,7 @@ func (c *Command) AddFlags(cmd *cobra.Command) { "Name of container that provides the environment and mounts for the intercept. Defaults to the container matching the targetPort") flagSet.StringSliceVar(&c.ToPod, "to-pod", []string{}, ``+ - `An additional port to forward from the intercepted pod, will be made available at localhost:PORT `+ + `An additional port to forward to the intercepted pod, will available for connections to localhost:PORT. `+ `Use this to, for example, access proxy/helper sidecars in the intercepted pod. The default protocol is TCP. `+ `Use /UDP for UDP ports`) @@ -108,10 +107,10 @@ func (c *Command) Validate(cmd *cobra.Command, positional []string) error { if c.AgentName == "" { c.AgentName = c.Name } - if c.Port == "" { + if len(c.Ports) == 0 { // Port defaults to the targeted container port unless a default is explicitly set in the client config. if dp := client.GetConfig(cmd.Context()).Intercept().DefaultPort; dp != 0 { - c.Port = strconv.Itoa(dp) + c.Ports = []string{strconv.Itoa(dp)} } } if err := c.MountFlags.Validate(cmd); err != nil { diff --git a/pkg/client/cli/intercept/info.go b/pkg/client/cli/intercept/info.go index 8fe63c79ff..866a78f521 100644 --- a/pkg/client/cli/intercept/info.go +++ b/pkg/client/cli/intercept/info.go @@ -4,13 +4,13 @@ import ( "context" "fmt" "io" - "net" + "strconv" "strings" "github.com/telepresenceio/telepresence/rpc/v2/manager" + "github.com/telepresenceio/telepresence/v2/pkg/agentconfig" "github.com/telepresenceio/telepresence/v2/pkg/client/cli/mount" "github.com/telepresenceio/telepresence/v2/pkg/ioutil" - "github.com/telepresenceio/telepresence/v2/pkg/iputil" ) type Ingress struct { @@ -28,10 +28,12 @@ type Info struct { WorkloadKind string `json:"workload_kind,omitempty" yaml:"workload_kind,omitempty"` TargetHost string `json:"target_host,omitempty" yaml:"target_host,omitempty"` TargetPort int32 `json:"target_port,omitempty" yaml:"target_port,omitempty"` + PodPorts []string `json:"pod_ports,omitempty" yaml:"pod_ports,omitempty"` ServiceUID string `json:"service_uid,omitempty" yaml:"service_uid,omitempty"` ServicePortID string `json:"service_port_id,omitempty" yaml:"service_port_id,omitempty"` // ServicePortID is deprecated. Use PortID PortID string `json:"port_id,omitempty" yaml:"port_id,omitempty"` ContainerPort int32 `json:"container_port,omitempty" yaml:"container_port,omitempty"` + Protocol string `json:"protocol,omitempty" yaml:"protocol,omitempty"` Environment map[string]string `json:"environment,omitempty" yaml:"environment,omitempty"` Mount *mount.Info `json:"mount,omitempty" yaml:"mount,omitempty"` FilterDesc string `json:"filter_desc,omitempty" yaml:"filter_desc,omitempty"` @@ -83,10 +85,12 @@ func NewInfo(ctx context.Context, ii *manager.InterceptInfo, ro bool, mountError WorkloadKind: spec.WorkloadKind, TargetHost: spec.TargetHost, TargetPort: spec.TargetPort, + PodPorts: spec.PodPorts, Mount: m, ServiceUID: spec.ServiceUid, PortID: spec.PortIdentifier, ContainerPort: spec.ContainerPort, + Protocol: spec.Protocol, PodIP: ii.PodIp, Environment: ii.Environment, FilterDesc: ii.MechanismArgsDesc, @@ -124,26 +128,44 @@ func (ii *Info) WriteTo(w io.Writer) (int64, error) { kvf.Add("ID", ii.ID) } - kvf.Add( - "Destination", - net.JoinHostPort(ii.TargetHost, fmt.Sprintf("%d", ii.TargetPort)), - ) - + // Show all ports as mappings from containter port to local port. + pkv := ioutil.DefaultKeyValueFormatter() + pkv.Indent = "" + pkv.Separator = " -> " if ii.PortID != "" { - if ii.ServiceUID == "" { - kvf.Add("Container Port Identifier", ii.PortID) - } else { - kvf.Add("Service Port Identifier", ii.PortID) - } + pm, _ := agentconfig.NewPortIdentifier(ii.Protocol, strconv.Itoa(int(ii.ContainerPort))) + pkv.Add(pm.String(), fmt.Sprintf("%d %s", ii.TargetPort, ii.Protocol)) } - if ii.debug { - m := "http" - if ii.Global { - m = "tcp" + for _, pp := range ii.PodPorts { + pm := agentconfig.PortMapping(pp) + to := pm.To() + pkv.Add(pm.From().String(), fmt.Sprintf("%d %s", to.Port, to.Proto)) + } + kvf.Add("Intercepting", fmt.Sprintf("%s -> %s\n%s", ii.PodIP, ii.TargetHost, pkv)) + + if !ii.Global { + kvf.Add("Intercepting", func() string { + if ii.FilterDesc != "" { + return ii.FilterDesc + } + if ii.Global { + return `using mechanism "tcp"` + } + return fmt.Sprintf("using mechanism=%q with args=%q", "http", ii.HttpFilter) + }()) + + if ii.PreviewURL != "" { + previewURL := ii.PreviewURL + // Right now SystemA gives back domains with the leading "https://", but + // let's not rely on that. + if !strings.HasPrefix(previewURL, "https://") && !strings.HasPrefix(previewURL, "http://") { + previewURL = "https://" + previewURL + } + kvf.Add("Preview URL", previewURL) + } + if in := ii.Ingress; in != nil { + kvf.Add("Layer 5 Hostname", in.L5Host) } - kvf.Add("Mechanism", m) - kvf.Add("Mechanism Command", fmt.Sprintf("%q", ii.FilterDesc)) - kvf.Add("Metadata", fmt.Sprintf("%q", ii.Metadata)) } if m := ii.Mount; m != nil { @@ -154,30 +176,8 @@ func (ii *Info) WriteTo(w io.Writer) (int64, error) { } } - kvf.Add("Intercepting", func() string { - if ii.FilterDesc != "" { - return ii.FilterDesc - } - if ii.Global { - return `using mechanism "tcp"` - } - return fmt.Sprintf("using mechanism=%q with args=%q", "http", ii.HttpFilter) - }()) - if ii.ServiceUID == "" { - kvf.Add("Address", iputil.JoinHostPort(ii.PodIP, uint16(ii.ContainerPort))) - } - - if ii.PreviewURL != "" { - previewURL := ii.PreviewURL - // Right now SystemA gives back domains with the leading "https://", but - // let's not rely on that. - if !strings.HasPrefix(previewURL, "https://") && !strings.HasPrefix(previewURL, "http://") { - previewURL = "https://" + previewURL - } - kvf.Add("Preview URL", previewURL) - } - if in := ii.Ingress; in != nil { - kvf.Add("Layer 5 Hostname", in.L5Host) + if len(ii.Metadata) > 0 { + kvf.Add("Metadata", fmt.Sprintf("%q", ii.Metadata)) } return kvf.WriteTo(w) } diff --git a/pkg/client/cli/intercept/result.go b/pkg/client/cli/intercept/result.go index 53f33fcea9..ad11586935 100644 --- a/pkg/client/cli/intercept/result.go +++ b/pkg/client/cli/intercept/result.go @@ -40,9 +40,7 @@ func Result(r *connector.InterceptResult, err error) error { "Cannot create an intercept in namespace %q. A workstation cannot have simultaneous intercepts in different namespaces. Leave all intercepts in namespace %q first.", nss[1], nss[0]) case common.InterceptError_LOCAL_TARGET_IN_USE: - spec := r.InterceptInfo.Spec - msg = fmt.Sprintf("Port %s:%d is already in use by intercept %s", - spec.TargetHost, spec.TargetPort, spec.Name) + msg = r.ErrorText case common.InterceptError_NO_ACCEPTABLE_WORKLOAD: msg = fmt.Sprintf("No interceptable deployment, replicaset, or statefulset matching %s found", r.ErrorText) case common.InterceptError_AMBIGUOUS_MATCH: diff --git a/pkg/client/cli/intercept/state.go b/pkg/client/cli/intercept/state.go index 4d0813f897..013792e5b8 100644 --- a/pkg/client/cli/intercept/state.go +++ b/pkg/client/cli/intercept/state.go @@ -88,14 +88,34 @@ func (s *state) CreateRequest(ctx context.Context) (*connector.CreateInterceptRe ud := daemon.GetUserClient(ctx) // Parse port into spec based on how it's formatted - var err error - s.localPort, s.dockerPort, spec.PortIdentifier, err = parsePort(s.Port, s.DockerFlags.Run, ud.Containerized()) - if err != nil { - return nil, err + s.localPort, s.dockerPort, spec.PortIdentifier = 0, 0, "" + if len(s.Ports) > 0 { + var err error + s.localPort, s.dockerPort, spec.PortIdentifier, err = parsePort(s.Ports[0], s.DockerFlags.Run, ud.Containerized()) + if err != nil { + return nil, err + } + for i := 1; i < len(s.Ports); i++ { + pm := s.Ports[i] + if colIdx := strings.IndexByte(pm, ':'); colIdx > 0 { + // The "--port" arg puts local port first, but it's the destination in the pod-port mapping. + to := pm[:colIdx] + from := pm[colIdx+1:] + if slashIdx := strings.IndexByte(from, '/'); slashIdx > 0 { + from = from[:slashIdx] + to += from[slashIdx:] + } + pm = from + ":" + to + } + if err = agentconfig.PortMapping(pm).Validate(); err != nil { + return nil, errcat.User.New(err) + } + spec.PodPorts = append(spec.PodPorts, pm) + } } spec.TargetPort = int32(s.localPort) - if _, err = netip.ParseAddr(s.Address); err != nil { + if _, err := netip.ParseAddr(s.Address); err != nil { return nil, fmt.Errorf("--address %s is not a valid IP address", s.Address) } spec.TargetHost = s.Address diff --git a/pkg/client/userd/trafficmgr/intercept.go b/pkg/client/userd/trafficmgr/intercept.go index 631b453ca0..66463ed468 100644 --- a/pkg/client/userd/trafficmgr/intercept.go +++ b/pkg/client/userd/trafficmgr/intercept.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "io" + "net" "net/http" "os" "strconv" @@ -14,6 +15,7 @@ import ( grpcCodes "google.golang.org/grpc/codes" grpcStatus "google.golang.org/grpc/status" + core "k8s.io/api/core/v1" "github.com/datawire/dlib/dlog" "github.com/telepresenceio/telepresence/rpc/v2/common" @@ -333,15 +335,93 @@ func (s *session) ensureNoInterceptConflict(ir *rpc.CreateInterceptRequest) *rpc defer s.currentInterceptsLock.Unlock() spec := ir.Spec for _, iCept := range s.currentIntercepts { - switch { - case iCept.Spec.Name == spec.Name: + if iCept.Spec.Name == spec.Name { return InterceptError(common.InterceptError_ALREADY_EXISTS, errcat.User.New(spec.Name)) - case spec.TargetPort != 0 && iCept.Spec.TargetPort == spec.TargetPort && iCept.Spec.TargetHost == spec.TargetHost: - return &rpc.InterceptResult{ - Error: common.InterceptError_LOCAL_TARGET_IN_USE, - ErrorText: spec.Name, - ErrorCategory: int32(errcat.User), - InterceptInfo: iCept.InterceptInfo, + } + } + return nil +} + +// allBusyLocalPorts returns the sum of all ports that the intercept forwards to and all ports +// that are forwarded from. +func allBusyLocalPorts(spec *manager.InterceptSpec) []agentconfig.PortAndProto { + targetPort := spec.TargetPort + if targetPort == 0 { + targetPort = spec.ContainerPort + } + ports := make([]agentconfig.PortAndProto, 0, len(spec.LocalPorts)+len(spec.PodPorts)+1) + ports = append(ports, agentconfig.PortAndProto{ + Port: uint16(targetPort), + Proto: core.Protocol(spec.Protocol), + }) + for _, lp := range spec.LocalPorts { + pp, _ := agentconfig.NewPortAndProto(lp) + ports = append(ports, pp) + } + for _, ps := range spec.PodPorts { + pm := agentconfig.PortMapping(ps) + ports = append(ports, pm.To()) + } + return ports +} + +// ensureUniqueLocalPorts returns the sum of all local ports that the intercept will forward to, and all +// local ports that the client will forward from. Also ensures that there are no conflicts among those ports. +// The cluster-side of the port mappings are not checked here because we rely on the PrepareIntercept +// call to already have done that. +func ensureUniqueLocalPorts(spec *manager.InterceptSpec, pi *manager.PreparedIntercept) (map[agentconfig.PortAndProto]struct{}, error) { + targetPort := spec.TargetPort + if targetPort == 0 { + targetPort = pi.ContainerPort + } + + ports := make(map[agentconfig.PortAndProto]struct{}, len(spec.LocalPorts)+len(spec.PodPorts)+1) + ports[agentconfig.PortAndProto{ + Port: uint16(targetPort), + Proto: core.Protocol(pi.Protocol), + }] = struct{}{} + + for _, lp := range spec.LocalPorts { + pp, err := agentconfig.NewPortAndProto(lp) + if err != nil { + return nil, err + } + if _, ok := ports[pp]; ok { + return nil, fmt.Errorf("multiple use of port %s on %s", pp, spec.TargetHost) + } + ports[pp] = struct{}{} + } + for _, ps := range pi.PodPorts { + pm := agentconfig.PortMapping(ps) + if err := pm.Validate(); err != nil { + return nil, err + } + pp := pm.To() + if _, ok := ports[pp]; ok { + return nil, fmt.Errorf("multiple use of port %s on %s", pp, spec.TargetHost) + } + ports[pp] = struct{}{} + } + return ports, nil +} + +func (s *session) ensureNoPortConflict(spec *manager.InterceptSpec, ir *manager.PreparedIntercept) *rpc.InterceptResult { + ports, err := ensureUniqueLocalPorts(spec, ir) + if err != nil { + return InterceptError(common.InterceptError_TRAFFIC_MANAGER_ERROR, errcat.User.New(err)) + } + + s.currentInterceptsLock.Lock() + defer s.currentInterceptsLock.Unlock() + for _, ci := range s.currentIntercepts { + ciSpec := ci.Spec + for _, blp := range allBusyLocalPorts(ciSpec) { + if _, ok := ports[blp]; ok { + return &rpc.InterceptResult{ + Error: common.InterceptError_LOCAL_TARGET_IN_USE, + ErrorText: fmt.Sprintf("Port %s is already in use by intercept %s", net.JoinHostPort(ciSpec.TargetHost, blp.String()), ciSpec.Name), + ErrorCategory: int32(errcat.User), + } } } } @@ -367,10 +447,7 @@ func (s *session) CanIntercept(c context.Context, ir *rpc.CreateInterceptRequest return nil, nil } - mgrIr := &manager.CreateInterceptRequest{ - Session: s.SessionInfo(), - InterceptSpec: spec, - } + mgrIr := self.NewCreateInterceptRequest(spec) if er := self.InterceptProlog(c, mgrIr); er != nil { return nil, er } @@ -386,11 +463,8 @@ func (s *session) CanIntercept(c context.Context, ir *rpc.CreateInterceptRequest if pi.Error != "" { return nil, InterceptError(common.InterceptError_TRAFFIC_MANAGER_ERROR, errcat.Category(pi.ErrorCategory).New(pi.Error)) } - if spec.TargetPort == 0 { - spec.TargetPort = pi.ContainerPort - if er := s.ensureNoInterceptConflict(ir); er != nil { - return nil, er - } + if er := s.ensureNoPortConflict(spec, pi); er != nil { + return nil, er } iInfo := &interceptInfo{preparedIntercept: pi} @@ -430,7 +504,6 @@ func (s *session) AddIntercept(c context.Context, ir *rpc.CreateInterceptRequest if pi.ServicePort > 0 || pi.ServicePortName != "" { // Make spec port identifier unambiguous. - spec.ServiceName = pi.ServiceName spec.ServicePortName = pi.ServicePortName spec.ServicePort = pi.ServicePort pti, err := iInfo.PortIdentifier() @@ -439,10 +512,16 @@ func (s *session) AddIntercept(c context.Context, ir *rpc.CreateInterceptRequest } spec.PortIdentifier = pti.String() } + dlog.Debugf(c, "pi.Protocol = %s", pi.Protocol) spec.Protocol = pi.Protocol spec.ContainerPort = pi.ContainerPort + spec.PodPorts = pi.PodPorts result = iInfo.InterceptResult() + if spec.TargetPort == 0 { + spec.TargetPort = pi.ContainerPort + } + spec.ServiceUid = result.ServiceUid spec.WorkloadKind = result.WorkloadKind diff --git a/rpc/manager/manager.pb.go b/rpc/manager/manager.pb.go index 8d67d96f6a..978c90a301 100644 --- a/rpc/manager/manager.pb.go +++ b/rpc/manager/manager.pb.go @@ -168,7 +168,7 @@ func (x WorkloadInfo_Kind) Number() protoreflect.EnumNumber { // Deprecated: Use WorkloadInfo_Kind.Descriptor instead. func (WorkloadInfo_Kind) EnumDescriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{43, 0} + return file_manager_manager_proto_rawDescGZIP(), []int{44, 0} } type WorkloadInfo_State int32 @@ -228,7 +228,7 @@ func (x WorkloadInfo_State) Number() protoreflect.EnumNumber { // Deprecated: Use WorkloadInfo_State.Descriptor instead. func (WorkloadInfo_State) EnumDescriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{43, 1} + return file_manager_manager_proto_rawDescGZIP(), []int{44, 1} } type WorkloadInfo_AgentState int32 @@ -280,7 +280,7 @@ func (x WorkloadInfo_AgentState) Number() protoreflect.EnumNumber { // Deprecated: Use WorkloadInfo_AgentState.Descriptor instead. func (WorkloadInfo_AgentState) EnumDescriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{43, 2} + return file_manager_manager_proto_rawDescGZIP(), []int{44, 2} } type WorkloadEvent_Type int32 @@ -329,7 +329,7 @@ func (x WorkloadEvent_Type) Number() protoreflect.EnumNumber { // Deprecated: Use WorkloadEvent_Type.Descriptor instead. func (WorkloadEvent_Type) EnumDescriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{44, 0} + return file_manager_manager_proto_rawDescGZIP(), []int{45, 0} } // ClientInfo is the self-reported metadata that the on-laptop @@ -555,6 +555,60 @@ func (x *AgentInfo) GetContainers() map[string]*AgentInfo_ContainerInfo { return nil } +// PortMapping describes a mapping from a port number in the intercepted container to +// a port on the client for --from-pod and or vice versa when using --to-pod. +type PortMapping struct { + state protoimpl.MessageState `protogen:"open.v1"` + From int32 `protobuf:"varint,1,opt,name=from,proto3" json:"from,omitempty"` + To int32 `protobuf:"varint,2,opt,name=to,proto3" json:"to,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PortMapping) Reset() { + *x = PortMapping{} + mi := &file_manager_manager_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PortMapping) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PortMapping) ProtoMessage() {} + +func (x *PortMapping) ProtoReflect() protoreflect.Message { + mi := &file_manager_manager_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PortMapping.ProtoReflect.Descriptor instead. +func (*PortMapping) Descriptor() ([]byte, []int) { + return file_manager_manager_proto_rawDescGZIP(), []int{2} +} + +func (x *PortMapping) GetFrom() int32 { + if x != nil { + return x.From + } + return 0 +} + +func (x *PortMapping) GetTo() int32 { + if x != nil { + return x.To + } + return 0 +} + // InterceptSpec contains static information about an intercept. It is shared by // all running agent instances. type InterceptSpec struct { @@ -581,9 +635,21 @@ type InterceptSpec struct { // for more information about writing an extension descriptor file // to control what these values are. MechanismArgs []string `protobuf:"bytes,9,rep,name=mechanism_args,json=mechanismArgs,proto3" json:"mechanism_args,omitempty"` - TargetHost string `protobuf:"bytes,6,opt,name=target_host,json=targetHost,proto3" json:"target_host,omitempty"` - // The port on the workstation that the intercept is redirected to - TargetPort int32 `protobuf:"varint,7,opt,name=target_port,json=targetPort,proto3" json:"target_port,omitempty"` + // The host that the target_ports are routed to. + TargetHost string `protobuf:"bytes,6,opt,name=target_host,json=targetHost,proto3" json:"target_host,omitempty"` + // Ports that will be forwarded from the intercepting pod's IP address + // to the target_host, using the following syntax: + // + // PORT = port-decl ["/" protocol ] + // port-decl = port-spec [ ":" uint16 ] + // protocol = "TCP" | "UDP" + // port-spec = name | uint16 + // + // If two numbers are used, they signify source:destination. + PodPorts []string `protobuf:"bytes,5,rep,name=pod_ports,json=podPorts,proto3" json:"pod_ports,omitempty"` + // Ports that will be forwarded from the intercepting client's localhost + // to the intercepted pod. Uses the same syntax as target_ports. + LocalPorts []string `protobuf:"bytes,18,rep,name=local_ports,json=localPorts,proto3" json:"local_ports,omitempty"` // Identifier for the service or container port: either the name or port number // optionally followed by a "/TCP" or "/UDP" PortIdentifier string `protobuf:"bytes,10,opt,name=port_identifier,json=portIdentifier,proto3" json:"port_identifier,omitempty"` @@ -601,12 +667,10 @@ type InterceptSpec struct { // that owns the container_port, but in some cases it will differ because the container_port // is owned by some kind of routing mechanism (such as nginx). ContainerName string `protobuf:"bytes,24,opt,name=container_name,json=containerName,proto3" json:"container_name,omitempty"` - // The resolved container port + // The resolved container port that is intercepted. ContainerPort int32 `protobuf:"varint,23,opt,name=container_port,json=containerPort,proto3" json:"container_port,omitempty"` - // Extra ports that will be forwarded from the intercepting client's localhost - // to the intercepted pod. Each entry is a string containing a port number followed - // by an optional "/TCP" or "/UDP". - LocalPorts []string `protobuf:"bytes,18,rep,name=local_ports,json=localPorts,proto3" json:"local_ports,omitempty"` + // The port on the workstation that the intercepted container_port is redirected to. + TargetPort int32 `protobuf:"varint,7,opt,name=target_port,json=targetPort,proto3" json:"target_port,omitempty"` // The delay imposed by a call roundtrip between the traffic-agent and // the client on the workstation. This delay is added to the dial_timeout // when the workstation performs a dial on behalf of the traffic-agent. @@ -625,7 +689,7 @@ type InterceptSpec struct { func (x *InterceptSpec) Reset() { *x = InterceptSpec{} - mi := &file_manager_manager_proto_msgTypes[2] + mi := &file_manager_manager_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -637,7 +701,7 @@ func (x *InterceptSpec) String() string { func (*InterceptSpec) ProtoMessage() {} func (x *InterceptSpec) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[2] + mi := &file_manager_manager_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -650,7 +714,7 @@ func (x *InterceptSpec) ProtoReflect() protoreflect.Message { // Deprecated: Use InterceptSpec.ProtoReflect.Descriptor instead. func (*InterceptSpec) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{2} + return file_manager_manager_proto_rawDescGZIP(), []int{3} } func (x *InterceptSpec) GetName() string { @@ -709,11 +773,18 @@ func (x *InterceptSpec) GetTargetHost() string { return "" } -func (x *InterceptSpec) GetTargetPort() int32 { +func (x *InterceptSpec) GetPodPorts() []string { if x != nil { - return x.TargetPort + return x.PodPorts } - return 0 + return nil +} + +func (x *InterceptSpec) GetLocalPorts() []string { + if x != nil { + return x.LocalPorts + } + return nil } func (x *InterceptSpec) GetPortIdentifier() string { @@ -772,11 +843,11 @@ func (x *InterceptSpec) GetContainerPort() int32 { return 0 } -func (x *InterceptSpec) GetLocalPorts() []string { +func (x *InterceptSpec) GetTargetPort() int32 { if x != nil { - return x.LocalPorts + return x.TargetPort } - return nil + return 0 } func (x *InterceptSpec) GetRoundtripLatency() int64 { @@ -823,7 +894,7 @@ type IngressInfo struct { func (x *IngressInfo) Reset() { *x = IngressInfo{} - mi := &file_manager_manager_proto_msgTypes[3] + mi := &file_manager_manager_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -835,7 +906,7 @@ func (x *IngressInfo) String() string { func (*IngressInfo) ProtoMessage() {} func (x *IngressInfo) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[3] + mi := &file_manager_manager_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -848,7 +919,7 @@ func (x *IngressInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use IngressInfo.ProtoReflect.Descriptor instead. func (*IngressInfo) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{3} + return file_manager_manager_proto_rawDescGZIP(), []int{4} } func (x *IngressInfo) GetHost() string { @@ -891,7 +962,7 @@ type PreviewSpec struct { func (x *PreviewSpec) Reset() { *x = PreviewSpec{} - mi := &file_manager_manager_proto_msgTypes[4] + mi := &file_manager_manager_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -903,7 +974,7 @@ func (x *PreviewSpec) String() string { func (*PreviewSpec) ProtoMessage() {} func (x *PreviewSpec) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[4] + mi := &file_manager_manager_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -916,7 +987,7 @@ func (x *PreviewSpec) ProtoReflect() protoreflect.Message { // Deprecated: Use PreviewSpec.ProtoReflect.Descriptor instead. func (*PreviewSpec) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{4} + return file_manager_manager_proto_rawDescGZIP(), []int{5} } func (x *PreviewSpec) GetIngress() *IngressInfo { @@ -998,7 +1069,7 @@ type InterceptInfo struct { func (x *InterceptInfo) Reset() { *x = InterceptInfo{} - mi := &file_manager_manager_proto_msgTypes[5] + mi := &file_manager_manager_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1010,7 +1081,7 @@ func (x *InterceptInfo) String() string { func (*InterceptInfo) ProtoMessage() {} func (x *InterceptInfo) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[5] + mi := &file_manager_manager_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1023,7 +1094,7 @@ func (x *InterceptInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use InterceptInfo.ProtoReflect.Descriptor instead. func (*InterceptInfo) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{5} + return file_manager_manager_proto_rawDescGZIP(), []int{6} } func (x *InterceptInfo) GetSpec() *InterceptSpec { @@ -1177,7 +1248,7 @@ type SessionInfo struct { func (x *SessionInfo) Reset() { *x = SessionInfo{} - mi := &file_manager_manager_proto_msgTypes[6] + mi := &file_manager_manager_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1189,7 +1260,7 @@ func (x *SessionInfo) String() string { func (*SessionInfo) ProtoMessage() {} func (x *SessionInfo) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[6] + mi := &file_manager_manager_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1202,7 +1273,7 @@ func (x *SessionInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionInfo.ProtoReflect.Descriptor instead. func (*SessionInfo) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{6} + return file_manager_manager_proto_rawDescGZIP(), []int{7} } func (x *SessionInfo) GetSessionId() string { @@ -1236,7 +1307,7 @@ type AgentsRequest struct { func (x *AgentsRequest) Reset() { *x = AgentsRequest{} - mi := &file_manager_manager_proto_msgTypes[7] + mi := &file_manager_manager_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1248,7 +1319,7 @@ func (x *AgentsRequest) String() string { func (*AgentsRequest) ProtoMessage() {} func (x *AgentsRequest) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[7] + mi := &file_manager_manager_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1261,7 +1332,7 @@ func (x *AgentsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AgentsRequest.ProtoReflect.Descriptor instead. func (*AgentsRequest) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{7} + return file_manager_manager_proto_rawDescGZIP(), []int{8} } func (x *AgentsRequest) GetSession() *SessionInfo { @@ -1287,7 +1358,7 @@ type AgentInfoSnapshot struct { func (x *AgentInfoSnapshot) Reset() { *x = AgentInfoSnapshot{} - mi := &file_manager_manager_proto_msgTypes[8] + mi := &file_manager_manager_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1299,7 +1370,7 @@ func (x *AgentInfoSnapshot) String() string { func (*AgentInfoSnapshot) ProtoMessage() {} func (x *AgentInfoSnapshot) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[8] + mi := &file_manager_manager_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1312,7 +1383,7 @@ func (x *AgentInfoSnapshot) ProtoReflect() protoreflect.Message { // Deprecated: Use AgentInfoSnapshot.ProtoReflect.Descriptor instead. func (*AgentInfoSnapshot) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{8} + return file_manager_manager_proto_rawDescGZIP(), []int{9} } func (x *AgentInfoSnapshot) GetAgents() []*AgentInfo { @@ -1331,7 +1402,7 @@ type InterceptInfoSnapshot struct { func (x *InterceptInfoSnapshot) Reset() { *x = InterceptInfoSnapshot{} - mi := &file_manager_manager_proto_msgTypes[9] + mi := &file_manager_manager_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1343,7 +1414,7 @@ func (x *InterceptInfoSnapshot) String() string { func (*InterceptInfoSnapshot) ProtoMessage() {} func (x *InterceptInfoSnapshot) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[9] + mi := &file_manager_manager_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1356,7 +1427,7 @@ func (x *InterceptInfoSnapshot) ProtoReflect() protoreflect.Message { // Deprecated: Use InterceptInfoSnapshot.ProtoReflect.Descriptor instead. func (*InterceptInfoSnapshot) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{9} + return file_manager_manager_proto_rawDescGZIP(), []int{10} } func (x *InterceptInfoSnapshot) GetIntercepts() []*InterceptInfo { @@ -1377,7 +1448,7 @@ type CreateInterceptRequest struct { func (x *CreateInterceptRequest) Reset() { *x = CreateInterceptRequest{} - mi := &file_manager_manager_proto_msgTypes[10] + mi := &file_manager_manager_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1389,7 +1460,7 @@ func (x *CreateInterceptRequest) String() string { func (*CreateInterceptRequest) ProtoMessage() {} func (x *CreateInterceptRequest) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[10] + mi := &file_manager_manager_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1402,7 +1473,7 @@ func (x *CreateInterceptRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateInterceptRequest.ProtoReflect.Descriptor instead. func (*CreateInterceptRequest) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{10} + return file_manager_manager_proto_rawDescGZIP(), []int{11} } func (x *CreateInterceptRequest) GetSession() *SessionInfo { @@ -1436,7 +1507,7 @@ type EnsureAgentRequest struct { func (x *EnsureAgentRequest) Reset() { *x = EnsureAgentRequest{} - mi := &file_manager_manager_proto_msgTypes[11] + mi := &file_manager_manager_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1448,7 +1519,7 @@ func (x *EnsureAgentRequest) String() string { func (*EnsureAgentRequest) ProtoMessage() {} func (x *EnsureAgentRequest) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[11] + mi := &file_manager_manager_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1461,7 +1532,7 @@ func (x *EnsureAgentRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EnsureAgentRequest.ProtoReflect.Descriptor instead. func (*EnsureAgentRequest) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{11} + return file_manager_manager_proto_rawDescGZIP(), []int{12} } func (x *EnsureAgentRequest) GetSession() *SessionInfo { @@ -1492,13 +1563,14 @@ type PreparedIntercept struct { Protocol string `protobuf:"bytes,10,opt,name=protocol,proto3" json:"protocol,omitempty"` // TCP or UDP ContainerName string `protobuf:"bytes,11,opt,name=container_name,json=containerName,proto3" json:"container_name,omitempty"` ContainerPort int32 `protobuf:"varint,12,opt,name=container_port,json=containerPort,proto3" json:"container_port,omitempty"` + PodPorts []string `protobuf:"bytes,13,rep,name=pod_ports,json=podPorts,proto3" json:"pod_ports,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *PreparedIntercept) Reset() { *x = PreparedIntercept{} - mi := &file_manager_manager_proto_msgTypes[12] + mi := &file_manager_manager_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1510,7 +1582,7 @@ func (x *PreparedIntercept) String() string { func (*PreparedIntercept) ProtoMessage() {} func (x *PreparedIntercept) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[12] + mi := &file_manager_manager_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1523,7 +1595,7 @@ func (x *PreparedIntercept) ProtoReflect() protoreflect.Message { // Deprecated: Use PreparedIntercept.ProtoReflect.Descriptor instead. func (*PreparedIntercept) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{12} + return file_manager_manager_proto_rawDescGZIP(), []int{13} } func (x *PreparedIntercept) GetError() string { @@ -1610,6 +1682,13 @@ func (x *PreparedIntercept) GetContainerPort() int32 { return 0 } +func (x *PreparedIntercept) GetPodPorts() []string { + if x != nil { + return x.PodPorts + } + return nil +} + type UpdateInterceptRequest struct { state protoimpl.MessageState `protogen:"open.v1"` Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` @@ -1625,7 +1704,7 @@ type UpdateInterceptRequest struct { func (x *UpdateInterceptRequest) Reset() { *x = UpdateInterceptRequest{} - mi := &file_manager_manager_proto_msgTypes[13] + mi := &file_manager_manager_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1637,7 +1716,7 @@ func (x *UpdateInterceptRequest) String() string { func (*UpdateInterceptRequest) ProtoMessage() {} func (x *UpdateInterceptRequest) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[13] + mi := &file_manager_manager_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1650,7 +1729,7 @@ func (x *UpdateInterceptRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateInterceptRequest.ProtoReflect.Descriptor instead. func (*UpdateInterceptRequest) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{13} + return file_manager_manager_proto_rawDescGZIP(), []int{14} } func (x *UpdateInterceptRequest) GetSession() *SessionInfo { @@ -1718,7 +1797,7 @@ type RemoveInterceptRequest2 struct { func (x *RemoveInterceptRequest2) Reset() { *x = RemoveInterceptRequest2{} - mi := &file_manager_manager_proto_msgTypes[14] + mi := &file_manager_manager_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1730,7 +1809,7 @@ func (x *RemoveInterceptRequest2) String() string { func (*RemoveInterceptRequest2) ProtoMessage() {} func (x *RemoveInterceptRequest2) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[14] + mi := &file_manager_manager_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1743,7 +1822,7 @@ func (x *RemoveInterceptRequest2) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveInterceptRequest2.ProtoReflect.Descriptor instead. func (*RemoveInterceptRequest2) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{14} + return file_manager_manager_proto_rawDescGZIP(), []int{15} } func (x *RemoveInterceptRequest2) GetSession() *SessionInfo { @@ -1770,7 +1849,7 @@ type GetInterceptRequest struct { func (x *GetInterceptRequest) Reset() { *x = GetInterceptRequest{} - mi := &file_manager_manager_proto_msgTypes[15] + mi := &file_manager_manager_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1782,7 +1861,7 @@ func (x *GetInterceptRequest) String() string { func (*GetInterceptRequest) ProtoMessage() {} func (x *GetInterceptRequest) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[15] + mi := &file_manager_manager_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1795,7 +1874,7 @@ func (x *GetInterceptRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetInterceptRequest.ProtoReflect.Descriptor instead. func (*GetInterceptRequest) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{15} + return file_manager_manager_proto_rawDescGZIP(), []int{16} } func (x *GetInterceptRequest) GetSession() *SessionInfo { @@ -1839,7 +1918,7 @@ type ReviewInterceptRequest struct { func (x *ReviewInterceptRequest) Reset() { *x = ReviewInterceptRequest{} - mi := &file_manager_manager_proto_msgTypes[16] + mi := &file_manager_manager_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1851,7 +1930,7 @@ func (x *ReviewInterceptRequest) String() string { func (*ReviewInterceptRequest) ProtoMessage() {} func (x *ReviewInterceptRequest) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[16] + mi := &file_manager_manager_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1864,7 +1943,7 @@ func (x *ReviewInterceptRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReviewInterceptRequest.ProtoReflect.Descriptor instead. func (*ReviewInterceptRequest) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{16} + return file_manager_manager_proto_rawDescGZIP(), []int{17} } func (x *ReviewInterceptRequest) GetSession() *SessionInfo { @@ -1961,7 +2040,7 @@ type RemainRequest struct { func (x *RemainRequest) Reset() { *x = RemainRequest{} - mi := &file_manager_manager_proto_msgTypes[17] + mi := &file_manager_manager_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1973,7 +2052,7 @@ func (x *RemainRequest) String() string { func (*RemainRequest) ProtoMessage() {} func (x *RemainRequest) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[17] + mi := &file_manager_manager_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1986,7 +2065,7 @@ func (x *RemainRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemainRequest.ProtoReflect.Descriptor instead. func (*RemainRequest) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{17} + return file_manager_manager_proto_rawDescGZIP(), []int{18} } func (x *RemainRequest) GetSession() *SessionInfo { @@ -2015,7 +2094,7 @@ type LogLevelRequest struct { func (x *LogLevelRequest) Reset() { *x = LogLevelRequest{} - mi := &file_manager_manager_proto_msgTypes[18] + mi := &file_manager_manager_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2027,7 +2106,7 @@ func (x *LogLevelRequest) String() string { func (*LogLevelRequest) ProtoMessage() {} func (x *LogLevelRequest) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[18] + mi := &file_manager_manager_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2040,7 +2119,7 @@ func (x *LogLevelRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LogLevelRequest.ProtoReflect.Descriptor instead. func (*LogLevelRequest) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{18} + return file_manager_manager_proto_rawDescGZIP(), []int{19} } func (x *LogLevelRequest) GetLogLevel() string { @@ -2073,7 +2152,7 @@ type GetLogsRequest struct { func (x *GetLogsRequest) Reset() { *x = GetLogsRequest{} - mi := &file_manager_manager_proto_msgTypes[19] + mi := &file_manager_manager_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2085,7 +2164,7 @@ func (x *GetLogsRequest) String() string { func (*GetLogsRequest) ProtoMessage() {} func (x *GetLogsRequest) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[19] + mi := &file_manager_manager_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2098,7 +2177,7 @@ func (x *GetLogsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLogsRequest.ProtoReflect.Descriptor instead. func (*GetLogsRequest) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{19} + return file_manager_manager_proto_rawDescGZIP(), []int{20} } func (x *GetLogsRequest) GetTrafficManager() bool { @@ -2140,7 +2219,7 @@ type LogsResponse struct { func (x *LogsResponse) Reset() { *x = LogsResponse{} - mi := &file_manager_manager_proto_msgTypes[20] + mi := &file_manager_manager_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2152,7 +2231,7 @@ func (x *LogsResponse) String() string { func (*LogsResponse) ProtoMessage() {} func (x *LogsResponse) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[20] + mi := &file_manager_manager_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2165,7 +2244,7 @@ func (x *LogsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LogsResponse.ProtoReflect.Descriptor instead. func (*LogsResponse) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{20} + return file_manager_manager_proto_rawDescGZIP(), []int{21} } func (x *LogsResponse) GetPodLogs() map[string]string { @@ -2199,7 +2278,7 @@ type TelepresenceAPIInfo struct { func (x *TelepresenceAPIInfo) Reset() { *x = TelepresenceAPIInfo{} - mi := &file_manager_manager_proto_msgTypes[21] + mi := &file_manager_manager_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2211,7 +2290,7 @@ func (x *TelepresenceAPIInfo) String() string { func (*TelepresenceAPIInfo) ProtoMessage() {} func (x *TelepresenceAPIInfo) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[21] + mi := &file_manager_manager_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2224,7 +2303,7 @@ func (x *TelepresenceAPIInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use TelepresenceAPIInfo.ProtoReflect.Descriptor instead. func (*TelepresenceAPIInfo) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{21} + return file_manager_manager_proto_rawDescGZIP(), []int{22} } func (x *TelepresenceAPIInfo) GetPort() int32 { @@ -2246,7 +2325,7 @@ type VersionInfo2 struct { func (x *VersionInfo2) Reset() { *x = VersionInfo2{} - mi := &file_manager_manager_proto_msgTypes[22] + mi := &file_manager_manager_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2258,7 +2337,7 @@ func (x *VersionInfo2) String() string { func (*VersionInfo2) ProtoMessage() {} func (x *VersionInfo2) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[22] + mi := &file_manager_manager_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2271,7 +2350,7 @@ func (x *VersionInfo2) ProtoReflect() protoreflect.Message { // Deprecated: Use VersionInfo2.ProtoReflect.Descriptor instead. func (*VersionInfo2) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{22} + return file_manager_manager_proto_rawDescGZIP(), []int{23} } func (x *VersionInfo2) GetName() string { @@ -2303,7 +2382,7 @@ type License struct { func (x *License) Reset() { *x = License{} - mi := &file_manager_manager_proto_msgTypes[23] + mi := &file_manager_manager_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2315,7 +2394,7 @@ func (x *License) String() string { func (*License) ProtoMessage() {} func (x *License) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[23] + mi := &file_manager_manager_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2328,7 +2407,7 @@ func (x *License) ProtoReflect() protoreflect.Message { // Deprecated: Use License.ProtoReflect.Descriptor instead. func (*License) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{23} + return file_manager_manager_proto_rawDescGZIP(), []int{24} } func (x *License) GetLicense() string { @@ -2380,7 +2459,7 @@ type AmbassadorCloudConfig struct { func (x *AmbassadorCloudConfig) Reset() { *x = AmbassadorCloudConfig{} - mi := &file_manager_manager_proto_msgTypes[24] + mi := &file_manager_manager_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2392,7 +2471,7 @@ func (x *AmbassadorCloudConfig) String() string { func (*AmbassadorCloudConfig) ProtoMessage() {} func (x *AmbassadorCloudConfig) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[24] + mi := &file_manager_manager_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2405,7 +2484,7 @@ func (x *AmbassadorCloudConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use AmbassadorCloudConfig.ProtoReflect.Descriptor instead. func (*AmbassadorCloudConfig) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{24} + return file_manager_manager_proto_rawDescGZIP(), []int{25} } func (x *AmbassadorCloudConfig) GetHost() string { @@ -2438,7 +2517,7 @@ type AmbassadorCloudConnection struct { func (x *AmbassadorCloudConnection) Reset() { *x = AmbassadorCloudConnection{} - mi := &file_manager_manager_proto_msgTypes[25] + mi := &file_manager_manager_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2450,7 +2529,7 @@ func (x *AmbassadorCloudConnection) String() string { func (*AmbassadorCloudConnection) ProtoMessage() {} func (x *AmbassadorCloudConnection) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[25] + mi := &file_manager_manager_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2463,7 +2542,7 @@ func (x *AmbassadorCloudConnection) ProtoReflect() protoreflect.Message { // Deprecated: Use AmbassadorCloudConnection.ProtoReflect.Descriptor instead. func (*AmbassadorCloudConnection) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{25} + return file_manager_manager_proto_rawDescGZIP(), []int{26} } func (x *AmbassadorCloudConnection) GetCanConnect() bool { @@ -2483,7 +2562,7 @@ type TunnelMessage struct { func (x *TunnelMessage) Reset() { *x = TunnelMessage{} - mi := &file_manager_manager_proto_msgTypes[26] + mi := &file_manager_manager_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2495,7 +2574,7 @@ func (x *TunnelMessage) String() string { func (*TunnelMessage) ProtoMessage() {} func (x *TunnelMessage) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[26] + mi := &file_manager_manager_proto_msgTypes[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2508,7 +2587,7 @@ func (x *TunnelMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use TunnelMessage.ProtoReflect.Descriptor instead. func (*TunnelMessage) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{26} + return file_manager_manager_proto_rawDescGZIP(), []int{27} } func (x *TunnelMessage) GetPayload() []byte { @@ -2529,7 +2608,7 @@ type DialRequest struct { func (x *DialRequest) Reset() { *x = DialRequest{} - mi := &file_manager_manager_proto_msgTypes[27] + mi := &file_manager_manager_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2541,7 +2620,7 @@ func (x *DialRequest) String() string { func (*DialRequest) ProtoMessage() {} func (x *DialRequest) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[27] + mi := &file_manager_manager_proto_msgTypes[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2554,7 +2633,7 @@ func (x *DialRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DialRequest.ProtoReflect.Descriptor instead. func (*DialRequest) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{27} + return file_manager_manager_proto_rawDescGZIP(), []int{28} } func (x *DialRequest) GetConnId() []byte { @@ -2591,7 +2670,7 @@ type DNSRequest struct { func (x *DNSRequest) Reset() { *x = DNSRequest{} - mi := &file_manager_manager_proto_msgTypes[28] + mi := &file_manager_manager_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2603,7 +2682,7 @@ func (x *DNSRequest) String() string { func (*DNSRequest) ProtoMessage() {} func (x *DNSRequest) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[28] + mi := &file_manager_manager_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2616,7 +2695,7 @@ func (x *DNSRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DNSRequest.ProtoReflect.Descriptor instead. func (*DNSRequest) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{28} + return file_manager_manager_proto_rawDescGZIP(), []int{29} } func (x *DNSRequest) GetSession() *SessionInfo { @@ -2652,7 +2731,7 @@ type DNSResponse struct { func (x *DNSResponse) Reset() { *x = DNSResponse{} - mi := &file_manager_manager_proto_msgTypes[29] + mi := &file_manager_manager_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2664,7 +2743,7 @@ func (x *DNSResponse) String() string { func (*DNSResponse) ProtoMessage() {} func (x *DNSResponse) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[29] + mi := &file_manager_manager_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2677,7 +2756,7 @@ func (x *DNSResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DNSResponse.ProtoReflect.Descriptor instead. func (*DNSResponse) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{29} + return file_manager_manager_proto_rawDescGZIP(), []int{30} } func (x *DNSResponse) GetRCode() int32 { @@ -2708,7 +2787,7 @@ type DNSAgentResponse struct { func (x *DNSAgentResponse) Reset() { *x = DNSAgentResponse{} - mi := &file_manager_manager_proto_msgTypes[30] + mi := &file_manager_manager_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2720,7 +2799,7 @@ func (x *DNSAgentResponse) String() string { func (*DNSAgentResponse) ProtoMessage() {} func (x *DNSAgentResponse) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[30] + mi := &file_manager_manager_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2733,7 +2812,7 @@ func (x *DNSAgentResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DNSAgentResponse.ProtoReflect.Descriptor instead. func (*DNSAgentResponse) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{30} + return file_manager_manager_proto_rawDescGZIP(), []int{31} } func (x *DNSAgentResponse) GetSession() *SessionInfo { @@ -2768,7 +2847,7 @@ type IPNet struct { func (x *IPNet) Reset() { *x = IPNet{} - mi := &file_manager_manager_proto_msgTypes[31] + mi := &file_manager_manager_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2780,7 +2859,7 @@ func (x *IPNet) String() string { func (*IPNet) ProtoMessage() {} func (x *IPNet) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[31] + mi := &file_manager_manager_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2793,7 +2872,7 @@ func (x *IPNet) ProtoReflect() protoreflect.Message { // Deprecated: Use IPNet.ProtoReflect.Descriptor instead. func (*IPNet) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{31} + return file_manager_manager_proto_rawDescGZIP(), []int{32} } func (x *IPNet) GetIp() []byte { @@ -2844,7 +2923,7 @@ type ClusterInfo struct { func (x *ClusterInfo) Reset() { *x = ClusterInfo{} - mi := &file_manager_manager_proto_msgTypes[32] + mi := &file_manager_manager_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2856,7 +2935,7 @@ func (x *ClusterInfo) String() string { func (*ClusterInfo) ProtoMessage() {} func (x *ClusterInfo) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[32] + mi := &file_manager_manager_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2869,7 +2948,7 @@ func (x *ClusterInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use ClusterInfo.ProtoReflect.Descriptor instead. func (*ClusterInfo) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{32} + return file_manager_manager_proto_rawDescGZIP(), []int{33} } func (x *ClusterInfo) GetServiceSubnet() *IPNet { @@ -2960,7 +3039,7 @@ type Routing struct { func (x *Routing) Reset() { *x = Routing{} - mi := &file_manager_manager_proto_msgTypes[33] + mi := &file_manager_manager_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2972,7 +3051,7 @@ func (x *Routing) String() string { func (*Routing) ProtoMessage() {} func (x *Routing) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[33] + mi := &file_manager_manager_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2985,7 +3064,7 @@ func (x *Routing) ProtoReflect() protoreflect.Message { // Deprecated: Use Routing.ProtoReflect.Descriptor instead. func (*Routing) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{33} + return file_manager_manager_proto_rawDescGZIP(), []int{34} } func (x *Routing) GetAlsoProxySubnets() []*IPNet { @@ -3024,7 +3103,7 @@ type DNS struct { func (x *DNS) Reset() { *x = DNS{} - mi := &file_manager_manager_proto_msgTypes[34] + mi := &file_manager_manager_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3036,7 +3115,7 @@ func (x *DNS) String() string { func (*DNS) ProtoMessage() {} func (x *DNS) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[34] + mi := &file_manager_manager_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3049,7 +3128,7 @@ func (x *DNS) ProtoReflect() protoreflect.Message { // Deprecated: Use DNS.ProtoReflect.Descriptor instead. func (*DNS) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{34} + return file_manager_manager_proto_rawDescGZIP(), []int{35} } func (x *DNS) GetIncludeSuffixes() []string { @@ -3090,7 +3169,7 @@ type CLIConfig struct { func (x *CLIConfig) Reset() { *x = CLIConfig{} - mi := &file_manager_manager_proto_msgTypes[35] + mi := &file_manager_manager_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3102,7 +3181,7 @@ func (x *CLIConfig) String() string { func (*CLIConfig) ProtoMessage() {} func (x *CLIConfig) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[35] + mi := &file_manager_manager_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3115,7 +3194,7 @@ func (x *CLIConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use CLIConfig.ProtoReflect.Descriptor instead. func (*CLIConfig) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{35} + return file_manager_manager_proto_rawDescGZIP(), []int{36} } func (x *CLIConfig) GetConfigYaml() []byte { @@ -3134,7 +3213,7 @@ type AgentImageFQN struct { func (x *AgentImageFQN) Reset() { *x = AgentImageFQN{} - mi := &file_manager_manager_proto_msgTypes[36] + mi := &file_manager_manager_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3146,7 +3225,7 @@ func (x *AgentImageFQN) String() string { func (*AgentImageFQN) ProtoMessage() {} func (x *AgentImageFQN) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[36] + mi := &file_manager_manager_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3159,7 +3238,7 @@ func (x *AgentImageFQN) ProtoReflect() protoreflect.Message { // Deprecated: Use AgentImageFQN.ProtoReflect.Descriptor instead. func (*AgentImageFQN) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{36} + return file_manager_manager_proto_rawDescGZIP(), []int{37} } func (x *AgentImageFQN) GetFQN() string { @@ -3183,7 +3262,7 @@ type AgentPodInfo struct { func (x *AgentPodInfo) Reset() { *x = AgentPodInfo{} - mi := &file_manager_manager_proto_msgTypes[37] + mi := &file_manager_manager_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3195,7 +3274,7 @@ func (x *AgentPodInfo) String() string { func (*AgentPodInfo) ProtoMessage() {} func (x *AgentPodInfo) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[37] + mi := &file_manager_manager_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3208,7 +3287,7 @@ func (x *AgentPodInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use AgentPodInfo.ProtoReflect.Descriptor instead. func (*AgentPodInfo) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{37} + return file_manager_manager_proto_rawDescGZIP(), []int{38} } func (x *AgentPodInfo) GetPodName() string { @@ -3262,7 +3341,7 @@ type AgentPodInfoSnapshot struct { func (x *AgentPodInfoSnapshot) Reset() { *x = AgentPodInfoSnapshot{} - mi := &file_manager_manager_proto_msgTypes[38] + mi := &file_manager_manager_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3274,7 +3353,7 @@ func (x *AgentPodInfoSnapshot) String() string { func (*AgentPodInfoSnapshot) ProtoMessage() {} func (x *AgentPodInfoSnapshot) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[38] + mi := &file_manager_manager_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3287,7 +3366,7 @@ func (x *AgentPodInfoSnapshot) ProtoReflect() protoreflect.Message { // Deprecated: Use AgentPodInfoSnapshot.ProtoReflect.Descriptor instead. func (*AgentPodInfoSnapshot) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{38} + return file_manager_manager_proto_rawDescGZIP(), []int{39} } func (x *AgentPodInfoSnapshot) GetAgents() []*AgentPodInfo { @@ -3307,7 +3386,7 @@ type AgentConfigRequest struct { func (x *AgentConfigRequest) Reset() { *x = AgentConfigRequest{} - mi := &file_manager_manager_proto_msgTypes[39] + mi := &file_manager_manager_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3319,7 +3398,7 @@ func (x *AgentConfigRequest) String() string { func (*AgentConfigRequest) ProtoMessage() {} func (x *AgentConfigRequest) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[39] + mi := &file_manager_manager_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3332,7 +3411,7 @@ func (x *AgentConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AgentConfigRequest.ProtoReflect.Descriptor instead. func (*AgentConfigRequest) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{39} + return file_manager_manager_proto_rawDescGZIP(), []int{40} } func (x *AgentConfigRequest) GetSession() *SessionInfo { @@ -3358,7 +3437,7 @@ type AgentConfigResponse struct { func (x *AgentConfigResponse) Reset() { *x = AgentConfigResponse{} - mi := &file_manager_manager_proto_msgTypes[40] + mi := &file_manager_manager_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3370,7 +3449,7 @@ func (x *AgentConfigResponse) String() string { func (*AgentConfigResponse) ProtoMessage() {} func (x *AgentConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[40] + mi := &file_manager_manager_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3383,7 +3462,7 @@ func (x *AgentConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AgentConfigResponse.ProtoReflect.Descriptor instead. func (*AgentConfigResponse) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{40} + return file_manager_manager_proto_rawDescGZIP(), []int{41} } func (x *AgentConfigResponse) GetData() []byte { @@ -3406,7 +3485,7 @@ type TunnelMetrics struct { func (x *TunnelMetrics) Reset() { *x = TunnelMetrics{} - mi := &file_manager_manager_proto_msgTypes[41] + mi := &file_manager_manager_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3418,7 +3497,7 @@ func (x *TunnelMetrics) String() string { func (*TunnelMetrics) ProtoMessage() {} func (x *TunnelMetrics) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[41] + mi := &file_manager_manager_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3431,7 +3510,7 @@ func (x *TunnelMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use TunnelMetrics.ProtoReflect.Descriptor instead. func (*TunnelMetrics) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{41} + return file_manager_manager_proto_rawDescGZIP(), []int{42} } func (x *TunnelMetrics) GetClientSessionId() string { @@ -3464,7 +3543,7 @@ type KnownWorkloadKinds struct { func (x *KnownWorkloadKinds) Reset() { *x = KnownWorkloadKinds{} - mi := &file_manager_manager_proto_msgTypes[42] + mi := &file_manager_manager_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3476,7 +3555,7 @@ func (x *KnownWorkloadKinds) String() string { func (*KnownWorkloadKinds) ProtoMessage() {} func (x *KnownWorkloadKinds) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[42] + mi := &file_manager_manager_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3489,7 +3568,7 @@ func (x *KnownWorkloadKinds) ProtoReflect() protoreflect.Message { // Deprecated: Use KnownWorkloadKinds.ProtoReflect.Descriptor instead. func (*KnownWorkloadKinds) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{42} + return file_manager_manager_proto_rawDescGZIP(), []int{43} } func (x *KnownWorkloadKinds) GetKinds() []WorkloadInfo_Kind { @@ -3516,7 +3595,7 @@ type WorkloadInfo struct { func (x *WorkloadInfo) Reset() { *x = WorkloadInfo{} - mi := &file_manager_manager_proto_msgTypes[43] + mi := &file_manager_manager_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3528,7 +3607,7 @@ func (x *WorkloadInfo) String() string { func (*WorkloadInfo) ProtoMessage() {} func (x *WorkloadInfo) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[43] + mi := &file_manager_manager_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3541,7 +3620,7 @@ func (x *WorkloadInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadInfo.ProtoReflect.Descriptor instead. func (*WorkloadInfo) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{43} + return file_manager_manager_proto_rawDescGZIP(), []int{44} } func (x *WorkloadInfo) GetKind() WorkloadInfo_Kind { @@ -3603,7 +3682,7 @@ type WorkloadEvent struct { func (x *WorkloadEvent) Reset() { *x = WorkloadEvent{} - mi := &file_manager_manager_proto_msgTypes[44] + mi := &file_manager_manager_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3615,7 +3694,7 @@ func (x *WorkloadEvent) String() string { func (*WorkloadEvent) ProtoMessage() {} func (x *WorkloadEvent) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[44] + mi := &file_manager_manager_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3628,7 +3707,7 @@ func (x *WorkloadEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadEvent.ProtoReflect.Descriptor instead. func (*WorkloadEvent) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{44} + return file_manager_manager_proto_rawDescGZIP(), []int{45} } func (x *WorkloadEvent) GetType() WorkloadEvent_Type { @@ -3660,7 +3739,7 @@ type WorkloadEventsDelta struct { func (x *WorkloadEventsDelta) Reset() { *x = WorkloadEventsDelta{} - mi := &file_manager_manager_proto_msgTypes[45] + mi := &file_manager_manager_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3672,7 +3751,7 @@ func (x *WorkloadEventsDelta) String() string { func (*WorkloadEventsDelta) ProtoMessage() {} func (x *WorkloadEventsDelta) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[45] + mi := &file_manager_manager_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3685,7 +3764,7 @@ func (x *WorkloadEventsDelta) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadEventsDelta.ProtoReflect.Descriptor instead. func (*WorkloadEventsDelta) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{45} + return file_manager_manager_proto_rawDescGZIP(), []int{46} } func (x *WorkloadEventsDelta) GetSince() *timestamppb.Timestamp { @@ -3719,7 +3798,7 @@ type WorkloadEventsRequest struct { func (x *WorkloadEventsRequest) Reset() { *x = WorkloadEventsRequest{} - mi := &file_manager_manager_proto_msgTypes[46] + mi := &file_manager_manager_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3731,7 +3810,7 @@ func (x *WorkloadEventsRequest) String() string { func (*WorkloadEventsRequest) ProtoMessage() {} func (x *WorkloadEventsRequest) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[46] + mi := &file_manager_manager_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3744,7 +3823,7 @@ func (x *WorkloadEventsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadEventsRequest.ProtoReflect.Descriptor instead. func (*WorkloadEventsRequest) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{46} + return file_manager_manager_proto_rawDescGZIP(), []int{47} } func (x *WorkloadEventsRequest) GetSessionInfo() *SessionInfo { @@ -3790,7 +3869,7 @@ type AgentInfo_Mechanism struct { func (x *AgentInfo_Mechanism) Reset() { *x = AgentInfo_Mechanism{} - mi := &file_manager_manager_proto_msgTypes[47] + mi := &file_manager_manager_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3802,7 +3881,7 @@ func (x *AgentInfo_Mechanism) String() string { func (*AgentInfo_Mechanism) ProtoMessage() {} func (x *AgentInfo_Mechanism) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[47] + mi := &file_manager_manager_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3851,7 +3930,7 @@ type AgentInfo_ContainerInfo struct { func (x *AgentInfo_ContainerInfo) Reset() { *x = AgentInfo_ContainerInfo{} - mi := &file_manager_manager_proto_msgTypes[48] + mi := &file_manager_manager_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3863,7 +3942,7 @@ func (x *AgentInfo_ContainerInfo) String() string { func (*AgentInfo_ContainerInfo) ProtoMessage() {} func (x *AgentInfo_ContainerInfo) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[48] + mi := &file_manager_manager_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3903,7 +3982,7 @@ type WorkloadInfo_Intercept struct { func (x *WorkloadInfo_Intercept) Reset() { *x = WorkloadInfo_Intercept{} - mi := &file_manager_manager_proto_msgTypes[60] + mi := &file_manager_manager_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3915,7 +3994,7 @@ func (x *WorkloadInfo_Intercept) String() string { func (*WorkloadInfo_Intercept) ProtoMessage() {} func (x *WorkloadInfo_Intercept) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[60] + mi := &file_manager_manager_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3928,7 +4007,7 @@ func (x *WorkloadInfo_Intercept) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadInfo_Intercept.ProtoReflect.Descriptor instead. func (*WorkloadInfo_Intercept) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{43, 0} + return file_manager_manager_proto_rawDescGZIP(), []int{44, 0} } func (x *WorkloadInfo_Intercept) GetClient() string { @@ -4013,24 +4092,29 @@ var file_manager_manager_proto_rawDesc = []byte{ 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, - 0xf3, 0x05, 0x0a, 0x0d, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x53, 0x70, 0x65, - 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, - 0x05, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x5f, - 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, - 0x6c, 0x6f, 0x61, 0x64, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x65, 0x63, 0x68, 0x61, 0x6e, - 0x69, 0x73, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, 0x63, 0x68, 0x61, - 0x6e, 0x69, 0x73, 0x6d, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x65, 0x63, 0x68, 0x61, 0x6e, 0x69, 0x73, - 0x6d, 0x5f, 0x61, 0x72, 0x67, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x65, - 0x63, 0x68, 0x61, 0x6e, 0x69, 0x73, 0x6d, 0x41, 0x72, 0x67, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x74, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x27, 0x0a, + 0x31, 0x0a, 0x0b, 0x50, 0x6f, 0x72, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x12, + 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x66, 0x72, + 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, + 0x74, 0x6f, 0x22, 0x90, 0x06, 0x0a, 0x0d, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, + 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x12, 0x14, 0x0a, 0x05, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, + 0x61, 0x64, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, + 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, + 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x65, 0x63, + 0x68, 0x61, 0x6e, 0x69, 0x73, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, + 0x63, 0x68, 0x61, 0x6e, 0x69, 0x73, 0x6d, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x65, 0x63, 0x68, 0x61, + 0x6e, 0x69, 0x73, 0x6d, 0x5f, 0x61, 0x72, 0x67, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0d, 0x6d, 0x65, 0x63, 0x68, 0x61, 0x6e, 0x69, 0x73, 0x6d, 0x41, 0x72, 0x67, 0x73, 0x12, 0x1f, + 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x12, + 0x1b, 0x0a, 0x09, 0x70, 0x6f, 0x64, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x12, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, @@ -4049,9 +4133,9 @@ var file_manager_manager_proto_rawDesc = []byte{ 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x17, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50, - 0x6f, 0x72, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x72, - 0x74, 0x73, 0x18, 0x12, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, - 0x6f, 0x72, 0x74, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, + 0x6f, 0x72, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x70, 0x6f, + 0x72, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x50, 0x6f, 0x72, 0x74, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x5f, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, @@ -4204,7 +4288,7 @@ var file_manager_manager_proto_rawDesc = []byte{ 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xb1, 0x03, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xce, 0x03, 0x0a, 0x11, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x72, 0x72, @@ -4232,579 +4316,581 @@ var file_manager_manager_proto_rawDesc = []byte{ 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50, 0x6f, 0x72, - 0x74, 0x22, 0x8b, 0x02, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x07, - 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, - 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x51, 0x0a, - 0x12, 0x61, 0x64, 0x64, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x64, 0x6f, 0x6d, - 0x61, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x2e, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x53, 0x70, 0x65, 0x63, 0x48, 0x00, 0x52, 0x10, - 0x61, 0x64, 0x64, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, - 0x12, 0x34, 0x0a, 0x15, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, - 0x65, 0x77, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x48, - 0x00, 0x52, 0x13, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, - 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x42, 0x17, 0x0a, 0x15, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, - 0x77, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, - 0x6a, 0x0a, 0x17, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, - 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x32, 0x12, 0x3b, 0x0a, 0x07, 0x73, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, - 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x66, 0x0a, 0x13, 0x47, - 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, - 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x22, 0xb8, 0x06, 0x0a, 0x16, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x49, 0x6e, - 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, - 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, - 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x50, 0x0a, 0x0b, 0x64, - 0x69, 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, - 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, - 0x74, 0x44, 0x69, 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, - 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x70, 0x6f, 0x64, 0x5f, 0x69, - 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x6f, 0x64, 0x49, 0x70, 0x12, 0x1b, - 0x0a, 0x09, 0x73, 0x66, 0x74, 0x70, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x08, 0x73, 0x66, 0x74, 0x70, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x66, - 0x74, 0x70, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x66, - 0x74, 0x70, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x6d, 0x65, 0x63, 0x68, 0x61, - 0x6e, 0x69, 0x73, 0x6d, 0x5f, 0x61, 0x72, 0x67, 0x73, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6d, 0x65, 0x63, 0x68, 0x61, 0x6e, 0x69, 0x73, 0x6d, 0x41, - 0x72, 0x67, 0x73, 0x44, 0x65, 0x73, 0x63, 0x12, 0x53, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6f, 0x64, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x0d, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x73, 0x22, 0x8b, + 0x02, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, + 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x07, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x51, 0x0a, 0x12, 0x61, 0x64, + 0x64, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x50, 0x72, + 0x65, 0x76, 0x69, 0x65, 0x77, 0x53, 0x70, 0x65, 0x63, 0x48, 0x00, 0x52, 0x10, 0x61, 0x64, 0x64, + 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34, 0x0a, + 0x15, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x5f, + 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x13, + 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x44, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x42, 0x17, 0x0a, 0x15, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x64, + 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x6a, 0x0a, 0x17, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x32, 0x12, 0x3b, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, - 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x56, 0x0a, 0x08, - 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x12, 0x5f, 0x0a, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, - 0x65, 0x6e, 0x74, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, - 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, - 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x1a, 0x3a, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3e, - 0x0a, 0x10, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x65, - 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x3b, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, - 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, - 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, - 0x70, 0x69, 0x4b, 0x65, 0x79, 0x22, 0x65, 0x0a, 0x0f, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, - 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, - 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x67, - 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x73, 0x0a, 0x0e, - 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, - 0x0a, 0x0f, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, - 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, - 0x20, 0x0a, 0x0c, 0x67, 0x65, 0x74, 0x5f, 0x70, 0x6f, 0x64, 0x5f, 0x79, 0x61, 0x6d, 0x6c, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x67, 0x65, 0x74, 0x50, 0x6f, 0x64, 0x59, 0x61, 0x6d, - 0x6c, 0x22, 0xb7, 0x02, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x08, 0x70, 0x6f, 0x64, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, - 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x6f, 0x64, 0x4c, 0x6f, 0x67, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x70, 0x6f, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x17, - 0x0a, 0x07, 0x65, 0x72, 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x4a, 0x0a, 0x08, 0x70, 0x6f, 0x64, 0x5f, 0x79, - 0x61, 0x6d, 0x6c, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x2e, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x6f, - 0x64, 0x59, 0x61, 0x6d, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x70, 0x6f, 0x64, 0x59, - 0x61, 0x6d, 0x6c, 0x1a, 0x3a, 0x0a, 0x0c, 0x50, 0x6f, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, - 0x3a, 0x0a, 0x0c, 0x50, 0x6f, 0x64, 0x59, 0x61, 0x6d, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x29, 0x0a, 0x13, 0x54, - 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x41, 0x50, 0x49, 0x49, 0x6e, - 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x3c, 0x0a, 0x0c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x32, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x85, 0x01, 0x0a, 0x07, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, - 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, - 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x1d, - 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, - 0x07, 0x65, 0x72, 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x65, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x22, 0x6c, 0x0a, 0x15, - 0x41, 0x6d, 0x62, 0x61, 0x73, 0x73, 0x61, 0x64, 0x6f, 0x72, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, - 0x08, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x63, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, - 0x00, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x61, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, - 0x09, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x63, 0x61, 0x22, 0x3c, 0x0a, 0x19, 0x41, 0x6d, - 0x62, 0x61, 0x73, 0x73, 0x61, 0x64, 0x6f, 0x72, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x61, 0x6e, 0x5f, 0x63, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x63, 0x61, - 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x22, 0x29, 0x0a, 0x0d, 0x54, 0x75, 0x6e, 0x6e, - 0x65, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, - 0x6f, 0x61, 0x64, 0x22, 0x7c, 0x0a, 0x0b, 0x44, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x6e, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x72, - 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x5f, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, - 0x70, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x61, 0x6c, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, - 0x64, 0x69, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4a, 0x04, 0x08, 0x04, 0x10, - 0x05, 0x22, 0x71, 0x0a, 0x0a, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x66, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x22, 0x36, 0x0a, 0x0b, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x05, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x72, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x72, 0x72, 0x73, 0x22, 0xca, 0x01, 0x0a, - 0x10, 0x44, 0x4e, 0x53, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x3b, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, - 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3a, - 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x20, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, - 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x08, 0x72, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, + 0x22, 0xb8, 0x06, 0x0a, 0x16, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x07, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x72, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, - 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x0a, 0x05, 0x49, 0x50, 0x4e, - 0x65, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, - 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x04, 0x6d, 0x61, 0x73, 0x6b, 0x22, 0x8c, 0x04, 0x0a, 0x0b, 0x43, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x42, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x5f, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x49, 0x50, 0x4e, 0x65, 0x74, 0x52, 0x0d, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x12, 0x3c, 0x0a, 0x0b, 0x70, 0x6f, - 0x64, 0x5f, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, - 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x49, 0x50, 0x4e, 0x65, 0x74, 0x52, 0x0a, 0x70, 0x6f, - 0x64, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x64, 0x5f, 0x69, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0c, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x50, 0x6f, 0x64, 0x49, 0x70, 0x12, 0x28, - 0x0a, 0x10, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x64, 0x5f, 0x70, 0x6f, - 0x72, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, - 0x72, 0x50, 0x6f, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x69, 0x6e, 0x6a, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x76, 0x63, 0x5f, 0x69, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0d, 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x76, 0x63, 0x49, 0x70, - 0x12, 0x2a, 0x0a, 0x11, 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x76, 0x63, - 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x69, 0x6e, 0x6a, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x76, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x2a, 0x0a, 0x11, - 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x76, 0x63, 0x5f, 0x68, 0x6f, 0x73, - 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x53, 0x76, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x37, 0x0a, 0x07, 0x72, 0x6f, 0x75, 0x74, - 0x69, 0x6e, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, - 0x67, 0x12, 0x2b, 0x0a, 0x03, 0x64, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x03, 0x64, 0x6e, 0x73, 0x12, 0x1e, - 0x0a, 0x0b, 0x6b, 0x75, 0x62, 0x65, 0x5f, 0x64, 0x6e, 0x73, 0x5f, 0x69, 0x70, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6b, 0x75, 0x62, 0x65, 0x44, 0x6e, 0x73, 0x49, 0x70, 0x12, 0x25, - 0x0a, 0x0e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x44, - 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0xfa, 0x01, 0x0a, 0x07, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, - 0x67, 0x12, 0x49, 0x0a, 0x12, 0x61, 0x6c, 0x73, 0x6f, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, - 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x50, 0x0a, 0x0b, 0x64, 0x69, 0x73, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, - 0x61, 0x67, 0x65, 0x72, 0x2e, 0x49, 0x50, 0x4e, 0x65, 0x74, 0x52, 0x10, 0x61, 0x6c, 0x73, 0x6f, - 0x50, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x12, 0x4b, 0x0a, 0x13, - 0x6e, 0x65, 0x76, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x75, 0x62, 0x6e, - 0x65, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x61, 0x67, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x44, 0x69, + 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0b, 0x64, + 0x69, 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x70, 0x6f, 0x64, 0x5f, 0x69, 0x70, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x6f, 0x64, 0x49, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x73, + 0x66, 0x74, 0x70, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, + 0x73, 0x66, 0x74, 0x70, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x74, 0x70, 0x5f, + 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x66, 0x74, 0x70, 0x50, + 0x6f, 0x72, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, + 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x6d, 0x65, 0x63, 0x68, 0x61, 0x6e, 0x69, 0x73, + 0x6d, 0x5f, 0x61, 0x72, 0x67, 0x73, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x11, 0x6d, 0x65, 0x63, 0x68, 0x61, 0x6e, 0x69, 0x73, 0x6d, 0x41, 0x72, 0x67, 0x73, + 0x44, 0x65, 0x73, 0x63, 0x12, 0x53, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, + 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, + 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x76, + 0x69, 0x65, 0x77, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x56, 0x0a, 0x08, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x72, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, + 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x12, 0x5f, 0x0a, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, + 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x52, 0x65, + 0x76, 0x69, 0x65, 0x77, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x2e, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, + 0x6e, 0x74, 0x1a, 0x3a, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3b, + 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3e, 0x0a, 0x10, 0x45, + 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x65, 0x0a, 0x0d, 0x52, + 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x07, + 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x61, 0x70, 0x69, + 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x70, 0x69, 0x4b, + 0x65, 0x79, 0x22, 0x65, 0x0a, 0x0f, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, + 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x4c, 0x65, 0x76, + 0x65, 0x6c, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x73, 0x0a, 0x0e, 0x47, 0x65, 0x74, + 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x74, + 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x4d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x20, 0x0a, 0x0c, + 0x67, 0x65, 0x74, 0x5f, 0x70, 0x6f, 0x64, 0x5f, 0x79, 0x61, 0x6d, 0x6c, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0a, 0x67, 0x65, 0x74, 0x50, 0x6f, 0x64, 0x59, 0x61, 0x6d, 0x6c, 0x22, 0xb7, + 0x02, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x4a, 0x0a, 0x08, 0x70, 0x6f, 0x64, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, + 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x6f, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x07, 0x70, 0x6f, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x65, + 0x72, 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, + 0x72, 0x4d, 0x73, 0x67, 0x12, 0x4a, 0x0a, 0x08, 0x70, 0x6f, 0x64, 0x5f, 0x79, 0x61, 0x6d, 0x6c, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x6f, + 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x6f, 0x64, 0x59, 0x61, + 0x6d, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x70, 0x6f, 0x64, 0x59, 0x61, 0x6d, 0x6c, + 0x1a, 0x3a, 0x0a, 0x0c, 0x50, 0x6f, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3a, 0x0a, 0x0c, + 0x50, 0x6f, 0x64, 0x59, 0x61, 0x6d, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x29, 0x0a, 0x13, 0x54, 0x65, 0x6c, 0x65, + 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x41, 0x50, 0x49, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, + 0x6f, 0x72, 0x74, 0x22, 0x3c, 0x0a, 0x0c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, + 0x66, 0x6f, 0x32, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x22, 0x85, 0x01, 0x0a, 0x07, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x72, + 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, + 0x4d, 0x73, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x22, 0x6c, 0x0a, 0x15, 0x41, 0x6d, 0x62, + 0x61, 0x73, 0x73, 0x61, 0x64, 0x6f, 0x72, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x08, 0x70, 0x72, + 0x6f, 0x78, 0x79, 0x5f, 0x63, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, + 0x70, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x61, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x63, 0x61, 0x22, 0x3c, 0x0a, 0x19, 0x41, 0x6d, 0x62, 0x61, 0x73, + 0x73, 0x61, 0x64, 0x6f, 0x72, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x61, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x63, 0x61, 0x6e, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x22, 0x29, 0x0a, 0x0d, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, + 0x22, 0x7c, 0x0a, 0x0b, 0x44, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x17, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x6e, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x6f, 0x75, 0x6e, + 0x64, 0x74, 0x72, 0x69, 0x70, 0x5f, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x10, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x4c, 0x61, + 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x61, 0x6c, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x64, 0x69, 0x61, + 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x71, + 0x0a, 0x0a, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x07, + 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x36, 0x0a, 0x0b, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x15, 0x0a, 0x06, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x05, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x72, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x72, 0x72, 0x73, 0x22, 0xca, 0x01, 0x0a, 0x10, 0x44, 0x4e, + 0x53, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, + 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x07, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x72, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x2e, 0x49, 0x50, 0x4e, 0x65, 0x74, 0x52, 0x11, 0x6e, 0x65, 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, - 0x78, 0x79, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x12, 0x57, 0x0a, 0x19, 0x61, 0x6c, 0x6c, - 0x6f, 0x77, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x73, + 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x0a, 0x05, 0x49, 0x50, 0x4e, 0x65, 0x74, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, + 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x6d, + 0x61, 0x73, 0x6b, 0x22, 0x8c, 0x04, 0x0a, 0x0b, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x42, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x73, + 0x75, 0x62, 0x6e, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x72, 0x2e, 0x49, 0x50, 0x4e, 0x65, 0x74, 0x52, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x12, 0x3c, 0x0a, 0x0b, 0x70, 0x6f, 0x64, 0x5f, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x72, 0x2e, 0x49, 0x50, 0x4e, 0x65, 0x74, 0x52, 0x17, 0x61, 0x6c, 0x6c, 0x6f, 0x77, - 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x73, 0x22, 0x9b, 0x01, 0x0a, 0x03, 0x44, 0x4e, 0x53, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x53, 0x75, 0x66, - 0x66, 0x69, 0x78, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, - 0x5f, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x0f, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x53, 0x75, 0x66, 0x66, 0x69, 0x78, 0x65, 0x73, - 0x12, 0x17, 0x0a, 0x07, 0x6b, 0x75, 0x62, 0x65, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x06, 0x6b, 0x75, 0x62, 0x65, 0x49, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6c, 0x75, - 0x73, 0x74, 0x65, 0x72, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, - 0x22, 0x2c, 0x0a, 0x09, 0x43, 0x4c, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1f, 0x0a, - 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x79, 0x61, 0x6d, 0x6c, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x59, 0x61, 0x6d, 0x6c, 0x22, 0x23, - 0x0a, 0x0d, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x46, 0x51, 0x4e, 0x12, - 0x12, 0x0a, 0x05, 0x66, 0x5f, 0x71, 0x5f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x66, 0x51, 0x4e, 0x22, 0xc0, 0x01, 0x0a, 0x0c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x64, - 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6f, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6f, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x15, 0x0a, - 0x06, 0x70, 0x6f, 0x64, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, - 0x6f, 0x64, 0x49, 0x70, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x70, 0x6f, 0x72, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x61, 0x70, 0x69, 0x50, 0x6f, 0x72, 0x74, 0x12, - 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x65, - 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, - 0x61, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x52, 0x0a, 0x14, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x50, - 0x6f, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x3a, - 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x64, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x65, 0x0a, 0x12, 0x41, 0x67, - 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x3b, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, - 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x22, 0x29, 0x0a, 0x13, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x83, 0x01, 0x0a, - 0x0d, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x2a, - 0x0a, 0x11, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, - 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0c, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, - 0x21, 0x0a, 0x0c, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x42, 0x79, 0x74, - 0x65, 0x73, 0x22, 0x53, 0x0a, 0x12, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, - 0x6f, 0x61, 0x64, 0x4b, 0x69, 0x6e, 0x64, 0x73, 0x12, 0x3d, 0x0a, 0x05, 0x6b, 0x69, 0x6e, 0x64, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, - 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x57, - 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x4b, 0x69, 0x6e, 0x64, - 0x52, 0x05, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x22, 0x8d, 0x05, 0x0a, 0x0c, 0x57, 0x6f, 0x72, 0x6b, - 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3b, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, - 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x57, 0x6f, - 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x4b, 0x69, 0x6e, 0x64, 0x52, - 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x4e, 0x0a, 0x0b, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, + 0x67, 0x65, 0x72, 0x2e, 0x49, 0x50, 0x4e, 0x65, 0x74, 0x52, 0x0a, 0x70, 0x6f, 0x64, 0x53, 0x75, + 0x62, 0x6e, 0x65, 0x74, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, + 0x5f, 0x70, 0x6f, 0x64, 0x5f, 0x69, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x50, 0x6f, 0x64, 0x49, 0x70, 0x12, 0x28, 0x0a, 0x10, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x64, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x50, 0x6f, + 0x64, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x5f, 0x73, 0x76, 0x63, 0x5f, 0x69, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, + 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x76, 0x63, 0x49, 0x70, 0x12, 0x2a, 0x0a, + 0x11, 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x76, 0x63, 0x5f, 0x70, 0x6f, + 0x72, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x53, 0x76, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x69, 0x6e, 0x6a, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x76, 0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x0b, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x76, + 0x63, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x37, 0x0a, 0x07, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x52, 0x6f, + 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x2b, + 0x0a, 0x03, 0x64, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x72, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x03, 0x64, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x6b, + 0x75, 0x62, 0x65, 0x5f, 0x64, 0x6e, 0x73, 0x5f, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x09, 0x6b, 0x75, 0x62, 0x65, 0x44, 0x6e, 0x73, 0x49, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x63, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x44, 0x6f, 0x6d, 0x61, + 0x69, 0x6e, 0x22, 0xfa, 0x01, 0x0a, 0x07, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x49, + 0x0a, 0x12, 0x61, 0x6c, 0x73, 0x6f, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x75, 0x62, + 0x6e, 0x65, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x72, 0x2e, 0x49, 0x50, 0x4e, 0x65, 0x74, 0x52, 0x10, 0x61, 0x6c, 0x73, 0x6f, 0x50, 0x72, 0x6f, + 0x78, 0x79, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x12, 0x4b, 0x0a, 0x13, 0x6e, 0x65, 0x76, + 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x49, 0x50, + 0x4e, 0x65, 0x74, 0x52, 0x11, 0x6e, 0x65, 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x53, + 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x12, 0x57, 0x0a, 0x19, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, + 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x75, 0x62, 0x6e, + 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, + 0x2e, 0x49, 0x50, 0x4e, 0x65, 0x74, 0x52, 0x17, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, + 0x66, 0x6c, 0x69, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x22, + 0x9b, 0x01, 0x0a, 0x03, 0x44, 0x4e, 0x53, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x5f, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x53, 0x75, 0x66, 0x66, 0x69, 0x78, + 0x65, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x73, 0x75, + 0x66, 0x66, 0x69, 0x78, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x65, 0x78, + 0x63, 0x6c, 0x75, 0x64, 0x65, 0x53, 0x75, 0x66, 0x66, 0x69, 0x78, 0x65, 0x73, 0x12, 0x17, 0x0a, + 0x07, 0x6b, 0x75, 0x62, 0x65, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, + 0x6b, 0x75, 0x62, 0x65, 0x49, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, + 0x72, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x2c, 0x0a, + 0x09, 0x43, 0x4c, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x79, 0x61, 0x6d, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x59, 0x61, 0x6d, 0x6c, 0x22, 0x23, 0x0a, 0x0d, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x46, 0x51, 0x4e, 0x12, 0x12, 0x0a, 0x05, + 0x66, 0x5f, 0x71, 0x5f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x66, 0x51, 0x4e, + 0x22, 0xc0, 0x01, 0x0a, 0x0c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x64, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6f, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6f, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, + 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x70, 0x6f, + 0x64, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x6f, 0x64, 0x49, + 0x70, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x07, 0x61, 0x70, 0x69, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x20, 0x0a, 0x0b, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x12, 0x23, + 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x4e, + 0x61, 0x6d, 0x65, 0x22, 0x52, 0x0a, 0x14, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x64, 0x49, + 0x6e, 0x66, 0x6f, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x3a, 0x0a, 0x06, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x65, 0x0a, 0x12, 0x41, 0x67, 0x65, 0x6e, 0x74, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, + 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x6e, - 0x66, 0x6f, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0a, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x59, 0x0a, 0x11, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, + 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x29, + 0x0a, 0x13, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x83, 0x01, 0x0a, 0x0d, 0x54, 0x75, + 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x67, 0x72, 0x65, + 0x73, 0x73, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, + 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, + 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0b, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, + 0x53, 0x0a, 0x12, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, + 0x4b, 0x69, 0x6e, 0x64, 0x73, 0x12, 0x3d, 0x0a, 0x05, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, 0x6b, - 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, - 0x70, 0x74, 0x52, 0x10, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x43, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x73, 0x12, 0x3e, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, + 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x05, 0x6b, + 0x69, 0x6e, 0x64, 0x73, 0x22, 0x8d, 0x05, 0x0a, 0x0c, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, + 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3b, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, - 0x6f, 0x61, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, - 0x74, 0x61, 0x74, 0x65, 0x1a, 0x23, 0x0a, 0x09, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, - 0x74, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x22, 0x55, 0x0a, 0x04, 0x4b, 0x69, 0x6e, - 0x64, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, - 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x45, 0x50, 0x4c, 0x4f, 0x59, 0x4d, 0x45, 0x4e, 0x54, - 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x50, 0x4c, 0x49, 0x43, 0x41, 0x53, 0x45, 0x54, - 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x54, 0x41, 0x54, 0x45, 0x46, 0x55, 0x4c, 0x53, 0x45, - 0x54, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x4f, 0x4c, 0x4c, 0x4f, 0x55, 0x54, 0x10, 0x04, - 0x22, 0x4d, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x55, 0x4e, 0x4b, - 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, - 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x41, 0x56, 0x41, 0x49, 0x4c, 0x41, 0x42, 0x4c, 0x45, 0x10, - 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4e, 0x47, - 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x03, 0x22, - 0x46, 0x0a, 0x0a, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, - 0x14, 0x4e, 0x4f, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x53, 0x54, 0x41, - 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x43, - 0x45, 0x50, 0x54, 0x45, 0x44, 0x10, 0x02, 0x22, 0xc7, 0x01, 0x0a, 0x0d, 0x57, 0x6f, 0x72, 0x6b, - 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, - 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x57, - 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, - 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x3e, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x6c, - 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x77, - 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x38, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x15, 0x0a, 0x11, 0x41, 0x44, 0x44, 0x45, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, - 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x4d, 0x4f, 0x44, 0x49, 0x46, 0x49, - 0x45, 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, - 0x02, 0x22, 0x84, 0x01, 0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x73, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x69, 0x6e, - 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x65, + 0x6f, 0x61, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x6b, 0x69, + 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x4e, 0x0a, 0x0b, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xad, 0x01, 0x0a, 0x15, 0x57, 0x6f, 0x72, - 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x44, 0x0a, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, - 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, - 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x73, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x69, 0x6e, 0x63, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2a, 0xad, 0x01, 0x0a, 0x18, 0x49, 0x6e, 0x74, - 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x44, 0x69, 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, - 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, - 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x41, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, - 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x44, 0x10, 0x09, 0x12, 0x0d, 0x0a, 0x09, - 0x4e, 0x4f, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x4e, - 0x4f, 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x4f, 0x5f, - 0x4d, 0x45, 0x43, 0x48, 0x41, 0x4e, 0x49, 0x53, 0x4d, 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x4e, - 0x4f, 0x5f, 0x50, 0x4f, 0x52, 0x54, 0x53, 0x10, 0x06, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x47, 0x45, - 0x4e, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x07, 0x12, 0x0c, 0x0a, 0x08, 0x42, 0x41, - 0x44, 0x5f, 0x41, 0x52, 0x47, 0x53, 0x10, 0x08, 0x32, 0xbc, 0x18, 0x0a, 0x07, 0x4d, 0x61, 0x6e, - 0x61, 0x67, 0x65, 0x72, 0x12, 0x45, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, - 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x32, 0x12, 0x4f, 0x0a, 0x10, 0x47, - 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x46, 0x51, 0x4e, 0x12, - 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, - 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, - 0x67, 0x65, 0x6e, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x46, 0x51, 0x4e, 0x12, 0x65, 0x0a, 0x0e, - 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x28, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x2e, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0a, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x59, 0x0a, 0x11, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, + 0x65, 0x70, 0x74, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, + 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, + 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, + 0x10, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x73, 0x12, 0x3e, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, + 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x1a, 0x23, 0x0a, 0x09, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x12, 0x16, + 0x0a, 0x06, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x22, 0x55, 0x0a, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x0f, + 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x0e, 0x0a, 0x0a, 0x44, 0x45, 0x50, 0x4c, 0x4f, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x01, 0x12, + 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x50, 0x4c, 0x49, 0x43, 0x41, 0x53, 0x45, 0x54, 0x10, 0x02, 0x12, + 0x0f, 0x0a, 0x0b, 0x53, 0x54, 0x41, 0x54, 0x45, 0x46, 0x55, 0x4c, 0x53, 0x45, 0x54, 0x10, 0x03, + 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x4f, 0x4c, 0x4c, 0x4f, 0x55, 0x54, 0x10, 0x04, 0x22, 0x4d, 0x0a, + 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, + 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x0d, 0x0a, 0x09, 0x41, 0x56, 0x41, 0x49, 0x4c, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x0f, + 0x0a, 0x0b, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, + 0x0b, 0x0a, 0x07, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x03, 0x22, 0x46, 0x0a, 0x0a, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x4e, 0x4f, + 0x5f, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, + 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x45, + 0x44, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x43, 0x45, 0x50, 0x54, + 0x45, 0x44, 0x10, 0x02, 0x22, 0xc7, 0x01, 0x0a, 0x0d, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, + 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, + 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, 0x6b, + 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x12, 0x3e, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x57, 0x6f, + 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, + 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x38, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x15, 0x0a, 0x11, + 0x41, 0x44, 0x44, 0x45, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x4d, 0x4f, 0x44, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, + 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x02, 0x22, 0x84, + 0x01, 0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, - 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, - 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1d, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x19, 0x43, 0x61, 0x6e, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x41, 0x6d, 0x62, 0x61, 0x73, 0x73, 0x61, 0x64, 0x6f, 0x72, - 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x2f, 0x2e, + 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xad, 0x01, 0x0a, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, + 0x61, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x44, 0x0a, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, + 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x2a, 0xad, 0x01, 0x0a, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, + 0x65, 0x70, 0x74, 0x44, 0x69, 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x01, 0x12, + 0x0b, 0x0a, 0x07, 0x57, 0x41, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, + 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x44, 0x10, 0x09, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, + 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x4f, 0x5f, 0x41, + 0x47, 0x45, 0x4e, 0x54, 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x4f, 0x5f, 0x4d, 0x45, 0x43, + 0x48, 0x41, 0x4e, 0x49, 0x53, 0x4d, 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x4f, 0x5f, 0x50, + 0x4f, 0x52, 0x54, 0x53, 0x10, 0x06, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x5f, + 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x07, 0x12, 0x0c, 0x0a, 0x08, 0x42, 0x41, 0x44, 0x5f, 0x41, + 0x52, 0x47, 0x53, 0x10, 0x08, 0x32, 0xbc, 0x18, 0x0a, 0x07, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x72, 0x12, 0x45, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, + 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x32, 0x12, 0x4f, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x46, 0x51, 0x4e, 0x12, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, + 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, + 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x46, 0x51, 0x4e, 0x12, 0x65, 0x0a, 0x0e, 0x47, 0x65, 0x74, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x28, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, + 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, + 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x43, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x69, + 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x19, 0x43, 0x61, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x41, 0x6d, 0x62, 0x61, 0x73, 0x73, 0x61, 0x64, 0x6f, 0x72, 0x43, 0x6c, 0x6f, + 0x75, 0x64, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x2f, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x72, 0x2e, 0x41, 0x6d, 0x62, 0x61, 0x73, 0x73, 0x61, 0x64, 0x6f, 0x72, 0x43, 0x6c, 0x6f, 0x75, + 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x55, 0x0a, 0x0e, 0x47, + 0x65, 0x74, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, + 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x6d, 0x62, + 0x61, 0x73, 0x73, 0x61, 0x64, 0x6f, 0x72, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x4a, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, - 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x6d, 0x62, 0x61, 0x73, 0x73, 0x61, 0x64, 0x6f, 0x72, 0x43, - 0x6c, 0x6f, 0x75, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x55, - 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, - 0x41, 0x6d, 0x62, 0x61, 0x73, 0x73, 0x61, 0x64, 0x6f, 0x72, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4a, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x1a, 0x1f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, - 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x4c, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x57, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x54, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, - 0x65, 0x6e, 0x63, 0x65, 0x41, 0x50, 0x49, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, - 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, - 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, - 0x6e, 0x63, 0x65, 0x41, 0x50, 0x49, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x55, 0x0a, 0x0e, 0x41, 0x72, - 0x72, 0x69, 0x76, 0x65, 0x41, 0x73, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x2e, 0x74, + 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x4c, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x57, + 0x0a, 0x12, 0x47, 0x65, 0x74, 0x54, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, + 0x65, 0x41, 0x50, 0x49, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x21, + 0x67, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, + 0x41, 0x50, 0x49, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x55, 0x0a, 0x0e, 0x41, 0x72, 0x72, 0x69, 0x76, + 0x65, 0x41, 0x73, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, + 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x21, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x53, + 0x0a, 0x0d, 0x41, 0x72, 0x72, 0x69, 0x76, 0x65, 0x41, 0x73, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, + 0x1f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, + 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x45, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x23, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x43, 0x0a, 0x06, 0x44, 0x65, + 0x70, 0x61, 0x72, 0x74, 0x12, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, + 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, + 0x4c, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x25, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, - 0x6f, 0x12, 0x53, 0x0a, 0x0d, 0x41, 0x72, 0x72, 0x69, 0x76, 0x65, 0x41, 0x73, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x12, 0x1f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, - 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x49, - 0x6e, 0x66, 0x6f, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, - 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x45, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x61, 0x69, 0x6e, - 0x12, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, - 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, + 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x43, 0x0a, - 0x06, 0x44, 0x65, 0x70, 0x61, 0x72, 0x74, 0x12, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, - 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x12, 0x4c, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, - 0x6c, 0x12, 0x25, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, - 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, - 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x12, 0x53, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x24, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, - 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x61, 0x0a, 0x0e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x41, 0x67, - 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x64, 0x73, 0x12, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, - 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x2a, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, - 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x53, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x30, 0x01, 0x12, 0x5b, 0x0a, 0x0b, 0x57, 0x61, 0x74, 0x63, - 0x68, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, - 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, - 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x53, 0x6e, 0x61, 0x70, 0x73, - 0x68, 0x6f, 0x74, 0x30, 0x01, 0x12, 0x5f, 0x0a, 0x0d, 0x57, 0x61, 0x74, 0x63, 0x68, 0x41, 0x67, - 0x65, 0x6e, 0x74, 0x73, 0x4e, 0x53, 0x12, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, - 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x67, - 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x53, 0x6e, 0x61, 0x70, - 0x73, 0x68, 0x6f, 0x74, 0x30, 0x01, 0x12, 0x63, 0x0a, 0x0f, 0x57, 0x61, 0x74, 0x63, 0x68, 0x49, - 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x73, 0x12, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x53, 0x0a, + 0x07, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x24, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, + 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x61, 0x0a, 0x0e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x41, 0x67, 0x65, 0x6e, 0x74, + 0x50, 0x6f, 0x64, 0x73, 0x12, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, + 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, + 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x53, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x30, 0x01, 0x12, 0x5b, 0x0a, 0x0b, 0x57, 0x61, 0x74, 0x63, 0x68, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x73, 0x12, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, + 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, + 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, + 0x30, 0x01, 0x12, 0x5f, 0x0a, 0x0d, 0x57, 0x61, 0x74, 0x63, 0x68, 0x41, 0x67, 0x65, 0x6e, 0x74, + 0x73, 0x4e, 0x53, 0x12, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, + 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, + 0x74, 0x30, 0x01, 0x12, 0x63, 0x0a, 0x0f, 0x57, 0x61, 0x74, 0x63, 0x68, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x63, 0x65, 0x70, 0x74, 0x73, 0x12, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x2b, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x49, 0x6e, 0x66, - 0x6f, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x30, 0x01, 0x12, 0x6a, 0x0a, 0x0e, 0x57, - 0x61, 0x74, 0x63, 0x68, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x12, 0x2b, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, - 0x61, 0x67, 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x74, 0x65, 0x6c, + 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x53, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x30, 0x01, 0x12, 0x6a, 0x0a, 0x0e, 0x57, 0x61, 0x74, 0x63, + 0x68, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x12, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x44, 0x65, 0x6c, 0x74, 0x61, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x10, 0x57, 0x61, 0x74, 0x63, 0x68, - 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x21, 0x2e, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, + 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x57, + 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x44, 0x65, 0x6c, + 0x74, 0x61, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x10, 0x57, 0x61, 0x74, 0x63, 0x68, 0x43, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x21, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x30, 0x01, 0x12, 0x60, 0x0a, 0x0b, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x12, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, - 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, - 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x53, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x69, 0x0a, 0x10, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, - 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x12, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, - 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x50, - 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, - 0x12, 0x64, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, - 0x65, 0x70, 0x74, 0x12, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, - 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, - 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, - 0x70, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x58, 0x0a, 0x0f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, - 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x30, 0x01, + 0x12, 0x60, 0x0a, 0x0b, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, + 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x41, 0x67, 0x65, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x32, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x12, 0x69, 0x0a, 0x10, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x12, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, + 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x65, 0x70, + 0x61, 0x72, 0x65, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x12, 0x64, 0x0a, + 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, + 0x12, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x58, 0x0a, 0x0f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x32, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x64, 0x0a, + 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, + 0x12, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x5e, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, + 0x65, 0x70, 0x74, 0x12, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, + 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x57, 0x0a, 0x0f, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x12, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x52, 0x65, + 0x76, 0x69, 0x65, 0x77, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x64, 0x0a, 0x15, + 0x47, 0x65, 0x74, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, + 0x4b, 0x69, 0x6e, 0x64, 0x73, 0x12, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, + 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, + 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x4b, 0x69, 0x6e, + 0x64, 0x73, 0x12, 0x50, 0x0a, 0x09, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x44, 0x4e, 0x53, 0x12, + 0x20, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, + 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x16, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x6f, + 0x6b, 0x75, 0x70, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x44, 0x4e, 0x53, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x57, + 0x0a, 0x0e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x44, 0x4e, 0x53, + 0x12, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, + 0x6e, 0x66, 0x6f, 0x1a, 0x20, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, + 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x30, 0x01, 0x12, 0x50, 0x0a, 0x0d, 0x57, 0x61, 0x74, 0x63, 0x68, + 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x12, 0x64, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, - 0x65, 0x70, 0x74, 0x12, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, - 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, - 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, - 0x70, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x5e, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, - 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x12, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, - 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x47, 0x65, - 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, - 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, - 0x70, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x57, 0x0a, 0x0f, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, - 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x12, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, - 0x64, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, - 0x6f, 0x61, 0x64, 0x4b, 0x69, 0x6e, 0x64, 0x73, 0x12, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x1a, 0x25, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x30, 0x01, 0x12, 0x56, 0x0a, 0x06, 0x54, 0x75, 0x6e, + 0x6e, 0x65, 0x6c, 0x12, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, + 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, + 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, - 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x28, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x72, 0x2e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, - 0x4b, 0x69, 0x6e, 0x64, 0x73, 0x12, 0x50, 0x0a, 0x09, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x44, - 0x4e, 0x53, 0x12, 0x20, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, - 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, - 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x44, 0x4e, 0x53, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x16, 0x41, 0x67, 0x65, 0x6e, 0x74, - 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x44, 0x4e, 0x53, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x26, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, - 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x44, 0x4e, 0x53, 0x41, 0x67, 0x65, 0x6e, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x12, 0x57, 0x0a, 0x0e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, - 0x44, 0x4e, 0x53, 0x12, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, - 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x20, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, - 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x44, 0x4e, - 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x30, 0x01, 0x12, 0x50, 0x0a, 0x0d, 0x57, 0x61, - 0x74, 0x63, 0x68, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x1a, 0x25, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, - 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x4c, 0x65, - 0x76, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x30, 0x01, 0x12, 0x56, 0x0a, 0x06, - 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, - 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x54, 0x75, - 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x23, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x72, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x28, 0x01, 0x30, 0x01, 0x12, 0x4c, 0x0a, 0x0d, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, - 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x54, 0x75, 0x6e, - 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x12, 0x53, 0x0a, 0x09, 0x57, 0x61, 0x74, 0x63, 0x68, 0x44, 0x69, 0x61, 0x6c, 0x12, + 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x01, 0x30, + 0x01, 0x12, 0x4c, 0x0a, 0x0d, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x12, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, + 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, + 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, + 0x53, 0x0a, 0x09, 0x57, 0x61, 0x74, 0x63, 0x68, 0x44, 0x69, 0x61, 0x6c, 0x12, 0x21, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x6d, - 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, - 0x66, 0x6f, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, - 0x65, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x44, 0x69, 0x61, 0x6c, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x30, 0x01, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, - 0x63, 0x65, 0x69, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, - 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x44, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x30, 0x01, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x69, + 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2f, 0x72, + 0x70, 0x63, 0x2f, 0x76, 0x32, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -4820,7 +4906,7 @@ func file_manager_manager_proto_rawDescGZIP() []byte { } var file_manager_manager_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_manager_manager_proto_msgTypes = make([]protoimpl.MessageInfo, 61) +var file_manager_manager_proto_msgTypes = make([]protoimpl.MessageInfo, 62) var file_manager_manager_proto_goTypes = []any{ (InterceptDispositionType)(0), // 0: telepresence.manager.InterceptDispositionType (WorkloadInfo_Kind)(0), // 1: telepresence.manager.WorkloadInfo.Kind @@ -4829,197 +4915,198 @@ var file_manager_manager_proto_goTypes = []any{ (WorkloadEvent_Type)(0), // 4: telepresence.manager.WorkloadEvent.Type (*ClientInfo)(nil), // 5: telepresence.manager.ClientInfo (*AgentInfo)(nil), // 6: telepresence.manager.AgentInfo - (*InterceptSpec)(nil), // 7: telepresence.manager.InterceptSpec - (*IngressInfo)(nil), // 8: telepresence.manager.IngressInfo - (*PreviewSpec)(nil), // 9: telepresence.manager.PreviewSpec - (*InterceptInfo)(nil), // 10: telepresence.manager.InterceptInfo - (*SessionInfo)(nil), // 11: telepresence.manager.SessionInfo - (*AgentsRequest)(nil), // 12: telepresence.manager.AgentsRequest - (*AgentInfoSnapshot)(nil), // 13: telepresence.manager.AgentInfoSnapshot - (*InterceptInfoSnapshot)(nil), // 14: telepresence.manager.InterceptInfoSnapshot - (*CreateInterceptRequest)(nil), // 15: telepresence.manager.CreateInterceptRequest - (*EnsureAgentRequest)(nil), // 16: telepresence.manager.EnsureAgentRequest - (*PreparedIntercept)(nil), // 17: telepresence.manager.PreparedIntercept - (*UpdateInterceptRequest)(nil), // 18: telepresence.manager.UpdateInterceptRequest - (*RemoveInterceptRequest2)(nil), // 19: telepresence.manager.RemoveInterceptRequest2 - (*GetInterceptRequest)(nil), // 20: telepresence.manager.GetInterceptRequest - (*ReviewInterceptRequest)(nil), // 21: telepresence.manager.ReviewInterceptRequest - (*RemainRequest)(nil), // 22: telepresence.manager.RemainRequest - (*LogLevelRequest)(nil), // 23: telepresence.manager.LogLevelRequest - (*GetLogsRequest)(nil), // 24: telepresence.manager.GetLogsRequest - (*LogsResponse)(nil), // 25: telepresence.manager.LogsResponse - (*TelepresenceAPIInfo)(nil), // 26: telepresence.manager.TelepresenceAPIInfo - (*VersionInfo2)(nil), // 27: telepresence.manager.VersionInfo2 - (*License)(nil), // 28: telepresence.manager.License - (*AmbassadorCloudConfig)(nil), // 29: telepresence.manager.AmbassadorCloudConfig - (*AmbassadorCloudConnection)(nil), // 30: telepresence.manager.AmbassadorCloudConnection - (*TunnelMessage)(nil), // 31: telepresence.manager.TunnelMessage - (*DialRequest)(nil), // 32: telepresence.manager.DialRequest - (*DNSRequest)(nil), // 33: telepresence.manager.DNSRequest - (*DNSResponse)(nil), // 34: telepresence.manager.DNSResponse - (*DNSAgentResponse)(nil), // 35: telepresence.manager.DNSAgentResponse - (*IPNet)(nil), // 36: telepresence.manager.IPNet - (*ClusterInfo)(nil), // 37: telepresence.manager.ClusterInfo - (*Routing)(nil), // 38: telepresence.manager.Routing - (*DNS)(nil), // 39: telepresence.manager.DNS - (*CLIConfig)(nil), // 40: telepresence.manager.CLIConfig - (*AgentImageFQN)(nil), // 41: telepresence.manager.AgentImageFQN - (*AgentPodInfo)(nil), // 42: telepresence.manager.AgentPodInfo - (*AgentPodInfoSnapshot)(nil), // 43: telepresence.manager.AgentPodInfoSnapshot - (*AgentConfigRequest)(nil), // 44: telepresence.manager.AgentConfigRequest - (*AgentConfigResponse)(nil), // 45: telepresence.manager.AgentConfigResponse - (*TunnelMetrics)(nil), // 46: telepresence.manager.TunnelMetrics - (*KnownWorkloadKinds)(nil), // 47: telepresence.manager.KnownWorkloadKinds - (*WorkloadInfo)(nil), // 48: telepresence.manager.WorkloadInfo - (*WorkloadEvent)(nil), // 49: telepresence.manager.WorkloadEvent - (*WorkloadEventsDelta)(nil), // 50: telepresence.manager.WorkloadEventsDelta - (*WorkloadEventsRequest)(nil), // 51: telepresence.manager.WorkloadEventsRequest - (*AgentInfo_Mechanism)(nil), // 52: telepresence.manager.AgentInfo.Mechanism - (*AgentInfo_ContainerInfo)(nil), // 53: telepresence.manager.AgentInfo.ContainerInfo - nil, // 54: telepresence.manager.AgentInfo.ContainersEntry - nil, // 55: telepresence.manager.AgentInfo.ContainerInfo.EnvironmentEntry - nil, // 56: telepresence.manager.PreviewSpec.AddRequestHeadersEntry - nil, // 57: telepresence.manager.InterceptInfo.HeadersEntry - nil, // 58: telepresence.manager.InterceptInfo.MetadataEntry - nil, // 59: telepresence.manager.InterceptInfo.EnvironmentEntry - nil, // 60: telepresence.manager.ReviewInterceptRequest.HeadersEntry - nil, // 61: telepresence.manager.ReviewInterceptRequest.MetadataEntry - nil, // 62: telepresence.manager.ReviewInterceptRequest.EnvironmentEntry - nil, // 63: telepresence.manager.LogsResponse.PodLogsEntry - nil, // 64: telepresence.manager.LogsResponse.PodYamlEntry - (*WorkloadInfo_Intercept)(nil), // 65: telepresence.manager.WorkloadInfo.Intercept - (*timestamppb.Timestamp)(nil), // 66: google.protobuf.Timestamp - (*durationpb.Duration)(nil), // 67: google.protobuf.Duration - (*emptypb.Empty)(nil), // 68: google.protobuf.Empty + (*PortMapping)(nil), // 7: telepresence.manager.PortMapping + (*InterceptSpec)(nil), // 8: telepresence.manager.InterceptSpec + (*IngressInfo)(nil), // 9: telepresence.manager.IngressInfo + (*PreviewSpec)(nil), // 10: telepresence.manager.PreviewSpec + (*InterceptInfo)(nil), // 11: telepresence.manager.InterceptInfo + (*SessionInfo)(nil), // 12: telepresence.manager.SessionInfo + (*AgentsRequest)(nil), // 13: telepresence.manager.AgentsRequest + (*AgentInfoSnapshot)(nil), // 14: telepresence.manager.AgentInfoSnapshot + (*InterceptInfoSnapshot)(nil), // 15: telepresence.manager.InterceptInfoSnapshot + (*CreateInterceptRequest)(nil), // 16: telepresence.manager.CreateInterceptRequest + (*EnsureAgentRequest)(nil), // 17: telepresence.manager.EnsureAgentRequest + (*PreparedIntercept)(nil), // 18: telepresence.manager.PreparedIntercept + (*UpdateInterceptRequest)(nil), // 19: telepresence.manager.UpdateInterceptRequest + (*RemoveInterceptRequest2)(nil), // 20: telepresence.manager.RemoveInterceptRequest2 + (*GetInterceptRequest)(nil), // 21: telepresence.manager.GetInterceptRequest + (*ReviewInterceptRequest)(nil), // 22: telepresence.manager.ReviewInterceptRequest + (*RemainRequest)(nil), // 23: telepresence.manager.RemainRequest + (*LogLevelRequest)(nil), // 24: telepresence.manager.LogLevelRequest + (*GetLogsRequest)(nil), // 25: telepresence.manager.GetLogsRequest + (*LogsResponse)(nil), // 26: telepresence.manager.LogsResponse + (*TelepresenceAPIInfo)(nil), // 27: telepresence.manager.TelepresenceAPIInfo + (*VersionInfo2)(nil), // 28: telepresence.manager.VersionInfo2 + (*License)(nil), // 29: telepresence.manager.License + (*AmbassadorCloudConfig)(nil), // 30: telepresence.manager.AmbassadorCloudConfig + (*AmbassadorCloudConnection)(nil), // 31: telepresence.manager.AmbassadorCloudConnection + (*TunnelMessage)(nil), // 32: telepresence.manager.TunnelMessage + (*DialRequest)(nil), // 33: telepresence.manager.DialRequest + (*DNSRequest)(nil), // 34: telepresence.manager.DNSRequest + (*DNSResponse)(nil), // 35: telepresence.manager.DNSResponse + (*DNSAgentResponse)(nil), // 36: telepresence.manager.DNSAgentResponse + (*IPNet)(nil), // 37: telepresence.manager.IPNet + (*ClusterInfo)(nil), // 38: telepresence.manager.ClusterInfo + (*Routing)(nil), // 39: telepresence.manager.Routing + (*DNS)(nil), // 40: telepresence.manager.DNS + (*CLIConfig)(nil), // 41: telepresence.manager.CLIConfig + (*AgentImageFQN)(nil), // 42: telepresence.manager.AgentImageFQN + (*AgentPodInfo)(nil), // 43: telepresence.manager.AgentPodInfo + (*AgentPodInfoSnapshot)(nil), // 44: telepresence.manager.AgentPodInfoSnapshot + (*AgentConfigRequest)(nil), // 45: telepresence.manager.AgentConfigRequest + (*AgentConfigResponse)(nil), // 46: telepresence.manager.AgentConfigResponse + (*TunnelMetrics)(nil), // 47: telepresence.manager.TunnelMetrics + (*KnownWorkloadKinds)(nil), // 48: telepresence.manager.KnownWorkloadKinds + (*WorkloadInfo)(nil), // 49: telepresence.manager.WorkloadInfo + (*WorkloadEvent)(nil), // 50: telepresence.manager.WorkloadEvent + (*WorkloadEventsDelta)(nil), // 51: telepresence.manager.WorkloadEventsDelta + (*WorkloadEventsRequest)(nil), // 52: telepresence.manager.WorkloadEventsRequest + (*AgentInfo_Mechanism)(nil), // 53: telepresence.manager.AgentInfo.Mechanism + (*AgentInfo_ContainerInfo)(nil), // 54: telepresence.manager.AgentInfo.ContainerInfo + nil, // 55: telepresence.manager.AgentInfo.ContainersEntry + nil, // 56: telepresence.manager.AgentInfo.ContainerInfo.EnvironmentEntry + nil, // 57: telepresence.manager.PreviewSpec.AddRequestHeadersEntry + nil, // 58: telepresence.manager.InterceptInfo.HeadersEntry + nil, // 59: telepresence.manager.InterceptInfo.MetadataEntry + nil, // 60: telepresence.manager.InterceptInfo.EnvironmentEntry + nil, // 61: telepresence.manager.ReviewInterceptRequest.HeadersEntry + nil, // 62: telepresence.manager.ReviewInterceptRequest.MetadataEntry + nil, // 63: telepresence.manager.ReviewInterceptRequest.EnvironmentEntry + nil, // 64: telepresence.manager.LogsResponse.PodLogsEntry + nil, // 65: telepresence.manager.LogsResponse.PodYamlEntry + (*WorkloadInfo_Intercept)(nil), // 66: telepresence.manager.WorkloadInfo.Intercept + (*timestamppb.Timestamp)(nil), // 67: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 68: google.protobuf.Duration + (*emptypb.Empty)(nil), // 69: google.protobuf.Empty } var file_manager_manager_proto_depIdxs = []int32{ - 52, // 0: telepresence.manager.AgentInfo.mechanisms:type_name -> telepresence.manager.AgentInfo.Mechanism - 54, // 1: telepresence.manager.AgentInfo.containers:type_name -> telepresence.manager.AgentInfo.ContainersEntry - 8, // 2: telepresence.manager.PreviewSpec.ingress:type_name -> telepresence.manager.IngressInfo - 56, // 3: telepresence.manager.PreviewSpec.add_request_headers:type_name -> telepresence.manager.PreviewSpec.AddRequestHeadersEntry - 7, // 4: telepresence.manager.InterceptInfo.spec:type_name -> telepresence.manager.InterceptSpec - 11, // 5: telepresence.manager.InterceptInfo.client_session:type_name -> telepresence.manager.SessionInfo - 9, // 6: telepresence.manager.InterceptInfo.preview_spec:type_name -> telepresence.manager.PreviewSpec + 53, // 0: telepresence.manager.AgentInfo.mechanisms:type_name -> telepresence.manager.AgentInfo.Mechanism + 55, // 1: telepresence.manager.AgentInfo.containers:type_name -> telepresence.manager.AgentInfo.ContainersEntry + 9, // 2: telepresence.manager.PreviewSpec.ingress:type_name -> telepresence.manager.IngressInfo + 57, // 3: telepresence.manager.PreviewSpec.add_request_headers:type_name -> telepresence.manager.PreviewSpec.AddRequestHeadersEntry + 8, // 4: telepresence.manager.InterceptInfo.spec:type_name -> telepresence.manager.InterceptSpec + 12, // 5: telepresence.manager.InterceptInfo.client_session:type_name -> telepresence.manager.SessionInfo + 10, // 6: telepresence.manager.InterceptInfo.preview_spec:type_name -> telepresence.manager.PreviewSpec 0, // 7: telepresence.manager.InterceptInfo.disposition:type_name -> telepresence.manager.InterceptDispositionType - 57, // 8: telepresence.manager.InterceptInfo.headers:type_name -> telepresence.manager.InterceptInfo.HeadersEntry - 58, // 9: telepresence.manager.InterceptInfo.metadata:type_name -> telepresence.manager.InterceptInfo.MetadataEntry - 59, // 10: telepresence.manager.InterceptInfo.environment:type_name -> telepresence.manager.InterceptInfo.EnvironmentEntry - 66, // 11: telepresence.manager.InterceptInfo.modified_at:type_name -> google.protobuf.Timestamp - 11, // 12: telepresence.manager.AgentsRequest.session:type_name -> telepresence.manager.SessionInfo + 58, // 8: telepresence.manager.InterceptInfo.headers:type_name -> telepresence.manager.InterceptInfo.HeadersEntry + 59, // 9: telepresence.manager.InterceptInfo.metadata:type_name -> telepresence.manager.InterceptInfo.MetadataEntry + 60, // 10: telepresence.manager.InterceptInfo.environment:type_name -> telepresence.manager.InterceptInfo.EnvironmentEntry + 67, // 11: telepresence.manager.InterceptInfo.modified_at:type_name -> google.protobuf.Timestamp + 12, // 12: telepresence.manager.AgentsRequest.session:type_name -> telepresence.manager.SessionInfo 6, // 13: telepresence.manager.AgentInfoSnapshot.agents:type_name -> telepresence.manager.AgentInfo - 10, // 14: telepresence.manager.InterceptInfoSnapshot.intercepts:type_name -> telepresence.manager.InterceptInfo - 11, // 15: telepresence.manager.CreateInterceptRequest.session:type_name -> telepresence.manager.SessionInfo - 7, // 16: telepresence.manager.CreateInterceptRequest.intercept_spec:type_name -> telepresence.manager.InterceptSpec - 11, // 17: telepresence.manager.EnsureAgentRequest.session:type_name -> telepresence.manager.SessionInfo - 11, // 18: telepresence.manager.UpdateInterceptRequest.session:type_name -> telepresence.manager.SessionInfo - 9, // 19: telepresence.manager.UpdateInterceptRequest.add_preview_domain:type_name -> telepresence.manager.PreviewSpec - 11, // 20: telepresence.manager.RemoveInterceptRequest2.session:type_name -> telepresence.manager.SessionInfo - 11, // 21: telepresence.manager.GetInterceptRequest.session:type_name -> telepresence.manager.SessionInfo - 11, // 22: telepresence.manager.ReviewInterceptRequest.session:type_name -> telepresence.manager.SessionInfo + 11, // 14: telepresence.manager.InterceptInfoSnapshot.intercepts:type_name -> telepresence.manager.InterceptInfo + 12, // 15: telepresence.manager.CreateInterceptRequest.session:type_name -> telepresence.manager.SessionInfo + 8, // 16: telepresence.manager.CreateInterceptRequest.intercept_spec:type_name -> telepresence.manager.InterceptSpec + 12, // 17: telepresence.manager.EnsureAgentRequest.session:type_name -> telepresence.manager.SessionInfo + 12, // 18: telepresence.manager.UpdateInterceptRequest.session:type_name -> telepresence.manager.SessionInfo + 10, // 19: telepresence.manager.UpdateInterceptRequest.add_preview_domain:type_name -> telepresence.manager.PreviewSpec + 12, // 20: telepresence.manager.RemoveInterceptRequest2.session:type_name -> telepresence.manager.SessionInfo + 12, // 21: telepresence.manager.GetInterceptRequest.session:type_name -> telepresence.manager.SessionInfo + 12, // 22: telepresence.manager.ReviewInterceptRequest.session:type_name -> telepresence.manager.SessionInfo 0, // 23: telepresence.manager.ReviewInterceptRequest.disposition:type_name -> telepresence.manager.InterceptDispositionType - 60, // 24: telepresence.manager.ReviewInterceptRequest.headers:type_name -> telepresence.manager.ReviewInterceptRequest.HeadersEntry - 61, // 25: telepresence.manager.ReviewInterceptRequest.metadata:type_name -> telepresence.manager.ReviewInterceptRequest.MetadataEntry - 62, // 26: telepresence.manager.ReviewInterceptRequest.environment:type_name -> telepresence.manager.ReviewInterceptRequest.EnvironmentEntry - 11, // 27: telepresence.manager.RemainRequest.session:type_name -> telepresence.manager.SessionInfo - 67, // 28: telepresence.manager.LogLevelRequest.duration:type_name -> google.protobuf.Duration - 63, // 29: telepresence.manager.LogsResponse.pod_logs:type_name -> telepresence.manager.LogsResponse.PodLogsEntry - 64, // 30: telepresence.manager.LogsResponse.pod_yaml:type_name -> telepresence.manager.LogsResponse.PodYamlEntry - 11, // 31: telepresence.manager.DNSRequest.session:type_name -> telepresence.manager.SessionInfo - 11, // 32: telepresence.manager.DNSAgentResponse.session:type_name -> telepresence.manager.SessionInfo - 33, // 33: telepresence.manager.DNSAgentResponse.request:type_name -> telepresence.manager.DNSRequest - 34, // 34: telepresence.manager.DNSAgentResponse.response:type_name -> telepresence.manager.DNSResponse - 36, // 35: telepresence.manager.ClusterInfo.service_subnet:type_name -> telepresence.manager.IPNet - 36, // 36: telepresence.manager.ClusterInfo.pod_subnets:type_name -> telepresence.manager.IPNet - 38, // 37: telepresence.manager.ClusterInfo.routing:type_name -> telepresence.manager.Routing - 39, // 38: telepresence.manager.ClusterInfo.dns:type_name -> telepresence.manager.DNS - 36, // 39: telepresence.manager.Routing.also_proxy_subnets:type_name -> telepresence.manager.IPNet - 36, // 40: telepresence.manager.Routing.never_proxy_subnets:type_name -> telepresence.manager.IPNet - 36, // 41: telepresence.manager.Routing.allow_conflicting_subnets:type_name -> telepresence.manager.IPNet - 42, // 42: telepresence.manager.AgentPodInfoSnapshot.agents:type_name -> telepresence.manager.AgentPodInfo - 11, // 43: telepresence.manager.AgentConfigRequest.session:type_name -> telepresence.manager.SessionInfo + 61, // 24: telepresence.manager.ReviewInterceptRequest.headers:type_name -> telepresence.manager.ReviewInterceptRequest.HeadersEntry + 62, // 25: telepresence.manager.ReviewInterceptRequest.metadata:type_name -> telepresence.manager.ReviewInterceptRequest.MetadataEntry + 63, // 26: telepresence.manager.ReviewInterceptRequest.environment:type_name -> telepresence.manager.ReviewInterceptRequest.EnvironmentEntry + 12, // 27: telepresence.manager.RemainRequest.session:type_name -> telepresence.manager.SessionInfo + 68, // 28: telepresence.manager.LogLevelRequest.duration:type_name -> google.protobuf.Duration + 64, // 29: telepresence.manager.LogsResponse.pod_logs:type_name -> telepresence.manager.LogsResponse.PodLogsEntry + 65, // 30: telepresence.manager.LogsResponse.pod_yaml:type_name -> telepresence.manager.LogsResponse.PodYamlEntry + 12, // 31: telepresence.manager.DNSRequest.session:type_name -> telepresence.manager.SessionInfo + 12, // 32: telepresence.manager.DNSAgentResponse.session:type_name -> telepresence.manager.SessionInfo + 34, // 33: telepresence.manager.DNSAgentResponse.request:type_name -> telepresence.manager.DNSRequest + 35, // 34: telepresence.manager.DNSAgentResponse.response:type_name -> telepresence.manager.DNSResponse + 37, // 35: telepresence.manager.ClusterInfo.service_subnet:type_name -> telepresence.manager.IPNet + 37, // 36: telepresence.manager.ClusterInfo.pod_subnets:type_name -> telepresence.manager.IPNet + 39, // 37: telepresence.manager.ClusterInfo.routing:type_name -> telepresence.manager.Routing + 40, // 38: telepresence.manager.ClusterInfo.dns:type_name -> telepresence.manager.DNS + 37, // 39: telepresence.manager.Routing.also_proxy_subnets:type_name -> telepresence.manager.IPNet + 37, // 40: telepresence.manager.Routing.never_proxy_subnets:type_name -> telepresence.manager.IPNet + 37, // 41: telepresence.manager.Routing.allow_conflicting_subnets:type_name -> telepresence.manager.IPNet + 43, // 42: telepresence.manager.AgentPodInfoSnapshot.agents:type_name -> telepresence.manager.AgentPodInfo + 12, // 43: telepresence.manager.AgentConfigRequest.session:type_name -> telepresence.manager.SessionInfo 1, // 44: telepresence.manager.KnownWorkloadKinds.kinds:type_name -> telepresence.manager.WorkloadInfo.Kind 1, // 45: telepresence.manager.WorkloadInfo.kind:type_name -> telepresence.manager.WorkloadInfo.Kind 3, // 46: telepresence.manager.WorkloadInfo.agent_state:type_name -> telepresence.manager.WorkloadInfo.AgentState - 65, // 47: telepresence.manager.WorkloadInfo.intercept_clients:type_name -> telepresence.manager.WorkloadInfo.Intercept + 66, // 47: telepresence.manager.WorkloadInfo.intercept_clients:type_name -> telepresence.manager.WorkloadInfo.Intercept 2, // 48: telepresence.manager.WorkloadInfo.state:type_name -> telepresence.manager.WorkloadInfo.State 4, // 49: telepresence.manager.WorkloadEvent.type:type_name -> telepresence.manager.WorkloadEvent.Type - 48, // 50: telepresence.manager.WorkloadEvent.workload:type_name -> telepresence.manager.WorkloadInfo - 66, // 51: telepresence.manager.WorkloadEventsDelta.since:type_name -> google.protobuf.Timestamp - 49, // 52: telepresence.manager.WorkloadEventsDelta.events:type_name -> telepresence.manager.WorkloadEvent - 11, // 53: telepresence.manager.WorkloadEventsRequest.session_info:type_name -> telepresence.manager.SessionInfo - 66, // 54: telepresence.manager.WorkloadEventsRequest.since:type_name -> google.protobuf.Timestamp - 55, // 55: telepresence.manager.AgentInfo.ContainerInfo.environment:type_name -> telepresence.manager.AgentInfo.ContainerInfo.EnvironmentEntry - 53, // 56: telepresence.manager.AgentInfo.ContainersEntry.value:type_name -> telepresence.manager.AgentInfo.ContainerInfo - 68, // 57: telepresence.manager.Manager.Version:input_type -> google.protobuf.Empty - 68, // 58: telepresence.manager.Manager.GetAgentImageFQN:input_type -> google.protobuf.Empty - 44, // 59: telepresence.manager.Manager.GetAgentConfig:input_type -> telepresence.manager.AgentConfigRequest - 68, // 60: telepresence.manager.Manager.GetLicense:input_type -> google.protobuf.Empty - 68, // 61: telepresence.manager.Manager.CanConnectAmbassadorCloud:input_type -> google.protobuf.Empty - 68, // 62: telepresence.manager.Manager.GetCloudConfig:input_type -> google.protobuf.Empty - 68, // 63: telepresence.manager.Manager.GetClientConfig:input_type -> google.protobuf.Empty - 68, // 64: telepresence.manager.Manager.GetTelepresenceAPI:input_type -> google.protobuf.Empty + 49, // 50: telepresence.manager.WorkloadEvent.workload:type_name -> telepresence.manager.WorkloadInfo + 67, // 51: telepresence.manager.WorkloadEventsDelta.since:type_name -> google.protobuf.Timestamp + 50, // 52: telepresence.manager.WorkloadEventsDelta.events:type_name -> telepresence.manager.WorkloadEvent + 12, // 53: telepresence.manager.WorkloadEventsRequest.session_info:type_name -> telepresence.manager.SessionInfo + 67, // 54: telepresence.manager.WorkloadEventsRequest.since:type_name -> google.protobuf.Timestamp + 56, // 55: telepresence.manager.AgentInfo.ContainerInfo.environment:type_name -> telepresence.manager.AgentInfo.ContainerInfo.EnvironmentEntry + 54, // 56: telepresence.manager.AgentInfo.ContainersEntry.value:type_name -> telepresence.manager.AgentInfo.ContainerInfo + 69, // 57: telepresence.manager.Manager.Version:input_type -> google.protobuf.Empty + 69, // 58: telepresence.manager.Manager.GetAgentImageFQN:input_type -> google.protobuf.Empty + 45, // 59: telepresence.manager.Manager.GetAgentConfig:input_type -> telepresence.manager.AgentConfigRequest + 69, // 60: telepresence.manager.Manager.GetLicense:input_type -> google.protobuf.Empty + 69, // 61: telepresence.manager.Manager.CanConnectAmbassadorCloud:input_type -> google.protobuf.Empty + 69, // 62: telepresence.manager.Manager.GetCloudConfig:input_type -> google.protobuf.Empty + 69, // 63: telepresence.manager.Manager.GetClientConfig:input_type -> google.protobuf.Empty + 69, // 64: telepresence.manager.Manager.GetTelepresenceAPI:input_type -> google.protobuf.Empty 5, // 65: telepresence.manager.Manager.ArriveAsClient:input_type -> telepresence.manager.ClientInfo 6, // 66: telepresence.manager.Manager.ArriveAsAgent:input_type -> telepresence.manager.AgentInfo - 22, // 67: telepresence.manager.Manager.Remain:input_type -> telepresence.manager.RemainRequest - 11, // 68: telepresence.manager.Manager.Depart:input_type -> telepresence.manager.SessionInfo - 23, // 69: telepresence.manager.Manager.SetLogLevel:input_type -> telepresence.manager.LogLevelRequest - 24, // 70: telepresence.manager.Manager.GetLogs:input_type -> telepresence.manager.GetLogsRequest - 11, // 71: telepresence.manager.Manager.WatchAgentPods:input_type -> telepresence.manager.SessionInfo - 11, // 72: telepresence.manager.Manager.WatchAgents:input_type -> telepresence.manager.SessionInfo - 12, // 73: telepresence.manager.Manager.WatchAgentsNS:input_type -> telepresence.manager.AgentsRequest - 11, // 74: telepresence.manager.Manager.WatchIntercepts:input_type -> telepresence.manager.SessionInfo - 51, // 75: telepresence.manager.Manager.WatchWorkloads:input_type -> telepresence.manager.WorkloadEventsRequest - 11, // 76: telepresence.manager.Manager.WatchClusterInfo:input_type -> telepresence.manager.SessionInfo - 16, // 77: telepresence.manager.Manager.EnsureAgent:input_type -> telepresence.manager.EnsureAgentRequest - 15, // 78: telepresence.manager.Manager.PrepareIntercept:input_type -> telepresence.manager.CreateInterceptRequest - 15, // 79: telepresence.manager.Manager.CreateIntercept:input_type -> telepresence.manager.CreateInterceptRequest - 19, // 80: telepresence.manager.Manager.RemoveIntercept:input_type -> telepresence.manager.RemoveInterceptRequest2 - 18, // 81: telepresence.manager.Manager.UpdateIntercept:input_type -> telepresence.manager.UpdateInterceptRequest - 20, // 82: telepresence.manager.Manager.GetIntercept:input_type -> telepresence.manager.GetInterceptRequest - 21, // 83: telepresence.manager.Manager.ReviewIntercept:input_type -> telepresence.manager.ReviewInterceptRequest - 11, // 84: telepresence.manager.Manager.GetKnownWorkloadKinds:input_type -> telepresence.manager.SessionInfo - 33, // 85: telepresence.manager.Manager.LookupDNS:input_type -> telepresence.manager.DNSRequest - 35, // 86: telepresence.manager.Manager.AgentLookupDNSResponse:input_type -> telepresence.manager.DNSAgentResponse - 11, // 87: telepresence.manager.Manager.WatchLookupDNS:input_type -> telepresence.manager.SessionInfo - 68, // 88: telepresence.manager.Manager.WatchLogLevel:input_type -> google.protobuf.Empty - 31, // 89: telepresence.manager.Manager.Tunnel:input_type -> telepresence.manager.TunnelMessage - 46, // 90: telepresence.manager.Manager.ReportMetrics:input_type -> telepresence.manager.TunnelMetrics - 11, // 91: telepresence.manager.Manager.WatchDial:input_type -> telepresence.manager.SessionInfo - 27, // 92: telepresence.manager.Manager.Version:output_type -> telepresence.manager.VersionInfo2 - 41, // 93: telepresence.manager.Manager.GetAgentImageFQN:output_type -> telepresence.manager.AgentImageFQN - 45, // 94: telepresence.manager.Manager.GetAgentConfig:output_type -> telepresence.manager.AgentConfigResponse - 28, // 95: telepresence.manager.Manager.GetLicense:output_type -> telepresence.manager.License - 30, // 96: telepresence.manager.Manager.CanConnectAmbassadorCloud:output_type -> telepresence.manager.AmbassadorCloudConnection - 29, // 97: telepresence.manager.Manager.GetCloudConfig:output_type -> telepresence.manager.AmbassadorCloudConfig - 40, // 98: telepresence.manager.Manager.GetClientConfig:output_type -> telepresence.manager.CLIConfig - 26, // 99: telepresence.manager.Manager.GetTelepresenceAPI:output_type -> telepresence.manager.TelepresenceAPIInfo - 11, // 100: telepresence.manager.Manager.ArriveAsClient:output_type -> telepresence.manager.SessionInfo - 11, // 101: telepresence.manager.Manager.ArriveAsAgent:output_type -> telepresence.manager.SessionInfo - 68, // 102: telepresence.manager.Manager.Remain:output_type -> google.protobuf.Empty - 68, // 103: telepresence.manager.Manager.Depart:output_type -> google.protobuf.Empty - 68, // 104: telepresence.manager.Manager.SetLogLevel:output_type -> google.protobuf.Empty - 25, // 105: telepresence.manager.Manager.GetLogs:output_type -> telepresence.manager.LogsResponse - 43, // 106: telepresence.manager.Manager.WatchAgentPods:output_type -> telepresence.manager.AgentPodInfoSnapshot - 13, // 107: telepresence.manager.Manager.WatchAgents:output_type -> telepresence.manager.AgentInfoSnapshot - 13, // 108: telepresence.manager.Manager.WatchAgentsNS:output_type -> telepresence.manager.AgentInfoSnapshot - 14, // 109: telepresence.manager.Manager.WatchIntercepts:output_type -> telepresence.manager.InterceptInfoSnapshot - 50, // 110: telepresence.manager.Manager.WatchWorkloads:output_type -> telepresence.manager.WorkloadEventsDelta - 37, // 111: telepresence.manager.Manager.WatchClusterInfo:output_type -> telepresence.manager.ClusterInfo - 13, // 112: telepresence.manager.Manager.EnsureAgent:output_type -> telepresence.manager.AgentInfoSnapshot - 17, // 113: telepresence.manager.Manager.PrepareIntercept:output_type -> telepresence.manager.PreparedIntercept - 10, // 114: telepresence.manager.Manager.CreateIntercept:output_type -> telepresence.manager.InterceptInfo - 68, // 115: telepresence.manager.Manager.RemoveIntercept:output_type -> google.protobuf.Empty - 10, // 116: telepresence.manager.Manager.UpdateIntercept:output_type -> telepresence.manager.InterceptInfo - 10, // 117: telepresence.manager.Manager.GetIntercept:output_type -> telepresence.manager.InterceptInfo - 68, // 118: telepresence.manager.Manager.ReviewIntercept:output_type -> google.protobuf.Empty - 47, // 119: telepresence.manager.Manager.GetKnownWorkloadKinds:output_type -> telepresence.manager.KnownWorkloadKinds - 34, // 120: telepresence.manager.Manager.LookupDNS:output_type -> telepresence.manager.DNSResponse - 68, // 121: telepresence.manager.Manager.AgentLookupDNSResponse:output_type -> google.protobuf.Empty - 33, // 122: telepresence.manager.Manager.WatchLookupDNS:output_type -> telepresence.manager.DNSRequest - 23, // 123: telepresence.manager.Manager.WatchLogLevel:output_type -> telepresence.manager.LogLevelRequest - 31, // 124: telepresence.manager.Manager.Tunnel:output_type -> telepresence.manager.TunnelMessage - 68, // 125: telepresence.manager.Manager.ReportMetrics:output_type -> google.protobuf.Empty - 32, // 126: telepresence.manager.Manager.WatchDial:output_type -> telepresence.manager.DialRequest + 23, // 67: telepresence.manager.Manager.Remain:input_type -> telepresence.manager.RemainRequest + 12, // 68: telepresence.manager.Manager.Depart:input_type -> telepresence.manager.SessionInfo + 24, // 69: telepresence.manager.Manager.SetLogLevel:input_type -> telepresence.manager.LogLevelRequest + 25, // 70: telepresence.manager.Manager.GetLogs:input_type -> telepresence.manager.GetLogsRequest + 12, // 71: telepresence.manager.Manager.WatchAgentPods:input_type -> telepresence.manager.SessionInfo + 12, // 72: telepresence.manager.Manager.WatchAgents:input_type -> telepresence.manager.SessionInfo + 13, // 73: telepresence.manager.Manager.WatchAgentsNS:input_type -> telepresence.manager.AgentsRequest + 12, // 74: telepresence.manager.Manager.WatchIntercepts:input_type -> telepresence.manager.SessionInfo + 52, // 75: telepresence.manager.Manager.WatchWorkloads:input_type -> telepresence.manager.WorkloadEventsRequest + 12, // 76: telepresence.manager.Manager.WatchClusterInfo:input_type -> telepresence.manager.SessionInfo + 17, // 77: telepresence.manager.Manager.EnsureAgent:input_type -> telepresence.manager.EnsureAgentRequest + 16, // 78: telepresence.manager.Manager.PrepareIntercept:input_type -> telepresence.manager.CreateInterceptRequest + 16, // 79: telepresence.manager.Manager.CreateIntercept:input_type -> telepresence.manager.CreateInterceptRequest + 20, // 80: telepresence.manager.Manager.RemoveIntercept:input_type -> telepresence.manager.RemoveInterceptRequest2 + 19, // 81: telepresence.manager.Manager.UpdateIntercept:input_type -> telepresence.manager.UpdateInterceptRequest + 21, // 82: telepresence.manager.Manager.GetIntercept:input_type -> telepresence.manager.GetInterceptRequest + 22, // 83: telepresence.manager.Manager.ReviewIntercept:input_type -> telepresence.manager.ReviewInterceptRequest + 12, // 84: telepresence.manager.Manager.GetKnownWorkloadKinds:input_type -> telepresence.manager.SessionInfo + 34, // 85: telepresence.manager.Manager.LookupDNS:input_type -> telepresence.manager.DNSRequest + 36, // 86: telepresence.manager.Manager.AgentLookupDNSResponse:input_type -> telepresence.manager.DNSAgentResponse + 12, // 87: telepresence.manager.Manager.WatchLookupDNS:input_type -> telepresence.manager.SessionInfo + 69, // 88: telepresence.manager.Manager.WatchLogLevel:input_type -> google.protobuf.Empty + 32, // 89: telepresence.manager.Manager.Tunnel:input_type -> telepresence.manager.TunnelMessage + 47, // 90: telepresence.manager.Manager.ReportMetrics:input_type -> telepresence.manager.TunnelMetrics + 12, // 91: telepresence.manager.Manager.WatchDial:input_type -> telepresence.manager.SessionInfo + 28, // 92: telepresence.manager.Manager.Version:output_type -> telepresence.manager.VersionInfo2 + 42, // 93: telepresence.manager.Manager.GetAgentImageFQN:output_type -> telepresence.manager.AgentImageFQN + 46, // 94: telepresence.manager.Manager.GetAgentConfig:output_type -> telepresence.manager.AgentConfigResponse + 29, // 95: telepresence.manager.Manager.GetLicense:output_type -> telepresence.manager.License + 31, // 96: telepresence.manager.Manager.CanConnectAmbassadorCloud:output_type -> telepresence.manager.AmbassadorCloudConnection + 30, // 97: telepresence.manager.Manager.GetCloudConfig:output_type -> telepresence.manager.AmbassadorCloudConfig + 41, // 98: telepresence.manager.Manager.GetClientConfig:output_type -> telepresence.manager.CLIConfig + 27, // 99: telepresence.manager.Manager.GetTelepresenceAPI:output_type -> telepresence.manager.TelepresenceAPIInfo + 12, // 100: telepresence.manager.Manager.ArriveAsClient:output_type -> telepresence.manager.SessionInfo + 12, // 101: telepresence.manager.Manager.ArriveAsAgent:output_type -> telepresence.manager.SessionInfo + 69, // 102: telepresence.manager.Manager.Remain:output_type -> google.protobuf.Empty + 69, // 103: telepresence.manager.Manager.Depart:output_type -> google.protobuf.Empty + 69, // 104: telepresence.manager.Manager.SetLogLevel:output_type -> google.protobuf.Empty + 26, // 105: telepresence.manager.Manager.GetLogs:output_type -> telepresence.manager.LogsResponse + 44, // 106: telepresence.manager.Manager.WatchAgentPods:output_type -> telepresence.manager.AgentPodInfoSnapshot + 14, // 107: telepresence.manager.Manager.WatchAgents:output_type -> telepresence.manager.AgentInfoSnapshot + 14, // 108: telepresence.manager.Manager.WatchAgentsNS:output_type -> telepresence.manager.AgentInfoSnapshot + 15, // 109: telepresence.manager.Manager.WatchIntercepts:output_type -> telepresence.manager.InterceptInfoSnapshot + 51, // 110: telepresence.manager.Manager.WatchWorkloads:output_type -> telepresence.manager.WorkloadEventsDelta + 38, // 111: telepresence.manager.Manager.WatchClusterInfo:output_type -> telepresence.manager.ClusterInfo + 14, // 112: telepresence.manager.Manager.EnsureAgent:output_type -> telepresence.manager.AgentInfoSnapshot + 18, // 113: telepresence.manager.Manager.PrepareIntercept:output_type -> telepresence.manager.PreparedIntercept + 11, // 114: telepresence.manager.Manager.CreateIntercept:output_type -> telepresence.manager.InterceptInfo + 69, // 115: telepresence.manager.Manager.RemoveIntercept:output_type -> google.protobuf.Empty + 11, // 116: telepresence.manager.Manager.UpdateIntercept:output_type -> telepresence.manager.InterceptInfo + 11, // 117: telepresence.manager.Manager.GetIntercept:output_type -> telepresence.manager.InterceptInfo + 69, // 118: telepresence.manager.Manager.ReviewIntercept:output_type -> google.protobuf.Empty + 48, // 119: telepresence.manager.Manager.GetKnownWorkloadKinds:output_type -> telepresence.manager.KnownWorkloadKinds + 35, // 120: telepresence.manager.Manager.LookupDNS:output_type -> telepresence.manager.DNSResponse + 69, // 121: telepresence.manager.Manager.AgentLookupDNSResponse:output_type -> google.protobuf.Empty + 34, // 122: telepresence.manager.Manager.WatchLookupDNS:output_type -> telepresence.manager.DNSRequest + 24, // 123: telepresence.manager.Manager.WatchLogLevel:output_type -> telepresence.manager.LogLevelRequest + 32, // 124: telepresence.manager.Manager.Tunnel:output_type -> telepresence.manager.TunnelMessage + 69, // 125: telepresence.manager.Manager.ReportMetrics:output_type -> google.protobuf.Empty + 33, // 126: telepresence.manager.Manager.WatchDial:output_type -> telepresence.manager.DialRequest 92, // [92:127] is the sub-list for method output_type 57, // [57:92] is the sub-list for method input_type 57, // [57:57] is the sub-list for extension type_name @@ -5032,19 +5119,19 @@ func file_manager_manager_proto_init() { if File_manager_manager_proto != nil { return } - file_manager_manager_proto_msgTypes[6].OneofWrappers = []any{} - file_manager_manager_proto_msgTypes[13].OneofWrappers = []any{ + file_manager_manager_proto_msgTypes[7].OneofWrappers = []any{} + file_manager_manager_proto_msgTypes[14].OneofWrappers = []any{ (*UpdateInterceptRequest_AddPreviewDomain)(nil), (*UpdateInterceptRequest_RemovePreviewDomain)(nil), } - file_manager_manager_proto_msgTypes[24].OneofWrappers = []any{} + file_manager_manager_proto_msgTypes[25].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_manager_manager_proto_rawDesc, NumEnums: 5, - NumMessages: 61, + NumMessages: 62, NumExtensions: 0, NumServices: 1, }, diff --git a/rpc/manager/manager.proto b/rpc/manager/manager.proto index 4e8cacc4db..51bbcae3c3 100644 --- a/rpc/manager/manager.proto +++ b/rpc/manager/manager.proto @@ -70,6 +70,13 @@ message AgentInfo { reserved 6; } +// PortMapping describes a mapping from a port number in the intercepted container to +// a port on the client for --from-pod and or vice versa when using --to-pod. +message PortMapping { + int32 from = 1; + int32 to = 2; +} + // InterceptSpec contains static information about an intercept. It is shared by // all running agent instances. message InterceptSpec { @@ -102,10 +109,23 @@ message InterceptSpec { // to control what these values are. repeated string mechanism_args = 9; + // The host that the target_ports are routed to. string target_host = 6; - // The port on the workstation that the intercept is redirected to - int32 target_port = 7; + // Ports that will be forwarded from the intercepting pod's IP address + // to the target_host, using the following syntax: + // + // PORT = port-decl ["/" protocol ] + // port-decl = port-spec [ ":" uint16 ] + // protocol = "TCP" | "UDP" + // port-spec = name | uint16 + // + // If two numbers are used, they signify source:destination. + repeated string pod_ports = 5; + + // Ports that will be forwarded from the intercepting client's localhost + // to the intercepted pod. Uses the same syntax as target_ports. + repeated string local_ports = 18; // Identifier for the service or container port: either the name or port number // optionally followed by a "/TCP" or "/UDP" @@ -131,13 +151,11 @@ message InterceptSpec { // is owned by some kind of routing mechanism (such as nginx). string container_name = 24; - // The resolved container port + // The resolved container port that is intercepted. int32 container_port = 23; - // Extra ports that will be forwarded from the intercepting client's localhost - // to the intercepted pod. Each entry is a string containing a port number followed - // by an optional "/TCP" or "/UDP". - repeated string local_ports = 18; + // The port on the workstation that the intercepted container_port is redirected to. + int32 target_port = 7; // The delay imposed by a call roundtrip between the traffic-agent and // the client on the workstation. This delay is added to the dial_timeout @@ -325,6 +343,7 @@ message PreparedIntercept { string protocol = 10; // TCP or UDP string container_name = 11; int32 container_port = 12; + repeated string pod_ports = 13; } message UpdateInterceptRequest { From f0bad4e0ad41bb650434b9643820e28c0723d3e0 Mon Sep 17 00:00:00 2001 From: Thomas Hallgren Date: Sat, 4 Jan 2025 22:24:55 +0100 Subject: [PATCH 7/9] Add complementary DeleteApp for the NamespacePair Apply app in CI. Signed-off-by: Thomas Hallgren --- integration_test/itest/apply_app.go | 9 +++++++++ integration_test/itest/namespace.go | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/integration_test/itest/apply_app.go b/integration_test/itest/apply_app.go index 7074406781..1fc864b52e 100644 --- a/integration_test/itest/apply_app.go +++ b/integration_test/itest/apply_app.go @@ -43,6 +43,15 @@ func ApplyApp(ctx context.Context, name, namespace, workload string) { require.NoError(t, RolloutStatusWait(ctx, namespace, workload)) } +// DeleteApp calls kubectl delete -n -f on the given app + .yaml found in testdata/k8s relative +// to the directory returned by GetWorkingDir. +func DeleteApp(ctx context.Context, name, namespace string) { + t := getT(ctx) + t.Helper() + manifest := filepath.Join("testdata", "k8s", name+".yaml") + require.NoError(t, Kubectl(ctx, namespace, "delete", "-f", manifest), "failed to delete %s", manifest) +} + type AppPort struct { ServicePortName string ServicePortNumber uint16 diff --git a/integration_test/itest/namespace.go b/integration_test/itest/namespace.go index a6bd78a077..01c1421934 100644 --- a/integration_test/itest/namespace.go +++ b/integration_test/itest/namespace.go @@ -22,6 +22,7 @@ type NamespacePair interface { ApplyApp(ctx context.Context, name, workload string) ApplyEchoService(ctx context.Context, name string, port int) ApplyTemplate(ctx context.Context, path string, values any) + DeleteApp(ctx context.Context, name string) DeleteTemplate(ctx context.Context, path string, values any) AppNamespace() string TelepresenceConnect(ctx context.Context, args ...string) string @@ -164,6 +165,13 @@ func (s *nsPair) ApplyApp(ctx context.Context, name, workload string) { ApplyApp(ctx, name, s.AppNamespace(), workload) } +// DeleteApp calls kubectl delete -n -f on the given app + .yaml found in testdata/k8s relative +// to the directory returned by GetCurrentDirectory. +func (s *nsPair) DeleteApp(ctx context.Context, name string) { + getT(ctx).Helper() + DeleteApp(ctx, name, s.AppNamespace()) +} + func (s *nsPair) RolloutStatusWait(ctx context.Context, workload string) error { return RolloutStatusWait(ctx, s.AppNamespace(), workload) } From b96a3b80d789104b042cd0c73ab5b4df92bf1d0a Mon Sep 17 00:00:00 2001 From: Thomas Hallgren Date: Sun, 5 Jan 2025 12:03:32 +0100 Subject: [PATCH 8/9] Skip initial tick-delay when pining servers in CI tests. The `Eventually` function will always wait for its initial tick-delay. This commit ensures that the PingInterceptedEchoServer pings immediately and then uses Eventually if that ping fails. Signed-off-by: Thomas Hallgren --- integration_test/itest/cluster.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/integration_test/itest/cluster.go b/integration_test/itest/cluster.go index 6a9b81efa1..8ed742f2ea 100644 --- a/integration_test/itest/cluster.go +++ b/integration_test/itest/cluster.go @@ -1163,7 +1163,9 @@ func PingInterceptedEchoServer(ctx context.Context, svc, svcPort string, headers svc = svc[:slashIdx] } expectedOutput := fmt.Sprintf("%s from intercept at /", wl) - require.Eventually(getT(ctx), func() bool { + dlog.Infof(ctx, "pinging %s, expecting output: %s", net.JoinHostPort(svc, svcPort), expectedOutput) + + ping := func() bool { // condition ips, err := net.DefaultResolver.LookupIP(ctx, "ip", svc) if err != nil { @@ -1203,11 +1205,11 @@ func PingInterceptedEchoServer(ctx context.Context, svc, svcPort string, headers return false } return true - }, - time.Minute, // waitFor - 5*time.Second, // polling interval - `body of %q equals %q`, "http://"+svc, expectedOutput, - ) + } + if ping() { + return + } + require.Eventually(getT(ctx), ping, time.Minute, 5*time.Second, `body of %q equals %q`, "http://"+svc, expectedOutput) } func WithConfig(c context.Context, modifierFunc func(config client.Config)) context.Context { From d9fd14f8fae42982d734ba1eee5194c0f08693c8 Mon Sep 17 00:00:00 2001 From: Thomas Hallgren Date: Sun, 5 Jan 2025 04:06:06 +0100 Subject: [PATCH 9/9] Add for multi-port single-intercept tests. Signed-off-by: Thomas Hallgren --- .../multiple_port_intercept_test.go | 141 ++++++++++++++++++ .../k8s/{echo-two.yaml => echo-both.yaml} | 0 2 files changed, 141 insertions(+) create mode 100644 integration_test/multiple_port_intercept_test.go rename integration_test/testdata/k8s/{echo-two.yaml => echo-both.yaml} (100%) diff --git a/integration_test/multiple_port_intercept_test.go b/integration_test/multiple_port_intercept_test.go new file mode 100644 index 0000000000..e9e8aa3d6f --- /dev/null +++ b/integration_test/multiple_port_intercept_test.go @@ -0,0 +1,141 @@ +package integration_test + +import ( + "context" + "fmt" + "strconv" + "sync" + "time" + + core "k8s.io/api/core/v1" + + "github.com/telepresenceio/telepresence/v2/integration_test/itest" +) + +type multiportInterceptSuite struct { + itest.Suite + itest.TrafficManager + servicePort [4]int + serviceCancel [4]context.CancelFunc + workloads [2]string + ports [2][2]string +} + +func (s *multiportInterceptSuite) SuiteName() string { + return "MultiPortIntercept" +} + +func init() { + itest.AddTrafficManagerSuite("", func(h itest.TrafficManager) itest.TestingSuite { + return &multiportInterceptSuite{ + Suite: itest.Suite{Harness: h}, + TrafficManager: h, + workloads: [2]string{"echo-both", "echo-double-one-unnamed"}, + ports: [2][2]string{{"one", "two"}, {"8080", "8081"}}, + } + }) +} + +func (s *multiportInterceptSuite) SetupSuite() { + s.Suite.SetupSuite() + ctx := s.Context() + for i := 0; i < 4; i++ { + s.servicePort[i], s.serviceCancel[i] = itest.StartLocalHttpEchoServer(ctx, fmt.Sprintf("%s-%d", "echo", i)) + } + wg := sync.WaitGroup{} + wg.Add(2) + for i := 0; i < 2; i++ { + go func() { + defer wg.Done() + dep := s.workloads[i] + s.ApplyApp(ctx, dep, "deploy/"+dep) + }() + } + s.TelepresenceConnect(ctx) + wg.Wait() +} + +func (s *multiportInterceptSuite) TearDownSuite() { + ctx := s.Context() + itest.TelepresenceQuitOk(ctx) + for i := 0; i < 2; i++ { + s.DeleteApp(ctx, s.workloads[i]) + } + for i := 0; i < 4; i++ { + s.serviceCancel[i]() + } +} + +func (s *multiportInterceptSuite) Test_MultiPortIntercept() { + ctx := s.Context() + for i := 0; i < 2; i++ { + itest.TelepresenceOk(ctx, "intercept", s.workloads[i], + "--mount=false", + "--port", fmt.Sprintf("%d:%s", s.servicePort[i*2], s.ports[i][0]), + "--port", fmt.Sprintf("%d:%s", s.servicePort[i*2+1], s.ports[i][1])) + } + defer func() { + for i := 0; i < 2; i++ { + itest.TelepresenceOk(ctx, "leave", s.workloads[i]) + } + }() + + rq := s.Require() + rq.Eventually(func() bool { + st := itest.TelepresenceStatusOk(ctx) + ics := st.UserDaemon.Intercepts + if len(ics) != 2 { + return false + } + for i := 0; i < 2; i++ { + ic := ics[i] + if ic.Name != s.workloads[i] { + return false + } + } + return true + }, 10*time.Second, time.Second) + + var edoPods []core.Pod + rq.Eventually(func() bool { + edoPods = itest.RunningPods(ctx, s.workloads[1], s.AppNamespace()) + return len(edoPods) == 1 + }, 30*time.Second, 3*time.Second) + + edoPodIP := edoPods[0].Status.PodIP + ports := [4]string{"80", "80", "8080", "8081"} + for i, svc := range [4]string{"echo-one", "echo-two", edoPodIP, edoPodIP} { + itest.PingInterceptedEchoServer(ctx, fmt.Sprintf("%s/echo-%d", svc, i), ports[i]) + } +} + +func (s *multiportInterceptSuite) Test_MultiPortLocalConflict() { + ctx := s.Context() + itest.TelepresenceOk(ctx, "intercept", s.workloads[0], + "--mount=false", + "--port", fmt.Sprintf("%d:%s", s.servicePort[0], s.ports[0][0]), + "--port", fmt.Sprintf("%d:%s", s.servicePort[1], s.ports[0][1])) + defer itest.TelepresenceOk(ctx, "leave", s.workloads[0]) + + _, _, err := itest.Telepresence(ctx, "intercept", s.workloads[1], + "--mount=false", + "--port", fmt.Sprintf("%d:%s", s.servicePort[2], s.ports[1][0]), + "--port", fmt.Sprintf("%d:%s", s.servicePort[1], s.ports[1][1])) + s.Require().Error(err) + s.Contains(err.Error(), fmt.Sprintf("%d is already in use by intercept %s", s.servicePort[1], s.workloads[0])) +} + +func (s *multiportInterceptSuite) Test_MultiPortRemoteConflict() { + ctx := s.Context() + itest.TelepresenceOk(ctx, "intercept", s.workloads[0], + "--mount=false", + "--port", fmt.Sprintf("%d:%s", s.servicePort[0], s.ports[0][0]), + "--port", fmt.Sprintf("%d:%s", s.servicePort[1], s.ports[0][1])) + defer itest.TelepresenceOk(ctx, "leave", s.workloads[0]) + + _, _, err := itest.Telepresence(ctx, "intercept", "--workload", s.workloads[0], s.workloads[0]+"-again", + "--mount=false", + "--port", strconv.Itoa(s.servicePort[1]), "--service", "echo-two") + s.Require().Error(err) + s.Regexp(fmt.Sprintf(`container port 8081 is already intercepted by \S+ intercept %s`, s.workloads[0]), err.Error()) +} diff --git a/integration_test/testdata/k8s/echo-two.yaml b/integration_test/testdata/k8s/echo-both.yaml similarity index 100% rename from integration_test/testdata/k8s/echo-two.yaml rename to integration_test/testdata/k8s/echo-both.yaml