~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/lxc/lxd/lxd/db_images.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package main
 
2
 
 
3
import (
 
4
        "database/sql"
 
5
        "fmt"
 
6
        "time"
 
7
 
 
8
        _ "github.com/mattn/go-sqlite3"
 
9
 
 
10
        "github.com/lxc/lxd/shared"
 
11
)
 
12
 
 
13
var dbImageSourceProtocol = map[int]string{
 
14
        0: "lxd",
 
15
        1: "direct",
 
16
        2: "simplestreams",
 
17
}
 
18
 
 
19
func dbImagesGet(db *sql.DB, public bool) ([]string, error) {
 
20
        q := "SELECT fingerprint FROM images"
 
21
        if public == true {
 
22
                q = "SELECT fingerprint FROM images WHERE public=1"
 
23
        }
 
24
 
 
25
        var fp string
 
26
        inargs := []interface{}{}
 
27
        outfmt := []interface{}{fp}
 
28
        dbResults, err := dbQueryScan(db, q, inargs, outfmt)
 
29
        if err != nil {
 
30
                return []string{}, err
 
31
        }
 
32
 
 
33
        results := []string{}
 
34
        for _, r := range dbResults {
 
35
                results = append(results, r[0].(string))
 
36
        }
 
37
 
 
38
        return results, nil
 
39
}
 
40
 
 
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'))`
 
43
 
 
44
        var fp string
 
45
        inargs := []interface{}{}
 
46
        outfmt := []interface{}{fp}
 
47
        dbResults, err := dbQueryScan(db, q, inargs, outfmt)
 
48
        if err != nil {
 
49
                return []string{}, err
 
50
        }
 
51
 
 
52
        results := []string{}
 
53
        for _, r := range dbResults {
 
54
                results = append(results, r[0].(string))
 
55
        }
 
56
 
 
57
        return results, nil
 
58
}
 
59
 
 
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 (?, ?, ?, ?, ?)`
 
62
 
 
63
        protocolInt := -1
 
64
        for protoInt, protoString := range dbImageSourceProtocol {
 
65
                if protoString == protocol {
 
66
                        protocolInt = protoInt
 
67
                }
 
68
        }
 
69
 
 
70
        if protocolInt == -1 {
 
71
                return fmt.Errorf("Invalid protocol: %s", protocol)
 
72
        }
 
73
 
 
74
        _, err := dbExec(db, stmt, imageId, server, protocolInt, certificate, alias)
 
75
        return err
 
76
}
 
77
 
 
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=?`
 
80
 
 
81
        id := 0
 
82
        protocolInt := -1
 
83
        result := shared.ImageSource{}
 
84
 
 
85
        arg1 := []interface{}{imageId}
 
86
        arg2 := []interface{}{&id, &result.Server, &protocolInt, &result.Certificate, &result.Alias}
 
87
        err := dbQueryRowScan(db, q, arg1, arg2)
 
88
        if err != nil {
 
89
                if err == sql.ErrNoRows {
 
90
                        return -1, shared.ImageSource{}, NoSuchObjectError
 
91
                }
 
92
 
 
93
                return -1, shared.ImageSource{}, err
 
94
        }
 
95
 
 
96
        protocol, found := dbImageSourceProtocol[protocolInt]
 
97
        if !found {
 
98
                return -1, shared.ImageSource{}, fmt.Errorf("Invalid protocol: %d", protocolInt)
 
99
        }
 
100
 
 
101
        result.Protocol = protocol
 
102
 
 
103
        return id, result, nil
 
104
 
 
105
}
 
106
 
 
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) {
 
113
        var err error
 
114
        var create, expire, used, upload *time.Time // These hold the db-returned times
 
115
 
 
116
        // The object we'll actually return
 
117
        image := shared.ImageInfo{}
 
118
        id := -1
 
119
        arch := -1
 
120
 
 
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}
 
125
 
 
126
        var query string
 
127
 
 
128
        var inargs []interface{}
 
129
        if strictMatching {
 
130
                inargs = []interface{}{fingerprint}
 
131
                query = `
 
132
        SELECT
 
133
            id, fingerprint, filename, size, cached, public, auto_update, architecture,
 
134
            creation_date, expiry_date, last_use_date, upload_date
 
135
        FROM
 
136
            images
 
137
        WHERE fingerprint = ?`
 
138
        } else {
 
139
                inargs = []interface{}{fingerprint + "%"}
 
140
                query = `
 
141
        SELECT
 
142
            id, fingerprint, filename, size, cached, public, auto_update, architecture,
 
143
            creation_date, expiry_date, last_use_date, upload_date
 
144
        FROM
 
145
            images
 
146
        WHERE fingerprint LIKE ?`
 
147
        }
 
148
 
 
149
        if public {
 
150
                query = query + " AND public=1"
 
151
        }
 
152
 
 
153
        err = dbQueryRowScan(db, query, inargs, outfmt)
 
154
 
 
155
        if err != nil {
 
156
                return -1, nil, err // Likely: there are no rows for this fingerprint
 
157
        }
 
158
 
 
159
        // Some of the dates can be nil in the DB, let's process them.
 
160
        if create != nil {
 
161
                image.CreationDate = *create
 
162
        } else {
 
163
                image.CreationDate = time.Time{}
 
164
        }
 
165
 
 
166
        if expire != nil {
 
167
                image.ExpiryDate = *expire
 
168
        } else {
 
169
                image.ExpiryDate = time.Time{}
 
170
        }
 
171
 
 
172
        if used != nil {
 
173
                image.LastUsedDate = *used
 
174
        } else {
 
175
                image.LastUsedDate = time.Time{}
 
176
        }
 
177
 
 
178
        image.Architecture, _ = shared.ArchitectureName(arch)
 
179
 
 
180
        // The upload date is enforced by NOT NULL in the schema, so it can never be nil.
 
181
        image.UploadDate = *upload
 
182
 
 
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)
 
189
        if err != nil {
 
190
                return -1, nil, err
 
191
        }
 
192
 
 
193
        properties := map[string]string{}
 
194
        for _, r := range results {
 
195
                key = r[0].(string)
 
196
                value = r[1].(string)
 
197
                properties[key] = value
 
198
        }
 
199
 
 
200
        image.Properties = properties
 
201
 
 
202
        // Get the aliases
 
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)
 
207
        if err != nil {
 
208
                return -1, nil, err
 
209
        }
 
210
 
 
211
        aliases := []shared.ImageAlias{}
 
212
        for _, r := range results {
 
213
                name = r[0].(string)
 
214
                desc = r[0].(string)
 
215
                a := shared.ImageAlias{Name: name, Description: desc}
 
216
                aliases = append(aliases, a)
 
217
        }
 
218
 
 
219
        image.Aliases = aliases
 
220
 
 
221
        _, source, err := dbImageSourceGet(db, id)
 
222
        if err == nil {
 
223
                image.Source = &source
 
224
        }
 
225
 
 
226
        return id, &image, nil
 
227
}
 
228
 
 
229
func dbImageDelete(db *sql.DB, id int) error {
 
230
        tx, err := dbBegin(db)
 
231
        if err != nil {
 
232
                return err
 
233
        }
 
234
 
 
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)
 
239
 
 
240
        if err := txCommit(tx); err != nil {
 
241
                return err
 
242
        }
 
243
 
 
244
        return nil
 
245
}
 
246
 
 
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
 
249
                         FROM images_aliases
 
250
                         INNER JOIN images
 
251
                         ON images_aliases.image_id=images.id
 
252
                         WHERE images_aliases.name=?`
 
253
        if !isTrustedClient {
 
254
                q = q + ` AND images.public=1`
 
255
        }
 
256
 
 
257
        var fingerprint, description string
 
258
        id := -1
 
259
 
 
260
        arg1 := []interface{}{name}
 
261
        arg2 := []interface{}{&id, &fingerprint, &description}
 
262
        err := dbQueryRowScan(db, q, arg1, arg2)
 
263
        if err != nil {
 
264
                if err == sql.ErrNoRows {
 
265
                        return -1, shared.ImageAliasesEntry{}, NoSuchObjectError
 
266
                }
 
267
 
 
268
                return -1, shared.ImageAliasesEntry{}, err
 
269
        }
 
270
 
 
271
        return id, shared.ImageAliasesEntry{Name: name, Target: fingerprint, Description: description}, nil
 
272
}
 
273
 
 
274
func dbImageAliasRename(db *sql.DB, id int, name string) error {
 
275
        _, err := dbExec(db, "UPDATE images_aliases SET name=? WHERE id=?", name, id)
 
276
        return err
 
277
}
 
278
 
 
279
func dbImageAliasDelete(db *sql.DB, name string) error {
 
280
        _, err := dbExec(db, "DELETE FROM images_aliases WHERE name=?", name)
 
281
        return err
 
282
}
 
283
 
 
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)
 
286
        return err
 
287
}
 
288
 
 
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)
 
293
        return err
 
294
}
 
295
 
 
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)
 
299
        return err
 
300
}
 
301
 
 
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)
 
305
        return err
 
306
}
 
307
 
 
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)
 
311
        return err
 
312
}
 
313
 
 
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)
 
316
        if err != nil {
 
317
                arch = 0
 
318
        }
 
319
 
 
320
        tx, err := dbBegin(db)
 
321
        if err != nil {
 
322
                return err
 
323
        }
 
324
 
 
325
        publicInt := 0
 
326
        if public {
 
327
                publicInt = 1
 
328
        }
 
329
 
 
330
        autoUpdateInt := 0
 
331
        if autoUpdate {
 
332
                autoUpdateInt = 1
 
333
        }
 
334
 
 
335
        stmt, err := tx.Prepare(`UPDATE images SET filename=?, size=?, public=?, auto_update=?, architecture=?, creation_date=?, expiry_date=? WHERE id=?`)
 
336
        if err != nil {
 
337
                tx.Rollback()
 
338
                return err
 
339
        }
 
340
        defer stmt.Close()
 
341
 
 
342
        _, err = stmt.Exec(fname, sz, publicInt, autoUpdateInt, arch, creationDate, expiryDate, id)
 
343
        if err != nil {
 
344
                tx.Rollback()
 
345
                return err
 
346
        }
 
347
 
 
348
        _, err = tx.Exec(`DELETE FROM images_properties WHERE image_id=?`, id)
 
349
 
 
350
        stmt, err = tx.Prepare(`INSERT INTO images_properties (image_id, type, key, value) VALUES (?, ?, ?, ?)`)
 
351
        if err != nil {
 
352
                tx.Rollback()
 
353
                return err
 
354
        }
 
355
 
 
356
        for key, value := range properties {
 
357
                _, err = stmt.Exec(id, 0, key, value)
 
358
                if err != nil {
 
359
                        tx.Rollback()
 
360
                        return err
 
361
                }
 
362
        }
 
363
 
 
364
        if err := txCommit(tx); err != nil {
 
365
                return err
 
366
        }
 
367
 
 
368
        return nil
 
369
}
 
370
 
 
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)
 
373
        if err != nil {
 
374
                arch = 0
 
375
        }
 
376
 
 
377
        tx, err := dbBegin(db)
 
378
        if err != nil {
 
379
                return err
 
380
        }
 
381
 
 
382
        publicInt := 0
 
383
        if public {
 
384
                publicInt = 1
 
385
        }
 
386
 
 
387
        autoUpdateInt := 0
 
388
        if autoUpdate {
 
389
                autoUpdateInt = 1
 
390
        }
 
391
 
 
392
        stmt, err := tx.Prepare(`INSERT INTO images (fingerprint, filename, size, public, auto_update, architecture, creation_date, expiry_date, upload_date) VALUES (?, ?, ?, ?, ?, ?, ?, ?, strftime("%s"))`)
 
393
        if err != nil {
 
394
                tx.Rollback()
 
395
                return err
 
396
        }
 
397
        defer stmt.Close()
 
398
 
 
399
        result, err := stmt.Exec(fp, fname, sz, publicInt, autoUpdateInt, arch, creationDate, expiryDate)
 
400
        if err != nil {
 
401
                tx.Rollback()
 
402
                return err
 
403
        }
 
404
 
 
405
        if len(properties) > 0 {
 
406
                id64, err := result.LastInsertId()
 
407
                if err != nil {
 
408
                        tx.Rollback()
 
409
                        return err
 
410
                }
 
411
                id := int(id64)
 
412
 
 
413
                pstmt, err := tx.Prepare(`INSERT INTO images_properties (image_id, type, key, value) VALUES (?, 0, ?, ?)`)
 
414
                if err != nil {
 
415
                        tx.Rollback()
 
416
                        return err
 
417
                }
 
418
                defer pstmt.Close()
 
419
 
 
420
                for k, v := range properties {
 
421
 
 
422
                        // we can assume, that there is just one
 
423
                        // value per key
 
424
                        _, err = pstmt.Exec(id, k, v)
 
425
                        if err != nil {
 
426
                                tx.Rollback()
 
427
                                return err
 
428
                        }
 
429
                }
 
430
 
 
431
        }
 
432
 
 
433
        if err := txCommit(tx); err != nil {
 
434
                return err
 
435
        }
 
436
 
 
437
        return nil
 
438
}