[lxc-devel] [lxd/master] API Instances

tomponline on Github lxc-bot at linuxcontainers.org
Tue Sep 10 14:42:23 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 444 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190910/3904ae6a/attachment-0001.bin>
-------------- next part --------------
From 887f0c9307d9aadd2352eec4817e72c0e525ae43 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <tomp at tomp.uk>
Date: Tue, 10 Sep 2019 10:35:15 +0100
Subject: [PATCH 1/7] lxd/db/containers: Removes ContainerType, CTypeRegular
 and CTypeSnapshot

Signed-off-by: Thomas Parrott <tomp at tomp.uk>
---
 lxd/db/containers.go | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/lxd/db/containers.go b/lxd/db/containers.go
index 7bd85e7b88..9bd3bdbb05 100644
--- a/lxd/db/containers.go
+++ b/lxd/db/containers.go
@@ -157,15 +157,6 @@ type ContainerBackupArgs struct {
 	OptimizedStorage bool
 }
 
-// ContainerType encodes the type of container (either regular or snapshot).
-type ContainerType int
-
-// Numerical codes for container types.
-const (
-	CTypeRegular  ContainerType = 0
-	CTypeSnapshot ContainerType = 1
-)
-
 // ContainerNames returns the names of all containers the given project.
 func (c *ClusterTx) ContainerNames(project string) ([]string, error) {
 	stmt := `

From f2e957502a2e5a091916e6c9d8b5ad2b32694114 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <tomp at tomp.uk>
Date: Tue, 10 Sep 2019 11:20:07 +0100
Subject: [PATCH 2/7] lxd: Replaces CType with instance.Type

- Adds dbType and snapshot to containerLXC
- Adds Type and Snapshot to ContainerArgs

Signed-off-by: Thomas Parrott <tomp at tomp.uk>
---
 lxd/api_internal.go          |  6 ++++--
 lxd/container.go             | 17 ++++++++++-------
 lxd/container_lxc.go         | 17 ++++++++++++-----
 lxd/container_snapshot.go    |  5 ++++-
 lxd/container_state.go       |  2 ++
 lxd/containers_post.go       |  9 +++++----
 lxd/db/containers.go         | 34 +++++++++++++++++++---------------
 lxd/db/snapshots.go          |  3 ++-
 lxd/logging.go               |  3 ++-
 lxd/main_activateifneeded.go |  3 ++-
 lxd/patches.go               |  8 ++------
 lxd/profiles_utils.go        |  2 ++
 lxd/storage_lvm_utils.go     |  3 ++-
 lxd/storage_migration.go     |  4 +++-
 lxd/storage_volumes_utils.go |  2 ++
 15 files changed, 73 insertions(+), 45 deletions(-)

diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index 1f48eda280..588f75e05a 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -22,6 +22,7 @@ import (
 	"github.com/lxc/lxd/lxd/db/node"
 	"github.com/lxc/lxd/lxd/db/query"
 	deviceConfig "github.com/lxc/lxd/lxd/device/config"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/project"
 	driver "github.com/lxc/lxd/lxd/storage"
 	"github.com/lxc/lxd/shared"
@@ -905,7 +906,7 @@ func internalImport(d *Daemon, r *http.Request) Response {
 		BaseImage:    baseImage,
 		Config:       backup.Container.Config,
 		CreationDate: backup.Container.CreatedAt,
-		Ctype:        db.CTypeRegular,
+		Type:         instance.TypeContainer,
 		Description:  backup.Container.Description,
 		Devices:      deviceConfig.NewDevices(backup.Container.Devices),
 		Ephemeral:    backup.Container.Ephemeral,
@@ -1011,7 +1012,8 @@ func internalImport(d *Daemon, r *http.Request) Response {
 			BaseImage:    baseImage,
 			Config:       snap.Config,
 			CreationDate: snap.CreatedAt,
-			Ctype:        db.CTypeSnapshot,
+			Type:         instance.TypeContainer,
+			Snapshot:     true,
 			Devices:      deviceConfig.NewDevices(snap.Devices),
 			Ephemeral:    snap.Ephemeral,
 			LastUsedDate: snap.LastUsedAt,
diff --git a/lxd/container.go b/lxd/container.go
index 666e0a8fe9..a6a04c3837 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -608,7 +608,8 @@ func containerCreateAsCopy(s *state.State, args db.ContainerArgs, sourceContaine
 			csArgs := db.ContainerArgs{
 				Architecture: snap.Architecture(),
 				Config:       snap.LocalConfig(),
-				Ctype:        db.CTypeSnapshot,
+				Type:         sourceContainer.Type(),
+				Snapshot:     true,
 				Devices:      snapDevices,
 				Description:  snap.Description(),
 				Ephemeral:    snap.IsEphemeral(),
@@ -799,8 +800,8 @@ func containerCreateInternal(s *state.State, args db.ContainerArgs) (container,
 		args.Architecture = s.OS.Architectures[0]
 	}
 
-	// Validate container name
-	if args.Ctype == db.CTypeRegular {
+	// Validate container name if not snapshot (as snapshots use disallowed / char in names).
+	if !args.Snapshot {
 		err := containerValidName(args.Name)
 		if err != nil {
 			return nil, err
@@ -876,7 +877,7 @@ func containerCreateInternal(s *state.State, args db.ContainerArgs) (container,
 			return fmt.Errorf("Project %q does not exist", args.Project)
 		}
 
-		if args.Ctype == db.CTypeSnapshot {
+		if args.Snapshot {
 			parts := strings.SplitN(args.Name, shared.SnapshotDelimiter, 2)
 			instanceName := parts[0]
 			snapshotName := parts[1]
@@ -916,7 +917,8 @@ func containerCreateInternal(s *state.State, args db.ContainerArgs) (container,
 			Project:      args.Project,
 			Name:         args.Name,
 			Node:         node,
-			Type:         int(args.Ctype),
+			Type:         args.Type,
+			Snapshot:     args.Snapshot,
 			Architecture: args.Architecture,
 			Ephemeral:    args.Ephemeral,
 			CreationDate: args.CreationDate,
@@ -1082,7 +1084,7 @@ func containerLoadByProject(s *state.State, project string) ([]container, error)
 	err := s.Cluster.Transaction(func(tx *db.ClusterTx) error {
 		filter := db.InstanceFilter{
 			Project: project,
-			Type:    int(db.CTypeRegular),
+			Type:    instance.TypeContainer,
 		}
 		var err error
 		cts, err = tx.InstanceList(filter)
@@ -1385,7 +1387,8 @@ func autoCreateContainerSnapshots(ctx context.Context, d *Daemon, containers []c
 			args := db.ContainerArgs{
 				Architecture: c.Architecture(),
 				Config:       c.LocalConfig(),
-				Ctype:        db.CTypeSnapshot,
+				Type:         c.Type(),
+				Snapshot:     true,
 				Devices:      c.LocalDevices(),
 				Ephemeral:    c.IsEphemeral(),
 				Name:         snapshotName,
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 6ab80d9dcc..f0fdd9c791 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -328,7 +328,8 @@ func containerLXCCreate(s *state.State, args db.ContainerArgs) (container, error
 		description:  args.Description,
 		ephemeral:    args.Ephemeral,
 		architecture: args.Architecture,
-		cType:        args.Ctype,
+		dbType:       args.Type,
+		snapshot:     args.Snapshot,
 		stateful:     args.Stateful,
 		creationDate: args.CreationDate,
 		lastUsedDate: args.LastUsedDate,
@@ -562,7 +563,8 @@ func containerLXCInstantiate(s *state.State, args db.ContainerArgs) *containerLX
 		description:  args.Description,
 		ephemeral:    args.Ephemeral,
 		architecture: args.Architecture,
-		cType:        args.Ctype,
+		dbType:       args.Type,
+		snapshot:     args.Snapshot,
 		creationDate: args.CreationDate,
 		lastUsedDate: args.LastUsedDate,
 		profiles:     args.Profiles,
@@ -593,7 +595,8 @@ func containerLXCInstantiate(s *state.State, args db.ContainerArgs) *containerLX
 type containerLXC struct {
 	// Properties
 	architecture int
-	cType        db.ContainerType
+	dbType       instance.Type
+	snapshot     bool
 	creationDate time.Time
 	lastUsedDate time.Time
 	ephemeral    bool
@@ -631,7 +634,7 @@ type containerLXC struct {
 }
 
 func (c *containerLXC) Type() instance.Type {
-	return instance.TypeContainer
+	return c.dbType
 }
 
 func (c *containerLXC) createOperation(action string, reusable bool, reuse bool) (*lxcContainerOperation, error) {
@@ -3434,6 +3437,8 @@ func (c *containerLXC) Restore(sourceContainer container, stateful bool) error {
 				Ephemeral:    false,
 				Profiles:     c.Profiles(),
 				Project:      c.Project(),
+				Type:         c.Type(),
+				Snapshot:     c.IsSnapshot(),
 			}
 
 			err := c.Update(args, false)
@@ -3490,6 +3495,8 @@ func (c *containerLXC) Restore(sourceContainer container, stateful bool) error {
 		Ephemeral:    sourceContainer.IsEphemeral(),
 		Profiles:     sourceContainer.Profiles(),
 		Project:      sourceContainer.Project(),
+		Type:         sourceContainer.Type(),
+		Snapshot:     sourceContainer.IsSnapshot(),
 	}
 
 	err = c.Update(args, false)
@@ -6681,7 +6688,7 @@ func (c *containerLXC) IsRunning() bool {
 }
 
 func (c *containerLXC) IsSnapshot() bool {
-	return c.cType == db.CTypeSnapshot
+	return c.snapshot
 }
 
 // Various property query functions
diff --git a/lxd/container_snapshot.go b/lxd/container_snapshot.go
index 851d23c2d9..67fe2e71d4 100644
--- a/lxd/container_snapshot.go
+++ b/lxd/container_snapshot.go
@@ -140,7 +140,8 @@ func containerSnapshotsPost(d *Daemon, r *http.Request) Response {
 			Project:      c.Project(),
 			Architecture: c.Architecture(),
 			Config:       c.LocalConfig(),
-			Ctype:        db.CTypeSnapshot,
+			Type:         c.Type(),
+			Snapshot:     true,
 			Devices:      c.LocalDevices(),
 			Ephemeral:    c.IsEphemeral(),
 			Name:         fullName,
@@ -255,6 +256,8 @@ func snapshotPut(d *Daemon, r *http.Request, sc container, name string) Response
 				Profiles:     sc.Profiles(),
 				Project:      sc.Project(),
 				ExpiryDate:   configRaw.ExpiresAt,
+				Type:         sc.Type(),
+				Snapshot:     sc.IsSnapshot(),
 			}
 
 			err = sc.Update(args, false)
diff --git a/lxd/container_state.go b/lxd/container_state.go
index 77ced1182b..8b86a0a362 100644
--- a/lxd/container_state.go
+++ b/lxd/container_state.go
@@ -137,6 +137,8 @@ func containerStatePut(d *Daemon, r *http.Request) Response {
 					Ephemeral:    false,
 					Profiles:     c.Profiles(),
 					Project:      c.Project(),
+					Type:         c.Type(),
+					Snapshot:     c.IsSnapshot(),
 				}
 
 				err := c.Update(args, false)
diff --git a/lxd/containers_post.go b/lxd/containers_post.go
index fc4a707ce2..106c1e3feb 100644
--- a/lxd/containers_post.go
+++ b/lxd/containers_post.go
@@ -20,6 +20,7 @@ import (
 	"github.com/lxc/lxd/lxd/cluster"
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/device/config"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
@@ -96,7 +97,7 @@ func createFromImage(d *Daemon, project string, req *api.ContainersPost) Respons
 		args := db.ContainerArgs{
 			Project:     project,
 			Config:      req.Config,
-			Ctype:       db.CTypeRegular,
+			Type:        instance.TypeContainer,
 			Description: req.Description,
 			Devices:     config.NewDevices(req.Devices),
 			Ephemeral:   req.Ephemeral,
@@ -152,7 +153,7 @@ func createFromNone(d *Daemon, project string, req *api.ContainersPost) Response
 	args := db.ContainerArgs{
 		Project:     project,
 		Config:      req.Config,
-		Ctype:       db.CTypeRegular,
+		Type:        instance.TypeContainer,
 		Description: req.Description,
 		Devices:     config.NewDevices(req.Devices),
 		Ephemeral:   req.Ephemeral,
@@ -209,7 +210,7 @@ func createFromMigration(d *Daemon, project string, req *api.ContainersPost) Res
 		Architecture: architecture,
 		BaseImage:    req.Source.BaseImage,
 		Config:       req.Config,
-		Ctype:        db.CTypeRegular,
+		Type:         instance.TypeContainer,
 		Devices:      config.NewDevices(req.Devices),
 		Description:  req.Description,
 		Ephemeral:    req.Ephemeral,
@@ -555,7 +556,7 @@ func createFromCopy(d *Daemon, project string, req *api.ContainersPost) Response
 		Architecture: source.Architecture(),
 		BaseImage:    req.Source.BaseImage,
 		Config:       req.Config,
-		Ctype:        db.CTypeRegular,
+		Type:         instance.TypeContainer,
 		Description:  req.Description,
 		Devices:      config.NewDevices(req.Devices),
 		Ephemeral:    req.Ephemeral,
diff --git a/lxd/db/containers.go b/lxd/db/containers.go
index 9bd3bdbb05..78822a0f7c 100644
--- a/lxd/db/containers.go
+++ b/lxd/db/containers.go
@@ -10,6 +10,7 @@ import (
 	"github.com/lxc/lxd/lxd/db/query"
 	"github.com/lxc/lxd/lxd/device/config"
 	deviceConfig "github.com/lxc/lxd/lxd/device/config"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
 	"github.com/lxc/lxd/shared/logger"
@@ -69,7 +70,8 @@ type Instance struct {
 	Project      string `db:"primary=yes&join=projects.name"`
 	Name         string `db:"primary=yes"`
 	Node         string `db:"join=nodes.name"`
-	Type         int
+	Type         instance.Type
+	Snapshot     bool
 	Architecture int
 	Ephemeral    bool
 	CreationDate time.Time
@@ -87,7 +89,7 @@ type InstanceFilter struct {
 	Project string
 	Name    string
 	Node    string
-	Type    int
+	Type    instance.Type
 }
 
 // ContainerToArgs is a convenience to convert the new Container db struct into
@@ -98,7 +100,8 @@ func ContainerToArgs(container *Instance) ContainerArgs {
 		Project:      container.Project,
 		Name:         container.Name,
 		Node:         container.Node,
-		Ctype:        ContainerType(container.Type),
+		Type:         container.Type,
+		Snapshot:     container.Snapshot,
 		Architecture: container.Architecture,
 		Ephemeral:    container.Ephemeral,
 		CreationDate: container.CreationDate,
@@ -122,9 +125,10 @@ func ContainerToArgs(container *Instance) ContainerArgs {
 // container.
 type ContainerArgs struct {
 	// Don't set manually
-	ID    int
-	Node  string
-	Ctype ContainerType
+	ID       int
+	Node     string
+	Type     instance.Type
+	Snapshot bool
 
 	// Creation only
 	Project      string
@@ -164,7 +168,7 @@ SELECT instances.name FROM instances
   JOIN projects ON projects.id = instances.project_id
   WHERE projects.name = ? AND instances.type = ?
 `
-	return query.SelectStrings(c.tx, stmt, project, CTypeRegular)
+	return query.SelectStrings(c.tx, stmt, project, instance.TypeContainer)
 }
 
 // ContainerNodeAddress returns the address of the node hosting the container
@@ -252,7 +256,7 @@ SELECT instances.name, nodes.id, nodes.address, nodes.heartbeat
     AND projects.name = ?
   ORDER BY instances.id
 `
-	rows, err := c.tx.Query(stmt, CTypeRegular, project)
+	rows, err := c.tx.Query(stmt, instance.TypeContainer, project)
 	if err != nil {
 		return nil, err
 	}
@@ -333,7 +337,7 @@ SELECT instances.name, nodes.name
   WHERE instances.type=?
     AND projects.name = ?
 `
-	rows, err := c.tx.Query(stmt, CTypeRegular, project)
+	rows, err := c.tx.Query(stmt, instance.TypeContainer, project)
 	if err != nil {
 		return nil, err
 	}
@@ -479,7 +483,7 @@ func (c *ClusterTx) ContainerNodeList() ([]Instance, error) {
 	}
 	filter := InstanceFilter{
 		Node: node,
-		Type: int(CTypeRegular),
+		Type: instance.TypeContainer,
 	}
 
 	return c.InstanceList(filter)
@@ -494,7 +498,7 @@ func (c *ClusterTx) ContainerNodeProjectList(project string) ([]Instance, error)
 	filter := InstanceFilter{
 		Project: project,
 		Node:    node,
-		Type:    int(CTypeRegular),
+		Type:    instance.TypeContainer,
 	}
 
 	return c.InstanceList(filter)
@@ -786,7 +790,7 @@ func (c *Cluster) ContainerConfig(id int) (map[string]string, error) {
 // use it for new code.
 func (c *Cluster) LegacyContainersList() ([]string, error) {
 	q := fmt.Sprintf("SELECT name FROM instances WHERE type=? ORDER BY name")
-	inargs := []interface{}{CTypeRegular}
+	inargs := []interface{}{instance.TypeContainer}
 	var container string
 	outfmt := []interface{}{container}
 	result, err := queryScan(c.db, q, inargs, outfmt)
@@ -813,7 +817,7 @@ FROM instances_snapshots
 JOIN instances ON instances.id = instances_snapshots.instance_id
 WHERE type=? ORDER BY instances.name, instances_snapshots.name
 `)
-	inargs := []interface{}{CTypeRegular}
+	inargs := []interface{}{instance.TypeContainer}
 	var container string
 	var snapshot string
 	outfmt := []interface{}{container, snapshot}
@@ -832,9 +836,9 @@ WHERE type=? ORDER BY instances.name, instances_snapshots.name
 
 // ContainersNodeList returns the names of all the containers of the given type
 // running on the local node.
-func (c *Cluster) ContainersNodeList(cType ContainerType) ([]string, error) {
+func (c *Cluster) ContainersNodeList(instanceType instance.Type) ([]string, error) {
 	q := fmt.Sprintf("SELECT name FROM instances WHERE type=? AND node_id=? ORDER BY name")
-	inargs := []interface{}{cType, c.nodeID}
+	inargs := []interface{}{instanceType, c.nodeID}
 	var container string
 	outfmt := []interface{}{container}
 	result, err := queryScan(c.db, q, inargs, outfmt)
diff --git a/lxd/db/snapshots.go b/lxd/db/snapshots.go
index 5c48106218..284bf8837c 100644
--- a/lxd/db/snapshots.go
+++ b/lxd/db/snapshots.go
@@ -69,7 +69,8 @@ func InstanceSnapshotToInstance(instance *Instance, snapshot *InstanceSnapshot)
 		Project:      snapshot.Project,
 		Name:         instance.Name + shared.SnapshotDelimiter + snapshot.Name,
 		Node:         instance.Node,
-		Type:         int(CTypeSnapshot),
+		Type:         instance.Type,
+		Snapshot:     true,
 		Architecture: instance.Architecture,
 		Ephemeral:    false,
 		CreationDate: snapshot.CreationDate,
diff --git a/lxd/logging.go b/lxd/logging.go
index e46bad2509..162ad51a3d 100644
--- a/lxd/logging.go
+++ b/lxd/logging.go
@@ -7,6 +7,7 @@ import (
 	"time"
 
 	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/lxd/task"
 	"github.com/lxc/lxd/shared"
@@ -52,7 +53,7 @@ func expireLogs(ctx context.Context, state *state.State) error {
 	var containers []string
 	ch := make(chan struct{})
 	go func() {
-		containers, err = state.Cluster.ContainersNodeList(db.CTypeRegular)
+		containers, err = state.Cluster.ContainersNodeList(instance.TypeContainer)
 		ch <- struct{}{}
 	}()
 	select {
diff --git a/lxd/main_activateifneeded.go b/lxd/main_activateifneeded.go
index 686a3df4fc..16196ef827 100644
--- a/lxd/main_activateifneeded.go
+++ b/lxd/main_activateifneeded.go
@@ -10,6 +10,7 @@ import (
 
 	lxd "github.com/lxc/lxd/client"
 	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/node"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/idmap"
@@ -111,7 +112,7 @@ func (c *cmdActivateifneeded) Run(cmd *cobra.Command, args []string) error {
 
 	var containers []db.Instance
 	err = d.cluster.Transaction(func(tx *db.ClusterTx) error {
-		filter := db.InstanceFilter{Type: int(db.CTypeRegular)}
+		filter := db.InstanceFilter{Type: instance.TypeContainer}
 		var err error
 		containers, err = tx.InstanceList(filter)
 		return err
diff --git a/lxd/patches.go b/lxd/patches.go
index e0606d63c6..5d9ff5119e 100644
--- a/lxd/patches.go
+++ b/lxd/patches.go
@@ -1889,12 +1889,8 @@ func updatePoolPropertyForAllObjects(d *Daemon, poolName string, allcontainers [
 			Description:  c.Description(),
 			Ephemeral:    c.IsEphemeral(),
 			Profiles:     c.Profiles(),
-		}
-
-		if c.IsSnapshot() {
-			args.Ctype = db.CTypeSnapshot
-		} else {
-			args.Ctype = db.CTypeRegular
+			Type:         c.Type(),
+			Snapshot:     c.IsSnapshot(),
 		}
 
 		// Check if the container already has a valid root device entry (profile or previous upgrade)
diff --git a/lxd/profiles_utils.go b/lxd/profiles_utils.go
index a271a04862..de2db4349b 100644
--- a/lxd/profiles_utils.go
+++ b/lxd/profiles_utils.go
@@ -219,6 +219,8 @@ func doProfileUpdateContainer(d *Daemon, name string, old api.ProfilePut, nodeNa
 		Ephemeral:    c.IsEphemeral(),
 		Profiles:     c.Profiles(),
 		Project:      c.Project(),
+		Type:         c.Type(),
+		Snapshot:     c.IsSnapshot(),
 	}, true)
 }
 
diff --git a/lxd/storage_lvm_utils.go b/lxd/storage_lvm_utils.go
index 3c88a36888..7ea61f13f2 100644
--- a/lxd/storage_lvm_utils.go
+++ b/lxd/storage_lvm_utils.go
@@ -11,6 +11,7 @@ import (
 	"github.com/pkg/errors"
 
 	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/state"
 	driver "github.com/lxc/lxd/lxd/storage"
@@ -721,7 +722,7 @@ func storageLVMThinpoolExists(vgName string, poolName string) (bool, error) {
 func storageLVMGetThinPoolUsers(s *state.State) ([]string, error) {
 	results := []string{}
 
-	cNames, err := s.Cluster.ContainersNodeList(db.CTypeRegular)
+	cNames, err := s.Cluster.ContainersNodeList(instance.TypeContainer)
 	if err != nil {
 		return results, err
 	}
diff --git a/lxd/storage_migration.go b/lxd/storage_migration.go
index b3cca61997..d3de32b69d 100644
--- a/lxd/storage_migration.go
+++ b/lxd/storage_migration.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/lxc/lxd/lxd/db"
 	deviceConfig "github.com/lxc/lxd/lxd/device/config"
+	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/migration"
 	"github.com/lxc/lxd/lxd/project"
 	driver "github.com/lxc/lxd/lxd/storage"
@@ -198,7 +199,8 @@ func snapshotProtobufToContainerArgs(project string, containerName string, snap
 	args := db.ContainerArgs{
 		Architecture: int(snap.GetArchitecture()),
 		Config:       config,
-		Ctype:        db.CTypeSnapshot,
+		Type:         instance.TypeContainer,
+		Snapshot:     true,
 		Devices:      devices,
 		Ephemeral:    snap.GetEphemeral(),
 		Name:         name,
diff --git a/lxd/storage_volumes_utils.go b/lxd/storage_volumes_utils.go
index 1face018c0..2c2f3d63d7 100644
--- a/lxd/storage_volumes_utils.go
+++ b/lxd/storage_volumes_utils.go
@@ -320,6 +320,8 @@ func storagePoolVolumeUpdateUsers(d *Daemon, oldPoolName string,
 			Ephemeral:    c.IsEphemeral(),
 			Profiles:     c.Profiles(),
 			Project:      c.Project(),
+			Type:         c.Type(),
+			Snapshot:     c.IsSnapshot(),
 		}
 
 		err = c.Update(args, false)

From 218cc36d6ab0f769e66e87e0970b3e7705673e89 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <tomp at tomp.uk>
Date: Tue, 10 Sep 2019 12:02:46 +0100
Subject: [PATCH 3/7] test: Switches to instance.Type

Signed-off-by: Thomas Parrott <tomp at tomp.uk>
---
 lxd/container_test.go     | 43 ++++++++++++++++++++-------------------
 lxd/db/containers_test.go | 20 ++++++++++--------
 lxd/db/snapshots_test.go  | 10 +++++----
 3 files changed, 39 insertions(+), 34 deletions(-)

diff --git a/lxd/container_test.go b/lxd/container_test.go
index 3982e1bd45..55f9fe3443 100644
--- a/lxd/container_test.go
+++ b/lxd/container_test.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/device/config"
+	"github.com/lxc/lxd/lxd/instance"
 	driver "github.com/lxc/lxd/lxd/storage"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
@@ -20,7 +21,7 @@ type containerTestSuite struct {
 
 func (suite *containerTestSuite) TestContainer_ProfilesDefault() {
 	args := db.ContainerArgs{
-		Ctype:     db.CTypeRegular,
+		Type:      instance.TypeContainer,
 		Ephemeral: false,
 		Name:      "testFoo",
 	}
@@ -62,7 +63,7 @@ func (suite *containerTestSuite) TestContainer_ProfilesMulti() {
 	}()
 
 	args := db.ContainerArgs{
-		Ctype:     db.CTypeRegular,
+		Type:      instance.TypeContainer,
 		Ephemeral: false,
 		Profiles:  []string{"default", "unprivileged"},
 		Name:      "testFoo",
@@ -85,7 +86,7 @@ func (suite *containerTestSuite) TestContainer_ProfilesMulti() {
 
 func (suite *containerTestSuite) TestContainer_ProfilesOverwriteDefaultNic() {
 	args := db.ContainerArgs{
-		Ctype:     db.CTypeRegular,
+		Type:      instance.TypeContainer,
 		Ephemeral: false,
 		Config:    map[string]string{"security.privileged": "true"},
 		Devices: config.Devices{
@@ -115,7 +116,7 @@ func (suite *containerTestSuite) TestContainer_ProfilesOverwriteDefaultNic() {
 
 func (suite *containerTestSuite) TestContainer_LoadFromDB() {
 	args := db.ContainerArgs{
-		Ctype:     db.CTypeRegular,
+		Type:      instance.TypeContainer,
 		Ephemeral: false,
 		Config:    map[string]string{"security.privileged": "true"},
 		Devices: config.Devices{
@@ -153,7 +154,7 @@ func (suite *containerTestSuite) TestContainer_LoadFromDB() {
 func (suite *containerTestSuite) TestContainer_Path_Regular() {
 	// Regular
 	args := db.ContainerArgs{
-		Ctype:     db.CTypeRegular,
+		Type:      instance.TypeContainer,
 		Ephemeral: false,
 		Name:      "testFoo",
 	}
@@ -169,7 +170,7 @@ func (suite *containerTestSuite) TestContainer_Path_Regular() {
 
 func (suite *containerTestSuite) TestContainer_LogPath() {
 	args := db.ContainerArgs{
-		Ctype:     db.CTypeRegular,
+		Type:      instance.TypeContainer,
 		Ephemeral: false,
 		Name:      "testFoo",
 	}
@@ -183,7 +184,7 @@ func (suite *containerTestSuite) TestContainer_LogPath() {
 
 func (suite *containerTestSuite) TestContainer_IsPrivileged_Privileged() {
 	args := db.ContainerArgs{
-		Ctype:     db.CTypeRegular,
+		Type:      instance.TypeContainer,
 		Ephemeral: false,
 		Config:    map[string]string{"security.privileged": "true"},
 		Name:      "testFoo",
@@ -198,7 +199,7 @@ func (suite *containerTestSuite) TestContainer_IsPrivileged_Privileged() {
 
 func (suite *containerTestSuite) TestContainer_IsPrivileged_Unprivileged() {
 	args := db.ContainerArgs{
-		Ctype:     db.CTypeRegular,
+		Type:      instance.TypeContainer,
 		Ephemeral: false,
 		Config:    map[string]string{"security.privileged": "false"},
 		Name:      "testFoo",
@@ -213,7 +214,7 @@ func (suite *containerTestSuite) TestContainer_IsPrivileged_Unprivileged() {
 
 func (suite *containerTestSuite) TestContainer_Rename() {
 	args := db.ContainerArgs{
-		Ctype:     db.CTypeRegular,
+		Type:      instance.TypeContainer,
 		Ephemeral: false,
 		Name:      "testFoo",
 	}
@@ -228,8 +229,8 @@ func (suite *containerTestSuite) TestContainer_Rename() {
 
 func (suite *containerTestSuite) TestContainer_findIdmap_isolated() {
 	c1, err := containerCreateInternal(suite.d.State(), db.ContainerArgs{
-		Ctype: db.CTypeRegular,
-		Name:  "isol-1",
+		Type: instance.TypeContainer,
+		Name: "isol-1",
 		Config: map[string]string{
 			"security.idmap.isolated": "true",
 		},
@@ -238,8 +239,8 @@ func (suite *containerTestSuite) TestContainer_findIdmap_isolated() {
 	defer c1.Delete()
 
 	c2, err := containerCreateInternal(suite.d.State(), db.ContainerArgs{
-		Ctype: db.CTypeRegular,
-		Name:  "isol-2",
+		Type: instance.TypeContainer,
+		Name: "isol-2",
 		Config: map[string]string{
 			"security.idmap.isolated": "true",
 		},
@@ -269,8 +270,8 @@ func (suite *containerTestSuite) TestContainer_findIdmap_isolated() {
 
 func (suite *containerTestSuite) TestContainer_findIdmap_mixed() {
 	c1, err := containerCreateInternal(suite.d.State(), db.ContainerArgs{
-		Ctype: db.CTypeRegular,
-		Name:  "isol-1",
+		Type: instance.TypeContainer,
+		Name: "isol-1",
 		Config: map[string]string{
 			"security.idmap.isolated": "false",
 		},
@@ -279,8 +280,8 @@ func (suite *containerTestSuite) TestContainer_findIdmap_mixed() {
 	defer c1.Delete()
 
 	c2, err := containerCreateInternal(suite.d.State(), db.ContainerArgs{
-		Ctype: db.CTypeRegular,
-		Name:  "isol-2",
+		Type: instance.TypeContainer,
+		Name: "isol-2",
 		Config: map[string]string{
 			"security.idmap.isolated": "true",
 		},
@@ -310,8 +311,8 @@ func (suite *containerTestSuite) TestContainer_findIdmap_mixed() {
 
 func (suite *containerTestSuite) TestContainer_findIdmap_raw() {
 	c1, err := containerCreateInternal(suite.d.State(), db.ContainerArgs{
-		Ctype: db.CTypeRegular,
-		Name:  "isol-1",
+		Type: instance.TypeContainer,
+		Name: "isol-1",
 		Config: map[string]string{
 			"security.idmap.isolated": "false",
 			"raw.idmap":               "both 1000 1000",
@@ -349,8 +350,8 @@ func (suite *containerTestSuite) TestContainer_findIdmap_maxed() {
 
 	for i := 0; i < 7; i++ {
 		c, err := containerCreateInternal(suite.d.State(), db.ContainerArgs{
-			Ctype: db.CTypeRegular,
-			Name:  fmt.Sprintf("isol-%d", i),
+			Type: instance.TypeContainer,
+			Name: fmt.Sprintf("isol-%d", i),
 			Config: map[string]string{
 				"security.idmap.isolated": "true",
 			},
diff --git a/lxd/db/containers_test.go b/lxd/db/containers_test.go
index 8a0cd545cc..bc2adf4fa8 100644
--- a/lxd/db/containers_test.go
+++ b/lxd/db/containers_test.go
@@ -4,10 +4,12 @@ import (
 	"testing"
 	"time"
 
-	"github.com/lxc/lxd/lxd/db"
-	"github.com/lxc/lxd/shared/api"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
+
+	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/instance"
+	"github.com/lxc/lxd/shared/api"
 )
 
 func TestContainerList(t *testing.T) {
@@ -30,7 +32,7 @@ func TestContainerList(t *testing.T) {
 	addContainerDevice(t, tx, "c2", "eth0", "nic", nil)
 	addContainerDevice(t, tx, "c3", "root", "disk", map[string]string{"x": "y"})
 
-	filter := db.InstanceFilter{Type: int(db.CTypeRegular)}
+	filter := db.InstanceFilter{Type: instance.TypeContainer}
 	containers, err := tx.InstanceList(filter)
 	require.NoError(t, err)
 	assert.Len(t, containers, 3)
@@ -72,7 +74,7 @@ func TestContainerList_FilterByNode(t *testing.T) {
 	filter := db.InstanceFilter{
 		Project: "default",
 		Node:    "node2",
-		Type:    int(db.CTypeRegular),
+		Type:    instance.TypeContainer,
 	}
 
 	containers, err := tx.InstanceList(filter)
@@ -117,7 +119,7 @@ func TestInstanceList_ContainerWithSameNameInDifferentProjects(t *testing.T) {
 		Project:      "blah",
 		Name:         "c1",
 		Node:         "none",
-		Type:         int(db.CTypeRegular),
+		Type:         instance.TypeContainer,
 		Architecture: 1,
 		Ephemeral:    false,
 		Stateful:     true,
@@ -132,7 +134,7 @@ func TestInstanceList_ContainerWithSameNameInDifferentProjects(t *testing.T) {
 		Project:      "test",
 		Name:         "c1",
 		Node:         "none",
-		Type:         int(db.CTypeRegular),
+		Type:         instance.TypeContainer,
 		Architecture: 1,
 		Ephemeral:    false,
 		Stateful:     true,
@@ -171,7 +173,7 @@ func TestInstanceListExpanded(t *testing.T) {
 		Project:      "default",
 		Name:         "c1",
 		Node:         "none",
-		Type:         int(db.CTypeRegular),
+		Type:         instance.TypeContainer,
 		Architecture: 1,
 		Ephemeral:    false,
 		Stateful:     true,
@@ -396,7 +398,7 @@ func TestContainersNodeList(t *testing.T) {
 	})
 	require.NoError(t, err)
 
-	names, err := cluster.ContainersNodeList(db.CTypeRegular)
+	names, err := cluster.ContainersNodeList(instance.TypeContainer)
 	require.NoError(t, err)
 	assert.Equal(t, names, []string{"c1"})
 }
@@ -448,7 +450,7 @@ func addContainer(t *testing.T, tx *db.ClusterTx, nodeID int64, name string) {
 	stmt := `
 INSERT INTO instances(node_id, name, architecture, type, project_id) VALUES (?, ?, 1, ?, 1)
 `
-	_, err := tx.Tx().Exec(stmt, nodeID, name, db.CTypeRegular)
+	_, err := tx.Tx().Exec(stmt, nodeID, name, instance.TypeContainer)
 	require.NoError(t, err)
 }
 
diff --git a/lxd/db/snapshots_test.go b/lxd/db/snapshots_test.go
index dcc348552a..0ef5121170 100644
--- a/lxd/db/snapshots_test.go
+++ b/lxd/db/snapshots_test.go
@@ -4,10 +4,12 @@ import (
 	"testing"
 	"time"
 
-	"github.com/lxc/lxd/lxd/db"
-	"github.com/lxc/lxd/shared/api"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
+
+	"github.com/lxc/lxd/lxd/db"
+	"github.com/lxc/lxd/lxd/instance"
+	"github.com/lxc/lxd/shared/api"
 )
 
 func TestInstanceSnapshotList(t *testing.T) {
@@ -95,7 +97,7 @@ func TestInstanceSnapshotList_SameNameInDifferentProjects(t *testing.T) {
 		Project:      "default",
 		Name:         "i1",
 		Node:         "none",
-		Type:         int(db.CTypeRegular),
+		Type:         instance.TypeContainer,
 		Architecture: 1,
 		Ephemeral:    false,
 		Stateful:     true,
@@ -108,7 +110,7 @@ func TestInstanceSnapshotList_SameNameInDifferentProjects(t *testing.T) {
 		Project:      "p1",
 		Name:         "i1",
 		Node:         "none",
-		Type:         int(db.CTypeRegular),
+		Type:         instance.TypeContainer,
 		Architecture: 1,
 		Ephemeral:    false,
 		Stateful:     true,

From 9f1633a1f0e79e3d0c6348c8f67fefacd1aef3d0 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <tomp at tomp.uk>
Date: Tue, 10 Sep 2019 13:39:19 +0100
Subject: [PATCH 4/7] api: Adds instances extension

Signed-off-by: Thomas Parrott <tomp at tomp.uk>
---
 doc/api-extensions.md | 4 ++++
 shared/version/api.go | 1 +
 2 files changed, 5 insertions(+)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index dc4ef31970..2d2a5287ab 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -823,3 +823,7 @@ Export infiniband character device information (issm, umad, uverb) as part of th
 This introduces two new configuration keys `storage.images\_volume` and
 `storage.backups\_volume` to allow for a storage volume on an existing
 pool be used for storing the daemon-wide images and backups artifacts.
+
+## instances
+
+This introduces the concept of instances, of which currently the only type is "container".
diff --git a/shared/version/api.go b/shared/version/api.go
index 201e834828..dd9979868f 100644
--- a/shared/version/api.go
+++ b/shared/version/api.go
@@ -164,6 +164,7 @@ var APIExtensions = []string{
 	"storage_shifted",
 	"resources_infiniband",
 	"daemon_storage",
+	"instances",
 }
 
 // APIExtensionsCount returns the number of available API extensions.

From 00419228c31150386bf0d76bb0f80055b42f1897 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <tomp at tomp.uk>
Date: Tue, 10 Sep 2019 14:23:16 +0100
Subject: [PATCH 5/7] shared/api/container: Adds Type to Container and
 ContainersPost

- Defines instance type value for containers.

Signed-off-by: Thomas Parrott <tomp at tomp.uk>
---
 shared/api/container.go | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/shared/api/container.go b/shared/api/container.go
index ed41a6e61e..88ce8341ab 100644
--- a/shared/api/container.go
+++ b/shared/api/container.go
@@ -4,6 +4,9 @@ import (
 	"time"
 )
 
+// InstanceTypeContainer defines the instance type value for a container.
+const InstanceTypeContainer = "container"
+
 // ContainersPost represents the fields available for a new LXD container
 type ContainersPost struct {
 	ContainerPut `yaml:",inline"`
@@ -12,6 +15,9 @@ type ContainersPost struct {
 	Source ContainerSource `json:"source" yaml:"source"`
 
 	InstanceType string `json:"instance_type" yaml:"instance_type"`
+
+	// API extension: instances
+	Type string `json:"type" yaml:"type"`
 }
 
 // ContainerPost represents the fields required to rename/move a LXD container
@@ -73,6 +79,9 @@ type Container struct {
 
 	// API extension: clustering
 	Location string `json:"location" yaml:"location"`
+
+	// API extension: instances
+	Type string `json:"type" yaml:"type"`
 }
 
 // ContainerFull is a combination of Container, ContainerState and CotnainerSnapshot

From b465a1197441b0cc30b14a6fb4abcfbc06a3a59a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <tomp at tomp.uk>
Date: Tue, 10 Sep 2019 14:24:01 +0100
Subject: [PATCH 6/7] lxd/containers/post: Converts string instance type to
 internal representation

Defaults to container instance type if not supplied.

Signed-off-by: Thomas Parrott <tomp at tomp.uk>
---
 lxd/containers_post.go | 40 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 36 insertions(+), 4 deletions(-)

diff --git a/lxd/containers_post.go b/lxd/containers_post.go
index 106c1e3feb..afab34bec3 100644
--- a/lxd/containers_post.go
+++ b/lxd/containers_post.go
@@ -30,6 +30,18 @@ import (
 	"github.com/lxc/lxd/shared/osarch"
 )
 
+// instanceTypeToDBType validates the supplied string against the allowed types of instance and
+// returns the internal DB representation of that type. If empty string is supplied then the default
+// type returned is TypeContainer.
+func instanceTypeToDBType(arg string) (instance.Type, error) {
+	// If "container" or "" is supplied, return type as TypeContainer.
+	if arg == api.InstanceTypeContainer || arg == "" {
+		return instance.TypeContainer, nil
+	}
+
+	return -1, fmt.Errorf("Invalid instance type")
+}
+
 func createFromImage(d *Daemon, project string, req *api.ContainersPost) Response {
 	var hash string
 	var err error
@@ -93,11 +105,16 @@ func createFromImage(d *Daemon, project string, req *api.ContainersPost) Respons
 		return BadRequest(fmt.Errorf("Must specify one of alias, fingerprint or properties for init from image"))
 	}
 
+	dbType, err := instanceTypeToDBType(req.Type)
+	if err != nil {
+		return BadRequest(fmt.Errorf("Invalid instance type"))
+	}
+
 	run := func(op *operation) error {
 		args := db.ContainerArgs{
 			Project:     project,
 			Config:      req.Config,
-			Type:        instance.TypeContainer,
+			Type:        dbType,
 			Description: req.Description,
 			Devices:     config.NewDevices(req.Devices),
 			Ephemeral:   req.Ephemeral,
@@ -150,10 +167,15 @@ func createFromImage(d *Daemon, project string, req *api.ContainersPost) Respons
 }
 
 func createFromNone(d *Daemon, project string, req *api.ContainersPost) Response {
+	dbType, err := instanceTypeToDBType(req.Type)
+	if err != nil {
+		return BadRequest(fmt.Errorf("Invalid instance type"))
+	}
+
 	args := db.ContainerArgs{
 		Project:     project,
 		Config:      req.Config,
-		Type:        instance.TypeContainer,
+		Type:        dbType,
 		Description: req.Description,
 		Devices:     config.NewDevices(req.Devices),
 		Ephemeral:   req.Ephemeral,
@@ -204,13 +226,18 @@ func createFromMigration(d *Daemon, project string, req *api.ContainersPost) Res
 		req.Profiles = []string{"default"}
 	}
 
+	dbType, err := instanceTypeToDBType(req.Type)
+	if err != nil {
+		return BadRequest(fmt.Errorf("Invalid instance type"))
+	}
+
 	// Prepare the container creation request
 	args := db.ContainerArgs{
 		Project:      project,
 		Architecture: architecture,
 		BaseImage:    req.Source.BaseImage,
 		Config:       req.Config,
-		Type:         instance.TypeContainer,
+		Type:         dbType,
 		Devices:      config.NewDevices(req.Devices),
 		Description:  req.Description,
 		Ephemeral:    req.Ephemeral,
@@ -551,12 +578,17 @@ func createFromCopy(d *Daemon, project string, req *api.ContainersPost) Response
 		}
 	}
 
+	dbType, err := instanceTypeToDBType(req.Type)
+	if err != nil {
+		return BadRequest(fmt.Errorf("Invalid instance type"))
+	}
+
 	args := db.ContainerArgs{
 		Project:      targetProject,
 		Architecture: source.Architecture(),
 		BaseImage:    req.Source.BaseImage,
 		Config:       req.Config,
-		Type:         instance.TypeContainer,
+		Type:         dbType,
 		Description:  req.Description,
 		Devices:      config.NewDevices(req.Devices),
 		Ephemeral:    req.Ephemeral,

From 8eb83a9db53ae47077b12e5b973e080c541ab70b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <tomp at tomp.uk>
Date: Tue, 10 Sep 2019 15:31:42 +0100
Subject: [PATCH 7/7] lxd/api/internal: Set instance type from request data

Signed-off-by: Thomas Parrott <tomp at tomp.uk>
---
 lxd/api_internal.go | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index 588f75e05a..4a4b35acdd 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -22,7 +22,6 @@ import (
 	"github.com/lxc/lxd/lxd/db/node"
 	"github.com/lxc/lxd/lxd/db/query"
 	deviceConfig "github.com/lxc/lxd/lxd/device/config"
-	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/project"
 	driver "github.com/lxc/lxd/lxd/storage"
 	"github.com/lxc/lxd/shared"
@@ -900,13 +899,19 @@ func internalImport(d *Daemon, r *http.Request) Response {
 	if err != nil {
 		return SmartError(err)
 	}
+
+	dbType, err := instanceTypeToDBType(backup.Container.Type)
+	if err != nil {
+		return SmartError(fmt.Errorf("Invalid instance type"))
+	}
+
 	_, err = containerCreateInternal(d.State(), db.ContainerArgs{
 		Project:      projectName,
 		Architecture: arch,
 		BaseImage:    baseImage,
 		Config:       backup.Container.Config,
 		CreationDate: backup.Container.CreatedAt,
-		Type:         instance.TypeContainer,
+		Type:         dbType,
 		Description:  backup.Container.Description,
 		Devices:      deviceConfig.NewDevices(backup.Container.Devices),
 		Ephemeral:    backup.Container.Ephemeral,
@@ -1012,7 +1017,7 @@ func internalImport(d *Daemon, r *http.Request) Response {
 			BaseImage:    baseImage,
 			Config:       snap.Config,
 			CreationDate: snap.CreatedAt,
-			Type:         instance.TypeContainer,
+			Type:         dbType,
 			Snapshot:     true,
 			Devices:      deviceConfig.NewDevices(snap.Devices),
 			Ephemeral:    snap.Ephemeral,


More information about the lxc-devel mailing list