diff --git a/controller/controller.go b/controller/controller.go index 74fe35c0c..f64b84915 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -33,6 +33,7 @@ import ( "github.com/openziti/fabric/controller/xt_weighted" "github.com/openziti/fabric/controller/xtv" "github.com/openziti/foundation/channel2" + "github.com/openziti/foundation/common" "github.com/openziti/foundation/profiler" "github.com/openziti/foundation/util/concurrenz" "github.com/pkg/errors" @@ -53,7 +54,7 @@ type Controller struct { isShutdown concurrenz.AtomicBoolean } -func NewController(cfg *Config) (*Controller, error) { +func NewController(cfg *Config, versionProvider common.VersionProvider) (*Controller, error) { c := &Controller{ config: cfg, shutdownC: make(chan struct{}), @@ -64,7 +65,7 @@ func NewController(cfg *Config) (*Controller, error) { return nil, err } - if n, err := network.NewNetwork(cfg.Id, cfg.Network, cfg.Db, cfg.Metrics); err == nil { + if n, err := network.NewNetwork(cfg.Id, cfg.Network, cfg.Db, cfg.Metrics, versionProvider); err == nil { c.network = n } else { return nil, err @@ -83,11 +84,20 @@ func (c *Controller) Run() error { if err := c.registerComponents(); err != nil { return fmt.Errorf("error registering component: %s", err) } + versionInfo := c.network.VersionProvider.AsVersionInfo() + versionHeader, err := c.network.VersionProvider.EncoderDecoder().Encode(versionInfo) + + if err != nil { + pfxlog.Logger().Panicf("could not prepare version headers: %v", err) + } + headers := map[int32][]byte{ + channel2.HelloVersionHeader: versionHeader, + } /** * ctrl listener/accepter. */ - ctrlListener := channel2.NewClassicListener(c.config.Id, c.config.Ctrl.Listener, c.config.Ctrl.Options.ConnectOptions) + ctrlListener := channel2.NewClassicListener(c.config.Id, c.config.Ctrl.Listener, c.config.Ctrl.Options.ConnectOptions, headers) c.ctrlListener = ctrlListener if err := c.ctrlListener.Listen(c.ctrlConnectHandler); err != nil { panic(err) @@ -99,7 +109,7 @@ func (c *Controller) Run() error { /** * mgmt listener/accepter. */ - mgmtListener := channel2.NewClassicListener(c.config.Id, c.config.Mgmt.Listener, c.config.Mgmt.Options.ConnectOptions) + mgmtListener := channel2.NewClassicListener(c.config.Id, c.config.Mgmt.Listener, c.config.Mgmt.Options.ConnectOptions, headers) c.mgmtListener = mgmtListener if err := c.mgmtListener.Listen(c.mgmtConnectHandler); err != nil { panic(err) diff --git a/controller/handler_ctrl/accept.go b/controller/handler_ctrl/accept.go index e1848d366..2c9c839cb 100644 --- a/controller/handler_ctrl/accept.go +++ b/controller/handler_ctrl/accept.go @@ -52,6 +52,16 @@ func (ctrlAccepter *CtrlAccepter) Run() { if err == nil { if r, err := ctrlAccepter.network.GetRouter(ch.Id().Token); err == nil { if ch.Underlay().Headers() != nil { + if versionValue, found := ch.Underlay().Headers()[channel2.HelloVersionHeader]; found { + if versionInfo, err := ctrlAccepter.network.VersionProvider.EncoderDecoder().Decode(versionValue); err == nil { + r.VersionInfo = versionInfo + } else { + log.Warnf("could not parse version info from router hello: %v", err) + } + } else { + log.Warn("no version info header") + } + if listenerValue, found := ch.Underlay().Headers()[channel2.HelloRouterAdvertisementsHeader]; found { listenerString := string(listenerValue) r.AdvertisedListener = listenerString diff --git a/controller/network/circuit_test.go b/controller/network/circuit_test.go index f54bd3506..4979f26a3 100644 --- a/controller/network/circuit_test.go +++ b/controller/network/circuit_test.go @@ -20,11 +20,14 @@ import ( "github.com/openziti/fabric/controller/db" "github.com/openziti/fabric/controller/models" "github.com/openziti/foundation/channel2" + "github.com/openziti/foundation/common" "github.com/openziti/foundation/identity/identity" "github.com/openziti/foundation/transport" "github.com/openziti/foundation/transport/tcp" "github.com/stretchr/testify/assert" + "runtime" "testing" + "time" ) func TestSimpleCircuit2(t *testing.T) { @@ -32,7 +35,7 @@ func TestSimpleCircuit2(t *testing.T) { defer ctx.Cleanup() nodeId := &identity.TokenId{Token: "test"} - network, err := NewNetwork(nodeId, nil, ctx.GetDb(), nil) + network, err := NewNetwork(nodeId, nil, ctx.GetDb(), nil, NewVersionProviderTest()) assert.Nil(t, err) addr := "tcp:0.0.0.0:0" @@ -94,7 +97,7 @@ func TestTransitCircuit2(t *testing.T) { defer ctx.Cleanup() nodeId := &identity.TokenId{Token: "test"} - network, err := NewNetwork(nodeId, nil, ctx.GetDb(), nil) + network, err := NewNetwork(nodeId, nil, ctx.GetDb(), nil, NewVersionProviderTest()) assert.Nil(t, err) addr := "tcp:0.0.0.0:0" @@ -183,3 +186,36 @@ func newRouterForTest(id string, fingerprint string, advLstnr transport.Address, } return r } + +type VersionProviderTest struct { +} + +func (v VersionProviderTest) EncoderDecoder() common.VersionEncDec { + return &common.StdVersionEncDec +} + +func (v VersionProviderTest) Version() string { + return "v0.0.0" +} + +func (v VersionProviderTest) BuildDate() string { + return time.Now().String() +} + +func (v VersionProviderTest) Revision() string { + return "" +} + +func (v VersionProviderTest) AsVersionInfo() *common.VersionInfo { + return &common.VersionInfo{ + Version: v.Version(), + Revision: v.Revision(), + BuildDate: v.BuildDate(), + OS: runtime.GOOS, + Arch: runtime.GOARCH, + } +} + +func NewVersionProviderTest() common.VersionProvider { + return &VersionProviderTest{} +} diff --git a/controller/network/network.go b/controller/network/network.go index 456edc2f1..5caab44e7 100644 --- a/controller/network/network.go +++ b/controller/network/network.go @@ -26,6 +26,7 @@ import ( "github.com/openziti/fabric/pb/ctrl_pb" "github.com/openziti/fabric/trace" "github.com/openziti/foundation/channel2" + "github.com/openziti/foundation/common" "github.com/openziti/foundation/event" "github.com/openziti/foundation/events" "github.com/openziti/foundation/identity/identity" @@ -62,9 +63,10 @@ type Network struct { strategyRegistry xt.Registry lastSnapshot time.Time metricsRegistry metrics.Registry + VersionProvider common.VersionProvider } -func NewNetwork(nodeId *identity.TokenId, options *Options, database boltz.Db, metricsCfg *metrics.Config) (*Network, error) { +func NewNetwork(nodeId *identity.TokenId, options *Options, database boltz.Db, metricsCfg *metrics.Config, versionProvider common.VersionProvider) (*Network, error) { stores, err := db.InitStores(database) if err != nil { return nil, err @@ -88,6 +90,7 @@ func NewNetwork(nodeId *identity.TokenId, options *Options, database boltz.Db, m strategyRegistry: xt.GlobalRegistry(), lastSnapshot: time.Now().Add(-time.Hour), metricsRegistry: metrics.NewRegistry(nodeId.Token, nil), + VersionProvider: versionProvider, } metrics.Init(metricsCfg) events.AddMetricsEventHandler(network) diff --git a/controller/network/path_test.go b/controller/network/path_test.go index b998b318e..09165e48f 100644 --- a/controller/network/path_test.go +++ b/controller/network/path_test.go @@ -31,7 +31,7 @@ func TestShortestPath(t *testing.T) { req := assert.New(t) nodeId := &identity.TokenId{Token: "test"} - network, err := NewNetwork(nodeId, nil, ctx.GetDb(), nil) + network, err := NewNetwork(nodeId, nil, ctx.GetDb(), nil, NewVersionProviderTest()) req.NoError(err) addr := "tcp:0.0.0.0:0" diff --git a/controller/network/router.go b/controller/network/router.go index aea6e0152..41ebe41a9 100644 --- a/controller/network/router.go +++ b/controller/network/router.go @@ -20,6 +20,7 @@ import ( "github.com/openziti/fabric/controller/db" "github.com/openziti/fabric/controller/models" "github.com/openziti/foundation/channel2" + "github.com/openziti/foundation/common" "github.com/openziti/foundation/storage/boltz" "github.com/openziti/foundation/util/concurrenz" "github.com/orcaman/concurrent-map" @@ -35,6 +36,7 @@ type Router struct { AdvertisedListener string Control channel2.Channel Connected concurrenz.AtomicBoolean + VersionInfo *common.VersionInfo } func (entity *Router) fillFrom(_ Controller, _ *bbolt.Tx, boltEntity boltz.Entity) error { diff --git a/router/router.go b/router/router.go index fc080a285..205f2f0b1 100644 --- a/router/router.go +++ b/router/router.go @@ -34,6 +34,7 @@ import ( "github.com/openziti/fabric/router/xlink" "github.com/openziti/fabric/router/xlink_transport" "github.com/openziti/foundation/channel2" + "github.com/openziti/foundation/common" "github.com/openziti/foundation/event" "github.com/openziti/foundation/events" "github.com/openziti/foundation/metrics" @@ -63,13 +64,14 @@ type Router struct { isShutdown concurrenz.AtomicBoolean eventDispatcher event.Dispatcher metricsReporter metrics.Handler + versionProvider common.VersionProvider } func (self *Router) Channel() channel2.Channel { return self.ctrl } -func Create(config *Config) *Router { +func Create(config *Config, versionProvider common.VersionProvider) *Router { eventDispatcher := event.NewDispatcher() metricsConfig := &metrics.Config{ Source: config.Id.Token, @@ -84,6 +86,7 @@ func Create(config *Config) *Router { metricsRegistry: metricsRegistry, shutdownC: make(chan struct{}), eventDispatcher: eventDispatcher, + versionProvider: versionProvider, } } @@ -261,9 +264,18 @@ func (self *Router) startXgressListeners() { } func (self *Router) startControlPlane() error { - var attributes map[int32][]byte + attributes := map[int32][]byte{} + + version, err := self.versionProvider.EncoderDecoder().Encode(self.versionProvider.AsVersionInfo()) + + if err != nil { + return fmt.Errorf("error with version header information value: %v", err) + } + + attributes[channel2.HelloVersionHeader] = version + if len(self.xlinkListeners) == 1 { - attributes = make(map[int32][]byte) + attributes[channel2.HelloRouterAdvertisementsHeader] = []byte(self.xlinkListeners[0].GetAdvertisement()) } diff --git a/router/xlink_transport/listener.go b/router/xlink_transport/listener.go index 57ec4e421..3ce79b5e2 100644 --- a/router/xlink_transport/listener.go +++ b/router/xlink_transport/listener.go @@ -27,7 +27,7 @@ import ( ) func (self *listener) Listen() error { - listener := channel2.NewClassicListenerWithTransportConfiguration(self.id, self.config.bind, self.config.options.ConnectOptions, self.tcfg) + listener := channel2.NewClassicListenerWithTransportConfiguration(self.id, self.config.bind, self.config.options.ConnectOptions, self.tcfg, nil) self.listener = listener if err := self.listener.Listen(); err != nil {