[lxc-devel] [lxd/master] Images: Allow pruning of expires images in non-default project

tomponline on Github lxc-bot at linuxcontainers.org
Thu Mar 12 10:16:21 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 613 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200312/616d75da/attachment.bin>
-------------- next part --------------
From 666fbce982dca85bfd7dfcaa6a8e628499c63303 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 12 Mar 2020 10:12:39 +0000
Subject: [PATCH 1/3] lxd/db/images: Removes unnecessary whitespace

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/db/images.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxd/db/images.go b/lxd/db/images.go
index d8916d14f6..79d792d451 100644
--- a/lxd/db/images.go
+++ b/lxd/db/images.go
@@ -532,7 +532,7 @@ func (c *Cluster) imageFillProfiles(id int, image *api.Image, project string) er
 
 	// Get the profiles
 	q := `
-SELECT profiles.name FROM profiles 
+SELECT profiles.name FROM profiles
 	JOIN images_profiles ON images_profiles.profile_id = profiles.id
 	JOIN projects ON profiles.project_id = projects.id
 WHERE images_profiles.image_id = ? AND projects.name = ?
@@ -886,7 +886,7 @@ func (c *Cluster) ImageUpdate(id int, fname string, sz int64, public bool, autoU
 			if !enabled {
 				project = "default"
 			}
-			q := `DELETE FROM images_profiles 
+			q := `DELETE FROM images_profiles
 				WHERE image_id = ? AND profile_id IN (
 					SELECT profiles.id FROM profiles
 					JOIN projects ON profiles.project_id = projects.id

From dbc2ef7d06e61daa4a47a5397b75eb9694aa13b3 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 12 Mar 2020 10:10:42 +0000
Subject: [PATCH 2/3] lxd/db/images: Updates ImagesGetExpired to return
 ExpireImage struct with projectName

So that deleting expired images can be done when the image is in a non-default project.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/db/images.go | 37 ++++++++++++++++++++++++++++---------
 1 file changed, 28 insertions(+), 9 deletions(-)

diff --git a/lxd/db/images.go b/lxd/db/images.go
index 79d792d451..f196c3a0ce 100644
--- a/lxd/db/images.go
+++ b/lxd/db/images.go
@@ -88,23 +88,37 @@ SELECT fingerprint
 	return results, nil
 }
 
-// ImagesGetExpired returns the names of all images that have expired since the
-// given time.
-func (c *Cluster) ImagesGetExpired(expiry int64) ([]string, error) {
-	q := `SELECT fingerprint, last_use_date, upload_date FROM images WHERE cached=1`
+// ExpiredImage used to store expired image info.
+type ExpiredImage struct {
+	Fingerprint string
+	ProjectName string
+}
+
+// ImagesGetExpired returns the names and project name of all images that have expired since the given time.
+func (c *Cluster) ImagesGetExpired(expiry int64) ([]ExpiredImage, error) {
+	q := `
+	SELECT
+		fingerprint,
+		last_use_date,
+		upload_date,
+		projects.name as projectName
+	FROM images
+	JOIN projects ON projects.id = images.project_id
+	WHERE images.cached = 1`
 
 	var fpStr string
 	var useStr string
 	var uploadStr string
+	var projectName string
 
 	inargs := []interface{}{}
-	outfmt := []interface{}{fpStr, useStr, uploadStr}
+	outfmt := []interface{}{fpStr, useStr, uploadStr, projectName}
 	dbResults, err := queryScan(c.db, q, inargs, outfmt)
 	if err != nil {
-		return []string{}, err
+		return []ExpiredImage{}, err
 	}
 
-	results := []string{}
+	results := []ExpiredImage{}
 	for _, r := range dbResults {
 		// Figure out the expiry
 		timestamp := r[2]
@@ -115,7 +129,7 @@ func (c *Cluster) ImagesGetExpired(expiry int64) ([]string, error) {
 		var imageExpiry time.Time
 		err = imageExpiry.UnmarshalText([]byte(timestamp.(string)))
 		if err != nil {
-			return []string{}, err
+			return []ExpiredImage{}, err
 		}
 		imageExpiry = imageExpiry.Add(time.Duration(expiry*24) * time.Hour)
 
@@ -124,7 +138,12 @@ func (c *Cluster) ImagesGetExpired(expiry int64) ([]string, error) {
 			continue
 		}
 
-		results = append(results, r[0].(string))
+		result := ExpiredImage{
+			Fingerprint: r[0].(string),
+			ProjectName: r[3].(string),
+		}
+
+		results = append(results, result)
 	}
 
 	return results, nil

From 5a3d40a46d065a21932f9e69c44804c811da2a2a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 12 Mar 2020 10:12:06 +0000
Subject: [PATCH 3/3] lxd/images: Updates pruneExpiredImages to support
 removing expired images from non-default projects

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/images.go | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/lxd/images.go b/lxd/images.go
index c05c7d6582..9f804c2c8c 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -33,7 +33,6 @@ import (
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/node"
 	"github.com/lxc/lxd/lxd/operations"
-	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/response"
 	"github.com/lxc/lxd/lxd/state"
 	storagePools "github.com/lxc/lxd/lxd/storage"
@@ -1305,7 +1304,7 @@ func pruneExpiredImages(ctx context.Context, d *Daemon) error {
 	}
 
 	// Delete them
-	for _, fp := range images {
+	for _, img := range images {
 		// At each iteration we check if we got cancelled in the
 		// meantime. It is safe to abort here since anything not
 		// expired now will be expired at the next run.
@@ -1317,7 +1316,7 @@ func pruneExpiredImages(ctx context.Context, d *Daemon) error {
 
 		// Get the IDs of all storage pools on which a storage volume
 		// for the requested image currently exists.
-		poolIDs, err := d.cluster.ImageGetPools(fp)
+		poolIDs, err := d.cluster.ImageGetPools(img.Fingerprint)
 		if err != nil {
 			continue
 		}
@@ -1329,38 +1328,38 @@ func pruneExpiredImages(ctx context.Context, d *Daemon) error {
 		}
 
 		for _, pool := range poolNames {
-			err := doDeleteImageFromPool(d.State(), fp, pool)
+			err := doDeleteImageFromPool(d.State(), img.Fingerprint, pool)
 			if err != nil {
-				return errors.Wrapf(err, "Error deleting image %s from storage pool %s", fp, pool)
+				return errors.Wrapf(err, "Error deleting image %q from storage pool %q", img.Fingerprint, pool)
 			}
 		}
 
 		// Remove main image file.
-		fname := filepath.Join(d.os.VarDir, "images", fp)
+		fname := filepath.Join(d.os.VarDir, "images", img.Fingerprint)
 		if shared.PathExists(fname) {
 			err = os.Remove(fname)
 			if err != nil && !os.IsNotExist(err) {
-				return errors.Wrapf(err, "Error deleting image file %s", fname)
+				return errors.Wrapf(err, "Error deleting image file %q", fname)
 			}
 		}
 
 		// Remove the rootfs file for the image.
-		fname = filepath.Join(d.os.VarDir, "images", fp) + ".rootfs"
+		fname = filepath.Join(d.os.VarDir, "images", img.Fingerprint) + ".rootfs"
 		if shared.PathExists(fname) {
 			err = os.Remove(fname)
 			if err != nil && !os.IsNotExist(err) {
-				return errors.Wrapf(err, "Error deleting image file %s", fname)
+				return errors.Wrapf(err, "Error deleting image file %q", fname)
 			}
 		}
 
-		imgID, _, err := d.cluster.ImageGet(project.Default, fp, false, false)
+		imgID, _, err := d.cluster.ImageGet(img.ProjectName, img.Fingerprint, false, false)
 		if err != nil {
-			return errors.Wrapf(err, "Error retrieving image info %s", fp)
+			return errors.Wrapf(err, "Error retrieving image info for fingerprint %q and project %q", img.Fingerprint, img.ProjectName)
 		}
 
 		// Remove the database entry for the image.
 		if err = d.cluster.ImageDelete(imgID); err != nil {
-			return errors.Wrapf(err, "Error deleting image %s from database", fp)
+			return errors.Wrapf(err, "Error deleting image %q from database", img.Fingerprint)
 		}
 	}
 


More information about the lxc-devel mailing list