cmd/containerboot,kube: enable autoadvertisement of Tailscale services on containerboot (#18527)
* cmd/containerboot,kube/services: support the ability to automatically advertise services on startup Updates #17769 Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk> * cmd/containerboot: don't assume we want to use kube state store if in kubernetes Fixes #8188 Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk> --------- Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
This commit is contained in:
@@ -12,6 +12,29 @@ import (
|
||||
|
||||
type FakeLocalClient struct {
|
||||
FakeIPNBusWatcher
|
||||
SetServeCalled bool
|
||||
EditPrefsCalls []*ipn.MaskedPrefs
|
||||
GetPrefsResult *ipn.Prefs
|
||||
}
|
||||
|
||||
func (m *FakeLocalClient) SetServeConfig(ctx context.Context, cfg *ipn.ServeConfig) error {
|
||||
m.SetServeCalled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *FakeLocalClient) EditPrefs(ctx context.Context, mp *ipn.MaskedPrefs) (*ipn.Prefs, error) {
|
||||
m.EditPrefsCalls = append(m.EditPrefsCalls, mp)
|
||||
if m.GetPrefsResult == nil {
|
||||
return &ipn.Prefs{}, nil
|
||||
}
|
||||
return m.GetPrefsResult, nil
|
||||
}
|
||||
|
||||
func (m *FakeLocalClient) GetPrefs(ctx context.Context) (*ipn.Prefs, error) {
|
||||
if m.GetPrefsResult == nil {
|
||||
return &ipn.Prefs{}, nil
|
||||
}
|
||||
return m.GetPrefsResult, nil
|
||||
}
|
||||
|
||||
func (f *FakeLocalClient) WatchIPNBus(ctx context.Context, mask ipn.NotifyWatchOpt) (IPNBusWatcher, error) {
|
||||
|
||||
@@ -17,6 +17,8 @@ import (
|
||||
// for easier testing.
|
||||
type LocalClient interface {
|
||||
WatchIPNBus(ctx context.Context, mask ipn.NotifyWatchOpt) (IPNBusWatcher, error)
|
||||
SetServeConfig(context.Context, *ipn.ServeConfig) error
|
||||
EditPrefs(ctx context.Context, mp *ipn.MaskedPrefs) (*ipn.Prefs, error)
|
||||
CertIssuer
|
||||
}
|
||||
|
||||
@@ -40,6 +42,14 @@ type localClient struct {
|
||||
lc *local.Client
|
||||
}
|
||||
|
||||
func (lc *localClient) SetServeConfig(ctx context.Context, config *ipn.ServeConfig) error {
|
||||
return lc.lc.SetServeConfig(ctx, config)
|
||||
}
|
||||
|
||||
func (lc *localClient) EditPrefs(ctx context.Context, mp *ipn.MaskedPrefs) (*ipn.Prefs, error) {
|
||||
return lc.lc.EditPrefs(ctx, mp)
|
||||
}
|
||||
|
||||
func (lc *localClient) WatchIPNBus(ctx context.Context, mask ipn.NotifyWatchOpt) (IPNBusWatcher, error) {
|
||||
return lc.lc.WatchIPNBus(ctx, mask)
|
||||
}
|
||||
|
||||
@@ -12,9 +12,46 @@ import (
|
||||
|
||||
"tailscale.com/client/local"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/kube/localclient"
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
|
||||
// EnsureServicesAdvertised is a function that gets called on containerboot
|
||||
// startup and ensures that Services get advertised if they exist.
|
||||
func EnsureServicesAdvertised(ctx context.Context, services []string, lc localclient.LocalClient, logf logger.Logf) error {
|
||||
if _, err := lc.EditPrefs(ctx, &ipn.MaskedPrefs{
|
||||
AdvertiseServicesSet: true,
|
||||
Prefs: ipn.Prefs{
|
||||
AdvertiseServices: services,
|
||||
},
|
||||
}); err != nil {
|
||||
// EditPrefs only returns an error if it fails _set_ its local prefs.
|
||||
// If it fails to _persist_ the prefs in state, we don't get an error
|
||||
// and we continue waiting below, as control will failover as usual.
|
||||
return fmt.Errorf("error setting prefs AdvertiseServices: %w", err)
|
||||
}
|
||||
|
||||
// Services use the same (failover XOR regional routing) mechanism that
|
||||
// HA subnet routers use. Unfortunately we don't yet get a reliable signal
|
||||
// from control that it's responded to our unadvertisement, so the best we
|
||||
// can do is wait for 20 seconds, where 15s is the approximate maximum time
|
||||
// it should take for control to choose a new primary, and 5s is for buffer.
|
||||
//
|
||||
// Note: There is no guarantee that clients have been _informed_ of the new
|
||||
// primary no matter how long we wait. We would need a mechanism to await
|
||||
// netmap updates for peers to know for sure.
|
||||
//
|
||||
// See https://tailscale.com/kb/1115/high-availability for more details.
|
||||
// TODO(tomhjp): Wait for a netmap update instead of sleeping when control
|
||||
// supports that.
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case <-time.After(20 * time.Second):
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// EnsureServicesNotAdvertised is a function that gets called on containerboot
|
||||
// or k8s-proxy termination and ensures that any currently advertised Services
|
||||
// get unadvertised to give clients time to switch to another node before this
|
||||
|
||||
Reference in New Issue
Block a user