1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
//go:build linux && cgo && !agent
package cluster
import (
"context"
"database/sql"
"maps"
"github.com/lxc/incus/v6/internal/server/device/config"
"github.com/lxc/incus/v6/shared/api"
)
// Code generation directives.
//
//generate-database:mapper target profiles.mapper.go
//generate-database:mapper reset -i -b "//go:build linux && cgo && !agent"
//
//generate-database:mapper stmt -e profile objects
//generate-database:mapper stmt -e profile objects-by-ID
//generate-database:mapper stmt -e profile objects-by-Name
//generate-database:mapper stmt -e profile objects-by-Project
//generate-database:mapper stmt -e profile objects-by-Project-and-Name
//generate-database:mapper stmt -e profile id
//generate-database:mapper stmt -e profile create
//generate-database:mapper stmt -e profile rename
//generate-database:mapper stmt -e profile update
//generate-database:mapper stmt -e profile delete-by-Project-and-Name
//
//generate-database:mapper method -i -e profile ID
//generate-database:mapper method -i -e profile Exists
//generate-database:mapper method -i -e profile GetMany references=Config,Device
//generate-database:mapper method -i -e profile GetOne
//generate-database:mapper method -i -e profile Create references=Config,Device
//generate-database:mapper method -i -e profile Rename
//generate-database:mapper method -i -e profile Update references=Config,Device
//generate-database:mapper method -i -e profile DeleteOne-by-Project-and-Name
// Profile is a value object holding db-related details about a profile.
type Profile struct {
ID int
ProjectID int `db:"omit=create,update"`
Project string `db:"primary=yes&join=projects.name"`
Name string `db:"primary=yes"`
Description string `db:"coalesce=''"`
}
// ProfileFilter specifies potential query parameter fields.
type ProfileFilter struct {
ID *int
Project *string
Name *string
}
// ToAPI returns a cluster Profile as an API struct.
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 dbDevices map[string]Device
if profileDevices != nil {
dbDevices = map[string]Device{}
for _, dev := range profileDevices[p.ID] {
dbDevices[dev.Name] = dev
}
} else {
dbDevices, err = GetProfileDevices(ctx, tx, p.ID)
if err != nil {
return nil, err
}
}
profile := &api.Profile{
Name: p.Name,
ProfilePut: api.ProfilePut{
Description: p.Description,
Config: dbConfig,
Devices: DevicesToAPI(dbDevices),
},
Project: p.Project,
}
return profile, nil
}
// GetProfilesIfEnabled returns the profiles from the given project, or the
// default project if "features.profiles" is not set.
func GetProfilesIfEnabled(ctx context.Context, tx *sql.Tx, projectName string, names []string) ([]Profile, error) {
enabled, err := ProjectHasProfiles(ctx, tx, projectName)
if err != nil {
return nil, err
}
if !enabled {
projectName = "default"
}
profiles := make([]Profile, 0, len(names))
for _, name := range names {
profile, err := GetProfile(ctx, tx, projectName, name)
if err != nil {
return nil, err
}
profiles = append(profiles, *profile)
}
return profiles, nil
}
// ExpandInstanceConfig expands the given instance config with the config
// values of the given profiles.
func ExpandInstanceConfig(config map[string]string, profiles []api.Profile) map[string]string {
expandedConfig := map[string]string{}
// Apply all the profiles
profileConfigs := make([]map[string]string, len(profiles))
for i, profile := range profiles {
profileConfigs[i] = profile.Config
}
for i := range profileConfigs {
maps.Copy(expandedConfig, profileConfigs[i])
}
// Stick the given config on top
maps.Copy(expandedConfig, config)
return expandedConfig
}
// ExpandInstanceDevices expands the given instance devices with the devices
// defined in the given profiles.
func ExpandInstanceDevices(devices config.Devices, profiles []api.Profile) config.Devices {
expandedDevices := config.Devices{}
// Apply all the profiles
profileDevices := make([]config.Devices, len(profiles))
for i, profile := range profiles {
profileDevices[i] = config.NewDevices(profile.Devices)
}
for i := range profileDevices {
maps.Copy(expandedDevices, profileDevices[i])
}
// Stick the given devices on top
maps.Copy(expandedDevices, devices)
return expandedDevices
}
// GetAllProfileConfigs returns a map of all profile configurations, keyed by database ID.
func GetAllProfileConfigs(ctx context.Context, tx *sql.Tx) (map[int]map[string]string, error) {
return GetConfig(ctx, tx, "profiles", "profile")
}
// GetAllProfileDevices returns a map of all profile devices, keyed by database ID.
func GetAllProfileDevices(ctx context.Context, tx *sql.Tx) (map[int][]Device, error) {
return GetDevices(ctx, tx, "profiles", "profile")
}
|