8
_ "github.com/mattn/go-sqlite3"
10
"github.com/lxc/lxd/shared"
13
var dbImageSourceProtocol = map[int]string{
19
func dbImagesGet(db *sql.DB, public bool) ([]string, error) {
20
q := "SELECT fingerprint FROM images"
22
q = "SELECT fingerprint FROM images WHERE public=1"
26
inargs := []interface{}{}
27
outfmt := []interface{}{fp}
28
dbResults, err := dbQueryScan(db, q, inargs, outfmt)
30
return []string{}, err
34
for _, r := range dbResults {
35
results = append(results, r[0].(string))
41
func dbImagesGetExpired(db *sql.DB, expiry int) ([]string, error) {
42
q := `SELECT fingerprint FROM images WHERE cached=1 AND creation_date<=strftime('%s', date('now', '-` + fmt.Sprintf("%d", expiry) + ` day'))`
45
inargs := []interface{}{}
46
outfmt := []interface{}{fp}
47
dbResults, err := dbQueryScan(db, q, inargs, outfmt)
49
return []string{}, err
53
for _, r := range dbResults {
54
results = append(results, r[0].(string))
60
func dbImageSourceInsert(db *sql.DB, imageId int, server string, protocol string, certificate string, alias string) error {
61
stmt := `INSERT INTO images_source (image_id, server, protocol, certificate, alias) values (?, ?, ?, ?, ?)`
64
for protoInt, protoString := range dbImageSourceProtocol {
65
if protoString == protocol {
66
protocolInt = protoInt
70
if protocolInt == -1 {
71
return fmt.Errorf("Invalid protocol: %s", protocol)
74
_, err := dbExec(db, stmt, imageId, server, protocolInt, certificate, alias)
78
func dbImageSourceGet(db *sql.DB, imageId int) (int, shared.ImageSource, error) {
79
q := `SELECT id, server, protocol, certificate, alias FROM images_source WHERE image_id=?`
83
result := shared.ImageSource{}
85
arg1 := []interface{}{imageId}
86
arg2 := []interface{}{&id, &result.Server, &protocolInt, &result.Certificate, &result.Alias}
87
err := dbQueryRowScan(db, q, arg1, arg2)
89
if err == sql.ErrNoRows {
90
return -1, shared.ImageSource{}, NoSuchObjectError
93
return -1, shared.ImageSource{}, err
96
protocol, found := dbImageSourceProtocol[protocolInt]
98
return -1, shared.ImageSource{}, fmt.Errorf("Invalid protocol: %d", protocolInt)
101
result.Protocol = protocol
103
return id, result, nil
107
// dbImageGet gets an ImageBaseInfo object from the database.
108
// The argument fingerprint will be queried with a LIKE query, means you can
109
// pass a shortform and will get the full fingerprint.
110
// There can never be more than one image with a given fingerprint, as it is
111
// enforced by a UNIQUE constraint in the schema.
112
func dbImageGet(db *sql.DB, fingerprint string, public bool, strictMatching bool) (int, *shared.ImageInfo, error) {
114
var create, expire, used, upload *time.Time // These hold the db-returned times
116
// The object we'll actually return
117
image := shared.ImageInfo{}
121
// These two humongous things will be filled by the call to DbQueryRowScan
122
outfmt := []interface{}{&id, &image.Fingerprint, &image.Filename,
123
&image.Size, &image.Cached, &image.Public, &image.AutoUpdate, &arch,
124
&create, &expire, &used, &upload}
128
var inargs []interface{}
130
inargs = []interface{}{fingerprint}
133
id, fingerprint, filename, size, cached, public, auto_update, architecture,
134
creation_date, expiry_date, last_use_date, upload_date
137
WHERE fingerprint = ?`
139
inargs = []interface{}{fingerprint + "%"}
142
id, fingerprint, filename, size, cached, public, auto_update, architecture,
143
creation_date, expiry_date, last_use_date, upload_date
146
WHERE fingerprint LIKE ?`
150
query = query + " AND public=1"
153
err = dbQueryRowScan(db, query, inargs, outfmt)
156
return -1, nil, err // Likely: there are no rows for this fingerprint
159
// Some of the dates can be nil in the DB, let's process them.
161
image.CreationDate = *create
163
image.CreationDate = time.Time{}
167
image.ExpiryDate = *expire
169
image.ExpiryDate = time.Time{}
173
image.LastUsedDate = *used
175
image.LastUsedDate = time.Time{}
178
image.Architecture, _ = shared.ArchitectureName(arch)
180
// The upload date is enforced by NOT NULL in the schema, so it can never be nil.
181
image.UploadDate = *upload
183
// Get the properties
184
q := "SELECT key, value FROM images_properties where image_id=?"
185
var key, value, name, desc string
186
inargs = []interface{}{id}
187
outfmt = []interface{}{key, value}
188
results, err := dbQueryScan(db, q, inargs, outfmt)
193
properties := map[string]string{}
194
for _, r := range results {
196
value = r[1].(string)
197
properties[key] = value
200
image.Properties = properties
203
q = "SELECT name, description FROM images_aliases WHERE image_id=?"
204
inargs = []interface{}{id}
205
outfmt = []interface{}{name, desc}
206
results, err = dbQueryScan(db, q, inargs, outfmt)
211
aliases := []shared.ImageAlias{}
212
for _, r := range results {
215
a := shared.ImageAlias{Name: name, Description: desc}
216
aliases = append(aliases, a)
219
image.Aliases = aliases
221
_, source, err := dbImageSourceGet(db, id)
223
image.Source = &source
226
return id, &image, nil
229
func dbImageDelete(db *sql.DB, id int) error {
230
tx, err := dbBegin(db)
235
_, _ = tx.Exec("DELETE FROM images_aliases WHERE image_id=?", id)
236
_, _ = tx.Exec("DELETE FROM images_properties WHERE image_id=?", id)
237
_, _ = tx.Exec("DELETE FROM images_source WHERE image_id=?", id)
238
_, _ = tx.Exec("DELETE FROM images WHERE id=?", id)
240
if err := txCommit(tx); err != nil {
247
func dbImageAliasGet(db *sql.DB, name string, isTrustedClient bool) (int, shared.ImageAliasesEntry, error) {
248
q := `SELECT images_aliases.id, images.fingerprint, images_aliases.description
251
ON images_aliases.image_id=images.id
252
WHERE images_aliases.name=?`
253
if !isTrustedClient {
254
q = q + ` AND images.public=1`
257
var fingerprint, description string
260
arg1 := []interface{}{name}
261
arg2 := []interface{}{&id, &fingerprint, &description}
262
err := dbQueryRowScan(db, q, arg1, arg2)
264
if err == sql.ErrNoRows {
265
return -1, shared.ImageAliasesEntry{}, NoSuchObjectError
268
return -1, shared.ImageAliasesEntry{}, err
271
return id, shared.ImageAliasesEntry{Name: name, Target: fingerprint, Description: description}, nil
274
func dbImageAliasRename(db *sql.DB, id int, name string) error {
275
_, err := dbExec(db, "UPDATE images_aliases SET name=? WHERE id=?", name, id)
279
func dbImageAliasDelete(db *sql.DB, name string) error {
280
_, err := dbExec(db, "DELETE FROM images_aliases WHERE name=?", name)
284
func dbImageAliasesMove(db *sql.DB, source int, destination int) error {
285
_, err := dbExec(db, "UPDATE images_aliases SET image_id=? WHERE image_id=?", destination, source)
289
// Insert an alias ento the database.
290
func dbImageAliasAdd(db *sql.DB, name string, imageID int, desc string) error {
291
stmt := `INSERT INTO images_aliases (name, image_id, description) values (?, ?, ?)`
292
_, err := dbExec(db, stmt, name, imageID, desc)
296
func dbImageAliasUpdate(db *sql.DB, id int, imageID int, desc string) error {
297
stmt := `UPDATE images_aliases SET image_id=?, description=? WHERE id=?`
298
_, err := dbExec(db, stmt, imageID, desc, id)
302
func dbImageLastAccessUpdate(db *sql.DB, fingerprint string, date time.Time) error {
303
stmt := `UPDATE images SET last_use_date=? WHERE fingerprint=?`
304
_, err := dbExec(db, stmt, date, fingerprint)
308
func dbImageLastAccessInit(db *sql.DB, fingerprint string) error {
309
stmt := `UPDATE images SET cached=1, last_use_date=strftime("%s") WHERE fingerprint=?`
310
_, err := dbExec(db, stmt, fingerprint)
314
func dbImageUpdate(db *sql.DB, id int, fname string, sz int64, public bool, autoUpdate bool, architecture string, creationDate time.Time, expiryDate time.Time, properties map[string]string) error {
315
arch, err := shared.ArchitectureId(architecture)
320
tx, err := dbBegin(db)
335
stmt, err := tx.Prepare(`UPDATE images SET filename=?, size=?, public=?, auto_update=?, architecture=?, creation_date=?, expiry_date=? WHERE id=?`)
342
_, err = stmt.Exec(fname, sz, publicInt, autoUpdateInt, arch, creationDate, expiryDate, id)
348
_, err = tx.Exec(`DELETE FROM images_properties WHERE image_id=?`, id)
350
stmt, err = tx.Prepare(`INSERT INTO images_properties (image_id, type, key, value) VALUES (?, ?, ?, ?)`)
356
for key, value := range properties {
357
_, err = stmt.Exec(id, 0, key, value)
364
if err := txCommit(tx); err != nil {
371
func dbImageInsert(db *sql.DB, fp string, fname string, sz int64, public bool, autoUpdate bool, architecture string, creationDate time.Time, expiryDate time.Time, properties map[string]string) error {
372
arch, err := shared.ArchitectureId(architecture)
377
tx, err := dbBegin(db)
392
stmt, err := tx.Prepare(`INSERT INTO images (fingerprint, filename, size, public, auto_update, architecture, creation_date, expiry_date, upload_date) VALUES (?, ?, ?, ?, ?, ?, ?, ?, strftime("%s"))`)
399
result, err := stmt.Exec(fp, fname, sz, publicInt, autoUpdateInt, arch, creationDate, expiryDate)
405
if len(properties) > 0 {
406
id64, err := result.LastInsertId()
413
pstmt, err := tx.Prepare(`INSERT INTO images_properties (image_id, type, key, value) VALUES (?, 0, ?, ?)`)
420
for k, v := range properties {
422
// we can assume, that there is just one
424
_, err = pstmt.Exec(id, k, v)
433
if err := txCommit(tx); err != nil {