TUN-1828: Update declarative tunnel config struct
This commit is contained in:
parent
4bff1ef9df
commit
1485ca0fc7
2
Makefile
2
Makefile
|
@ -70,7 +70,7 @@ tunnel-deps: tunnelrpc/tunnelrpc.capnp.go
|
||||||
tunnelrpc/tunnelrpc.capnp.go: tunnelrpc/tunnelrpc.capnp
|
tunnelrpc/tunnelrpc.capnp.go: tunnelrpc/tunnelrpc.capnp
|
||||||
which capnp # https://capnproto.org/install.html
|
which capnp # https://capnproto.org/install.html
|
||||||
which capnpc-go # go get zombiezen.com/go/capnproto2/capnpc-go
|
which capnpc-go # go get zombiezen.com/go/capnproto2/capnpc-go
|
||||||
capnp compile -ogo -I ./tunnelrpc tunnelrpc/tunnelrpc.capnp
|
capnp compile -ogo tunnelrpc/tunnelrpc.capnp
|
||||||
|
|
||||||
.PHONY: vet
|
.PHONY: vet
|
||||||
vet:
|
vet:
|
||||||
|
|
|
@ -15,8 +15,8 @@ import (
|
||||||
/// Structs
|
/// Structs
|
||||||
///
|
///
|
||||||
|
|
||||||
type CloudflaredConfig struct {
|
type ClientConfig struct {
|
||||||
Timestamp time.Time
|
Version uint64
|
||||||
AutoUpdateFrequency time.Duration
|
AutoUpdateFrequency time.Duration
|
||||||
MetricsUpdateFrequency time.Duration
|
MetricsUpdateFrequency time.Duration
|
||||||
HeartbeatInterval time.Duration
|
HeartbeatInterval time.Duration
|
||||||
|
@ -24,6 +24,7 @@ type CloudflaredConfig struct {
|
||||||
GracePeriod time.Duration
|
GracePeriod time.Duration
|
||||||
DoHProxyConfigs []*DoHProxyConfig
|
DoHProxyConfigs []*DoHProxyConfig
|
||||||
ReverseProxyConfigs []*ReverseProxyConfig
|
ReverseProxyConfigs []*ReverseProxyConfig
|
||||||
|
NumHAConnections uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
type UseConfigurationResult struct {
|
type UseConfigurationResult struct {
|
||||||
|
@ -38,7 +39,7 @@ type DoHProxyConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReverseProxyConfig struct {
|
type ReverseProxyConfig struct {
|
||||||
TunnelID string
|
TunnelHostname string
|
||||||
Origin OriginConfig
|
Origin OriginConfig
|
||||||
Retries uint64
|
Retries uint64
|
||||||
ConnectionTimeout time.Duration
|
ConnectionTimeout time.Duration
|
||||||
|
@ -46,6 +47,27 @@ type ReverseProxyConfig struct {
|
||||||
CompressionQuality uint64
|
CompressionQuality uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewReverseProxyConfig(
|
||||||
|
tunnelHostname string,
|
||||||
|
originConfig OriginConfig,
|
||||||
|
retries uint64,
|
||||||
|
connectionTimeout time.Duration,
|
||||||
|
chunkedEncoding bool,
|
||||||
|
compressionQuality uint64,
|
||||||
|
) (*ReverseProxyConfig, error) {
|
||||||
|
if originConfig == nil {
|
||||||
|
return nil, fmt.Errorf("NewReverseProxyConfig: originConfig was null")
|
||||||
|
}
|
||||||
|
return &ReverseProxyConfig{
|
||||||
|
TunnelHostname: tunnelHostname,
|
||||||
|
Origin: originConfig,
|
||||||
|
Retries: retries,
|
||||||
|
ConnectionTimeout: connectionTimeout,
|
||||||
|
ChunkedEncoding: chunkedEncoding,
|
||||||
|
CompressionQuality: compressionQuality,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
//go-sumtype:decl OriginConfig
|
//go-sumtype:decl OriginConfig
|
||||||
type OriginConfig interface {
|
type OriginConfig interface {
|
||||||
isOriginConfig()
|
isOriginConfig()
|
||||||
|
@ -81,29 +103,31 @@ type HelloWorldOriginConfig struct{}
|
||||||
|
|
||||||
func (_ *HelloWorldOriginConfig) isOriginConfig() {}
|
func (_ *HelloWorldOriginConfig) isOriginConfig() {}
|
||||||
|
|
||||||
///
|
/*
|
||||||
/// Boilerplate to convert between these structs and the primitive structs generated by capnp-go
|
* Boilerplate to convert between these structs and the primitive structs
|
||||||
///
|
* generated by capnp-go.
|
||||||
|
* Mnemonics for variable names in this section:
|
||||||
|
* - `p` is for POGS (plain old Go struct)
|
||||||
|
* - `s` (and `ss`) is for "capnp.Struct", which is the fundamental type
|
||||||
|
* underlying the capnp-go data structures.
|
||||||
|
*/
|
||||||
|
|
||||||
func MarshalCloudflaredConfig(s tunnelrpc.CloudflaredConfig, p *CloudflaredConfig) error {
|
func MarshalClientConfig(s tunnelrpc.ClientConfig, p *ClientConfig) error {
|
||||||
s.SetTimestamp(p.Timestamp.UnixNano())
|
s.SetVersion(p.Version)
|
||||||
s.SetAutoUpdateFrequency(p.AutoUpdateFrequency.Nanoseconds())
|
s.SetAutoUpdateFrequency(p.AutoUpdateFrequency.Nanoseconds())
|
||||||
s.SetMetricsUpdateFrequency(p.MetricsUpdateFrequency.Nanoseconds())
|
s.SetMetricsUpdateFrequency(p.MetricsUpdateFrequency.Nanoseconds())
|
||||||
s.SetHeartbeatInterval(p.HeartbeatInterval.Nanoseconds())
|
s.SetHeartbeatInterval(p.HeartbeatInterval.Nanoseconds())
|
||||||
s.SetMaxFailedHeartbeats(p.MaxFailedHeartbeats)
|
s.SetMaxFailedHeartbeats(p.MaxFailedHeartbeats)
|
||||||
s.SetGracePeriod(p.GracePeriod.Nanoseconds())
|
s.SetGracePeriod(p.GracePeriod.Nanoseconds())
|
||||||
|
s.SetNumHAConnections(p.NumHAConnections)
|
||||||
err := marshalDoHProxyConfigs(s, p.DoHProxyConfigs)
|
err := marshalDoHProxyConfigs(s, p.DoHProxyConfigs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = marshalReverseProxyConfigs(s, p.ReverseProxyConfigs)
|
return marshalReverseProxyConfigs(s, p.ReverseProxyConfigs)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func marshalDoHProxyConfigs(s tunnelrpc.CloudflaredConfig, dohProxyConfigs []*DoHProxyConfig) error {
|
func marshalDoHProxyConfigs(s tunnelrpc.ClientConfig, dohProxyConfigs []*DoHProxyConfig) error {
|
||||||
capnpList, err := s.NewDohProxyConfigs(int32(len(dohProxyConfigs)))
|
capnpList, err := s.NewDohProxyConfigs(int32(len(dohProxyConfigs)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -117,7 +141,7 @@ func marshalDoHProxyConfigs(s tunnelrpc.CloudflaredConfig, dohProxyConfigs []*Do
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func marshalReverseProxyConfigs(s tunnelrpc.CloudflaredConfig, reverseProxyConfigs []*ReverseProxyConfig) error {
|
func marshalReverseProxyConfigs(s tunnelrpc.ClientConfig, reverseProxyConfigs []*ReverseProxyConfig) error {
|
||||||
capnpList, err := s.NewReverseProxyConfigs(int32(len(reverseProxyConfigs)))
|
capnpList, err := s.NewReverseProxyConfigs(int32(len(reverseProxyConfigs)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -131,14 +155,15 @@ func marshalReverseProxyConfigs(s tunnelrpc.CloudflaredConfig, reverseProxyConfi
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnmarshalCloudflaredConfig(s tunnelrpc.CloudflaredConfig) (*CloudflaredConfig, error) {
|
func UnmarshalClientConfig(s tunnelrpc.ClientConfig) (*ClientConfig, error) {
|
||||||
p := new(CloudflaredConfig)
|
p := new(ClientConfig)
|
||||||
p.Timestamp = time.Unix(0, s.Timestamp()).UTC()
|
p.Version = s.Version()
|
||||||
p.AutoUpdateFrequency = time.Duration(s.AutoUpdateFrequency())
|
p.AutoUpdateFrequency = time.Duration(s.AutoUpdateFrequency())
|
||||||
p.MetricsUpdateFrequency = time.Duration(s.MetricsUpdateFrequency())
|
p.MetricsUpdateFrequency = time.Duration(s.MetricsUpdateFrequency())
|
||||||
p.HeartbeatInterval = time.Duration(s.HeartbeatInterval())
|
p.HeartbeatInterval = time.Duration(s.HeartbeatInterval())
|
||||||
p.MaxFailedHeartbeats = s.MaxFailedHeartbeats()
|
p.MaxFailedHeartbeats = s.MaxFailedHeartbeats()
|
||||||
p.GracePeriod = time.Duration(s.GracePeriod())
|
p.GracePeriod = time.Duration(s.GracePeriod())
|
||||||
|
p.NumHAConnections = s.NumHAConnections()
|
||||||
dohProxyConfigs, err := unmarshalDoHProxyConfigs(s)
|
dohProxyConfigs, err := unmarshalDoHProxyConfigs(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -152,7 +177,7 @@ func UnmarshalCloudflaredConfig(s tunnelrpc.CloudflaredConfig) (*CloudflaredConf
|
||||||
return p, err
|
return p, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalDoHProxyConfigs(s tunnelrpc.CloudflaredConfig) ([]*DoHProxyConfig, error) {
|
func unmarshalDoHProxyConfigs(s tunnelrpc.ClientConfig) ([]*DoHProxyConfig, error) {
|
||||||
var result []*DoHProxyConfig
|
var result []*DoHProxyConfig
|
||||||
marshalledDoHProxyConfigs, err := s.DohProxyConfigs()
|
marshalledDoHProxyConfigs, err := s.DohProxyConfigs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -169,7 +194,7 @@ func unmarshalDoHProxyConfigs(s tunnelrpc.CloudflaredConfig) ([]*DoHProxyConfig,
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalReverseProxyConfigs(s tunnelrpc.CloudflaredConfig) ([]*ReverseProxyConfig, error) {
|
func unmarshalReverseProxyConfigs(s tunnelrpc.ClientConfig) ([]*ReverseProxyConfig, error) {
|
||||||
var result []*ReverseProxyConfig
|
var result []*ReverseProxyConfig
|
||||||
marshalledReverseProxyConfigs, err := s.ReverseProxyConfigs()
|
marshalledReverseProxyConfigs, err := s.ReverseProxyConfigs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -207,7 +232,7 @@ func UnmarshalDoHProxyConfig(s tunnelrpc.DoHProxyConfig) (*DoHProxyConfig, error
|
||||||
}
|
}
|
||||||
|
|
||||||
func MarshalReverseProxyConfig(s tunnelrpc.ReverseProxyConfig, p *ReverseProxyConfig) error {
|
func MarshalReverseProxyConfig(s tunnelrpc.ReverseProxyConfig, p *ReverseProxyConfig) error {
|
||||||
s.SetTunnelID(p.TunnelID)
|
s.SetTunnelHostname(p.TunnelHostname)
|
||||||
switch config := p.Origin.(type) {
|
switch config := p.Origin.(type) {
|
||||||
case *HTTPOriginConfig:
|
case *HTTPOriginConfig:
|
||||||
ss, err := s.Origin().NewHttp()
|
ss, err := s.Origin().NewHttp()
|
||||||
|
@ -245,11 +270,11 @@ func MarshalReverseProxyConfig(s tunnelrpc.ReverseProxyConfig, p *ReverseProxyCo
|
||||||
|
|
||||||
func UnmarshalReverseProxyConfig(s tunnelrpc.ReverseProxyConfig) (*ReverseProxyConfig, error) {
|
func UnmarshalReverseProxyConfig(s tunnelrpc.ReverseProxyConfig) (*ReverseProxyConfig, error) {
|
||||||
p := new(ReverseProxyConfig)
|
p := new(ReverseProxyConfig)
|
||||||
tunnelID, err := s.TunnelID()
|
tunnelHostname, err := s.TunnelHostname()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
p.TunnelID = tunnelID
|
p.TunnelHostname = tunnelHostname
|
||||||
switch s.Origin().Which() {
|
switch s.Origin().Which() {
|
||||||
case tunnelrpc.ReverseProxyConfig_origin_Which_http:
|
case tunnelrpc.ReverseProxyConfig_origin_Which_http:
|
||||||
ss, err := s.Origin().Http()
|
ss, err := s.Origin().Http()
|
||||||
|
@ -339,31 +364,30 @@ func UnmarshalHelloWorldOriginConfig(s tunnelrpc.HelloWorldOriginConfig) (*Hello
|
||||||
return p, err
|
return p, err
|
||||||
}
|
}
|
||||||
|
|
||||||
type CloudflaredServer interface {
|
type ClientService interface {
|
||||||
UseConfiguration(ctx context.Context, config *CloudflaredConfig) (*CloudflaredConfig, error)
|
UseConfiguration(ctx context.Context, config *ClientConfig) (*ClientConfig, error)
|
||||||
GetConfiguration(ctx context.Context) (*CloudflaredConfig, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CloudflaredServer_PogsClient struct {
|
type ClientService_PogsClient struct {
|
||||||
Client capnp.Client
|
Client capnp.Client
|
||||||
Conn *rpc.Conn
|
Conn *rpc.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CloudflaredServer_PogsClient) Close() error {
|
func (c *ClientService_PogsClient) Close() error {
|
||||||
return c.Conn.Close()
|
return c.Conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CloudflaredServer_PogsClient) UseConfiguration(
|
func (c *ClientService_PogsClient) UseConfiguration(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
config *CloudflaredConfig,
|
config *ClientConfig,
|
||||||
) (*UseConfigurationResult, error) {
|
) (*UseConfigurationResult, error) {
|
||||||
client := tunnelrpc.CloudflaredServer{Client: c.Client}
|
client := tunnelrpc.ClientService{Client: c.Client}
|
||||||
promise := client.UseConfiguration(ctx, func(p tunnelrpc.CloudflaredServer_useConfiguration_Params) error {
|
promise := client.UseConfiguration(ctx, func(p tunnelrpc.ClientService_useConfiguration_Params) error {
|
||||||
cloudflaredConfig, err := p.NewCloudflaredConfig()
|
clientServiceConfig, err := p.NewClientConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return MarshalCloudflaredConfig(cloudflaredConfig, config)
|
return MarshalClientConfig(clientServiceConfig, config)
|
||||||
})
|
})
|
||||||
retval, err := promise.Result().Struct()
|
retval, err := promise.Result().Struct()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package pogs
|
package pogs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -10,15 +12,18 @@ import (
|
||||||
capnp "zombiezen.com/go/capnproto2"
|
capnp "zombiezen.com/go/capnproto2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCloudflaredConfig(t *testing.T) {
|
func TestClientConfig(t *testing.T) {
|
||||||
addDoHProxyConfigs := func(c *CloudflaredConfig) {
|
addDoHProxyConfigs := func(c *ClientConfig) {
|
||||||
c.DoHProxyConfigs = []*DoHProxyConfig{
|
c.DoHProxyConfigs = []*DoHProxyConfig{
|
||||||
sampleDoHProxyConfig(),
|
sampleDoHProxyConfig(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addReverseProxyConfigs := func(c *CloudflaredConfig) {
|
addReverseProxyConfigs := func(c *ClientConfig) {
|
||||||
c.ReverseProxyConfigs = []*ReverseProxyConfig{
|
c.ReverseProxyConfigs = []*ReverseProxyConfig{
|
||||||
sampleReverseProxyConfig(),
|
sampleReverseProxyConfig(),
|
||||||
|
sampleReverseProxyConfig(func(c *ReverseProxyConfig) {
|
||||||
|
c.ChunkedEncoding = false
|
||||||
|
}),
|
||||||
sampleReverseProxyConfig(func(c *ReverseProxyConfig) {
|
sampleReverseProxyConfig(func(c *ReverseProxyConfig) {
|
||||||
c.Origin = sampleHTTPOriginConfig()
|
c.Origin = sampleHTTPOriginConfig()
|
||||||
}),
|
}),
|
||||||
|
@ -31,23 +36,23 @@ func TestCloudflaredConfig(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []*CloudflaredConfig{
|
testCases := []*ClientConfig{
|
||||||
sampleCloudflaredConfig(),
|
sampleClientConfig(),
|
||||||
sampleCloudflaredConfig(addDoHProxyConfigs),
|
sampleClientConfig(addDoHProxyConfigs),
|
||||||
sampleCloudflaredConfig(addReverseProxyConfigs),
|
sampleClientConfig(addReverseProxyConfigs),
|
||||||
sampleCloudflaredConfig(addDoHProxyConfigs, addReverseProxyConfigs),
|
sampleClientConfig(addDoHProxyConfigs, addReverseProxyConfigs),
|
||||||
}
|
}
|
||||||
for i, testCase := range testCases {
|
for i, testCase := range testCases {
|
||||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||||
capnpEntity, err := tunnelrpc.NewCloudflaredConfig(seg)
|
capnpEntity, err := tunnelrpc.NewClientConfig(seg)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.Fatal("Couldn't initialize a new message")
|
t.Fatal("Couldn't initialize a new message")
|
||||||
}
|
}
|
||||||
err = MarshalCloudflaredConfig(capnpEntity, testCase)
|
err = MarshalClientConfig(capnpEntity, testCase)
|
||||||
if !assert.NoError(t, err, "testCase index %v failed to marshal", i) {
|
if !assert.NoError(t, err, "testCase index %v failed to marshal", i) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
result, err := UnmarshalCloudflaredConfig(capnpEntity)
|
result, err := UnmarshalClientConfig(capnpEntity)
|
||||||
if !assert.NoError(t, err, "testCase index %v failed to unmarshal", i) {
|
if !assert.NoError(t, err, "testCase index %v failed to unmarshal", i) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -208,18 +213,17 @@ func TestWebSocketOriginConfig(t *testing.T) {
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// Functions to generate sample data for ease of testing
|
// Functions to generate sample data for ease of testing
|
||||||
|
|
||||||
func sampleCloudflaredConfig(overrides ...func(*CloudflaredConfig)) *CloudflaredConfig {
|
func sampleClientConfig(overrides ...func(*ClientConfig)) *ClientConfig {
|
||||||
// strip the location and monotonic clock reading so that assert.Equals()
|
sample := &ClientConfig{
|
||||||
// will work correctly
|
Version: uint64(1337),
|
||||||
now := time.Now().UTC().Round(0)
|
|
||||||
sample := &CloudflaredConfig{
|
|
||||||
Timestamp: now,
|
|
||||||
AutoUpdateFrequency: 21 * time.Hour,
|
AutoUpdateFrequency: 21 * time.Hour,
|
||||||
MetricsUpdateFrequency: 11 * time.Minute,
|
MetricsUpdateFrequency: 11 * time.Minute,
|
||||||
HeartbeatInterval: 5 * time.Second,
|
HeartbeatInterval: 5 * time.Second,
|
||||||
MaxFailedHeartbeats: 9001,
|
MaxFailedHeartbeats: 9001,
|
||||||
GracePeriod: 31 * time.Second,
|
GracePeriod: 31 * time.Second,
|
||||||
|
NumHAConnections: 49,
|
||||||
}
|
}
|
||||||
|
sample.ensureNoZeroFields()
|
||||||
for _, f := range overrides {
|
for _, f := range overrides {
|
||||||
f(sample)
|
f(sample)
|
||||||
}
|
}
|
||||||
|
@ -232,6 +236,7 @@ func sampleDoHProxyConfig(overrides ...func(*DoHProxyConfig)) *DoHProxyConfig {
|
||||||
ListenPort: 53,
|
ListenPort: 53,
|
||||||
Upstreams: []string{"https://1.example.com", "https://2.example.com"},
|
Upstreams: []string{"https://1.example.com", "https://2.example.com"},
|
||||||
}
|
}
|
||||||
|
sample.ensureNoZeroFields()
|
||||||
for _, f := range overrides {
|
for _, f := range overrides {
|
||||||
f(sample)
|
f(sample)
|
||||||
}
|
}
|
||||||
|
@ -240,13 +245,14 @@ func sampleDoHProxyConfig(overrides ...func(*DoHProxyConfig)) *DoHProxyConfig {
|
||||||
|
|
||||||
func sampleReverseProxyConfig(overrides ...func(*ReverseProxyConfig)) *ReverseProxyConfig {
|
func sampleReverseProxyConfig(overrides ...func(*ReverseProxyConfig)) *ReverseProxyConfig {
|
||||||
sample := &ReverseProxyConfig{
|
sample := &ReverseProxyConfig{
|
||||||
TunnelID: "hijk",
|
TunnelHostname: "hijk.example.com",
|
||||||
Origin: &HelloWorldOriginConfig{},
|
Origin: &HelloWorldOriginConfig{},
|
||||||
Retries: 18,
|
Retries: 18,
|
||||||
ConnectionTimeout: 5 * time.Second,
|
ConnectionTimeout: 5 * time.Second,
|
||||||
ChunkedEncoding: false,
|
ChunkedEncoding: true,
|
||||||
CompressionQuality: 4,
|
CompressionQuality: 4,
|
||||||
}
|
}
|
||||||
|
sample.ensureNoZeroFields()
|
||||||
for _, f := range overrides {
|
for _, f := range overrides {
|
||||||
f(sample)
|
f(sample)
|
||||||
}
|
}
|
||||||
|
@ -265,6 +271,7 @@ func sampleHTTPOriginConfig(overrides ...func(*HTTPOriginConfig)) *HTTPOriginCon
|
||||||
MaxIdleConnections: 19,
|
MaxIdleConnections: 19,
|
||||||
IdleConnectionTimeout: 17 * time.Second,
|
IdleConnectionTimeout: 17 * time.Second,
|
||||||
}
|
}
|
||||||
|
sample.ensureNoZeroFields()
|
||||||
for _, f := range overrides {
|
for _, f := range overrides {
|
||||||
f(sample)
|
f(sample)
|
||||||
}
|
}
|
||||||
|
@ -275,6 +282,7 @@ func sampleUnixSocketOriginConfig(overrides ...func(*UnixSocketOriginConfig)) *U
|
||||||
sample := &UnixSocketOriginConfig{
|
sample := &UnixSocketOriginConfig{
|
||||||
Path: "/var/lib/file.sock",
|
Path: "/var/lib/file.sock",
|
||||||
}
|
}
|
||||||
|
sample.ensureNoZeroFields()
|
||||||
for _, f := range overrides {
|
for _, f := range overrides {
|
||||||
f(sample)
|
f(sample)
|
||||||
}
|
}
|
||||||
|
@ -285,8 +293,71 @@ func sampleWebSocketOriginConfig(overrides ...func(*WebSocketOriginConfig)) *Web
|
||||||
sample := &WebSocketOriginConfig{
|
sample := &WebSocketOriginConfig{
|
||||||
URL: "ssh://example.com",
|
URL: "ssh://example.com",
|
||||||
}
|
}
|
||||||
|
sample.ensureNoZeroFields()
|
||||||
for _, f := range overrides {
|
for _, f := range overrides {
|
||||||
f(sample)
|
f(sample)
|
||||||
}
|
}
|
||||||
return sample
|
return sample
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ClientConfig) ensureNoZeroFields() {
|
||||||
|
ensureNoZeroFieldsInSample(reflect.ValueOf(c), []string{"DoHProxyConfigs", "ReverseProxyConfigs"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *DoHProxyConfig) ensureNoZeroFields() {
|
||||||
|
ensureNoZeroFieldsInSample(reflect.ValueOf(c), []string{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ReverseProxyConfig) ensureNoZeroFields() {
|
||||||
|
ensureNoZeroFieldsInSample(reflect.ValueOf(c), []string{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *HTTPOriginConfig) ensureNoZeroFields() {
|
||||||
|
ensureNoZeroFieldsInSample(reflect.ValueOf(c), []string{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *UnixSocketOriginConfig) ensureNoZeroFields() {
|
||||||
|
ensureNoZeroFieldsInSample(reflect.ValueOf(c), []string{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *WebSocketOriginConfig) ensureNoZeroFields() {
|
||||||
|
ensureNoZeroFieldsInSample(reflect.ValueOf(c), []string{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensureNoZeroFieldsInSample checks that all fields in the sample struct,
|
||||||
|
// except those listed in `allowedZeroFieldNames`, are initialized to nonzero
|
||||||
|
// values. Note that the value has to be a pointer for reflection to work
|
||||||
|
// correctly:
|
||||||
|
// e := &ExampleStruct{ ... }
|
||||||
|
// ensureNoZeroFieldsInSample(reflect.ValueOf(e), []string{})
|
||||||
|
//
|
||||||
|
// Context:
|
||||||
|
// Our tests work by taking a sample struct and marshalling/unmarshalling it.
|
||||||
|
// This makes them easy to write, but introduces some risk: if we don't
|
||||||
|
// include a field in the sample value, it won't be covered under tests.
|
||||||
|
// This check reduces that risk by requiring fields to be either initialized
|
||||||
|
// or explicitly uninitialized.
|
||||||
|
// https://bitbucket.cfdata.org/projects/TUN/repos/cloudflared/pull-requests/151/overview?commentId=348012
|
||||||
|
func ensureNoZeroFieldsInSample(ptrToSampleValue reflect.Value, allowedZeroFieldNames []string) {
|
||||||
|
sampleValue := ptrToSampleValue.Elem()
|
||||||
|
structType := ptrToSampleValue.Type().Elem()
|
||||||
|
|
||||||
|
allowedZeroFieldSet := make(map[string]bool)
|
||||||
|
for _, name := range allowedZeroFieldNames {
|
||||||
|
if _, ok := structType.FieldByName(name); !ok {
|
||||||
|
panic(fmt.Sprintf("struct %v has no field %v", structType.Name(), name))
|
||||||
|
}
|
||||||
|
allowedZeroFieldSet[name] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < structType.NumField(); i++ {
|
||||||
|
if allowedZeroFieldSet[structType.Field(i).Name] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
zeroValue := reflect.Zero(structType.Field(i).Type)
|
||||||
|
if reflect.DeepEqual(zeroValue.Interface(), sampleValue.Field(i).Interface()) {
|
||||||
|
panic(fmt.Sprintf("In the sample value for struct %v, field %v was not initialized", structType.Name(), structType.Field(i).Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -72,10 +72,11 @@ struct ConnectError {
|
||||||
shouldRetry @2 :Bool;
|
shouldRetry @2 :Bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CloudflaredConfig {
|
struct ClientConfig {
|
||||||
# Timestamp (in ns) of this configuration. Any configuration supplied to
|
# Version of this configuration. This value is opaque, but is guaranteed
|
||||||
# useConfiguration() with an older timestamp should be ignored.
|
# to monotonically increase in value. Any configuration supplied to
|
||||||
timestamp @0 :Int64;
|
# useConfiguration() with a smaller `version` should be ignored.
|
||||||
|
version @0 :UInt64;
|
||||||
# Frequency (in ns) to check Equinox for updates.
|
# Frequency (in ns) to check Equinox for updates.
|
||||||
# Zero means auto-update is disabled.
|
# Zero means auto-update is disabled.
|
||||||
# cloudflared CLI option: `autoupdate-freq`
|
# cloudflared CLI option: `autoupdate-freq`
|
||||||
|
@ -101,10 +102,14 @@ struct CloudflaredConfig {
|
||||||
dohProxyConfigs @6 :List(DoHProxyConfig);
|
dohProxyConfigs @6 :List(DoHProxyConfig);
|
||||||
# Configuration for cloudflared to run as an HTTP reverse proxy.
|
# Configuration for cloudflared to run as an HTTP reverse proxy.
|
||||||
reverseProxyConfigs @7 :List(ReverseProxyConfig);
|
reverseProxyConfigs @7 :List(ReverseProxyConfig);
|
||||||
|
# Number of persistent connections to keep open between cloudflared and
|
||||||
|
# the edge.
|
||||||
|
# cloudflared CLI option: `ha-connections`
|
||||||
|
numHAConnections @8 :UInt8;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ReverseProxyConfig {
|
struct ReverseProxyConfig {
|
||||||
tunnelID @0 :Text;
|
tunnelHostname @0 :Text;
|
||||||
origin :union {
|
origin :union {
|
||||||
http @1 :HTTPOriginConfig;
|
http @1 :HTTPOriginConfig;
|
||||||
socket @2 :UnixSocketOriginConfig;
|
socket @2 :UnixSocketOriginConfig;
|
||||||
|
@ -230,6 +235,6 @@ interface TunnelServer {
|
||||||
connect @3 (parameters :CapnpConnectParameters) -> (result :ConnectResult);
|
connect @3 (parameters :CapnpConnectParameters) -> (result :ConnectResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CloudflaredServer {
|
interface ClientService {
|
||||||
useConfiguration @0 (cloudflaredConfig :CloudflaredConfig) -> (result :UseConfigurationResult);
|
useConfiguration @0 (clientServiceConfig :ClientConfig) -> (result :UseConfigurationResult);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue