control/controlclient: fix panic regression from earlier load balancer hint header

In the recent 20e9f3369 we made HealthChangeRequest machine requests
include a NodeKey, as it was the oddball machine request that didn't
include one. Unfortunately, that code was sometimes being called (at
least in some of our integration tests) without a node key due to its
registration with health.RegisterWatcher(direct.ReportHealthChange).

Fortunately tests in corp caught this before we cut a release. It's
possible this only affects this particular integration test's
environment, but still worth fixing.

Updates tailscale/corp#1297

Change-Id: I84046779955105763dc1be5121c69fec3c138672
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2024-03-21 12:19:57 -07:00 committed by Maisem Ali
parent 85febda86d
commit 8444937c89
2 changed files with 25 additions and 1 deletions

View File

@ -1709,7 +1709,10 @@ func (c *Direct) ReportHealthChange(sys health.Subsystem, sysErr error) {
// Don't report errors to control if the server doesn't support noise. // Don't report errors to control if the server doesn't support noise.
return return
} }
nodeKey := c.GetPersist().PublicNodeKey() nodeKey, ok := c.GetPersist().PublicNodeKeyOK()
if !ok {
return
}
req := &tailcfg.HealthChangeRequest{ req := &tailcfg.HealthChangeRequest{
Subsys: string(sys), Subsys: string(sys),
NodeKey: nodeKey, NodeKey: nodeKey,

View File

@ -51,11 +51,32 @@ func (p *Persist) PublicNodeKey() key.NodePublic {
return p.PrivateNodeKey.Public() return p.PrivateNodeKey.Public()
} }
// PublicNodeKeyOK returns the public key for the node key.
//
// Unlike PublicNodeKey, it returns ok=false if there is no node private key
// instead of panicking.
func (p *Persist) PublicNodeKeyOK() (pub key.NodePublic, ok bool) {
if p.PrivateNodeKey.IsZero() {
return
}
return p.PrivateNodeKey.Public(), true
}
// PublicNodeKey returns the public key for the node key. // PublicNodeKey returns the public key for the node key.
//
// It panics if there is no node private key. See PublicNodeKeyOK.
func (p PersistView) PublicNodeKey() key.NodePublic { func (p PersistView) PublicNodeKey() key.NodePublic {
return p.ж.PublicNodeKey() return p.ж.PublicNodeKey()
} }
// PublicNodeKeyOK returns the public key for the node key.
//
// Unlike PublicNodeKey, it returns ok=false if there is no node private key
// instead of panicking.
func (p PersistView) PublicNodeKeyOK() (_ key.NodePublic, ok bool) {
return p.ж.PublicNodeKeyOK()
}
func (p PersistView) Equals(p2 PersistView) bool { func (p PersistView) Equals(p2 PersistView) bool {
return p.ж.Equals(p2.ж) return p.ж.Equals(p2.ж)
} }