[lxc-devel] [lxd/master] Support custom block volumes
monstermunchkin on Github
lxc-bot at linuxcontainers.org
Tue Jun 2 12:12:24 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200602/839a131b/attachment-0001.bin>
-------------- next part --------------
From 91bda8ef1bd5a676818c8f7d3748e3ea18e06741 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Thu, 28 May 2020 16:17:38 +0200
Subject: [PATCH 01/14] lxd/db/cluster: Add content_type to storage_volumes
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/db/cluster/schema.go | 12 +++++++----
lxd/db/cluster/update.go | 43 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 51 insertions(+), 4 deletions(-)
diff --git a/lxd/db/cluster/schema.go b/lxd/db/cluster/schema.go
index fbf24753fc..138f10b738 100644
--- a/lxd/db/cluster/schema.go
+++ b/lxd/db/cluster/schema.go
@@ -480,6 +480,7 @@ CREATE TABLE "storage_volumes" (
type INTEGER NOT NULL,
description TEXT,
project_id INTEGER NOT NULL,
+ content_type INTEGER NOT NULL DEFAULT 0,
UNIQUE (storage_pool_id, node_id, project_id, name, type),
FOREIGN KEY (storage_pool_id) REFERENCES storage_pools (id) ON DELETE CASCADE,
FOREIGN KEY (node_id) REFERENCES nodes (id) ON DELETE CASCADE,
@@ -492,14 +493,16 @@ CREATE VIEW storage_volumes_all (
node_id,
type,
description,
- project_id) AS
+ project_id,
+ content_type) AS
SELECT id,
name,
storage_pool_id,
node_id,
type,
description,
- project_id
+ project_id,
+ content_type
FROM storage_volumes UNION
SELECT storage_volumes_snapshots.id,
printf('%s/%s',
@@ -509,7 +512,8 @@ CREATE VIEW storage_volumes_all (
storage_volumes.node_id,
storage_volumes.type,
storage_volumes_snapshots.description,
- storage_volumes.project_id
+ storage_volumes.project_id,
+ storage_volumes.content_type
FROM storage_volumes
JOIN storage_volumes_snapshots ON storage_volumes.id = storage_volumes_snapshots.storage_volume_id;
CREATE TRIGGER storage_volumes_check_id
@@ -553,5 +557,5 @@ CREATE TABLE storage_volumes_snapshots_config (
UNIQUE (storage_volume_snapshot_id, key)
);
-INSERT INTO schema (version, updated_at) VALUES (28, strftime("%s"))
+INSERT INTO schema (version, updated_at) VALUES (29, strftime("%s"))
`
diff --git a/lxd/db/cluster/update.go b/lxd/db/cluster/update.go
index fb2c5c73b7..739c4eee1a 100644
--- a/lxd/db/cluster/update.go
+++ b/lxd/db/cluster/update.go
@@ -65,6 +65,49 @@ var updates = map[int]schema.Update{
26: updateFromV25,
27: updateFromV26,
28: updateFromV27,
+ 29: updateFromV28,
+}
+
+// Add content type field to storage volumes
+func updateFromV28(tx *sql.Tx) error {
+ stmts := `ALTER TABLE storage_volumes ADD COLUMN content_type INTEGER NOT NULL DEFAULT 0;
+UPDATE storage_volumes SET content_type = 1 WHERE type = 3;
+DROP VIEW storage_volumes_all;
+CREATE VIEW storage_volumes_all (
+ id,
+ name,
+ storage_pool_id,
+ node_id,
+ type,
+ description,
+ project_id,
+ content_type) AS
+ SELECT id,
+ name,
+ storage_pool_id,
+ node_id,
+ type,
+ description,
+ project_id,
+ content_type
+ FROM storage_volumes UNION
+ SELECT storage_volumes_snapshots.id,
+ printf('%s/%s', storage_volumes.name, storage_volumes_snapshots.name),
+ storage_volumes.storage_pool_id,
+ storage_volumes.node_id,
+ storage_volumes.type,
+ storage_volumes_snapshots.description,
+ storage_volumes.project_id,
+ storage_volumes.content_type
+ FROM storage_volumes
+ JOIN storage_volumes_snapshots ON storage_volumes.id = storage_volumes_snapshots.storage_volume_id;
+`
+ _, err := tx.Exec(stmts)
+ if err != nil {
+ return errors.Wrap(err, "Failed to add storage volume content type")
+ }
+
+ return nil
}
// Add expiry date to storage volume snapshots
From a8039b596c44a27a740d142ebb54ba4ded24849a Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Thu, 28 May 2020 18:45:25 +0200
Subject: [PATCH 02/14] shared/api: Add ContentType to StorageVolume
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
shared/api/storage_pool_volume.go | 3 +++
1 file changed, 3 insertions(+)
diff --git a/shared/api/storage_pool_volume.go b/shared/api/storage_pool_volume.go
index db916ff0fa..3aa881d9af 100644
--- a/shared/api/storage_pool_volume.go
+++ b/shared/api/storage_pool_volume.go
@@ -52,6 +52,9 @@ type StorageVolume struct {
// API extension: clustering
Location string `json:"location" yaml:"location"`
+
+ // API extension: custom_block_volumes
+ ContentType string `json:"content_type" yaml:"content_type"`
}
// StorageVolumePut represents the modifiable fields of a LXD storage volume.
From 8c11799f3e394eeee8cdc808e80538faf2501aee Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Thu, 28 May 2020 18:45:48 +0200
Subject: [PATCH 03/14] lxd/db: Add content type to storage volumes
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/db/storage_volumes.go | 51 +++++++++++++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/lxd/db/storage_volumes.go b/lxd/db/storage_volumes.go
index af000ef4a6..04062554de 100644
--- a/lxd/db/storage_volumes.go
+++ b/lxd/db/storage_volumes.go
@@ -246,11 +246,21 @@ func (c *Cluster) storagePoolVolumeGetType(project string, volumeName string, vo
return -1, nil, err
}
+ volumeContentType, err := c.GetStorageVolumeContentType(volumeID)
+ if err != nil {
+ return -1, nil, err
+ }
+
volumeTypeName, err := storagePoolVolumeTypeToName(volumeType)
if err != nil {
return -1, nil, err
}
+ volumeContentTypeName, err := storagePoolVolumeContentTypeToName(volumeContentType)
+ if err != nil {
+ return -1, nil, err
+ }
+
storageVolume := api.StorageVolume{
Type: volumeTypeName,
}
@@ -258,6 +268,7 @@ func (c *Cluster) storagePoolVolumeGetType(project string, volumeName string, vo
storageVolume.Description = volumeDescription
storageVolume.Config = volumeConfig
storageVolume.Location = volumeNode
+ storageVolume.ContentType = volumeContentTypeName
return volumeID, &storageVolume, nil
}
@@ -504,6 +515,16 @@ const (
StoragePoolVolumeTypeNameCustom string = "custom"
)
+const (
+ StoragePoolVolumeContentTypeFS = iota
+ StoragePoolVolumeContentTypeBlock
+)
+
+const (
+ StoragePoolVolumeContentTypeNameFS string = "filesystem"
+ StoragePoolVolumeContentTypeNameBlock string = "block"
+)
+
// StorageVolumeArgs is a value object holding all db-related details about a
// storage volume.
type StorageVolumeArgs struct {
@@ -657,6 +678,24 @@ func (c *Cluster) GetStorageVolumeDescription(volumeID int64) (string, error) {
return description.String, nil
}
+// GetStorageVolumeContentType gets the content type of a storage volume.
+func (c *Cluster) GetStorageVolumeContentType(volumeID int64) (int, error) {
+ var contentType int
+ query := "SELECT content_type FROM storage_volumes_all WHERE id=?"
+ inargs := []interface{}{volumeID}
+ outargs := []interface{}{&contentType}
+
+ err := dbQueryRowScan(c, query, inargs, outargs)
+ if err != nil {
+ if err == sql.ErrNoRows {
+ return -1, ErrNoSuchObject
+ }
+ return -1, err
+ }
+
+ return contentType, nil
+}
+
// GetNextStorageVolumeSnapshotIndex returns the index of the next snapshot of the storage
// volume with the given name should have.
//
@@ -887,3 +926,15 @@ func storagePoolVolumeTypeToName(volumeType int) (string, error) {
return "", fmt.Errorf("Invalid storage volume type")
}
+
+// Convert a volume integer content type code to its human-readable name.
+func storagePoolVolumeContentTypeToName(contentType int) (string, error) {
+ switch contentType {
+ case StoragePoolVolumeContentTypeFS:
+ return StoragePoolVolumeContentTypeNameFS, nil
+ case StoragePoolVolumeContentTypeBlock:
+ return StoragePoolVolumeContentTypeNameBlock, nil
+ }
+
+ return "", fmt.Errorf("Invalid storage volume content type")
+}
From 173c774c7444cc74bc678998c76258f4ce2e9a26 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Thu, 28 May 2020 18:46:10 +0200
Subject: [PATCH 04/14] lxc/storage_volume: Show content type when listing
volumes
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxc/storage_volume.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lxc/storage_volume.go b/lxc/storage_volume.go
index 3fde175de5..a1cbba5e65 100644
--- a/lxc/storage_volume.go
+++ b/lxc/storage_volume.go
@@ -1103,7 +1103,7 @@ func (c *cmdStorageVolumeList) Run(cmd *cobra.Command, args []string) error {
data := [][]string{}
for _, volume := range volumes {
usedby := strconv.Itoa(len(volume.UsedBy))
- entry := []string{volume.Type, volume.Name, volume.Description, usedby}
+ entry := []string{volume.Type, volume.Name, volume.Description, volume.ContentType, usedby}
if shared.IsSnapshot(volume.Name) {
entry[0] = fmt.Sprintf("%s (snapshot)", volume.Type)
}
@@ -1118,6 +1118,7 @@ func (c *cmdStorageVolumeList) Run(cmd *cobra.Command, args []string) error {
i18n.G("TYPE"),
i18n.G("NAME"),
i18n.G("DESCRIPTION"),
+ i18n.G("CONTENT TYPE"),
i18n.G("USED BY"),
}
if resource.server.IsClustered() {
From ad1ab17fa6caa1b68ddc7e11f79723258aafb5aa Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Thu, 28 May 2020 18:57:10 +0200
Subject: [PATCH 05/14] shared/version/api: Add API extension
custom_block_volumes
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
shared/version/api.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/shared/version/api.go b/shared/version/api.go
index 532db6ab0c..d65bf57992 100644
--- a/shared/version/api.go
+++ b/shared/version/api.go
@@ -213,6 +213,7 @@ var APIExtensions = []string{
"network_dns_search",
"container_nic_routed_limits",
"instance_nic_bridged_vlan",
+ "custom_block_volumes",
}
// APIExtensionsCount returns the number of available API extensions.
From 86b724c139007628f31396918ef9b621b3e3a4d4 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Thu, 28 May 2020 19:09:16 +0200
Subject: [PATCH 06/14] shared/api: Add ContentType to StorageVolumesPost
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
shared/api/storage_pool_volume.go | 3 +++
1 file changed, 3 insertions(+)
diff --git a/shared/api/storage_pool_volume.go b/shared/api/storage_pool_volume.go
index 3aa881d9af..85950c8461 100644
--- a/shared/api/storage_pool_volume.go
+++ b/shared/api/storage_pool_volume.go
@@ -11,6 +11,9 @@ type StorageVolumesPost struct {
// API extension: storage_api_local_volume_handling
Source StorageVolumeSource `json:"source" yaml:"source"`
+
+ // API extension: custom_block_volumes
+ ContentType string `json:"content_type" yaml:"content_type"`
}
// StorageVolumePost represents the fields required to rename a LXD storage pool volume
From 2321a93adb2c1846829bda481e56272bf0e28c1c Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Thu, 28 May 2020 19:10:02 +0200
Subject: [PATCH 07/14] lxc/storage_volume: Add -type flag to create
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxc/storage_volume.go | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/lxc/storage_volume.go b/lxc/storage_volume.go
index a1cbba5e65..a3c6c7d9db 100644
--- a/lxc/storage_volume.go
+++ b/lxc/storage_volume.go
@@ -451,9 +451,10 @@ func (c *cmdStorageVolumeCopy) Run(cmd *cobra.Command, args []string) error {
// Create
type cmdStorageVolumeCreate struct {
- global *cmdGlobal
- storage *cmdStorage
- storageVolume *cmdStorageVolume
+ global *cmdGlobal
+ storage *cmdStorage
+ storageVolume *cmdStorageVolume
+ flagContentType string
}
func (c *cmdStorageVolumeCreate) Command() *cobra.Command {
@@ -464,6 +465,7 @@ func (c *cmdStorageVolumeCreate) Command() *cobra.Command {
`Create new custom storage volumes`))
cmd.Flags().StringVar(&c.storage.flagTarget, "target", "", i18n.G("Cluster member name")+"``")
+ cmd.Flags().StringVar(&c.flagContentType, "type", "filesystem", i18n.G("Content type, block or filesystem")+"``")
cmd.RunE = c.Run
return cmd
@@ -497,6 +499,7 @@ func (c *cmdStorageVolumeCreate) Run(cmd *cobra.Command, args []string) error {
vol := api.StorageVolumesPost{}
vol.Name = volName
vol.Type = volType
+ vol.ContentType = c.flagContentType
vol.Config = map[string]string{}
for i := 2; i < len(args); i++ {
From 7ccf57d235417fb10e01525a4f7ad641782c860f Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Sat, 30 May 2020 20:00:19 +0200
Subject: [PATCH 08/14] lxd/storage: Pass contentType to CreateCustomVolume
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/storage/backend_lxd.go | 4 ++--
lxd/storage/backend_mock.go | 2 +-
lxd/storage/pool_interface.go | 2 +-
lxd/storage_volumes.go | 15 ++++++++++++++-
4 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 2a2cb7873d..f0cd88d2ea 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -2195,8 +2195,8 @@ func (b *lxdBackend) UpdateImage(fingerprint, newDesc string, newConfig map[stri
}
// CreateCustomVolume creates an empty custom volume.
-func (b *lxdBackend) CreateCustomVolume(projectName string, volName string, desc string, config map[string]string, op *operations.Operation) error {
- logger := logging.AddContext(b.logger, log.Ctx{"project": projectName, "volName": volName, "desc": desc, "config": config})
+func (b *lxdBackend) CreateCustomVolume(projectName string, volName string, desc string, config map[string]string, contentType drivers.ContentType, op *operations.Operation) error {
+ logger := logging.AddContext(b.logger, log.Ctx{"project": projectName, "volName": volName, "desc": desc, "config": config, "contentType": contentType})
logger.Debug("CreateCustomVolume started")
defer logger.Debug("CreateCustomVolume finished")
diff --git a/lxd/storage/backend_mock.go b/lxd/storage/backend_mock.go
index b5dc13083d..8942aed692 100644
--- a/lxd/storage/backend_mock.go
+++ b/lxd/storage/backend_mock.go
@@ -179,7 +179,7 @@ func (b *mockBackend) UpdateImage(fingerprint, newDesc string, newConfig map[str
return nil
}
-func (b *mockBackend) CreateCustomVolume(projectName string, volName string, desc string, config map[string]string, op *operations.Operation) error {
+func (b *mockBackend) CreateCustomVolume(projectName string, volName string, desc string, config map[string]string, contentType drivers.ContentType, op *operations.Operation) error {
return nil
}
diff --git a/lxd/storage/pool_interface.go b/lxd/storage/pool_interface.go
index bca6c57fd2..a1048621b7 100644
--- a/lxd/storage/pool_interface.go
+++ b/lxd/storage/pool_interface.go
@@ -67,7 +67,7 @@ type Pool interface {
UpdateImage(fingerprint string, newDesc string, newConfig map[string]string, op *operations.Operation) error
// Custom volumes.
- CreateCustomVolume(projectName string, volName string, desc string, config map[string]string, op *operations.Operation) error
+ CreateCustomVolume(projectName string, volName string, desc string, config map[string]string, contentType drivers.ContentType, op *operations.Operation) error
CreateCustomVolumeFromCopy(projectName string, volName, desc string, config map[string]string, srcPoolName, srcVolName string, srcVolOnly bool, op *operations.Operation) error
UpdateCustomVolume(projectName string, volName string, newDesc string, newConfig map[string]string, op *operations.Operation) error
RenameCustomVolume(projectName string, volName string, newVolName string, op *operations.Operation) error
diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go
index f4c194fe2c..8a47a80a4f 100644
--- a/lxd/storage_volumes.go
+++ b/lxd/storage_volumes.go
@@ -18,6 +18,7 @@ import (
"github.com/lxc/lxd/lxd/response"
"github.com/lxc/lxd/lxd/state"
storagePools "github.com/lxc/lxd/lxd/storage"
+ "github.com/lxc/lxd/lxd/storage/drivers"
"github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
@@ -284,6 +285,10 @@ func storagePoolVolumesTypePost(d *Daemon, r *http.Request) response.Response {
return response.BadRequest(fmt.Errorf("Storage volume names may not contain slashes"))
}
+ if !shared.StringInSlice(req.ContentType, []string{"block", "filesystem"}) {
+ return response.BadRequest(fmt.Errorf("ContentType needs to be \"block\" or \"filesystem\""))
+ }
+
req.Type = mux.Vars(r)["type"]
// We currently only allow to create storage volumes of type storagePoolVolumeTypeCustom.
@@ -333,9 +338,17 @@ func doVolumeCreateOrCopy(d *Daemon, projectName, poolName string, req *api.Stor
return response.SmartError(err)
}
+ var contentType drivers.ContentType
+
+ if req.ContentType == "filesystem" {
+ contentType = drivers.ContentTypeFS
+ } else if req.ContentType == "block" {
+ contentType = drivers.ContentTypeBlock
+ }
+
run = func(op *operations.Operation) error {
if req.Source.Name == "" {
- return pool.CreateCustomVolume(projectName, req.Name, req.Description, req.Config, op)
+ return pool.CreateCustomVolume(projectName, req.Name, req.Description, req.Config, contentType, op)
}
return pool.CreateCustomVolumeFromCopy(projectName, req.Name, req.Description, req.Config, req.Source.Pool, req.Source.Name, req.Source.VolumeOnly, op)
From 148a71943b1a73f01fd5ad27ee1feb8fcf059a5d Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Sat, 30 May 2020 21:42:48 +0200
Subject: [PATCH 09/14] lxd/migration: Add content type to VolumeTargetArgs
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/migration/migration_volumes.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/lxd/migration/migration_volumes.go b/lxd/migration/migration_volumes.go
index 261f7eaab0..57db9dbd3b 100644
--- a/lxd/migration/migration_volumes.go
+++ b/lxd/migration/migration_volumes.go
@@ -39,6 +39,7 @@ type VolumeTargetArgs struct {
Refresh bool
Live bool
VolumeSize int64
+ ContentType string
}
// TypesToHeader converts one or more Types to a MigrationHeader. It uses the first type argument
From 6a2aa2a2177d0a9b8f8a30165b3fc53902f7f98b Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Sat, 30 May 2020 20:06:54 +0200
Subject: [PATCH 10/14] lxd/storage: Pass contentType to VolumeDBCreate
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/storage/backend_lxd.go | 24 +++++++++++++++++-------
lxd/storage/utils.go | 2 +-
2 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index f0cd88d2ea..e357f67bc5 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -2040,8 +2040,11 @@ func (b *lxdBackend) EnsureImage(fingerprint string, op *operations.Operation) e
// Derive content type from image type. Image types are not the same as instance types, so don't use
// instance type constants for comparison.
contentType := drivers.ContentTypeFS
+ dbContentType := db.StoragePoolVolumeContentTypeNameFS
+
if image.Type == "virtual-machine" {
contentType = drivers.ContentTypeBlock
+ dbContentType = db.StoragePoolVolumeContentTypeNameBlock
}
// Try and load any existing volume config on this storage pool so we can compare filesystems if needed.
@@ -2097,7 +2100,7 @@ func (b *lxdBackend) EnsureImage(fingerprint string, op *operations.Operation) e
}
}
- err = VolumeDBCreate(b.state, project.Default, b.name, fingerprint, "", db.StoragePoolVolumeTypeNameImage, false, volConfig, time.Time{})
+ err = VolumeDBCreate(b.state, project.Default, b.name, fingerprint, "", db.StoragePoolVolumeTypeNameImage, false, volConfig, time.Time{}, dbContentType)
if err != nil {
return err
}
@@ -2211,7 +2214,7 @@ func (b *lxdBackend) CreateCustomVolume(projectName string, volName string, desc
}
// Create database entry for new storage volume.
- err = VolumeDBCreate(b.state, projectName, b.name, volName, desc, db.StoragePoolVolumeTypeNameCustom, false, vol.Config(), time.Time{})
+ err = VolumeDBCreate(b.state, projectName, b.name, volName, desc, db.StoragePoolVolumeTypeNameCustom, false, vol.Config(), time.Time{}, string(contentType))
if err != nil {
return err
}
@@ -2280,6 +2283,13 @@ func (b *lxdBackend) CreateCustomVolumeFromCopy(projectName string, volName stri
desc = srcVolRow.Description
}
+ // Get the source volume's content type.
+ contentType := drivers.ContentTypeFS
+
+ if srcVolRow.ContentType == "block" {
+ contentType = drivers.ContentTypeBlock
+ }
+
// If we are copying snapshots, retrieve a list of snapshots from source volume.
snapshotNames := []string{}
if !srcVolOnly {
@@ -2323,7 +2333,7 @@ func (b *lxdBackend) CreateCustomVolumeFromCopy(projectName string, volName stri
}
// Create database entry for new storage volume.
- err = VolumeDBCreate(b.state, projectName, b.name, volName, desc, db.StoragePoolVolumeTypeNameCustom, false, vol.Config(), time.Time{})
+ err = VolumeDBCreate(b.state, projectName, b.name, volName, desc, db.StoragePoolVolumeTypeNameCustom, false, vol.Config(), time.Time{}, string(contentType))
if err != nil {
return err
}
@@ -2335,7 +2345,7 @@ func (b *lxdBackend) CreateCustomVolumeFromCopy(projectName string, volName stri
newSnapshotName := drivers.GetSnapshotVolumeName(volName, snapName)
// Create database entry for new storage volume snapshot.
- err = VolumeDBCreate(b.state, projectName, b.name, newSnapshotName, desc, db.StoragePoolVolumeTypeNameCustom, true, vol.Config(), time.Time{})
+ err = VolumeDBCreate(b.state, projectName, b.name, newSnapshotName, desc, db.StoragePoolVolumeTypeNameCustom, true, vol.Config(), time.Time{}, string(contentType))
if err != nil {
return err
}
@@ -2471,7 +2481,7 @@ func (b *lxdBackend) CreateCustomVolumeFromMigration(projectName string, conn io
}
// Create database entry for new storage volume.
- err = VolumeDBCreate(b.state, projectName, b.name, args.Name, args.Description, db.StoragePoolVolumeTypeNameCustom, false, vol.Config(), time.Time{})
+ err = VolumeDBCreate(b.state, projectName, b.name, args.Name, args.Description, db.StoragePoolVolumeTypeNameCustom, false, vol.Config(), time.Time{}, args.ContentType)
if err != nil {
return err
}
@@ -2483,7 +2493,7 @@ func (b *lxdBackend) CreateCustomVolumeFromMigration(projectName string, conn io
newSnapshotName := drivers.GetSnapshotVolumeName(args.Name, snapName)
// Create database entry for new storage volume snapshot.
- err = VolumeDBCreate(b.state, projectName, b.name, newSnapshotName, args.Description, db.StoragePoolVolumeTypeNameCustom, true, vol.Config(), time.Time{})
+ err = VolumeDBCreate(b.state, projectName, b.name, newSnapshotName, args.Description, db.StoragePoolVolumeTypeNameCustom, true, vol.Config(), time.Time{}, args.ContentType)
if err != nil {
return err
}
@@ -2850,7 +2860,7 @@ func (b *lxdBackend) CreateCustomVolumeSnapshot(projectName, volName string, new
}
// Create database entry for new storage volume snapshot.
- err = VolumeDBCreate(b.state, projectName, b.name, fullSnapshotName, parentVol.Description, db.StoragePoolVolumeTypeNameCustom, true, parentVol.Config, newExpiryDate)
+ err = VolumeDBCreate(b.state, projectName, b.name, fullSnapshotName, parentVol.Description, db.StoragePoolVolumeTypeNameCustom, true, parentVol.Config, newExpiryDate, parentVol.ContentType)
if err != nil {
return err
}
diff --git a/lxd/storage/utils.go b/lxd/storage/utils.go
index 66b1aed6ec..9501aed2a4 100644
--- a/lxd/storage/utils.go
+++ b/lxd/storage/utils.go
@@ -137,7 +137,7 @@ func InstanceTypeToVolumeType(instType instancetype.Type) (drivers.VolumeType, e
}
// VolumeDBCreate creates a volume in the database.
-func VolumeDBCreate(s *state.State, project, poolName, volumeName, volumeDescription, volumeTypeName string, snapshot bool, volumeConfig map[string]string, expiryDate time.Time) error {
+func VolumeDBCreate(s *state.State, project, poolName, volumeName, volumeDescription, volumeTypeName string, snapshot bool, volumeConfig map[string]string, expiryDate time.Time, contentTypeName string) error {
// Convert the volume type name to our internal integer representation.
volDBType, err := VolumeTypeNameToType(volumeTypeName)
if err != nil {
From 498732b75225682aea3eaf30a3a7a4f364384694 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Tue, 2 Jun 2020 10:18:00 +0200
Subject: [PATCH 11/14] lxd/db: Add contentType arg to CreateStoragePoolVolume
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/db/storage_volumes.go | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/lxd/db/storage_volumes.go b/lxd/db/storage_volumes.go
index 04062554de..c9669f1823 100644
--- a/lxd/db/storage_volumes.go
+++ b/lxd/db/storage_volumes.go
@@ -396,7 +396,7 @@ func storagePoolVolumeReplicateIfCeph(tx *sql.Tx, volumeID int64, project, volum
// CreateStoragePoolVolume creates a new storage volume attached to a given
// storage pool.
-func (c *Cluster) CreateStoragePoolVolume(project, volumeName, volumeDescription string, volumeType int, poolID int64, volumeConfig map[string]string) (int64, error) {
+func (c *Cluster) CreateStoragePoolVolume(project, volumeName, volumeDescription string, volumeType int, poolID int64, volumeConfig map[string]string, contentType int) (int64, error) {
var thisVolumeID int64
if shared.IsSnapshot(volumeName) {
@@ -421,10 +421,10 @@ func (c *Cluster) CreateStoragePoolVolume(project, volumeName, volumeDescription
var volumeID int64
result, err := tx.tx.Exec(`
-INSERT INTO storage_volumes (storage_pool_id, node_id, type, name, description, project_id)
- VALUES (?, ?, ?, ?, ?, (SELECT id FROM projects WHERE name = ?))
+INSERT INTO storage_volumes (storage_pool_id, node_id, type, name, description, project_id, content_type)
+ VALUES (?, ?, ?, ?, ?, (SELECT id FROM projects WHERE name = ?), ?)
`,
- poolID, nodeID, volumeType, volumeName, volumeDescription, project)
+ poolID, nodeID, volumeType, volumeName, volumeDescription, project, contentType)
if err != nil {
return err
}
From dafbf9c11a0fcffe2cd2a406427e24d19c161091 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Tue, 2 Jun 2020 10:18:29 +0200
Subject: [PATCH 12/14] *: Pass content type to CreateStoragePoolVolume
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/instance/drivers/driver_lxc.go | 2 +-
lxd/instance/drivers/driver_qemu.go | 2 +-
lxd/patches.go | 16 ++++++++--------
lxd/storage/utils.go | 18 +++++++++++++++++-
4 files changed, 27 insertions(+), 11 deletions(-)
diff --git a/lxd/instance/drivers/driver_lxc.go b/lxd/instance/drivers/driver_lxc.go
index bbf0394b0c..c6bcc946bf 100644
--- a/lxd/instance/drivers/driver_lxc.go
+++ b/lxd/instance/drivers/driver_lxc.go
@@ -237,7 +237,7 @@ func lxcCreate(s *state.State, args db.InstanceArgs) (instance.Instance, error)
if c.IsSnapshot() {
_, err = s.Cluster.CreateStorageVolumeSnapshot(args.Project, args.Name, "", db.StoragePoolVolumeTypeContainer, poolID, volumeConfig, time.Time{})
} else {
- _, err = s.Cluster.CreateStoragePoolVolume(args.Project, args.Name, "", db.StoragePoolVolumeTypeContainer, poolID, volumeConfig)
+ _, err = s.Cluster.CreateStoragePoolVolume(args.Project, args.Name, "", db.StoragePoolVolumeTypeContainer, poolID, volumeConfig, db.StoragePoolVolumeContentTypeFS)
}
if err != nil {
c.Delete()
diff --git a/lxd/instance/drivers/driver_qemu.go b/lxd/instance/drivers/driver_qemu.go
index f798c7239c..d9270d04fa 100644
--- a/lxd/instance/drivers/driver_qemu.go
+++ b/lxd/instance/drivers/driver_qemu.go
@@ -250,7 +250,7 @@ func qemuCreate(s *state.State, args db.InstanceArgs) (instance.Instance, error)
_, err = s.Cluster.CreateStorageVolumeSnapshot(args.Project, args.Name, "", db.StoragePoolVolumeTypeVM, poolID, volumeConfig, time.Time{})
} else {
- _, err = s.Cluster.CreateStoragePoolVolume(args.Project, args.Name, "", db.StoragePoolVolumeTypeVM, poolID, volumeConfig)
+ _, err = s.Cluster.CreateStoragePoolVolume(args.Project, args.Name, "", db.StoragePoolVolumeTypeVM, poolID, volumeConfig, db.StoragePoolVolumeContentTypeBlock)
}
if err != nil {
return nil, err
diff --git a/lxd/patches.go b/lxd/patches.go
index 6b2293cd2f..ecb445c3ba 100644
--- a/lxd/patches.go
+++ b/lxd/patches.go
@@ -570,7 +570,7 @@ func upgradeFromStorageTypeBtrfs(name string, d *Daemon, defaultPoolName string,
}
} else if err == db.ErrNoSuchObject {
// Insert storage volumes for containers into the database.
- _, err := d.cluster.CreateStoragePoolVolume("default", ct, "", db.StoragePoolVolumeTypeContainer, poolID, containerPoolVolumeConfig)
+ _, err := d.cluster.CreateStoragePoolVolume("default", ct, "", db.StoragePoolVolumeTypeContainer, poolID, containerPoolVolumeConfig, db.StoragePoolVolumeContentTypeFS)
if err != nil {
logger.Errorf("Could not insert a storage volume for container \"%s\"", ct)
return err
@@ -739,7 +739,7 @@ func upgradeFromStorageTypeBtrfs(name string, d *Daemon, defaultPoolName string,
}
} else if err == db.ErrNoSuchObject {
// Insert storage volumes for containers into the database.
- _, err := d.cluster.CreateStoragePoolVolume("default", img, "", db.StoragePoolVolumeTypeImage, poolID, imagePoolVolumeConfig)
+ _, err := d.cluster.CreateStoragePoolVolume("default", img, "", db.StoragePoolVolumeTypeImage, poolID, imagePoolVolumeConfig, db.StoragePoolVolumeContentTypeFS)
if err != nil {
logger.Errorf("Could not insert a storage volume for image \"%s\"", img)
return err
@@ -860,7 +860,7 @@ func upgradeFromStorageTypeDir(name string, d *Daemon, defaultPoolName string, d
}
} else if err == db.ErrNoSuchObject {
// Insert storage volumes for containers into the database.
- _, err := d.cluster.CreateStoragePoolVolume("default", ct, "", db.StoragePoolVolumeTypeContainer, poolID, containerPoolVolumeConfig)
+ _, err := d.cluster.CreateStoragePoolVolume("default", ct, "", db.StoragePoolVolumeTypeContainer, poolID, containerPoolVolumeConfig, db.StoragePoolVolumeContentTypeFS)
if err != nil {
logger.Errorf("Could not insert a storage volume for container \"%s\"", ct)
return err
@@ -1007,7 +1007,7 @@ func upgradeFromStorageTypeDir(name string, d *Daemon, defaultPoolName string, d
}
} else if err == db.ErrNoSuchObject {
// Insert storage volumes for containers into the database.
- _, err := d.cluster.CreateStoragePoolVolume("default", img, "", db.StoragePoolVolumeTypeImage, poolID, imagePoolVolumeConfig)
+ _, err := d.cluster.CreateStoragePoolVolume("default", img, "", db.StoragePoolVolumeTypeImage, poolID, imagePoolVolumeConfig, db.StoragePoolVolumeContentTypeFS)
if err != nil {
logger.Errorf("Could not insert a storage volume for image \"%s\"", img)
return err
@@ -1169,7 +1169,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
}
} else if err == db.ErrNoSuchObject {
// Insert storage volumes for containers into the database.
- _, err := d.cluster.CreateStoragePoolVolume("default", ct, "", db.StoragePoolVolumeTypeContainer, poolID, containerPoolVolumeConfig)
+ _, err := d.cluster.CreateStoragePoolVolume("default", ct, "", db.StoragePoolVolumeTypeContainer, poolID, containerPoolVolumeConfig, db.StoragePoolVolumeContentTypeFS)
if err != nil {
logger.Errorf("Could not insert a storage volume for container \"%s\"", ct)
return err
@@ -1513,7 +1513,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, defaultPoolName string, d
}
} else if err == db.ErrNoSuchObject {
// Insert storage volumes for containers into the database.
- _, err := d.cluster.CreateStoragePoolVolume("default", img, "", db.StoragePoolVolumeTypeImage, poolID, imagePoolVolumeConfig)
+ _, err := d.cluster.CreateStoragePoolVolume("default", img, "", db.StoragePoolVolumeTypeImage, poolID, imagePoolVolumeConfig, db.StoragePoolVolumeContentTypeFS)
if err != nil {
logger.Errorf("Could not insert a storage volume for image \"%s\"", img)
return err
@@ -1705,7 +1705,7 @@ func upgradeFromStorageTypeZfs(name string, d *Daemon, defaultPoolName string, d
}
} else if err == db.ErrNoSuchObject {
// Insert storage volumes for containers into the database.
- _, err := d.cluster.CreateStoragePoolVolume("default", ct, "", db.StoragePoolVolumeTypeContainer, poolID, containerPoolVolumeConfig)
+ _, err := d.cluster.CreateStoragePoolVolume("default", ct, "", db.StoragePoolVolumeTypeContainer, poolID, containerPoolVolumeConfig, db.StoragePoolVolumeContentTypeFS)
if err != nil {
logger.Errorf("Could not insert a storage volume for container \"%s\"", ct)
return err
@@ -1847,7 +1847,7 @@ func upgradeFromStorageTypeZfs(name string, d *Daemon, defaultPoolName string, d
}
} else if err == db.ErrNoSuchObject {
// Insert storage volumes for containers into the database.
- _, err := d.cluster.CreateStoragePoolVolume("default", img, "", db.StoragePoolVolumeTypeImage, poolID, imagePoolVolumeConfig)
+ _, err := d.cluster.CreateStoragePoolVolume("default", img, "", db.StoragePoolVolumeTypeImage, poolID, imagePoolVolumeConfig, db.StoragePoolVolumeContentTypeFS)
if err != nil {
logger.Errorf("Could not insert a storage volume for image \"%s\"", img)
return err
diff --git a/lxd/storage/utils.go b/lxd/storage/utils.go
index 9501aed2a4..d4eecd78e0 100644
--- a/lxd/storage/utils.go
+++ b/lxd/storage/utils.go
@@ -136,6 +136,17 @@ func InstanceTypeToVolumeType(instType instancetype.Type) (drivers.VolumeType, e
return "", fmt.Errorf("Invalid instance type")
}
+func VolumeContentTypeNameToContentType(contentTypeName string) (int, error) {
+ switch contentTypeName {
+ case db.StoragePoolVolumeContentTypeNameFS:
+ return db.StoragePoolVolumeContentTypeFS, nil
+ case db.StoragePoolVolumeContentTypeNameBlock:
+ return db.StoragePoolVolumeContentTypeBlock, nil
+ }
+
+ return -1, fmt.Errorf("Invalid storage volume content type name")
+}
+
// VolumeDBCreate creates a volume in the database.
func VolumeDBCreate(s *state.State, project, poolName, volumeName, volumeDescription, volumeTypeName string, snapshot bool, volumeConfig map[string]string, expiryDate time.Time, contentTypeName string) error {
// Convert the volume type name to our internal integer representation.
@@ -144,6 +155,11 @@ func VolumeDBCreate(s *state.State, project, poolName, volumeName, volumeDescrip
return err
}
+ volDBContentType, err := VolumeContentTypeNameToContentType(contentTypeName)
+ if err != nil {
+ return err
+ }
+
// Load storage pool the volume will be attached to.
poolID, poolStruct, err := s.Cluster.GetStoragePool(poolName)
if err != nil {
@@ -181,7 +197,7 @@ func VolumeDBCreate(s *state.State, project, poolName, volumeName, volumeDescrip
if snapshot {
_, err = s.Cluster.CreateStorageVolumeSnapshot(project, volumeName, volumeDescription, volDBType, poolID, volumeConfig, expiryDate)
} else {
- _, err = s.Cluster.CreateStoragePoolVolume(project, volumeName, volumeDescription, volDBType, poolID, volumeConfig)
+ _, err = s.Cluster.CreateStoragePoolVolume(project, volumeName, volumeDescription, volDBType, poolID, volumeConfig, volDBContentType)
}
if err != nil {
return fmt.Errorf("Error inserting %q of type %q into database %q", poolName, volumeTypeName, err)
From 36e03b6a483519a97d098b9a5f177e6d6199704a Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Tue, 2 Jun 2020 13:17:46 +0200
Subject: [PATCH 13/14] lxd/db: Add ContentType to StorageVolumeArgs
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/db/storage_volumes.go | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lxd/db/storage_volumes.go b/lxd/db/storage_volumes.go
index c9669f1823..ada9134542 100644
--- a/lxd/db/storage_volumes.go
+++ b/lxd/db/storage_volumes.go
@@ -549,6 +549,8 @@ type StorageVolumeArgs struct {
// At least on of ProjectID or ProjectName must be set.
ProjectID int64
ProjectName string
+
+ ContentType string
}
// GetStorageVolumeNodeAddresses returns the addresses of all nodes on which the
From f41c516a4a1f8b90dfcb7f18fe7fe8cbaaf1f000 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Tue, 2 Jun 2020 13:22:30 +0200
Subject: [PATCH 14/14] lxd/*: Pass correct content type
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/migrate_storage_volumes.go | 1 +
lxd/storage/backend_lxd.go | 14 +++++++-------
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/lxd/migrate_storage_volumes.go b/lxd/migrate_storage_volumes.go
index e8e5be36f8..b6886d503c 100644
--- a/lxd/migrate_storage_volumes.go
+++ b/lxd/migrate_storage_volumes.go
@@ -274,6 +274,7 @@ func (c *migrationSink) DoStorage(state *state.State, projectName string, poolNa
Description: req.Description,
MigrationType: respTypes[0],
TrackProgress: true,
+ ContentType: string(contentType),
}
// A zero length Snapshots slice indicates volume only migration in
diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index e357f67bc5..6027598f34 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -2207,7 +2207,7 @@ func (b *lxdBackend) CreateCustomVolume(projectName string, volName string, desc
volStorageName := project.StorageVolume(projectName, volName)
// Validate config.
- vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, config)
+ vol := b.newVolume(drivers.VolumeTypeCustom, contentType, volStorageName, config)
err := b.driver.ValidateVolume(vol, false)
if err != nil {
return err
@@ -2320,11 +2320,11 @@ func (b *lxdBackend) CreateCustomVolumeFromCopy(projectName string, volName stri
// Get the volume name on storage.
volStorageName := project.StorageVolume(projectName, volName)
- vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, config)
+ vol := b.newVolume(drivers.VolumeTypeCustom, contentType, volStorageName, config)
// Get the src volume name on storage.
srcVolStorageName := project.StorageVolume(projectName, srcVolName)
- srcVol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, srcVolStorageName, srcVolRow.Config)
+ srcVol := b.newVolume(drivers.VolumeTypeCustom, contentType, srcVolStorageName, srcVolRow.Config)
// Check the supplied config and remove any fields not relevant for pool type.
err := b.driver.ValidateVolume(vol, true)
@@ -2368,9 +2368,9 @@ func (b *lxdBackend) CreateCustomVolumeFromCopy(projectName string, volName stri
logger.Debug("CreateCustomVolumeFromCopy cross-pool mode detected")
// Negotiate the migration type to use.
- offeredTypes := srcPool.MigrationTypes(drivers.ContentTypeFS, false)
+ offeredTypes := srcPool.MigrationTypes(contentType, false)
offerHeader := migration.TypesToHeader(offeredTypes...)
- migrationTypes, err := migration.MatchTypes(offerHeader, FallbackMigrationType(drivers.ContentTypeFS), b.MigrationTypes(drivers.ContentTypeFS, false))
+ migrationTypes, err := migration.MatchTypes(offerHeader, FallbackMigrationType(contentType), b.MigrationTypes(contentType, false))
if err != nil {
return fmt.Errorf("Failed to negotiate copy migration type: %v", err)
}
@@ -2405,7 +2405,7 @@ func (b *lxdBackend) CreateCustomVolumeFromCopy(projectName string, volName stri
Snapshots: snapshotNames,
MigrationType: migrationTypes[0],
TrackProgress: false, // Do not use a progress tracker on receiver.
-
+ ContentType: string(contentType),
}, op)
if err != nil {
@@ -2474,7 +2474,7 @@ func (b *lxdBackend) CreateCustomVolumeFromMigration(projectName string, conn io
volStorageName := project.StorageVolume(projectName, args.Name)
// Check the supplied config and remove any fields not relevant for destination pool type.
- vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, volStorageName, args.Config)
+ vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentType(args.ContentType), volStorageName, args.Config)
err := b.driver.ValidateVolume(vol, true)
if err != nil {
return err
More information about the lxc-devel
mailing list