The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6406

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) ===
- [ ] Instance rename
- [ ] Instance snapshot rename
From 2a5f7bec1784cd68b70d32f9a3328d96b06b06bf Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 5 Nov 2019 18:34:08 +0000
Subject: [PATCH 1/4] lxd/container/lxc: Links Rename to new storage package

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/container_lxc.go | 168 ++++++++++++++++++++++++++-----------------
 1 file changed, 102 insertions(+), 66 deletions(-)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index f2ceb68781..cd175ee210 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -3736,13 +3736,7 @@ func (c *containerLXC) Rename(newName string) error {
 
        logger.Info("Renaming container", ctxMap)
 
-       // Initialize storage interface for the container.
-       err := c.initStorage()
-       if err != nil {
-               return err
-       }
-
-       // Sanity checks
+       // Sanity checks.
        if !c.IsSnapshot() && !shared.ValidHostname(newName) {
                return fmt.Errorf("Invalid container name")
        }
@@ -3751,62 +3745,89 @@ func (c *containerLXC) Rename(newName string) error {
                return fmt.Errorf("Renaming of running container not allowed")
        }
 
-       // Clean things up
+       // Clean things up.
        c.cleanup()
 
-       // Rename the MAAS entry
-       if !c.IsSnapshot() {
-               err = c.maasRename(newName)
+       // Check if we can load new storage layer for pool driver type.
+       pool, err := storagePools.GetPoolByInstance(c.state, c)
+       if err != storageDrivers.ErrUnknownDriver && err != 
storageDrivers.ErrNotImplemented {
                if err != nil {
-                       return err
+                       return errors.Wrap(err, "Load instance storage pool")
                }
-       }
 
-       // Rename the logging path
-       os.RemoveAll(shared.LogPath(newName))
-       if shared.PathExists(c.LogPath()) {
-               err := os.Rename(c.LogPath(), shared.LogPath(newName))
-               if err != nil {
-                       logger.Error("Failed renaming container", ctxMap)
-                       return err
+               if c.IsSnapshot() {
+                       err = pool.RenameInstanceSnapshot(c, newName, nil)
+                       if err != nil {
+                               return errors.Wrap(err, "Rename instance 
snapshot")
+                       }
+               } else {
+                       err = pool.RenameInstance(c, newName, nil)
+                       if err != nil {
+                               return errors.Wrap(err, "Rename instance")
+                       }
                }
-       }
-
-       // Rename the storage entry
-       if c.IsSnapshot() {
-               err := c.storage.ContainerSnapshotRename(c, newName)
+       } else if c.Type() == instancetype.Container {
+               // Initialize storage interface for the container.
+               err = c.initStorage()
                if err != nil {
-                       logger.Error("Failed renaming container", ctxMap)
                        return err
                }
-       } else {
-               err := c.storage.ContainerRename(c, newName)
-               if err != nil {
-                       logger.Error("Failed renaming container", ctxMap)
-                       return err
+
+               // Rename the storage entry.
+               if c.IsSnapshot() {
+                       err := c.storage.ContainerSnapshotRename(c, newName)
+                       if err != nil {
+                               logger.Error("Failed renaming container", 
ctxMap)
+                               return err
+                       }
+               } else {
+                       err := c.storage.ContainerRename(c, newName)
+                       if err != nil {
+                               logger.Error("Failed renaming container", 
ctxMap)
+                               return err
+                       }
                }
-       }
 
-       // Rename the backups
-       backups, err := c.Backups()
-       if err != nil {
-               return err
-       }
+               poolID, _, _ := c.storage.GetContainerPoolInfo()
 
-       for _, backup := range backups {
-               backupName := strings.Split(backup.Name(), "/")[1]
-               newName := fmt.Sprintf("%s/%s", newName, backupName)
+               if !c.IsSnapshot() {
+                       // Rename all the snapshot volumes.
+                       results, err := 
c.state.Cluster.ContainerGetSnapshots(c.project, oldName)
+                       if err != nil {
+                               logger.Error("Failed to get container 
snapshots", ctxMap)
+                               return err
+                       }
 
-               err = backup.Rename(newName)
+                       for _, sname := range results {
+                               // Rename the snapshot volume.
+                               baseSnapName := filepath.Base(sname)
+                               newSnapshotName := newName + 
shared.SnapshotDelimiter + baseSnapName
+
+                               // Rename storage volume for the snapshot.
+                               err = 
c.state.Cluster.StoragePoolVolumeRename(c.project, sname, newSnapshotName, 
storagePoolVolumeTypeContainer, poolID)
+                               if err != nil {
+                                       logger.Error("Failed renaming storage 
volume", ctxMap)
+                                       return err
+                               }
+                       }
+               }
+
+               // Rename storage volume for the container.
+               err = c.state.Cluster.StoragePoolVolumeRename(c.project, 
oldName, newName, storagePoolVolumeTypeContainer, poolID)
                if err != nil {
+                       logger.Error("Failed renaming storage volume", ctxMap)
                        return err
                }
-       }
 
-       poolID, _, _ := c.storage.GetContainerPoolInfo()
+               // Update the storage volume name in the storage interface.
+               sNew := c.storage.GetStoragePoolVolumeWritable()
+               c.storage.SetStoragePoolVolumeWritable(&sNew)
+       } else {
+               return fmt.Errorf("Instance type not supported")
+       }
 
        if !c.IsSnapshot() {
-               // Rename all the snapshots
+               // Rename all the instance snapshot database entries.
                results, err := 
c.state.Cluster.ContainerGetSnapshots(c.project, oldName)
                if err != nil {
                        logger.Error("Failed to get container snapshots", 
ctxMap)
@@ -3814,10 +3835,9 @@ func (c *containerLXC) Rename(newName string) error {
                }
 
                for _, sname := range results {
-                       // Rename the snapshot
+                       // Rename the snapshot.
                        oldSnapName := strings.SplitN(sname, 
shared.SnapshotDelimiter, 2)[1]
                        baseSnapName := filepath.Base(sname)
-                       newSnapshotName := newName + shared.SnapshotDelimiter + 
baseSnapName
                        err := c.state.Cluster.Transaction(func(tx 
*db.ClusterTx) error {
                                return tx.InstanceSnapshotRename(c.project, 
oldName, oldSnapName, baseSnapName)
                        })
@@ -3825,46 +3845,62 @@ func (c *containerLXC) Rename(newName string) error {
                                logger.Error("Failed renaming snapshot", ctxMap)
                                return err
                        }
-
-                       // Rename storage volume for the snapshot.
-                       err = 
c.state.Cluster.StoragePoolVolumeRename(c.project, sname, newSnapshotName, 
storagePoolVolumeTypeContainer, poolID)
-                       if err != nil {
-                               logger.Error("Failed renaming storage volume", 
ctxMap)
-                               return err
-                       }
                }
        }
 
-       // Rename the database entry
+       // Rename the instance database entry.
        err = c.state.Cluster.Transaction(func(tx *db.ClusterTx) error {
                if c.IsSnapshot() {
                        oldParts := strings.SplitN(oldName, 
shared.SnapshotDelimiter, 2)
                        newParts := strings.SplitN(newName, 
shared.SnapshotDelimiter, 2)
                        return tx.InstanceSnapshotRename(c.project, 
oldParts[0], oldParts[1], newParts[1])
-               } else {
-                       return tx.InstanceRename(c.project, oldName, newName)
                }
+
+               return tx.InstanceRename(c.project, oldName, newName)
        })
        if err != nil {
                logger.Error("Failed renaming container", ctxMap)
                return err
        }
 
-       // Rename storage volume for the container.
-       err = c.state.Cluster.StoragePoolVolumeRename(c.project, oldName, 
newName, storagePoolVolumeTypeContainer, poolID)
+       // Rename the logging path.
+       os.RemoveAll(shared.LogPath(newName))
+       if shared.PathExists(c.LogPath()) {
+               err := os.Rename(c.LogPath(), shared.LogPath(newName))
+               if err != nil {
+                       logger.Error("Failed renaming container", ctxMap)
+                       return err
+               }
+       }
+
+       // Rename the MAAS entry.
+       if !c.IsSnapshot() {
+               err = c.maasRename(newName)
+               if err != nil {
+                       return err
+               }
+       }
+
+       // Rename the backups.
+       backups, err := c.Backups()
        if err != nil {
-               logger.Error("Failed renaming storage volume", ctxMap)
                return err
        }
 
-       // Set the new name in the struct
-       c.name = newName
+       for _, backup := range backups {
+               backupName := strings.Split(backup.Name(), "/")[1]
+               newName := fmt.Sprintf("%s/%s", newName, backupName)
+
+               err = backup.Rename(newName)
+               if err != nil {
+                       return err
+               }
+       }
 
-       // Update the storage volume name in the storage interface.
-       sNew := c.storage.GetStoragePoolVolumeWritable()
-       c.storage.SetStoragePoolVolumeWritable(&sNew)
+       // Set the new name in the struct.
+       c.name = newName
 
-       // Invalidate the go-lxc cache
+       // Invalidate the go-lxc cache.
        if c.c != nil {
                c.c.Release()
                c.c = nil
@@ -3872,7 +3908,7 @@ func (c *containerLXC) Rename(newName string) error {
 
        c.cConfig = false
 
-       // Update lease files
+       // Update lease files.
        networkUpdateStatic(c.state, "")
 
        logger.Info("Renamed container", ctxMap)

From a320cf54c259810895fa9c6acb5e3999b1c4603b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 5 Nov 2019 18:35:09 +0000
Subject: [PATCH 2/4] lxd/storage/backend/lxd: Reworks symlink functions

And makes some function comments use consistent terminology.

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/backend_lxd.go | 51 ++++++++++++++++++++++----------------
 1 file changed, 29 insertions(+), 22 deletions(-)

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 5600ec4c3a..c6cc9357ba 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -161,9 +161,12 @@ func (b *lxdBackend) Unmount() (bool, error) {
        return b.driver.Unmount()
 }
 
-// createInstanceSymlink creates a symlink in the instance directory to the 
instance's mount path.
-func (b *lxdBackend) createInstanceSymlink(inst Instance, mountPath string) 
error {
-       symlinkPath := inst.Path()
+// ensureInstanceSymlink creates a symlink in the instance directory to the 
instance's mount path
+// if doesn't exist already.
+func (b *lxdBackend) ensureInstanceSymlink(instanceType instancetype.Type, 
projectName, instanceName, mountPath string) error {
+       volStorageName := project.Prefix(projectName, instanceName)
+       symlinkPath := ContainerPath(volStorageName, false)
+
        if !shared.PathExists(symlinkPath) {
                err := os.Symlink(mountPath, symlinkPath)
                if err != nil {
@@ -175,8 +178,10 @@ func (b *lxdBackend) createInstanceSymlink(inst Instance, 
mountPath string) erro
 }
 
 // removeInstanceSymlink removes a symlink in the instance directory to the 
instance's mount path.
-func (b *lxdBackend) removeInstanceSymlink(inst Instance) error {
-       symlinkPath := inst.Path()
+func (b *lxdBackend) removeInstanceSymlink(instanceType instancetype.Type, 
projectName, instanceName string) error {
+       volStorageName := project.Prefix(projectName, instanceName)
+       symlinkPath := ContainerPath(volStorageName, false)
+
        if shared.PathExists(symlinkPath) {
                err := os.Remove(symlinkPath)
                if err != nil {
@@ -189,15 +194,16 @@ func (b *lxdBackend) removeInstanceSymlink(inst Instance) 
error {
 
 // ensureInstanceSnapshotSymlink creates a symlink in the snapshot directory 
to the instance's
 // snapshot path if doesn't exist already.
-func (b *lxdBackend) ensureInstanceSnapshotSymlink(inst Instance) error {
+func (b *lxdBackend) ensureInstanceSnapshotSymlink(instanceType 
instancetype.Type, projectName, instanceName string) error {
        // Check we can convert the instance to the volume type needed.
-       volType, err := InstanceTypeToVolumeType(inst.Type())
+       volType, err := InstanceTypeToVolumeType(instanceType)
        if err != nil {
                return err
        }
 
-       snapshotSymlink := shared.VarPath("snapshots", 
project.Prefix(inst.Project(), inst.Name()))
-       volStorageName := project.Prefix(inst.Project(), inst.Name())
+       parentName, _, _ := 
shared.ContainerGetParentAndSnapshotName(instanceName)
+       snapshotSymlink := shared.VarPath("snapshots", 
project.Prefix(projectName, parentName))
+       volStorageName := project.Prefix(projectName, parentName)
 
        snapshotTargetPath, err := drivers.GetVolumeSnapshotDir(b.name, 
volType, volStorageName)
        if err != nil {
@@ -217,15 +223,16 @@ func (b *lxdBackend) ensureInstanceSnapshotSymlink(inst 
Instance) error {
 // removeInstanceSnapshotSymlinkIfUnused removes the symlink in the snapshot 
directory to the
 // instance's snapshot path if the snapshot path is missing. It is expected 
that the driver will
 // remove the instance's snapshot path after the last snapshot is removed or 
the volume is deleted.
-func (b *lxdBackend) removeInstanceSnapshotSymlinkIfUnused(inst Instance) 
error {
+func (b *lxdBackend) removeInstanceSnapshotSymlinkIfUnused(instanceType 
instancetype.Type, projectName, instanceName string) error {
        // Check we can convert the instance to the volume type needed.
-       volType, err := InstanceTypeToVolumeType(inst.Type())
+       volType, err := InstanceTypeToVolumeType(instanceType)
        if err != nil {
                return err
        }
 
-       snapshotSymlink := shared.VarPath("snapshots", 
project.Prefix(inst.Project(), inst.Name()))
-       volStorageName := project.Prefix(inst.Project(), inst.Name())
+       parentName, _, _ := 
shared.ContainerGetParentAndSnapshotName(instanceName)
+       snapshotSymlink := shared.VarPath("snapshots", 
project.Prefix(projectName, parentName))
+       volStorageName := project.Prefix(projectName, parentName)
 
        snapshotTargetPath, err := drivers.GetVolumeSnapshotDir(b.name, 
volType, volStorageName)
        if err != nil {
@@ -270,7 +277,7 @@ func (b *lxdBackend) CreateInstance(inst Instance, op 
*operations.Operation) err
                return err
        }
 
-       err = b.createInstanceSymlink(inst, vol.MountPath())
+       err = b.ensureInstanceSymlink(inst.Type(), inst.Project(), inst.Name(), 
vol.MountPath())
        if err != nil {
                return err
        }
@@ -356,7 +363,7 @@ func (b *lxdBackend) CreateInstanceFromImage(inst Instance, 
fingerprint string,
                }
        }
 
-       err = b.createInstanceSymlink(inst, vol.MountPath())
+       err = b.ensureInstanceSymlink(inst.Type(), inst.Project(), inst.Name(), 
vol.MountPath())
        if err != nil {
                return err
        }
@@ -422,12 +429,12 @@ func (b *lxdBackend) DeleteInstance(inst Instance, op 
*operations.Operation) err
        }
 
        // Remove symlinks.
-       err = b.removeInstanceSymlink(inst)
+       err = b.removeInstanceSymlink(inst.Type(), inst.Project(), inst.Name())
        if err != nil {
                return err
        }
 
-       err = b.removeInstanceSnapshotSymlinkIfUnused(inst)
+       err = b.removeInstanceSnapshotSymlinkIfUnused(inst.Type(), 
inst.Project(), inst.Name())
        if err != nil {
                return err
        }
@@ -453,7 +460,7 @@ func (b *lxdBackend) BackupInstance(inst Instance, 
targetPath string, optimized
        return ErrNotImplemented
 }
 
-// GetInstanceUsage returns the disk usage of the instance's root device.
+// GetInstanceUsage returns the disk usage of the instance's root volume.
 func (b *lxdBackend) GetInstanceUsage(inst Instance) (int64, error) {
        logger := logging.AddContext(b.logger, log.Ctx{"project": 
inst.Project(), "instance": inst.Name()})
        logger.Debug("GetInstanceUsage started")
@@ -466,7 +473,7 @@ func (b *lxdBackend) GetInstanceUsage(inst Instance) 
(int64, error) {
        return -1, ErrNotImplemented
 }
 
-// SetInstanceQuota sets the quota on the instance's root device.
+// SetInstanceQuota sets the quota on the instance's root volume.
 // Returns ErrRunningQuotaResizeNotSupported if the instance is running and 
the storage driver
 // doesn't support resizing whilst the instance is running.
 func (b *lxdBackend) SetInstanceQuota(inst Instance, size string, op 
*operations.Operation) error {
@@ -490,7 +497,7 @@ func (b *lxdBackend) SetInstanceQuota(inst Instance, size 
string, op *operations
        return b.driver.SetVolumeQuota(volType, volStorageName, size, op)
 }
 
-// MountInstance mounts the instance's device.
+// MountInstance mounts the instance's root volume.
 func (b *lxdBackend) MountInstance(inst Instance, op *operations.Operation) 
(bool, error) {
        logger := logging.AddContext(b.logger, log.Ctx{"project": 
inst.Project(), "instance": inst.Name()})
        logger.Debug("MountInstance started")
@@ -508,7 +515,7 @@ func (b *lxdBackend) MountInstance(inst Instance, op 
*operations.Operation) (boo
        return b.driver.MountVolume(volType, volStorageName, op)
 }
 
-// UnmountInstance unmounts the instance's device.
+// UnmountInstance unmounts the instance's root volume.
 func (b *lxdBackend) UnmountInstance(inst Instance, op *operations.Operation) 
(bool, error) {
        logger := logging.AddContext(b.logger, log.Ctx{"project": 
inst.Project(), "instance": inst.Name()})
        logger.Debug("UnmountInstance started")
@@ -572,7 +579,7 @@ func (b *lxdBackend) DeleteInstanceSnapshot(inst Instance, 
op *operations.Operat
        }
 
        // Delete symlink if needed.
-       err = b.removeInstanceSnapshotSymlinkIfUnused(inst)
+       err = b.removeInstanceSnapshotSymlinkIfUnused(inst.Type(), 
inst.Project(), inst.Name())
        if err != nil {
                return err
        }

From ef53b0136800acac3b5cd01a423700c64b2db959 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 5 Nov 2019 18:35:44 +0000
Subject: [PATCH 3/4] lxd/storage/backend/lxd: RenameInstance

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/backend_lxd.go | 103 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 102 insertions(+), 1 deletion(-)

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index c6cc9357ba..2fa6448e11 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -381,8 +381,109 @@ func (b *lxdBackend) CreateInstanceFromMigration(inst 
Instance, conn io.ReadWrit
        return ErrNotImplemented
 }
 
+// RenameInstance renames the instance's root volume and any snapshot volumes.
 func (b *lxdBackend) RenameInstance(inst Instance, newName string, op 
*operations.Operation) error {
-       return ErrNotImplemented
+       logger := logging.AddContext(b.logger, log.Ctx{"project": 
inst.Project(), "instance": inst.Name(), "newName": newName})
+       logger.Debug("RenameInstance started")
+       defer logger.Debug("RenameInstance finished")
+
+       if inst.IsSnapshot() {
+               return fmt.Errorf("Instance cannot be a snapshot")
+       }
+
+       if shared.IsSnapshot(newName) {
+               return fmt.Errorf("New volume name cannot be a snapshot")
+       }
+
+       // Check we can convert the instance to the volume types needed.
+       volType, err := InstanceTypeToVolumeType(inst.Type())
+       if err != nil {
+               return err
+       }
+
+       volDBType, err := VolumeTypeToDBType(volType)
+       if err != nil {
+               return err
+       }
+
+       type volRevert struct {
+               oldName string
+               newName string
+       }
+
+       // Create slice to record DB volumes renamed if revert needed later.
+       revertDBVolumes := []volRevert{}
+       defer func() {
+               // Remove any DB volume rows created if we are reverting.
+               for _, vol := range revertDBVolumes {
+                       b.state.Cluster.StoragePoolVolumeRename(inst.Project(), 
vol.newName, vol.oldName, volDBType, b.ID())
+               }
+       }()
+
+       // Get any snapshots the instance has in the format <instance 
name>/<snapshot name>.
+       snapshots, err := b.state.Cluster.ContainerGetSnapshots(inst.Project(), 
inst.Name())
+       if err != nil {
+               return err
+       }
+
+       // Rename each snapshot DB record to have the new parent volume prefix.
+       for _, srcSnapshot := range snapshots {
+               _, snapName, _ := 
shared.ContainerGetParentAndSnapshotName(srcSnapshot)
+               newSnapVolName := drivers.GetSnapshotVolumeName(newName, 
snapName)
+               err = b.state.Cluster.StoragePoolVolumeRename(inst.Project(), 
srcSnapshot, newSnapVolName, volDBType, b.ID())
+               if err != nil {
+                       return err
+               }
+
+               revertDBVolumes = append(revertDBVolumes, volRevert{
+                       newName: newSnapVolName,
+                       oldName: srcSnapshot,
+               })
+       }
+
+       // Rename the parent volume DB record.
+       err = b.state.Cluster.StoragePoolVolumeRename(inst.Project(), 
inst.Name(), newName, volDBType, b.ID())
+       if err != nil {
+               return err
+       }
+
+       revertDBVolumes = append(revertDBVolumes, volRevert{
+               newName: newName,
+               oldName: inst.Name(),
+       })
+
+       // Rename the volume and its snapshots on the storage device.
+       err = b.driver.RenameVolume(volType, inst.Name(), newName, op)
+       if err != nil {
+               return err
+       }
+
+       // Remove old instance symlink and create new one.
+       err = b.removeInstanceSymlink(inst.Type(), inst.Project(), inst.Name())
+       if err != nil {
+               return err
+       }
+
+       err = b.ensureInstanceSymlink(inst.Type(), inst.Project(), newName, 
drivers.GetVolumeMountPath(b.name, volType, newName))
+       if err != nil {
+               return err
+       }
+
+       // Remove old instance snapshot symlink and create a new one if needed.
+       err = b.removeInstanceSnapshotSymlinkIfUnused(inst.Type(), 
inst.Project(), inst.Name())
+       if err != nil {
+               return err
+       }
+
+       if len(snapshots) > 0 {
+               err = b.ensureInstanceSnapshotSymlink(inst.Type(), 
inst.Project(), newName)
+               if err != nil {
+                       return err
+               }
+       }
+
+       revertDBVolumes = nil
+       return nil
 }
 
 // DeleteInstance removes the instance's root volume (all snapshots need to be 
removed first).

From 7514973b25ad2af56c45d3a5a08a94587dec34d3 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 5 Nov 2019 18:35:58 +0000
Subject: [PATCH 4/4] lxd/storage/interfaces: Removes unused Path function in
 Instance interface

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/interfaces.go | 1 -
 1 file changed, 1 deletion(-)

diff --git a/lxd/storage/interfaces.go b/lxd/storage/interfaces.go
index 398adc21eb..cc7d249a55 100644
--- a/lxd/storage/interfaces.go
+++ b/lxd/storage/interfaces.go
@@ -16,7 +16,6 @@ type Instance interface {
        Name() string
        Project() string
        Type() instancetype.Type
-       Path() string
 
        IsRunning() bool
        IsSnapshot() bool
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to