The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6384
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 55cd3375cfdf9ff6eed28d80c46da65708da463e Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 1 Nov 2019 08:50:12 +0000 Subject: [PATCH 01/14] lxd/container/lxc: Removes usage of legacy ContainerGetUsage Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/container_lxc.go | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go index 8dc40f7292..937856218d 100644 --- a/lxd/container_lxc.go +++ b/lxd/container_lxc.go @@ -42,7 +42,6 @@ import ( "github.com/lxc/lxd/lxd/seccomp" "github.com/lxc/lxd/lxd/state" storagePools "github.com/lxc/lxd/lxd/storage" - storageDrivers "github.com/lxc/lxd/lxd/storage/drivers" "github.com/lxc/lxd/lxd/template" "github.com/lxc/lxd/lxd/util" "github.com/lxc/lxd/shared" @@ -5907,24 +5906,16 @@ func (c *containerLXC) diskState() map[string]api.InstanceStateDisk { var usage int64 - // Check if we can load new storage layer for pool driver type. pool, err := storagePools.GetPoolByName(c.state, dev.Config["pool"]) - if err != storageDrivers.ErrUnknownDriver { - if err != nil { - logger.Errorf("Error loading storage pool for %s: %v", c.Name(), err) - continue - } + if err != nil { + logger.Errorf("Error loading storage pool for %s: %v", c.Name(), err) + continue + } - usage, err = pool.GetInstanceUsage(c) - if err != nil { - logger.Errorf("Error getting disk usage for %s: %v", c.Name(), err) - continue - } - } else { - usage, err = c.storage.ContainerGetUsage(c) - if err != nil { - continue - } + usage, err = pool.GetInstanceUsage(c) + if err != nil { + logger.Errorf("Error getting disk usage for %s: %v", c.Name(), err) + continue } disk[dev.Name] = api.InstanceStateDisk{Usage: usage} From 6f6923fddaa867d8f85e1599a19ec6a1144cece0 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 1 Nov 2019 08:54:22 +0000 Subject: [PATCH 02/14] lxd/images: Removes usage of legacy ImageCreate Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/images.go | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/lxd/images.go b/lxd/images.go index 77b543cd06..9ede764e74 100644 --- a/lxd/images.go +++ b/lxd/images.go @@ -34,7 +34,6 @@ import ( "github.com/lxc/lxd/lxd/response" "github.com/lxc/lxd/lxd/state" storagePools "github.com/lxc/lxd/lxd/storage" - storageDrivers "github.com/lxc/lxd/lxd/storage/drivers" "github.com/lxc/lxd/lxd/task" "github.com/lxc/lxd/lxd/util" "github.com/lxc/lxd/shared" @@ -628,31 +627,14 @@ func imageCreateInPool(d *Daemon, info *api.Image, storagePool string) error { return fmt.Errorf("No storage pool specified") } - // Check if we can load new storage layer for pool driver type. pool, err := storagePools.GetPoolByName(d.State(), storagePool) - if err != storageDrivers.ErrUnknownDriver { - if err != nil { - return err - } - - err = pool.CreateImage(info.Fingerprint, nil) - if err != nil { - return err - } - } else { - // Initialize a new storage interface. - s, err := storagePoolInit(d.State(), storagePool) - if err != nil { - return err - } - - // Create the storage volume for the image on the requested storage - // pool. - err = s.ImageCreate(info.Fingerprint, nil) - if err != nil { - return err - } + if err != nil { + return err + } + err = pool.CreateImage(info.Fingerprint, nil) + if err != nil { + return err } return nil From 7343816cb8cb846a433c52a7f360dee87f3d5a1d Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 1 Nov 2019 08:56:39 +0000 Subject: [PATCH 03/14] lxd/migrate/storage/volumes: Removes use of legacy storage in migration source DoStorage Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/migrate_storage_volumes.go | 141 ++++++--------------------------- 1 file changed, 25 insertions(+), 116 deletions(-) diff --git a/lxd/migrate_storage_volumes.go b/lxd/migrate_storage_volumes.go index 978d95ed88..5404dc34c9 100644 --- a/lxd/migrate_storage_volumes.go +++ b/lxd/migrate_storage_volumes.go @@ -43,56 +43,19 @@ func (s *migrationSourceWs) DoStorage(state *state.State, poolName string, volNa var offerHeader migration.MigrationHeader var poolMigrationTypes []migration.Type - // Check if sending storage pool supports new storage layer. pool, err := storagePools.GetPoolByName(state, poolName) - if err != storageDrivers.ErrUnknownDriver { - if err != nil { - return err - } - - poolMigrationTypes = pool.MigrationTypes(storageDrivers.ContentTypeFS) - if len(poolMigrationTypes) < 0 { - return fmt.Errorf("No source migration types available") - } - - // Convert the pool's migration type options to an offer header to target. - offerHeader = migration.TypesToHeader(poolMigrationTypes...) - } else { - storage, err := storagePoolVolumeInit(state, "default", poolName, volName, storagePoolVolumeTypeCustom) - if err != nil { - return err - } - s.storage = storage - myType := s.storage.MigrationType() - hasFeature := true - offerHeader = migration.MigrationHeader{ - Fs: &myType, - RsyncFeatures: &migration.RsyncFeatures{ - Xattrs: &hasFeature, - Delete: &hasFeature, - Compress: &hasFeature, - Bidirectional: &hasFeature, - }, - } - - if len(zfsVersion) >= 3 && zfsVersion[0:3] != "0.6" { - offerHeader.ZfsFeatures = &migration.ZfsFeatures{ - Compress: &hasFeature, - } - } + if err != nil { + return err + } - // Storage needs to start unconditionally now, since we need to initialize a new - // storage interface. - ourMount, err := s.storage.StoragePoolVolumeMount() - if err != nil { - logger.Errorf("Failed to mount storage volume") - return err - } - if ourMount { - defer s.storage.StoragePoolVolumeUmount() - } + poolMigrationTypes = pool.MigrationTypes(storageDrivers.ContentTypeFS) + if len(poolMigrationTypes) < 0 { + return fmt.Errorf("No source migration types available") } + // Convert the pool's migration type options to an offer header to target. + offerHeader = migration.TypesToHeader(poolMigrationTypes...) + snapshots := []*migration.Snapshot{} snapshotNames := []string{} @@ -141,78 +104,24 @@ func (s *migrationSourceWs) DoStorage(state *state.State, poolName string, volNa return err } - // Use new storage layer for migration if supported. - if pool != nil { - migrationType, err := migration.MatchTypes(respHeader, migration.MigrationFSType_RSYNC, poolMigrationTypes) - if err != nil { - logger.Errorf("Failed to neogotiate migration type: %v", err) - s.sendControl(err) - return err - } - - volSourceArgs := migration.VolumeSourceArgs{ - Name: volName, - MigrationType: migrationType, - Snapshots: snapshotNames, - TrackProgress: true, - } - - err = pool.MigrateCustomVolume(&shared.WebsocketIO{Conn: s.fsConn}, volSourceArgs, migrateOp) - if err != nil { - go s.sendControl(err) - return err - } - } else { - // Use legacy storage layer for migration. - - // Get target's rsync options. - rsyncFeatures := respHeader.GetRsyncFeaturesSlice() - if !shared.StringInSlice("bidirectional", rsyncFeatures) { - // If no bi-directional support, assume LXD 3.7 level - // NOTE: Do NOT extend this list of arguments - rsyncFeatures = []string{"xattrs", "delete", "compress"} - } - - // Get target's zfs options. - zfsFeatures := respHeader.GetZfsFeaturesSlice() - - // Set source args - sourceArgs := MigrationSourceArgs{ - RsyncFeatures: rsyncFeatures, - ZfsFeatures: zfsFeatures, - VolumeOnly: s.volumeOnly, - } - - driver, fsErr := s.storage.StorageMigrationSource(sourceArgs) - if fsErr != nil { - logger.Errorf("Failed to initialize new storage volume migration driver") - s.sendControl(fsErr) - return fsErr - } - - bwlimit := "" - - if *offerHeader.Fs != *respHeader.Fs { - driver, _ = rsyncStorageMigrationSource(sourceArgs) - - // Check if this storage pool has a rate limit set for rsync. - poolwritable := s.storage.GetStoragePoolWritable() - if poolwritable.Config != nil { - bwlimit = poolwritable.Config["rsync.bwlimit"] - } - } + migrationType, err := migration.MatchTypes(respHeader, migration.MigrationFSType_RSYNC, poolMigrationTypes) + if err != nil { + logger.Errorf("Failed to neogotiate migration type: %v", err) + s.sendControl(err) + return err + } - abort := func(err error) error { - driver.Cleanup() - go s.sendControl(err) - return err - } + volSourceArgs := migration.VolumeSourceArgs{ + Name: volName, + MigrationType: migrationType, + Snapshots: snapshotNames, + TrackProgress: true, + } - err = driver.SendStorageVolume(s.fsConn, migrateOp, bwlimit, s.storage, s.volumeOnly) - if err != nil { - logger.Errorf("Failed to send storage volume") - return abort(err) - } + err = pool.MigrateCustomVolume(&shared.WebsocketIO{Conn: s.fsConn}, volSourceArgs, migrateOp) + if err != nil { + go s.sendControl(err) + return err } msg := migration.MigrationControl{} From 3cdb031eb934d958220050f7a11f6fc6475a55b7 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 1 Nov 2019 08:57:45 +0000 Subject: [PATCH 04/14] lxd/migrate/storage/volumes: Removes use of legacy storage from migration sink DoStorage Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/migrate_storage_volumes.go | 105 ++++++++++----------------------- 1 file changed, 31 insertions(+), 74 deletions(-) diff --git a/lxd/migrate_storage_volumes.go b/lxd/migrate_storage_volumes.go index 5404dc34c9..42a480c1f3 100644 --- a/lxd/migrate_storage_volumes.go +++ b/lxd/migrate_storage_volumes.go @@ -242,88 +242,45 @@ func (c *migrationSink) DoStorage(state *state.State, poolName string, req *api. // The migration header to be sent back to source with our target options. var respHeader migration.MigrationHeader - // Check if we can load new storage layer for pool driver type. pool, err := storagePools.GetPoolByName(state, poolName) - if err != storageDrivers.ErrUnknownDriver { - if err != nil { - return err - } - - // Extract the source's migration type and then match it against our pool's - // supported types and features. If a match is found the combined features list - // will be sent back to requester. - respType, err := migration.MatchTypes(offerHeader, migration.MigrationFSType_RSYNC, pool.MigrationTypes(storageDrivers.ContentTypeFS)) - if err != nil { - return err - } - - // Convert response type to response header and copy snapshot info into it. - respHeader = migration.TypesToHeader(respType) - respHeader.SnapshotNames = offerHeader.SnapshotNames - respHeader.Snapshots = offerHeader.Snapshots - - // Translate the legacy MigrationSinkArgs to a VolumeTargetArgs suitable for use - // with the new storage layer. - myTarget = func(conn *websocket.Conn, op *operations.Operation, args MigrationSinkArgs) error { - volTargetArgs := migration.VolumeTargetArgs{ - Name: req.Name, - Config: req.Config, - Description: req.Description, - MigrationType: respType, - TrackProgress: true, - } - - // A zero length Snapshots slice indicates volume only migration in - // VolumeTargetArgs. So if VoluneOnly was requested, do not populate them. - if !args.VolumeOnly { - volTargetArgs.Snapshots = make([]string, 0, len(args.Snapshots)) - for _, snap := range args.Snapshots { - volTargetArgs.Snapshots = append(volTargetArgs.Snapshots, *snap.Name) - } - } + if err != nil { + return err + } - return pool.CreateCustomVolumeFromMigration(&shared.WebsocketIO{Conn: conn}, volTargetArgs, op) - } - } else { - // Setup legacy storage migration sink if destination pool isn't supported yet by - // new storage layer. - storage, err := storagePoolVolumeDBCreateInternal(state, poolName, req) - if err != nil { - return err - } + // Extract the source's migration type and then match it against our pool's + // supported types and features. If a match is found the combined features list + // will be sent back to requester. + respType, err := migration.MatchTypes(offerHeader, migration.MigrationFSType_RSYNC, pool.MigrationTypes(storageDrivers.ContentTypeFS)) + if err != nil { + return err + } - // Link the storage variable into the migrationSink (like NewStorageMigrationSink - // would have done originally). - c.src.storage = storage - c.dest.storage = storage - myTarget = c.src.storage.StorageMigrationSink - myType := c.src.storage.MigrationType() - - hasFeature := true - respHeader = migration.MigrationHeader{ - Fs: &myType, - Snapshots: offerHeader.Snapshots, - SnapshotNames: offerHeader.SnapshotNames, - RsyncFeatures: &migration.RsyncFeatures{ - Xattrs: &hasFeature, - Delete: &hasFeature, - Compress: &hasFeature, - Bidirectional: &hasFeature, - }, + // Convert response type to response header and copy snapshot info into it. + respHeader = migration.TypesToHeader(respType) + respHeader.SnapshotNames = offerHeader.SnapshotNames + respHeader.Snapshots = offerHeader.Snapshots + + // Translate the legacy MigrationSinkArgs to a VolumeTargetArgs suitable for use + // with the new storage layer. + myTarget = func(conn *websocket.Conn, op *operations.Operation, args MigrationSinkArgs) error { + volTargetArgs := migration.VolumeTargetArgs{ + Name: req.Name, + Config: req.Config, + Description: req.Description, + MigrationType: respType, + TrackProgress: true, } - if len(zfsVersion) >= 3 && zfsVersion[0:3] != "0.6" { - respHeader.ZfsFeatures = &migration.ZfsFeatures{ - Compress: &hasFeature, + // A zero length Snapshots slice indicates volume only migration in + // VolumeTargetArgs. So if VoluneOnly was requested, do not populate them. + if !args.VolumeOnly { + volTargetArgs.Snapshots = make([]string, 0, len(args.Snapshots)) + for _, snap := range args.Snapshots { + volTargetArgs.Snapshots = append(volTargetArgs.Snapshots, *snap.Name) } } - // If the storage type the source has doesn't match what we have, then we have to - // use rsync. - if *offerHeader.Fs != *respHeader.Fs { - myTarget = rsyncStorageMigrationSink - myType = migration.MigrationFSType_RSYNC - } + return pool.CreateCustomVolumeFromMigration(&shared.WebsocketIO{Conn: conn}, volTargetArgs, op) } err = sender(&respHeader) From 99f75bd05b4a499bbf11cb04e204de0dd3577fb2 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 1 Nov 2019 08:59:08 +0000 Subject: [PATCH 05/14] lxd/storage/volumes/snapshot: Removes use of legacy storage from storagePoolVolumeSnapshotsTypePost Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage_volumes_snapshot.go | 59 ++++----------------------------- 1 file changed, 6 insertions(+), 53 deletions(-) diff --git a/lxd/storage_volumes_snapshot.go b/lxd/storage_volumes_snapshot.go index 7e21741a34..d0923530a8 100644 --- a/lxd/storage_volumes_snapshot.go +++ b/lxd/storage_volumes_snapshot.go @@ -85,9 +85,7 @@ func storagePoolVolumeSnapshotsTypePost(d *Daemon, r *http.Request) response.Res return response.BadRequest(fmt.Errorf("Volumes used by LXD itself cannot have snapshots")) } - // Retrieve ID of the storage pool (and check if the storage pool - // exists). - poolID, err := d.cluster.StoragePoolGetID(poolName) + pool, err := storagePools.GetPoolByName(d.State(), poolName) if err != nil { return response.SmartError(err) } @@ -97,19 +95,13 @@ func storagePoolVolumeSnapshotsTypePost(d *Daemon, r *http.Request) response.Res return resp } - resp = ForwardedResponseIfVolumeIsRemote(d, r, poolID, volumeName, volumeType) + resp = ForwardedResponseIfVolumeIsRemote(d, r, pool.ID(), volumeName, volumeType) if resp != nil { return resp } - // Ensure that the storage volume exists. - storage, err := storagePoolVolumeInit(d.State(), "default", poolName, volumeName, volumeType) - if err != nil { - return response.SmartError(err) - } - // Ensure that the snapshot doesn't already exist - _, _, err = d.cluster.StoragePoolNodeVolumeGetType(fmt.Sprintf("%s/%s", volumeName, req.Name), volumeType, poolID) + _, _, err = d.cluster.StoragePoolNodeVolumeGetType(fmt.Sprintf("%s/%s", volumeName, req.Name), volumeType, pool.ID()) if err != db.ErrNoSuchObject { if err != nil { return response.SmartError(err) @@ -119,48 +111,9 @@ func storagePoolVolumeSnapshotsTypePost(d *Daemon, r *http.Request) response.Res } snapshot := func(op *operations.Operation) error { - // Check if we can load new storage layer for pool driver type. - pool, err := storagePools.GetPoolByName(d.State(), poolName) - if err != storageDrivers.ErrUnknownDriver { - if err != nil { - return err - } - - err = pool.CreateCustomVolumeSnapshot(volumeName, req.Name, op) - if err != nil { - return err - } - } else { - // Start the storage. - ourMount, err := storage.StoragePoolVolumeMount() - if err != nil { - return err - } - if ourMount { - defer storage.StoragePoolVolumeUmount() - } - - volWritable := storage.GetStoragePoolVolumeWritable() - fullSnapName := fmt.Sprintf("%s%s%s", volumeName, shared.SnapshotDelimiter, req.Name) - req.Name = fullSnapName - dbArgs := &db.StorageVolumeArgs{ - Name: fullSnapName, - PoolName: poolName, - TypeName: volumeTypeName, - Snapshot: true, - Config: volWritable.Config, - Description: volWritable.Description, - } - - err = storage.StoragePoolVolumeSnapshotCreate(&req) - if err != nil { - return err - } - - _, err = storagePoolVolumeSnapshotDBCreateInternal(d.State(), dbArgs) - if err != nil { - return err - } + err = pool.CreateCustomVolumeSnapshot(volumeName, req.Name, op) + if err != nil { + return err } return nil From 77f0c13e8422b907c197a6dbf8752d774b1a2ee4 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 1 Nov 2019 09:00:49 +0000 Subject: [PATCH 06/14] lxd/storage/volumes/snapshot: Removes use of legacy storage from storagePoolVolumeSnapshotTypePost Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage_volumes_snapshot.go | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/lxd/storage_volumes_snapshot.go b/lxd/storage_volumes_snapshot.go index d0923530a8..d292174731 100644 --- a/lxd/storage_volumes_snapshot.go +++ b/lxd/storage_volumes_snapshot.go @@ -252,36 +252,19 @@ func storagePoolVolumeSnapshotTypePost(d *Daemon, r *http.Request) response.Resp return resp } - poolID, _, err := d.cluster.StoragePoolGet(poolName) + pool, err := storagePools.GetPoolByName(d.State(), poolName) if err != nil { return response.SmartError(err) } fullSnapshotName := fmt.Sprintf("%s/%s", volumeName, snapshotName) - resp = ForwardedResponseIfVolumeIsRemote(d, r, poolID, fullSnapshotName, volumeType) + resp = ForwardedResponseIfVolumeIsRemote(d, r, pool.ID(), fullSnapshotName, volumeType) if resp != nil { return resp } - s, err := storagePoolVolumeInit(d.State(), "default", poolName, fullSnapshotName, volumeType) - if err != nil { - return response.NotFound(err) - } - snapshotRename := func(op *operations.Operation) error { - // Check if we can load new storage layer for pool driver type. - pool, err := storagePools.GetPoolByName(d.State(), poolName) - if err != storageDrivers.ErrUnknownDriver { - if err != nil { - return err - } - - err = pool.RenameCustomVolumeSnapshot(fullSnapshotName, req.Name, op) - } else { - err = s.StoragePoolVolumeSnapshotRename(req.Name) - } - - return err + return pool.RenameCustomVolumeSnapshot(fullSnapshotName, req.Name, op) } resources := map[string][]string{} From 4daf69d4045161d7ce3af6ff7ff3bcb92c981b7a Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 1 Nov 2019 09:02:04 +0000 Subject: [PATCH 07/14] lxd/storage/volumes/snapshot: Removes use of legacy storage from storagePoolVolumeSnapshotTypeDelete Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage_volumes_snapshot.go | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/lxd/storage_volumes_snapshot.go b/lxd/storage_volumes_snapshot.go index d292174731..afbebcad8f 100644 --- a/lxd/storage_volumes_snapshot.go +++ b/lxd/storage_volumes_snapshot.go @@ -12,7 +12,6 @@ import ( "github.com/lxc/lxd/lxd/operations" "github.com/lxc/lxd/lxd/response" storagePools "github.com/lxc/lxd/lxd/storage" - storageDrivers "github.com/lxc/lxd/lxd/storage/drivers" "github.com/lxc/lxd/lxd/util" "github.com/lxc/lxd/shared" "github.com/lxc/lxd/shared/api" @@ -447,36 +446,19 @@ func storagePoolVolumeSnapshotTypeDelete(d *Daemon, r *http.Request) response.Re return resp } - poolID, _, err := d.cluster.StoragePoolGet(poolName) + pool, err := storagePools.GetPoolByName(d.State(), poolName) if err != nil { return response.SmartError(err) } fullSnapshotName := fmt.Sprintf("%s/%s", volumeName, snapshotName) - resp = ForwardedResponseIfVolumeIsRemote(d, r, poolID, fullSnapshotName, volumeType) + resp = ForwardedResponseIfVolumeIsRemote(d, r, pool.ID(), fullSnapshotName, volumeType) if resp != nil { return resp } - s, err := storagePoolVolumeInit(d.State(), "default", poolName, fullSnapshotName, volumeType) - if err != nil { - return response.NotFound(err) - } - snapshotDelete := func(op *operations.Operation) error { - // Check if we can load new storage layer for pool driver type. - pool, err := storagePools.GetPoolByName(d.State(), poolName) - if err != storageDrivers.ErrUnknownDriver { - if err != nil { - return err - } - - err = pool.DeleteCustomVolumeSnapshot(fullSnapshotName, op) - } else { - err = s.StoragePoolVolumeSnapshotDelete() - } - - return err + return pool.DeleteCustomVolumeSnapshot(fullSnapshotName, op) } resources := map[string][]string{} From 52058075e9f9744df58231e4ea47319e6a6fea0b Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 1 Nov 2019 09:04:55 +0000 Subject: [PATCH 08/14] lxd/storage/volumes: Removes use of legacy storage from doVolumeCreateOrCopy Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage_volumes.go | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go index 1f7f31cea4..02188c0fe5 100644 --- a/lxd/storage_volumes.go +++ b/lxd/storage_volumes.go @@ -294,27 +294,17 @@ func storagePoolVolumesTypePost(d *Daemon, r *http.Request) response.Response { } func doVolumeCreateOrCopy(d *Daemon, poolName string, req *api.StorageVolumesPost) response.Response { - var run func(op *operations.Operation) error - - // Check if we can load new storage layer for both target and source pool driver types. pool, err := storagePools.GetPoolByName(d.State(), poolName) - _, srcPoolErr := storagePools.GetPoolByName(d.State(), req.Source.Pool) - if err != storageDrivers.ErrUnknownDriver && srcPoolErr != storageDrivers.ErrUnknownDriver { - if err != nil { - return response.SmartError(err) - } - - run = func(op *operations.Operation) error { - if req.Source.Name == "" { - return pool.CreateCustomVolume(req.Name, req.Description, req.Config, op) - } + if err != nil { + return response.SmartError(err) + } - return pool.CreateCustomVolumeFromCopy(req.Name, req.Description, req.Config, req.Source.Pool, req.Source.Name, req.Source.VolumeOnly, op) - } - } else { - run = func(op *operations.Operation) error { - return storagePoolVolumeCreateInternal(d.State(), poolName, req) + run := func(op *operations.Operation) error { + if req.Source.Name == "" { + return pool.CreateCustomVolume(req.Name, req.Description, req.Config, op) } + + return pool.CreateCustomVolumeFromCopy(req.Name, req.Description, req.Config, req.Source.Pool, req.Source.Name, req.Source.VolumeOnly, op) } // If no source name supplied then this a volume create operation. From 7a87fbc0fa8e523c8c75625e4cbbb45ca8dffc4e Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 1 Nov 2019 09:06:59 +0000 Subject: [PATCH 09/14] lxd/storage/volumes: Removes use of legacy storage from storagePoolVolumeTypePostRename Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage_volumes.go | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go index 02188c0fe5..4707eda868 100644 --- a/lxd/storage_volumes.go +++ b/lxd/storage_volumes.go @@ -636,31 +636,16 @@ func storagePoolVolumeTypePostRename(d *Daemon, poolName string, volumeName stri return response.SmartError(err) } - // Check if we can load new storage layer for pool driver type. pool, err := storagePools.GetPoolByName(d.State(), poolName) - if err != storageDrivers.ErrUnknownDriver { - if err != nil { - return response.SmartError(err) - } - - err = pool.RenameCustomVolume(volumeName, req.Name, nil) - if err != nil { - // Notify users of the volume that it's name is changing back. - storagePoolVolumeUpdateUsers(d, req.Pool, req.Name, poolName, volumeName) - return response.SmartError(err) - } - } else { - s, err := storagePoolVolumeInit(d.State(), "default", poolName, volumeName, volumeType) - if err != nil { - return response.InternalError(err) - } + if err != nil { + return response.SmartError(err) + } - err = s.StoragePoolVolumeRename(req.Name) - if err != nil { - // Notify users of the volume that it's name is changing back. - storagePoolVolumeUpdateUsers(d, req.Pool, req.Name, poolName, volumeName) - return response.SmartError(err) - } + err = pool.RenameCustomVolume(volumeName, req.Name, nil) + if err != nil { + // Notify users of the volume that it's name is changing back. + storagePoolVolumeUpdateUsers(d, req.Pool, req.Name, poolName, volumeName) + return response.SmartError(err) } return response.SyncResponseLocation(true, nil, fmt.Sprintf("/%s/storage-pools/%s/volumes/%s", version.APIVersion, poolName, storagePoolVolumeAPIEndpointCustom)) From 3570136b1dbd3c9a13e231bf983c27ecd8ddff6a Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 1 Nov 2019 09:09:31 +0000 Subject: [PATCH 10/14] lxd/storage/volumes: Removes use of legacy storage from storagePoolVolumeTypePostMove Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage_volumes.go | 103 +++++++---------------------------------- 1 file changed, 18 insertions(+), 85 deletions(-) diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go index 4707eda868..024826ce28 100644 --- a/lxd/storage_volumes.go +++ b/lxd/storage_volumes.go @@ -653,100 +653,33 @@ func storagePoolVolumeTypePostRename(d *Daemon, poolName string, volumeName stri // storagePoolVolumeTypePostMove handles volume move type POST requests. func storagePoolVolumeTypePostMove(d *Daemon, poolName string, volumeName string, volumeType int, req api.StorageVolumePost) response.Response { - var run func(op *operations.Operation) error + srcPool, err := storagePools.GetPoolByName(d.State(), poolName) + if err != nil { + return response.SmartError(err) + } - // Check if we can load new storage layer for both target and source pool driver types. - srcPool, srcPoolErr := storagePools.GetPoolByName(d.State(), poolName) pool, err := storagePools.GetPoolByName(d.State(), req.Pool) - if err != storageDrivers.ErrUnknownDriver && srcPoolErr != storageDrivers.ErrUnknownDriver { - if err != nil { - return response.SmartError(err) - } - - run = func(op *operations.Operation) error { - // Notify users of the volume that it's name is changing. - err := storagePoolVolumeUpdateUsers(d, poolName, volumeName, req.Pool, req.Name) - if err != nil { - return err - } - - // Provide empty description and nil config to instruct - // CreateCustomVolumeFromCopy to copy it from source volume. - err = pool.CreateCustomVolumeFromCopy(req.Name, "", nil, poolName, volumeName, false, op) - if err != nil { - // Notify users of the volume that it's name is changing back. - storagePoolVolumeUpdateUsers(d, req.Pool, req.Name, poolName, volumeName) - return err - } - - return srcPool.DeleteCustomVolume(volumeName, op) - } - } else { - // Convert poolName to poolID. - poolID, _, err := d.cluster.StoragePoolGet(poolName) - if err != nil { - return response.SmartError(err) - } + if err != nil { + return response.SmartError(err) + } - // Get the storage volume. - _, volume, err := d.cluster.StoragePoolNodeVolumeGetType(volumeName, volumeType, poolID) + run := func(op *operations.Operation) error { + // Notify users of the volume that it's name is changing. + err = storagePoolVolumeUpdateUsers(d, poolName, volumeName, req.Pool, req.Name) if err != nil { - return response.SmartError(err) + return err } - // Get storage volume snapshots. - snapshots, err := d.cluster.StoragePoolVolumeSnapshotsGetType(volumeName, volumeType, poolID) + // Provide empty description and nil config to instruct + // CreateCustomVolumeFromCopy to copy it from source volume. + err = pool.CreateCustomVolumeFromCopy(req.Name, "", nil, poolName, volumeName, false, op) if err != nil { - return response.SmartError(err) + // Notify users of the volume that it's name is changing back. + storagePoolVolumeUpdateUsers(d, req.Pool, req.Name, poolName, volumeName) + return err } - // This is a move request, so copy the volume and then delete the original. - moveReq := api.StorageVolumesPost{} - moveReq.Name = req.Name - moveReq.Type = "custom" - moveReq.Config = volume.Config - moveReq.Source.Name = volumeName - moveReq.Source.Pool = poolName - - run = func(op *operations.Operation) error { - // Notify users of the volume that it's name is changing. - err := storagePoolVolumeUpdateUsers(d, poolName, volumeName, req.Pool, req.Name) - if err != nil { - return err - } - - err = storagePoolVolumeCreateInternal(d.State(), req.Pool, &moveReq) - if err != nil { - // Notify users of the volume that it's name is changing back. - storagePoolVolumeUpdateUsers(d, req.Pool, req.Name, poolName, volumeName) - return err - } - - // Delete snapshot volumes. - for _, snapshot := range snapshots { - s, err := storagePoolVolumeInit(d.State(), "default", poolName, snapshot.Name, volumeType) - if err != nil { - return err - } - - err = s.StoragePoolVolumeSnapshotDelete() - if err != nil { - return err - } - } - - s, err := storagePoolVolumeInit(d.State(), "default", poolName, volumeName, volumeType) - if err != nil { - return err - } - - err = s.StoragePoolVolumeDelete() - if err != nil { - return err - } - - return nil - } + return srcPool.DeleteCustomVolume(volumeName, op) } op, err := operations.OperationCreate(d.State(), "", operations.OperationClassTask, db.OperationVolumeMove, nil, nil, run, nil, nil) From be736fde88c6c360b463c74cf7b1702e219d9913 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 1 Nov 2019 09:15:13 +0000 Subject: [PATCH 11/14] lxd/storage/volumes: Removes use of legacy storage from storagePoolVolumeTypePut Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage_volumes.go | 100 +++++++++++++---------------------------- 1 file changed, 32 insertions(+), 68 deletions(-) diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go index 024826ce28..1b207a960b 100644 --- a/lxd/storage_volumes.go +++ b/lxd/storage_volumes.go @@ -815,23 +815,23 @@ func storagePoolVolumeTypePut(d *Daemon, r *http.Request, volumeTypeName string) return response.BadRequest(fmt.Errorf("Invalid storage volume type %s", volumeTypeName)) } - poolID, poolRow, err := d.cluster.StoragePoolGet(poolName) - if err != nil { - return response.SmartError(err) - } - resp := ForwardedResponseIfTargetIsRemote(d, r) if resp != nil { return resp } - resp = ForwardedResponseIfVolumeIsRemote(d, r, poolID, volumeName, volumeType) + pool, err := storagePools.GetPoolByName(d.State(), poolName) + if err != nil { + return response.SmartError(err) + } + + resp = ForwardedResponseIfVolumeIsRemote(d, r, pool.ID(), volumeName, volumeType) if resp != nil { return resp } // Get the existing storage volume. - _, vol, err := d.cluster.StoragePoolNodeVolumeGetType(volumeName, volumeType, poolID) + _, vol, err := d.cluster.StoragePoolNodeVolumeGetType(volumeName, volumeType, pool.ID()) if err != nil { return response.SmartError(err) } @@ -849,76 +849,40 @@ func storagePoolVolumeTypePut(d *Daemon, r *http.Request, volumeTypeName string) return response.BadRequest(err) } - // Check if we can load new storage layer for pool driver type. - pool, err := storagePools.GetPoolByName(d.State(), poolName) - if err != storageDrivers.ErrUnknownDriver { - if err != nil { - return response.SmartError(err) - } - - if volumeType == db.StoragePoolVolumeTypeCustom { - // Restore custom volume from snapshot if requested. This should occur first - // before applying config changes so that changes are applied to the - // restored volume. - if req.Restore != "" { - err = pool.RestoreCustomVolume(vol.Name, req.Restore, nil) - if err != nil { - return response.SmartError(err) - } - } - - // Handle update requests. - err = pool.UpdateCustomVolume(vol.Name, req.Description, req.Config, nil) + if volumeType == db.StoragePoolVolumeTypeCustom { + // Restore custom volume from snapshot if requested. This should occur first + // before applying config changes so that changes are applied to the + // restored volume. + if req.Restore != "" { + err = pool.RestoreCustomVolume(vol.Name, req.Restore, nil) if err != nil { return response.SmartError(err) } - } else { - // You are only allowed to modify the description for non-custom volumes. - // This is a special case because the rootfs devices do not provide a way - // to update a non-custom volume's description. - if len(req.Config) > 0 { - return response.BadRequest(fmt.Errorf("Only description can be modified for volume type %s", volumeTypeName)) - } - - // There is a bug in the lxc client (lxc/storage_volume.go#L829-L865) which - // means that modifying a snapshot's description gets routed here rather - // than the dedicated snapshot editing route. So need to handle snapshot - // volumes here too. + } - // Update the database if description changed. - if req.Description != vol.Description { - err = d.cluster.StoragePoolVolumeUpdate(vol.Name, volumeType, poolID, req.Description, vol.Config) - if err != nil { - response.SmartError(err) - } - } + // Handle update requests. + err = pool.UpdateCustomVolume(vol.Name, req.Description, req.Config, nil) + if err != nil { + return response.SmartError(err) } } else { + // You are only allowed to modify the description for non-custom volumes. + // This is a special case because the rootfs devices do not provide a way + // to update a non-custom volume's description. + if len(req.Config) > 0 { + return response.BadRequest(fmt.Errorf("Only description can be modified for volume type %s", volumeTypeName)) + } - if req.Restore != "" { - ctsUsingVolume, err := storagePoolVolumeUsedByRunningContainersWithProfilesGet(d.State(), poolName, vol.Name, storagePoolVolumeTypeNameCustom, true) - if err != nil { - return response.InternalError(err) - } - - if len(ctsUsingVolume) != 0 { - return response.BadRequest(fmt.Errorf("Cannot restore custom volume used by running containers")) - } - - err = storagePoolVolumeRestore(d.State(), poolName, volumeName, volumeType, req.Restore) - if err != nil { - return response.SmartError(err) - } - } else { - // Validate the configuration - err = storagePools.VolumeValidateConfig(volumeName, req.Config, poolRow) - if err != nil { - return response.BadRequest(err) - } + // There is a bug in the lxc client (lxc/storage_volume.go#L829-L865) which + // means that modifying a snapshot's description gets routed here rather + // than the dedicated snapshot editing route. So need to handle snapshot + // volumes here too. - err = storagePoolVolumeUpdate(d.State(), poolName, volumeName, volumeType, req.Description, req.Config) + // Update the database if description changed. + if req.Description != vol.Description { + err = d.cluster.StoragePoolVolumeUpdate(vol.Name, volumeType, pool.ID(), req.Description, vol.Config) if err != nil { - return response.SmartError(err) + response.SmartError(err) } } } From 8a82a953a4429668994305f37d78ef90e361c1e0 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 1 Nov 2019 09:18:51 +0000 Subject: [PATCH 12/14] lxd/storage/volumes: Removes use of legacy storage from storagePoolVolumeTypePatch Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage_volumes.go | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go index 1b207a960b..61fee49e8e 100644 --- a/lxd/storage_volumes.go +++ b/lxd/storage_volumes.go @@ -925,8 +925,7 @@ func storagePoolVolumeTypePatch(d *Daemon, r *http.Request, volumeTypeName strin return response.BadRequest(fmt.Errorf("Invalid storage volume type %s", volumeTypeName)) } - // Get the ID of the storage pool the storage volume is supposed to be attached to. - poolID, poolRow, err := d.cluster.StoragePoolGet(poolName) + pool, err := storagePools.GetPoolByName(d.State(), poolName) if err != nil { return response.SmartError(err) } @@ -936,13 +935,13 @@ func storagePoolVolumeTypePatch(d *Daemon, r *http.Request, volumeTypeName strin return resp } - resp = ForwardedResponseIfVolumeIsRemote(d, r, poolID, volumeName, volumeType) + resp = ForwardedResponseIfVolumeIsRemote(d, r, pool.ID(), volumeName, volumeType) if resp != nil { return resp } // Get the existing storage volume. - _, vol, err := d.cluster.StoragePoolNodeVolumeGetType(volumeName, volumeType, poolID) + _, vol, err := d.cluster.StoragePoolNodeVolumeGetType(volumeName, volumeType, pool.ID()) if err != nil { return response.SmartError(err) } @@ -972,28 +971,9 @@ func storagePoolVolumeTypePatch(d *Daemon, r *http.Request, volumeTypeName strin } } - // Check if we can load new storage layer for pool driver type. - pool, err := storagePools.GetPoolByName(d.State(), poolName) - if err != storageDrivers.ErrUnknownDriver { - if err != nil { - return response.SmartError(err) - } - - err = pool.UpdateCustomVolume(vol.Name, req.Description, req.Config, nil) - if err != nil { - return response.SmartError(err) - } - } else { - // Validate the configuration. - err = storagePools.VolumeValidateConfig(volumeName, req.Config, poolRow) - if err != nil { - return response.BadRequest(err) - } - - err = storagePoolVolumeUpdate(d.State(), poolName, volumeName, volumeType, req.Description, req.Config) - if err != nil { - return response.SmartError(err) - } + err = pool.UpdateCustomVolume(vol.Name, req.Description, req.Config, nil) + if err != nil { + return response.SmartError(err) } return response.EmptySyncResponse From 1c411db85c7d3356ca30ae99b4bb4f2c50839710 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 1 Nov 2019 09:20:26 +0000 Subject: [PATCH 13/14] lxd/storage/volumes: Removes use of legacy storage from storagePoolVolumeTypeDelete Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage_volumes.go | 77 +++++++----------------------------------- 1 file changed, 13 insertions(+), 64 deletions(-) diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go index 61fee49e8e..e6a8d106f7 100644 --- a/lxd/storage_volumes.go +++ b/lxd/storage_volumes.go @@ -16,7 +16,6 @@ import ( "github.com/lxc/lxd/lxd/response" "github.com/lxc/lxd/lxd/state" storagePools "github.com/lxc/lxd/lxd/storage" - storageDrivers "github.com/lxc/lxd/lxd/storage/drivers" "github.com/lxc/lxd/lxd/util" "github.com/lxc/lxd/shared" "github.com/lxc/lxd/shared/api" @@ -1021,12 +1020,12 @@ func storagePoolVolumeTypeDelete(d *Daemon, r *http.Request, volumeTypeName stri return resp } - poolID, _, err := d.cluster.StoragePoolGet(poolName) + pool, err := storagePools.GetPoolByName(d.State(), poolName) if err != nil { return response.SmartError(err) } - resp = ForwardedResponseIfVolumeIsRemote(d, r, poolID, volumeName, volumeType) + resp = ForwardedResponseIfVolumeIsRemote(d, r, pool.ID(), volumeName, volumeType) if resp != nil { return resp } @@ -1046,71 +1045,21 @@ func storagePoolVolumeTypeDelete(d *Daemon, r *http.Request, volumeTypeName stri } if len(volumeUsedBy) > 0 { - if len(volumeUsedBy) != 1 || - volumeType != storagePoolVolumeTypeImage || - volumeUsedBy[0] != fmt.Sprintf( - "/%s/images/%s", - version.APIVersion, - volumeName) { + if len(volumeUsedBy) != 1 || volumeType != storagePoolVolumeTypeImage || volumeUsedBy[0] != fmt.Sprintf("/%s/images/%s", version.APIVersion, volumeName) { return response.BadRequest(fmt.Errorf("The storage volume is still in use")) } } - // Check if we can load new storage layer for pool driver type. - pool, err := storagePools.GetPoolByName(d.State(), poolName) - if err != storageDrivers.ErrUnknownDriver { - if err != nil { - return response.SmartError(err) - } - - switch volumeType { - case storagePoolVolumeTypeCustom: - err = pool.DeleteCustomVolume(volumeName, nil) - case storagePoolVolumeTypeImage: - err = pool.DeleteImage(volumeName, nil) - default: - return response.BadRequest(fmt.Errorf(`Storage volumes of type "%s" cannot be deleted with the storage api`, volumeTypeName)) - } - if err != nil { - return response.SmartError(err) - } - } else { - s, err := storagePoolVolumeInit(d.State(), project, poolName, volumeName, volumeType) - if err != nil { - return response.NotFound(err) - } - - switch volumeType { - case storagePoolVolumeTypeCustom: - var snapshots []db.StorageVolumeArgs - - // Delete storage volume snapshots - snapshots, err = d.cluster.StoragePoolVolumeSnapshotsGetType(volumeName, volumeType, poolID) - if err != nil { - return response.SmartError(err) - } - - for _, snapshot := range snapshots { - s, err := storagePoolVolumeInit(d.State(), project, poolName, snapshot.Name, volumeType) - if err != nil { - return response.NotFound(err) - } - - err = s.StoragePoolVolumeSnapshotDelete() - if err != nil { - return response.SmartError(err) - } - } - - err = s.StoragePoolVolumeDelete() - case storagePoolVolumeTypeImage: - err = s.ImageDelete(volumeName) - default: - return response.BadRequest(fmt.Errorf(`Storage volumes of type "%s" cannot be deleted with the storage api`, volumeTypeName)) - } - if err != nil { - return response.SmartError(err) - } + switch volumeType { + case storagePoolVolumeTypeCustom: + err = pool.DeleteCustomVolume(volumeName, nil) + case storagePoolVolumeTypeImage: + err = pool.DeleteImage(volumeName, nil) + default: + return response.BadRequest(fmt.Errorf(`Storage volumes of type "%s" cannot be deleted with the storage api`, volumeTypeName)) + } + if err != nil { + return response.SmartError(err) } return response.EmptySyncResponse From 2436ba2dbd97f2ee4ce8fd31a9e7b24228663cba Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 1 Nov 2019 09:42:03 +0000 Subject: [PATCH 14/14] lxd/storage/volumes/utils: Removes unused legacy storage funtions To appease static analysis. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/storage_volumes_utils.go | 271 ----------------------------------- 1 file changed, 271 deletions(-) diff --git a/lxd/storage_volumes_utils.go b/lxd/storage_volumes_utils.go index ab7791e742..0456c3899b 100644 --- a/lxd/storage_volumes_utils.go +++ b/lxd/storage_volumes_utils.go @@ -3,7 +3,6 @@ package main import ( "fmt" "path/filepath" - "strings" "github.com/lxc/lxd/lxd/db" "github.com/lxc/lxd/lxd/state" @@ -69,144 +68,6 @@ func storagePoolVolumeTypeToAPIEndpoint(volumeType int) (string, error) { return "", fmt.Errorf("invalid storage volume type") } -func storagePoolVolumeRestore(state *state.State, poolName string, volumeName string, volumeType int, snapshotName string) error { - s, err := storagePoolVolumeInit(state, "default", poolName, - fmt.Sprintf("%s/%s", volumeName, snapshotName), volumeType) - if err != nil { - return err - } - - snapshotWritable := s.GetStoragePoolVolumeWritable() - snapshotWritable.Restore = snapshotName - - s, err = storagePoolVolumeInit(state, "default", poolName, volumeName, volumeType) - if err != nil { - return err - } - - err = s.StoragePoolVolumeUpdate(&snapshotWritable, nil) - if err != nil { - return err - } - - return nil -} - -func storagePoolVolumeUpdate(state *state.State, poolName string, volumeName string, volumeType int, newDescription string, newConfig map[string]string) error { - s, err := storagePoolVolumeInit(state, "default", poolName, volumeName, volumeType) - if err != nil { - return err - } - - oldWritable := s.GetStoragePoolVolumeWritable() - newWritable := oldWritable - - // Backup the current state - oldDescription := oldWritable.Description - oldConfig := map[string]string{} - err = shared.DeepCopy(&oldWritable.Config, &oldConfig) - if err != nil { - return err - } - - // Define a function which reverts everything. Defer this function - // so that it doesn't need to be explicitly called in every failing - // return path. Track whether or not we want to undo the changes - // using a closure. - undoChanges := true - defer func() { - if undoChanges { - s.SetStoragePoolVolumeWritable(&oldWritable) - } - }() - - // Diff the configurations - changedConfig := []string{} - userOnly := true - for key := range oldConfig { - if oldConfig[key] != newConfig[key] { - if !strings.HasPrefix(key, "user.") { - userOnly = false - } - - if !shared.StringInSlice(key, changedConfig) { - changedConfig = append(changedConfig, key) - } - } - } - - for key := range newConfig { - if oldConfig[key] != newConfig[key] { - if !strings.HasPrefix(key, "user.") { - userOnly = false - } - - if !shared.StringInSlice(key, changedConfig) { - changedConfig = append(changedConfig, key) - } - } - } - - // Apply config changes if there are any - if len(changedConfig) != 0 { - newWritable.Description = newDescription - newWritable.Config = newConfig - - // Update the storage pool - if !userOnly { - err = s.StoragePoolVolumeUpdate(&newWritable, changedConfig) - if err != nil { - return err - } - } - - // Apply the new configuration - s.SetStoragePoolVolumeWritable(&newWritable) - } - - // Check that security.unmapped and security.shifted aren't set together - if shared.IsTrue(newConfig["security.unmapped"]) && shared.IsTrue(newConfig["security.shifted"]) { - return fmt.Errorf("security.unmapped and security.shifted are mutually exclusive") - } - - // Confirm that no containers are running when changing shifted state - if newConfig["security.shifted"] != oldConfig["security.shifted"] { - ctsUsingVolume, err := storagePoolVolumeUsedByRunningContainersWithProfilesGet(state, poolName, volumeName, storagePoolVolumeTypeNameCustom, true) - if err != nil { - return err - } - - if len(ctsUsingVolume) != 0 { - return fmt.Errorf("Cannot modify shifting with running containers using the volume") - } - } - - // Unset idmap keys if volume is unmapped - if shared.IsTrue(newConfig["security.unmapped"]) { - delete(newConfig, "volatile.idmap.last") - delete(newConfig, "volatile.idmap.next") - } - - // Get the pool ID - poolID, err := state.Cluster.StoragePoolGetID(poolName) - if err != nil { - return err - } - - // Update the database if something changed - if len(changedConfig) != 0 || newDescription != oldDescription { - err = state.Cluster.StoragePoolVolumeUpdate(volumeName, volumeType, poolID, newDescription, newConfig) - if err != nil { - return err - } - } - - // Success, update the closure to mark that the changes should be kept. - undoChanges = false - - return nil -} - func storagePoolVolumeUsedByContainersGet(s *state.State, project, poolName string, volumeName string) ([]string, error) { insts, err := instanceLoadByProject(s, project) if err != nil { @@ -494,138 +355,6 @@ func profilesUsingPoolVolumeGetNames(db *db.Cluster, volumeName string, volumeTy return usedBy, nil } -func storagePoolVolumeDBCreateInternal(state *state.State, poolName string, vol *api.StorageVolumesPost) (storage, error) { - volumeName := vol.Name - volumeDescription := vol.Description - volumeTypeName := vol.Type - volumeConfig := vol.Config - - if vol.Source.Name != "" { - // Initialize instance of new pool to translate properties - // between storage drivers. - s, err := storagePoolInit(state, poolName) - if err != nil { - return nil, err - } - - driver := s.GetStorageTypeName() - newConfig, err := storagePools.VolumePropertiesTranslate(vol.Config, driver) - if err != nil { - return nil, err - } - - vol.Config = newConfig - volumeConfig = newConfig - } - - // Create database entry for new storage volume. - err := storagePools.VolumeDBCreate(state, poolName, volumeName, volumeDescription, volumeTypeName, false, volumeConfig) - if err != nil { - return nil, err - } - - // Convert the volume type name to our internal integer representation. - poolID, err := state.Cluster.StoragePoolGetID(poolName) - if err != nil { - return nil, err - } - - volumeType, err := storagePools.VolumeTypeNameToType(volumeTypeName) - if err != nil { - state.Cluster.StoragePoolVolumeDelete("default", volumeName, volumeType, poolID) - return nil, err - } - - // Initialize new storage volume on the target storage pool. - s, err := storagePoolVolumeInit(state, "default", poolName, volumeName, volumeType) - if err != nil { - state.Cluster.StoragePoolVolumeDelete("default", volumeName, volumeType, poolID) - return nil, err - } - - return s, nil -} - -func storagePoolVolumeCreateInternal(state *state.State, poolName string, vol *api.StorageVolumesPost) error { - s, err := storagePoolVolumeDBCreateInternal(state, poolName, vol) - if err != nil { - return err - } - - volumeType, err1 := storagePools.VolumeTypeNameToType(vol.Type) - poolID, _, _ := s.GetContainerPoolInfo() - revert := true - - defer func() { - if revert && err1 == nil { - state.Cluster.StoragePoolVolumeDelete("default", vol.Name, volumeType, poolID) - } - }() - - if vol.Source.Name == "" { - err = s.StoragePoolVolumeCreate() - } else { - if !vol.Source.VolumeOnly { - snapshots, err := storagePools.VolumeSnapshotsGet(state, vol.Source.Pool, vol.Source.Name, volumeType) - if err != nil { - return err - } - - for _, snap := range snapshots { - _, snapName, _ := shared.ContainerGetParentAndSnapshotName(snap.Name) - _, err := storagePoolVolumeSnapshotCopyInternal(state, poolName, vol, snapName) - if err != nil { - return err - } - } - } - - err = s.StoragePoolVolumeCopy(&vol.Source) - } - if err != nil { - return err - } - - revert = false - - return nil -} - -func storagePoolVolumeSnapshotCopyInternal(state *state.State, poolName string, vol *api.StorageVolumesPost, snapshotName string) (storage, error) { - volumeType, err := storagePools.VolumeTypeNameToType(vol.Type) - if err != nil { - return nil, err - } - - fullSnapshotName := fmt.Sprintf("%s/%s", vol.Name, snapshotName) - - sourcePoolID, err := state.Cluster.StoragePoolGetID(vol.Source.Pool) - if err != nil { - return nil, err - } - - volumeID, err := state.Cluster.StoragePoolNodeVolumeGetTypeID(vol.Source.Name, volumeType, sourcePoolID) - if err != nil { - return nil, err - } - - volumeDescription, err := state.Cluster.StorageVolumeDescriptionGet(volumeID) - if err != nil { - return nil, err - } - - dbArgs := &db.StorageVolumeArgs{ - Name: fullSnapshotName, - PoolName: poolName, - TypeName: vol.Type, - Snapshot: true, - Config: vol.Config, - Description: volumeDescription, - } - - return storagePoolVolumeSnapshotDBCreateInternal(state, dbArgs) -} - func storagePoolVolumeSnapshotDBCreateInternal(state *state.State, dbArgs *db.StorageVolumeArgs) (storage, error) { // Create database entry for new storage volume. err := storagePools.VolumeDBCreate(state, dbArgs.PoolName, dbArgs.Name, dbArgs.Description, dbArgs.TypeName, true, dbArgs.Config)
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel