Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Director ¶
type Director struct {
// contains filtered or unexported fields
}
Director manages routing of gRPC requests between local and remote backends.
func NewDirector ¶
func (*Director) Director ¶
func (d *Director) Director(ctx context.Context, fullMethodName string) (proxy.Mode, []proxy.Backend, error)
Director implements proxy.StreamDirector for grpc-proxy, routing requests to local or remote backends based on gRPC metadata in the context. Each machine metadata is injected into the response messages by the proxy if the request is proxied to multiple backends.
func (*Director) FlushRemoteBackends ¶
func (d *Director) FlushRemoteBackends()
FlushRemoteBackends closes all remote backend connections and removes them from the cache.
func (*Director) UpdateLocalAddress ¶
UpdateLocalAddress updates the local machine address used to identify which requests should be proxied to the local gRPC server.
type LocalBackend ¶
type LocalBackend struct { One2ManyResponder // contains filtered or unexported fields }
LocalBackend is a proxy.One2ManyResponder implementation that proxies to a local gRPC server listening on a Unix socket.
func NewLocalBackend ¶
func NewLocalBackend(sockPath, addr string) *LocalBackend
NewLocalBackend returns a new LocalBackend for the given Unix socket path. The addr parameter is the local address of the current machine which could be empty if it's not known. The address is used to populate response metadata in one2many mode.
func (*LocalBackend) Close ¶
func (b *LocalBackend) Close()
Close closes the upstream gRPC connection.
func (*LocalBackend) GetConnection ¶
func (b *LocalBackend) GetConnection(ctx context.Context, _ string) (context.Context, *grpc.ClientConn, error)
GetConnection returns a gRPC connection to the local server listening on the Unix socket.
func (*LocalBackend) String ¶
func (b *LocalBackend) String() string
type One2ManyResponder ¶
type One2ManyResponder struct {
// contains filtered or unexported fields
}
One2ManyResponder converts upstream responses into messages from upstreams, so that multiple successful and failure responses might be returned in One2Many mode.
func (*One2ManyResponder) AppendInfo ¶
func (b *One2ManyResponder) AppendInfo(streaming bool, resp []byte) ([]byte, error)
AppendInfo is called to enhance response from the backend with additional data.
AppendInfo enhances upstream response with machine metadata (target).
This method depends on grpc protobuf response structure, each response should look like:
message SomeResponse { repeated SomeReply messages = 1; // please note field ID == 1 } message SomeReply { common.Metadata metadata = 1; <other fields go here ...> }
As 'SomeReply' is repeated in 'SomeResponse', if we concatenate protobuf representation of several 'SomeResponse' messages, we still get valid 'SomeResponse' representation but with more entries (feature of protobuf binary representation).
If we look at binary representation of any unary 'SomeResponse' message, it will always contain one protobuf field with field ID 1 (see above) and type 2 (embedded message SomeReply is encoded as string with length). So if we want to add fields to 'SomeReply', we can simply read field header, adjust length for new 'SomeReply' representation, and prepend new field header.
At the same time, we can add 'common.Metadata' structure to 'SomeReply' by simply appending or prepending 'common.Metadata' as a single field. This requires 'metadata' field to be not defined in original response. (This is due to the fact that protobuf message representation is concatenation of each field representation).
To build only single field (Metadata) we use helper message which contains exactly this field with same field ID as in every other 'SomeReply':
message Empty { common.Metadata metadata = 1; }
As streaming replies are not wrapped into 'SomeResponse' with 'repeated', handling is simpler: we just need to append Empty with details.
So AppendInfo does the following: validates that response contains field ID 1 encoded as string, cuts field header, rest is representation of some reply. Marshal 'Empty' as protobuf, which builds 'common.Metadata' field, append it to original response message, build new header for new length of some response, and add back new field header.
func (*One2ManyResponder) BuildError ¶
func (b *One2ManyResponder) BuildError(streaming bool, err error) ([]byte, error)
BuildError converts upstream error into message from upstream, so that multiple successful and failure responses might be returned.
This simply relies on the fact that any response contains 'Empty' message. So if 'Empty' is unmarshalled into any other reply message, all the fields are undefined but 'Metadata':
message Empty { common.Metadata metadata = 1; } message EmptyResponse { repeated Empty messages = 1; }
Streaming responses are not wrapped into Empty, so we simply marshall EmptyResponse message.
type RemoteBackend ¶
type RemoteBackend struct { One2ManyResponder // contains filtered or unexported fields }
RemoteBackend is a proxy.One2ManyResponder implementation that proxies to a remote gRPC server, injecting machine metadata into the response.
Based on the Talos apid implementation: https://github.com/siderolabs/talos/blob/59a78da42cdea8fbccc35d0851f9b0eef928261b/internal/app/apid/pkg/backend/apid.go
func NewRemoteBackend ¶
func NewRemoteBackend(addr string, port uint16) (*RemoteBackend, error)
NewRemoteBackend creates a new instance of RemoteBackend for the given IPv6 address and port.
func (*RemoteBackend) Close ¶
func (b *RemoteBackend) Close()
Close closes the upstream gRPC connection.
func (*RemoteBackend) GetConnection ¶
func (b *RemoteBackend) GetConnection(ctx context.Context, _ string) (context.Context, *grpc.ClientConn, error)
GetConnection returns a gRPC connection to the remote server.
func (*RemoteBackend) String ¶
func (b *RemoteBackend) String() string