diff --git a/cmd/incusd/api_1.0.go b/cmd/incusd/api_1.0.go index b059263a5c2..37fae659e81 100644 --- a/cmd/incusd/api_1.0.go +++ b/cmd/incusd/api_1.0.go @@ -672,7 +672,7 @@ func doApi10Update(d *Daemon, r *http.Request, req api.ServerPut, patch bool) re var newClusterConfig *clusterConfig.Config oldClusterConfig := make(map[string]string) - err = s.DB.Cluster.Transaction(context.Background(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { var err error newClusterConfig, err = clusterConfig.Load(ctx, tx) if err != nil { diff --git a/cmd/incusd/api_cluster.go b/cmd/incusd/api_cluster.go index 423e23f3e5f..8b9a39f9277 100644 --- a/cmd/incusd/api_cluster.go +++ b/cmd/incusd/api_cluster.go @@ -57,7 +57,7 @@ import ( ) type evacuateStopFunc func(inst instance.Instance, action string) error -type evacuateMigrateFunc func(s *state.State, r *http.Request, inst instance.Instance, targetMemberInfo *db.NodeInfo, live bool, startInstance bool, metadata map[string]any, op *operations.Operation) error +type evacuateMigrateFunc func(ctx context.Context, s *state.State, r *http.Request, inst instance.Instance, targetMemberInfo *db.NodeInfo, live bool, startInstance bool, metadata map[string]any, op *operations.Operation) error type evacuateOpts struct { s *state.State @@ -207,7 +207,7 @@ func clusterGet(d *Daemon, r *http.Request) response.Response { serverName = "" } - memberConfig, err := clusterGetMemberConfig(s.DB.Cluster) + memberConfig, err := clusterGetMemberConfig(r.Context(), s.DB.Cluster) if err != nil { return response.SmartError(err) } @@ -243,13 +243,13 @@ func clusterGet(d *Daemon, r *http.Request) response.Response { // Fetch information about all node-specific configuration keys set on the // storage pools and networks of this cluster. -func clusterGetMemberConfig(cluster *db.Cluster) ([]api.ClusterMemberConfigKey, error) { +func clusterGetMemberConfig(ctx context.Context, cluster *db.Cluster) ([]api.ClusterMemberConfigKey, error) { var pools map[string]map[string]string var networks map[string]map[string]string keys := []api.ClusterMemberConfigKey{} - err := cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var err error pools, err = tx.GetStoragePoolsLocalConfig(ctx) @@ -424,7 +424,7 @@ func clusterPutBootstrap(d *Daemon, r *http.Request, req api.ClusterPut) respons // let's default to it. var err error var config *node.Config - err = s.DB.Node.Transaction(context.TODO(), func(ctx context.Context, tx *db.NodeTx) error { + err = s.DB.Node.Transaction(r.Context(), func(ctx context.Context, tx *db.NodeTx) error { config, err = node.ConfigLoad(ctx, tx) if err != nil { return fmt.Errorf("Failed to fetch member configuration: %w", err) @@ -506,7 +506,7 @@ func clusterPutJoin(d *Daemon, r *http.Request, req api.ClusterPut) response.Res return response.SmartError(err) } - err = s.DB.Node.Transaction(context.TODO(), func(ctx context.Context, tx *db.NodeTx) error { + err = s.DB.Node.Transaction(r.Context(), func(ctx context.Context, tx *db.NodeTx) error { config, err = node.ConfigLoad(ctx, tx) if err != nil { return fmt.Errorf("Failed to load cluster config: %w", err) @@ -537,7 +537,7 @@ func clusterPutJoin(d *Daemon, r *http.Request, req api.ClusterPut) response.Res } // Update the cluster.https_address config key. - err := s.DB.Node.Transaction(context.TODO(), func(ctx context.Context, tx *db.NodeTx) error { + err := s.DB.Node.Transaction(r.Context(), func(ctx context.Context, tx *db.NodeTx) error { var err error config, err = node.ConfigLoad(ctx, tx) @@ -1340,7 +1340,7 @@ func clusterNodesPost(d *Daemon, r *http.Request) response.Response { // retrieving remote operations. onlineNodeAddresses := make([]any, 0) - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Get the nodes. members, err := tx.GetNodes(ctx) if err != nil { @@ -1708,7 +1708,7 @@ func updateClusterNode(s *state.State, gateway *cluster.Gateway, r *http.Request } // Update the database - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { nodeInfo, err := tx.GetNodeByName(ctx, name) if err != nil { return fmt.Errorf("Loading node information: %w", err) @@ -1898,7 +1898,7 @@ func clusterNodePost(d *Daemon, r *http.Request) response.Response { return response.BadRequest(err) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { return tx.RenameNode(ctx, memberName, req.ServerName) }) if err != nil { @@ -1959,7 +1959,7 @@ func clusterNodeDelete(d *Daemon, r *http.Request) response.Response { } var localInfo, leaderInfo db.NodeInfo - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { localInfo, err = tx.GetNodeByAddress(ctx, localClusterAddress) if err != nil { return fmt.Errorf("Failed loading local member info %q: %w", localClusterAddress, err) @@ -1978,7 +1978,7 @@ func clusterNodeDelete(d *Daemon, r *http.Request) response.Response { // Get information about the cluster. var nodes []db.RaftNode - err = s.DB.Node.Transaction(context.TODO(), func(ctx context.Context, tx *db.NodeTx) error { + err = s.DB.Node.Transaction(r.Context(), func(ctx context.Context, tx *db.NodeTx) error { var err error nodes, err = tx.GetRaftNodes(ctx) return err @@ -2094,7 +2094,7 @@ func clusterNodeDelete(d *Daemon, r *http.Request) response.Response { // Get a list of projects for networks. var networkProjectNames []string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { networkProjectNames, err = dbCluster.GetProjectNames(ctx, tx.Tx()) return err }) @@ -2124,7 +2124,7 @@ func clusterNodeDelete(d *Daemon, r *http.Request) response.Response { var pools []string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Delete all the pools on this node pools, err = tx.GetStoragePoolNames(ctx) @@ -2261,7 +2261,7 @@ func updateClusterCertificate(ctx context.Context, s *state.State, gateway *clus var err error revert.Add(func() { - _ = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + _ = s.DB.Cluster.Transaction(context.Background(), func(ctx context.Context, tx *db.ClusterTx) error { return tx.UpsertWarningLocalNode(ctx, "", -1, -1, warningtype.UnableToUpdateClusterCertificate, err.Error()) }) }) @@ -2424,12 +2424,12 @@ func internalClusterPostAccept(d *Daemon, r *http.Request) response.Response { // Check that the pools and networks provided by the joining node have // configs that match the cluster ones. - err = clusterCheckStoragePoolsMatch(s.DB.Cluster, req.StoragePools) + err = clusterCheckStoragePoolsMatch(r.Context(), s.DB.Cluster, req.StoragePools) if err != nil { return response.SmartError(err) } - err = clusterCheckNetworksMatch(s.DB.Cluster, req.Networks) + err = clusterCheckNetworksMatch(r.Context(), s.DB.Cluster, req.Networks) if err != nil { return response.SmartError(err) } @@ -2570,7 +2570,7 @@ func upgradeNodesWithoutRaftRole(s *state.State, gateway *cluster.Gateway) error } var members []db.NodeInfo - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(context.Background(), func(ctx context.Context, tx *db.ClusterTx) error { var err error members, err = tx.GetNodes(ctx) if err != nil { @@ -2784,8 +2784,8 @@ type internalClusterPostHandoverRequest struct { Address string `json:"address" yaml:"address"` } -func clusterCheckStoragePoolsMatch(cluster *db.Cluster, reqPools []api.StoragePool) error { - return cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { +func clusterCheckStoragePoolsMatch(ctx context.Context, cluster *db.Cluster, reqPools []api.StoragePool) error { + return cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { poolNames, err := tx.GetCreatedStoragePoolNames(ctx) if err != nil && !response.IsNotFoundError(err) { return err @@ -2829,8 +2829,8 @@ func clusterCheckStoragePoolsMatch(cluster *db.Cluster, reqPools []api.StoragePo }) } -func clusterCheckNetworksMatch(cluster *db.Cluster, reqNetworks []api.InitNetworksProjectPost) error { - return cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { +func clusterCheckNetworksMatch(ctx context.Context, cluster *db.Cluster, reqNetworks []api.InitNetworksProjectPost) error { + return cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Get a list of projects for networks. networkProjectNames, err := dbCluster.GetProjectNames(ctx, tx.Tx()) if err != nil { @@ -3064,14 +3064,14 @@ func clusterNodeStatePost(d *Daemon, r *http.Request) response.Response { return nil } - migrateFunc := func(s *state.State, r *http.Request, inst instance.Instance, targetMemberInfo *db.NodeInfo, live bool, startInstance bool, metadata map[string]any, op *operations.Operation) error { + migrateFunc := func(ctx context.Context, s *state.State, r *http.Request, inst instance.Instance, targetMemberInfo *db.NodeInfo, live bool, startInstance bool, metadata map[string]any, op *operations.Operation) error { // Migrate the instance. req := api.InstancePost{ Name: inst.Name(), Live: live, } - err := migrateInstance(s, r, inst, targetMemberInfo.Name, req, op) + err := migrateInstance(ctx, s, r, inst, targetMemberInfo.Name, req, op) if err != nil { return fmt.Errorf("Failed to migrate instance %q in project %q: %w", inst.Name(), inst.Project().Name, err) } @@ -3115,7 +3115,7 @@ func clusterNodeStatePost(d *Daemon, r *http.Request) response.Response { } func internalClusterHeal(d *Daemon, r *http.Request) response.Response { - migrateFunc := func(s *state.State, r *http.Request, inst instance.Instance, targetMemberInfo *db.NodeInfo, live bool, startInstance bool, metadata map[string]any, op *operations.Operation) error { + migrateFunc := func(ctx context.Context, s *state.State, r *http.Request, inst instance.Instance, targetMemberInfo *db.NodeInfo, live bool, startInstance bool, metadata map[string]any, op *operations.Operation) error { // This returns an error if the instance's storage pool is local. // Since we only care about remote backed instances, this can be ignored and return nil instead. poolName, err := inst.StoragePool() @@ -3182,7 +3182,7 @@ func internalClusterHeal(d *Daemon, r *http.Request) response.Response { } func evacuateClusterSetState(s *state.State, name string, state int) error { - return s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + return s.DB.Cluster.Transaction(context.Background(), func(ctx context.Context, tx *db.ClusterTx) error { // Get the node. node, err := tx.GetNodeByName(ctx, name) if err != nil { @@ -3225,7 +3225,7 @@ func evacuateClusterMember(s *state.State, gateway *cluster.Gateway, r *http.Req // The instances are retrieved in a separate transaction, after the node is in EVACUATED state. var dbInstances []dbCluster.Instance - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // If evacuating, consider only the instances on the node which needs to be evacuated. dbInstances, err = dbCluster.GetInstances(ctx, tx.Tx(), dbCluster.InstanceFilter{Node: &nodeName}) if err != nil { @@ -3265,8 +3265,6 @@ func evacuateClusterMember(s *state.State, gateway *cluster.Gateway, r *http.Req _ = evacuateClusterSetState(s, nodeName, db.ClusterMemberStateCreated) }) - ctx := context.TODO() - opts := evacuateOpts{ s: s, gateway: gateway, @@ -3279,7 +3277,7 @@ func evacuateClusterMember(s *state.State, gateway *cluster.Gateway, r *http.Req op: op, } - err = evacuateInstances(ctx, opts) + err = evacuateInstances(context.Background(), opts) if err != nil { return err } @@ -3372,7 +3370,7 @@ func evacuateInstances(ctx context.Context, opts evacuateOpts) error { } start := isRunning || instanceShouldAutoStart(inst) - err = opts.migrateInstance(opts.s, opts.r, inst, targetMemberInfo, action == "live-migrate", start, metadata, opts.op) + err = opts.migrateInstance(ctx, opts.s, opts.r, inst, targetMemberInfo, action == "live-migrate", start, metadata, opts.op) if err != nil { return err } @@ -3391,7 +3389,7 @@ func restoreClusterMember(d *Daemon, r *http.Request) response.Response { // List the instances. var dbInstances []dbCluster.Instance - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { dbInstances, err = dbCluster.GetInstances(ctx, tx.Tx()) if err != nil { return fmt.Errorf("Failed to get instances: %w", err) @@ -3486,7 +3484,7 @@ func restoreClusterMember(d *Daemon, r *http.Request) response.Response { metadata["evacuation_progress"] = fmt.Sprintf("Migrating %q in project %q from %q", inst.Name(), inst.Project().Name, inst.Location()) _ = op.UpdateMetadata(metadata) - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(context.Background(), func(ctx context.Context, tx *db.ClusterTx) error { sourceNode, err = tx.GetNodeByName(ctx, inst.Location()) if err != nil { return fmt.Errorf("Failed to get node %q: %w", inst.Location(), err) @@ -3663,7 +3661,7 @@ func clusterGroupsPost(d *Daemon, r *http.Request) response.Response { return response.BadRequest(err) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { obj := dbCluster.ClusterGroup{ Name: req.Name, Description: req.Description, @@ -3786,7 +3784,7 @@ func clusterGroupsGet(d *Daemon, r *http.Request) response.Response { var result any - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { var err error if recursion { @@ -3879,7 +3877,7 @@ func clusterGroupGet(d *Daemon, r *http.Request) response.Response { var group *dbCluster.ClusterGroup - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Get the cluster group. group, err = dbCluster.GetClusterGroup(ctx, tx.Tx(), name) if err != nil { @@ -3965,7 +3963,7 @@ func clusterGroupPost(d *Daemon, r *http.Request) response.Response { return response.BadRequest(err) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Check that the name isn't already in use. _, err = dbCluster.GetClusterGroup(ctx, tx.Tx(), req.Name) if err == nil { @@ -4040,7 +4038,7 @@ func clusterGroupPut(d *Daemon, r *http.Request) response.Response { return response.BadRequest(err) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { group, err := dbCluster.GetClusterGroup(ctx, tx.Tx(), name) if err != nil { return err @@ -4155,7 +4153,7 @@ func clusterGroupPatch(d *Daemon, r *http.Request) response.Response { var clusterGroup *api.ClusterGroup var dbClusterGroup *dbCluster.ClusterGroup - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { dbClusterGroup, err = dbCluster.GetClusterGroup(ctx, tx.Tx(), name) if err != nil { return err @@ -4201,7 +4199,7 @@ func clusterGroupPatch(d *Daemon, r *http.Request) response.Response { req.Members = clusterGroup.Members } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { obj := dbCluster.ClusterGroup{ Name: dbClusterGroup.Name, Description: req.Description, @@ -4316,7 +4314,7 @@ func clusterGroupDelete(d *Daemon, r *http.Request) response.Response { return response.Forbidden(fmt.Errorf("The 'default' cluster group cannot be deleted")) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { members, err := tx.GetClusterGroupNodes(ctx, name) if err != nil { return err diff --git a/cmd/incusd/api_internal.go b/cmd/incusd/api_internal.go index f0c1ea62933..a6d8f31e548 100644 --- a/cmd/incusd/api_internal.go +++ b/cmd/incusd/api_internal.go @@ -186,7 +186,7 @@ func internalCreateWarning(d *Daemon, r *http.Request) response.Response { return response.SmartError(fmt.Errorf("Invalid entity type")) } - err = d.State().DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = d.State().DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { return tx.UpsertWarning(ctx, req.Location, req.Project, req.EntityTypeCode, req.EntityID, warningtype.Type(req.TypeCode), req.Message) }) if err != nil { @@ -571,7 +571,7 @@ func internalSQLExec(tx *sql.Tx, query string, result *internalSQL.SQLResult) er // internalImportFromBackup creates instance, storage pool and volume DB records from an instance's backup file. // It expects the instance volume to be mounted so that the backup.yaml file is readable. -func internalImportFromBackup(s *state.State, projectName string, instName string, allowNameOverride bool) error { +func internalImportFromBackup(ctx context.Context, s *state.State, projectName string, instName string, allowNameOverride bool) error { if instName == "" { return fmt.Errorf("The name of the instance is required") } @@ -661,7 +661,7 @@ func internalImportFromBackup(s *state.State, projectName string, instName strin pool, err := storagePools.LoadByName(s, instancePoolName) if response.IsNotFoundError(err) { // Create the storage pool db entry if it doesn't exist. - _, err = storagePoolDBCreate(s, instancePoolName, "", backupConf.Pool.Driver, backupConf.Pool.Config) + _, err = storagePoolDBCreate(ctx, s, instancePoolName, "", backupConf.Pool.Driver, backupConf.Pool.Config) if err != nil { return fmt.Errorf("Create storage pool database entry: %w", err) } @@ -690,7 +690,7 @@ func internalImportFromBackup(s *state.State, projectName string, instName strin // Check if a storage volume entry for the instance already exists. var dbVolume *db.StorageVolume - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { dbVolume, err = tx.GetStoragePoolVolume(ctx, pool.ID(), projectName, instanceDBVolType, backupConf.Container.Name, true) if err != nil && !response.IsNotFoundError(err) { return err @@ -706,7 +706,7 @@ func internalImportFromBackup(s *state.State, projectName string, instName strin return fmt.Errorf(`Storage volume for instance %q already exists in the database`, backupConf.Container.Name) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Check if an entry for the instance already exists in the db. _, err := tx.GetInstanceID(ctx, projectName, backupConf.Container.Name) @@ -726,7 +726,7 @@ func internalImportFromBackup(s *state.State, projectName string, instName strin var profiles []api.Profile - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { profiles, err = tx.GetProfiles(ctx, projectName, backupConf.Container.Profiles) return err @@ -780,7 +780,7 @@ func internalImportFromBackup(s *state.State, projectName string, instName strin for _, snap := range existingSnapshots { snapInstName := fmt.Sprintf("%s%s%s", backupConf.Container.Name, internalInstance.SnapshotDelimiter, snap.Name) - snapErr := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + snapErr := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Check if an entry for the snapshot already exists in the db. _, err := tx.GetInstanceSnapshotID(ctx, projectName, backupConf.Container.Name, snap.Name) @@ -796,7 +796,7 @@ func internalImportFromBackup(s *state.State, projectName string, instName strin // Check if a storage volume entry for the snapshot already exists. var dbVolume *db.StorageVolume - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { dbVolume, err = tx.GetStoragePoolVolume(ctx, pool.ID(), projectName, instanceDBVolType, snapInstName, true) if err != nil && !response.IsNotFoundError(err) { return err @@ -814,7 +814,7 @@ func internalImportFromBackup(s *state.State, projectName string, instName strin } if snapErr == nil { - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { return tx.DeleteInstance(ctx, projectName, snapInstName) }) if err != nil { @@ -823,7 +823,7 @@ func internalImportFromBackup(s *state.State, projectName string, instName strin } if dbVolume != nil { - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { return tx.RemoveStoragePoolVolume(ctx, projectName, snapInstName, instanceDBVolType, pool.ID()) }) if err != nil { @@ -838,7 +838,7 @@ func internalImportFromBackup(s *state.State, projectName string, instName strin return err } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { profiles, err = tx.GetProfiles(ctx, projectName, snap.Profiles) return err diff --git a/cmd/incusd/api_internal_recover.go b/cmd/incusd/api_internal_recover.go index 33cd00ab684..65df744df87 100644 --- a/cmd/incusd/api_internal_recover.go +++ b/cmd/incusd/api_internal_recover.go @@ -48,7 +48,7 @@ func init() { } // internalRecoverScan provides the discovery and import functionality for both recovery validate and import steps. -func internalRecoverScan(s *state.State, userPools []api.StoragePoolsPost, validateOnly bool) response.Response { +func internalRecoverScan(ctx context.Context, s *state.State, userPools []api.StoragePoolsPost, validateOnly bool) response.Response { var err error var projects map[string]*api.Project var projectProfiles map[string][]*api.Profile @@ -56,7 +56,7 @@ func internalRecoverScan(s *state.State, userPools []api.StoragePoolsPost, valid // Retrieve all project, profile and network info in a single transaction so we can use it for all // imported instances and volumes, and avoid repeatedly querying the same information. - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Load list of projects for validation. ps, err := dbCluster.GetProjects(ctx, tx.Tx()) if err != nil { @@ -331,7 +331,7 @@ func internalRecoverScan(s *state.State, userPools []api.StoragePoolsPost, valid if instPoolVol != nil { // Create storage pool DB record from config in the instance. logger.Info("Creating storage pool DB record from instance config", logger.Ctx{"name": instPoolVol.Pool.Name, "description": instPoolVol.Pool.Description, "driver": instPoolVol.Pool.Driver, "config": instPoolVol.Pool.Config}) - poolID, err = dbStoragePoolCreateAndUpdateCache(s, instPoolVol.Pool.Name, instPoolVol.Pool.Description, instPoolVol.Pool.Driver, instPoolVol.Pool.Config) + poolID, err = dbStoragePoolCreateAndUpdateCache(ctx, s, instPoolVol.Pool.Name, instPoolVol.Pool.Description, instPoolVol.Pool.Driver, instPoolVol.Pool.Config) if err != nil { return response.SmartError(fmt.Errorf("Failed creating storage pool %q database entry: %w", pool.Name(), err)) } @@ -341,19 +341,19 @@ func internalRecoverScan(s *state.State, userPools []api.StoragePoolsPost, valid poolDriverName := pool.Driver().Info().Name poolDriverConfig := pool.Driver().Config() logger.Info("Creating storage pool DB record from user config", logger.Ctx{"name": pool.Name(), "driver": poolDriverName, "config": poolDriverConfig}) - poolID, err = dbStoragePoolCreateAndUpdateCache(s, pool.Name(), "", poolDriverName, poolDriverConfig) + poolID, err = dbStoragePoolCreateAndUpdateCache(ctx, s, pool.Name(), "", poolDriverName, poolDriverConfig) if err != nil { return response.SmartError(fmt.Errorf("Failed creating storage pool %q database entry: %w", pool.Name(), err)) } } revert.Add(func() { - _ = dbStoragePoolDeleteAndUpdateCache(s, pool.Name()) + _ = dbStoragePoolDeleteAndUpdateCache(context.Background(), s, pool.Name()) }) // Set storage pool node to storagePoolCreated. // Must come before storage pool is loaded from the database. - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { return tx.StoragePoolNodeCreated(poolID) }) if err != nil { @@ -582,7 +582,7 @@ func internalRecoverValidate(d *Daemon, r *http.Request) response.Response { return response.BadRequest(err) } - return internalRecoverScan(d.State(), req.Pools, true) + return internalRecoverScan(r.Context(), d.State(), req.Pools, true) } // internalRecoverImport performs the pool volume recovery. @@ -594,5 +594,5 @@ func internalRecoverImport(d *Daemon, r *http.Request) response.Response { return response.BadRequest(err) } - return internalRecoverScan(d.State(), req.Pools, false) + return internalRecoverScan(r.Context(), d.State(), req.Pools, false) } diff --git a/cmd/incusd/api_project.go b/cmd/incusd/api_project.go index 1c2faa8327d..0e2b283158d 100644 --- a/cmd/incusd/api_project.go +++ b/cmd/incusd/api_project.go @@ -148,7 +148,7 @@ func projectsGet(d *Daemon, r *http.Request) response.Response { } var result any - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { projects, err := cluster.GetProjects(ctx, tx.Tx()) if err != nil { return err @@ -312,7 +312,7 @@ func projectsPost(d *Daemon, r *http.Request) response.Response { } var id int64 - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { id, err = cluster.CreateProject(ctx, tx.Tx(), cluster.Project{Description: project.Description, Name: project.Name}) if err != nil { return fmt.Errorf("Failed adding database record: %w", err) @@ -324,7 +324,7 @@ func projectsPost(d *Daemon, r *http.Request) response.Response { } if util.IsTrue(project.Config["features.profiles"]) { - err = projectCreateDefaultProfile(tx, project.Name) + err = projectCreateDefaultProfile(ctx, tx, project.Name) if err != nil { return err } @@ -356,14 +356,14 @@ func projectsPost(d *Daemon, r *http.Request) response.Response { } // Create the default profile of a project. -func projectCreateDefaultProfile(tx *db.ClusterTx, project string) error { +func projectCreateDefaultProfile(ctx context.Context, tx *db.ClusterTx, project string) error { // Create a default profile profile := cluster.Profile{} profile.Project = project profile.Name = api.ProjectDefaultName profile.Description = fmt.Sprintf("Default Incus profile for project %s", project) - _, err := cluster.CreateProfile(context.TODO(), tx.Tx(), profile) + _, err := cluster.CreateProfile(ctx, tx.Tx(), profile) if err != nil { return fmt.Errorf("Add default profile to database: %w", err) } @@ -415,7 +415,7 @@ func projectGet(d *Daemon, r *http.Request) response.Response { // Get the database entry var project *api.Project - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { dbProject, err := cluster.GetProject(ctx, tx.Tx(), name) if err != nil { return err @@ -480,7 +480,7 @@ func projectPut(d *Daemon, r *http.Request) response.Response { // Get the current data var project *api.Project - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { dbProject, err := cluster.GetProject(ctx, tx.Tx(), name) if err != nil { return err @@ -524,7 +524,7 @@ func projectPut(d *Daemon, r *http.Request) response.Response { requestor := request.CreateRequestor(r) s.Events.SendLifecycle(project.Name, lifecycle.ProjectUpdated.Event(project.Name, requestor, nil)) - return projectChange(s, project, req) + return projectChange(r.Context(), s, project, req) } // swagger:operation PATCH /1.0/projects/{name} projects project_patch @@ -566,7 +566,7 @@ func projectPatch(d *Daemon, r *http.Request) response.Response { // Get the current data var project *api.Project - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { dbProject, err := cluster.GetProject(ctx, tx.Tx(), name) if err != nil { return err @@ -640,11 +640,11 @@ func projectPatch(d *Daemon, r *http.Request) response.Response { requestor := request.CreateRequestor(r) s.Events.SendLifecycle(project.Name, lifecycle.ProjectUpdated.Event(project.Name, requestor, nil)) - return projectChange(s, project, req) + return projectChange(r.Context(), s, project, req) } // Common logic between PUT and PATCH. -func projectChange(s *state.State, project *api.Project, req api.ProjectPut) response.Response { +func projectChange(ctx context.Context, s *state.State, project *api.Project, req api.ProjectPut) response.Response { // Make a list of config keys that have changed. configChanged := []string{} for key := range project.Config { @@ -703,7 +703,7 @@ func projectChange(s *state.State, project *api.Project, req api.ProjectPut) res } // Update the database entry. - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { err := projecthelpers.AllowProjectUpdate(tx, project.Name, req.Config, configChanged) if err != nil { return err @@ -716,7 +716,7 @@ func projectChange(s *state.State, project *api.Project, req api.ProjectPut) res if slices.Contains(configChanged, "features.profiles") { if util.IsTrue(req.Config["features.profiles"]) { - err = projectCreateDefaultProfile(tx, project.Name) + err = projectCreateDefaultProfile(ctx, tx, project.Name) if err != nil { return err } @@ -888,7 +888,7 @@ func projectDelete(d *Daemon, r *http.Request) response.Response { } var id int64 - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { project, err := cluster.GetProject(ctx, tx.Tx(), name) if err != nil { return fmt.Errorf("Fetch project %q: %w", name, err) @@ -972,7 +972,7 @@ func projectStateGet(d *Daemon, r *http.Request) response.Response { state := api.ProjectState{} // Get current limits and usage. - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { result, err := projecthelpers.GetCurrentAllocations(ctx, tx, name) if err != nil { return err diff --git a/cmd/incusd/certificates.go b/cmd/incusd/certificates.go index 3a43e4061ae..99e5d00b7f5 100644 --- a/cmd/incusd/certificates.go +++ b/cmd/incusd/certificates.go @@ -146,7 +146,7 @@ func certificatesGet(d *Daemon, r *http.Request) response.Response { var certResponses []api.Certificate var baseCerts []dbCluster.Certificate var err error - err = d.State().DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = d.State().DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { baseCerts, err = dbCluster.GetCertificates(ctx, tx.Tx()) if err != nil { return err @@ -205,7 +205,7 @@ func updateCertificateCache(d *Daemon) { var dbCerts []dbCluster.Certificate var localCerts []dbCluster.Certificate var err error - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.ClusterTx) error { dbCerts, err = dbCluster.GetCertificates(ctx, tx.Tx()) if err != nil { return err @@ -256,7 +256,7 @@ func updateCertificateCache(d *Daemon) { } // Write out the server certs to the local database to allow the cluster to restart. - err = s.DB.Node.Transaction(context.TODO(), func(ctx context.Context, tx *db.NodeTx) error { + err = s.DB.Node.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.NodeTx) error { return tx.ReplaceCertificates(localCerts) }) if err != nil { @@ -270,6 +270,8 @@ func updateCertificateCache(d *Daemon) { // updateCertificateCacheFromLocal loads trusted server certificates from local database into memory. func updateCertificateCacheFromLocal(d *Daemon) error { + s := d.State() + logger.Debug("Refreshing local trusted certificate cache") newCerts := map[certificate.Type]map[string]x509.Certificate{} @@ -277,7 +279,7 @@ func updateCertificateCacheFromLocal(d *Daemon) error { var dbCerts []dbCluster.Certificate var err error - err = d.State().DB.Node.Transaction(context.TODO(), func(ctx context.Context, tx *db.NodeTx) error { + err = s.DB.Node.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.NodeTx) error { dbCerts, err = tx.GetCertificates(ctx) return err }) @@ -705,7 +707,7 @@ func certificatesPost(d *Daemon, r *http.Request) response.Response { } if !isClusterNotification(r) { - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Check if we already have the certificate. existingCert, _ := dbCluster.GetCertificateByFingerprintPrefix(ctx, tx.Tx(), fingerprint) if existingCert != nil { @@ -807,7 +809,7 @@ func certificateGet(d *Daemon, r *http.Request) response.Response { } var cert *api.Certificate - err = d.State().DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = d.State().DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { dbCertInfo, err := dbCluster.GetCertificateByFingerprintPrefix(ctx, tx.Tx(), fingerprint) if err != nil { return err @@ -860,7 +862,7 @@ func certificatePut(d *Daemon, r *http.Request) response.Response { // Get current database record. var apiEntry *api.Certificate - err = d.State().DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = d.State().DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { oldEntry, err := dbCluster.GetCertificateByFingerprintPrefix(ctx, tx.Tx(), fingerprint) if err != nil { return err @@ -929,7 +931,7 @@ func certificatePatch(d *Daemon, r *http.Request) response.Response { // Get current database record. var apiEntry *api.Certificate - err = d.State().DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = d.State().DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { oldEntry, err := dbCluster.GetCertificateByFingerprintPrefix(ctx, tx.Tx(), fingerprint) if err != nil { return err @@ -1122,7 +1124,7 @@ func certificateDelete(d *Daemon, r *http.Request) response.Response { if !isClusterNotification(r) { var certInfo *dbCluster.Certificate - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Get current database record. var err error certInfo, err = dbCluster.GetCertificateByFingerprintPrefix(ctx, tx.Tx(), fingerprint) @@ -1176,7 +1178,7 @@ func certificateDelete(d *Daemon, r *http.Request) response.Response { } } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Perform the delete with the expanded fingerprint. return dbCluster.DeleteCertificate(ctx, tx.Tx(), certInfo.Fingerprint) }) diff --git a/cmd/incusd/daemon.go b/cmd/incusd/daemon.go index a80f4926117..a2abc32350c 100644 --- a/cmd/incusd/daemon.go +++ b/cmd/incusd/daemon.go @@ -260,7 +260,7 @@ func allowPermission(objectType auth.ObjectType, entitlement auth.Entitlement, m if objectType == auth.ObjectTypeImage { var imgInfo *api.Image - err := d.db.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := d.db.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { var err error _, imgInfo, err = tx.GetImage(ctx, fingerprint, dbCluster.ImageFilter{Project: &projectName}) diff --git a/cmd/incusd/daemon_config.go b/cmd/incusd/daemon_config.go index f834f9ea11c..c7ffadaffa5 100644 --- a/cmd/incusd/daemon_config.go +++ b/cmd/incusd/daemon_config.go @@ -19,7 +19,7 @@ func daemonConfigRender(state *state.State) (map[string]string, error) { } // Apply the local config. - err := state.DB.Node.Transaction(context.TODO(), func(ctx context.Context, tx *db.NodeTx) error { + err := state.DB.Node.Transaction(context.Background(), func(ctx context.Context, tx *db.NodeTx) error { nodeConfig, err := node.ConfigLoad(ctx, tx) if err != nil { return err diff --git a/cmd/incusd/daemon_images.go b/cmd/incusd/daemon_images.go index b9679a69e4e..5c57561ab47 100644 --- a/cmd/incusd/daemon_images.go +++ b/cmd/incusd/daemon_images.go @@ -51,16 +51,16 @@ type ImageDownloadArgs struct { } // imageOperationLock acquires a lock for operating on an image and returns the unlock function. -func imageOperationLock(fingerprint string) (locking.UnlockFunc, error) { +func imageOperationLock(ctx context.Context, fingerprint string) (locking.UnlockFunc, error) { l := logger.AddContext(logger.Ctx{"fingerprint": fingerprint}) l.Debug("Acquiring lock for image") defer l.Debug("Lock acquired for image") - return locking.Lock(context.TODO(), fmt.Sprintf("ImageOperation_%s", fingerprint)) + return locking.Lock(ctx, fmt.Sprintf("ImageOperation_%s", fingerprint)) } // ImageDownload resolves the image fingerprint and if not in the database, downloads it. -func ImageDownload(r *http.Request, s *state.State, op *operations.Operation, args *ImageDownloadArgs) (*api.Image, error) { +func ImageDownload(ctx context.Context, r *http.Request, s *state.State, op *operations.Operation, args *ImageDownloadArgs) (*api.Image, error) { var err error var ctxMap logger.Ctx @@ -127,7 +127,7 @@ func ImageDownload(r *http.Request, s *state.State, op *operations.Operation, ar } // Ensure we are the only ones operating on this image. - unlock, err := imageOperationLock(fp) + unlock, err := imageOperationLock(ctx, fp) if err != nil { return nil, err } @@ -142,7 +142,7 @@ func ImageDownload(r *http.Request, s *state.State, op *operations.Operation, ar interval := s.GlobalConfig.ImagesAutoUpdateIntervalHours() if args.PreferCached && interval > 0 && alias != fp { - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { for _, architecture := range s.OS.Architectures { cachedFingerprint, err := tx.GetCachedImageSourceFingerprint(ctx, args.Server, args.Protocol, alias, args.Type, architecture) if err == nil && cachedFingerprint != fp { @@ -160,7 +160,7 @@ func ImageDownload(r *http.Request, s *state.State, op *operations.Operation, ar var imgInfo *api.Image - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Check if the image already exists in this project (partial hash match). _, imgInfo, err = tx.GetImage(ctx, fp, cluster.ImageFilter{Project: &args.ProjectName}) @@ -169,7 +169,7 @@ func ImageDownload(r *http.Request, s *state.State, op *operations.Operation, ar if err == nil { var nodeAddress string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Check if the image is available locally or it's on another node. nodeAddress, err = tx.LocateImage(ctx, imgInfo.Fingerprint) @@ -186,7 +186,7 @@ func ImageDownload(r *http.Request, s *state.State, op *operations.Operation, ar return nil, fmt.Errorf("Failed transferring image %q from %q: %w", imgInfo.Fingerprint, nodeAddress, err) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // As the image record already exists in the project, just add the node ID to the image. return tx.AddImageToLocalNode(ctx, args.ProjectName, imgInfo.Fingerprint) }) @@ -195,7 +195,7 @@ func ImageDownload(r *http.Request, s *state.State, op *operations.Operation, ar } } } else if response.IsNotFoundError(err) { - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Check if the image already exists in some other project. _, imgInfo, err = tx.GetImageFromAnyProject(ctx, fp) @@ -204,7 +204,7 @@ func ImageDownload(r *http.Request, s *state.State, op *operations.Operation, ar if err == nil { var nodeAddress string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Check if the image is available locally or it's on another node. Do this before creating // the missing DB record so we don't include ourself in the search results. nodeAddress, err = tx.LocateImage(ctx, imgInfo.Fingerprint) @@ -265,7 +265,7 @@ func ImageDownload(r *http.Request, s *state.State, op *operations.Operation, ar var poolID int64 var poolIDs []int64 - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Get the ID of the target storage pool. poolID, err = tx.GetStoragePoolID(ctx, args.StoragePool) if err != nil { @@ -550,7 +550,7 @@ func ImageDownload(r *http.Request, s *state.State, op *operations.Operation, ar info.AutoUpdate = args.AutoUpdate } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Create the database entry return tx.CreateImage(ctx, args.ProjectName, info.Fingerprint, info.Filename, info.Size, info.Public, info.AutoUpdate, info.Architecture, info.CreatedAt, info.ExpiresAt, info.Properties, info.Type, nil) }) @@ -579,7 +579,7 @@ func ImageDownload(r *http.Request, s *state.State, op *operations.Operation, ar // Record the image source if alias != fp { - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { id, _, err := tx.GetImage(ctx, fp, cluster.ImageFilter{Project: &args.ProjectName}) if err != nil { return err @@ -602,7 +602,7 @@ func ImageDownload(r *http.Request, s *state.State, op *operations.Operation, ar // Mark the image as "cached" if downloading for an instance if args.SetCached { - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { return tx.SetImageCachedAndLastUseDate(ctx, args.ProjectName, fp, time.Now().UTC()) }) if err != nil { diff --git a/cmd/incusd/daemon_storage.go b/cmd/incusd/daemon_storage.go index d1fe8892be6..2f7b04fc596 100644 --- a/cmd/incusd/daemon_storage.go +++ b/cmd/incusd/daemon_storage.go @@ -22,7 +22,7 @@ func daemonStorageVolumesUnmount(s *state.State) error { var storageBackups string var storageImages string - err := s.DB.Node.Transaction(context.TODO(), func(ctx context.Context, tx *db.NodeTx) error { + err := s.DB.Node.Transaction(context.Background(), func(ctx context.Context, tx *db.NodeTx) error { nodeConfig, err := node.ConfigLoad(ctx, tx) if err != nil { return err @@ -78,7 +78,7 @@ func daemonStorageVolumesUnmount(s *state.State) error { func daemonStorageMount(s *state.State) error { var storageBackups string var storageImages string - err := s.DB.Node.Transaction(context.TODO(), func(ctx context.Context, tx *db.NodeTx) error { + err := s.DB.Node.Transaction(context.Background(), func(ctx context.Context, tx *db.NodeTx) error { nodeConfig, err := node.ConfigLoad(ctx, tx) if err != nil { return err @@ -157,7 +157,7 @@ func daemonStorageValidate(s *state.State, target string) error { var poolID int64 var snapshots []db.StorageVolumeArgs - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(context.Background(), func(ctx context.Context, tx *db.ClusterTx) error { // Validate pool exists. poolID, _, _, err = tx.GetStoragePool(ctx, poolName) if err != nil { diff --git a/cmd/incusd/images.go b/cmd/incusd/images.go index a7d7ae7ba56..28a61b0203d 100644 --- a/cmd/incusd/images.go +++ b/cmd/incusd/images.go @@ -199,7 +199,7 @@ func compressFile(compress string, infile io.Reader, outfile io.Writer) error { * This function takes a container or snapshot from the local image server and * exports it as an image. */ -func imgPostInstanceInfo(s *state.State, r *http.Request, req api.ImagesPost, op *operations.Operation, builddir string, budget int64) (*api.Image, error) { +func imgPostInstanceInfo(ctx context.Context, s *state.State, r *http.Request, req api.ImagesPost, op *operations.Operation, builddir string, budget int64) (*api.Image, error) { info := api.Image{} info.Properties = map[string]string{} projectName := request.ProjectParam(r) @@ -292,7 +292,7 @@ func imgPostInstanceInfo(s *state.State, r *http.Request, req api.ImagesPost, op compress = req.CompressionAlgorithm } else { var p *api.Project - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { project, err := dbCluster.GetProject(ctx, tx.Tx(), projectName) if err != nil { return err @@ -373,7 +373,7 @@ func imgPostInstanceInfo(s *state.State, r *http.Request, req api.ImagesPost, op info.Fingerprint = fmt.Sprintf("%x", sha256.Sum(nil)) info.CreatedAt = time.Now().UTC() - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { _, _, err = tx.GetImage(ctx, info.Fingerprint, dbCluster.ImageFilter{Project: &projectName}) return err @@ -396,7 +396,7 @@ func imgPostInstanceInfo(s *state.State, r *http.Request, req api.ImagesPost, op info.Architecture, _ = osarch.ArchitectureName(c.Architecture()) info.Properties = meta.Properties - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Create the database entry return tx.CreateImage(ctx, c.Project().Name, info.Fingerprint, info.Filename, info.Size, info.Public, info.AutoUpdate, info.Architecture, info.CreatedAt, info.ExpiresAt, info.Properties, info.Type, nil) }) @@ -407,7 +407,7 @@ func imgPostInstanceInfo(s *state.State, r *http.Request, req api.ImagesPost, op return &info, nil } -func imgPostRemoteInfo(s *state.State, r *http.Request, req api.ImagesPost, op *operations.Operation, project string, budget int64) (*api.Image, error) { +func imgPostRemoteInfo(ctx context.Context, s *state.State, r *http.Request, req api.ImagesPost, op *operations.Operation, project string, budget int64) (*api.Image, error) { var err error var hash string @@ -419,7 +419,7 @@ func imgPostRemoteInfo(s *state.State, r *http.Request, req api.ImagesPost, op * return nil, fmt.Errorf("must specify one of alias or fingerprint for init from image") } - info, err := ImageDownload(r, s, op, &ImageDownloadArgs{ + info, err := ImageDownload(ctx, r, s, op, &ImageDownloadArgs{ Server: req.Source.Server, Protocol: req.Source.Protocol, Certificate: req.Source.Certificate, @@ -436,7 +436,7 @@ func imgPostRemoteInfo(s *state.State, r *http.Request, req api.ImagesPost, op * return nil, err } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var id int id, info, err = tx.GetImage(ctx, info.Fingerprint, dbCluster.ImageFilter{Project: &project}) @@ -484,7 +484,7 @@ func imgPostRemoteInfo(s *state.State, r *http.Request, req api.ImagesPost, op * return info, nil } -func imgPostURLInfo(s *state.State, r *http.Request, req api.ImagesPost, op *operations.Operation, project string, budget int64) (*api.Image, error) { +func imgPostURLInfo(ctx context.Context, s *state.State, r *http.Request, req api.ImagesPost, op *operations.Operation, project string, budget int64) (*api.Image, error) { var err error if req.Source.URL == "" { @@ -532,7 +532,7 @@ func imgPostURLInfo(s *state.State, r *http.Request, req api.ImagesPost, op *ope } // Import the image - info, err := ImageDownload(r, s, op, &ImageDownloadArgs{ + info, err := ImageDownload(ctx, r, s, op, &ImageDownloadArgs{ Server: url, Protocol: "direct", Alias: hash, @@ -545,7 +545,7 @@ func imgPostURLInfo(s *state.State, r *http.Request, req api.ImagesPost, op *ope return nil, err } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var id int id, info, err = tx.GetImage(ctx, info.Fingerprint, dbCluster.ImageFilter{Project: &project}) @@ -574,7 +574,7 @@ func imgPostURLInfo(s *state.State, r *http.Request, req api.ImagesPost, op *ope return info, nil } -func getImgPostInfo(s *state.State, r *http.Request, builddir string, project string, post *os.File, metadata map[string]any) (*api.Image, error) { +func getImgPostInfo(ctx context.Context, s *state.State, r *http.Request, builddir string, project string, post *os.File, metadata map[string]any) (*api.Image, error) { info := api.Image{} var imageMeta *api.ImageMetadata l := logger.AddContext(logger.Ctx{"function": "getImgPostInfo"}) @@ -772,7 +772,7 @@ func getImgPostInfo(s *state.State, r *http.Request, builddir string, project st p, _ := url.ParseQuery(profilesHeaders) profileIds = make([]int64, len(p["profile"])) - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { for i, val := range p["profile"] { profileID, _, err := tx.GetProfile(ctx, project, val) if response.IsNotFoundError(err) { @@ -793,7 +793,7 @@ func getImgPostInfo(s *state.State, r *http.Request, builddir string, project st var exists bool - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Check if the image already exists exists, err = tx.ImageExists(ctx, project, info.Fingerprint) @@ -807,7 +807,7 @@ func getImgPostInfo(s *state.State, r *http.Request, builddir string, project st // Do not create a database entry if the request is coming from the internal // cluster communications for image synchronization if isClusterNotification(r) { - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { return tx.AddImageToLocalNode(ctx, project, info.Fingerprint) }) if err != nil { @@ -822,7 +822,7 @@ func getImgPostInfo(s *state.State, r *http.Request, builddir string, project st info.Public = public.(bool) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Create the database entry return tx.CreateImage(ctx, project, info.Fingerprint, info.Filename, info.Size, info.Public, info.AutoUpdate, info.Architecture, info.CreatedAt, info.ExpiresAt, info.Properties, info.Type, profileIds) }) @@ -1031,7 +1031,7 @@ func imagesPost(d *Daemon, r *http.Request) response.Response { // Possibly set a quota on the amount of disk space this project is // allowed to use. var budget int64 - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { budget, err = projectutils.GetImageSpaceBudget(tx, projectName) return err }) @@ -1117,18 +1117,18 @@ func imagesPost(d *Daemon, r *http.Request) response.Response { if imageUpload { /* Processing image upload */ - info, err = getImgPostInfo(s, r, builddir, projectName, post, imageMetadata) + info, err = getImgPostInfo(context.TODO(), s, r, builddir, projectName, post, imageMetadata) } else { if req.Source.Type == "image" { /* Processing image copy from remote */ - info, err = imgPostRemoteInfo(s, r, req, op, projectName, budget) + info, err = imgPostRemoteInfo(context.TODO(), s, r, req, op, projectName, budget) } else if req.Source.Type == "url" { /* Processing image copy from URL */ - info, err = imgPostURLInfo(s, r, req, op, projectName, budget) + info, err = imgPostURLInfo(context.TODO(), s, r, req, op, projectName, budget) } else { /* Processing image creation from container */ imagePublishLock.Lock() - info, err = imgPostInstanceInfo(s, r, req, op, builddir, budget) + info, err = imgPostInstanceInfo(context.TODO(), s, r, req, op, builddir, budget) imagePublishLock.Unlock() } } @@ -1192,7 +1192,7 @@ func imagesPost(d *Daemon, r *http.Request) response.Response { } // Sync the images between each node in the cluster on demand - err = imageSyncBetweenNodes(s, r, projectName, info.Fingerprint) + err = imageSyncBetweenNodes(context.TODO(), s, r, projectName, info.Fingerprint) if err != nil { return fmt.Errorf("Failed syncing image between nodes: %w", err) } @@ -1717,7 +1717,7 @@ func autoUpdateImagesTask(d *Daemon) (task.Func, task.Schedule) { func autoUpdateImages(ctx context.Context, s *state.State) error { imageMap := make(map[string][]dbCluster.Image) - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var err error autoUpdate := true @@ -1741,7 +1741,7 @@ func autoUpdateImages(ctx context.Context, s *state.State) error { var nodes []string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { nodes, err = tx.GetNodesWithImageAndAutoUpdate(ctx, fingerprint, true) return err @@ -1755,7 +1755,7 @@ func autoUpdateImages(ctx context.Context, s *state.State) error { var nodeIDs []int64 for _, node := range nodes { - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var err error nodeInfo, err := tx.GetNodeByAddress(ctx, node) @@ -1805,7 +1805,7 @@ func autoUpdateImages(ctx context.Context, s *state.State) error { var imageInfo *api.Image - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { _, imageInfo, err = tx.GetImage(ctx, image.Fingerprint, filter) return err @@ -1845,7 +1845,7 @@ func autoUpdateImages(ctx context.Context, s *state.State) error { } } - _ = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + _ = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { for _, ID := range deleteIDs { // Remove the database entry for the image after distributing to cluster members. err := tx.DeleteImage(ctx, ID) @@ -1874,7 +1874,7 @@ func distributeImage(ctx context.Context, s *state.State, nodes []string, oldFin // may be different for each cluster member. var imageVolumes []string - err := s.DB.Node.Transaction(context.TODO(), func(ctx context.Context, tx *db.NodeTx) error { + err := s.DB.Node.Transaction(ctx, func(ctx context.Context, tx *db.NodeTx) error { config, err := node.ConfigLoad(ctx, tx) if err != nil { return err @@ -1916,7 +1916,7 @@ func distributeImage(ctx context.Context, s *state.State, nodes []string, oldFin var poolIDs []int64 var poolNames []string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Get the IDs of all storage pools on which a storage volume // for the requested image currently exists. poolIDs, err = tx.GetPoolsWithImage(ctx, newImage.Fingerprint) @@ -1944,7 +1944,7 @@ func distributeImage(ctx context.Context, s *state.State, nodes []string, oldFin } var nodeInfo db.NodeInfo - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var err error nodeInfo, err = tx.GetNodeByAddress(ctx, nodeAddress) return err @@ -2078,7 +2078,7 @@ func autoUpdateImage(ctx context.Context, s *state.State, op *operations.Operati var interval int64 var project *api.Project - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { p, err := dbCluster.GetProject(ctx, tx.Tx(), projectName) if err != nil { return err @@ -2114,7 +2114,7 @@ func autoUpdateImage(ctx context.Context, s *state.State, op *operations.Operati var poolNames []string - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var err error _, source, err = tx.GetImageSource(ctx, id) if err != nil { @@ -2176,7 +2176,7 @@ func autoUpdateImage(ctx context.Context, s *state.State, op *operations.Operati default: } - newInfo, err = ImageDownload(nil, s, op, &ImageDownloadArgs{ + newInfo, err = ImageDownload(ctx, nil, s, op, &ImageDownloadArgs{ Server: source.Server, Protocol: source.Protocol, Certificate: source.Certificate, @@ -2201,7 +2201,7 @@ func autoUpdateImage(ctx context.Context, s *state.State, op *operations.Operati var newID int - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { newID, _, err = tx.GetImage(ctx, hash, dbCluster.ImageFilter{Project: &projectName}) return err @@ -2212,7 +2212,7 @@ func autoUpdateImage(ctx context.Context, s *state.State, op *operations.Operati } if info.Cached { - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { return tx.SetImageCachedAndLastUseDate(ctx, projectName, hash, info.LastUsedAt) }) if err != nil { @@ -2234,7 +2234,7 @@ func autoUpdateImage(ctx context.Context, s *state.State, op *operations.Operati } } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { return tx.MoveImageAlias(ctx, id, newID) }) if err != nil { @@ -2242,7 +2242,7 @@ func autoUpdateImage(ctx context.Context, s *state.State, op *operations.Operati continue } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { return tx.CopyDefaultImageProfiles(ctx, id, newID) }) if err != nil { @@ -2350,7 +2350,7 @@ func pruneLeftoverImages(s *state.State) { opRun := func(op *operations.Operation) error { // Check if dealing with shared image storage. var storageImages string - err := s.DB.Node.Transaction(context.TODO(), func(ctx context.Context, tx *db.NodeTx) error { + err := s.DB.Node.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.NodeTx) error { nodeConfig, err := node.ConfigLoad(ctx, tx) if err != nil { return err @@ -2388,7 +2388,7 @@ func pruneLeftoverImages(s *state.State) { // Get all images var images []string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.ClusterTx) error { var err error images, err = tx.GetLocalImagesFingerprints(ctx) return err @@ -2531,7 +2531,7 @@ func pruneExpiredImages(ctx context.Context, s *state.State, op *operations.Oper continue } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Remove the database entry for the image. return tx.DeleteImage(ctx, dbImage.ID) }) @@ -2555,7 +2555,7 @@ func pruneExpiredImages(ctx context.Context, s *state.State, op *operations.Oper var poolIDs []int64 var poolNames []string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Get the IDs of all storage pools on which a storage volume for the image currently exists. poolIDs, err = tx.GetPoolsWithImage(ctx, fingerprint) if err != nil { @@ -2643,7 +2643,7 @@ func imageDelete(d *Daemon, r *http.Request) response.Response { var imgID int var imgInfo *api.Image - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Use the fingerprint we received in a LIKE query and use the full // fingerprint we receive from the database in all further queries. imgID, imgInfo, err = tx.GetImage(ctx, fingerprint, dbCluster.ImageFilter{Project: &projectName}) @@ -2657,7 +2657,7 @@ func imageDelete(d *Daemon, r *http.Request) response.Response { do := func(op *operations.Operation) error { // Lock this operation to ensure that concurrent image operations don't conflict. // Other operations will wait for this one to finish. - unlock, err := imageOperationLock(imgInfo.Fingerprint) + unlock, err := imageOperationLock(context.TODO(), imgInfo.Fingerprint) if err != nil { return err } @@ -3063,7 +3063,7 @@ func imagePut(d *Daemon, r *http.Request) response.Response { var id int var info *api.Image - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { id, info, err = tx.GetImage(ctx, fingerprint, dbCluster.ImageFilter{Project: &projectName}) return err @@ -3172,7 +3172,7 @@ func imagePatch(d *Daemon, r *http.Request) response.Response { var id int var info *api.Image - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { id, info, err = tx.GetImage(ctx, fingerprint, dbCluster.ImageFilter{Project: &projectName}) return err @@ -3233,7 +3233,7 @@ func imagePatch(d *Daemon, r *http.Request) response.Response { info.Properties = properties } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { return tx.UpdateImage(ctx, id, info.Filename, info.Size, info.Public, info.AutoUpdate, info.Architecture, info.CreatedAt, info.ExpiresAt, info.Properties, "", nil) }) if err != nil { @@ -3998,7 +3998,7 @@ func imageExport(d *Daemon, r *http.Request) response.Response { var imgInfo *api.Image - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Get the image (expand the fingerprint). _, imgInfo, err = tx.GetImage(ctx, fingerprint, dbCluster.ImageFilter{Project: &projectName}) @@ -4042,7 +4042,7 @@ func imageExport(d *Daemon, r *http.Request) response.Response { var address string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Check if the image is only available on another node. address, err = tx.LocateImage(ctx, imgInfo.Fingerprint) @@ -4148,7 +4148,7 @@ func imageExportPost(d *Daemon, r *http.Request) response.Response { return response.SmartError(err) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Check if the image exists _, _, err = tx.GetImage(ctx, fingerprint, dbCluster.ImageFilter{Project: &projectName}) @@ -4296,7 +4296,7 @@ func imageSecret(d *Daemon, r *http.Request) response.Response { var imgInfo *api.Image - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { _, imgInfo, err = tx.GetImage(ctx, fingerprint, dbCluster.ImageFilter{Project: &projectName}) return err @@ -4416,7 +4416,7 @@ func imageRefresh(d *Daemon, r *http.Request) response.Response { var imageID int var imageInfo *api.Image - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { imageID, imageInfo, err = tx.GetImage(ctx, fingerprint, dbCluster.ImageFilter{Project: &projectName}) return err @@ -4438,14 +4438,14 @@ func imageRefresh(d *Daemon, r *http.Request) response.Response { return fmt.Errorf("Error getting cluster members for refreshing image %q in project %q: %w", fingerprint, projectName, err) } - newImage, err := autoUpdateImage(s.ShutdownCtx, s, op, imageID, imageInfo, projectName, true) + newImage, err := autoUpdateImage(context.TODO(), s, op, imageID, imageInfo, projectName, true) if err != nil { return fmt.Errorf("Failed to update image %q in project %q: %w", fingerprint, projectName, err) } if newImage != nil { if len(nodes) > 1 { - err := distributeImage(s.ShutdownCtx, s, nodes, fingerprint, newImage) + err := distributeImage(context.TODO(), s, nodes, fingerprint, newImage) if err != nil { return fmt.Errorf("Failed to distribute new image %q: %w", newImage.Fingerprint, err) } @@ -4531,7 +4531,7 @@ func autoSyncImagesTask(d *Daemon) (task.Func, task.Schedule) { func autoSyncImages(ctx context.Context, s *state.State) error { var imageProjectInfo map[string][]string - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var err error // Get all images. @@ -4546,7 +4546,7 @@ func autoSyncImages(ctx context.Context, s *state.State) error { for fingerprint, projects := range imageProjectInfo { ch := make(chan error) go func() { - err := imageSyncBetweenNodes(s, nil, projects[0], fingerprint) + err := imageSyncBetweenNodes(ctx, s, nil, projects[0], fingerprint) if err != nil { logger.Error("Failed to synchronize images", logger.Ctx{"err": err, "fingerprint": fingerprint}) } @@ -4564,14 +4564,14 @@ func autoSyncImages(ctx context.Context, s *state.State) error { return nil } -func imageSyncBetweenNodes(s *state.State, r *http.Request, project string, fingerprint string) error { +func imageSyncBetweenNodes(ctx context.Context, s *state.State, r *http.Request, project string, fingerprint string) error { logger.Info("Syncing image to members started", logger.Ctx{"fingerprint": fingerprint, "project": project}) defer logger.Info("Syncing image to members finished", logger.Ctx{"fingerprint": fingerprint, "project": project}) var desiredSyncNodeCount int64 var syncNodeAddresses []string - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { desiredSyncNodeCount = s.GlobalConfig.ImagesMinimalReplica() // -1 means that we want to replicate the image on all nodes @@ -4622,7 +4622,7 @@ func imageSyncBetweenNodes(s *state.State, r *http.Request, project string, fing var image *api.Image - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Get the image. _, image, err = tx.GetImage(ctx, fingerprint, dbCluster.ImageFilter{Project: &project}) @@ -4642,7 +4642,7 @@ func imageSyncBetweenNodes(s *state.State, r *http.Request, project string, fing for i := 0; i < int(nodeCount); i++ { var addresses []string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Get a list of nodes that do not have the image. addresses, err = tx.GetNodesWithoutImage(ctx, fingerprint) diff --git a/cmd/incusd/instance.go b/cmd/incusd/instance.go index e4fd9d69fc7..47181195c76 100644 --- a/cmd/incusd/instance.go +++ b/cmd/incusd/instance.go @@ -85,13 +85,13 @@ func instanceImageTransfer(s *state.State, r *http.Request, projectName string, return nil } -func ensureImageIsLocallyAvailable(s *state.State, r *http.Request, img *api.Image, projectName string, instanceType instancetype.Type) error { +func ensureImageIsLocallyAvailable(ctx context.Context, s *state.State, r *http.Request, img *api.Image, projectName string, instanceType instancetype.Type) error { // Check if the image is available locally or it's on another member. // Ensure we are the only ones operating on this image. Otherwise another instance created at the same // time may also arrive at the conclusion that the image doesn't exist on this cluster member and then // think it needs to download the image and store the record in the database as well, which will lead to // duplicate record errors. - unlock, err := imageOperationLock(img.Fingerprint) + unlock, err := imageOperationLock(ctx, img.Fingerprint) if err != nil { return err } @@ -100,7 +100,7 @@ func ensureImageIsLocallyAvailable(s *state.State, r *http.Request, img *api.Ima var memberAddress string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { memberAddress, err = tx.LocateImage(ctx, img.Fingerprint) return err @@ -116,7 +116,7 @@ func ensureImageIsLocallyAvailable(s *state.State, r *http.Request, img *api.Ima return fmt.Errorf("Failed transferring image %q from %q: %w", img.Fingerprint, memberAddress, err) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // As the image record already exists in the project, just add the node ID to the image. return tx.AddImageToLocalNode(ctx, projectName, img.Fingerprint) }) @@ -129,7 +129,7 @@ func ensureImageIsLocallyAvailable(s *state.State, r *http.Request, img *api.Ima } // instanceCreateFromImage creates an instance from a rootfs image. -func instanceCreateFromImage(s *state.State, r *http.Request, img *api.Image, args db.InstanceArgs, op *operations.Operation) error { +func instanceCreateFromImage(ctx context.Context, s *state.State, r *http.Request, img *api.Image, args db.InstanceArgs, op *operations.Operation) error { revert := revert.New() defer revert.Fail() @@ -162,7 +162,7 @@ func instanceCreateFromImage(s *state.State, r *http.Request, img *api.Image, ar revert.Add(cleanup) defer instOp.Done(nil) - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { err = tx.UpdateImageLastUseDate(ctx, args.Project, img.Fingerprint, time.Now().UTC()) if err != nil { return fmt.Errorf("Error updating image last use date: %w", err) @@ -195,7 +195,7 @@ func instanceCreateFromImage(s *state.State, r *http.Request, img *api.Image, ar return nil } -func instanceRebuildFromImage(s *state.State, r *http.Request, inst instance.Instance, img *api.Image, op *operations.Operation) error { +func instanceRebuildFromImage(ctx context.Context, s *state.State, r *http.Request, inst instance.Instance, img *api.Image, op *operations.Operation) error { // Validate the type of the image matches the type of the instance. imgType, err := instancetype.New(img.Type) if err != nil { @@ -206,7 +206,7 @@ func instanceRebuildFromImage(s *state.State, r *http.Request, inst instance.Ins return fmt.Errorf("Requested image's type %q doesn't match instance type %q", imgType, inst.Type()) } - err = ensureImageIsLocallyAvailable(s, r, img, inst.Project().Name, inst.Type()) + err = ensureImageIsLocallyAvailable(ctx, s, r, img, inst.Project().Name, inst.Type()) if err != nil { return err } diff --git a/cmd/incusd/instance_backup.go b/cmd/incusd/instance_backup.go index b33913d6599..958dc99a1b4 100644 --- a/cmd/incusd/instance_backup.go +++ b/cmd/incusd/instance_backup.go @@ -231,7 +231,7 @@ func instanceBackupsPost(d *Daemon, r *http.Request) response.Response { return response.BadRequest(fmt.Errorf("Invalid instance name")) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { err := project.AllowBackupCreation(tx, projectName) return err }) diff --git a/cmd/incusd/instance_patch.go b/cmd/incusd/instance_patch.go index 58bc842c281..8fe1d8e52bb 100644 --- a/cmd/incusd/instance_patch.go +++ b/cmd/incusd/instance_patch.go @@ -186,7 +186,7 @@ func instancePatch(d *Daemon, r *http.Request) response.Response { // Check project limits. apiProfiles := make([]api.Profile, 0, len(req.Profiles)) - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { profiles, err := cluster.GetProfilesIfEnabled(ctx, tx.Tx(), projectName, req.Profiles) if err != nil { return err diff --git a/cmd/incusd/instance_post.go b/cmd/incusd/instance_post.go index 459de607881..3160da3ab65 100644 --- a/cmd/incusd/instance_post.go +++ b/cmd/incusd/instance_post.go @@ -331,7 +331,7 @@ func instancePost(d *Daemon, r *http.Request) response.Response { // Setup the instance move operation. run := func(op *operations.Operation) error { - return instancePostMigration(s, inst, req.Name, req.Pool, req.Project, req.Config, req.Devices, req.Profiles, req.InstanceOnly, req.Live, req.AllowInconsistent, op) + return instancePostMigration(context.TODO(), s, inst, req.Name, req.Pool, req.Project, req.Config, req.Devices, req.Profiles, req.InstanceOnly, req.Live, req.AllowInconsistent, op) } resources := map[string][]api.URL{} @@ -362,7 +362,7 @@ func instancePost(d *Daemon, r *http.Request) response.Response { } run := func(op *operations.Operation) error { - return migrateInstance(s, r, inst, targetMemberInfo.Name, req, op) + return migrateInstance(context.TODO(), s, r, inst, targetMemberInfo.Name, req, op) } resources := map[string][]api.URL{} @@ -453,7 +453,7 @@ func instancePost(d *Daemon, r *http.Request) response.Response { } // Move an instance. -func instancePostMigration(s *state.State, inst instance.Instance, newName string, newPool string, newProject string, config map[string]string, devices map[string]map[string]string, profiles []string, instanceOnly bool, stateful bool, allowInconsistent bool, op *operations.Operation) error { +func instancePostMigration(ctx context.Context, s *state.State, inst instance.Instance, newName string, newPool string, newProject string, config map[string]string, devices map[string]map[string]string, profiles []string, instanceOnly bool, stateful bool, allowInconsistent bool, op *operations.Operation) error { if inst.IsSnapshot() { return fmt.Errorf("Instance snapshots cannot be moved between pools") } @@ -502,7 +502,7 @@ func instancePostMigration(s *state.State, inst instance.Instance, newName strin apiProfiles := []api.Profile{} if len(profiles) > 0 { - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { profiles, err := dbCluster.GetProfilesIfEnabled(ctx, tx.Tx(), newProject, profiles) if err != nil { return err @@ -939,7 +939,7 @@ func instancePostClusteringMigrateRemoteStorage(s *state.State, r *http.Request, return run, nil } -func migrateInstance(s *state.State, r *http.Request, inst instance.Instance, targetNode string, req api.InstancePost, op *operations.Operation) error { +func migrateInstance(ctx context.Context, s *state.State, r *http.Request, inst instance.Instance, targetNode string, req api.InstancePost, op *operations.Operation) error { // If target isn't the same as the instance's location. if targetNode == inst.Location() { return fmt.Errorf("Target must be different than instance's current location") @@ -950,7 +950,7 @@ func migrateInstance(s *state.State, r *http.Request, inst instance.Instance, ta // If the source member is online then get its address so we can connect to it and see if the // instance is running later. - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { srcMember, err = tx.GetNodeByName(ctx, inst.Location()) if err != nil { return fmt.Errorf("Failed getting current cluster member of instance %q", inst.Name()) diff --git a/cmd/incusd/instance_rebuild.go b/cmd/incusd/instance_rebuild.go index 3fc2e90ec9f..6503d734b7d 100644 --- a/cmd/incusd/instance_rebuild.go +++ b/cmd/incusd/instance_rebuild.go @@ -141,7 +141,7 @@ func instanceRebuildPost(d *Daemon, r *http.Request) response.Response { } if req.Source.Server != "" { - sourceImage, err = ensureDownloadedImageFitWithinBudget(s, r, op, *targetProject, sourceImage, sourceImageRef, req.Source, inst.Type().String()) + sourceImage, err = ensureDownloadedImageFitWithinBudget(context.TODO(), s, r, op, *targetProject, sourceImage, sourceImageRef, req.Source, inst.Type().String()) if err != nil { return err } @@ -151,7 +151,7 @@ func instanceRebuildPost(d *Daemon, r *http.Request) response.Response { return fmt.Errorf("Image not provided for instance rebuild") } - return instanceRebuildFromImage(s, r, inst, sourceImage, op) + return instanceRebuildFromImage(context.TODO(), s, r, inst, sourceImage, op) } resources := map[string][]api.URL{} diff --git a/cmd/incusd/instance_snapshot.go b/cmd/incusd/instance_snapshot.go index de4d2b06433..fb4fd630190 100644 --- a/cmd/incusd/instance_snapshot.go +++ b/cmd/incusd/instance_snapshot.go @@ -257,7 +257,7 @@ func instanceSnapshotsPost(d *Daemon, r *http.Request) response.Response { return response.BadRequest(fmt.Errorf("Invalid instance name")) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { dbProject, err := cluster.GetProject(context.Background(), tx.Tx(), projectName) if err != nil { return err @@ -732,7 +732,7 @@ func snapshotPost(s *state.State, r *http.Request, snapInst instance.Instance) r fullName := parentName + internalInstance.SnapshotDelimiter + newName - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Check that the name isn't already in use id, _ := tx.GetInstanceSnapshotID(ctx, snapInst.Project().Name, parentName, newName) if id > 0 { diff --git a/cmd/incusd/instances.go b/cmd/incusd/instances.go index 1a083d6f22e..a53f03522eb 100644 --- a/cmd/incusd/instances.go +++ b/cmd/incusd/instances.go @@ -239,7 +239,7 @@ func instancesStart(s *state.State, instances []instance.Instance) { instLogger.Warn("Failed auto start instance attempt", logger.Ctx{"attempt": attempt, "maxAttempts": maxAttempts, "err": err}) if attempt >= maxAttempts { - warnErr := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + warnErr := s.DB.Cluster.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.ClusterTx) error { // If unable to start after 3 tries, record a warning. return tx.UpsertWarningLocalNode(ctx, inst.Project().Name, cluster.TypeInstance, inst.ID(), warningtype.InstanceAutostartFailure, fmt.Sprintf("%v", err)) }) diff --git a/cmd/incusd/instances_post.go b/cmd/incusd/instances_post.go index f81bbec30c5..a68a499ee72 100644 --- a/cmd/incusd/instances_post.go +++ b/cmd/incusd/instances_post.go @@ -41,7 +41,7 @@ import ( "github.com/lxc/incus/shared/util" ) -func ensureDownloadedImageFitWithinBudget(s *state.State, r *http.Request, op *operations.Operation, p api.Project, img *api.Image, imgAlias string, source api.InstanceSource, imgType string) (*api.Image, error) { +func ensureDownloadedImageFitWithinBudget(ctx context.Context, s *state.State, r *http.Request, op *operations.Operation, p api.Project, img *api.Image, imgAlias string, source api.InstanceSource, imgType string) (*api.Image, error) { var autoUpdate bool var err error if p.Config["images.auto_update_cached"] != "" { @@ -51,7 +51,7 @@ func ensureDownloadedImageFitWithinBudget(s *state.State, r *http.Request, op *o } var budget int64 - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { budget, err = project.GetImageSpaceBudget(tx, p.Name) return err }) @@ -59,7 +59,7 @@ func ensureDownloadedImageFitWithinBudget(s *state.State, r *http.Request, op *o return nil, err } - imgDownloaded, err := ImageDownload(r, s, op, &ImageDownloadArgs{ + imgDownloaded, err := ImageDownload(ctx, r, s, op, &ImageDownloadArgs{ Server: source.Server, Protocol: source.Protocol, Certificate: source.Certificate, @@ -105,12 +105,12 @@ func createFromImage(s *state.State, r *http.Request, p api.Project, profiles [] } if req.Source.Server != "" { - img, err = ensureDownloadedImageFitWithinBudget(s, r, op, p, img, imgAlias, req.Source, string(req.Type)) + img, err = ensureDownloadedImageFitWithinBudget(context.TODO(), s, r, op, p, img, imgAlias, req.Source, string(req.Type)) if err != nil { return err } } else if img != nil { - err := ensureImageIsLocallyAvailable(s, r, img, args.Project, args.Type) + err := ensureImageIsLocallyAvailable(context.TODO(), s, r, img, args.Project, args.Type) if err != nil { return err } @@ -124,7 +124,7 @@ func createFromImage(s *state.State, r *http.Request, p api.Project, profiles [] } // Actually create the instance. - err = instanceCreateFromImage(s, r, img, args, op) + err = instanceCreateFromImage(context.TODO(), s, r, img, args, op) if err != nil { return err } @@ -204,8 +204,8 @@ func createFromNone(s *state.State, r *http.Request, projectName string, profile return operations.OperationResponse(op) } -func createFromMigration(s *state.State, r *http.Request, projectName string, profiles []api.Profile, req *api.InstancesPost) response.Response { - if s.DB.Cluster.LocalNodeIsEvacuated() && r.Context().Value(request.CtxProtocol) != "cluster" { +func createFromMigration(ctx context.Context, s *state.State, r *http.Request, projectName string, profiles []api.Profile, req *api.InstancesPost) response.Response { + if s.DB.Cluster.LocalNodeIsEvacuated() && r != nil && r.Context().Value(request.CtxProtocol) != "cluster" { return response.Forbidden(fmt.Errorf("Cluster member is evacuated")) } @@ -244,7 +244,7 @@ func createFromMigration(s *state.State, r *http.Request, projectName string, pr Stateful: req.Stateful, } - storagePool, storagePoolProfile, localRootDiskDeviceKey, localRootDiskDevice, resp := instanceFindStoragePool(s, projectName, req) + storagePool, storagePoolProfile, localRootDiskDeviceKey, localRootDiskDevice, resp := instanceFindStoragePool(ctx, s, projectName, req) if resp != nil { return resp } @@ -417,7 +417,7 @@ func createFromMigration(s *state.State, r *http.Request, projectName string, pr return operations.OperationResponse(op) } -func createFromCopy(s *state.State, r *http.Request, projectName string, profiles []api.Profile, req *api.InstancesPost) response.Response { +func createFromCopy(ctx context.Context, s *state.State, r *http.Request, projectName string, profiles []api.Profile, req *api.InstancesPost) response.Response { if s.DB.Cluster.LocalNodeIsEvacuated() { return response.Forbidden(fmt.Errorf("Cluster member is evacuated")) } @@ -447,19 +447,19 @@ func createFromCopy(s *state.State, r *http.Request, projectName string, profile _, rootDevice, _ := internalInstance.GetRootDiskDevice(source.ExpandedDevices().CloneNative()) sourcePoolName := rootDevice["pool"] - destPoolName, _, _, _, resp := instanceFindStoragePool(s, targetProject, req) + destPoolName, _, _, _, resp := instanceFindStoragePool(r.Context(), s, targetProject, req) if resp != nil { return resp } if sourcePoolName != destPoolName { // Redirect to migration - return clusterCopyContainerInternal(s, r, source, projectName, profiles, req) + return clusterCopyContainerInternal(ctx, s, r, source, projectName, profiles, req) } var pool *api.StoragePool - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { _, pool, _, err = tx.GetStoragePoolInAnyState(ctx, sourcePoolName) return err @@ -471,7 +471,7 @@ func createFromCopy(s *state.State, r *http.Request, projectName string, profile if !slices.Contains(db.StorageRemoteDriverNames(), pool.Driver) { // Redirect to migration - return clusterCopyContainerInternal(s, r, source, projectName, profiles, req) + return clusterCopyContainerInternal(ctx, s, r, source, projectName, profiles, req) } } } @@ -649,7 +649,7 @@ func createFromBackup(s *state.State, r *http.Request, projectName string, data // Check project permissions. var req api.InstancesPost - err = s.DB.Cluster.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { req = api.InstancesPost{ InstancePut: bInfo.Config.Container.InstancePut, Name: bInfo.Name, @@ -685,7 +685,7 @@ func createFromBackup(s *state.State, r *http.Request, projectName string, data "snapshots": bInfo.Snapshots, }) - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Check storage pool exists. _, _, _, err = tx.GetStoragePoolInAnyState(ctx, bInfo.Pool) @@ -701,7 +701,7 @@ func createFromBackup(s *state.State, r *http.Request, projectName string, data var profile *api.Profile - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Otherwise try and restore to the project's default profile pool. _, profile, err = tx.GetProfile(ctx, bInfo.Project, "default") @@ -751,7 +751,7 @@ func createFromBackup(s *state.State, r *http.Request, projectName string, data runRevert.Add(revertHook) - err = internalImportFromBackup(s, bInfo.Project, bInfo.Name, instanceName != "") + err = internalImportFromBackup(context.TODO(), s, bInfo.Project, bInfo.Name, instanceName != "") if err != nil { return fmt.Errorf("Failed importing backup: %w", err) } @@ -1160,15 +1160,15 @@ func instancesPost(d *Daemon, r *http.Request) response.Response { case "none": return createFromNone(s, r, targetProjectName, profiles, &req) case "migration": - return createFromMigration(s, r, targetProjectName, profiles, &req) + return createFromMigration(r.Context(), s, r, targetProjectName, profiles, &req) case "copy": - return createFromCopy(s, r, targetProjectName, profiles, &req) + return createFromCopy(r.Context(), s, r, targetProjectName, profiles, &req) default: return response.BadRequest(fmt.Errorf("Unknown source type %s", req.Source.Type)) } } -func instanceFindStoragePool(s *state.State, projectName string, req *api.InstancesPost) (string, string, string, map[string]string, response.Response) { +func instanceFindStoragePool(ctx context.Context, s *state.State, projectName string, req *api.InstancesPost) (string, string, string, map[string]string, response.Response) { // Grab the container's root device if one is specified storagePool := "" storagePoolProfile := "" @@ -1180,7 +1180,7 @@ func instanceFindStoragePool(s *state.State, projectName string, req *api.Instan // Handle copying/moving between two storage-api instances. if storagePool != "" { - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { _, err := tx.GetStoragePoolID(ctx, storagePool) return err @@ -1195,7 +1195,7 @@ func instanceFindStoragePool(s *state.State, projectName string, req *api.Instan // If we don't have a valid pool yet, look through profiles if storagePool == "" { - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { for _, pName := range req.Profiles { _, p, err := tx.GetProfile(ctx, projectName, pName) if err != nil { @@ -1223,7 +1223,7 @@ func instanceFindStoragePool(s *state.State, projectName string, req *api.Instan var pools []string - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var err error pools, err = tx.GetStoragePoolNames(ctx) @@ -1246,10 +1246,10 @@ func instanceFindStoragePool(s *state.State, projectName string, req *api.Instan return storagePool, storagePoolProfile, localRootDiskDeviceKey, localRootDiskDevice, nil } -func clusterCopyContainerInternal(s *state.State, r *http.Request, source instance.Instance, projectName string, profiles []api.Profile, req *api.InstancesPost) response.Response { +func clusterCopyContainerInternal(ctx context.Context, s *state.State, r *http.Request, source instance.Instance, projectName string, profiles []api.Profile, req *api.InstancesPost) response.Response { // Locate the source of the container var nodeAddress string - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { var err error // Load source node. @@ -1325,7 +1325,7 @@ func clusterCopyContainerInternal(s *state.State, r *http.Request, source instan req.Source.Project = "" // Run the migration - return createFromMigration(s, nil, projectName, profiles, req) + return createFromMigration(ctx, s, nil, projectName, profiles, req) } func instanceCreateFinish(s *state.State, req *api.InstancesPost, args db.InstanceArgs) error { diff --git a/cmd/incusd/main_test.go b/cmd/incusd/main_test.go index 3ff2dbec5ed..37ec87e5f20 100644 --- a/cmd/incusd/main_test.go +++ b/cmd/incusd/main_test.go @@ -74,7 +74,7 @@ func (suite *daemonTestSuite) SetupTest() { // Create the database entry for the storage pool. poolDescription := fmt.Sprintf("%s storage pool", daemonTestSuiteDefaultStoragePool) - _, err = dbStoragePoolCreateAndUpdateCache(suite.d.State(), daemonTestSuiteDefaultStoragePool, poolDescription, "mock", poolConfig) + _, err = dbStoragePoolCreateAndUpdateCache(context.Background(), suite.d.State(), daemonTestSuiteDefaultStoragePool, poolDescription, "mock", poolConfig) if err != nil { suite.T().Errorf("failed to create default storage pool: %v", err) } diff --git a/cmd/incusd/migrate_storage_volumes.go b/cmd/incusd/migrate_storage_volumes.go index 265e9784112..2a032e61b4e 100644 --- a/cmd/incusd/migrate_storage_volumes.go +++ b/cmd/incusd/migrate_storage_volumes.go @@ -70,7 +70,7 @@ func newStorageMigrationSource(volumeOnly bool, pushTarget *api.StorageVolumePos func (s *migrationSourceWs) DoStorage(state *state.State, projectName string, poolName string, volName string, migrateOp *operations.Operation) error { l := logger.AddContext(logger.Ctx{"project": projectName, "pool": poolName, "volume": volName, "push": s.pushOperationURL != ""}) - ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10) + ctx, cancel := context.WithTimeout(state.ShutdownCtx, time.Second*10) defer cancel() l.Info("Waiting for migration connections on source") @@ -176,7 +176,7 @@ func (s *migrationSourceWs) DoStorage(state *state.State, projectName string, po } } - fsConn, err := s.conns[api.SecretNameFilesystem].WebsocketIO(context.TODO()) + fsConn, err := s.conns[api.SecretNameFilesystem].WebsocketIO(state.ShutdownCtx) if err != nil { return err } @@ -243,7 +243,7 @@ func newStorageMigrationSink(args *migrationSinkArgs) (*migrationSink, error) { func (c *migrationSink) DoStorage(state *state.State, projectName string, poolName string, req *api.StorageVolumesPost, op *operations.Operation) error { l := logger.AddContext(logger.Ctx{"project": projectName, "pool": poolName, "volume": req.Name, "push": c.push}) - ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10) + ctx, cancel := context.WithTimeout(state.ShutdownCtx, time.Second*10) defer cancel() l.Info("Waiting for migration connections on target") @@ -425,7 +425,7 @@ func (c *migrationSink) DoStorage(state *state.State, projectName string, poolNa Refresh: c.refresh, } - fsConn, err := c.conns[api.SecretNameFilesystem].WebsocketIO(context.TODO()) + fsConn, err := c.conns[api.SecretNameFilesystem].WebsocketIO(state.ShutdownCtx) if err != nil { fsTransfer <- err return diff --git a/cmd/incusd/network_acls.go b/cmd/incusd/network_acls.go index f238a84a310..2cb75513e15 100644 --- a/cmd/incusd/network_acls.go +++ b/cmd/incusd/network_acls.go @@ -154,7 +154,7 @@ func networkACLsGet(d *Daemon, r *http.Request) response.Response { var aclNames []string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { var err error // Get list of Network ACLs. diff --git a/cmd/incusd/networks.go b/cmd/incusd/networks.go index 2c72144ac5e..c52724281a9 100644 --- a/cmd/incusd/networks.go +++ b/cmd/incusd/networks.go @@ -375,7 +375,7 @@ func networksPost(d *Daemon, r *http.Request) response.Response { // This is an internal request which triggers the actual creation of the network across all nodes // after they have been previously defined. - err = doNetworksCreate(s, n, clientType) + err = doNetworksCreate(r.Context(), s, n, clientType) if err != nil { return response.SmartError(err) } @@ -397,7 +397,7 @@ func networksPost(d *Daemon, r *http.Request) response.Response { } } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { return tx.CreatePendingNetwork(ctx, targetNode, projectName, req.Name, netType.DBType(), req.Config) }) if err != nil { @@ -435,7 +435,7 @@ func networksPost(d *Daemon, r *http.Request) response.Response { // Simulate adding pending node network config when the driver doesn't support per-node config. if !netTypeInfo.NodeSpecificConfig && clientType != clusterRequest.ClientTypeJoiner { // Create pending entry for each node. - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { members, err := tx.GetNodes(ctx) if err != nil { return fmt.Errorf("Failed getting cluster members: %w", err) @@ -457,7 +457,7 @@ func networksPost(d *Daemon, r *http.Request) response.Response { } } - err = networksPostCluster(s, projectName, netInfo, req, clientType, netType) + err = networksPostCluster(r.Context(), s, projectName, netInfo, req, clientType, netType) if err != nil { return response.SmartError(err) } @@ -492,7 +492,7 @@ func networksPost(d *Daemon, r *http.Request) response.Response { } revert.Add(func() { - _ = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + _ = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { return tx.DeleteNetwork(ctx, projectName, req.Name) }) }) @@ -502,7 +502,7 @@ func networksPost(d *Daemon, r *http.Request) response.Response { return response.SmartError(fmt.Errorf("Failed loading network: %w", err)) } - err = doNetworksCreate(s, n, clientType) + err = doNetworksCreate(r.Context(), s, n, clientType) if err != nil { return response.SmartError(err) } @@ -542,7 +542,7 @@ func networkPartiallyCreated(netInfo *api.Network) bool { // networksPostCluster checks that there is a pending network in the database and then attempts to setup the // network on each node. If all nodes are successfully setup then the network's state is set to created. // Accepts an optional existing network record, which will exist when performing subsequent re-create attempts. -func networksPostCluster(s *state.State, projectName string, netInfo *api.Network, req api.NetworksPost, clientType clusterRequest.ClientType, netType network.Type) error { +func networksPostCluster(ctx context.Context, s *state.State, projectName string, netInfo *api.Network, req api.NetworksPost, clientType clusterRequest.ClientType, netType network.Type) error { // Check that no node-specific config key has been supplied in request. for key := range req.Config { if slices.Contains(db.NodeSpecificNetworkConfig, key) { @@ -565,7 +565,7 @@ func networksPostCluster(s *state.State, projectName string, netInfo *api.Networ // Check that the network is properly defined, get the node-specific configs and merge with global config. var nodeConfigs map[string]map[string]string - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Check if any global config exists already, if so we should not create global config again. if netInfo != nil && networkPartiallyCreated(netInfo) { if len(req.Config) > 0 { @@ -625,7 +625,7 @@ func networksPostCluster(s *state.State, projectName string, netInfo *api.Networ netConfig := n.Config() - err = doNetworksCreate(s, n, clientType) + err = doNetworksCreate(ctx, s, n, clientType) if err != nil { return err } @@ -680,7 +680,7 @@ func networksPostCluster(s *state.State, projectName string, netInfo *api.Networ } // Mark network global status as networkCreated now that all nodes have succeeded. - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { return tx.NetworkCreated(projectName, req.Name) }) if err != nil { @@ -694,7 +694,7 @@ func networksPostCluster(s *state.State, projectName string, netInfo *api.Networ // Create the network on the system. The clusterNotification flag is used to indicate whether creation request // is coming from a cluster notification (and if so we should not delete the database record on error). -func doNetworksCreate(s *state.State, n network.Network, clientType clusterRequest.ClientType) error { +func doNetworksCreate(ctx context.Context, s *state.State, n network.Network, clientType clusterRequest.ClientType) error { revert := revert.New() defer revert.Fail() @@ -733,7 +733,7 @@ func doNetworksCreate(s *state.State, n network.Network, clientType clusterReque } // Mark local as status as networkCreated. - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { return tx.NetworkNodeCreated(n.ID()) }) if err != nil { @@ -1487,7 +1487,7 @@ func networkStartup(s *state.State) error { // Get a list of projects. var projectNames []string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.ClusterTx) error { projectNames, err = dbCluster.GetProjectNames(ctx, tx.Tx()) return err }) @@ -1505,7 +1505,7 @@ func networkStartup(s *state.State) error { networkPriorityLogical: make(map[network.ProjectNetwork]struct{}), } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.ClusterTx) error { for _, projectName := range projectNames { networkNames, err := tx.GetCreatedNetworkNamesByProject(ctx, projectName) if err != nil { @@ -1536,7 +1536,7 @@ func networkStartup(s *state.State) error { if err != nil { err = fmt.Errorf("Failed starting: %w", err) - _ = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + _ = s.DB.Cluster.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.ClusterTx) error { return tx.UpsertWarningLocalNode(ctx, n.Project(), dbCluster.TypeNetwork, int(n.ID()), warningtype.NetworkUnvailable, err.Error()) }) @@ -1745,7 +1745,7 @@ func networkRestartOVN(s *state.State) error { // Get a list of projects. var projectNames []string var err error - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.ClusterTx) error { projectNames, err = dbCluster.GetProjectNames(ctx, tx.Tx()) return err }) @@ -1757,7 +1757,7 @@ func networkRestartOVN(s *state.State) error { for _, projectName := range projectNames { var networkNames []string - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.ClusterTx) error { networkNames, err = tx.GetCreatedNetworkNamesByProject(ctx, projectName) return err diff --git a/cmd/incusd/operations.go b/cmd/incusd/operations.go index 5c5f140026d..1969890ba54 100644 --- a/cmd/incusd/operations.go +++ b/cmd/incusd/operations.go @@ -61,7 +61,7 @@ func waitForOperations(ctx context.Context, cluster *db.Cluster, consoleShutdown timeout := time.After(consoleShutdownTimeout) defer func() { - _ = cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + _ = cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { err := dbCluster.DeleteOperations(ctx, tx.Tx(), cluster.GetNodeID()) if err != nil { logger.Error("Failed cleaning up operations") @@ -192,7 +192,7 @@ func operationGet(d *Daemon, r *http.Request) response.Response { // Then check if the query is from an operation on another node, and, if so, forward it var address string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { filter := dbCluster.OperationFilter{UUID: &id} ops, err := dbCluster.GetOperations(ctx, tx.Tx(), filter) if err != nil { @@ -292,7 +292,7 @@ func operationDelete(d *Daemon, r *http.Request) response.Response { // Then check if the query is from an operation on another node, and, if so, forward it var address string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { filter := dbCluster.OperationFilter{UUID: &id} ops, err := dbCluster.GetOperations(ctx, tx.Tx(), filter) if err != nil { @@ -344,7 +344,7 @@ func operationCancel(s *state.State, r *http.Request, projectName string, op *ap // If not found locally, try connecting to remote member to delete it. var memberAddress string var err error - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { filter := dbCluster.OperationFilter{UUID: &op.ID} ops, err := dbCluster.GetOperations(ctx, tx.Tx(), filter) if err != nil { @@ -610,7 +610,7 @@ func operationsGet(d *Daemon, r *http.Request) response.Response { // Get all nodes with running operations in this project. var membersWithOps []string var members []db.NodeInfo - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { var err error if allProjects { @@ -733,7 +733,7 @@ func operationsGetByType(s *state.State, r *http.Request, projectName string, op // Get all operations of the specified type in project. var members []db.NodeInfo memberOps := make(map[string]map[string]dbCluster.Operation) - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { var err error members, err = tx.GetNodes(ctx) @@ -982,7 +982,7 @@ func operationWaitGet(d *Daemon, r *http.Request) response.Response { // Then check if the query is from an operation on another node, and, if so, forward it var address string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { filter := dbCluster.OperationFilter{UUID: &id} ops, err := dbCluster.GetOperations(ctx, tx.Tx(), filter) if err != nil { @@ -1113,7 +1113,7 @@ func operationWebsocketGet(d *Daemon, r *http.Request) response.Response { } var address string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { filter := dbCluster.OperationFilter{UUID: &id} ops, err := dbCluster.GetOperations(ctx, tx.Tx(), filter) if err != nil { @@ -1206,7 +1206,7 @@ func autoRemoveOrphanedOperations(ctx context.Context, s *state.State) error { offlineThreshold := s.GlobalConfig.OfflineThreshold() - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { members, err := tx.GetNodes(ctx) if err != nil { return fmt.Errorf("Failed getting cluster members: %w", err) diff --git a/cmd/incusd/profiles.go b/cmd/incusd/profiles.go index cc546195e8d..0e0a7c8f831 100644 --- a/cmd/incusd/profiles.go +++ b/cmd/incusd/profiles.go @@ -158,7 +158,7 @@ func profilesGet(d *Daemon, r *http.Request) response.Response { } var result any - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { filter := dbCluster.ProfileFilter{ Project: &p.Name, } @@ -295,7 +295,7 @@ func profilesPost(d *Daemon, r *http.Request) response.Response { } // Update DB entry. - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { devices, err := dbCluster.APIToDevices(req.Devices) if err != nil { return err @@ -400,7 +400,7 @@ func profileGet(d *Daemon, r *http.Request) response.Response { var resp *api.Profile - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { profile, err := dbCluster.GetProfile(ctx, tx.Tx(), p.Name, name) if err != nil { return fmt.Errorf("Fetch profile: %w", err) @@ -484,14 +484,14 @@ func profilePut(d *Daemon, r *http.Request) response.Response { return response.BadRequest(err) } - err = doProfileUpdateCluster(s, p.Name, name, old) + err = doProfileUpdateCluster(r.Context(), s, p.Name, name, old) return response.SmartError(err) } var id int64 var profile *api.Profile - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { current, err := dbCluster.GetProfile(ctx, tx.Tx(), p.Name, name) if err != nil { return fmt.Errorf("Failed to retrieve profile %q: %w", name, err) @@ -523,7 +523,7 @@ func profilePut(d *Daemon, r *http.Request) response.Response { return response.BadRequest(err) } - err = doProfileUpdate(s, *p, name, id, profile, req) + err = doProfileUpdate(r.Context(), s, *p, name, id, profile, req) if err == nil && !isClusterNotification(r) { // Notify all other nodes. If a node is down, it will be ignored. @@ -596,7 +596,7 @@ func profilePatch(d *Daemon, r *http.Request) response.Response { var id int64 var profile *api.Profile - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { current, err := dbCluster.GetProfile(ctx, tx.Tx(), p.Name, name) if err != nil { return fmt.Errorf("Failed to retrieve profile=%q: %w", name, err) @@ -675,7 +675,7 @@ func profilePatch(d *Daemon, r *http.Request) response.Response { requestor := request.CreateRequestor(r) s.Events.SendLifecycle(p.Name, lifecycle.ProfileUpdated.Event(name, p.Name, requestor, nil)) - return response.SmartError(doProfileUpdate(s, *p, name, id, profile, req)) + return response.SmartError(doProfileUpdate(r.Context(), s, *p, name, id, profile, req)) } // swagger:operation POST /1.0/profiles/{name} profiles profile_post @@ -746,7 +746,7 @@ func profilePost(d *Daemon, r *http.Request) response.Response { return response.BadRequest(fmt.Errorf("Invalid profile name %q", req.Name)) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Check that the name isn't already in use. _, err = dbCluster.GetProfile(ctx, tx.Tx(), p.Name, req.Name) if err == nil { @@ -812,7 +812,7 @@ func profileDelete(d *Daemon, r *http.Request) response.Response { return response.Forbidden(errors.New(`The "default" profile cannot be deleted`)) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { profile, err := dbCluster.GetProfile(ctx, tx.Tx(), p.Name, name) if err != nil { return err diff --git a/cmd/incusd/profiles_utils.go b/cmd/incusd/profiles_utils.go index 8aaef4cb4dc..b4c57968f53 100644 --- a/cmd/incusd/profiles_utils.go +++ b/cmd/incusd/profiles_utils.go @@ -15,9 +15,9 @@ import ( "github.com/lxc/incus/shared/api" ) -func doProfileUpdate(s *state.State, p api.Project, profileName string, id int64, profile *api.Profile, req api.ProfilePut) error { +func doProfileUpdate(ctx context.Context, s *state.State, p api.Project, profileName string, id int64, profile *api.Profile, req api.ProfilePut) error { // Check project limits. - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { return project.AllowProfileUpdate(tx, p.Name, profileName, req) }) if err != nil { @@ -37,7 +37,7 @@ func doProfileUpdate(s *state.State, p api.Project, profileName string, id int64 return err } - insts, projects, err := getProfileInstancesInfo(s.DB.Cluster, p.Name, profileName) + insts, projects, err := getProfileInstancesInfo(ctx, s.DB.Cluster, p.Name, profileName) if err != nil { return fmt.Errorf("Failed to query instances associated with profile %q: %w", profileName, err) } @@ -55,7 +55,7 @@ func doProfileUpdate(s *state.State, p api.Project, profileName string, id int64 continue } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Check what profile the device comes from by working backwards along the profiles list. for i := len(inst.Profiles) - 1; i >= 0; i-- { _, profile, err := tx.GetProfile(ctx, p.Name, inst.Profiles[i].Name) @@ -86,7 +86,7 @@ func doProfileUpdate(s *state.State, p api.Project, profileName string, id int64 } // Update the database. - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { devices, err := cluster.APIToDevices(req.Devices) if err != nil { return err @@ -140,7 +140,7 @@ func doProfileUpdate(s *state.State, p api.Project, profileName string, id int64 continue // This instance does not belong to this member, skip. } - err := doProfileUpdateInstance(s, inst, *projects[inst.Project]) + err := doProfileUpdateInstance(ctx, s, inst, *projects[inst.Project]) if err != nil { failures[&inst] = err } @@ -160,8 +160,8 @@ func doProfileUpdate(s *state.State, p api.Project, profileName string, id int64 // Like doProfileUpdate but does not update the database, since it was already // updated by doProfileUpdate itself, called on the notifying node. -func doProfileUpdateCluster(s *state.State, projectName string, profileName string, old api.ProfilePut) error { - insts, projects, err := getProfileInstancesInfo(s.DB.Cluster, projectName, profileName) +func doProfileUpdateCluster(ctx context.Context, s *state.State, projectName string, profileName string, old api.ProfilePut) error { + insts, projects, err := getProfileInstancesInfo(ctx, s.DB.Cluster, projectName, profileName) if err != nil { return fmt.Errorf("Failed to query instances associated with profile %q: %w", profileName, err) } @@ -185,7 +185,7 @@ func doProfileUpdateCluster(s *state.State, projectName string, profileName stri } } - err := doProfileUpdateInstance(s, inst, *projects[inst.Project]) + err := doProfileUpdateInstance(ctx, s, inst, *projects[inst.Project]) if err != nil { failures[&inst] = err } @@ -204,7 +204,7 @@ func doProfileUpdateCluster(s *state.State, projectName string, profileName stri } // Profile update of a single instance. -func doProfileUpdateInstance(s *state.State, args db.InstanceArgs, p api.Project) error { +func doProfileUpdateInstance(ctx context.Context, s *state.State, args db.InstanceArgs, p api.Project) error { profileNames := make([]string, 0, len(args.Profiles)) for _, profile := range args.Profiles { @@ -213,7 +213,7 @@ func doProfileUpdateInstance(s *state.State, args db.InstanceArgs, p api.Project var profiles []api.Profile - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var err error profiles, err = tx.GetProfiles(ctx, args.Project, profileNames) @@ -245,11 +245,11 @@ func doProfileUpdateInstance(s *state.State, args db.InstanceArgs, p api.Project } // Query the db for information about instances associated with the given profile. -func getProfileInstancesInfo(dbCluster *db.Cluster, projectName string, profileName string) (map[int]db.InstanceArgs, map[string]*api.Project, error) { +func getProfileInstancesInfo(ctx context.Context, dbCluster *db.Cluster, projectName string, profileName string) (map[int]db.InstanceArgs, map[string]*api.Project, error) { var projectInstNames map[string][]string // Query the db for information about instances associated with the given profile. - err := dbCluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := dbCluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var err error projectInstNames, err = tx.GetInstancesWithProfile(ctx, projectName, profileName) @@ -263,7 +263,7 @@ func getProfileInstancesInfo(dbCluster *db.Cluster, projectName string, profileN var instances map[int]db.InstanceArgs projects := make(map[string]*api.Project) - err = dbCluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = dbCluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var dbInstances []cluster.Instance for instProject, instNames := range projectInstNames { diff --git a/cmd/incusd/storage.go b/cmd/incusd/storage.go index c3cd594001b..390f5f893f8 100644 --- a/cmd/incusd/storage.go +++ b/cmd/incusd/storage.go @@ -46,11 +46,11 @@ func readStoragePoolDriversCache() ([]api.ServerStorageDriverInfo, map[string]st func storageStartup(s *state.State, forceCheck bool) error { // Update the storage drivers supported and used cache in api_1.0.go. - storagePoolDriversCacheUpdate(s) + storagePoolDriversCacheUpdate(s.ShutdownCtx, s) var poolNames []string - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.ClusterTx) error { var err error poolNames, err = tx.GetCreatedStoragePoolNames(ctx) @@ -88,7 +88,7 @@ func storageStartup(s *state.State, forceCheck bool) error { _, err = pool.Mount() if err != nil { logger.Error("Failed mounting storage pool", logger.Ctx{"pool": poolName, "err": err}) - _ = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + _ = s.DB.Cluster.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.ClusterTx) error { return tx.UpsertWarningLocalNode(ctx, "", cluster.TypeStoragePool, int(pool.ID()), warningtype.StoragePoolUnvailable, err.Error()) }) @@ -162,7 +162,7 @@ func storageStartup(s *state.State, forceCheck bool) error { return nil } -func storagePoolDriversCacheUpdate(s *state.State) { +func storagePoolDriversCacheUpdate(ctx context.Context, s *state.State) { // Get a list of all storage drivers currently in use // on this server. Only do this when we do not already have done // this once to avoid unnecessarily querying the db. All subsequent @@ -175,7 +175,7 @@ func storagePoolDriversCacheUpdate(s *state.State) { var drivers []string - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var err error drivers, err = tx.GetStoragePoolDrivers(ctx) diff --git a/cmd/incusd/storage_buckets_backup.go b/cmd/incusd/storage_buckets_backup.go index 0c4f190b71c..9122690c4f7 100644 --- a/cmd/incusd/storage_buckets_backup.go +++ b/cmd/incusd/storage_buckets_backup.go @@ -475,7 +475,7 @@ func storagePoolBucketBackupGet(d *Daemon, r *http.Request) response.Response { fullName := bucketName + internalInstance.SnapshotDelimiter + backupName - entry, err := storagePoolBucketBackupLoadByName(s, projectName, poolName, fullName) + entry, err := storagePoolBucketBackupLoadByName(r.Context(), s, projectName, poolName, fullName) if err != nil { return response.SmartError(err) } @@ -570,7 +570,7 @@ func storagePoolBucketBackupPost(d *Daemon, r *http.Request) response.Response { oldName := bucketName + internalInstance.SnapshotDelimiter + backupName - entry, err := storagePoolBucketBackupLoadByName(s, projectName, poolName, oldName) + entry, err := storagePoolBucketBackupLoadByName(r.Context(), s, projectName, poolName, oldName) if err != nil { return response.SmartError(err) } @@ -670,7 +670,7 @@ func storagePoolBucketBackupDelete(d *Daemon, r *http.Request) response.Response fullName := bucketName + internalInstance.SnapshotDelimiter + backupName - entry, err := storagePoolBucketBackupLoadByName(s, projectName, poolName, fullName) + entry, err := storagePoolBucketBackupLoadByName(r.Context(), s, projectName, poolName, fullName) if err != nil { return response.SmartError(err) } @@ -786,10 +786,10 @@ func storagePoolBucketBackupExportGet(d *Daemon, r *http.Request) response.Respo return response.FileResponse(r, []response.FileResponseEntry{ent}, nil) } -func storagePoolBucketBackupLoadByName(s *state.State, projectName, poolName, backupName string) (*backup.BucketBackup, error) { +func storagePoolBucketBackupLoadByName(ctx context.Context, s *state.State, projectName, poolName, backupName string) (*backup.BucketBackup, error) { var b db.StoragePoolBucketBackup - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var err error b, err = tx.GetStoragePoolBucketBackup(ctx, projectName, poolName, backupName) return err diff --git a/cmd/incusd/storage_pools.go b/cmd/incusd/storage_pools.go index ede7443fb39..165fd046865 100644 --- a/cmd/incusd/storage_pools.go +++ b/cmd/incusd/storage_pools.go @@ -147,7 +147,7 @@ func storagePoolsGet(d *Daemon, r *http.Request) response.Response { var poolNames []string - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { var err error poolNames, err = tx.GetStoragePoolNames(ctx) @@ -301,7 +301,7 @@ func storagePoolsPost(d *Daemon, r *http.Request) response.Response { var poolID int64 - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { var err error poolID, err = tx.GetStoragePoolID(ctx, req.Name) @@ -312,7 +312,7 @@ func storagePoolsPost(d *Daemon, r *http.Request) response.Response { return response.SmartError(err) } - _, err = storagePoolCreateLocal(s, poolID, req, clientType) + _, err = storagePoolCreateLocal(r.Context(), s, poolID, req, clientType) if err != nil { return response.SmartError(err) } @@ -334,7 +334,7 @@ func storagePoolsPost(d *Daemon, r *http.Request) response.Response { return response.BadRequest(err) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { return tx.CreatePendingStoragePool(ctx, targetNode, req.Name, req.Driver, req.Config) }) if err != nil { @@ -350,7 +350,7 @@ func storagePoolsPost(d *Daemon, r *http.Request) response.Response { var pool *api.StoragePool - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { var err error // Load existing pool if exists, if not don't fail. @@ -371,13 +371,13 @@ func storagePoolsPost(d *Daemon, r *http.Request) response.Response { // No targetNode was specified and we're clustered or there is an existing partially created single node // pool, either way finalize the config in the db and actually create the pool on all nodes in the cluster. if count > 1 || (pool != nil && pool.Status != api.StoragePoolStatusCreated) { - err = storagePoolsPostCluster(s, pool, req, clientType) + err = storagePoolsPostCluster(r.Context(), s, pool, req, clientType) if err != nil { return response.InternalError(err) } } else { // Create new single node storage pool. - err = storagePoolCreateGlobal(s, req, clientType) + err = storagePoolCreateGlobal(r.Context(), s, req, clientType) if err != nil { return response.SmartError(err) } @@ -416,7 +416,7 @@ func storagePoolPartiallyCreated(pool *api.StoragePool) bool { // storagePoolsPostCluster handles creating storage pools after the per-node config records have been created. // Accepts an optional existing pool record, which will exist when performing subsequent re-create attempts. -func storagePoolsPostCluster(s *state.State, pool *api.StoragePool, req api.StoragePoolsPost, clientType clusterRequest.ClientType) error { +func storagePoolsPostCluster(ctx context.Context, s *state.State, pool *api.StoragePool, req api.StoragePoolsPost, clientType clusterRequest.ClientType) error { // Check that no node-specific config key has been defined. for key := range req.Config { if slices.Contains(db.NodeSpecificStorageConfig, key) { @@ -440,7 +440,7 @@ func storagePoolsPostCluster(s *state.State, pool *api.StoragePool, req api.Stor // Check that the pool is properly defined, fetch the node-specific configs and insert the global config. var configs map[string]map[string]string var poolID int64 - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var err error // Check that the pool was defined at all. Must come before partially created checks. @@ -496,7 +496,7 @@ func storagePoolsPostCluster(s *state.State, pool *api.StoragePool, req api.Stor nodeReq.Config[key] = value } - updatedConfig, err := storagePoolCreateLocal(s, poolID, req, clientType) + updatedConfig, err := storagePoolCreateLocal(ctx, s, poolID, req, clientType) if err != nil { return err } @@ -544,7 +544,7 @@ func storagePoolsPostCluster(s *state.State, pool *api.StoragePool, req api.Stor } // Finally update the storage pool state. - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { return tx.StoragePoolCreated(req.Name) }) if err != nil { @@ -1019,7 +1019,7 @@ func storagePoolDelete(d *Daemon, r *http.Request) response.Response { return response.SmartError(err) } - err = dbStoragePoolDeleteAndUpdateCache(s, pool.Name()) + err = dbStoragePoolDeleteAndUpdateCache(r.Context(), s, pool.Name()) if err != nil { return response.SmartError(err) } diff --git a/cmd/incusd/storage_pools_utils.go b/cmd/incusd/storage_pools_utils.go index 820c3cac276..143560e46f6 100644 --- a/cmd/incusd/storage_pools_utils.go +++ b/cmd/incusd/storage_pools_utils.go @@ -14,8 +14,8 @@ import ( ) // storagePoolDBCreate creates a storage pool DB entry and returns the created Pool ID. -func storagePoolDBCreate(s *state.State, poolName string, poolDescription string, driver string, config map[string]string) (int64, error) { - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { +func storagePoolDBCreate(ctx context.Context, s *state.State, poolName string, poolDescription string, driver string, config map[string]string) (int64, error) { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Check that the storage pool does not already exist. _, err := tx.GetStoragePoolID(ctx, poolName) @@ -36,7 +36,7 @@ func storagePoolDBCreate(s *state.State, poolName string, poolDescription string } // Create the database entry for the storage pool. - id, err := dbStoragePoolCreateAndUpdateCache(s, poolName, poolDescription, driver, config) + id, err := dbStoragePoolCreateAndUpdateCache(ctx, s, poolName, poolDescription, driver, config) if err != nil { return -1, fmt.Errorf("Error inserting %s into database: %w", poolName, err) } @@ -65,9 +65,9 @@ func storagePoolValidate(s *state.State, poolName string, driverName string, con return nil } -func storagePoolCreateGlobal(state *state.State, req api.StoragePoolsPost, clientType request.ClientType) error { +func storagePoolCreateGlobal(ctx context.Context, state *state.State, req api.StoragePoolsPost, clientType request.ClientType) error { // Create the database entry. - id, err := storagePoolDBCreate(state, req.Name, req.Description, req.Driver, req.Config) + id, err := storagePoolDBCreate(ctx, state, req.Name, req.Description, req.Driver, req.Config) if err != nil { return err } @@ -79,9 +79,9 @@ func storagePoolCreateGlobal(state *state.State, req api.StoragePoolsPost, clien revert := revert.New() defer revert.Fail() - revert.Add(func() { _ = dbStoragePoolDeleteAndUpdateCache(state, req.Name) }) + revert.Add(func() { _ = dbStoragePoolDeleteAndUpdateCache(context.Background(), state, req.Name) }) - _, err = storagePoolCreateLocal(state, id, req, clientType) + _, err = storagePoolCreateLocal(ctx, state, id, req, clientType) if err != nil { return err } @@ -92,7 +92,7 @@ func storagePoolCreateGlobal(state *state.State, req api.StoragePoolsPost, clien // This performs local pool setup and updates DB record if config was changed during pool setup. // Returns resulting config. -func storagePoolCreateLocal(state *state.State, poolID int64, req api.StoragePoolsPost, clientType request.ClientType) (map[string]string, error) { +func storagePoolCreateLocal(ctx context.Context, state *state.State, poolID int64, req api.StoragePoolsPost, clientType request.ClientType) (map[string]string, error) { // Setup revert. revert := revert.New() defer revert.Fail() @@ -129,7 +129,7 @@ func storagePoolCreateLocal(state *state.State, poolID int64, req api.StoragePoo // see if something like this has happened. configDiff, _ := storagePools.ConfigDiff(req.Config, pool.Driver().Config()) if len(configDiff) > 0 { - err = state.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = state.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Update the database entry for the storage pool. return tx.UpdateStoragePool(ctx, req.Name, req.Description, pool.Driver().Config()) }) @@ -139,7 +139,7 @@ func storagePoolCreateLocal(state *state.State, poolID int64, req api.StoragePoo } // Set storage pool node to storagePoolCreated. - err = state.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = state.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { return tx.StoragePoolNodeCreated(poolID) }) if err != nil { @@ -153,10 +153,10 @@ func storagePoolCreateLocal(state *state.State, poolID int64, req api.StoragePoo } // Helper around the low-level DB API, which also updates the driver names cache. -func dbStoragePoolCreateAndUpdateCache(s *state.State, poolName string, poolDescription string, poolDriver string, poolConfig map[string]string) (int64, error) { +func dbStoragePoolCreateAndUpdateCache(ctx context.Context, s *state.State, poolName string, poolDescription string, poolDriver string, poolConfig map[string]string) (int64, error) { var id int64 - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var err error id, err = tx.CreateStoragePool(ctx, poolName, poolDescription, poolDriver, poolConfig) @@ -168,15 +168,15 @@ func dbStoragePoolCreateAndUpdateCache(s *state.State, poolName string, poolDesc } // Update the storage drivers cache in api_1.0.go. - storagePoolDriversCacheUpdate(s) + storagePoolDriversCacheUpdate(ctx, s) return id, nil } // Helper around the low-level DB API, which also updates the driver names // cache. -func dbStoragePoolDeleteAndUpdateCache(s *state.State, poolName string) error { - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { +func dbStoragePoolDeleteAndUpdateCache(ctx context.Context, s *state.State, poolName string) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { _, err := tx.RemoveStoragePool(ctx, poolName) return err @@ -186,7 +186,7 @@ func dbStoragePoolDeleteAndUpdateCache(s *state.State, poolName string) error { } // Update the storage drivers cache in api_1.0.go. - storagePoolDriversCacheUpdate(s) + storagePoolDriversCacheUpdate(ctx, s) return err } diff --git a/cmd/incusd/storage_volumes.go b/cmd/incusd/storage_volumes.go index a411c57cfe0..e4dbb5ed7e4 100644 --- a/cmd/incusd/storage_volumes.go +++ b/cmd/incusd/storage_volumes.go @@ -695,7 +695,7 @@ func storagePoolVolumesPost(d *Daemon, r *http.Request) response.Response { var poolID int64 var dbVolume *db.StorageVolume - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { poolID, err = tx.GetStoragePoolID(ctx, poolName) if err != nil { return err @@ -1276,7 +1276,7 @@ func storagePoolVolumePost(d *Daemon, r *http.Request) response.Response { targetPoolName = srcPoolName } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { targetPoolID, err = tx.GetStoragePoolID(ctx, targetPoolName) return err @@ -1285,7 +1285,7 @@ func storagePoolVolumePost(d *Daemon, r *http.Request) response.Response { return response.SmartError(err) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Check that the name isn't already in use. _, err = tx.GetStoragePoolNodeVolumeID(ctx, targetProjectName, req.Name, volumeType, targetPoolID) @@ -1313,7 +1313,7 @@ func storagePoolVolumePost(d *Daemon, r *http.Request) response.Response { var volumeNotFound bool var targetIsSet bool - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Load source volume. srcPoolID, err := tx.GetStoragePoolID(ctx, srcPoolName) if err != nil { @@ -1550,7 +1550,7 @@ func storagePoolVolumeTypePostRename(s *state.State, r *http.Request, poolName s defer revert.Fail() // Update devices using the volume in instances and profiles. - err = storagePoolVolumeUpdateUsers(s, projectName, pool.Name(), vol, pool.Name(), &newVol) + err = storagePoolVolumeUpdateUsers(r.Context(), s, projectName, pool.Name(), vol, pool.Name(), &newVol) if err != nil { return response.SmartError(err) } @@ -1591,13 +1591,13 @@ func storagePoolVolumeTypePostMove(s *state.State, r *http.Request, poolName str defer revert.Fail() // Update devices using the volume in instances and profiles. - err = storagePoolVolumeUpdateUsers(s, requestProjectName, pool.Name(), vol, newPool.Name(), &newVol) + err = storagePoolVolumeUpdateUsers(context.TODO(), s, requestProjectName, pool.Name(), vol, newPool.Name(), &newVol) if err != nil { return err } revert.Add(func() { - _ = storagePoolVolumeUpdateUsers(s, projectName, newPool.Name(), &newVol, pool.Name(), vol) + _ = storagePoolVolumeUpdateUsers(context.TODO(), s, projectName, newPool.Name(), &newVol, pool.Name(), vol) }) // Provide empty description and nil config to instruct CreateCustomVolumeFromCopy to copy it @@ -1718,7 +1718,7 @@ func storagePoolVolumeGet(d *Daemon, r *http.Request) response.Response { var dbVolume *db.StorageVolume - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Get the ID of the storage pool the storage volume is supposed to be attached to. poolID, err := tx.GetStoragePoolID(ctx, poolName) if err != nil { @@ -2355,7 +2355,7 @@ func createStoragePoolVolumeFromBackup(s *state.State, r *http.Request, requestP "snapshots": bInfo.Snapshots, }) - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Check storage pool exists. _, _, _, err = tx.GetStoragePoolInAnyState(ctx, bInfo.Pool) @@ -2371,7 +2371,7 @@ func createStoragePoolVolumeFromBackup(s *state.State, r *http.Request, requestP var profile *api.Profile - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Otherwise try and restore to the project's default profile pool. _, profile, err = tx.GetProfile(ctx, bInfo.Project, "default") diff --git a/cmd/incusd/storage_volumes_backup.go b/cmd/incusd/storage_volumes_backup.go index 4e9f8403302..d1ef4431fc1 100644 --- a/cmd/incusd/storage_volumes_backup.go +++ b/cmd/incusd/storage_volumes_backup.go @@ -192,7 +192,7 @@ func storagePoolVolumeTypeCustomBackupsGet(d *Daemon, r *http.Request) response. var poolID int64 - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { var err error poolID, _, _, err = tx.GetStoragePool(ctx, poolName) @@ -336,7 +336,7 @@ func storagePoolVolumeTypeCustomBackupsPost(d *Daemon, r *http.Request) response var poolID int64 - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { var err error poolID, _, _, err = tx.GetStoragePool(ctx, poolName) @@ -564,7 +564,7 @@ func storagePoolVolumeTypeCustomBackupGet(d *Daemon, r *http.Request) response.R fullName := volumeName + internalInstance.SnapshotDelimiter + backupName - backup, err := storagePoolVolumeBackupLoadByName(s, projectName, poolName, fullName) + backup, err := storagePoolVolumeBackupLoadByName(r.Context(), s, projectName, poolName, fullName) if err != nil { return response.SmartError(err) } @@ -675,7 +675,7 @@ func storagePoolVolumeTypeCustomBackupPost(d *Daemon, r *http.Request) response. oldName := volumeName + internalInstance.SnapshotDelimiter + backupName - backup, err := storagePoolVolumeBackupLoadByName(s, projectName, poolName, oldName) + backup, err := storagePoolVolumeBackupLoadByName(r.Context(), s, projectName, poolName, oldName) if err != nil { return response.SmartError(err) } @@ -791,7 +791,7 @@ func storagePoolVolumeTypeCustomBackupDelete(d *Daemon, r *http.Request) respons fullName := volumeName + internalInstance.SnapshotDelimiter + backupName - backup, err := storagePoolVolumeBackupLoadByName(s, projectName, poolName, fullName) + backup, err := storagePoolVolumeBackupLoadByName(r.Context(), s, projectName, poolName, fullName) if err != nil { return response.SmartError(err) } @@ -902,7 +902,7 @@ func storagePoolVolumeTypeCustomBackupExportGet(d *Daemon, r *http.Request) resp fullName := volumeName + internalInstance.SnapshotDelimiter + backupName // Ensure the volume exists - _, err = storagePoolVolumeBackupLoadByName(s, projectName, poolName, fullName) + _, err = storagePoolVolumeBackupLoadByName(r.Context(), s, projectName, poolName, fullName) if err != nil { return response.SmartError(err) } diff --git a/cmd/incusd/storage_volumes_snapshot.go b/cmd/incusd/storage_volumes_snapshot.go index d9c81fd5683..85fffeb0e8d 100644 --- a/cmd/incusd/storage_volumes_snapshot.go +++ b/cmd/incusd/storage_volumes_snapshot.go @@ -171,7 +171,7 @@ func storagePoolVolumeSnapshotsTypePost(d *Daemon, r *http.Request) response.Res if req.Name == "" { var i int - _ = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + _ = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { i = tx.GetNextStorageVolumeSnapshotIndex(ctx, poolName, volumeName, volumeType, "snap%d") return nil @@ -396,7 +396,7 @@ func storagePoolVolumeSnapshotsTypeGet(d *Daemon, r *http.Request) response.Resp var poolID int64 var volumes []db.StorageVolumeArgs - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { var err error // Retrieve ID of the storage pool (and check if the storage pool exists). @@ -705,7 +705,7 @@ func storagePoolVolumeSnapshotTypeGet(d *Daemon, r *http.Request) response.Respo var dbVolume *db.StorageVolume var expiry time.Time - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Get the snapshot. poolID, _, _, err = tx.GetStoragePool(ctx, poolName) if err != nil { @@ -835,7 +835,7 @@ func storagePoolVolumeSnapshotTypePut(d *Daemon, r *http.Request) response.Respo var dbVolume *db.StorageVolume var expiry time.Time - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Get the snapshot. poolID, _, _, err = tx.GetStoragePool(ctx, poolName) if err != nil { @@ -970,7 +970,7 @@ func storagePoolVolumeSnapshotTypePatch(d *Daemon, r *http.Request) response.Res var dbVolume *db.StorageVolume var expiry time.Time - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { // Get the snapshot. poolID, _, _, err = tx.GetStoragePool(ctx, poolName) if err != nil { @@ -1422,7 +1422,7 @@ func autoCreateCustomVolumeSnapshots(ctx context.Context, s *state.State, volume return err // Stop if context is cancelled. } - snapshotName, err := volumeDetermineNextSnapshotName(s, v, "snap%d") + snapshotName, err := volumeDetermineNextSnapshotName(ctx, s, v, "snap%d") if err != nil { return fmt.Errorf("Error retrieving next snapshot name for volume %q (project %q, pool %q): %w", v.Name, v.ProjectName, v.PoolName, err) } @@ -1446,7 +1446,7 @@ func autoCreateCustomVolumeSnapshots(ctx context.Context, s *state.State, volume return nil } -func volumeDetermineNextSnapshotName(s *state.State, volume db.StorageVolumeArgs, defaultPattern string) (string, error) { +func volumeDetermineNextSnapshotName(ctx context.Context, s *state.State, volume db.StorageVolumeArgs, defaultPattern string) (string, error) { var err error pattern, ok := volume.Config["snapshots.pattern"] @@ -1467,7 +1467,7 @@ func volumeDetermineNextSnapshotName(s *state.State, volume db.StorageVolumeArgs } else if count == 1 { var i int - _ = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + _ = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { i = tx.GetNextStorageVolumeSnapshotIndex(ctx, volume.PoolName, volume.Name, db.StoragePoolVolumeTypeCustom, pattern) return nil @@ -1482,7 +1482,7 @@ func volumeDetermineNextSnapshotName(s *state.State, volume db.StorageVolumeArgs var projects []string var pools []string - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { projects, err = dbCluster.GetProjectNames(ctx, tx.Tx()) if err != nil { return err @@ -1502,7 +1502,7 @@ func volumeDetermineNextSnapshotName(s *state.State, volume db.StorageVolumeArgs for _, pool := range pools { var poolID int64 - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { poolID, err = tx.GetStoragePoolID(ctx, pool) if err != nil { return err @@ -1536,7 +1536,7 @@ func volumeDetermineNextSnapshotName(s *state.State, volume db.StorageVolumeArgs if snapshotExists { var i int - _ = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + _ = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { i = tx.GetNextStorageVolumeSnapshotIndex(ctx, volume.PoolName, volume.Name, db.StoragePoolVolumeTypeCustom, pattern) return nil diff --git a/cmd/incusd/storage_volumes_utils.go b/cmd/incusd/storage_volumes_utils.go index d7935ccb570..ac1e24b5d9b 100644 --- a/cmd/incusd/storage_volumes_utils.go +++ b/cmd/incusd/storage_volumes_utils.go @@ -16,7 +16,7 @@ import ( var supportedVolumeTypes = []int{db.StoragePoolVolumeTypeContainer, db.StoragePoolVolumeTypeVM, db.StoragePoolVolumeTypeCustom, db.StoragePoolVolumeTypeImage} -func storagePoolVolumeUpdateUsers(s *state.State, projectName string, oldPoolName string, oldVol *api.StorageVolume, newPoolName string, newVol *api.StorageVolume) error { +func storagePoolVolumeUpdateUsers(ctx context.Context, s *state.State, projectName string, oldPoolName string, oldVol *api.StorageVolume, newPoolName string, newVol *api.StorageVolume) error { // Update all instances that are using the volume with a local (non-expanded) device. err := storagePools.VolumeUsedByInstanceDevices(s, oldPoolName, projectName, oldVol, false, func(dbInst db.InstanceArgs, project api.Project, usedByDevices []string) error { inst, err := instance.Load(s, dbInst, project) @@ -69,7 +69,7 @@ func storagePoolVolumeUpdateUsers(s *state.State, projectName string, oldPoolNam pUpdate.Config = profile.Config pUpdate.Description = profile.Description pUpdate.Devices = profile.Devices - err = doProfileUpdate(s, p, profile.Name, profileID, &profile, pUpdate) + err = doProfileUpdate(ctx, s, p, profile.Name, profileID, &profile, pUpdate) if err != nil { return err } @@ -134,10 +134,10 @@ func storagePoolVolumeUsedByGet(s *state.State, requestProjectName string, poolN return volumeUsedBy, nil } -func storagePoolVolumeBackupLoadByName(s *state.State, projectName, poolName, backupName string) (*backup.VolumeBackup, error) { +func storagePoolVolumeBackupLoadByName(ctx context.Context, s *state.State, projectName, poolName, backupName string) (*backup.VolumeBackup, error) { var b db.StoragePoolVolumeBackup - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { var err error b, err = tx.GetStoragePoolVolumeBackup(ctx, projectName, poolName, backupName) return err diff --git a/cmd/incusd/warnings.go b/cmd/incusd/warnings.go index c7129683e92..5fea30b392c 100644 --- a/cmd/incusd/warnings.go +++ b/cmd/incusd/warnings.go @@ -171,7 +171,7 @@ func warningsGet(d *Daemon, r *http.Request) response.Response { projectName := request.QueryParam(r, "project") var warnings []api.Warning - err = d.State().DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = d.State().DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { filters := []cluster.WarningFilter{} if projectName != "" { filter := cluster.WarningFilter{Project: &projectName} @@ -269,7 +269,7 @@ func warningGet(d *Daemon, r *http.Request) response.Response { } var resp api.Warning - err = d.State().DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = d.State().DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { dbWarning, err := cluster.GetWarning(ctx, tx.Tx(), id) if err != nil { return err @@ -375,7 +375,7 @@ func warningPut(d *Daemon, r *http.Request) response.Response { return response.Forbidden(fmt.Errorf(`Status may only be set to "acknowledge" or "new"`)) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { err := tx.UpdateWarningStatus(id, status) if err != nil { return err @@ -418,7 +418,7 @@ func warningDelete(d *Daemon, r *http.Request) response.Response { return response.SmartError(err) } - err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err = s.DB.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { err := cluster.DeleteWarning(ctx, tx.Tx(), id) if err != nil { return err @@ -469,7 +469,7 @@ func pruneResolvedWarningsTask(d *Daemon) (task.Func, task.Schedule) { } func pruneResolvedWarnings(ctx context.Context, s *state.State) error { - err := s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error { + err := s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { // Retrieve warnings by resolved status. statusResolved := warningtype.StatusResolved filter := cluster.WarningFilter{