The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7479
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) ===
From 91bda8ef1bd5a676818c8f7d3748e3ea18e06741 Mon Sep 17 00:00:00 2001 From: Thomas Hipp <thomas.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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.h...@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
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel