cmd/tailscale/cli: use optimistic concurrency control on SetServeConfig

This PR uses the etag/if-match pattern to ensure multiple calls
to SetServeConfig are synchronized. It currently errors out and
asks the user to retry but we can add occ retries as a follow up.

Updates #8489

Signed-off-by: Marwan Sulaiman <marwan@tailscale.com>
This commit is contained in:
Marwan Sulaiman
2023-09-11 21:32:51 -04:00
committed by Marwan Sulaiman
parent 6e66e5beeb
commit 3421784e37
5 changed files with 70 additions and 9 deletions

View File

@@ -91,6 +91,7 @@ var _ServeConfigCloneNeedsRegeneration = ServeConfig(struct {
Web map[HostPort]*WebServerConfig
AllowFunnel map[HostPort]bool
Foreground map[string]*ServeConfig
ETag string
}{})
// Clone makes a deep copy of TCPPortHandler.

View File

@@ -182,6 +182,7 @@ func (v ServeConfigView) Foreground() views.MapFn[string, *ServeConfig, ServeCon
return t.View()
})
}
func (v ServeConfigView) ETag() string { return v.ж.ETag }
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
var _ServeConfigViewNeedsRegeneration = ServeConfig(struct {
@@ -189,6 +190,7 @@ var _ServeConfigViewNeedsRegeneration = ServeConfig(struct {
Web map[HostPort]*WebServerConfig
AllowFunnel map[HostPort]bool
Foreground map[string]*ServeConfig
ETag string
}{})
// View returns a readonly view of TCPPortHandler.

View File

@@ -44,6 +44,12 @@ type ServeConfig struct {
// of either the client or the LocalBackend does not expose ports
// that users are not aware of.
Foreground map[string]*ServeConfig `json:",omitempty"`
// ETag is the checksum of the serve config that's populated
// by the LocalClient through the HTTP ETag header during a
// GetServeConfig request and is translated to an If-Match header
// during a SetServeConfig request.
ETag string `json:"-"`
}
// HostPort is an SNI name and port number, joined by a colon.