diff --git a/cmd/incusd/api_internal_recover.go b/cmd/incusd/api_internal_recover.go index e9d1473ca70..0e1264eacab 100644 --- a/cmd/incusd/api_internal_recover.go +++ b/cmd/incusd/api_internal_recover.go @@ -80,6 +80,11 @@ func internalRecoverScan(ctx context.Context, s *state.State, userPools []api.St return err } + profileConfigs, err := dbCluster.GetConfig(ctx, tx.Tx(), "profile") + if err != nil { + return err + } + profileDevices, err := dbCluster.GetDevices(ctx, tx.Tx(), "profile") if err != nil { return err @@ -92,7 +97,7 @@ func internalRecoverScan(ctx context.Context, s *state.State, userPools []api.St projectProfiles[profile.Project] = []*api.Profile{} } - apiProfile, err := profile.ToAPI(ctx, tx.Tx(), profileDevices) + apiProfile, err := profile.ToAPI(ctx, tx.Tx(), profileConfigs, profileDevices) if err != nil { return err } diff --git a/cmd/incusd/instance_patch.go b/cmd/incusd/instance_patch.go index de48b44b727..544e7a18026 100644 --- a/cmd/incusd/instance_patch.go +++ b/cmd/incusd/instance_patch.go @@ -192,13 +192,18 @@ func instancePatch(d *Daemon, r *http.Request) response.Response { return err } + profileConfigs, err := cluster.GetConfig(ctx, tx.Tx(), "profile") + if err != nil { + return err + } + profileDevices, err := cluster.GetDevices(ctx, tx.Tx(), "profile") if err != nil { return err } for _, profile := range profiles { - apiProfile, err := profile.ToAPI(ctx, tx.Tx(), profileDevices) + apiProfile, err := profile.ToAPI(ctx, tx.Tx(), profileConfigs, profileDevices) if err != nil { return err } diff --git a/cmd/incusd/instance_post.go b/cmd/incusd/instance_post.go index 88024df6a32..c8753817e73 100644 --- a/cmd/incusd/instance_post.go +++ b/cmd/incusd/instance_post.go @@ -636,13 +636,18 @@ func migrateInstance(ctx context.Context, s *state.State, inst instance.Instance return err } + profileConfigs, err := dbCluster.GetConfig(ctx, tx.Tx(), "profile") + if err != nil { + return err + } + profileDevices, err := dbCluster.GetDevices(ctx, tx.Tx(), "profile") if err != nil { return err } for _, profile := range rawProfiles { - apiProfile, err := profile.ToAPI(ctx, tx.Tx(), profileDevices) + apiProfile, err := profile.ToAPI(ctx, tx.Tx(), profileConfigs, profileDevices) if err != nil { return err } diff --git a/cmd/incusd/instance_put.go b/cmd/incusd/instance_put.go index 3ef106807e0..3297367d8bd 100644 --- a/cmd/incusd/instance_put.go +++ b/cmd/incusd/instance_put.go @@ -138,13 +138,18 @@ func instancePut(d *Daemon, r *http.Request) response.Response { return err } + profileConfigs, err := cluster.GetConfig(ctx, tx.Tx(), "profile") + if err != nil { + return err + } + profileDevices, err := cluster.GetDevices(ctx, tx.Tx(), "profile") if err != nil { return err } for _, profile := range profiles { - apiProfile, err := profile.ToAPI(ctx, tx.Tx(), profileDevices) + apiProfile, err := profile.ToAPI(ctx, tx.Tx(), profileConfigs, profileDevices) if err != nil { return err } diff --git a/cmd/incusd/instances_post.go b/cmd/incusd/instances_post.go index f6c7fde9aca..d3161a10b0e 100644 --- a/cmd/incusd/instances_post.go +++ b/cmd/incusd/instances_post.go @@ -993,6 +993,11 @@ func instancesPost(d *Daemon, r *http.Request) response.Response { return err } + dbProfileConfigs, err := dbCluster.GetConfig(ctx, tx.Tx(), "profile") + if err != nil { + return err + } + dbProfileDevices, err := dbCluster.GetDevices(ctx, tx.Tx(), "profile") if err != nil { return err @@ -1009,7 +1014,7 @@ func instancesPost(d *Daemon, r *http.Request) response.Response { return fmt.Errorf("Requested profile %q doesn't exist", profileName) } - apiProfile, err := profile.ToAPI(ctx, tx.Tx(), dbProfileDevices) + apiProfile, err := profile.ToAPI(ctx, tx.Tx(), dbProfileConfigs, dbProfileDevices) if err != nil { return err } diff --git a/cmd/incusd/profiles.go b/cmd/incusd/profiles.go index 1a430b0b48a..21451d5ae82 100644 --- a/cmd/incusd/profiles.go +++ b/cmd/incusd/profiles.go @@ -190,6 +190,11 @@ func profilesGet(d *Daemon, r *http.Request) response.Response { } if recursion { + profileConfigs, err := dbCluster.GetConfig(ctx, tx.Tx(), "profile") + if err != nil { + return err + } + profileDevices, err := dbCluster.GetDevices(ctx, tx.Tx(), "profile") if err != nil { return err @@ -201,7 +206,7 @@ func profilesGet(d *Daemon, r *http.Request) response.Response { continue } - apiProfile, err := profile.ToAPI(ctx, tx.Tx(), profileDevices) + apiProfile, err := profile.ToAPI(ctx, tx.Tx(), profileConfigs, profileDevices) if err != nil { return err } @@ -437,12 +442,17 @@ func profileGet(d *Daemon, r *http.Request) response.Response { return fmt.Errorf("Fetch profile: %w", err) } + profileConfigs, err := dbCluster.GetConfig(ctx, tx.Tx(), "profile") + if err != nil { + return err + } + profileDevices, err := dbCluster.GetDevices(ctx, tx.Tx(), "profile") if err != nil { return err } - resp, err = profile.ToAPI(ctx, tx.Tx(), profileDevices) + resp, err = profile.ToAPI(ctx, tx.Tx(), profileConfigs, profileDevices) if err != nil { return err } @@ -533,7 +543,7 @@ func profilePut(d *Daemon, r *http.Request) response.Response { return fmt.Errorf("Failed to retrieve profile %q: %w", name, err) } - profile, err = current.ToAPI(ctx, tx.Tx(), nil) + profile, err = current.ToAPI(ctx, tx.Tx(), nil, nil) if err != nil { return err } @@ -638,7 +648,7 @@ func profilePatch(d *Daemon, r *http.Request) response.Response { return fmt.Errorf("Failed to retrieve profile=%q: %w", name, err) } - profile, err = current.ToAPI(ctx, tx.Tx(), nil) + profile, err = current.ToAPI(ctx, tx.Tx(), nil, nil) if err != nil { return err } diff --git a/internal/server/backup/backup_config_utils.go b/internal/server/backup/backup_config_utils.go index 0404e49b2ba..597a6b9f6f0 100644 --- a/internal/server/backup/backup_config_utils.go +++ b/internal/server/backup/backup_config_utils.go @@ -51,6 +51,12 @@ func ConfigToInstanceDBArgs(state *state.State, c *config.Config, projectName st return err } + // Get all the profile configs. + profileConfigs, err := cluster.GetConfig(ctx, tx.Tx(), "profile") + if err != nil { + return err + } + // Get all the profile devices. profileDevices, err := cluster.GetDevices(ctx, tx.Tx(), "profile") if err != nil { @@ -58,7 +64,7 @@ func ConfigToInstanceDBArgs(state *state.State, c *config.Config, projectName st } for _, profile := range profiles { - apiProfile, err := profile.ToAPI(ctx, tx.Tx(), profileDevices) + apiProfile, err := profile.ToAPI(ctx, tx.Tx(), profileConfigs, profileDevices) if err != nil { return err } diff --git a/internal/server/db/cluster/instances.go b/internal/server/db/cluster/instances.go index 98e3088be83..2c3b7b1493c 100644 --- a/internal/server/db/cluster/instances.go +++ b/internal/server/db/cluster/instances.go @@ -77,12 +77,19 @@ type InstanceFilter struct { } // ToAPI converts the database Instance to API type. -func (i *Instance) ToAPI(ctx context.Context, tx *sql.Tx, instanceDevices map[int][]Device, profileDevices map[int][]Device) (*api.Instance, error) { +func (i *Instance) ToAPI(ctx context.Context, tx *sql.Tx, instanceDevices map[int][]Device, profileConfigs map[int]map[string]string, profileDevices map[int][]Device) (*api.Instance, error) { profiles, err := GetInstanceProfiles(ctx, tx, i.ID) if err != nil { return nil, err } + if profileConfigs == nil { + profileConfigs, err = GetConfig(ctx, tx, "profile") + if err != nil { + return nil, err + } + } + if profileDevices == nil { profileDevices, err = GetDevices(ctx, tx, "profile") if err != nil { @@ -93,7 +100,7 @@ func (i *Instance) ToAPI(ctx context.Context, tx *sql.Tx, instanceDevices map[in apiProfiles := make([]api.Profile, 0, len(profiles)) profileNames := make([]string, 0, len(profiles)) for _, p := range profiles { - apiProfile, err := p.ToAPI(ctx, tx, profileDevices) + apiProfile, err := p.ToAPI(ctx, tx, profileConfigs, profileDevices) if err != nil { return nil, err } diff --git a/internal/server/db/cluster/profiles.go b/internal/server/db/cluster/profiles.go index dc59883b49b..acf07c087f4 100644 --- a/internal/server/db/cluster/profiles.go +++ b/internal/server/db/cluster/profiles.go @@ -52,21 +52,31 @@ type ProfileFilter struct { } // ToAPI returns a cluster Profile as an API struct. -func (p *Profile) ToAPI(ctx context.Context, tx *sql.Tx, profileDevices map[int][]Device) (*api.Profile, error) { - config, err := GetProfileConfig(ctx, tx, p.ID) - if err != nil { - return nil, err +func (p *Profile) ToAPI(ctx context.Context, tx *sql.Tx, profileConfigs map[int]map[string]string, profileDevices map[int][]Device) (*api.Profile, error) { + var err error + + var dbConfig map[string]string + if profileConfigs != nil { + dbConfig = profileConfigs[p.ID] + if dbConfig == nil { + dbConfig = map[string]string{} + } + } else { + dbConfig, err = GetProfileConfig(ctx, tx, p.ID) + if err != nil { + return nil, err + } } - var devices map[string]Device + var dbDevices map[string]Device if profileDevices != nil { - devices = map[string]Device{} + dbDevices = map[string]Device{} for _, dev := range profileDevices[p.ID] { - devices[dev.Name] = dev + dbDevices[dev.Name] = dev } } else { - devices, err = GetProfileDevices(ctx, tx, p.ID) + dbDevices, err = GetProfileDevices(ctx, tx, p.ID) if err != nil { return nil, err } @@ -76,8 +86,8 @@ func (p *Profile) ToAPI(ctx context.Context, tx *sql.Tx, profileDevices map[int] Name: p.Name, ProfilePut: api.ProfilePut{ Description: p.Description, - Config: config, - Devices: DevicesToAPI(devices), + Config: dbConfig, + Devices: DevicesToAPI(dbDevices), }, Project: p.Project, } diff --git a/internal/server/db/instances.go b/internal/server/db/instances.go index cad70562540..a78eb595aca 100644 --- a/internal/server/db/instances.go +++ b/internal/server/db/instances.go @@ -534,6 +534,12 @@ func (c *ClusterTx) instanceProfilesFill(ctx context.Context, snapshotsMode bool return fmt.Errorf("Failed loading profiles: %w", err) } + // Get all the profile configs. + profileConfigs, err := cluster.GetConfig(context.TODO(), c.Tx(), "profile") + if err != nil { + return fmt.Errorf("Failed loading profile configs: %w", err) + } + // Get all the profile devices. profileDevices, err := cluster.GetDevices(context.TODO(), c.Tx(), "profile") if err != nil { @@ -549,7 +555,7 @@ func (c *ClusterTx) instanceProfilesFill(ctx context.Context, snapshotsMode bool continue } - profilesByID[profile.ID], err = profile.ToAPI(context.TODO(), c.tx, profileDevices) + profilesByID[profile.ID], err = profile.ToAPI(context.TODO(), c.tx, profileConfigs, profileDevices) if err != nil { return err } diff --git a/internal/server/db/profiles.go b/internal/server/db/profiles.go index fde0fc4e8a5..9a4484fcdb2 100644 --- a/internal/server/db/profiles.go +++ b/internal/server/db/profiles.go @@ -61,7 +61,7 @@ func (c *ClusterTx) GetProfile(ctx context.Context, project, name string) (int64 profile := profiles[0] id := int64(profile.ID) - result, err := profile.ToAPI(ctx, c.tx, nil) + result, err := profile.ToAPI(ctx, c.tx, nil, nil) if err != nil { return -1, nil, err } @@ -78,6 +78,12 @@ func (c *ClusterTx) GetProfiles(ctx context.Context, projectName string, profile return nil, err } + // Get all the profile configs. + profileConfigs, err := cluster.GetConfig(ctx, c.Tx(), "profile") + if err != nil { + return nil, err + } + // Get all the profile devices. profileDevices, err := cluster.GetDevices(ctx, c.Tx(), "profile") if err != nil { @@ -85,7 +91,7 @@ func (c *ClusterTx) GetProfiles(ctx context.Context, projectName string, profile } for i, profile := range dbProfiles { - apiProfile, err := profile.ToAPI(ctx, c.tx, profileDevices) + apiProfile, err := profile.ToAPI(ctx, c.tx, profileConfigs, profileDevices) if err != nil { return nil, err } diff --git a/internal/server/project/permissions.go b/internal/server/project/permissions.go index 551b1871555..c6044983d8e 100644 --- a/internal/server/project/permissions.go +++ b/internal/server/project/permissions.go @@ -1257,6 +1257,11 @@ func fetchProject(tx *db.ClusterTx, projectName string, skipIfNoLimits bool) (*p return nil, fmt.Errorf("Fetch profiles from database: %w", err) } + dbProfileConfigs, err := cluster.GetConfig(ctx, tx.Tx(), "profile") + if err != nil { + return nil, fmt.Errorf("Fetch profile configs from database: %w", err) + } + dbProfileDevices, err := cluster.GetDevices(ctx, tx.Tx(), "profile") if err != nil { return nil, fmt.Errorf("Fetch profile devices from database: %w", err) @@ -1264,7 +1269,7 @@ func fetchProject(tx *db.ClusterTx, projectName string, skipIfNoLimits bool) (*p profiles := make([]api.Profile, 0, len(dbProfiles)) for _, profile := range dbProfiles { - apiProfile, err := profile.ToAPI(ctx, tx.Tx(), dbProfileDevices) + apiProfile, err := profile.ToAPI(ctx, tx.Tx(), dbProfileConfigs, dbProfileDevices) if err != nil { return nil, err } @@ -1284,7 +1289,7 @@ func fetchProject(tx *db.ClusterTx, projectName string, skipIfNoLimits bool) (*p instances := make([]api.Instance, 0, len(dbInstances)) for _, instance := range dbInstances { - apiInstance, err := instance.ToAPI(ctx, tx.Tx(), dbInstanceDevices, dbProfileDevices) + apiInstance, err := instance.ToAPI(ctx, tx.Tx(), dbInstanceDevices, dbProfileConfigs, dbProfileDevices) if err != nil { return nil, fmt.Errorf("Failed to get API data for instance %q in project %q: %w", instance.Name, instance.Project, err) } diff --git a/internal/server/scriptlet/instance_placement.go b/internal/server/scriptlet/instance_placement.go index 342b27bc1a2..29956c3a76a 100644 --- a/internal/server/scriptlet/instance_placement.go +++ b/internal/server/scriptlet/instance_placement.go @@ -267,7 +267,7 @@ func InstancePlacementRun(ctx context.Context, l logger.Logger, s *state.State, // Convert the []Instances into []api.Instances. for _, obj := range objects { - instance, err := obj.ToAPI(ctx, tx.Tx(), objectDevices, nil) + instance, err := obj.ToAPI(ctx, tx.Tx(), objectDevices, nil, nil) if err != nil { return err } diff --git a/internal/server/storage/utils.go b/internal/server/storage/utils.go index f1b5a61f131..3d8b98330ce 100644 --- a/internal/server/storage/utils.go +++ b/internal/server/storage/utils.go @@ -821,14 +821,20 @@ func VolumeUsedByProfileDevices(s *state.State, poolName string, projectName str return fmt.Errorf("Failed loading profiles: %w", err) } + // Get all the profile configs. + profileConfigs, err := cluster.GetConfig(ctx, tx.Tx(), "profile") + if err != nil { + return fmt.Errorf("Failed loading profile configs: %w", err) + } + // Get all the profile devices. profileDevices, err := cluster.GetDevices(ctx, tx.Tx(), "profile") if err != nil { - return fmt.Errorf("Failed loading profiles: %w", err) + return fmt.Errorf("Failed loading profile devices: %w", err) } for _, profile := range dbProfiles { - apiProfile, err := profile.ToAPI(ctx, tx.Tx(), profileDevices) + apiProfile, err := profile.ToAPI(ctx, tx.Tx(), profileConfigs, profileDevices) if err != nil { return fmt.Errorf("Failed getting API Profile %q: %w", profile.Name, err) }