From 5782723dde66c5517e48b4a6cd0486f6e88f5596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Thu, 14 Nov 2024 21:40:28 -0500 Subject: [PATCH 1/6] incusd/instance_post: Provide target project to relocation scriptlet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber --- cmd/incusd/instance_post.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/incusd/instance_post.go b/cmd/incusd/instance_post.go index 2e74d2d4b28..e38034e1323 100644 --- a/cmd/incusd/instance_post.go +++ b/cmd/incusd/instance_post.go @@ -336,7 +336,7 @@ func instancePost(d *Daemon, r *http.Request) response.Response { Devices: inst.ExpandedDevices().CloneNative(), }, }, - Project: projectName, + Project: instProject, Reason: apiScriptlet.InstancePlacementReasonRelocation, } From 700f35e329408617521ea508a8d77accccd8b959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Thu, 14 Nov 2024 22:16:23 -0500 Subject: [PATCH 2/6] incusd/cluster/request: Add new internal user-agent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber --- internal/server/cluster/request/clienttype.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/internal/server/cluster/request/clienttype.go b/internal/server/cluster/request/clienttype.go index 8f1a3c0c7ae..f4699bc74ef 100644 --- a/internal/server/cluster/request/clienttype.go +++ b/internal/server/cluster/request/clienttype.go @@ -4,6 +4,10 @@ package request // notifying other nodes of a cluster change. const UserAgentNotifier = "incus-cluster-notifier" +// UserAgentClient used to distinguish between a regular client request and an internal cluster request when +// performing a regular API interaction as an internal client. +const UserAgentClient = "incus-cluster-client" + // UserAgentJoiner used to distinguish between a regular client request and an internal cluster request when // joining a node to a cluster. const UserAgentJoiner = "incus-cluster-joiner" @@ -20,6 +24,9 @@ const ClientTypeJoiner ClientType = "joiner" // ClientTypeNormal normal client. const ClientTypeNormal ClientType = "normal" +// ClientTypeInternal cluster internal client. +const ClientTypeInternal ClientType = "internal" + // UserAgentClientType converts user agent to client type. func UserAgentClientType(userAgent string) ClientType { switch userAgent { @@ -27,6 +34,8 @@ func UserAgentClientType(userAgent string) ClientType { return ClientTypeNotifier case UserAgentJoiner: return ClientTypeJoiner + case UserAgentClient: + return ClientTypeInternal } return ClientTypeNormal From cd2539df7524cd539ae938cd96a73ad763139e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Thu, 14 Nov 2024 22:17:08 -0500 Subject: [PATCH 3/6] incusd/instances_post: Don't re-run placement on internal requests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber --- cmd/incusd/instances_post.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/incusd/instances_post.go b/cmd/incusd/instances_post.go index 1de9fc0135c..ea0e95b037a 100644 --- a/cmd/incusd/instances_post.go +++ b/cmd/incusd/instances_post.go @@ -832,6 +832,7 @@ func instancesPost(d *Daemon, r *http.Request) response.Response { targetProjectName := request.ProjectParam(r) clusterNotification := isClusterNotification(r) + clusterInternal := isClusterInternal(r) logger.Debug("Responding to instance create") @@ -1102,7 +1103,7 @@ func instancesPost(d *Daemon, r *http.Request) response.Response { return response.BadRequest(err) } - if s.ServerClustered && !clusterNotification { + if s.ServerClustered && !clusterNotification && !clusterInternal { // If a target was specified, limit the list of candidates to that target. if targetMemberInfo != nil { candidateMembers = []db.NodeInfo{*targetMemberInfo} @@ -1142,7 +1143,7 @@ func instancesPost(d *Daemon, r *http.Request) response.Response { } // Record the cluster group as a volatile config key if present. - if !clusterNotification && targetGroupName != "" { + if !clusterNotification && !clusterInternal && targetGroupName != "" { req.Config["volatile.cluster.group"] = targetGroupName } From eeaa9f3dc2c7914e1541db6400ea8bd175f67b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Thu, 14 Nov 2024 22:16:50 -0500 Subject: [PATCH 4/6] incusd/api: Handle new user agent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber --- cmd/incusd/api.go | 4 ++++ cmd/incusd/daemon.go | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/cmd/incusd/api.go b/cmd/incusd/api.go index 55f5ef650f0..6bf2e438e4e 100644 --- a/cmd/incusd/api.go +++ b/cmd/incusd/api.go @@ -422,6 +422,10 @@ func isClusterNotification(r *http.Request) bool { return r.Header.Get("User-Agent") == clusterRequest.UserAgentNotifier } +func isClusterInternal(r *http.Request) bool { + return r.Header.Get("User-Agent") == clusterRequest.UserAgentClient +} + type uiHttpDir struct { http.FileSystem } diff --git a/cmd/incusd/daemon.go b/cmd/incusd/daemon.go index 08c5c0a036f..44da19811f1 100644 --- a/cmd/incusd/daemon.go +++ b/cmd/incusd/daemon.go @@ -482,6 +482,11 @@ func (d *Daemon) Authenticate(w http.ResponseWriter, r *http.Request) (bool, str return false, "", "", fmt.Errorf("Cluster notification isn't using trusted server certificate") } + // Cluster internal client with wrong certificate. + if isClusterInternal(r) { + return false, "", "", fmt.Errorf("Cluster internal client isn't using trusted server certificate") + } + // Bad query, no TLS found. if r.TLS == nil { return false, "", "", fmt.Errorf("Bad/missing TLS on network query") From 51a8dc484e0d30202b3bc2bd8a720df0c9009d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Thu, 14 Nov 2024 22:17:38 -0500 Subject: [PATCH 5/6] incusd/instance_post: Pass in internal user agent during relocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #1299 Signed-off-by: Stéphane Graber --- cmd/incusd/instance_post.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cmd/incusd/instance_post.go b/cmd/incusd/instance_post.go index e38034e1323..d50b2cb4a1a 100644 --- a/cmd/incusd/instance_post.go +++ b/cmd/incusd/instance_post.go @@ -14,6 +14,7 @@ import ( internalInstance "github.com/lxc/incus/v6/internal/instance" "github.com/lxc/incus/v6/internal/server/auth" "github.com/lxc/incus/v6/internal/server/cluster" + clusterRequest "github.com/lxc/incus/v6/internal/server/cluster/request" "github.com/lxc/incus/v6/internal/server/db" dbCluster "github.com/lxc/incus/v6/internal/server/db/cluster" "github.com/lxc/incus/v6/internal/server/db/operationtype" @@ -595,7 +596,12 @@ func migrateInstance(ctx context.Context, s *state.State, inst instance.Instance // Handle pool and project moves. if req.Project != "" || req.Pool != "" { // Get a local client. - target, err := incus.ConnectIncusUnix(s.OS.GetUnixSocket(), nil) + args := &incus.ConnectionArgs{ + SkipGetServer: true, + UserAgent: clusterRequest.UserAgentClient, + } + + target, err := incus.ConnectIncusUnix(s.OS.GetUnixSocket(), args) if err != nil { return err } From d33cb3ff8800d021d67f5c3c6522096ea1753d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Thu, 14 Nov 2024 23:02:25 -0500 Subject: [PATCH 6/6] incusd/instance/qemu: Don't overtake operations on console retrieval MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes an issue where we'd get both stopped and migrated events during live-migration as the console retrieval happening during the migration would mark the migration operation as completed, turning the final stop operation into its own entity rather than completing the migration operation. Signed-off-by: Stéphane Graber --- internal/server/instance/drivers/driver_qemu.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/server/instance/drivers/driver_qemu.go b/internal/server/instance/drivers/driver_qemu.go index f13e1cd85e6..38be7d614f5 100644 --- a/internal/server/instance/drivers/driver_qemu.go +++ b/internal/server/instance/drivers/driver_qemu.go @@ -9329,7 +9329,10 @@ func (d *qemu) ConsoleLog() (string, error) { return "", err } - defer op.Done(nil) + // Only mark the operation as done if only processing the console retrieval. + if op.Action() == operationlock.ActionConsoleRetrieve { + defer op.Done(nil) + } // Check if the agent is running. monitor, err := qmp.Connect(d.monitorPath(), qemuSerialChardevName, d.getMonitorEventHandler(), d.QMPLogFilePath())