File: profiles.go

package info (click to toggle)
incus 6.0.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 24,392 kB
  • sloc: sh: 16,313; ansic: 3,121; python: 457; makefile: 337; ruby: 51; sql: 50; lisp: 6
file content (174 lines) | stat: -rw-r--r-- 5,181 bytes parent folder | download | duplicates (2)
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")
}