diff --git a/bazel/cc_grpc_library.bzl b/bazel/cc_grpc_library.bzl index 9c31f0c1e2e..55ea11cd53f 100644 --- a/bazel/cc_grpc_library.bzl +++ b/bazel/cc_grpc_library.bzl @@ -74,7 +74,8 @@ def cc_grpc_library( cc_proto_target = name if proto_only else "_" + name + "_cc_proto" proto_deps = ["_" + dep + "_only" for dep in deps if dep.find(":") == -1] - proto_deps += [dep.split(":")[0] + ":" + "_" + dep.split(":")[1] + "_only" for dep in deps if dep.find(":") != -1] + proto_deps += [dep.split(":")[0] + ":" + "_" + dep.split(":")[1] + "_only" for dep in deps if dep.find(":") != -1 and dep.find("com_google_googleapis") == -1] + proto_deps += [dep for dep in deps if dep.find("com_google_googleapis") != -1] if well_known_protos: proto_deps += well_known_proto_libs() proto_library( diff --git a/src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc index 604c5a8d0ba..40f84d4c155 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc @@ -334,6 +334,10 @@ void EventEngineClientChannelDNSResolver::EventEngineDNSRequestWrapper:: result = OnResolvedLocked(); return; } + if (srv_records->empty()) { + result = OnResolvedLocked(); + return; + } // Do a subsequent hostname query since SRV records were returned for (auto& srv_record : *srv_records) { GRPC_EVENT_ENGINE_RESOLVER_TRACE( @@ -496,6 +500,11 @@ absl::optional EventEngineClientChannelDNSResolver:: absl::Status status = errors_.status( absl::StatusCode::kUnavailable, absl::StrCat("errors resolving ", resolver_->name_to_resolve())); + if (status.ok()) { + // If no errors were returned, but the results are empty, we still need to + // return an error. Validation errors may be empty. + status = absl::UnavailableError("No results from DNS queries"); + } GRPC_EVENT_ENGINE_RESOLVER_TRACE("%s", status.message().data()); result.addresses = status; result.service_config = status; diff --git a/src/proto/grpc/service_config/BUILD b/src/proto/grpc/service_config/BUILD new file mode 100644 index 00000000000..4fc9f33325b --- /dev/null +++ b/src/proto/grpc/service_config/BUILD @@ -0,0 +1,46 @@ +# Copyright 2023 gRPC authors. +# +# 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. + +load("@rules_proto//proto:defs.bzl", "proto_library") +load("//bazel:grpc_build_system.bzl", "grpc_package", "grpc_proto_library") + +licenses(["notice"]) + +grpc_package( + name = "src/proto/grpc/service_config", + visibility = "public", +) + +grpc_proto_library( + name = "service_config_proto", + srcs = ["service_config.proto"], + has_services = False, + well_known_protos = True, + deps = [ + "//src/proto/grpc/lookup/v1:rls_config_proto", + "@com_google_googleapis//google/rpc:code_proto", + ], +) + +proto_library( + name = "service_config_proto_descriptor", + srcs = ["service_config.proto"], + deps = [ + "//src/proto/grpc/lookup/v1:rls_config_proto_descriptor", + "@com_google_googleapis//google/rpc:code_proto", + "@com_google_protobuf//:duration_proto", + "@com_google_protobuf//:struct_proto", + "@com_google_protobuf//:wrappers_proto", + ], +) diff --git a/src/proto/grpc/service_config/service_config.proto b/src/proto/grpc/service_config/service_config.proto new file mode 100644 index 00000000000..fce2dfb36dd --- /dev/null +++ b/src/proto/grpc/service_config/service_config.proto @@ -0,0 +1,786 @@ +// Copyright 2016 The gRPC Authors +// +// 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. + +// A ServiceConfig is supplied when a service is deployed. It mostly contains +// parameters for how clients that connect to the service should behave (for +// example, the load balancing policy to use to pick between service replicas). +// +// The configuration options provided here act as overrides to automatically +// chosen option values. Service owners should be conservative in specifying +// options as the system is likely to choose better values for these options in +// the vast majority of cases. In other words, please specify a configuration +// option only if you really have to, and avoid copy-paste inclusion of configs. +// +// Note that gRPC uses the service config in JSON form, not in protobuf +// form. This proto definition is intended to help document the schema but +// will not actually be used directly by gRPC. +// +// Copied from https://github.com/grpc/grpc-proto/blob/master/grpc/service_config/service_config.proto +// for testing purposes + +syntax = "proto3"; + +package grpc.service_config; + +import "google/protobuf/duration.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/wrappers.proto"; +import "google/rpc/code.proto"; +import "src/proto/grpc/lookup/v1/rls_config.proto"; + +option java_package = "io.grpc.serviceconfig"; +option java_multiple_files = true; +option java_outer_classname = "ServiceConfigProto"; + +// Configuration for a method. +message MethodConfig { + // The names of the methods to which this configuration applies. + // - MethodConfig without names (empty list) will be skipped. + // - Each name entry must be unique across the entire ServiceConfig. + // - If the 'method' field is empty, this MethodConfig specifies the defaults + // for all methods for the specified service. + // - If the 'service' field is empty, the 'method' field must be empty, and + // this MethodConfig specifies the default for all methods (it's the default + // config). + // + // When determining which MethodConfig to use for a given RPC, the most + // specific match wins. For example, let's say that the service config + // contains the following MethodConfig entries: + // + // method_config { name { } ... } + // method_config { name { service: "MyService" } ... } + // method_config { name { service: "MyService" method: "Foo" } ... } + // + // MyService/Foo will use the third entry, because it exactly matches the + // service and method name. MyService/Bar will use the second entry, because + // it provides the default for all methods of MyService. AnotherService/Baz + // will use the first entry, because it doesn't match the other two. + // + // In JSON representation, value "", value `null`, and not present are the + // same. The following are the same Name: + // - { "service": "s" } + // - { "service": "s", "method": null } + // - { "service": "s", "method": "" } + message Name { + string service = 1; // Required. Includes proto package name. + string method = 2; + } + repeated Name name = 1; + + // Whether RPCs sent to this method should wait until the connection is + // ready by default. If false, the RPC will abort immediately if there is + // a transient failure connecting to the server. Otherwise, gRPC will + // attempt to connect until the deadline is exceeded. + // + // The value specified via the gRPC client API will override the value + // set here. However, note that setting the value in the client API will + // also affect transient errors encountered during name resolution, which + // cannot be caught by the value here, since the service config is + // obtained by the gRPC client via name resolution. + google.protobuf.BoolValue wait_for_ready = 2; + + // The default timeout in seconds for RPCs sent to this method. This can be + // overridden in code. If no reply is received in the specified amount of + // time, the request is aborted and a DEADLINE_EXCEEDED error status + // is returned to the caller. + // + // The actual deadline used will be the minimum of the value specified here + // and the value set by the application via the gRPC client API. If either + // one is not set, then the other will be used. If neither is set, then the + // request has no deadline. + google.protobuf.Duration timeout = 3; + + // The maximum allowed payload size for an individual request or object in a + // stream (client->server) in bytes. The size which is measured is the + // serialized payload after per-message compression (but before stream + // compression) in bytes. This applies both to streaming and non-streaming + // requests. + // + // The actual value used is the minimum of the value specified here and the + // value set by the application via the gRPC client API. If either one is + // not set, then the other will be used. If neither is set, then the + // built-in default is used. + // + // If a client attempts to send an object larger than this value, it will not + // be sent and the client will see a ClientError. + // Note that 0 is a valid value, meaning that the request message + // must be empty. + google.protobuf.UInt32Value max_request_message_bytes = 4; + + // The maximum allowed payload size for an individual response or object in a + // stream (server->client) in bytes. The size which is measured is the + // serialized payload after per-message compression (but before stream + // compression) in bytes. This applies both to streaming and non-streaming + // requests. + // + // The actual value used is the minimum of the value specified here and the + // value set by the application via the gRPC client API. If either one is + // not set, then the other will be used. If neither is set, then the + // built-in default is used. + // + // If a server attempts to send an object larger than this value, it will not + // be sent, and a ServerError will be sent to the client instead. + // Note that 0 is a valid value, meaning that the response message + // must be empty. + google.protobuf.UInt32Value max_response_message_bytes = 5; + + // The retry policy for outgoing RPCs. + message RetryPolicy { + // The maximum number of RPC attempts, including the original attempt. + // + // This field is required and must be greater than 1. + // Any value greater than 5 will be treated as if it were 5. + uint32 max_attempts = 1; + + // Exponential backoff parameters. The initial retry attempt will occur at + // random(0, initial_backoff). In general, the nth attempt will occur at + // random(0, + // min(initial_backoff*backoff_multiplier**(n-1), max_backoff)). + // Required. Must be greater than zero. + google.protobuf.Duration initial_backoff = 2; + // Required. Must be greater than zero. + google.protobuf.Duration max_backoff = 3; + float backoff_multiplier = 4; // Required. Must be greater than zero. + + // The set of status codes which may be retried. + // + // This field is required and must be non-empty. + repeated google.rpc.Code retryable_status_codes = 5; + } + + // The hedging policy for outgoing RPCs. Hedged RPCs may execute more than + // once on the server, so only idempotent methods should specify a hedging + // policy. + message HedgingPolicy { + // The hedging policy will send up to max_requests RPCs. + // This number represents the total number of all attempts, including + // the original attempt. + // + // This field is required and must be greater than 1. + // Any value greater than 5 will be treated as if it were 5. + uint32 max_attempts = 1; + + // The first RPC will be sent immediately, but the max_requests-1 subsequent + // hedged RPCs will be sent at intervals of every hedging_delay. Set this + // to 0 to immediately send all max_requests RPCs. + google.protobuf.Duration hedging_delay = 2; + + // The set of status codes which indicate other hedged RPCs may still + // succeed. If a non-fatal status code is returned by the server, hedged + // RPCs will continue. Otherwise, outstanding requests will be canceled and + // the error returned to the client application layer. + // + // This field is optional. + repeated google.rpc.Code non_fatal_status_codes = 3; + } + + // Only one of retry_policy or hedging_policy may be set. If neither is set, + // RPCs will not be retried or hedged. + oneof retry_or_hedging_policy { + RetryPolicy retry_policy = 6; + HedgingPolicy hedging_policy = 7; + } +} + +// Configuration for pick_first LB policy. +message PickFirstConfig { + // If set to true, instructs the LB policy to randomly shuffle the list of + // addresses received from the name resolver before attempting to connect to + // them. + bool shuffle_address_list = 1; +} + +// Configuration for round_robin LB policy. +message RoundRobinConfig {} + +// Configuration for weighted_round_robin LB policy. +message WeightedRoundRobinLbConfig { + // Whether to enable out-of-band utilization reporting collection from + // the endpoints. By default, per-request utilization reporting is used. + google.protobuf.BoolValue enable_oob_load_report = 1; + + // Load reporting interval to request from the server. Note that the + // server may not provide reports as frequently as the client requests. + // Used only when enable_oob_load_report is true. Default is 10 seconds. + google.protobuf.Duration oob_reporting_period = 2; + + // A given endpoint must report load metrics continuously for at least + // this long before the endpoint weight will be used. This avoids + // churn when the set of endpoint addresses changes. Takes effect + // both immediately after we establish a connection to an endpoint and + // after weight_expiration_period has caused us to stop using the most + // recent load metrics. Default is 10 seconds. + google.protobuf.Duration blackout_period = 3; + + // If a given endpoint has not reported load metrics in this long, + // then we stop using the reported weight. This ensures that we do + // not continue to use very stale weights. Once we stop using a stale + // value, if we later start seeing fresh reports again, the + // blackout_period applies. Defaults to 3 minutes. + google.protobuf.Duration weight_expiration_period = 4; + + // How often endpoint weights are recalculated. Values less than 100ms are + // capped at 100ms. Default is 1 second. + google.protobuf.Duration weight_update_period = 5; + + // The multiplier used to adjust endpoint weights with the error rate + // calculated as eps/qps. Configuration is rejected if this value is negative. + // Default is 1.0. + google.protobuf.FloatValue error_utilization_penalty = 6; +} + +// Configuration for outlier_detection LB policy +message OutlierDetectionLoadBalancingConfig { + // The time interval between ejection analysis sweeps. This can result in + // both new ejections as well as addresses being returned to service. Defaults + // to 10000ms or 10s. + google.protobuf.Duration interval = 1; + + // The base time that as address is ejected for. The real time is equal to the + // base time multiplied by the number of times the address has been ejected. + // Defaults to 30000ms or 30s. + google.protobuf.Duration base_ejection_time = 2; + + // The maximum time that an address is ejected for. If not specified, the default value (300000ms or 300s) or + // the base_ejection_time value is applied, whatever is larger. + google.protobuf.Duration max_ejection_time = 3; + + // The maximum % of an address list that can be ejected due to outlier + // detection. Defaults to 10% but will eject at least one address regardless of the value. + google.protobuf.UInt32Value max_ejection_percent = 4; + + // Parameters for the success rate ejection algorithm. + // This algorithm monitors the request success rate for all endpoints and + // ejects individual endpoints whose success rates are statistical outliers. + message SuccessRateEjection { + // This factor is used to determine the ejection threshold for success rate + // outlier ejection. The ejection threshold is the difference between the + // mean success rate, and the product of this factor and the standard + // deviation of the mean success rate: mean - (stdev * + // success_rate_stdev_factor). This factor is divided by a thousand to get a + // double. That is, if the desired factor is 1.9, the runtime value should + // be 1900. Defaults to 1900. + google.protobuf.UInt32Value stdev_factor = 1; + + // The % chance that an address will be actually ejected when an outlier status + // is detected through success rate statistics. This setting can be used to + // disable ejection or to ramp it up slowly. Defaults to 100. + google.protobuf.UInt32Value enforcement_percentage = 2; + + // The number of addresses that must have enough request volume to + // detect success rate outliers. If the number of addresses is less than this + // setting, outlier detection via success rate statistics is not performed + // for any addresses. Defaults to 5. + google.protobuf.UInt32Value minimum_hosts = 3; + + // The minimum number of total requests that must be collected in one + // interval (as defined by the interval duration above) to include this address + // in success rate based outlier detection. If the volume is lower than this + // setting, outlier detection via success rate statistics is not performed + // for that address. Defaults to 100. + google.protobuf.UInt32Value request_volume = 4; + } + + // Parameters for the failure percentage algorithm. + // This algorithm ejects individual endpoints whose failure rate is greater than + // some threshold, independently of any other endpoint. + message FailurePercentageEjection { + // The failure percentage to use when determining failure percentage-based outlier detection. If + // the failure percentage of a given address is greater than or equal to this value, it will be + // ejected. Defaults to 85. + google.protobuf.UInt32Value threshold = 1; + + // The % chance that an address will be actually ejected when an outlier status is detected through + // failure percentage statistics. This setting can be used to disable ejection or to ramp it up + // slowly. Defaults to 100. + google.protobuf.UInt32Value enforcement_percentage = 2; + + // The minimum number of addresses in order to perform failure percentage-based ejection. + // If the total number of addresses is less than this value, failure percentage-based + // ejection will not be performed. Defaults to 5. + google.protobuf.UInt32Value minimum_hosts = 3; + + // The minimum number of total requests that must be collected in one interval (as defined by the + // interval duration above) to perform failure percentage-based ejection for this address. If the + // volume is lower than this setting, failure percentage-based ejection will not be performed for + // this host. Defaults to 50. + google.protobuf.UInt32Value request_volume = 4; + } + + // If set, success rate ejections will be performed + SuccessRateEjection success_rate_ejection = 5; + + // If set, failure rate ejections will be performed + FailurePercentageEjection failure_percentage_ejection = 6; + + // The config for the child policy + repeated LoadBalancingConfig child_policy = 13; +} + +// Configuration for grpclb LB policy. +message GrpcLbConfig { + // Optional. What LB policy to use for routing between the backend + // addresses. If unset, defaults to round_robin. + // Currently, the only supported values are round_robin and pick_first. + // Note that this will be used both in balancer mode and in fallback mode. + // Multiple LB policies can be specified; clients will iterate through + // the list in order and stop at the first policy that they support. + repeated LoadBalancingConfig child_policy = 1; + // Optional. If specified, overrides the name of the service to be sent to + // the balancer. + string service_name = 2; + // Optional. The timeout in seconds for receiving the server list from the LB + // server. Defaults to 10s. + google.protobuf.Duration initial_fallback_timeout = 3; +} + +// Configuration for priority LB policy. +message PriorityLoadBalancingPolicyConfig { + // A map of name to child policy configuration. + // The names are used to allow the priority policy to update + // existing child policies instead of creating new ones every + // time it receives a config update. + message Child { + repeated LoadBalancingConfig config = 1; + + // If true, will ignore reresolution requests from this child. + bool ignore_reresolution_requests = 2; + } + map children = 1; + + // A list of child names in decreasing priority order + // (i.e., first element is the highest priority). + repeated string priorities = 2; +} + +// Configuration for weighted_target LB policy. +message WeightedTargetLoadBalancingPolicyConfig { + message Target { + uint32 weight = 1; + repeated LoadBalancingConfig child_policy = 2; + } + map targets = 1; +} + +// Config for RLS LB policy. +message RlsLoadBalancingPolicyConfig { + grpc.lookup.v1.RouteLookupConfig route_lookup_config = 1; + + // Service config to use for the RLS channel. + ServiceConfig route_lookup_channel_service_config = 2; + + repeated LoadBalancingConfig child_policy = 3; + // Field name to add to child policy config to contain the target name. + string child_policy_config_target_field_name = 4; +} + +// Configuration for xds_cluster_manager_experimental LB policy. +message XdsClusterManagerLoadBalancingPolicyConfig { + message Child { + repeated LoadBalancingConfig child_policy = 1; + } + map children = 1; +} + +// Configuration for the cds LB policy. +message CdsConfig { + string cluster = 1; // Required. +} + +// Represents an xDS server. +message XdsServer { + string server_uri = 1 [json_name = "server_uri"]; // Required. + + message ChannelCredentials { + string type = 1; // Required. + google.protobuf.Struct config = 2; // Optional JSON config. + } + // A list of channel creds to use. The first supported type will be used. + repeated ChannelCredentials channel_creds = 2 [json_name = "channel_creds"]; + + // A repeated list of server features. + repeated google.protobuf.Value server_features = 3 + [json_name = "server_features"]; +} + +// Configuration for xds_cluster_resolver LB policy. +message XdsClusterResolverLoadBalancingPolicyConfig { + // Describes a discovery mechanism instance. + // For EDS or LOGICAL_DNS clusters, there will be exactly one + // DiscoveryMechanism, which will describe the cluster of the parent + // CDS policy. + // For aggregate clusters, there will be one DiscoveryMechanism for each + // underlying cluster. + message DiscoveryMechanism { + // Cluster name. + string cluster = 1; + + // LRS server to send load reports to. + // If not present, load reporting will be disabled. + // If set to the empty string, load reporting will be sent to the same + // server that we obtained CDS data from. + // DEPRECATED: Use new lrs_load_reporting_server field instead. + google.protobuf.StringValue lrs_load_reporting_server_name = 2 + [deprecated=true]; + + // LRS server to send load reports to. + // If not present, load reporting will be disabled. + // Supercedes lrs_load_reporting_server_name field. + XdsServer lrs_load_reporting_server = 7; + + // Maximum number of outstanding requests can be made to the upstream + // cluster. Default is 1024. + google.protobuf.UInt32Value max_concurrent_requests = 3; + + enum Type { + UNKNOWN = 0; + EDS = 1; + LOGICAL_DNS = 2; + }; + Type type = 4; + + // For type EDS only. + // EDS service name, as returned in CDS. + // May be unset if not specified in CDS. + string eds_service_name = 5; + + // For type LOGICAL_DNS only. + // DNS name to resolve in "host:port" form. + string dns_hostname = 6; + + // The configuration for outlier_detection child policies + // Within this message, the child_policy field will be ignored + OutlierDetectionLoadBalancingConfig outlier_detection = 8; + + // The configuration for xds_override_host child policy + repeated OverrideHostLoadBalancingPolicyConfig.HealthStatus override_host_status = 9; + } + + // Ordered list of discovery mechanisms. + // Must have at least one element. + // Results from each discovery mechanism are concatenated together in + // successive priorities. + repeated DiscoveryMechanism discovery_mechanisms = 1; + + // xDS LB policy. Will be used as the child config of the xds_cluster_impl LB policy. + repeated LoadBalancingConfig xds_lb_policy = 2; +} + +// Configuration for xds_cluster_impl LB policy. +message XdsClusterImplLoadBalancingPolicyConfig { + // Cluster name. Required. + string cluster = 1; + + // EDS service name. + // Not set if cluster is not an EDS cluster or if it does not + // specify an EDS service name. + string eds_service_name = 2; + + // Server to send load reports to. + // If unset, no load reporting is done. + // If set to empty string, load reporting will be sent to the same + // server as we are getting xds data from. + // DEPRECATED: Use new lrs_load_reporting_server field instead. + google.protobuf.StringValue lrs_load_reporting_server_name = 3 + [deprecated=true]; + + // LRS server to send load reports to. + // If not present, load reporting will be disabled. + // Supercedes lrs_load_reporting_server_name field. + XdsServer lrs_load_reporting_server = 7; + + // Maximum number of outstanding requests can be made to the upstream cluster. + // Default is 1024. + google.protobuf.UInt32Value max_concurrent_requests = 4; + + // Drop configuration. + message DropCategory { + string category = 1; + uint32 requests_per_million = 2; + } + repeated DropCategory drop_categories = 5; + + // Child policy. + repeated LoadBalancingConfig child_policy = 6; +} + +// Configuration for eds LB policy. +message EdsLoadBalancingPolicyConfig { + // Cluster name. Required. + string cluster = 1; + + // EDS service name, as returned in CDS. + // May be unset if not specified in CDS. + string eds_service_name = 2; + + // Server to send load reports to. + // If unset, no load reporting is done. + // If set to empty string, load reporting will be sent to the same + // server as we are getting xds data from. + google.protobuf.StringValue lrs_load_reporting_server_name = 3; + + // Locality-picking policy. + // This policy's config is expected to be in the format used + // by the weighted_target policy. Note that the config should include + // an empty value for the "targets" field; that empty value will be + // replaced by one that is dynamically generated based on the EDS data. + // Optional; defaults to "weighted_target". + repeated LoadBalancingConfig locality_picking_policy = 4; + + // Endpoint-picking policy. + // This will be configured as the policy for each child in the + // locality-policy's config. + // Optional; defaults to "round_robin". + repeated LoadBalancingConfig endpoint_picking_policy = 5; +} + +// Configuration for ring_hash LB policy. +message RingHashLoadBalancingConfig { + // A client-side option will cap these values to 4096. If either of these + // values are greater than the client-side cap, they will be treated + // as the client-side cap value. + uint64 min_ring_size = 1; // Optional, defaults to 1024, max 8M. + uint64 max_ring_size = 2; // Optional, defaults to 4096, max 8M. +} + +// Configuration for lrs LB policy. +message LrsLoadBalancingPolicyConfig { + // Cluster name. Required. + string cluster_name = 1; + + // EDS service name, as returned in CDS. + // May be unset if not specified in CDS. + string eds_service_name = 2; + + // Server to send load reports to. Required. + // If set to empty string, load reporting will be sent to the same + // server as we are getting xds data from. + string lrs_load_reporting_server_name = 3; + + // The locality for which this policy will report load. Required. + message Locality { + string region = 1; + string zone = 2; + string subzone = 3; + } + Locality locality = 4; + + // Endpoint-picking policy. + repeated LoadBalancingConfig child_policy = 5; +} + +// Configuration for the xds_wrr_locality load balancing policy. +message XdsWrrLocalityLoadBalancingPolicyConfig { + repeated LoadBalancingConfig child_policy = 1; +} + +// Configuration for the least_request LB policy. +message LeastRequestLocalityLoadBalancingPolicyConfig { + uint64 choice_count = 1; +} + + +// Configuration for the override_host LB policy. +message OverrideHostLoadBalancingPolicyConfig { + enum HealthStatus { + UNKNOWN = 0; + HEALTHY = 1; + DRAINING = 3; + } + + // valid health status for hosts that are considered when using + // xds_override_host_experimental policy. + // Default is [UNKNOWN, HEALTHY] + repeated HealthStatus override_host_status = 1; + + repeated LoadBalancingConfig child_policy = 2; +} + +// Configuration for xds LB policy. +message XdsConfig { + // Name of balancer to connect to. + string balancer_name = 1 [deprecated = true]; + // Optional. What LB policy to use for intra-locality routing. + // If unset, will use whatever algorithm is specified by the balancer. + // Multiple LB policies can be specified; clients will iterate through + // the list in order and stop at the first policy that they support. + repeated LoadBalancingConfig child_policy = 2; + // Optional. What LB policy to use in fallback mode. If not + // specified, defaults to round_robin. + // Multiple LB policies can be specified; clients will iterate through + // the list in order and stop at the first policy that they support. + repeated LoadBalancingConfig fallback_policy = 3; + // Optional. Name to use in EDS query. If not present, defaults to + // the server name from the target URI. + string eds_service_name = 4; + // LRS server to send load reports to. + // If not present, load reporting will be disabled. + // If set to the empty string, load reporting will be sent to the same + // server that we obtained CDS data from. + google.protobuf.StringValue lrs_load_reporting_server_name = 5; +} + +// Selects LB policy and provides corresponding configuration. +// +// In general, all instances of this field should be repeated. Clients will +// iterate through the list in order and stop at the first policy that they +// support. This allows the service config to specify custom policies that may +// not be known to all clients. +// +// - If the config for the first supported policy is invalid, the whole service +// config is invalid. +// - If the list doesn't contain any supported policy, the whole service config +// is invalid. +message LoadBalancingConfig { + // Exactly one LB policy may be configured. + oneof policy { + // For each new LB policy supported by gRPC, a new field must be added + // here. The field's name must be the LB policy name and its type is a + // message that provides whatever configuration parameters are needed + // by the LB policy. The configuration message will be passed to the + // LB policy when it is instantiated on the client. + // + // If the LB policy does not require any configuration parameters, the + // message for that LB policy may be empty. + // + // Note that if an LB policy contains another nested LB policy + // (e.g., a gslb policy picks the cluster and then delegates to + // a round_robin policy to pick the backend within that cluster), its + // configuration message may include a nested instance of the + // LoadBalancingConfig message to configure the nested LB policy. + + PickFirstConfig pick_first = 4 [json_name = "pick_first"]; + + RoundRobinConfig round_robin = 1 [json_name = "round_robin"]; + + WeightedRoundRobinLbConfig weighted_round_robin = 20 + [json_name = "weighted_round_robin"]; + + // gRPC lookaside load balancing. + // This will eventually be deprecated by the new xDS-based local + // balancing policy. + GrpcLbConfig grpclb = 3; + + // REMAINING POLICIES ARE EXPERIMENTAL -- DO NOT USE + + PriorityLoadBalancingPolicyConfig priority_experimental = 9 + [json_name = "priority_experimental"]; + WeightedTargetLoadBalancingPolicyConfig weighted_target_experimental = 10 + [json_name = "weighted_target_experimental"]; + OutlierDetectionLoadBalancingConfig outlier_detection = 15 + [json_name = "outlier_detection_experimental"]; + RlsLoadBalancingPolicyConfig rls = 19 [json_name = "rls_experimental"]; + + // xDS-based load balancing. + XdsClusterManagerLoadBalancingPolicyConfig xds_cluster_manager_experimental + = 14 [json_name = "xds_cluster_manager_experimental"]; + CdsConfig cds_experimental = 6 [json_name = "cds_experimental"]; + XdsClusterResolverLoadBalancingPolicyConfig + xds_cluster_resolver_experimental = 11 + [json_name = "xds_cluster_resolver_experimental"]; + XdsClusterImplLoadBalancingPolicyConfig xds_cluster_impl_experimental = 12 + [json_name = "xds_cluster_impl_experimental"]; + OverrideHostLoadBalancingPolicyConfig override_host_experimental = 18 + [json_name = "override_host_experimental"]; + XdsWrrLocalityLoadBalancingPolicyConfig xds_wrr_locality_experimental = 16 + [json_name = "xds_wrr_locality_experimental"]; + RingHashLoadBalancingConfig ring_hash_experimental = 13 + [json_name = "ring_hash_experimental"]; + LeastRequestLocalityLoadBalancingPolicyConfig least_request_experimental = + 17 [json_name = "least_request_experimental"]; + + // Deprecated xDS-related policies. + LrsLoadBalancingPolicyConfig lrs_experimental = 8 + [json_name = "lrs_experimental", deprecated = true]; + EdsLoadBalancingPolicyConfig eds_experimental = 7 + [json_name = "eds_experimental", deprecated = true]; + XdsConfig xds = 2 [deprecated = true]; + XdsConfig xds_experimental = 5 [json_name = "xds_experimental", + deprecated = true]; + + // Next available ID: 21 + } +} + +// A ServiceConfig represents information about a service but is not specific to +// any name resolver. +message ServiceConfig { + // Load balancing policy. + // + // Note that load_balancing_policy is deprecated in favor of + // load_balancing_config; the former will be used only if the latter + // is unset. + // + // If no LB policy is configured here, then the default is pick_first. + // If the policy name is set via the client API, that value overrides + // the value specified here. + // + // If the deprecated load_balancing_policy field is used, note that if the + // resolver returns at least one balancer address (as opposed to backend + // addresses), gRPC will use grpclb (see + // https://github.com/grpc/grpc/blob/master/doc/load-balancing.md), + // regardless of what policy is configured here. However, if the resolver + // returns at least one backend address in addition to the balancer + // address(es), the client may fall back to the requested policy if it + // is unable to reach any of the grpclb load balancers. + enum LoadBalancingPolicy { + UNSPECIFIED = 0; + ROUND_ROBIN = 1; + } + LoadBalancingPolicy load_balancing_policy = 1 [deprecated = true]; + // Multiple LB policies can be specified; clients will iterate through + // the list in order and stop at the first policy that they support. If none + // are supported, the service config is considered invalid. + repeated LoadBalancingConfig load_balancing_config = 4; + + // Per-method configuration. + repeated MethodConfig method_config = 2; + + // If a RetryThrottlingPolicy is provided, gRPC will automatically throttle + // retry attempts and hedged RPCs when the client's ratio of failures to + // successes exceeds a threshold. + // + // For each server name, the gRPC client will maintain a token_count which is + // initially set to max_tokens. Every outgoing RPC (regardless of service or + // method invoked) will change token_count as follows: + // + // - Every failed RPC will decrement the token_count by 1. + // - Every successful RPC will increment the token_count by token_ratio. + // + // If token_count is less than or equal to max_tokens / 2, then RPCs will not + // be retried and hedged RPCs will not be sent. + message RetryThrottlingPolicy { + // The number of tokens starts at max_tokens. The token_count will always be + // between 0 and max_tokens. + // + // This field is required and must be greater than zero. + uint32 max_tokens = 1; + + // The amount of tokens to add on each successful RPC. Typically this will + // be some number between 0 and 1, e.g., 0.1. + // + // This field is required and must be greater than zero. Up to 3 decimal + // places are supported. + float token_ratio = 2; + } + RetryThrottlingPolicy retry_throttling = 3; + + message HealthCheckConfig { + // Service name to use in the health-checking request. + google.protobuf.StringValue service_name = 1; + } + HealthCheckConfig health_check_config = 5; + + // next available tag: 6 +} diff --git a/test/core/ext/filters/event_engine_client_channel_resolver/BUILD b/test/core/ext/filters/event_engine_client_channel_resolver/BUILD new file mode 100644 index 00000000000..35ba1e809f5 --- /dev/null +++ b/test/core/ext/filters/event_engine_client_channel_resolver/BUILD @@ -0,0 +1,47 @@ +# Copyright 2023 gRPC authors. +# +# 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. + +load("//bazel:grpc_build_system.bzl", "grpc_package") +load("//test/core/util:grpc_fuzzer.bzl", "grpc_proto_fuzzer") + +grpc_package(name = "test/core/ext/filters/event_engine_client_channel_resolver") + +licenses(["notice"]) + +grpc_proto_fuzzer( + name = "resolver_fuzzer", + size = "enormous", + srcs = ["resolver_fuzzer.cc"], + corpus = "resolver_fuzzer_corpus", + language = "C++", + proto = "resolver_ops.proto", + proto_deps = [ + "//src/proto/grpc/service_config:service_config_proto", + ], + tags = [ + "no_mac", + "no_windows", + ], + uses_event_engine = False, + uses_polling = False, + deps = [ + "//:gpr", + "//:grpc", + "//src/core:channel_args", + "//test/core/event_engine:aborting_event_engine", + "//test/core/event_engine/fuzzing_event_engine", + "//test/core/util:grpc_test_util", + "//test/core/util:grpc_test_util_base", + ], +) diff --git a/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer.cc b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer.cc new file mode 100644 index 00000000000..7ec9dcf6718 --- /dev/null +++ b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer.cc @@ -0,0 +1,282 @@ +// Copyright 2023 The gRPC Authors +// +// 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. +#include + +#include +#include +#include +#include +#include +#include + +#include "absl/base/thread_annotations.h" +#include "absl/functional/any_invocable.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "google/protobuf/json/json.h" + +#include +#include +#include + +#include "src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/event_engine/tcp_socket_utils.h" +#include "src/core/lib/gprpp/crash.h" +#include "src/core/lib/gprpp/debug_location.h" +#include "src/core/lib/gprpp/notification.h" +#include "src/core/lib/gprpp/orphanable.h" +#include "src/core/lib/gprpp/work_serializer.h" +#include "src/core/lib/resolver/resolver.h" +#include "src/core/lib/resolver/resolver_factory.h" +#include "src/core/lib/uri/uri_parser.h" +#include "src/libfuzzer/libfuzzer_macro.h" +#include "src/proto/grpc/service_config/service_config.pb.h" +#include "test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h" +#include "test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.h" +#include "test/core/event_engine/util/aborting_event_engine.h" +#include "test/core/ext/filters/event_engine_client_channel_resolver/resolver_ops.pb.h" + +// TODO(hork): exercise Orphan on the client channel resolver, which will +// exercise the resolution cancellation path. Currently, all requests will get +// responses. + +bool squelch = true; + +namespace { + +using event_engine_client_channel_resolver::TXTRecordType; +using grpc_core::EventEngineClientChannelDNSResolverFactory; +using grpc_event_engine::experimental::EventEngine; +using grpc_event_engine::experimental::FuzzingEventEngine; +using grpc_event_engine::experimental::URIToResolvedAddress; + +constexpr char g_grpc_config_prefix[] = "grpc_config="; + +absl::Status ErrorToAbslStatus( + const event_engine_client_channel_resolver::Error& error) { + // clamp error.code() in (0, 16] + return absl::Status(static_cast(error.code() % 16 + 1), + error.message()); +} + +class FuzzingResolverEventEngine + : public grpc_event_engine::experimental::AbortingEventEngine { + public: + explicit FuzzingResolverEventEngine( + const event_engine_client_channel_resolver::Msg& msg) + : runner_(FuzzingEventEngine::Options(), + fuzzing_event_engine::Actions()) { + // Set hostname responses + if (msg.has_hostname_error()) { + hostname_responses_ = ErrorToAbslStatus(msg.hostname_error()); + } else if (msg.has_hostname_response()) { + hostname_responses_.emplace(); + for (const auto& address : msg.hostname_response().addresses()) { + hostname_responses_->emplace_back(*URIToResolvedAddress( + absl::StrCat("ipv4:127.0.0.1:", address.port() % 65535))); + } + } + // Set SRV Responses + if (msg.has_srv_error()) { + srv_responses_ = ErrorToAbslStatus(msg.srv_error()); + } else if (msg.has_srv_response()) { + srv_responses_.emplace(); + for (const auto& srv_record : msg.srv_response().srv_records()) { + EventEngine::DNSResolver::SRVRecord final_r; + final_r.host = srv_record.host(); + final_r.port = srv_record.port(); + final_r.priority = srv_record.priority(); + final_r.weight = srv_record.weight(); + srv_responses_->emplace_back(final_r); + } + } + // Set TXT Responses + if (msg.has_txt_error()) { + txt_responses_ = ErrorToAbslStatus(msg.txt_error()); + } else if (msg.has_txt_response()) { + txt_responses_.emplace(); + for (const auto& txt_record : msg.txt_response().txt_records()) { + if (txt_record.has_enumerated_value()) { + switch (txt_record.enumerated_value()) { + case TXTRecordType::TXT_VALID: + txt_responses_->emplace_back(txt_valid_config_); + break; + case TXTRecordType::TXT_RANDOM_NON_CONFIG: + txt_responses_->emplace_back(txt_record.arbitrary_value()); + break; + case TXTRecordType::TXT_RANDOM_PREFIXED_CONFIG: + txt_responses_->emplace_back(absl::StrCat( + g_grpc_config_prefix, txt_record.arbitrary_value())); + break; + default: + grpc_core::Crash("Invalid txt record type"); + } + } else if (txt_record.has_fuzzed_service_config()) { + std::string fuzzed_config_json_str; + ::google::protobuf::json::PrintOptions print_options; + auto status = + MessageToJsonString(txt_record.fuzzed_service_config(), + &fuzzed_config_json_str, print_options); + // Sometimes LLVM will generate protos that can't be dumped to JSON + // (Durations out of bounds, for example). These are ignored. + if (status.ok()) { + txt_responses_->emplace_back(fuzzed_config_json_str); + } + } + } + } + } + std::unique_ptr GetDNSResolver( + const DNSResolver::ResolverOptions& /* options */) override { + return std::make_unique(this); + } + + void Tick() { runner_.Tick(); } + + private: + class FuzzingDNSResolver : public DNSResolver { + public: + explicit FuzzingDNSResolver(FuzzingResolverEventEngine* engine) + : engine_(engine) {} + LookupTaskHandle LookupHostname(LookupHostnameCallback on_resolve, + absl::string_view /* name */, + absl::string_view /* default_port */, + Duration /* timeout */) override { + auto finish = + [cb = std::move(on_resolve), runner = &engine_->runner_]( + absl::StatusOr> response) mutable { + runner->Run( + [cb = std::move(cb), response = std::move(response)]() mutable { + cb(response); + }); + return EventEngine::DNSResolver::LookupTaskHandle::kInvalid; + }; + return finish(engine_->hostname_responses_); + } + LookupTaskHandle LookupSRV(LookupSRVCallback on_resolve, + absl::string_view /* name */, + Duration /* timeout */) override { + auto finish = + [cb = std::move(on_resolve), runner = &engine_->runner_]( + absl::StatusOr> response) mutable { + runner->Run( + [cb = std::move(cb), response = std::move(response)]() mutable { + cb(response); + }); + return EventEngine::DNSResolver::LookupTaskHandle::kInvalid; + }; + return finish(engine_->srv_responses_); + } + LookupTaskHandle LookupTXT(LookupTXTCallback on_resolve, + absl::string_view /* name */, + Duration /* timeout */) override { + auto finish = + [cb = std::move(on_resolve), runner = &engine_->runner_]( + absl::StatusOr> response) mutable { + runner->Run( + [cb = std::move(cb), response = std::move(response)]() mutable { + cb(response); + }); + return EventEngine::DNSResolver::LookupTaskHandle::kInvalid; + }; + return finish(engine_->txt_responses_); + } + bool CancelLookup(LookupTaskHandle /* handle */) override { return false; } + + private: + FuzzingResolverEventEngine* engine_; + }; + + // members + FuzzingEventEngine runner_; + + // responses + absl::StatusOr> hostname_responses_; + absl::StatusOr> + srv_responses_; + absl::StatusOr> txt_responses_; + + // base case for a valid gRPC config + const std::string txt_valid_config_ = + "grpc_config=[{\"serviceConfig\":{\"loadBalancingPolicy\":\"round_" + "robin\",\"methodConfig\":[{\"name\":[{\"method\":\"Foo\",\"service\":" + "\"SimpleService\"}],\"waitForReady\":true}]}}]"; +}; + +grpc_core::ChannelArgs ConstructChannelArgs( + const event_engine_client_channel_resolver::Msg& msg, + std::shared_ptr engine) { + // put the engine in channel args + return grpc_core::ChannelArgs() + .SetObject(std::move(engine)) + .Set(GRPC_ARG_SERVICE_CONFIG_DISABLE_RESOLUTION, + !msg.resolver_args().request_service_config()) + .Set(GRPC_ARG_DNS_ENABLE_SRV_QUERIES, + msg.resolver_args().enable_srv_queries()); +} + +class FuzzingResultHandler : public grpc_core::Resolver::ResultHandler { + public: + explicit FuzzingResultHandler(grpc_core::Notification* signal) + : signal_(signal) {} + void ReportResult(grpc_core::Resolver::Result /* result */) override { + signal_->Notify(); + } + + private: + grpc_core::Notification* signal_; +}; + +grpc_core::ResolverArgs ConstructResolverArgs( + const grpc_core::ChannelArgs& channel_args, + grpc_core::Notification* result_handler_notification, + std::shared_ptr work_serializer) { + grpc_core::ResolverArgs resolver_args; + auto uri = grpc_core::URI::Parse("dns:localhost"); + GPR_ASSERT(uri.ok()); + resolver_args.uri = *uri; + resolver_args.args = channel_args; + resolver_args.pollset_set = nullptr; + resolver_args.work_serializer = std::move(work_serializer); + auto result_handler = + std::make_unique(result_handler_notification); + resolver_args.result_handler = std::move(result_handler); + return resolver_args; +} + +} // namespace + +DEFINE_PROTO_FUZZER(const event_engine_client_channel_resolver::Msg& msg) { + auto engine = std::make_shared(msg); + auto channel_args = ConstructChannelArgs(msg, engine); + grpc_core::Notification result_handler_notification; + auto work_serializer = std::make_shared(); + auto resolver_args = ConstructResolverArgs( + channel_args, &result_handler_notification, work_serializer); + EventEngineClientChannelDNSResolverFactory resolver_factory; + auto resolver = resolver_factory.CreateResolver(std::move(resolver_args)); + work_serializer->Run([resolver = resolver.get()]() + ABSL_EXCLUSIVE_LOCKS_REQUIRED( + *work_serializer) { resolver->StartLocked(); }, + DEBUG_LOCATION); + // wait for result (no need to check validity) + do { + engine->Tick(); + } while (!result_handler_notification.WaitForNotificationWithTimeout( + absl::Milliseconds(33))); +} diff --git a/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/crash-0dca225f566df998becb705fc3a6b33a2441b928 b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/crash-0dca225f566df998becb705fc3a6b33a2441b928 new file mode 100644 index 00000000000..c92e81c97ad --- /dev/null +++ b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/crash-0dca225f566df998becb705fc3a6b33a2441b928 @@ -0,0 +1,23 @@ +resolver_args { + request_service_config: true + enable_srv_queries: true +} +hostname_response { +} +txt_response { + txt_records { + fuzzed_service_config { + load_balancing_policy: ROUND_ROBIN + method_config { + timeout { + seconds: 8679573376966066176 + } + max_response_message_bytes { + value: 10 + } + } + retry_throttling { + } + } + } +} diff --git a/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/crash-1f078e66afdaf4f9db6ac5704c15d6ee7150bd80 b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/crash-1f078e66afdaf4f9db6ac5704c15d6ee7150bd80 new file mode 100644 index 00000000000..0f276aaf938 --- /dev/null +++ b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/crash-1f078e66afdaf4f9db6ac5704c15d6ee7150bd80 @@ -0,0 +1,10 @@ +resolver_args { + request_service_config: true +} +hostname_response { +} +txt_response { + txt_records { + enumerated_value: TXT_RANDOM_PREFIXED_CONFIG + } +} diff --git a/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/crash-8a4668f3c812f8d7d0eb5e96493ba84fe77edfc2 b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/crash-8a4668f3c812f8d7d0eb5e96493ba84fe77edfc2 new file mode 100644 index 00000000000..e49f615075b --- /dev/null +++ b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/crash-8a4668f3c812f8d7d0eb5e96493ba84fe77edfc2 @@ -0,0 +1,8 @@ +resolver_args { + request_service_config: true +} +txt_response { + txt_records { + enumerated_value: TXT_RANDOM_PREFIXED_CONFIG + } +} diff --git a/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/crash-da39a3ee5e6b4b0d3255bfef95601890afd80709 b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/crash-da39a3ee5e6b4b0d3255bfef95601890afd80709 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/timeout-1860f73b73574e91ce7b3cd8519cc0ec9753c5d8 b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/timeout-1860f73b73574e91ce7b3cd8519cc0ec9753c5d8 new file mode 100644 index 00000000000..cdfa20e64e8 --- /dev/null +++ b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/timeout-1860f73b73574e91ce7b3cd8519cc0ec9753c5d8 @@ -0,0 +1,16 @@ +resolver_args { + enable_srv_queries: true +} +hostname_response { + addresses { + port: 32 + } + addresses { + port: 32 + } + addresses { + port: 1996488736 + } +} +srv_response { +} diff --git a/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/timeout-7a3822831087e0f79e2743c8f87650cc34a18898 b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/timeout-7a3822831087e0f79e2743c8f87650cc34a18898 new file mode 100644 index 00000000000..0a154c0cfd4 --- /dev/null +++ b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer_corpus/timeout-7a3822831087e0f79e2743c8f87650cc34a18898 @@ -0,0 +1,5 @@ +resolver_args { + enable_srv_queries: true +} +txt_response { +} diff --git a/test/core/ext/filters/event_engine_client_channel_resolver/resolver_ops.proto b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_ops.proto new file mode 100644 index 00000000000..25c971254be --- /dev/null +++ b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_ops.proto @@ -0,0 +1,80 @@ +// Copyright 2021 gRPC authors. +// +// 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 = "proto3"; + +import "src/proto/grpc/service_config/service_config.proto"; + +package event_engine_client_channel_resolver; + +message ResolverArgs { + bool request_service_config = 2; + bool enable_srv_queries = 3; +} + +message Error { + uint32 code = 1; + string message = 2; +} + +message ResolvedAddress { + uint32 port = 1; +} +message ResolvedAddresses { + repeated ResolvedAddress addresses = 1; +} + +message SRVRecord { + string host = 1; + uint32 port = 2; + uint32 priority = 3; + uint32 weight = 4; +} +message SRVRecords { + repeated SRVRecord srv_records = 1; +} + +enum TXTRecordType { + TXT_VALID = 0; + TXT_RANDOM_NON_CONFIG = 1; + TXT_RANDOM_PREFIXED_CONFIG = 2; +} +message TXTRecord { + oneof record { + TXTRecordType enumerated_value = 1; + grpc.service_config.ServiceConfig fuzzed_service_config = 2; + } + // Random TXT record content, used for some TXTRecordTypes. + string arbitrary_value = 3; +} +message TXTRecords { + repeated TXTRecord txt_records = 1; +} + +message Msg { + ResolverArgs resolver_args = 1; + oneof hostname { + ResolvedAddresses hostname_response = 2; + Error hostname_error = 3; + } + oneof srv { + SRVRecords srv_response = 4; + Error srv_error = 5; + } + oneof txt { + TXTRecords txt_response = 6; + Error txt_error = 7; + } + // TODO(hork): consider if cancellation responses can be fuzzed +}