diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c3d458dd8..a98cd3e684 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -107,7 +107,10 @@ Please see the [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest - Change: Emissary will now watch for ConfigMap or Secret resources specified by the `AGENT_CONFIG_RESOURCE_NAME` environment variable in order to allow all components (and not only - the Ambassador Agent) to authenticate requests to Ambassador Cloud. + the Ambassador Agent) to authenticate requests to Ambassador Cloud. Support for the Envoy V2 API + and the `AMBASSADOR_ENVOY_API_VERSION` environment + +- Feature: Support for streaming Envoy metrics about the clusters to Ambassador's cloud. ([4053]) - Feature: The Emissary agent now receives commands to manipulate Rollouts (pause, continue, and abort are currently supported) via directives and executes them in the cluster. A report is send @@ -119,6 +122,7 @@ Please see the [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest [3906]: https://github.com/emissary-ingress/emissary/issues/3906 [3821]: https://github.com/emissary-ingress/emissary/issues/3821 +[4053]: https://github.com/emissary-ingress/emissary/pull/4053 [4040]: https://github.com/emissary-ingress/emissary/pull/4040 ## [2.1.2] January 25, 2022 diff --git a/api/agent/director.proto b/api/agent/director.proto index 1ee5eda203..7368445c52 100644 --- a/api/agent/director.proto +++ b/api/agent/director.proto @@ -8,19 +8,24 @@ syntax = "proto3"; import "google/protobuf/duration.proto"; import "google/protobuf/timestamp.proto"; +import "prometheus/metrics.proto"; + package agent; service Director { - // Report a consistent Snapshot of information to the CEPC. This + // Report a consistent Snapshot of information to the DCP. This // method is deprecated, you should call ReportStream instead. rpc Report(Snapshot) returns (SnapshotResponse) { option deprecated = true; } - // Report a consistent Snapshot of information to the CEPC. + // Report a consistent Snapshot of information to the DCP. rpc ReportStream(stream RawSnapshotChunk) returns (SnapshotResponse) {} - // Retrieve Directives from the CEPC + // Stream metrics to the DCP. + rpc StreamMetrics(stream StreamMetricsMessage) returns (StreamMetricsResponse) {} + + // Retrieve Directives from the DCP rpc Retrieve(Identity) returns (stream Directive) {} // Reports the result of a command execution to the cloud @@ -29,11 +34,11 @@ service Director { rpc RetrieveSnapshot(Identity) returns (stream RawSnapshotChunk) {} } -// How Ambassador's Agent identifies itself to the CEPC +// How Ambassador's Agent identifies itself to the DCP // This is the identity of the ambassador the agent is reporting on behalf of // no user account specific information should be contained in here message Identity { - // The account ID assigned by the CEPC + // The account ID assigned by the DCP string account_id = 1 [deprecated=true]; // Ambassador version @@ -53,7 +58,7 @@ message Identity { } // Information that Ambassador's Agent can send to the Director -// component of the CEPC +// component of the DCP message Snapshot { Identity identity = 1; string message = 2; @@ -86,7 +91,7 @@ message SnapshotResponse { // an error. In the future this may contain additional information. } -// Instructions that the CEPC can send to Ambassador +// Instructions that the DCP can send to Ambassador message Directive { string ID = 1; @@ -103,7 +108,7 @@ message Directive { repeated Command commands = 4; } -// An individual instruction from the CEPC +// An individual instruction from the DCP message Command { // Log this message if present string message = 1; @@ -128,4 +133,15 @@ message CommandResult { string message = 3; } -message CommandResultResponse {} +message CommandResultResponse { +} + +message StreamMetricsMessage { + Identity identity = 1; + + // A list of metric entries + repeated io.prometheus.client.MetricFamily envoy_metrics = 2; +} + +message StreamMetricsResponse { +} diff --git a/api/prometheus/metrics.proto b/api/prometheus/metrics.proto new file mode 100644 index 0000000000..c9546f1420 --- /dev/null +++ b/api/prometheus/metrics.proto @@ -0,0 +1,92 @@ +// Copyright 2013 Prometheus Team +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto2"; + +package io.prometheus.client; +option java_package = "io.prometheus.client"; +option go_package = "github.com/prometheus/client_model/go;io_prometheus_client"; + +import "google/protobuf/timestamp.proto"; + +message LabelPair { + optional string name = 1; + optional string value = 2; +} + +enum MetricType { + COUNTER = 0; + GAUGE = 1; + SUMMARY = 2; + UNTYPED = 3; + HISTOGRAM = 4; +} + +message Gauge { + optional double value = 1; +} + +message Counter { + optional double value = 1; + optional Exemplar exemplar = 2; +} + +message Quantile { + optional double quantile = 1; + optional double value = 2; +} + +message Summary { + optional uint64 sample_count = 1; + optional double sample_sum = 2; + repeated Quantile quantile = 3; +} + +message Untyped { + optional double value = 1; +} + +message Histogram { + optional uint64 sample_count = 1; + optional double sample_sum = 2; + repeated Bucket bucket = 3; // Ordered in increasing order of upper_bound, +Inf bucket is optional. +} + +message Bucket { + optional uint64 cumulative_count = 1; // Cumulative in increasing order. + optional double upper_bound = 2; // Inclusive. + optional Exemplar exemplar = 3; +} + +message Exemplar { + repeated LabelPair label = 1; + optional double value = 2; + optional google.protobuf.Timestamp timestamp = 3; // OpenMetrics-style. +} + +message Metric { + repeated LabelPair label = 1; + optional Gauge gauge = 2; + optional Counter counter = 3; + optional Summary summary = 4; + optional Untyped untyped = 5; + optional Histogram histogram = 7; + optional int64 timestamp_ms = 6; +} + +message MetricFamily { + optional string name = 1; + optional string help = 2; + optional MetricType type = 3; + repeated Metric metric = 4; +} diff --git a/builder/requirements-dev.txt b/builder/requirements-dev.txt index cd9e0e5764..8fd1d6580e 100644 --- a/builder/requirements-dev.txt +++ b/builder/requirements-dev.txt @@ -3,7 +3,7 @@ dpath gitpython mypy pexpect -pytest +pytest==6.2.5 pytest-cov retry httpretty diff --git a/charts/emissary-ingress/templates/ambassador-agent.yaml b/charts/emissary-ingress/templates/ambassador-agent.yaml index 43b9ff070b..c583a1daf8 100644 --- a/charts/emissary-ingress/templates/ambassador-agent.yaml +++ b/charts/emissary-ingress/templates/ambassador-agent.yaml @@ -226,6 +226,9 @@ spec: image: {{ include "ambassador.image" . }} imagePullPolicy: {{ .Values.image.pullPolicy }} command: [ "agent" ] + ports: + - containerPort: 8006 + name: grpc env: - name: AGENT_NAMESPACE valueFrom: @@ -242,5 +245,33 @@ spec: progressDeadlineSeconds: {{ .Values.progressDeadlines.agent }} {{- end }} {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "ambassador.fullname" . }}-agent + namespace: {{ include "ambassador.namespace" . }} + labels: + {{- if ne .Values.deploymentTool "getambassador.io" }} + app.kubernetes.io/name: {{ include "ambassador.name" . }}-agent + app.kubernetes.io/part-of: {{ .Release.Name }} + helm.sh/chart: {{ include "ambassador.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + {{- if .Values.deploymentTool }} + app.kubernetes.io/managed-by: {{ .Values.deploymentTool }} + {{- else }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- end }} + {{- end }} + product: aes +spec: + ports: + - port: 8006 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: {{ include "ambassador.fullname" . }}-agent + app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} {{- end }} diff --git a/charts/emissary-ingress/templates/deployment.yaml b/charts/emissary-ingress/templates/deployment.yaml index 0d65ac127f..813a292ec4 100644 --- a/charts/emissary-ingress/templates/deployment.yaml +++ b/charts/emissary-ingress/templates/deployment.yaml @@ -172,6 +172,8 @@ spec: - name: admin containerPort: {{ .Values.adminService.port }} env: + - name: AMBASSADOR_GRPC_METRICS_SINK + value: {{ include "ambassador.fullname" . }}:8006 - name: HOST_IP valueFrom: fieldRef: diff --git a/cmd/agent/main.go b/cmd/agent/main.go index 11beb56797..b45d534fc4 100644 --- a/cmd/agent/main.go +++ b/cmd/agent/main.go @@ -4,6 +4,7 @@ import ( "context" "flag" "fmt" + "github.com/datawire/dlib/dgroup" "os" "github.com/spf13/cobra" @@ -50,6 +51,17 @@ func run(cmd *cobra.Command, args []string) error { snapshotURL = fmt.Sprintf(DefaultSnapshotURLFmt, entrypoint.ExternalSnapshotPort) } + group := dgroup.NewGroup(ctx, dgroup.GroupConfig{}) + + group.Go("metrics-server", func(ctx context.Context) error { + metricsServer := agent.NewMetricsServer(ambAgent.MetricsRelayHandler) + if err := metricsServer.StartServer(ctx); err != nil { + dlog.Errorf(ctx, "metrics service failed to listen: %v", err) + return err + } + return nil + }) + if err := ambAgent.Watch(ctx, snapshotURL); err != nil { return err } diff --git a/cmd/example-envoy-metrics-sink/main.go b/cmd/example-envoy-metrics-sink/main.go index f0bf09f510..f52a6d214e 100644 --- a/cmd/example-envoy-metrics-sink/main.go +++ b/cmd/example-envoy-metrics-sink/main.go @@ -29,7 +29,7 @@ func main() { dlog.Print(ctx, "starting...") - if err := sc.ListenAndServe(ctx, ":8123"); err != nil { + if err := sc.ListenAndServe(ctx, ":8006"); err != nil { dlog.Errorf(ctx, "shut down with error: %v", err) os.Exit(1) } diff --git a/docs/releaseNotes.yml b/docs/releaseNotes.yml index f2cc662a36..9db7a215f5 100644 --- a/docs/releaseNotes.yml +++ b/docs/releaseNotes.yml @@ -73,6 +73,15 @@ items: `AGENT_CONFIG_RESOURCE_NAME` environment variable in order to allow all components (and not only the Ambassador Agent) to authenticate requests to Ambassador Cloud. + Support for the Envoy V2 API and the `AMBASSADOR_ENVOY_API_VERSION` environment + + - title: Stream metrics from Envoy to the Ambassador cloud + type: feature + body: >- + Support for streaming Envoy metrics about the clusters to Ambassador's cloud. + github: + - title: 4053 + link: https://github.com/emissary-ingress/emissary/pull/4053 - title: Support received commands to pause, continue and abort a Rollout via Agent directives type: feature diff --git a/k8s-config/emissary-defaultns/require.yaml b/k8s-config/emissary-defaultns/require.yaml index fe714a7201..af9d2dfbf7 100644 --- a/k8s-config/emissary-defaultns/require.yaml +++ b/k8s-config/emissary-defaultns/require.yaml @@ -3,6 +3,7 @@ _anchors: resources: - { kind: Service, name: emissary-ingress-admin, namespace: *namespace } - { kind: Service, name: emissary-ingress, namespace: *namespace } + - { kind: Service, name: emissary-ingress-agent, namespace: *namespace } - { kind: ClusterRole, name: emissary-ingress } - { kind: ServiceAccount, name: emissary-ingress, namespace: *namespace } - { kind: ClusterRoleBinding, name: emissary-ingress } diff --git a/k8s-config/emissary-emissaryns/require.yaml b/k8s-config/emissary-emissaryns/require.yaml index 24c321298f..469efc5da3 100644 --- a/k8s-config/emissary-emissaryns/require.yaml +++ b/k8s-config/emissary-emissaryns/require.yaml @@ -3,6 +3,7 @@ _anchors: resources: - { kind: Service, name: emissary-ingress-admin, namespace: *namespace } - { kind: Service, name: emissary-ingress, namespace: *namespace } + - { kind: Service, name: emissary-ingress-agent, namespace: *namespace } - { kind: ClusterRole, name: emissary-ingress } - { kind: ServiceAccount, name: emissary-ingress, namespace: *namespace } - { kind: ClusterRoleBinding, name: emissary-ingress } diff --git a/manifests/emissary/emissary-defaultns-agent.yaml.in b/manifests/emissary/emissary-defaultns-agent.yaml.in index d2ff98cfc8..aa55185374 100644 --- a/manifests/emissary/emissary-defaultns-agent.yaml.in +++ b/manifests/emissary/emissary-defaultns-agent.yaml.in @@ -260,4 +260,7 @@ spec: image: $imageRepo$:$version$ imagePullPolicy: IfNotPresent name: agent + ports: + - containerPort: 8006 + name: grpc serviceAccountName: emissary-ingress-agent diff --git a/manifests/emissary/emissary-defaultns-migration.yaml.in b/manifests/emissary/emissary-defaultns-migration.yaml.in index ac2c3383d0..12027c2848 100644 --- a/manifests/emissary/emissary-defaultns-migration.yaml.in +++ b/manifests/emissary/emissary-defaultns-migration.yaml.in @@ -271,6 +271,8 @@ spec: weight: 100 containers: - env: + - name: AMBASSADOR_GRPC_METRICS_SINK + value: emissary-ingress:8006 - name: HOST_IP valueFrom: fieldRef: diff --git a/manifests/emissary/emissary-defaultns.yaml.in b/manifests/emissary/emissary-defaultns.yaml.in index 9ec9391ecb..10e9237f59 100644 --- a/manifests/emissary/emissary-defaultns.yaml.in +++ b/manifests/emissary/emissary-defaultns.yaml.in @@ -74,6 +74,23 @@ spec: profile: main type: LoadBalancer --- +apiVersion: v1 +kind: Service +metadata: + labels: + product: aes + name: emissary-ingress-agent + namespace: default +spec: + ports: + - name: grpc + port: 8006 + protocol: TCP + targetPort: grpc + selector: + app.kubernetes.io/instance: emissary-ingress + app.kubernetes.io/name: emissary-ingress-agent +--- aggregationRule: clusterRoleSelectors: - matchLabels: @@ -271,6 +288,8 @@ spec: weight: 100 containers: - env: + - name: AMBASSADOR_GRPC_METRICS_SINK + value: emissary-ingress:8006 - name: HOST_IP valueFrom: fieldRef: @@ -592,4 +611,7 @@ spec: image: $imageRepo$:$version$ imagePullPolicy: IfNotPresent name: agent + ports: + - containerPort: 8006 + name: grpc serviceAccountName: emissary-ingress-agent diff --git a/manifests/emissary/emissary-emissaryns-agent.yaml.in b/manifests/emissary/emissary-emissaryns-agent.yaml.in index cb96e5a8e9..9b9c2e259d 100644 --- a/manifests/emissary/emissary-emissaryns-agent.yaml.in +++ b/manifests/emissary/emissary-emissaryns-agent.yaml.in @@ -260,4 +260,7 @@ spec: image: $imageRepo$:$version$ imagePullPolicy: IfNotPresent name: agent + ports: + - containerPort: 8006 + name: grpc serviceAccountName: emissary-ingress-agent diff --git a/manifests/emissary/emissary-emissaryns-migration.yaml.in b/manifests/emissary/emissary-emissaryns-migration.yaml.in index b301119140..9bd25922ba 100644 --- a/manifests/emissary/emissary-emissaryns-migration.yaml.in +++ b/manifests/emissary/emissary-emissaryns-migration.yaml.in @@ -271,6 +271,8 @@ spec: weight: 100 containers: - env: + - name: AMBASSADOR_GRPC_METRICS_SINK + value: emissary-ingress:8006 - name: HOST_IP valueFrom: fieldRef: diff --git a/manifests/emissary/emissary-emissaryns.yaml.in b/manifests/emissary/emissary-emissaryns.yaml.in index aae9f7cd27..d36ff28155 100644 --- a/manifests/emissary/emissary-emissaryns.yaml.in +++ b/manifests/emissary/emissary-emissaryns.yaml.in @@ -74,6 +74,23 @@ spec: profile: main type: LoadBalancer --- +apiVersion: v1 +kind: Service +metadata: + labels: + product: aes + name: emissary-ingress-agent + namespace: emissary +spec: + ports: + - name: grpc + port: 8006 + protocol: TCP + targetPort: grpc + selector: + app.kubernetes.io/instance: emissary-ingress + app.kubernetes.io/name: emissary-ingress-agent +--- aggregationRule: clusterRoleSelectors: - matchLabels: @@ -271,6 +288,8 @@ spec: weight: 100 containers: - env: + - name: AMBASSADOR_GRPC_METRICS_SINK + value: emissary-ingress:8006 - name: HOST_IP valueFrom: fieldRef: @@ -592,4 +611,7 @@ spec: image: $imageRepo$:$version$ imagePullPolicy: IfNotPresent name: agent + ports: + - containerPort: 8006 + name: grpc serviceAccountName: emissary-ingress-agent diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index 11b99882e6..6f267de4fa 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -4,10 +4,13 @@ import ( "context" "encoding/json" "fmt" + envoyMetrics "github.com/datawire/ambassador/v2/pkg/api/envoy/service/metrics/v3" + io_prometheus_client "github.com/prometheus/client_model/go" "io/ioutil" "net/http" "net/url" "os" + "strings" "sync" "time" @@ -28,6 +31,7 @@ type Comm interface { Report(context.Context, *agent.Snapshot, string) error ReportCommandResult(context.Context, *agent.CommandResult, string) error Directives() <-chan *agent.Directive + StreamMetrics(context.Context, *agent.StreamMetricsMessage, string) error } type atomicBool struct { @@ -47,7 +51,7 @@ func (ab *atomicBool) Set(v bool) { ab.value = v } -// Agent is the component that talks to the CEPC Director, which is a cloud +// Agent is the component that talks to the DCP Director, which is a cloud // service run by Datawire. type Agent struct { // Connectivity to the Director @@ -462,13 +466,13 @@ func (a *Agent) MaybeReport(ctx context.Context) { // It's time to send a report if a.comm == nil { - // The communications channel to the CEPC was not yet created or was + // The communications channel to the DCP was not yet created or was // closed above, due to a change in identity, or close elsewhere, due to // a change in endpoint configuration. newComm, err := NewComm(ctx, a.connInfo, a.agentID, a.ambassadorAPIKey) if err != nil { - dlog.Warnf(ctx, "Failed to dial the CEPC: %v", err) - dlog.Warn(ctx, "CEPC functionality disabled until next retry") + dlog.Warnf(ctx, "Failed to dial the DCP: %v", err) + dlog.Warn(ctx, "DCP functionality disabled until next retry") return } @@ -603,6 +607,37 @@ func (a *Agent) ProcessSnapshot(ctx context.Context, snapshot *snapshotTypes.Sna return nil } +var allowedMetricsSuffixes = []string{"upstream_rq_total", "upstream_rq_time", "upstream_rq_5xx"} + +func (a *Agent) MetricsRelayHandler(logCtx context.Context, in *envoyMetrics.StreamMetricsMessage) { + metrics := in.GetEnvoyMetrics() + dlog.Debugf(logCtx, "received %d metrics", len(metrics)) + if a.comm != nil && !a.reportingStopped { + a.ambassadorAPIKeyMutex.Lock() + apikey := a.ambassadorAPIKey + a.ambassadorAPIKeyMutex.Unlock() + + outMetrics := make([]*io_prometheus_client.MetricFamily, 0, len(metrics)) + for _, metricFamily := range metrics { + for _, suffix := range allowedMetricsSuffixes { + if strings.HasSuffix(metricFamily.GetName(), suffix) { + outMetrics = append(outMetrics, metricFamily) + break + } + } + } + + outMessage := &agent.StreamMetricsMessage{ + Identity: a.agentID, + EnvoyMetrics: outMetrics, + } + dlog.Debugf(logCtx, "relaying %d metrics", len(outMessage.GetEnvoyMetrics())) + if err := a.comm.StreamMetrics(logCtx, outMessage, apikey); err != nil { + dlog.Errorf(logCtx, "Error streaming metrics: %+v", err) + } + } +} + // ClearComm ends the current connection to the Director, if it exists, thereby // forcing a new connection to be created when needed. func (a *Agent) ClearComm() { diff --git a/pkg/agent/agent_internal_test.go b/pkg/agent/agent_internal_test.go index eb4397f86f..4a72946b15 100644 --- a/pkg/agent/agent_internal_test.go +++ b/pkg/agent/agent_internal_test.go @@ -270,7 +270,7 @@ func TestProcessSnapshot(t *testing.T) { }, { // ProcessSnapshot should set the Agent.connInfo to the parsed url from the - // ambassador module's CEPC config + // ambassador module's DCP config testName: "module-contains-connection-info", address: "http://somecooladdress:1234", inputSnap: &snapshotTypes.Snapshot{ diff --git a/pkg/agent/comm.go b/pkg/agent/comm.go index 31d68ed571..3430a09533 100644 --- a/pkg/agent/comm.go +++ b/pkg/agent/comm.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "net/url" + "sync" "google.golang.org/grpc" "google.golang.org/grpc/credentials" @@ -19,12 +20,13 @@ import ( const APIKeyMetadataKey = "x-ambassador-api-key" type RPCComm struct { - conn io.Closer - client agent.DirectorClient - rptWake chan struct{} - retCancel context.CancelFunc - agentID *agent.Identity - directives chan *agent.Directive + conn io.Closer + client agent.DirectorClient + rptWake chan struct{} + retCancel context.CancelFunc + agentID *agent.Identity + directives chan *agent.Directive + metricsStreamWriterMutex sync.Mutex } const ( @@ -199,6 +201,19 @@ func (c *RPCComm) Report(ctx context.Context, report *agent.Snapshot, apiKey str return nil } +func (c *RPCComm) StreamMetrics(ctx context.Context, metrics *agent.StreamMetricsMessage, apiKey string) error { + ctx = dlog.WithField(ctx, "agent", "streammetrics") + + c.metricsStreamWriterMutex.Lock() + defer c.metricsStreamWriterMutex.Unlock() + ctx = metadata.AppendToOutgoingContext(ctx, APIKeyMetadataKey, apiKey) + streamClient, err := c.client.StreamMetrics(ctx) + if err != nil { + return err + } + return streamClient.Send(metrics) +} + func (c *RPCComm) Directives() <-chan *agent.Directive { return c.directives } diff --git a/pkg/agent/comm_internal_test.go b/pkg/agent/comm_internal_test.go index 4eedab7121..8f89efe318 100644 --- a/pkg/agent/comm_internal_test.go +++ b/pkg/agent/comm_internal_test.go @@ -63,6 +63,10 @@ func (m *MockClient) Report(ctx context.Context, in *agent.Snapshot, opts ...grp return nil, nil } +func (m *MockClient) StreamMetrics(ctx context.Context, opts ...grpc.CallOption) (agent.Director_StreamMetricsClient, error) { + panic("implement me") +} + type mockReportStreamClient struct { ctx context.Context opts []grpc.CallOption diff --git a/pkg/agent/envoy_metrics_server.go b/pkg/agent/envoy_metrics_server.go new file mode 100644 index 0000000000..37fa08d180 --- /dev/null +++ b/pkg/agent/envoy_metrics_server.go @@ -0,0 +1,56 @@ +package agent + +import ( + "context" + envoyMetrics "github.com/datawire/ambassador/v2/pkg/api/envoy/service/metrics/v3" + "github.com/datawire/dlib/dhttp" + "github.com/datawire/dlib/dlog" + "google.golang.org/grpc" + "io" +) + +type streamHandler func(logCtx context.Context, in *envoyMetrics.StreamMetricsMessage) + +type metricsServer struct { + envoyMetrics.MetricsServiceServer + handler streamHandler + logCtx context.Context +} + +// NewMetricsServer is the main metricsServer constructor. +func NewMetricsServer(handler streamHandler) *metricsServer { + return &metricsServer{ + handler: handler, + } +} + +// StartServer will start the metrics gRPC server, listening on :8006 +// It is a blocking call until sc.ListenAndServe returns. +func (s *metricsServer) StartServer(ctx context.Context) error { + grpcServer := grpc.NewServer() + envoyMetrics.RegisterMetricsServiceServer(grpcServer, s) + + sc := &dhttp.ServerConfig{ + Handler: grpcServer, + } + + s.logCtx = ctx + dlog.Info(ctx, "starting metrics service listening on :8006") + return sc.ListenAndServe(ctx, ":8006") +} + +// StreamMetrics implements the StreamMetrics rpc call by calling the stream handler on each +// message received. It's invoked whenever metrics arrive from Envoy. +func (s *metricsServer) StreamMetrics(stream envoyMetrics.MetricsService_StreamMetricsServer) error { + dlog.Debug(s.logCtx, "started stream") + for { + in, err := stream.Recv() + if err == io.EOF { + return nil + } + if err != nil { + return err + } + s.handler(s.logCtx, in) + } +} diff --git a/pkg/agent/report.go b/pkg/agent/report.go index 84a90fd451..500b28b13f 100644 --- a/pkg/agent/report.go +++ b/pkg/agent/report.go @@ -5,7 +5,7 @@ import ( snapshotTypes "github.com/datawire/ambassador/v2/pkg/snapshot/v1" ) -// GetIdentity returns the Agent's CEPC Identity, if present, enabled, and +// GetIdentity returns the Agent's DCP Identity, if present, enabled, and // configured by the user. func GetIdentity(ambassadorMeta *snapshotTypes.AmbassadorMetaInfo, ambHost string) *agent.Identity { if ambassadorMeta == nil || ambassadorMeta.ClusterID == "" { diff --git a/pkg/api/agent/director.pb.go b/pkg/api/agent/director.pb.go index 957aebfb35..886cc834c7 100644 --- a/pkg/api/agent/director.pb.go +++ b/pkg/api/agent/director.pb.go @@ -16,6 +16,7 @@ import ( proto "github.com/golang/protobuf/proto" duration "github.com/golang/protobuf/ptypes/duration" timestamp "github.com/golang/protobuf/ptypes/timestamp" + _go "github.com/prometheus/client_model/go" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" @@ -85,7 +86,7 @@ func (RolloutCommand_Action) EnumDescriptor() ([]byte, []int) { return file_agent_director_proto_rawDescGZIP(), []int{7, 0} } -// How Ambassador's Agent identifies itself to the CEPC +// How Ambassador's Agent identifies itself to the DCP // This is the identity of the ambassador the agent is reporting on behalf of // no user account specific information should be contained in here type Identity struct { @@ -93,7 +94,7 @@ type Identity struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The account ID assigned by the CEPC + // The account ID assigned by the DCP // // Deprecated: Do not use. AccountId string `protobuf:"bytes,1,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"` @@ -191,7 +192,7 @@ func (x *Identity) GetLabel() string { } // Information that Ambassador's Agent can send to the Director -// component of the CEPC +// component of the DCP type Snapshot struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -452,7 +453,7 @@ func (*SnapshotResponse) Descriptor() ([]byte, []int) { return file_agent_director_proto_rawDescGZIP(), []int{4} } -// Instructions that the CEPC can send to Ambassador +// Instructions that the DCP can send to Ambassador type Directive struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -530,7 +531,7 @@ func (x *Directive) GetCommands() []*Command { return nil } -// An individual instruction from the CEPC +// An individual instruction from the DCP type Command struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -759,6 +760,100 @@ func (*CommandResultResponse) Descriptor() ([]byte, []int) { return file_agent_director_proto_rawDescGZIP(), []int{9} } +type StreamMetricsMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Identity *Identity `protobuf:"bytes,1,opt,name=identity,proto3" json:"identity,omitempty"` + // A list of metric entries + EnvoyMetrics []*_go.MetricFamily `protobuf:"bytes,2,rep,name=envoy_metrics,json=envoyMetrics,proto3" json:"envoy_metrics,omitempty"` +} + +func (x *StreamMetricsMessage) Reset() { + *x = StreamMetricsMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_director_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamMetricsMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamMetricsMessage) ProtoMessage() {} + +func (x *StreamMetricsMessage) ProtoReflect() protoreflect.Message { + mi := &file_agent_director_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamMetricsMessage.ProtoReflect.Descriptor instead. +func (*StreamMetricsMessage) Descriptor() ([]byte, []int) { + return file_agent_director_proto_rawDescGZIP(), []int{10} +} + +func (x *StreamMetricsMessage) GetIdentity() *Identity { + if x != nil { + return x.Identity + } + return nil +} + +func (x *StreamMetricsMessage) GetEnvoyMetrics() []*_go.MetricFamily { + if x != nil { + return x.EnvoyMetrics + } + return nil +} + +type StreamMetricsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *StreamMetricsResponse) Reset() { + *x = StreamMetricsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_director_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamMetricsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamMetricsResponse) ProtoMessage() {} + +func (x *StreamMetricsResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_director_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamMetricsResponse.ProtoReflect.Descriptor instead. +func (*StreamMetricsResponse) Descriptor() ([]byte, []int) { + return file_agent_director_proto_rawDescGZIP(), []int{11} +} + var File_agent_director_proto protoreflect.FileDescriptor var file_agent_director_proto_rawDesc = []byte{ @@ -767,120 +862,137 @@ var file_agent_director_proto_rawDesc = []byte{ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xba, - 0x01, 0x0a, 0x08, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x21, 0x0a, 0x0a, 0x61, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x02, 0x18, 0x01, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1c, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x02, 0x18, 0x01, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, - 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x69, 0x63, 0x65, - 0x6e, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, - 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, - 0x64, 0x12, 0x18, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x02, 0x18, 0x01, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0xa5, 0x02, 0x0a, 0x08, - 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x2b, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x08, 0x69, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x2e, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x42, 0x02, 0x18, 0x01, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, - 0x21, 0x0a, 0x0c, 0x72, 0x61, 0x77, 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x72, 0x61, 0x77, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, - 0x6f, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x70, 0x69, 0x5f, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x0b, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, - 0x6f, 0x74, 0x5f, 0x74, 0x73, 0x18, 0x07, 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, 0x0a, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, - 0x74, 0x54, 0x73, 0x22, 0x28, 0x0a, 0x10, 0x52, 0x61, 0x77, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, - 0x6f, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x22, 0xad, 0x02, - 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 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, 0x32, 0x0a, 0x06, 0x6c, - 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, 0x61, 0x62, 0x65, - 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, - 0x41, 0x0a, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 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, 0x3e, 0x0a, - 0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x12, 0x0a, - 0x10, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0xb5, 0x01, 0x0a, 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, - 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, - 0x25, 0x0a, 0x0e, 0x73, 0x74, 0x6f, 0x70, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, - 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x45, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x03, 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, 0x0f, 0x6d, 0x69, - 0x6e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x2a, 0x0a, - 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x0e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, - 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x22, 0x62, 0x0a, 0x07, 0x43, 0x6f, 0x6d, - 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3d, - 0x0a, 0x0e, 0x72, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, - 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x0e, 0x72, - 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22, 0xc3, 0x01, - 0x0a, 0x0e, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 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, 0x34, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, - 0x75, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, - 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x22, 0x2a, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x41, 0x55, 0x53, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, - 0x52, 0x45, 0x53, 0x55, 0x4d, 0x45, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x42, 0x4f, 0x52, - 0x54, 0x10, 0x02, 0x22, 0x62, 0x0a, 0x0d, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, - 0x64, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x17, 0x0a, 0x15, 0x43, 0x6f, 0x6d, 0x6d, 0x61, - 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x32, 0xcb, 0x02, 0x0a, 0x08, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x37, 0x0a, - 0x06, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x0f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, - 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x12, 0x44, 0x0a, 0x0c, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, - 0x61, 0x77, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x1a, - 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x12, 0x31, 0x0a, 0x08, - 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x12, 0x0f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x10, 0x2e, 0x61, 0x67, 0x65, 0x6e, - 0x74, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, - 0x4b, 0x0a, 0x13, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, - 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x14, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x1c, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x10, - 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, - 0x12, 0x0f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x1a, 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x61, 0x77, 0x53, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x22, 0x00, 0x30, 0x01, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, + 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xba, 0x01, 0x0a, 0x08, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x21, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x61, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, + 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x05, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x05, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0xa5, 0x02, 0x0a, 0x08, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x12, 0x2b, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, + 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x02, 0x18, 0x01, 0x52, + 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x61, 0x77, + 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0b, 0x72, 0x61, 0x77, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x21, 0x0a, 0x0c, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x1f, 0x0a, 0x0b, 0x61, 0x70, 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x3b, 0x0a, 0x0b, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x74, 0x73, 0x18, + 0x07, 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, 0x0a, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x54, 0x73, 0x22, 0x28, 0x0a, + 0x10, 0x52, 0x61, 0x77, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x43, 0x68, 0x75, 0x6e, + 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x22, 0xad, 0x02, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 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, 0x32, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x41, 0x0a, 0x0b, 0x61, 0x6e, 0x6e, + 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, + 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x39, 0x0a, 0x0b, + 0x4c, 0x61, 0x62, 0x65, 0x6c, 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, 0x3e, 0x0a, 0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x12, 0x0a, 0x10, 0x53, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xb5, 0x01, 0x0a, 0x09, + 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x74, 0x6f, + 0x70, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0d, 0x73, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, + 0x12, 0x45, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x70, + 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x03, 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, 0x0f, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x2a, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x73, 0x22, 0x62, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x18, + 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3d, 0x0a, 0x0e, 0x72, 0x6f, 0x6c, 0x6c, + 0x6f, 0x75, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x0e, 0x72, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22, 0xc3, 0x01, 0x0a, 0x0e, 0x52, 0x6f, 0x6c, 0x6c, + 0x6f, 0x75, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 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, 0x34, 0x0a, 0x06, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x43, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, + 0x64, 0x22, 0x2a, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x50, + 0x41, 0x55, 0x53, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x53, 0x55, 0x4d, 0x45, + 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x42, 0x4f, 0x52, 0x54, 0x10, 0x02, 0x22, 0x62, 0x0a, + 0x0d, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1d, + 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x18, 0x0a, + 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0x17, 0x0a, 0x15, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x8c, 0x01, 0x0a, 0x14, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x12, 0x47, 0x0a, 0x0d, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, + 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x4d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x52, 0x0c, 0x65, 0x6e, 0x76, + 0x6f, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x17, 0x0a, 0x15, 0x53, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x32, 0x9b, 0x03, 0x0a, 0x08, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, + 0x37, 0x0a, 0x06, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x0f, 0x2e, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x2e, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x12, 0x44, 0x0a, 0x0c, 0x52, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x2e, 0x52, 0x61, 0x77, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x43, 0x68, 0x75, 0x6e, + 0x6b, 0x1a, 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x12, 0x4e, + 0x0a, 0x0d, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, + 0x1b, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x12, 0x31, + 0x0a, 0x08, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x12, 0x0f, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x10, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x22, 0x00, 0x30, + 0x01, 0x12, 0x4b, 0x0a, 0x13, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x14, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x1c, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40, + 0x0a, 0x10, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x12, 0x0f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x1a, 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x61, 0x77, 0x53, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x22, 0x00, 0x30, 0x01, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -896,7 +1008,7 @@ func file_agent_director_proto_rawDescGZIP() []byte { } var file_agent_director_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_agent_director_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_agent_director_proto_msgTypes = make([]protoimpl.MessageInfo, 14) var file_agent_director_proto_goTypes = []interface{}{ (RolloutCommand_Action)(0), // 0: agent.RolloutCommand.Action (*Identity)(nil), // 1: agent.Identity @@ -909,36 +1021,43 @@ var file_agent_director_proto_goTypes = []interface{}{ (*RolloutCommand)(nil), // 8: agent.RolloutCommand (*CommandResult)(nil), // 9: agent.CommandResult (*CommandResultResponse)(nil), // 10: agent.CommandResultResponse - nil, // 11: agent.Service.LabelsEntry - nil, // 12: agent.Service.AnnotationsEntry - (*timestamp.Timestamp)(nil), // 13: google.protobuf.Timestamp - (*duration.Duration)(nil), // 14: google.protobuf.Duration + (*StreamMetricsMessage)(nil), // 11: agent.StreamMetricsMessage + (*StreamMetricsResponse)(nil), // 12: agent.StreamMetricsResponse + nil, // 13: agent.Service.LabelsEntry + nil, // 14: agent.Service.AnnotationsEntry + (*timestamp.Timestamp)(nil), // 15: google.protobuf.Timestamp + (*duration.Duration)(nil), // 16: google.protobuf.Duration + (*_go.MetricFamily)(nil), // 17: io.prometheus.client.MetricFamily } var file_agent_director_proto_depIdxs = []int32{ 1, // 0: agent.Snapshot.identity:type_name -> agent.Identity 4, // 1: agent.Snapshot.services:type_name -> agent.Service - 13, // 2: agent.Snapshot.snapshot_ts:type_name -> google.protobuf.Timestamp - 11, // 3: agent.Service.labels:type_name -> agent.Service.LabelsEntry - 12, // 4: agent.Service.annotations:type_name -> agent.Service.AnnotationsEntry - 14, // 5: agent.Directive.min_report_period:type_name -> google.protobuf.Duration + 15, // 2: agent.Snapshot.snapshot_ts:type_name -> google.protobuf.Timestamp + 13, // 3: agent.Service.labels:type_name -> agent.Service.LabelsEntry + 14, // 4: agent.Service.annotations:type_name -> agent.Service.AnnotationsEntry + 16, // 5: agent.Directive.min_report_period:type_name -> google.protobuf.Duration 7, // 6: agent.Directive.commands:type_name -> agent.Command 8, // 7: agent.Command.rolloutCommand:type_name -> agent.RolloutCommand 0, // 8: agent.RolloutCommand.action:type_name -> agent.RolloutCommand.Action - 2, // 9: agent.Director.Report:input_type -> agent.Snapshot - 3, // 10: agent.Director.ReportStream:input_type -> agent.RawSnapshotChunk - 1, // 11: agent.Director.Retrieve:input_type -> agent.Identity - 9, // 12: agent.Director.ReportCommandResult:input_type -> agent.CommandResult - 1, // 13: agent.Director.RetrieveSnapshot:input_type -> agent.Identity - 5, // 14: agent.Director.Report:output_type -> agent.SnapshotResponse - 5, // 15: agent.Director.ReportStream:output_type -> agent.SnapshotResponse - 6, // 16: agent.Director.Retrieve:output_type -> agent.Directive - 10, // 17: agent.Director.ReportCommandResult:output_type -> agent.CommandResultResponse - 3, // 18: agent.Director.RetrieveSnapshot:output_type -> agent.RawSnapshotChunk - 14, // [14:19] is the sub-list for method output_type - 9, // [9:14] is the sub-list for method input_type - 9, // [9:9] is the sub-list for extension type_name - 9, // [9:9] is the sub-list for extension extendee - 0, // [0:9] is the sub-list for field type_name + 1, // 9: agent.StreamMetricsMessage.identity:type_name -> agent.Identity + 17, // 10: agent.StreamMetricsMessage.envoy_metrics:type_name -> io.prometheus.client.MetricFamily + 2, // 11: agent.Director.Report:input_type -> agent.Snapshot + 3, // 12: agent.Director.ReportStream:input_type -> agent.RawSnapshotChunk + 11, // 13: agent.Director.StreamMetrics:input_type -> agent.StreamMetricsMessage + 1, // 14: agent.Director.Retrieve:input_type -> agent.Identity + 9, // 15: agent.Director.ReportCommandResult:input_type -> agent.CommandResult + 1, // 16: agent.Director.RetrieveSnapshot:input_type -> agent.Identity + 5, // 17: agent.Director.Report:output_type -> agent.SnapshotResponse + 5, // 18: agent.Director.ReportStream:output_type -> agent.SnapshotResponse + 12, // 19: agent.Director.StreamMetrics:output_type -> agent.StreamMetricsResponse + 6, // 20: agent.Director.Retrieve:output_type -> agent.Directive + 10, // 21: agent.Director.ReportCommandResult:output_type -> agent.CommandResultResponse + 3, // 22: agent.Director.RetrieveSnapshot:output_type -> agent.RawSnapshotChunk + 17, // [17:23] is the sub-list for method output_type + 11, // [11:17] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name } func init() { file_agent_director_proto_init() } @@ -1067,6 +1186,30 @@ func file_agent_director_proto_init() { return nil } } + file_agent_director_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StreamMetricsMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_director_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StreamMetricsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -1074,7 +1217,7 @@ func file_agent_director_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_agent_director_proto_rawDesc, NumEnums: 1, - NumMessages: 12, + NumMessages: 14, NumExtensions: 0, NumServices: 1, }, @@ -1102,12 +1245,14 @@ const _ = grpc.SupportPackageIsVersion6 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type DirectorClient interface { // Deprecated: Do not use. - // Report a consistent Snapshot of information to the CEPC. This + // Report a consistent Snapshot of information to the DCP. This // method is deprecated, you should call ReportStream instead. Report(ctx context.Context, in *Snapshot, opts ...grpc.CallOption) (*SnapshotResponse, error) - // Report a consistent Snapshot of information to the CEPC. + // Report a consistent Snapshot of information to the DCP. ReportStream(ctx context.Context, opts ...grpc.CallOption) (Director_ReportStreamClient, error) - // Retrieve Directives from the CEPC + // Stream metrics to the DCP. + StreamMetrics(ctx context.Context, opts ...grpc.CallOption) (Director_StreamMetricsClient, error) + // Retrieve Directives from the DCP Retrieve(ctx context.Context, in *Identity, opts ...grpc.CallOption) (Director_RetrieveClient, error) // Reports the result of a command execution to the cloud ReportCommandResult(ctx context.Context, in *CommandResult, opts ...grpc.CallOption) (*CommandResultResponse, error) @@ -1166,8 +1311,42 @@ func (x *directorReportStreamClient) CloseAndRecv() (*SnapshotResponse, error) { return m, nil } +func (c *directorClient) StreamMetrics(ctx context.Context, opts ...grpc.CallOption) (Director_StreamMetricsClient, error) { + stream, err := c.cc.NewStream(ctx, &_Director_serviceDesc.Streams[1], "/agent.Director/StreamMetrics", opts...) + if err != nil { + return nil, err + } + x := &directorStreamMetricsClient{stream} + return x, nil +} + +type Director_StreamMetricsClient interface { + Send(*StreamMetricsMessage) error + CloseAndRecv() (*StreamMetricsResponse, error) + grpc.ClientStream +} + +type directorStreamMetricsClient struct { + grpc.ClientStream +} + +func (x *directorStreamMetricsClient) Send(m *StreamMetricsMessage) error { + return x.ClientStream.SendMsg(m) +} + +func (x *directorStreamMetricsClient) CloseAndRecv() (*StreamMetricsResponse, error) { + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + m := new(StreamMetricsResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + func (c *directorClient) Retrieve(ctx context.Context, in *Identity, opts ...grpc.CallOption) (Director_RetrieveClient, error) { - stream, err := c.cc.NewStream(ctx, &_Director_serviceDesc.Streams[1], "/agent.Director/Retrieve", opts...) + stream, err := c.cc.NewStream(ctx, &_Director_serviceDesc.Streams[2], "/agent.Director/Retrieve", opts...) if err != nil { return nil, err } @@ -1208,7 +1387,7 @@ func (c *directorClient) ReportCommandResult(ctx context.Context, in *CommandRes } func (c *directorClient) RetrieveSnapshot(ctx context.Context, in *Identity, opts ...grpc.CallOption) (Director_RetrieveSnapshotClient, error) { - stream, err := c.cc.NewStream(ctx, &_Director_serviceDesc.Streams[2], "/agent.Director/RetrieveSnapshot", opts...) + stream, err := c.cc.NewStream(ctx, &_Director_serviceDesc.Streams[3], "/agent.Director/RetrieveSnapshot", opts...) if err != nil { return nil, err } @@ -1242,12 +1421,14 @@ func (x *directorRetrieveSnapshotClient) Recv() (*RawSnapshotChunk, error) { // DirectorServer is the server API for Director service. type DirectorServer interface { // Deprecated: Do not use. - // Report a consistent Snapshot of information to the CEPC. This + // Report a consistent Snapshot of information to the DCP. This // method is deprecated, you should call ReportStream instead. Report(context.Context, *Snapshot) (*SnapshotResponse, error) - // Report a consistent Snapshot of information to the CEPC. + // Report a consistent Snapshot of information to the DCP. ReportStream(Director_ReportStreamServer) error - // Retrieve Directives from the CEPC + // Stream metrics to the DCP. + StreamMetrics(Director_StreamMetricsServer) error + // Retrieve Directives from the DCP Retrieve(*Identity, Director_RetrieveServer) error // Reports the result of a command execution to the cloud ReportCommandResult(context.Context, *CommandResult) (*CommandResultResponse, error) @@ -1264,6 +1445,9 @@ func (*UnimplementedDirectorServer) Report(context.Context, *Snapshot) (*Snapsho func (*UnimplementedDirectorServer) ReportStream(Director_ReportStreamServer) error { return status.Errorf(codes.Unimplemented, "method ReportStream not implemented") } +func (*UnimplementedDirectorServer) StreamMetrics(Director_StreamMetricsServer) error { + return status.Errorf(codes.Unimplemented, "method StreamMetrics not implemented") +} func (*UnimplementedDirectorServer) Retrieve(*Identity, Director_RetrieveServer) error { return status.Errorf(codes.Unimplemented, "method Retrieve not implemented") } @@ -1322,6 +1506,32 @@ func (x *directorReportStreamServer) Recv() (*RawSnapshotChunk, error) { return m, nil } +func _Director_StreamMetrics_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(DirectorServer).StreamMetrics(&directorStreamMetricsServer{stream}) +} + +type Director_StreamMetricsServer interface { + SendAndClose(*StreamMetricsResponse) error + Recv() (*StreamMetricsMessage, error) + grpc.ServerStream +} + +type directorStreamMetricsServer struct { + grpc.ServerStream +} + +func (x *directorStreamMetricsServer) SendAndClose(m *StreamMetricsResponse) error { + return x.ServerStream.SendMsg(m) +} + +func (x *directorStreamMetricsServer) Recv() (*StreamMetricsMessage, error) { + m := new(StreamMetricsMessage) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + func _Director_Retrieve_Handler(srv interface{}, stream grpc.ServerStream) error { m := new(Identity) if err := stream.RecvMsg(m); err != nil { @@ -1401,6 +1611,11 @@ var _Director_serviceDesc = grpc.ServiceDesc{ Handler: _Director_ReportStream_Handler, ClientStreams: true, }, + { + StreamName: "StreamMetrics", + Handler: _Director_StreamMetrics_Handler, + ClientStreams: true, + }, { StreamName: "Retrieve", Handler: _Director_Retrieve_Handler, diff --git a/python/README.md b/python/README.md index 334ad7920f..7ba67fe9da 100644 --- a/python/README.md +++ b/python/README.md @@ -27,12 +27,13 @@ Ambassador comprises several different components: Ambassador uses several TCP ports while running. All but one of them are in the range 8000-8499, and any future assignments for Ambassador ports should come from this range. | Port | Process | Function | -| :--- | :------ | :------- | +| :--- |:--------------------------------------|:-------------------------------------------------------------------------------------------------------------------| | 8001 | `envoy` | Internal stats, logging, etc.; not exposed outside pod | | 8002 | `entrypoint/watcher` | Internal `watt` snapshot access; not exposed outside pod | | 8003 | `entrypoint/ambex` | Internal `ambex` snapshot access; not exposed outside pod | | 8004 | `diagd` | Internal `diagd` access when `AMBASSADOR_FAST_RECONFIGURE` is set; not exposed outside pod | | 8005 | `entrypoint/external_snapshot_server` | Exposes configuration snapshots for integration with other tools, such as the Ambassador Agent | +| 8006 | `entrypoint/agent` | Receives GRPC calls made by the Envoy Metrics Server | | 8080 | `envoy` | Default HTTP service port | | 8443 | `envoy` | Default HTTPS service port | | 8877 | `diagd` | Direct access to diagnostics UI; provided by `busyambassador entrypoint` when `AMBASSADOR_FAST_RECONFIGURE` is set | diff --git a/python/ambassador/envoy/v3/v3bootstrap.py b/python/ambassador/envoy/v3/v3bootstrap.py index 4933a3c8de..e5d098f007 100644 --- a/python/ambassador/envoy/v3/v3bootstrap.py +++ b/python/ambassador/envoy/v3/v3bootstrap.py @@ -1,7 +1,9 @@ from typing import TYPE_CHECKING from typing import cast as typecast +from typing import Tuple, Optional import os +from urllib.parse import urlparse from ...ir.ircluster import IRCluster from ...ir.irlogservice import IRLogService @@ -107,6 +109,57 @@ def __init__(self, config: 'V3Config') -> None: # assert ratelimit.cluster # clusters.append(V3Cluster(config, ratelimit.cluster)) + stats_sinks = [] + + grpcSink = os.environ.get("AMBASSADOR_GRPC_METRICS_SINK") + if grpcSink: + try: + host, port = split_host_port(grpcSink) + valid = True + except ValueError as ex: + config.ir.logger.error("AMBASSADOR_GRPC_METRICS_SINK value %s is invalid: %s" % (grpcSink, ex)) + valid = False + + if valid: + stats_sinks.append({ + 'name': "envoy.metrics_service", + 'typed_config': { + '@type': 'type.googleapis.com/envoy.config.metrics.v3.MetricsServiceConfig', + 'transport_api_version': 'V3', + 'grpc_service': { + 'envoy_grpc': { + 'cluster_name': 'envoy_metrics_service' + } + } + } + }) + clusters.append({ + "name": "envoy_metrics_service", + "type": "strict_dns", + "connect_timeout": "1s", + "http2_protocol_options": {}, + "load_assignment": { + "cluster_name": "envoy_metrics_service", + "endpoints": [ + { + "lb_endpoints": [ + { + "endpoint": { + "address": { + "socket_address": { + "address": host, + "port_value": port, + "protocol": "TCP" + } + } + } + } + ] + } + ] + } + }) + if config.ir.statsd['enabled']: if config.ir.statsd['dogstatsd']: name = 'envoy.stat_sinks.dog_statsd' @@ -122,28 +175,31 @@ def __init__(self, config: 'V3Config') -> None: name = 'envoy.stats_sinks.statsd' typename = 'type.googleapis.com/envoy.config.metrics.v3.StatsdSink' - self['stats_sinks'] = [ - { - 'name': name, - 'typed_config': { - '@type': typename, - 'address': { - 'socket_address': { - 'protocol': 'UDP', - 'address': config.ir.statsd['ip'], - 'port_value': 8125 - } + stats_sinks.append({ + 'name': name, + 'typed_config': { + '@type': typename, + 'address': { + 'socket_address': { + 'protocol': 'UDP', + 'address': config.ir.statsd['ip'], + 'port_value': 8125 } } } - ] + }) self['stats_flush_interval'] = { 'seconds': config.ir.statsd['interval'] } - + self['stats_sinks'] = stats_sinks self['static_resources']['clusters'] = clusters @classmethod def generate(cls, config: 'V3Config') -> None: config.bootstrap = V3Bootstrap(config) + + +def split_host_port(value: str) -> Tuple[Optional[str], int]: + parsed = urlparse("//"+value) + return parsed.hostname, int(parsed.port or 80) diff --git a/python/tests/integration/manifests/ambassador.yaml b/python/tests/integration/manifests/ambassador.yaml index 868a5ff7db..de0e5548bf 100644 --- a/python/tests/integration/manifests/ambassador.yaml +++ b/python/tests/integration/manifests/ambassador.yaml @@ -91,6 +91,8 @@ metadata: spec: containers: - env: + - name: AMBASSADOR_GRPC_METRICS_SINK + value: {self.path.k8s}:8006 - name: HOST_IP valueFrom: fieldRef: