The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6184
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) === Adds `/1.0/instances*` endpoints with support for a `type` field that indicates instance type. Includes https://github.com/lxc/lxd/pull/6176
From 887f0c9307d9aadd2352eec4817e72c0e525ae43 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <t...@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 <t...@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 <t...@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 <t...@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 <t...@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 <t...@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 <t...@tomp.uk> Date: Tue, 10 Sep 2019 13:39:19 +0100 Subject: [PATCH 4/7] api: Adds instances extension Signed-off-by: Thomas Parrott <t...@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 <t...@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 <t...@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 <t...@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 <t...@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 <t...@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 <t...@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,
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel