Skip to content

Commit

Permalink
incusd: Extend heartbeat data for minimum API extension count
Browse files Browse the repository at this point in the history
This exposes not only the maximum API extension count as done today to
detect needed upgrades, but also the minimum value so newer servers can
restrict what they expose to clients while waiting for the cluster to be
consistent.

Signed-off-by: Stéphane Graber <[email protected]>
  • Loading branch information
stgraber committed Jul 18, 2024
1 parent 1bbcc63 commit 14a9f80
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 6 deletions.
2 changes: 1 addition & 1 deletion cmd/incusd/api_1.0.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ func api10Get(d *Daemon, r *http.Request) response.Response {
}

srv := api.ServerUntrusted{
APIExtensions: version.APIExtensions,
APIExtensions: version.APIExtensions[:d.apiExtensions],
APIStatus: "stable",
APIVersion: version.APIVersion,
Public: false,
Expand Down
8 changes: 8 additions & 0 deletions cmd/incusd/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ type Daemon struct {
// OVN clients.
ovnnb *ovn.NB
ovnsb *ovn.SB

// API info.
apiExtensions int
}

// DaemonConfig holds configuration values for Daemon.
Expand Down Expand Up @@ -197,6 +200,7 @@ func newDaemon(config *DaemonConfig, os *sys.OS) *Daemon {
shutdownCtx: shutdownCtx,
shutdownCancel: shutdownCancel,
shutdownDoneCh: make(chan error),
apiExtensions: len(version.APIExtensions),
}

d.serverCert = func() *localtls.CertInfo { return d.serverCertInt }
Expand Down Expand Up @@ -2384,6 +2388,10 @@ func (d *Daemon) nodeRefreshTask(heartbeatData *cluster.APIHeartbeat, isLeader b
return
}

if heartbeatData.Version.MinAPIExtensions > 0 && heartbeatData.Version.MinAPIExtensions != d.apiExtensions {
d.apiExtensions = heartbeatData.Version.MinAPIExtensions
}

// If the max version of the cluster has changed, check whether we need to upgrade.
if d.lastNodeList == nil || d.lastNodeList.Version.APIExtensions != heartbeatData.Version.APIExtensions || d.lastNodeList.Version.Schema != heartbeatData.Version.Schema {
err := cluster.MaybeUpdate(s)
Expand Down
16 changes: 11 additions & 5 deletions internal/server/cluster/heartbeat.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ type APIHeartbeatMember struct {

// APIHeartbeatVersion contains max versions for all nodes in cluster.
type APIHeartbeatVersion struct {
Schema int
APIExtensions int
Schema int
APIExtensions int
MinAPIExtensions int
}

// NewAPIHearbeat returns initialized APIHeartbeat.
Expand All @@ -74,7 +75,7 @@ type APIHeartbeat struct {
// Update updates an existing APIHeartbeat struct with the raft and all node states supplied.
// If allNodes provided is an empty set then this is considered a non-full state list.
func (hbState *APIHeartbeat) Update(fullStateList bool, raftNodes []db.RaftNode, allNodes []db.NodeInfo, offlineThreshold time.Duration) {
var maxSchemaVersion, maxAPIExtensionsVersion int
var maxSchemaVersion, maxAPIExtensionsVersion, minAPIExtensionsVersion int

if hbState.Members == nil {
hbState.Members = make(map[int64]APIHeartbeatMember)
Expand Down Expand Up @@ -115,14 +116,19 @@ func (hbState *APIHeartbeat) Update(fullStateList bool, raftNodes []db.RaftNode,
maxAPIExtensionsVersion = node.APIExtensions
}

if minAPIExtensionsVersion == 0 || node.APIExtensions < minAPIExtensionsVersion {
minAPIExtensionsVersion = node.APIExtensions
}

if node.Schema > maxSchemaVersion {
maxSchemaVersion = node.Schema
}
}

hbState.Version = APIHeartbeatVersion{
Schema: maxSchemaVersion,
APIExtensions: maxAPIExtensionsVersion,
Schema: maxSchemaVersion,
APIExtensions: maxAPIExtensionsVersion,
MinAPIExtensions: minAPIExtensionsVersion,
}

if len(raftNodeMap) > 0 && hbState.cluster != nil {
Expand Down

0 comments on commit 14a9f80

Please sign in to comment.