Module: Async::GRPC::XDS::ResourceBuilder

Defined in:
lib/async/grpc/xds/resource_builder.rb

Overview

Builds Envoy xDS resource protobufs.

Constant Summary collapse

TYPE_URL_PREFIX =
"type.googleapis.com"
CLUSTER_TYPE =
"#{TYPE_URL_PREFIX}/envoy.config.cluster.v3.Cluster"
ENDPOINT_TYPE =
"#{TYPE_URL_PREFIX}/envoy.config.endpoint.v3.ClusterLoadAssignment"

Class Method Summary collapse

Class Method Details

.cluster(name, service_name: name, load_balancer_policy: :round_robin, connect_timeout: 5, protocol: :http2) ⇒ Object

Build an EDS cluster resource.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/async/grpc/xds/resource_builder.rb', line 45

def self.cluster(name, service_name: name, load_balancer_policy: :round_robin, connect_timeout: 5, protocol: :http2)
	options = {
		name: name.to_s,
		type: Envoy::Config::Cluster::V3::Cluster::DiscoveryType::EDS,
		eds_cluster_config: Envoy::Config::Cluster::V3::Cluster::EdsClusterConfig.new(
			service_name: service_name.to_s,
			eds_config: Envoy::Config::Core::V3::ConfigSource.new(
				ads: Envoy::Config::Core::V3::AggregatedConfigSource.new
			)
		),
		connect_timeout: duration(connect_timeout),
		lb_policy: load_balancer_policy_value(load_balancer_policy),
	}
	
	case protocol
	when :http1
		# Envoy uses HTTP/1 by default.
	when :http2
		options[:http2_protocol_options] = Envoy::Config::Core::V3::Http2ProtocolOptions.new
	else
		raise ArgumentError, "Unsupported upstream protocol: #{protocol.inspect}"
	end
	
	Envoy::Config::Cluster::V3::Cluster.new(**options)
end

.cluster_load_assignment(cluster_name, endpoints) ⇒ Object

Build an EDS cluster load assignment from normalized endpoint state.



75
76
77
78
79
80
81
82
83
84
# File 'lib/async/grpc/xds/resource_builder.rb', line 75

def self.cluster_load_assignment(cluster_name, endpoints)
	Envoy::Config::Endpoint::V3::ClusterLoadAssignment.new(
		cluster_name: cluster_name.to_s,
		endpoints: [
			Envoy::Config::Endpoint::V3::LocalityLbEndpoints.new(
				lb_endpoints: endpoints.map{|endpoint| load_balancer_endpoint(endpoint)}
			)
		]
	)
end

.duration(seconds) ⇒ Object

Convert seconds to a protobuf duration.



136
137
138
139
140
141
# File 'lib/async/grpc/xds/resource_builder.rb', line 136

def self.duration(seconds)
	whole_seconds = seconds.to_i
	nanos = ((seconds.to_f - whole_seconds) * 1_000_000_000).to_i
	
	Google::Protobuf::Duration.new(seconds: whole_seconds, nanos: nanos)
end

.health_status_value(healthy) ⇒ Object

Convert an endpoint health status to its Envoy enum value.



162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/async/grpc/xds/resource_builder.rb', line 162

def self.health_status_value(healthy)
	case healthy
	when :healthy, :HEALTHY, "healthy", "HEALTHY", true
		Envoy::Config::Core::V3::HealthStatus::HEALTHY
	when :unhealthy, :UNHEALTHY, "unhealthy", "UNHEALTHY", false
		Envoy::Config::Core::V3::HealthStatus::UNHEALTHY
	when :degraded, :DEGRADED, "degraded", "DEGRADED"
		Envoy::Config::Core::V3::HealthStatus::DEGRADED
	else
		Envoy::Config::Core::V3::HealthStatus::UNKNOWN
	end
end

.load_balancer_endpoint(endpoint) ⇒ Object

Build an Envoy load-balancer endpoint from normalized endpoint state.

Raises:

  • (ArgumentError)


91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/async/grpc/xds/resource_builder.rb', line 91

def self.load_balancer_endpoint(endpoint)
	addresses, healthy = endpoint.fetch_values(:addresses, :healthy)
	raise ArgumentError, "An endpoint requires at least one address!" if addresses.empty?
	
	address, *additional_addresses = addresses
	
	Envoy::Config::Endpoint::V3::LbEndpoint.new(
		endpoint: Envoy::Config::Endpoint::V3::Endpoint.new(
			address: build_address(address),
			additional_addresses: additional_addresses.map do |additional_address|
				Envoy::Config::Endpoint::V3::Endpoint::AdditionalAddress.new(
					address: build_address(additional_address)
				)
			end
		),
		health_status: health_status_value(healthy)
	)
end

.load_balancer_policy_value(load_balancer_policy) ⇒ Object

Convert a load-balancer policy name to its Envoy enum value.



146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/async/grpc/xds/resource_builder.rb', line 146

def self.load_balancer_policy_value(load_balancer_policy)
	case load_balancer_policy
	when :round_robin, :ROUND_ROBIN, "round_robin", "ROUND_ROBIN"
		Envoy::Config::Cluster::V3::Cluster::LbPolicy::ROUND_ROBIN
	when :least_request, :LEAST_REQUEST, "least_request", "LEAST_REQUEST"
		Envoy::Config::Cluster::V3::Cluster::LbPolicy::LEAST_REQUEST
	when :random, :RANDOM, "random", "RANDOM"
		Envoy::Config::Cluster::V3::Cluster::LbPolicy::RANDOM
	else
		load_balancer_policy
	end
end

.pack(resource) ⇒ Object

Pack a protobuf resource into a google.protobuf.Any message.



30
31
32
33
34
35
# File 'lib/async/grpc/xds/resource_builder.rb', line 30

def self.pack(resource)
	Google::Protobuf::Any.new(
		type_url: "#{TYPE_URL_PREFIX}/#{resource.class.descriptor.name}",
		value: resource.to_proto
	)
end