Add L7 and PROXY protocol fields to gRPC API and CLI

Proto: Route message gains mode, tls_cert, tls_key, backend_tls,
send_proxy_protocol fields. ListenerStatus gains proxy_protocol.
Generated code regenerated with protoc v29.5.

gRPC server: AddRoute validates mode ("l4"/"l7", defaults to "l4"),
requires tls_cert/tls_key for L7 routes, persists all fields via
write-through. ListRoutes returns full route info. GetStatus
includes proxy_protocol on listener status.

Client package: Route struct expanded with Mode, TLSCert, TLSKey,
BackendTLS, SendProxyProtocol. AddRoute signature changed to accept
a Route struct instead of individual hostname/backend strings.
ListenerStatus gains ProxyProtocol. ListRoutes maps all proto fields.

mcproxyctl: routes add gains --mode, --tls-cert, --tls-key,
--backend-tls, --send-proxy-protocol flags. routes list displays
mode and option tags for each route.

New tests: add L7 route via gRPC with field round-trip verification,
L7 route missing cert/key (InvalidArgument), invalid mode rejection,
default-to-L4 backward compatibility, proxy_protocol in status.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-25 13:55:43 -07:00
parent 97909b7fbc
commit 498f040cbe
9 changed files with 341 additions and 35 deletions

View File

@@ -40,10 +40,15 @@ func (c *Client) Close() error {
return c.conn.Close()
}
// Route represents a hostname to backend mapping.
// Route represents a hostname to backend mapping with mode and options.
type Route struct {
Hostname string
Backend string
Hostname string
Backend string
Mode string // "l4" or "l7"
TLSCert string
TLSKey string
BackendTLS bool
SendProxyProtocol bool
}
// ListRoutes returns all routes for the given listener address.
@@ -58,20 +63,30 @@ func (c *Client) ListRoutes(ctx context.Context, listenerAddr string) ([]Route,
routes := make([]Route, len(resp.Routes))
for i, r := range resp.Routes {
routes[i] = Route{
Hostname: r.Hostname,
Backend: r.Backend,
Hostname: r.Hostname,
Backend: r.Backend,
Mode: r.Mode,
TLSCert: r.TlsCert,
TLSKey: r.TlsKey,
BackendTLS: r.BackendTls,
SendProxyProtocol: r.SendProxyProtocol,
}
}
return routes, nil
}
// AddRoute adds a route to the given listener.
func (c *Client) AddRoute(ctx context.Context, listenerAddr, hostname, backend string) error {
func (c *Client) AddRoute(ctx context.Context, listenerAddr string, route Route) error {
_, err := c.admin.AddRoute(ctx, &pb.AddRouteRequest{
ListenerAddr: listenerAddr,
Route: &pb.Route{
Hostname: hostname,
Backend: backend,
Hostname: route.Hostname,
Backend: route.Backend,
Mode: route.Mode,
TlsCert: route.TLSCert,
TlsKey: route.TLSKey,
BackendTls: route.BackendTLS,
SendProxyProtocol: route.SendProxyProtocol,
},
})
return err
@@ -145,6 +160,7 @@ type ListenerStatus struct {
Addr string
RouteCount int
ActiveConnections int64
ProxyProtocol bool
}
// Status contains the server's current status.
@@ -176,6 +192,7 @@ func (c *Client) GetStatus(ctx context.Context) (*Status, error) {
Addr: ls.Addr,
RouteCount: int(ls.RouteCount),
ActiveConnections: ls.ActiveConnections,
ProxyProtocol: ls.ProxyProtocol,
}
}

View File

@@ -219,7 +219,7 @@ func TestClientAddRemoveRoute(t *testing.T) {
ctx := context.Background()
// Add a new route.
err := client.AddRoute(ctx, ":443", "new.test", "127.0.0.1:9443")
err := client.AddRoute(ctx, ":443", Route{Hostname: "new.test", Backend: "127.0.0.1:9443"})
if err != nil {
t.Fatalf("AddRoute: %v", err)
}