pgv: bazel plumbing for PGV support, some PGV related fixups. (#299)

* Added PGV C++ generation support. This (hopefully temporarily)
  abandons using native proto_library in favor of pgv_cc_proto_library.
  We maintain build support for proto_library for the glorious future in
  which we write a Bazel aspect to run PGV against the native
  proto_library shadow graph.

* Replace min_len with min_bytes on strings, until PGV gets not-empty or
  min_len support for C++.

* Various fixups for places where the PGV plugin objected to
  annotations.

Signed-off-by: Harvey Tuch <htuch@google.com>
pull/301/head
htuch 7 years ago committed by GitHub
parent 65bb3f3717
commit 5cdd72f06c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      api/BUILD
  2. 4
      api/address.proto
  3. 8
      api/base.proto
  4. 2
      api/cds.proto
  5. 6
      api/eds.proto
  6. 30
      api/filter/http/fault.proto
  7. 2
      api/filter/http/health_check.proto
  8. 2
      api/filter/http/lua.proto
  9. 2
      api/filter/http/transcoder.proto
  10. 6
      api/filter/network/http_connection_manager.proto
  11. 2
      api/filter/network/mongo_proxy.proto
  12. 4
      api/filter/network/redis_proxy.proto
  13. 6
      api/filter/network/tcp_proxy.proto
  14. 4
      api/health_check.proto
  15. 2
      api/lds.proto
  16. 11
      api/protocol.proto
  17. 28
      api/rds.proto
  18. 2
      api/sds.proto
  19. 22
      bazel/api_build_system.bzl
  20. 42
      bazel/repositories.bzl
  21. 14
      test/validate/BUILD
  22. 35
      test/validate/pgv_test.cc
  23. 13
      test/validate/test.proto
  24. 2
      tools/protodoc/protodoc.py

@ -98,7 +98,7 @@ api_proto_library(
has_services = 1, has_services = 1,
deps = [ deps = [
":base", ":base",
"@promotheus_metrics_model//:client_model_protos_lib", "@promotheus_metrics_model//:client_model",
], ],
require_py = 0, require_py = 0,
) )

@ -11,7 +11,7 @@ import "validate/validate.proto";
message Pipe { message Pipe {
// Unix Domain Socket path. // Unix Domain Socket path.
string path = 1 [(validate.rules).string.min_len = 1]; string path = 1 [(validate.rules).string.min_bytes = 1];
} }
message SocketAddress { message SocketAddress {
@ -65,7 +65,7 @@ message Address {
// the subnet mask for a `CIDR <https://tools.ietf.org/html/rfc4632>`_ range. // the subnet mask for a `CIDR <https://tools.ietf.org/html/rfc4632>`_ range.
message CidrRange { message CidrRange {
// IPv4 or IPv6 address, e.g. 192.0.0.0 or 2001:db8::. // IPv4 or IPv6 address, e.g. 192.0.0.0 or 2001:db8::.
string address_prefix = 1 [(validate.rules).string.min_len = 1]; string address_prefix = 1 [(validate.rules).string.min_bytes = 1];
// Length of prefix, e.g. 0, 32. // Length of prefix, e.g. 0, 32.
google.protobuf.UInt32Value prefix_len = 2 [(validate.rules).uint32.lte = 128]; google.protobuf.UInt32Value prefix_len = 2 [(validate.rules).uint32.lte = 128];
} }

@ -35,9 +35,9 @@ message Locality {
// configuration for serving. // configuration for serving.
message Node { message Node {
// An opaque node identifier for the Envoy node. // An opaque node identifier for the Envoy node.
string id = 1 [(validate.rules).string.min_len = 1]; string id = 1 [(validate.rules).string.min_bytes = 1];
// The cluster that the Envoy node belongs to. // The cluster that the Envoy node belongs to.
string cluster = 2 [(validate.rules).string.min_len = 1]; string cluster = 2 [(validate.rules).string.min_bytes = 1];
// Opaque metadata extending the node identifier. Envoy will pass this // Opaque metadata extending the node identifier. Envoy will pass this
// directly to the management server. // directly to the management server.
google.protobuf.Struct metadata = 3; google.protobuf.Struct metadata = 3;
@ -84,7 +84,7 @@ message RuntimeUInt32 {
uint32 default_value = 2; uint32 default_value = 2;
// Runtime key to get value for comparison. This value is used if defined. // Runtime key to get value for comparison. This value is used if defined.
string runtime_key = 3 [(validate.rules).string.min_len = 1]; string runtime_key = 3 [(validate.rules).string.min_bytes = 1];
} }
// Envoy supports :ref:`upstream priority routing // Envoy supports :ref:`upstream priority routing
@ -189,7 +189,7 @@ message ConfigSource {
message TransportSocket { message TransportSocket {
// The name of the transport socket to instantiate. The name must match a supported transport // The name of the transport socket to instantiate. The name must match a supported transport
// socket implementation. // socket implementation.
string name = 1 [(validate.rules).string.min_len = 1]; string name = 1 [(validate.rules).string.min_bytes = 1];
// Implementation specific configuration which depends on the implementation being instantiated. // Implementation specific configuration which depends on the implementation being instantiated.
// See the supported transport socket implementations for further documentation. // See the supported transport socket implementations for further documentation.

@ -84,7 +84,7 @@ message Cluster {
// By default, the maximum length of a cluster name is limited to 60 // By default, the maximum length of a cluster name is limited to 60
// characters. This limit can be increased by setting the // characters. This limit can be increased by setting the
// :option:`--max-obj-name-len` command line argument to the desired value. // :option:`--max-obj-name-len` command line argument to the desired value.
string name = 1 [(validate.rules).string.min_len = 1]; string name = 1 [(validate.rules).string.min_bytes = 1];
// Refer to :ref:`service discovery type <arch_overview_service_discovery_types>` // Refer to :ref:`service discovery type <arch_overview_service_discovery_types>`
// for an explanation on each type. // for an explanation on each type.

@ -201,7 +201,7 @@ message UpstreamLocalityStats {
// :ref:`LoadStatsRequest<envoy_api_msg_LoadStatsRequest>` // :ref:`LoadStatsRequest<envoy_api_msg_LoadStatsRequest>`
message ClusterStats { message ClusterStats {
// The name of the cluster. // The name of the cluster.
string cluster_name = 1 [(validate.rules).string.min_len = 1]; string cluster_name = 1 [(validate.rules).string.min_bytes = 1];
// Need at least one. // Need at least one.
repeated UpstreamLocalityStats upstream_locality_stats = 2 [(validate.rules).repeated.min_items = 1]; repeated UpstreamLocalityStats upstream_locality_stats = 2 [(validate.rules).repeated.min_items = 1];
@ -243,7 +243,7 @@ message ClusterLoadAssignment {
// <envoy_api_field_Cluster.EdsClusterConfig.service_name>` value if specified // <envoy_api_field_Cluster.EdsClusterConfig.service_name>` value if specified
// in the cluster :ref:`EdsClusterConfig // in the cluster :ref:`EdsClusterConfig
// <envoy_api_msg_Cluster.EdsClusterConfig>`. // <envoy_api_msg_Cluster.EdsClusterConfig>`.
string cluster_name = 1 [(validate.rules).string.min_len = 1]; string cluster_name = 1 [(validate.rules).string.min_bytes = 1];
// List of endpoints to load balance to. // List of endpoints to load balance to.
repeated LocalityLbEndpoints endpoints = 2; repeated LocalityLbEndpoints endpoints = 2;
@ -255,7 +255,7 @@ message ClusterLoadAssignment {
// recover from an outage or should they be unable to autoscale and hence // recover from an outage or should they be unable to autoscale and hence
// overall incoming traffic volume need to be trimmed to protect them. // overall incoming traffic volume need to be trimmed to protect them.
// [#v2-api-diff: This is known as maintenance mode in v1.] // [#v2-api-diff: This is known as maintenance mode in v1.]
double drop_overload = 1 [(validate.rules).fixed32 = {gte:0, lte: 100}]; double drop_overload = 1 [(validate.rules).double = {gte:0, lte: 100}];
} }
// Load balancing policy settings. // Load balancing policy settings.

@ -41,17 +41,21 @@ message HTTPFault {
string upstream_cluster = 3; string upstream_cluster = 3;
// Specifies a set of headers that the filter should match on. The fault // Specifies a set of headers that the filter should match on. The fault
// injection filter can be applied selectively to requests that match a set of headers specified in // injection filter can be applied selectively to requests that match a set of
// the fault filter config. The chances of actual fault injection further depend on the value of // headers specified in the fault filter config. The chances of actual fault
// the :ref:`percent <envoy_api_field_filter.http.FaultAbort.percent>` field. The filter will check the request's headers // injection further depend on the value of the :ref:`percent
// against all the specified headers in the filter config. A match will happen if all the headers in // <envoy_api_field_filter.http.FaultAbort.percent>` field. The filter will
// the config are present in the request with the same values (or based on presence if the *value* // check the request's headers against all the specified headers in the filter
// field is not in the config). // config. A match will happen if all the headers in the config are present in
repeated HeaderMatcher headers = 4 [(validate.rules).repeated.unique = true]; // the request with the same values (or based on presence if the *value* field
// is not in the config).
// Faults are injected for the specified list of downstream hosts. If this setting is repeated HeaderMatcher headers = 4;
// not set, faults are injected for all downstream nodes. Downstream node name is taken from
// :ref:`the HTTP x-envoy-downstream-service-node <config_http_conn_man_headers_downstream-service-node>` // Faults are injected for the specified list of downstream hosts. If this
// header and compared against downstream_nodes list. // setting is not set, faults are injected for all downstream nodes.
repeated string downstream_nodes = 5 [(validate.rules).repeated.unique = true]; // Downstream node name is taken from :ref:`the HTTP
// x-envoy-downstream-service-node
// <config_http_conn_man_headers_downstream-service-node>` header and compared
// against downstream_nodes list.
repeated string downstream_nodes = 5;
} }

@ -16,7 +16,7 @@ message HealthCheck {
// Specifies the incoming HTTP endpoint that should be considered the // Specifies the incoming HTTP endpoint that should be considered the
// health check endpoint. For example */healthcheck*. // health check endpoint. For example */healthcheck*.
string endpoint = 2 [(validate.rules).string.min_len = 1]; string endpoint = 2 [(validate.rules).string.min_bytes = 1];
// If operating in pass through mode, the amount of time in milliseconds // If operating in pass through mode, the amount of time in milliseconds
// that the filter should cache the upstream response. // that the filter should cache the upstream response.

@ -12,5 +12,5 @@ message Lua {
// further loads code from disk if desired. Note that if JSON configuration is used, the code must // further loads code from disk if desired. Note that if JSON configuration is used, the code must
// be properly escaped. YAML configuration may be easier to read since YAML supports multi-line // be properly escaped. YAML configuration may be easier to read since YAML supports multi-line
// strings so complex scripts can be easily expressed inline in the configuration. // strings so complex scripts can be easily expressed inline in the configuration.
string inline_code = 1 [(validate.rules).string.min_len = 1]; string inline_code = 1 [(validate.rules).string.min_bytes = 1];
} }

@ -29,7 +29,7 @@ message GrpcJsonTranscoder {
// --descriptor_set_out=proto.pb test/proto/bookstore.proto // --descriptor_set_out=proto.pb test/proto/bookstore.proto
// //
// If you have more than one proto source files, you can pass all of them in one command. // If you have more than one proto source files, you can pass all of them in one command.
string proto_descriptor = 1 [(validate.rules).string.min_len = 1]; string proto_descriptor = 1 [(validate.rules).string.min_bytes = 1];
// A list of strings that supplies the service names that the // A list of strings that supplies the service names that the
// transcoder will translate. If the service name doesn't exist in ``proto_descriptor``, Envoy // transcoder will translate. If the service name doesn't exist in ``proto_descriptor``, Envoy

@ -25,7 +25,7 @@ message Rds {
// API. This allows an Envoy configuration with multiple HTTP listeners (and // API. This allows an Envoy configuration with multiple HTTP listeners (and
// associated HTTP connection manager filters) to use different route // associated HTTP connection manager filters) to use different route
// configurations. // configurations.
string route_config_name = 2 [(validate.rules).string.min_len = 1]; string route_config_name = 2 [(validate.rules).string.min_bytes = 1];
} }
message HttpFilter { message HttpFilter {
@ -44,7 +44,7 @@ message HttpFilter {
// * :ref:`envoy.lua <config_http_filters_lua>` // * :ref:`envoy.lua <config_http_filters_lua>`
// * :ref:`envoy.rate_limit <config_http_filters_rate_limit>` // * :ref:`envoy.rate_limit <config_http_filters_rate_limit>`
// * :ref:`envoy.router <config_http_filters_router>` // * :ref:`envoy.router <config_http_filters_router>`
string name = 1 [(validate.rules).string.min_len = 1]; string name = 1 [(validate.rules).string.min_bytes = 1];
// Filter specific configuration which depends on the filter being // Filter specific configuration which depends on the filter being
// instantiated. See the supported filters for further documentation. // instantiated. See the supported filters for further documentation.
@ -85,7 +85,7 @@ message HttpConnectionManager {
// The human readable prefix to use when emitting statistics for the // The human readable prefix to use when emitting statistics for the
// connection manager. See the :ref:`statistics documentation <config_http_conn_man_stats>` for // connection manager. See the :ref:`statistics documentation <config_http_conn_man_stats>` for
// more information. // more information.
string stat_prefix = 2 [(validate.rules).string.min_len = 1]; string stat_prefix = 2 [(validate.rules).string.min_bytes = 1];
oneof route_specifier { oneof route_specifier {
option (validate.required) = true; option (validate.required) = true;

@ -12,7 +12,7 @@ import "validate/validate.proto";
message MongoProxy { message MongoProxy {
// The human readable prefix to use when emitting :ref:`statistics // The human readable prefix to use when emitting :ref:`statistics
// <config_network_filters_mongo_proxy_stats>`. // <config_network_filters_mongo_proxy_stats>`.
string stat_prefix = 1 [(validate.rules).string.min_len = 1]; string stat_prefix = 1 [(validate.rules).string.min_bytes = 1];
// The optional path to use for writing Mongo access logs. If not access log // The optional path to use for writing Mongo access logs. If not access log
// path is specified no access logs will be written. Note that access log is // path is specified no access logs will be written. Note that access log is

@ -11,12 +11,12 @@ import "validate/validate.proto";
message RedisProxy { message RedisProxy {
// The prefix to use when emitting :ref:`statistics <config_network_filters_redis_proxy_stats>`. // The prefix to use when emitting :ref:`statistics <config_network_filters_redis_proxy_stats>`.
string stat_prefix = 1 [(validate.rules).string.min_len = 1]; string stat_prefix = 1 [(validate.rules).string.min_bytes = 1];
// Name of cluster from cluster manager. See the :ref:`configuration section // Name of cluster from cluster manager. See the :ref:`configuration section
// <arch_overview_redis_configuration>` of the architecture overview for recommendations on // <arch_overview_redis_configuration>` of the architecture overview for recommendations on
// configuring the backing cluster. // configuring the backing cluster.
string cluster = 2 [(validate.rules).string.min_len = 1]; string cluster = 2 [(validate.rules).string.min_bytes = 1];
// Redis connection pool settings. // Redis connection pool settings.
message ConnPoolSettings { message ConnPoolSettings {

@ -18,10 +18,10 @@ import "validate/validate.proto";
message TcpProxy { message TcpProxy {
// The prefix to use when emitting :ref:`statistics // The prefix to use when emitting :ref:`statistics
// <config_network_filters_tcp_proxy_stats>`. // <config_network_filters_tcp_proxy_stats>`.
string stat_prefix = 1 [(validate.rules).string.min_len = 1]; string stat_prefix = 1 [(validate.rules).string.min_bytes = 1];
// The upstream cluster to connect to. // The upstream cluster to connect to.
string cluster = 2 [(validate.rules).string.min_len = 1]; string cluster = 2 [(validate.rules).string.min_bytes = 1];
// [#not-implemented-hide:] The idle timeout for connections managed by the TCP proxy // [#not-implemented-hide:] The idle timeout for connections managed by the TCP proxy
// filter. The idle timeout is defined as the period in which there is no // filter. The idle timeout is defined as the period in which there is no
@ -53,7 +53,7 @@ message TcpProxy {
message TCPRoute { message TCPRoute {
// The cluster to connect to when a the downstream network connection // The cluster to connect to when a the downstream network connection
// matches the specified criteria. // matches the specified criteria.
string cluster = 1 [(validate.rules).string.min_len = 1]; string cluster = 1 [(validate.rules).string.min_bytes = 1];
// An optional list of IP address subnets in the form // An optional list of IP address subnets in the form
// ip_address/xx. The criteria is satisfied if the destination IP // ip_address/xx. The criteria is satisfied if the destination IP

@ -46,7 +46,7 @@ message HealthCheck {
option (validate.required) = true; option (validate.required) = true;
// Hex encoded payload. E.g., "000000FF". // Hex encoded payload. E.g., "000000FF".
string text = 1 [(validate.rules).string.min_len = 1]; string text = 1 [(validate.rules).string.min_bytes = 1];
// [#not-implemented-hide:] Binary payload. // [#not-implemented-hide:] Binary payload.
bytes binary = 2; bytes binary = 2;
@ -61,7 +61,7 @@ message HealthCheck {
// Specifies the HTTP path that will be requested during health checking. For example // Specifies the HTTP path that will be requested during health checking. For example
// */healthcheck*. // */healthcheck*.
string path = 2 [(validate.rules).string.min_len = 1]; string path = 2 [(validate.rules).string.min_bytes = 1];
// [#not-implemented-hide:] HTTP specific payload. // [#not-implemented-hide:] HTTP specific payload.
Payload send = 3; Payload send = 3;

@ -44,7 +44,7 @@ message Filter {
// * :ref:`envoy.mongo_proxy <config_network_filters_mongo_proxy>` // * :ref:`envoy.mongo_proxy <config_network_filters_mongo_proxy>`
// * :ref:`envoy.redis_proxy <config_network_filters_redis_proxy>` // * :ref:`envoy.redis_proxy <config_network_filters_redis_proxy>`
// * :ref:`envoy.tcp_proxy <config_network_filters_tcp_proxy>` // * :ref:`envoy.tcp_proxy <config_network_filters_tcp_proxy>`
string name = 1 [(validate.rules).string.min_len = 1]; string name = 1 [(validate.rules).string.min_bytes = 1];
// Filter specific configuration which depends on the filter being // Filter specific configuration which depends on the filter being
// instantiated. See the supported filters for further documentation. // instantiated. See the supported filters for further documentation.

@ -6,6 +6,8 @@ package envoy.api.v2;
import "google/protobuf/wrappers.proto"; import "google/protobuf/wrappers.proto";
import "validate/validate.proto";
// [#protodoc-title: Protocol options] // [#protodoc-title: Protocol options]
// [#not-implemented-hide:] // [#not-implemented-hide:]
@ -30,7 +32,8 @@ message Http2ProtocolOptions {
// `Maximum concurrent streams <http://httpwg.org/specs/rfc7540.html#rfc.section.5.1.2>`_ // `Maximum concurrent streams <http://httpwg.org/specs/rfc7540.html#rfc.section.5.1.2>`_
// allowed for peer on one HTTP/2 connection. Valid values range from 1 to 2147483647 (2^31 - 1) // allowed for peer on one HTTP/2 connection. Valid values range from 1 to 2147483647 (2^31 - 1)
// and defaults to 2147483647. // and defaults to 2147483647.
google.protobuf.UInt32Value max_concurrent_streams = 2; google.protobuf.UInt32Value max_concurrent_streams = 2
[(validate.rules).uint32 = {gte: 1, lte: 2147483647}];
// `Initial stream-level flow-control window // `Initial stream-level flow-control window
// <http://httpwg.org/specs/rfc7540.html#rfc.section.6.9.2>`_ size. Valid values range from 65535 // <http://httpwg.org/specs/rfc7540.html#rfc.section.6.9.2>`_ size. Valid values range from 65535
@ -43,11 +46,13 @@ message Http2ProtocolOptions {
// This field also acts as a soft limit on the number of bytes Envoy will buffer per-stream in the // This field also acts as a soft limit on the number of bytes Envoy will buffer per-stream in the
// HTTP/2 codec buffers. Once the buffer reaches this pointer, watermark callbacks will fire to // HTTP/2 codec buffers. Once the buffer reaches this pointer, watermark callbacks will fire to
// stop the flow of data to the codec buffers. // stop the flow of data to the codec buffers.
google.protobuf.UInt32Value initial_stream_window_size = 3; google.protobuf.UInt32Value initial_stream_window_size = 3
[(validate.rules).uint32 = {gte: 65535, lte: 2147483647}];
// Similar to *initial_stream_window_size*, but for connection-level flow-control // Similar to *initial_stream_window_size*, but for connection-level flow-control
// window. Currently, this has the same minimum/maximum/default as *initial_stream_window_size*. // window. Currently, this has the same minimum/maximum/default as *initial_stream_window_size*.
google.protobuf.UInt32Value initial_connection_window_size = 4; google.protobuf.UInt32Value initial_connection_window_size = 4
[(validate.rules).uint32 = {gte: 65535, lte: 2147483647}];
} }
// [#not-implemented-hide:] // [#not-implemented-hide:]

@ -43,7 +43,7 @@ message WeightedCluster {
message ClusterWeight { message ClusterWeight {
// Name of the upstream cluster. The cluster must exist in the // Name of the upstream cluster. The cluster must exist in the
// :ref:`cluster manager configuration <config_cluster_manager>`. // :ref:`cluster manager configuration <config_cluster_manager>`.
string name = 1 [(validate.rules).string.min_len = 1]; string name = 1 [(validate.rules).string.min_bytes = 1];
// An integer between 0-100. When a request matches the route, the choice of // An integer between 0-100. When a request matches the route, the choice of
// an upstream cluster is determined by its weight. The sum of weights // an upstream cluster is determined by its weight. The sum of weights
@ -242,7 +242,7 @@ message RouteAction {
message RequestMirrorPolicy { message RequestMirrorPolicy {
// Specifies the cluster that requests will be mirrored to. The cluster must // Specifies the cluster that requests will be mirrored to. The cluster must
// exist in the cluster manager configuration. // exist in the cluster manager configuration.
string cluster = 1 [(validate.rules).string.min_len = 1]; string cluster = 1 [(validate.rules).string.min_bytes = 1];
// If not specified, all requests to the target cluster will be mirrored. If // If not specified, all requests to the target cluster will be mirrored. If
// specified, Envoy will lookup the runtime key to get the % of requests to // specified, Envoy will lookup the runtime key to get the % of requests to
@ -291,7 +291,7 @@ message RouteAction {
message Header { message Header {
// The name of the request header that will be used to obtain the hash // The name of the request header that will be used to obtain the hash
// key. If the request header is not present, no hash will be produced. // key. If the request header is not present, no hash will be produced.
string header_name = 1 [(validate.rules).string.min_len = 1]; string header_name = 1 [(validate.rules).string.min_bytes = 1];
} }
// Envoy supports two types of cookie affinity: // Envoy supports two types of cookie affinity:
@ -312,7 +312,7 @@ message RouteAction {
// The name of the cookie that will be used to obtain the hash key. If the // The name of the cookie that will be used to obtain the hash key. If the
// cookie is not present and ttl below is not set, no hash will be // cookie is not present and ttl below is not set, no hash will be
// produced. // produced.
string name = 1 [(validate.rules).string.min_len = 1]; string name = 1 [(validate.rules).string.min_bytes = 1];
// If specified, a cookie with the TTL will be generated if the cookie is // If specified, a cookie with the TTL will be generated if the cookie is
// not present. // not present.
@ -410,7 +410,7 @@ message Decorator {
// For ingress (inbound) requests, or egress (outbound) responses, this value may be overridden // For ingress (inbound) requests, or egress (outbound) responses, this value may be overridden
// by the :ref:`x-envoy-decorator-operation // by the :ref:`x-envoy-decorator-operation
// <config_http_filters_router_x-envoy-decorator-operation>` header. // <config_http_filters_router_x-envoy-decorator-operation>` header.
string operation = 1 [(validate.rules).string.min_len = 1]; string operation = 1 [(validate.rules).string.min_bytes = 1];
} }
// A route is both a specification of how to match a request as well as an indication of what to do // A route is both a specification of how to match a request as well as an indication of what to do
@ -476,12 +476,12 @@ message VirtualCluster {
// * The regex */rides/\d+* matches the path */rides/0* // * The regex */rides/\d+* matches the path */rides/0*
// * The regex */rides/\d+* matches the path */rides/123* // * The regex */rides/\d+* matches the path */rides/123*
// * The regex */rides/\d+* does not match the path */rides/123/456* // * The regex */rides/\d+* does not match the path */rides/123/456*
string pattern = 1 [(validate.rules).string.min_len = 1]; string pattern = 1 [(validate.rules).string.min_bytes = 1];
// Specifies the name of the virtual cluster. The virtual cluster name as well // Specifies the name of the virtual cluster. The virtual cluster name as well
// as the virtual host name are used when emitting statistics. The statistics are emitted by the // as the virtual host name are used when emitting statistics. The statistics are emitted by the
// router filter and are documented :ref:`here <config_http_filters_router_stats>`. // router filter and are documented :ref:`here <config_http_filters_router_stats>`.
string name = 2 [(validate.rules).string.min_len = 1]; string name = 2 [(validate.rules).string.min_bytes = 1];
// Optionally specifies the HTTP method to match on. For example GET, PUT, // Optionally specifies the HTTP method to match on. For example GET, PUT,
// etc. // etc.
@ -540,10 +540,10 @@ message RateLimit {
// The header name to be queried from the request headers. The headers // The header name to be queried from the request headers. The headers
// value is used to populate the value of the descriptor entry for the // value is used to populate the value of the descriptor entry for the
// descriptor_key. // descriptor_key.
string header_name = 1 [(validate.rules).string.min_len = 1]; string header_name = 1 [(validate.rules).string.min_bytes = 1];
// The key to use in the descriptor entry. // The key to use in the descriptor entry.
string descriptor_key = 2 [(validate.rules).string.min_len = 1]; string descriptor_key = 2 [(validate.rules).string.min_bytes = 1];
} }
// The following descriptor entry is appended to the descriptor and is populated using the // The following descriptor entry is appended to the descriptor and is populated using the
@ -561,7 +561,7 @@ message RateLimit {
// ("generic_key", "<descriptor_value>") // ("generic_key", "<descriptor_value>")
message GenericKey { message GenericKey {
// The value to use in the descriptor entry. // The value to use in the descriptor entry.
string descriptor_value = 1 [(validate.rules).string.min_len = 1]; string descriptor_value = 1 [(validate.rules).string.min_bytes = 1];
} }
// The following descriptor entry is appended to the descriptor: // The following descriptor entry is appended to the descriptor:
@ -571,7 +571,7 @@ message RateLimit {
// ("header_match", "<descriptor_value>") // ("header_match", "<descriptor_value>")
message HeaderValueMatch { message HeaderValueMatch {
// The value to use in the descriptor entry. // The value to use in the descriptor entry.
string descriptor_value = 1 [(validate.rules).string.min_len = 1]; string descriptor_value = 1 [(validate.rules).string.min_bytes = 1];
// If set to true, the action will append a descriptor entry when the // If set to true, the action will append a descriptor entry when the
// request matches the headers. If set to false, the action will append a // request matches the headers. If set to false, the action will append a
@ -616,7 +616,7 @@ message RateLimit {
// cannot append a descriptor entry, no descriptor is generated for the // cannot append a descriptor entry, no descriptor is generated for the
// configuration. See :ref:`composing actions // configuration. See :ref:`composing actions
// <config_http_filters_rate_limit_composing_actions>` for additional documentation. // <config_http_filters_rate_limit_composing_actions>` for additional documentation.
repeated Action actions = 3 [(validate.rules).string.min_len = 1]; repeated Action actions = 3 [(validate.rules).repeated.min_items = 1];
} }
// .. attention:: // .. attention::
@ -637,7 +637,7 @@ message RateLimit {
// } // }
message HeaderMatcher { message HeaderMatcher {
// Specifies the name of the header in the request. // Specifies the name of the header in the request.
string name = 1 [(validate.rules).string.min_len = 1]; string name = 1 [(validate.rules).string.min_bytes = 1];
// Specifies the value of the header. If the value is absent a request that // Specifies the value of the header. If the value is absent a request that
// has the name header will match, regardless of the headers value. // has the name header will match, regardless of the headers value.
@ -665,7 +665,7 @@ message HeaderMatcher {
message VirtualHost { message VirtualHost {
// The logical name of the virtual host. This is used when emitting certain // The logical name of the virtual host. This is used when emitting certain
// statistics but is not relevant for routing. // statistics but is not relevant for routing.
string name = 1 [(validate.rules).string.min_len = 1]; string name = 1 [(validate.rules).string.min_bytes = 1];
// A list of domains (host/authority header) that will be matched to this // A list of domains (host/authority header) that will be matched to this
// virtual host. Wildcard hosts are supported in the form of *.foo.com or // virtual host. Wildcard hosts are supported in the form of *.foo.com or

@ -31,7 +31,7 @@ message DataSource {
option (validate.required) = true; option (validate.required) = true;
// Local filesystem data source. // Local filesystem data source.
string filename = 1 [(validate.rules).string.min_len = 1]; string filename = 1 [(validate.rules).string.min_bytes = 1];
// [#not-implemented-hide:] // [#not-implemented-hide:]
bytes inline = 2; bytes inline = 2;

@ -1,4 +1,5 @@
load("@com_google_protobuf//:protobuf.bzl", "py_proto_library") load("@com_google_protobuf//:protobuf.bzl", "py_proto_library")
load("@com_lyft_protoc_gen_validate//bazel:pgv_proto_library.bzl", "pgv_cc_proto_library")
def _CcSuffix(d): def _CcSuffix(d):
return d + "_cc" return d + "_cc"
@ -27,6 +28,12 @@ def api_py_proto_library(name, srcs = [], deps = [], has_services = 0):
# TODO(htuch): has_services is currently ignored but will in future support # TODO(htuch): has_services is currently ignored but will in future support
# gRPC stub generation. # gRPC stub generation.
def api_proto_library(name, srcs = [], deps = [], has_services = 0, require_py = 1): def api_proto_library(name, srcs = [], deps = [], has_services = 0, require_py = 1):
# This is now vestigial, since there are no direct consumers in
# data-plane-api. However, we want to maintain native proto_library support
# in the proto graph to (1) support future C++ use of native rules with
# cc_proto_library (or some Bazel aspect that works on proto_library) when
# it can play well with the PGV plugin and (2) other language support that
# can make use of native proto_library.
native.proto_library( native.proto_library(
name = name, name = name,
srcs = srcs, srcs = srcs,
@ -37,14 +44,23 @@ def api_proto_library(name, srcs = [], deps = [], has_services = 0, require_py =
"@com_google_protobuf//:struct_proto", "@com_google_protobuf//:struct_proto",
"@com_google_protobuf//:timestamp_proto", "@com_google_protobuf//:timestamp_proto",
"@com_google_protobuf//:wrappers_proto", "@com_google_protobuf//:wrappers_proto",
"@googleapis//:http_api_protos_lib", "@googleapis//:http_api_protos_proto",
"@com_lyft_protoc_gen_validate//validate:validate_proto", "@com_lyft_protoc_gen_validate//validate:validate_proto",
], ],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
native.cc_proto_library( # Under the hood, this is just an extension of the Protobuf library's
# bespoke cc_proto_library. It doesn't consume proto_library as a proto
# provider. Hopefully one day we can move to a model where this target and
# the proto_library above are aligned.
pgv_cc_proto_library(
name = _CcSuffix(name), name = _CcSuffix(name),
deps = [name], srcs = srcs,
deps = [_CcSuffix(d) for d in deps],
external_deps = [
"@com_google_protobuf//:cc_wkt_protos",
"@googleapis//:http_api_protos",
],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
if (require_py == 1): if (require_py == 1):

@ -1,22 +1,20 @@
GOOGLEAPIS_SHA = "5c6df0cd18c6a429eab739fb711c27f6e1393366" # May 14, 2017 GOOGLEAPIS_SHA = "5c6df0cd18c6a429eab739fb711c27f6e1393366" # May 14, 2017
PROMETHEUS_SHA = "6f3806018612930941127f2a7c6c453ba2c527d2" # Nov 02, 2017 PROMETHEUS_SHA = "6f3806018612930941127f2a7c6c453ba2c527d2" # Nov 02, 2017
PGV_GIT_SHA = "f3332cbd75bb28f711377dfb84761ef0d52eca0f" PGV_GIT_SHA = "af35f0b0d2cee1178f77329d30252e07047918c3"
PGV_TAR_SHA = "039ffa842eb62495b6aca305a4eb3d6dc3ac1dd056e228fba5e720161ddfb9c1"
def api_dependencies(): def api_dependencies():
native.http_archive( native.git_repository(
name = "com_lyft_protoc_gen_validate", name = "com_lyft_protoc_gen_validate",
strip_prefix = "protoc-gen-validate-" + PGV_GIT_SHA, remote = "https://github.com/lyft/protoc-gen-validate.git",
sha256 = PGV_TAR_SHA, commit = PGV_GIT_SHA,
url = "https://github.com/lyft/protoc-gen-validate/archive/" + PGV_GIT_SHA + ".tar.gz",
) )
native.new_http_archive( native.new_http_archive(
name = "googleapis", name = "googleapis",
strip_prefix = "googleapis-" + GOOGLEAPIS_SHA, strip_prefix = "googleapis-" + GOOGLEAPIS_SHA,
url = "https://github.com/googleapis/googleapis/archive/" + GOOGLEAPIS_SHA + ".tar.gz", url = "https://github.com/googleapis/googleapis/archive/" + GOOGLEAPIS_SHA + ".tar.gz",
build_file_content = """ build_file_content = """
load("@com_google_protobuf//:protobuf.bzl", "py_proto_library") load("@com_google_protobuf//:protobuf.bzl", "cc_proto_library", "py_proto_library")
filegroup( filegroup(
name = "http_api_protos_src", name = "http_api_protos_src",
@ -28,7 +26,7 @@ filegroup(
) )
proto_library( proto_library(
name = "http_api_protos_lib", name = "http_api_protos_proto",
srcs = [":http_api_protos_src"], srcs = [":http_api_protos_src"],
deps = ["@com_google_protobuf//:descriptor_proto"], deps = ["@com_google_protobuf//:descriptor_proto"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
@ -36,7 +34,13 @@ proto_library(
cc_proto_library( cc_proto_library(
name = "http_api_protos", name = "http_api_protos",
deps = [":http_api_protos_lib"], srcs = [
"google/api/annotations.proto",
"google/api/http.proto",
],
default_runtime = "@com_google_protobuf//:protobuf",
protoc = "@com_google_protobuf//:protoc",
deps = ["@com_google_protobuf//:cc_wkt_protos"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
@ -60,25 +64,13 @@ py_proto_library(
strip_prefix = "client_model-" + PROMETHEUS_SHA, strip_prefix = "client_model-" + PROMETHEUS_SHA,
url = "https://github.com/prometheus/client_model/archive/" + PROMETHEUS_SHA + ".tar.gz", url = "https://github.com/prometheus/client_model/archive/" + PROMETHEUS_SHA + ".tar.gz",
build_file_content = """ build_file_content = """
load("@envoy_api//bazel:api_build_system.bzl", "api_proto_library")
filegroup( api_proto_library(
name = "client_model_protos_src", name = "client_model",
srcs = [ srcs = [
"metrics.proto", "metrics.proto",
], ],
visibility = ["//visibility:public"],
)
proto_library(
name = "client_model_protos_lib",
srcs = [":client_model_protos_src"],
visibility = ["//visibility:public"],
)
cc_proto_library(
name = "client_model_protos",
deps = [":client_model_protos_lib"],
visibility = ["//visibility:public"],
) )
""", """,
) )

@ -0,0 +1,14 @@
load("//bazel:api_build_system.bzl", "api_cc_test", "api_proto_library")
licenses(["notice"]) # Apache 2
api_proto_library(
name = "test",
srcs = ["test.proto"],
)
api_cc_test(
name = "pgv_test",
srcs = ["pgv_test.cc"],
proto_deps = [":test"],
)

@ -0,0 +1,35 @@
#include <iostream>
#include <cstdlib>
#include "test/validate/test.pb.validate.h"
// Basic protoc-gen-validate C++ validation header inclusion and Validate calls
// from data-plane-api.
// TODO(htuch): Switch to using real data-plane-api protos once we can support
// the required field types.
int main(int argc, char *argv[]) {
{
test::validate::Foo empty;
std::string err;
if (Validate(empty, &err)) {
std::cout << "Unexpected successful validation of empty proto."
<< std::endl;
exit(EXIT_FAILURE);
}
}
{
test::validate::Foo non_empty;
non_empty.mutable_baz();
std::string err;
if (!Validate(non_empty, &err)) {
std::cout << "Unexpected failed validation of empty proto: " << err
<< std::endl;
exit(EXIT_FAILURE);
}
}
exit(EXIT_SUCCESS);
}

@ -0,0 +1,13 @@
syntax = "proto3";
package test.validate;
import "validate/validate.proto";
message Bar {
uint32 xyz = 1;
}
message Foo {
Bar baz = 1 [(.validate.rules).message.required = true];
}

@ -505,7 +505,7 @@ def FormatFieldAsDefinitionListItem(outer_type_context, type_context, field):
if field.options.HasExtension(validate_pb2.rules): if field.options.HasExtension(validate_pb2.rules):
rule = field.options.Extensions[validate_pb2.rules] rule = field.options.Extensions[validate_pb2.rules]
if ((rule.HasField('message') and rule.message.required) or if ((rule.HasField('message') and rule.message.required) or
(rule.HasField('string') and rule.string.min_len > 0) or (rule.HasField('string') and rule.string.min_bytes > 0) or
(rule.HasField('repeated') and rule.repeated.min_items > 0)): (rule.HasField('repeated') and rule.repeated.min_items > 0)):
annotations.append('*REQUIRED*') annotations.append('*REQUIRED*')
leading_comment, comment_annotations = type_context.LeadingCommentPathLookup() leading_comment, comment_annotations = type_context.LeadingCommentPathLookup()

Loading…
Cancel
Save