[lxc-devel] [lxd/master] Shared API Instances
tomponline on Github
lxc-bot at linuxcontainers.org
Wed Sep 11 12:52:56 UTC 2019
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 348 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190911/acf345a1/attachment-0001.bin>
-------------- next part --------------
From 62949ba5eaec705943bdeb0adc8183958763f618 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 11 Sep 2019 09:44:29 +0100
Subject: [PATCH 01/16] lxd/instance/instance: Adds functions to convert
to/from instance.Type and string
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/instance/instance.go | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/lxd/instance/instance.go b/lxd/instance/instance.go
index 10952e4821..bf15662dfc 100644
--- a/lxd/instance/instance.go
+++ b/lxd/instance/instance.go
@@ -1,5 +1,11 @@
package instance
+import (
+ "fmt"
+
+ "github.com/lxc/lxd/shared/api"
+)
+
// Type indicates the type of instance.
type Type int
@@ -9,3 +15,25 @@ const (
// TypeContainer represents a container instance type.
TypeContainer = Type(0)
)
+
+// New validates the supplied string against the allowed types of instance and returns the internal
+// representation of that type. If empty string is supplied then the type returned is TypeContainer.
+// If an invalid name is supplied an error will be returned.
+func New(name string) (Type, error) {
+ // If "container" or "" is supplied, return type as TypeContainer.
+ if name == api.InstanceTypeContainer || name == "" {
+ return TypeContainer, nil
+ }
+
+ return -1, fmt.Errorf("Invalid instance type")
+}
+
+// String converts the internal representation of instance type to a string used in API requests.
+// Returns empty string if value is not a valid instance type.
+func (instanceType Type) String() string {
+ if instanceType == TypeContainer {
+ return api.InstanceTypeContainer
+ }
+
+ return ""
+}
From e8a8d793f1480b63165c99f53096c96a2f4f2840 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 02/16] api: Adds instances extension
Signed-off-by: Thomas Parrott <tomp at tomp.uk>
---
doc/api-extensions.md | 3 +++
shared/version/api.go | 1 +
2 files changed, 4 insertions(+)
diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index dc4ef31970..e562f4a32e 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -823,3 +823,6 @@ 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 98965fcecc04b76a67c673bc9be50e1b4d78831d 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 03/16] 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 15a3c55747ae24de3eec16dfcf8514fb8f1928f5 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 04/16] lxd/containers/post: Converts from string instance type
and instance.Type
- Defaults to container instance type if not supplied during POST.
Signed-off-by: Thomas Parrott <tomp at tomp.uk>
---
lxd/containers_post.go | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/lxd/containers_post.go b/lxd/containers_post.go
index 106c1e3feb..b2c6fc6382 100644
--- a/lxd/containers_post.go
+++ b/lxd/containers_post.go
@@ -93,11 +93,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 := instance.New(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 +155,15 @@ func createFromImage(d *Daemon, project string, req *api.ContainersPost) Respons
}
func createFromNone(d *Daemon, project string, req *api.ContainersPost) Response {
+ dbType, err := instance.New(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 +214,18 @@ func createFromMigration(d *Daemon, project string, req *api.ContainersPost) Res
req.Profiles = []string{"default"}
}
+ dbType, err := instance.New(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 +566,17 @@ func createFromCopy(d *Daemon, project string, req *api.ContainersPost) Response
}
}
+ dbType, err := instance.New(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 ac2acfa788a7d5385045b53e01d2c63235d2585d 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 05/16] lxd/api/internal: Set instance type from request data
Signed-off-by: Thomas Parrott <tomp at tomp.uk>
---
lxd/api_internal.go | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index 588f75e05a..29d18c662b 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -900,13 +900,19 @@ func internalImport(d *Daemon, r *http.Request) Response {
if err != nil {
return SmartError(err)
}
+
+ dbType, err := instance.New(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 +1018,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,
From 28a32d75b3bc3a0e20ae2d8c964e44cced07d6ad Mon Sep 17 00:00:00 2001
From: Thomas Parrott <tomp at tomp.uk>
Date: Tue, 10 Sep 2019 17:15:54 +0100
Subject: [PATCH 06/16] lxd/db/instances/mapper: Updates InstanceList to use
instance.TypeAny
Signed-off-by: Thomas Parrott <tomp at tomp.uk>
---
lxd/db/instances.mapper.go | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/lxd/db/instances.mapper.go b/lxd/db/instances.mapper.go
index f5b9e5c9cf..74389ef9e7 100644
--- a/lxd/db/instances.mapper.go
+++ b/lxd/db/instances.mapper.go
@@ -5,10 +5,13 @@ package db
import (
"database/sql"
"fmt"
+
+ "github.com/pkg/errors"
+
"github.com/lxc/lxd/lxd/db/cluster"
"github.com/lxc/lxd/lxd/db/query"
+ "github.com/lxc/lxd/lxd/instance"
"github.com/lxc/lxd/shared/api"
- "github.com/pkg/errors"
)
var _ = api.ServerEnvironment{}
@@ -163,7 +166,7 @@ func (c *ClusterTx) InstanceList(filter InstanceFilter) ([]Instance, error) {
if filter.Node != "" {
criteria["Node"] = filter.Node
}
- if filter.Type != -1 {
+ if filter.Type != instance.TypeAny {
criteria["Type"] = filter.Type
}
From 43c03601dca2f100782ddeab9b037a09db1c3c50 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <tomp at tomp.uk>
Date: Tue, 10 Sep 2019 17:16:51 +0100
Subject: [PATCH 07/16] lxd/db/containers: Updates container filtering
functions to support instance.Type
Signed-off-by: Thomas Parrott <tomp at tomp.uk>
---
lxd/db/containers.go | 54 ++++++++++++++++++++++++++++++++------------
1 file changed, 40 insertions(+), 14 deletions(-)
diff --git a/lxd/db/containers.go b/lxd/db/containers.go
index 78822a0f7c..068da2532a 100644
--- a/lxd/db/containers.go
+++ b/lxd/db/containers.go
@@ -241,22 +241,35 @@ SELECT nodes.id, nodes.address
// string, to distinguish it from remote nodes.
//
// Containers whose node is down are addeded to the special address "0.0.0.0".
-func (c *ClusterTx) ContainersListByNodeAddress(project string) (map[string][]string, error) {
+func (c *ClusterTx) ContainersListByNodeAddress(project string, instanceType instance.Type) (map[string][]string, error) {
offlineThreshold, err := c.NodeOfflineThreshold()
if err != nil {
return nil, err
}
- stmt := `
+ args := make([]interface{}, 0, 2) // Expect up to 2 filters.
+ var filters strings.Builder
+
+ // Project filter.
+ filters.WriteString("projects.name = ?")
+ args = append(args, project)
+
+ // Instance type filter.
+ if instanceType != instance.TypeAny {
+ filters.WriteString(" AND instances.type = ?")
+ args = append(args, instanceType)
+ }
+
+ stmt := fmt.Sprintf(`
SELECT instances.name, nodes.id, nodes.address, nodes.heartbeat
FROM instances
JOIN nodes ON nodes.id = instances.node_id
JOIN projects ON projects.id = instances.project_id
- WHERE instances.type=?
- AND projects.name = ?
+ WHERE %s
ORDER BY instances.id
-`
- rows, err := c.tx.Query(stmt, instance.TypeContainer, project)
+`, filters.String())
+
+ rows, err := c.tx.Query(stmt, args...)
if err != nil {
return nil, err
}
@@ -328,16 +341,29 @@ func (c *ClusterTx) ContainerListExpanded() ([]Instance, error) {
// ContainersByNodeName returns a map associating each container to the name of
// its node.
-func (c *ClusterTx) ContainersByNodeName(project string) (map[string]string, error) {
- stmt := `
+func (c *ClusterTx) ContainersByNodeName(project string, instanceType instance.Type) (map[string]string, error) {
+ args := make([]interface{}, 0, 2) // Expect up to 2 filters.
+ var filters strings.Builder
+
+ // Project filter.
+ filters.WriteString("projects.name = ?")
+ args = append(args, project)
+
+ // Instance type filter.
+ if instanceType != instance.TypeAny {
+ filters.WriteString(" AND instances.type = ?")
+ args = append(args, instanceType)
+ }
+
+ stmt := fmt.Sprintf(`
SELECT instances.name, nodes.name
FROM instances
JOIN nodes ON nodes.id = instances.node_id
JOIN projects ON projects.id = instances.project_id
- WHERE instances.type=?
- AND projects.name = ?
-`
- rows, err := c.tx.Query(stmt, instance.TypeContainer, project)
+ WHERE %s
+`, filters.String())
+
+ rows, err := c.tx.Query(stmt, args...)
if err != nil {
return nil, err
}
@@ -490,7 +516,7 @@ func (c *ClusterTx) ContainerNodeList() ([]Instance, error) {
}
// ContainerNodeProjectList returns all container objects on the local node within the given project.
-func (c *ClusterTx) ContainerNodeProjectList(project string) ([]Instance, error) {
+func (c *ClusterTx) ContainerNodeProjectList(project string, instanceType instance.Type) ([]Instance, error) {
node, err := c.NodeName()
if err != nil {
return nil, errors.Wrap(err, "Local node name")
@@ -498,7 +524,7 @@ func (c *ClusterTx) ContainerNodeProjectList(project string) ([]Instance, error)
filter := InstanceFilter{
Project: project,
Node: node,
- Type: instance.TypeContainer,
+ Type: instanceType,
}
return c.InstanceList(filter)
From cdce67eae625b3b6a3c5dff193a6a6f6ac4f37af Mon Sep 17 00:00:00 2001
From: Thomas Parrott <tomp at tomp.uk>
Date: Tue, 10 Sep 2019 17:17:22 +0100
Subject: [PATCH 08/16] lxd/container: Updates containerLoadNodeProjectAll to
support instance.Type filtering
Signed-off-by: Thomas Parrott <tomp at tomp.uk>
---
lxd/container.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lxd/container.go b/lxd/container.go
index a6a04c3837..cd0edf6a2e 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -1152,12 +1152,12 @@ func containerLoadNodeAll(s *state.State) ([]container, error) {
}
// Load all containers of this nodes under the given project.
-func containerLoadNodeProjectAll(s *state.State, project string) ([]container, error) {
+func containerLoadNodeProjectAll(s *state.State, project string, instanceType instance.Type) ([]container, error) {
// Get all the container arguments
var cts []db.Instance
err := s.Cluster.Transaction(func(tx *db.ClusterTx) error {
var err error
- cts, err = tx.ContainerNodeProjectList(project)
+ cts, err = tx.ContainerNodeProjectList(project, instanceType)
if err != nil {
return err
}
From 09d2a2dc84d89141724de1aa5401d4f0f81936ea Mon Sep 17 00:00:00 2001
From: Thomas Parrott <tomp at tomp.uk>
Date: Tue, 10 Sep 2019 17:17:52 +0100
Subject: [PATCH 09/16] lxd/container/lxc: Adds instance Type string field
population in Render()
Signed-off-by: Thomas Parrott <tomp at tomp.uk>
---
lxd/container_lxc.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index f0fdd9c791..b1e67d781a 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -3246,6 +3246,7 @@ func (c *containerLXC) Render() (interface{}, interface{}, error) {
Status: statusCode.String(),
StatusCode: statusCode,
Location: c.node,
+ Type: c.Type().String(),
}
ct.Description = c.description
From fb28d9f01c4ef2d815a08bbc6d442e8ee72610f6 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <tomp at tomp.uk>
Date: Tue, 10 Sep 2019 17:18:47 +0100
Subject: [PATCH 10/16] lxd/containers/get: Makes /1.0/containers filter by
instance type container
- However there is still work to do in doContainersGetFromNode and doContainersFullGetFromNode to actually filter, however this requires changing the client package.
Signed-off-by: Thomas Parrott <tomp at tomp.uk>
---
lxd/containers_get.go | 32 +++++++++++++++++++++++---------
1 file changed, 23 insertions(+), 9 deletions(-)
diff --git a/lxd/containers_get.go b/lxd/containers_get.go
index e45c458aa5..60193da982 100644
--- a/lxd/containers_get.go
+++ b/lxd/containers_get.go
@@ -5,17 +5,21 @@ import (
"net/http"
"sort"
"strconv"
+ "strings"
"sync"
"time"
+ "github.com/gorilla/mux"
+ "github.com/pkg/errors"
+
"github.com/lxc/lxd/lxd/cluster"
"github.com/lxc/lxd/lxd/db"
"github.com/lxc/lxd/lxd/db/query"
+ "github.com/lxc/lxd/lxd/instance"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/logger"
"github.com/lxc/lxd/shared/version"
- "github.com/pkg/errors"
)
func containersGet(d *Daemon, r *http.Request) Response {
@@ -44,6 +48,12 @@ func doContainersGet(d *Daemon, r *http.Request) (interface{}, error) {
resultFullList := []*api.ContainerFull{}
resultMu := sync.Mutex{}
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
// Parse the recursion field
recursionStr := r.FormValue("recursion")
@@ -61,12 +71,12 @@ func doContainersGet(d *Daemon, r *http.Request) (interface{}, error) {
err = d.cluster.Transaction(func(tx *db.ClusterTx) error {
var err error
- result, err = tx.ContainersListByNodeAddress(project)
+ result, err = tx.ContainersListByNodeAddress(project, instanceType)
if err != nil {
return err
}
- nodes, err = tx.ContainersByNodeName(project)
+ nodes, err = tx.ContainersByNodeName(project, instanceType)
if err != nil {
return err
}
@@ -80,7 +90,7 @@ func doContainersGet(d *Daemon, r *http.Request) (interface{}, error) {
// Get the local containers
nodeCts := map[string]container{}
if recursion > 0 {
- cts, err := containerLoadNodeProjectAll(d.State(), project)
+ cts, err := containerLoadNodeProjectAll(d.State(), project, instanceType)
if err != nil {
return nil, err
}
@@ -151,7 +161,7 @@ func doContainersGet(d *Daemon, r *http.Request) (interface{}, error) {
cert := d.endpoints.NetworkCert()
if recursion == 1 {
- cs, err := doContainersGetFromNode(project, address, cert)
+ cs, err := doContainersGetFromNode(project, address, cert, instanceType)
if err != nil {
for _, name := range containers {
resultListAppend(name, api.Container{}, err)
@@ -167,7 +177,7 @@ func doContainersGet(d *Daemon, r *http.Request) (interface{}, error) {
return
}
- cs, err := doContainersFullGetFromNode(project, address, cert)
+ cs, err := doContainersFullGetFromNode(project, address, cert, instanceType)
if err != nil {
for _, name := range containers {
resultFullListAppend(name, api.ContainerFull{}, err)
@@ -186,7 +196,11 @@ func doContainersGet(d *Daemon, r *http.Request) (interface{}, error) {
if recursion == 0 {
for _, container := range containers {
- url := fmt.Sprintf("/%s/containers/%s", version.APIVersion, container)
+ instancePath := "instances"
+ if instanceType == instance.TypeContainer {
+ instancePath = "containers"
+ }
+ url := fmt.Sprintf("/%s/%s/%s", version.APIVersion, instancePath, container)
resultString = append(resultString, url)
}
} else {
@@ -262,7 +276,7 @@ func doContainersGet(d *Daemon, r *http.Request) (interface{}, error) {
// Fetch information about the containers on the given remote node, using the
// rest API and with a timeout of 30 seconds.
-func doContainersGetFromNode(project, node string, cert *shared.CertInfo) ([]api.Container, error) {
+func doContainersGetFromNode(project, node string, cert *shared.CertInfo, instanceType instance.Type) ([]api.Container, error) {
f := func() ([]api.Container, error) {
client, err := cluster.Connect(node, cert, true)
if err != nil {
@@ -299,7 +313,7 @@ func doContainersGetFromNode(project, node string, cert *shared.CertInfo) ([]api
return containers, err
}
-func doContainersFullGetFromNode(project, node string, cert *shared.CertInfo) ([]api.ContainerFull, error) {
+func doContainersFullGetFromNode(project, node string, cert *shared.CertInfo, instanceType instance.Type) ([]api.ContainerFull, error) {
f := func() ([]api.ContainerFull, error) {
client, err := cluster.Connect(node, cert, true)
if err != nil {
From 3d773c4da37c325297ec509279dfc8e23045d99f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <tomp at tomp.uk>
Date: Tue, 10 Sep 2019 17:40:52 +0100
Subject: [PATCH 11/16] lxd/db/containers/test: Fixes tests
Signed-off-by: Thomas Parrott <tomp at tomp.uk>
---
lxd/db/containers_test.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lxd/db/containers_test.go b/lxd/db/containers_test.go
index bc2adf4fa8..ef829b9e37 100644
--- a/lxd/db/containers_test.go
+++ b/lxd/db/containers_test.go
@@ -313,7 +313,7 @@ func TestContainersListByNodeAddress(t *testing.T) {
addContainer(t, tx, nodeID3, "c3")
addContainer(t, tx, nodeID2, "c4")
- result, err := tx.ContainersListByNodeAddress("default")
+ result, err := tx.ContainersListByNodeAddress("default", instance.TypeContainer)
require.NoError(t, err)
assert.Equal(
t,
@@ -337,7 +337,7 @@ func TestContainersByNodeName(t *testing.T) {
addContainer(t, tx, nodeID2, "c1")
addContainer(t, tx, nodeID1, "c2")
- result, err := tx.ContainersByNodeName("default")
+ result, err := tx.ContainersByNodeName("default", instance.TypeContainer)
require.NoError(t, err)
assert.Equal(
t,
From 3ea17480785f7e324840d75f0d315ccd6abbf028 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 11 Sep 2019 11:11:22 +0100
Subject: [PATCH 12/16] lxd/db/containers: Adds instanceType filter to
ContainerNodeAddress
- Supports instance.TypeAny if no filter is needed.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/db/containers.go | 43 +++++++++++++++++++++++++++++++++----------
1 file changed, 33 insertions(+), 10 deletions(-)
diff --git a/lxd/db/containers.go b/lxd/db/containers.go
index 068da2532a..0334215e06 100644
--- a/lxd/db/containers.go
+++ b/lxd/db/containers.go
@@ -175,30 +175,53 @@ SELECT instances.name FROM instances
// with the given name in the given project.
//
// It returns the empty string if the container is hosted on this node.
-func (c *ClusterTx) ContainerNodeAddress(project string, name string) (string, error) {
+func (c *ClusterTx) ContainerNodeAddress(project string, name string, instanceType instance.Type) (string, error) {
var stmt string
- args := []interface{}{project}
+
+ args := make([]interface{}, 0, 4) // Expect up to 4 filters.
+ var filters strings.Builder
+
+ // Project filter.
+ filters.WriteString("projects.name = ?")
+ args = append(args, project)
+
+ // Instance type filter.
+ if instanceType != instance.TypeAny {
+ filters.WriteString(" AND instances.type = ?")
+ args = append(args, instanceType)
+ }
if strings.Contains(name, shared.SnapshotDelimiter) {
parts := strings.SplitN(name, shared.SnapshotDelimiter, 2)
- stmt = `
+
+ // Instance name filter.
+ filters.WriteString(" AND instances.name = ?")
+ args = append(args, parts[0])
+
+ // Snapshot name filter.
+ filters.WriteString(" AND instances_snapshots.name = ?")
+ args = append(args, parts[1])
+
+ stmt = fmt.Sprintf(`
SELECT nodes.id, nodes.address
FROM nodes
JOIN instances ON instances.node_id = nodes.id
JOIN projects ON projects.id = instances.project_id
JOIN instances_snapshots ON instances_snapshots.instance_id = instances.id
- WHERE projects.name = ? AND instances.name = ? AND instances_snapshots.name = ?
-`
- args = append(args, parts[0], parts[1])
+ WHERE %s
+`, filters.String())
} else {
- stmt = `
+ // Instance name filter.
+ filters.WriteString(" AND instances.name = ?")
+ args = append(args, name)
+
+ stmt = fmt.Sprintf(`
SELECT nodes.id, nodes.address
FROM nodes
JOIN instances ON instances.node_id = nodes.id
JOIN projects ON projects.id = instances.project_id
- WHERE projects.name = ? AND instances.name = ?
-`
- args = append(args, name)
+ WHERE %s
+`, filters.String())
}
var address string
From 92ae4f361700b45d696c60b45b35aab628e46f2c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 11 Sep 2019 11:12:49 +0100
Subject: [PATCH 13/16] lxd/cluster/connect: Adds instanceType filter to
ConnectIfContainerIsRemote
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/cluster/connect.go | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lxd/cluster/connect.go b/lxd/cluster/connect.go
index 710d164fe6..b97625ffd1 100644
--- a/lxd/cluster/connect.go
+++ b/lxd/cluster/connect.go
@@ -7,6 +7,7 @@ import (
lxd "github.com/lxc/lxd/client"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/instance"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/pkg/errors"
@@ -37,11 +38,11 @@ func Connect(address string, cert *shared.CertInfo, notify bool) (lxd.ContainerS
// running the container with the given name. If it's not the local node will
// connect to it and return the connected client, otherwise it will just return
// nil.
-func ConnectIfContainerIsRemote(cluster *db.Cluster, project, name string, cert *shared.CertInfo) (lxd.ContainerServer, error) {
+func ConnectIfContainerIsRemote(cluster *db.Cluster, project, name string, cert *shared.CertInfo, instanceType instance.Type) (lxd.ContainerServer, error) {
var address string // Node address
err := cluster.Transaction(func(tx *db.ClusterTx) error {
var err error
- address, err = tx.ContainerNodeAddress(project, name)
+ address, err = tx.ContainerNodeAddress(project, name, instanceType)
return err
})
if err != nil {
From c59207c727a19c3c0ffc8449d8fd5ddb1511055e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 11 Sep 2019 11:13:47 +0100
Subject: [PATCH 14/16] lxd/response: Adds instanceType filter to
ForwardedResponseIfContainerIsRemote
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/response.go | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lxd/response.go b/lxd/response.go
index 76b58b3b3c..bd0980fb6b 100644
--- a/lxd/response.go
+++ b/lxd/response.go
@@ -18,6 +18,7 @@ import (
lxd "github.com/lxc/lxd/client"
"github.com/lxc/lxd/lxd/cluster"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/instance"
"github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
@@ -191,9 +192,9 @@ func ForwardedResponseIfTargetIsRemote(d *Daemon, request *http.Request) Respons
// ForwardedResponseIfContainerIsRemote redirects a request to the node running
// the container with the given name. If the container is local, nothing gets
// done and nil is returned.
-func ForwardedResponseIfContainerIsRemote(d *Daemon, r *http.Request, project, name string) (Response, error) {
+func ForwardedResponseIfContainerIsRemote(d *Daemon, r *http.Request, project, name string, instanceType instance.Type) (Response, error) {
cert := d.endpoints.NetworkCert()
- client, err := cluster.ConnectIfContainerIsRemote(d.cluster, project, name, cert)
+ client, err := cluster.ConnectIfContainerIsRemote(d.cluster, project, name, cert, instanceType)
if err != nil {
return nil, err
}
From e09015ba1146087a8f47d9d0ba6fed5db79b186f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 11 Sep 2019 11:14:10 +0100
Subject: [PATCH 15/16] lxd: Updates use of
ForwardedResponseIfContainerIsRemote to supply instanceType
- This has the effect of validating whether the supplied instance name exists as the same type as the context of the endpoint.
- Instance type is derived from the context of the endpoint.
- If context is /1.0/containers then instance.TypeContainer is used.
- If context is /1.0/instances then instance.TypeAny is used.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/container_backup.go | 49 ++++++++++++++++++++++++++++++++++-----
lxd/container_console.go | 18 ++++++++++++--
lxd/container_delete.go | 10 +++++++-
lxd/container_exec.go | 12 +++++++---
lxd/container_file.go | 10 +++++++-
lxd/container_get.go | 11 ++++++++-
lxd/container_logs.go | 26 ++++++++++++++++++---
lxd/container_metadata.go | 44 +++++++++++++++++++++++++++++------
lxd/container_patch.go | 10 +++++++-
lxd/container_post.go | 18 ++++++++++----
lxd/container_put.go | 10 +++++++-
lxd/container_snapshot.go | 25 +++++++++++++++++---
lxd/container_state.go | 18 ++++++++++++--
lxd/containers_post.go | 2 +-
lxd/images.go | 13 +++++++----
15 files changed, 235 insertions(+), 41 deletions(-)
diff --git a/lxd/container_backup.go b/lxd/container_backup.go
index bbf436e126..7f950a222c 100644
--- a/lxd/container_backup.go
+++ b/lxd/container_backup.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/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
@@ -18,11 +19,17 @@ import (
)
func containerBackupsGet(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
cname := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, cname)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, cname, instanceType)
if err != nil {
return SmartError(err)
}
@@ -64,11 +71,17 @@ func containerBackupsGet(d *Daemon, r *http.Request) Response {
}
func containerBackupsPost(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
@@ -176,12 +189,18 @@ func containerBackupsPost(d *Daemon, r *http.Request) Response {
}
func containerBackupGet(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
backupName := mux.Vars(r)["backupName"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
@@ -199,12 +218,18 @@ func containerBackupGet(d *Daemon, r *http.Request) Response {
}
func containerBackupPost(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
backupName := mux.Vars(r)["backupName"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
@@ -253,12 +278,18 @@ func containerBackupPost(d *Daemon, r *http.Request) Response {
}
func containerBackupDelete(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
backupName := mux.Vars(r)["backupName"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
@@ -294,12 +325,18 @@ func containerBackupDelete(d *Daemon, r *http.Request) Response {
}
func containerBackupExportGet(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
backupName := mux.Vars(r)["backupName"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
diff --git a/lxd/container_console.go b/lxd/container_console.go
index c498f6cad7..2ccf9094f4 100644
--- a/lxd/container_console.go
+++ b/lxd/container_console.go
@@ -8,6 +8,7 @@ import (
"os"
"os/exec"
"strconv"
+ "strings"
"sync"
"syscall"
@@ -18,6 +19,7 @@ import (
"github.com/lxc/lxd/lxd/cluster"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/instance"
"github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
@@ -254,6 +256,12 @@ func (s *consoleWs) Do(op *operation) error {
}
func containerConsolePost(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
@@ -270,7 +278,7 @@ func containerConsolePost(d *Daemon, r *http.Request) Response {
// Forward the request if the container is remote.
cert := d.endpoints.NetworkCert()
- client, err := cluster.ConnectIfContainerIsRemote(d.cluster, project, name, cert)
+ client, err := cluster.ConnectIfContainerIsRemote(d.cluster, project, name, cert, instanceType)
if err != nil {
return SmartError(err)
}
@@ -343,11 +351,17 @@ func containerConsolePost(d *Daemon, r *http.Request) Response {
}
func containerConsoleLogGet(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
// Forward the request if the container is remote.
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
diff --git a/lxd/container_delete.go b/lxd/container_delete.go
index 6e6d653928..319f7cd853 100644
--- a/lxd/container_delete.go
+++ b/lxd/container_delete.go
@@ -3,17 +3,25 @@ package main
import (
"fmt"
"net/http"
+ "strings"
"github.com/gorilla/mux"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/instance"
)
func containerDelete(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
diff --git a/lxd/container_exec.go b/lxd/container_exec.go
index e53fad8727..358b88f555 100644
--- a/lxd/container_exec.go
+++ b/lxd/container_exec.go
@@ -19,13 +19,13 @@ import (
"github.com/lxc/lxd/lxd/cluster"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/instance"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
+ log "github.com/lxc/lxd/shared/log15"
"github.com/lxc/lxd/shared/logger"
"github.com/lxc/lxd/shared/netutils"
"github.com/lxc/lxd/shared/version"
-
- log "github.com/lxc/lxd/shared/log15"
)
type execWs struct {
@@ -342,6 +342,12 @@ func (s *execWs) Do(op *operation) error {
}
func containerExecPost(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
@@ -357,7 +363,7 @@ func containerExecPost(d *Daemon, r *http.Request) Response {
// Forward the request if the container is remote.
cert := d.endpoints.NetworkCert()
- client, err := cluster.ConnectIfContainerIsRemote(d.cluster, project, name, cert)
+ client, err := cluster.ConnectIfContainerIsRemote(d.cluster, project, name, cert, instanceType)
if err != nil {
return SmartError(err)
}
diff --git a/lxd/container_file.go b/lxd/container_file.go
index e9358c091a..21f8b33693 100644
--- a/lxd/container_file.go
+++ b/lxd/container_file.go
@@ -7,17 +7,25 @@ import (
"net/http"
"os"
"path/filepath"
+ "strings"
"github.com/gorilla/mux"
+ "github.com/lxc/lxd/lxd/instance"
"github.com/lxc/lxd/shared"
)
func containerFileHandler(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
diff --git a/lxd/container_get.go b/lxd/container_get.go
index 565699364d..7dacde2f60 100644
--- a/lxd/container_get.go
+++ b/lxd/container_get.go
@@ -2,16 +2,25 @@ package main
import (
"net/http"
+ "strings"
"github.com/gorilla/mux"
+
+ "github.com/lxc/lxd/lxd/instance"
)
func containerGet(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
diff --git a/lxd/container_logs.go b/lxd/container_logs.go
index 92e026d3e2..72b3dfa80e 100644
--- a/lxd/container_logs.go
+++ b/lxd/container_logs.go
@@ -9,6 +9,7 @@ import (
"github.com/gorilla/mux"
+ "github.com/lxc/lxd/lxd/instance"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/version"
)
@@ -38,11 +39,18 @@ func containerLogsGet(d *Daemon, r *http.Request) Response {
* However, we should check this name and ensure it's a valid container
* name just so that people can't list arbitrary directories.
*/
+
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
@@ -84,11 +92,17 @@ func validLogFileName(fname string) bool {
}
func containerLogGet(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
@@ -115,11 +129,17 @@ func containerLogGet(d *Daemon, r *http.Request) Response {
}
func containerLogDelete(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
diff --git a/lxd/container_metadata.go b/lxd/container_metadata.go
index adfce53c57..78b7f182c9 100644
--- a/lxd/container_metadata.go
+++ b/lxd/container_metadata.go
@@ -10,20 +10,26 @@ import (
"path/filepath"
"strings"
- "gopkg.in/yaml.v2"
-
"github.com/gorilla/mux"
+ "gopkg.in/yaml.v2"
+ "github.com/lxc/lxd/lxd/instance"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
)
func containerMetadataGet(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
@@ -75,11 +81,17 @@ func containerMetadataGet(d *Daemon, r *http.Request) Response {
}
func containerMetadataPut(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
@@ -124,11 +136,17 @@ func containerMetadataPut(d *Daemon, r *http.Request) Response {
// Return a list of templates used in a container or the content of a template
func containerMetadataTemplatesGet(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
@@ -213,11 +231,17 @@ func containerMetadataTemplatesGet(d *Daemon, r *http.Request) Response {
// Add a container template file
func containerMetadataTemplatesPostPut(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
@@ -280,12 +304,18 @@ func containerMetadataTemplatesPostPut(d *Daemon, r *http.Request) Response {
// Delete a container template
func containerMetadataTemplatesDelete(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
diff --git a/lxd/container_patch.go b/lxd/container_patch.go
index 18f454dcf0..c7be6f8f64 100644
--- a/lxd/container_patch.go
+++ b/lxd/container_patch.go
@@ -6,11 +6,13 @@ import (
"fmt"
"io/ioutil"
"net/http"
+ "strings"
"github.com/gorilla/mux"
"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/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
@@ -18,13 +20,19 @@ import (
)
func containerPatch(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
// Get the container
name := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
diff --git a/lxd/container_post.go b/lxd/container_post.go
index 3865b646c1..e030133472 100644
--- a/lxd/container_post.go
+++ b/lxd/container_post.go
@@ -6,6 +6,7 @@ import (
"fmt"
"io/ioutil"
"net/http"
+ "strings"
"github.com/gorilla/mux"
"github.com/pborman/uuid"
@@ -14,6 +15,7 @@ import (
lxd "github.com/lxc/lxd/client"
"github.com/lxc/lxd/lxd/cluster"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/instance"
driver "github.com/lxc/lxd/lxd/storage"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
@@ -27,6 +29,12 @@ var internalClusterContainerMovedCmd = APIEndpoint{
}
func containerPost(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
@@ -70,7 +78,7 @@ func containerPost(d *Daemon, r *http.Request) Response {
targetNodeOffline = node.IsOffline(config.OfflineThreshold())
// Load source node.
- address, err := tx.ContainerNodeAddress(project, name)
+ address, err := tx.ContainerNodeAddress(project, name, instanceType)
if err != nil {
return errors.Wrap(err, "Failed to get address of container's node")
}
@@ -121,7 +129,7 @@ func containerPost(d *Daemon, r *http.Request) Response {
// and we'll either forward the request or load the container.
if targetNode == "" || !sourceNodeOffline {
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
@@ -181,7 +189,7 @@ func containerPost(d *Daemon, r *http.Request) Response {
return SmartError(err)
}
if pool.Driver == "ceph" {
- return containerPostClusteringMigrateWithCeph(d, c, project, name, req.Name, targetNode)
+ return containerPostClusteringMigrateWithCeph(d, c, project, name, req.Name, targetNode, instanceType)
}
// If this is not a ceph-based container, make sure
@@ -393,7 +401,7 @@ func containerPostClusteringMigrate(d *Daemon, c container, oldName, newName, ne
}
// Special case migrating a container backed by ceph across two cluster nodes.
-func containerPostClusteringMigrateWithCeph(d *Daemon, c container, project, oldName, newName, newNode string) Response {
+func containerPostClusteringMigrateWithCeph(d *Daemon, c container, project, oldName, newName, newNode string, instanceType instance.Type) Response {
run := func(*operation) error {
// If source node is online (i.e. we're serving the request on
// it, and c != nil), let's unmap the RBD volume locally
@@ -467,7 +475,7 @@ func containerPostClusteringMigrateWithCeph(d *Daemon, c container, project, old
// Create the container mount point on the target node
cert := d.endpoints.NetworkCert()
- client, err := cluster.ConnectIfContainerIsRemote(d.cluster, project, newName, cert)
+ client, err := cluster.ConnectIfContainerIsRemote(d.cluster, project, newName, cert, instanceType)
if err != nil {
return errors.Wrap(err, "Failed to connect to target node")
}
diff --git a/lxd/container_put.go b/lxd/container_put.go
index 27b5be9f43..6ac1426f96 100644
--- a/lxd/container_put.go
+++ b/lxd/container_put.go
@@ -4,11 +4,13 @@ import (
"encoding/json"
"fmt"
"net/http"
+ "strings"
"github.com/gorilla/mux"
"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/state"
"github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
@@ -21,13 +23,19 @@ import (
* the named snapshot
*/
func containerPut(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
// Get the container
name := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
diff --git a/lxd/container_snapshot.go b/lxd/container_snapshot.go
index 67fe2e71d4..d800cb0590 100644
--- a/lxd/container_snapshot.go
+++ b/lxd/container_snapshot.go
@@ -13,6 +13,7 @@ import (
"github.com/gorilla/mux"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/instance"
"github.com/lxc/lxd/lxd/util"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
@@ -20,11 +21,17 @@ import (
)
func containerSnapshotsGet(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
cname := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, cname)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, cname, instanceType)
if err != nil {
return SmartError(err)
}
@@ -81,11 +88,17 @@ func containerSnapshotsGet(d *Daemon, r *http.Request) Response {
}
func containerSnapshotsPost(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
@@ -170,11 +183,17 @@ func containerSnapshotsPost(d *Daemon, r *http.Request) Response {
}
func containerSnapshotHandler(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
containerName := mux.Vars(r)["name"]
snapshotName := mux.Vars(r)["snapshotName"]
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, containerName)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, containerName, instanceType)
if err != nil {
return SmartError(err)
}
diff --git a/lxd/container_state.go b/lxd/container_state.go
index 8b86a0a362..c47309546a 100644
--- a/lxd/container_state.go
+++ b/lxd/container_state.go
@@ -4,21 +4,29 @@ import (
"encoding/json"
"fmt"
"net/http"
+ "strings"
"time"
"github.com/gorilla/mux"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/instance"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
)
func containerState(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
@@ -39,11 +47,17 @@ func containerState(d *Daemon, r *http.Request) Response {
}
func containerStatePut(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
name := mux.Vars(r)["name"]
// Handle requests targeted to a container on a different node
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
return SmartError(err)
}
diff --git a/lxd/containers_post.go b/lxd/containers_post.go
index b2c6fc6382..b032d60d1d 100644
--- a/lxd/containers_post.go
+++ b/lxd/containers_post.go
@@ -884,7 +884,7 @@ func clusterCopyContainerInternal(d *Daemon, source container, project string, r
var err error
// Load source node.
- nodeAddress, err = tx.ContainerNodeAddress(project, name)
+ nodeAddress, err = tx.ContainerNodeAddress(project, name, source.Type())
if err != nil {
return errors.Wrap(err, "Failed to get address of container's node")
}
diff --git a/lxd/images.go b/lxd/images.go
index 2ea8330c9f..383ae47643 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -23,12 +23,12 @@ import (
"github.com/gorilla/mux"
"github.com/pkg/errors"
-
"gopkg.in/yaml.v2"
lxd "github.com/lxc/lxd/client"
"github.com/lxc/lxd/lxd/cluster"
"github.com/lxc/lxd/lxd/db"
+ "github.com/lxc/lxd/lxd/instance"
"github.com/lxc/lxd/lxd/node"
"github.com/lxc/lxd/lxd/state"
"github.com/lxc/lxd/lxd/task"
@@ -36,12 +36,11 @@ import (
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/ioprogress"
+ log "github.com/lxc/lxd/shared/log15"
"github.com/lxc/lxd/shared/logger"
"github.com/lxc/lxd/shared/logging"
"github.com/lxc/lxd/shared/osarch"
"github.com/lxc/lxd/shared/version"
-
- log "github.com/lxc/lxd/shared/log15"
)
var imagesCmd = APIEndpoint{
@@ -637,6 +636,12 @@ func imageCreateInPool(d *Daemon, info *api.Image, storagePool string) error {
}
func imagesPost(d *Daemon, r *http.Request) Response {
+ // Instance type.
+ instanceType := instance.TypeAny
+ if strings.HasPrefix(mux.CurrentRoute(r).GetName(), "container") {
+ instanceType = instance.TypeContainer
+ }
+
project := projectParam(r)
var err error
@@ -698,7 +703,7 @@ func imagesPost(d *Daemon, r *http.Request) Response {
if name != "" {
post.Seek(0, 0)
r.Body = post
- response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name)
+ response, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, instanceType)
if err != nil {
cleanup(builddir, post)
return SmartError(err)
From ac9162a552b7c02841d2c0098f9146a48f2aff61 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 11 Sep 2019 13:50:25 +0100
Subject: [PATCH 16/16] shared/api: Renames container files and types to
instance
- Aliases old Container types to maintain backwards compatibility.
- Where old types contain fields that are of old types too, the new type has been duplicated.
- Where old types have functions that return old types, the aliased old type has a function that calls the equivalent function on the new type and casts the result back to the old type.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
shared/api/container_console.go | 17 ---
shared/api/container_state.go | 70 ---------
shared/api/{container.go => instance.go} | 132 +++++++++++++----
...container_backup.go => instance_backup.go} | 32 +++-
shared/api/instance_console.go | 27 ++++
.../{container_exec.go => instance_exec.go} | 18 ++-
...ainer_snapshot.go => instance_snapshot.go} | 56 +++++--
shared/api/instance_state.go | 139 ++++++++++++++++++
8 files changed, 353 insertions(+), 138 deletions(-)
delete mode 100644 shared/api/container_console.go
delete mode 100644 shared/api/container_state.go
rename shared/api/{container.go => instance.go} (66%)
rename shared/api/{container_backup.go => instance_backup.go} (58%)
create mode 100644 shared/api/instance_console.go
rename shared/api/{container_exec.go => instance_exec.go} (67%)
rename shared/api/{container_snapshot.go => instance_snapshot.go} (56%)
create mode 100644 shared/api/instance_state.go
diff --git a/shared/api/container_console.go b/shared/api/container_console.go
deleted file mode 100644
index 56aff07aa4..0000000000
--- a/shared/api/container_console.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package api
-
-// ContainerConsoleControl represents a message on the container console "control" socket
-//
-// API extension: console
-type ContainerConsoleControl struct {
- Command string `json:"command" yaml:"command"`
- Args map[string]string `json:"args" yaml:"args"`
-}
-
-// ContainerConsolePost represents a LXD container console request
-//
-// API extension: console
-type ContainerConsolePost struct {
- Width int `json:"width" yaml:"width"`
- Height int `json:"height" yaml:"height"`
-}
diff --git a/shared/api/container_state.go b/shared/api/container_state.go
deleted file mode 100644
index f9e1cb9b53..0000000000
--- a/shared/api/container_state.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package api
-
-// ContainerStatePut represents the modifiable fields of a LXD container's state
-type ContainerStatePut struct {
- Action string `json:"action" yaml:"action"`
- Timeout int `json:"timeout" yaml:"timeout"`
- Force bool `json:"force" yaml:"force"`
- Stateful bool `json:"stateful" yaml:"stateful"`
-}
-
-// ContainerState represents a LXD container's state
-type ContainerState struct {
- Status string `json:"status" yaml:"status"`
- StatusCode StatusCode `json:"status_code" yaml:"status_code"`
- Disk map[string]ContainerStateDisk `json:"disk" yaml:"disk"`
- Memory ContainerStateMemory `json:"memory" yaml:"memory"`
- Network map[string]ContainerStateNetwork `json:"network" yaml:"network"`
- Pid int64 `json:"pid" yaml:"pid"`
- Processes int64 `json:"processes" yaml:"processes"`
-
- // API extension: container_cpu_time
- CPU ContainerStateCPU `json:"cpu" yaml:"cpu"`
-}
-
-// ContainerStateDisk represents the disk information section of a LXD container's state
-type ContainerStateDisk struct {
- Usage int64 `json:"usage" yaml:"usage"`
-}
-
-// ContainerStateCPU represents the cpu information section of a LXD container's state
-//
-// API extension: container_cpu_time
-type ContainerStateCPU struct {
- Usage int64 `json:"usage" yaml:"usage"`
-}
-
-// ContainerStateMemory represents the memory information section of a LXD container's state
-type ContainerStateMemory struct {
- Usage int64 `json:"usage" yaml:"usage"`
- UsagePeak int64 `json:"usage_peak" yaml:"usage_peak"`
- SwapUsage int64 `json:"swap_usage" yaml:"swap_usage"`
- SwapUsagePeak int64 `json:"swap_usage_peak" yaml:"swap_usage_peak"`
-}
-
-// ContainerStateNetwork represents the network information section of a LXD container's state
-type ContainerStateNetwork struct {
- Addresses []ContainerStateNetworkAddress `json:"addresses" yaml:"addresses"`
- Counters ContainerStateNetworkCounters `json:"counters" yaml:"counters"`
- Hwaddr string `json:"hwaddr" yaml:"hwaddr"`
- HostName string `json:"host_name" yaml:"host_name"`
- Mtu int `json:"mtu" yaml:"mtu"`
- State string `json:"state" yaml:"state"`
- Type string `json:"type" yaml:"type"`
-}
-
-// ContainerStateNetworkAddress represents a network address as part of the network section of a LXD container's state
-type ContainerStateNetworkAddress struct {
- Family string `json:"family" yaml:"family"`
- Address string `json:"address" yaml:"address"`
- Netmask string `json:"netmask" yaml:"netmask"`
- Scope string `json:"scope" yaml:"scope"`
-}
-
-// ContainerStateNetworkCounters represents packet counters as part of the network section of a LXD container's state
-type ContainerStateNetworkCounters struct {
- BytesReceived int64 `json:"bytes_received" yaml:"bytes_received"`
- BytesSent int64 `json:"bytes_sent" yaml:"bytes_sent"`
- PacketsReceived int64 `json:"packets_received" yaml:"packets_received"`
- PacketsSent int64 `json:"packets_sent" yaml:"packets_sent"`
-}
diff --git a/shared/api/container.go b/shared/api/instance.go
similarity index 66%
rename from shared/api/container.go
rename to shared/api/instance.go
index 88ce8341ab..2e5f54f9c4 100644
--- a/shared/api/container.go
+++ b/shared/api/instance.go
@@ -7,7 +7,22 @@ import (
// InstanceTypeContainer defines the instance type value for a container.
const InstanceTypeContainer = "container"
-// ContainersPost represents the fields available for a new LXD container
+// InstancesPost represents the fields available for a new LXD instance.
+//
+// API extension: instances
+type InstancesPost struct {
+ InstancePut `yaml:",inline"`
+
+ Name string `json:"name" yaml:"name"`
+ Source InstanceSource `json:"source" yaml:"source"`
+
+ InstanceType string `json:"instance_type" yaml:"instance_type"`
+
+ // API extension: instances
+ Type string `json:"type" yaml:"type"`
+}
+
+// ContainersPost represents the fields available for a new LXD container,
type ContainersPost struct {
ContainerPut `yaml:",inline"`
@@ -20,7 +35,27 @@ type ContainersPost struct {
Type string `json:"type" yaml:"type"`
}
-// ContainerPost represents the fields required to rename/move a LXD container
+// InstancePost represents the fields required to rename/move a LXD instance.
+//
+// API extension: instances
+type InstancePost struct {
+ // Used for renames
+ Name string `json:"name" yaml:"name"`
+
+ // Used for migration
+ Migration bool `json:"migration" yaml:"migration"`
+
+ // API extension: container_stateless_copy
+ Live bool `json:"live" yaml:"live"`
+
+ // API extension: container_only_migration
+ ContainerOnly bool `json:"container_only" yaml:"container_only"`
+
+ // API extension: container_push_target
+ Target *InstancePostTarget `json:"target" yaml:"target"`
+}
+
+// ContainerPost represents the fields required to rename/move a LXD container.
type ContainerPost struct {
// Used for renames
Name string `json:"name" yaml:"name"`
@@ -38,17 +73,24 @@ type ContainerPost struct {
Target *ContainerPostTarget `json:"target" yaml:"target"`
}
-// ContainerPostTarget represents the migration target host and operation
+// InstancePostTarget represents the migration target host and operation.
//
-// API extension: container_push_target
-type ContainerPostTarget struct {
+// API extension: instances
+type InstancePostTarget struct {
Certificate string `json:"certificate" yaml:"certificate"`
Operation string `json:"operation,omitempty" yaml:"operation,omitempty"`
Websockets map[string]string `json:"secrets,omitempty" yaml:"secrets,omitempty"`
}
-// ContainerPut represents the modifiable fields of a LXD container
-type ContainerPut struct {
+// ContainerPostTarget represents the migration target host and operation.
+//
+// API extension: container_push_target
+type ContainerPostTarget InstancePostTarget
+
+// InstancePut represents the modifiable fields of a LXD instance.
+//
+// API extension: instances
+type InstancePut struct {
Architecture string `json:"architecture" yaml:"architecture"`
Config map[string]string `json:"config" yaml:"config"`
Devices map[string]map[string]string `json:"devices" yaml:"devices"`
@@ -63,9 +105,14 @@ type ContainerPut struct {
Description string `json:"description" yaml:"description"`
}
-// Container represents a LXD container
-type Container struct {
- ContainerPut `yaml:",inline"`
+// ContainerPut represents the modifiable fields of a LXD container.
+type ContainerPut InstancePut
+
+// Instance represents a LXD instance.
+//
+// API extension: instances
+type Instance struct {
+ InstancePut `yaml:",inline"`
CreatedAt time.Time `json:"created_at" yaml:"created_at"`
ExpandedConfig map[string]string `json:"expanded_config" yaml:"expanded_config"`
@@ -84,24 +131,13 @@ type Container struct {
Type string `json:"type" yaml:"type"`
}
-// ContainerFull is a combination of Container, ContainerState and CotnainerSnapshot
-//
-// API extension: container_full
-type ContainerFull struct {
- Container `yaml:",inline"`
-
- Backups []ContainerBackup `json:"backups" yaml:"backups"`
- State *ContainerState `json:"state" yaml:"state"`
- Snapshots []ContainerSnapshot `json:"snapshots" yaml:"snapshots"`
-}
-
-// Writable converts a full Container struct into a ContainerPut struct (filters read-only fields)
-func (c *Container) Writable() ContainerPut {
- return c.ContainerPut
+// Writable converts a full Instance struct into a InstancePut struct (filters read-only fields).
+func (c *Instance) Writable() InstancePut {
+ return c.InstancePut
}
-// IsActive checks whether the container state indicates the container is active
-func (c Container) IsActive() bool {
+// IsActive checks whether the instance state indicates the instance is active.
+func (c Instance) IsActive() bool {
switch c.StatusCode {
case Stopped:
return false
@@ -112,8 +148,45 @@ func (c Container) IsActive() bool {
}
}
-// ContainerSource represents the creation source for a new container
-type ContainerSource struct {
+// Container represents a LXD container.
+type Container Instance
+
+// Writable converts a full Container struct into a ContainerPut struct (filters read-only fields).
+func (c *Container) Writable() ContainerPut {
+ return ContainerPut(c.InstancePut)
+}
+
+// IsActive checks whether the container state indicates the container is active.
+func (c Container) IsActive() bool {
+ return Instance(c).IsActive()
+}
+
+// InstanceFull is a combination of Instance, InstanceBackup, InstanceState and InstanceSnapshot.
+//
+// API extension: instances
+type InstanceFull struct {
+ Instance `yaml:",inline"`
+
+ Backups []InstanceBackup `json:"backups" yaml:"backups"`
+ State *InstanceState `json:"state" yaml:"state"`
+ Snapshots []InstanceSnapshot `json:"snapshots" yaml:"snapshots"`
+}
+
+// ContainerFull is a combination of Container, ContainerBackup, ContainerState and ContainerSnapshot.
+//
+// API extension: container_full
+type ContainerFull struct {
+ Container `yaml:",inline"`
+
+ Backups []ContainerBackup `json:"backups" yaml:"backups"`
+ State *ContainerState `json:"state" yaml:"state"`
+ Snapshots []ContainerSnapshot `json:"snapshots" yaml:"snapshots"`
+}
+
+// InstanceSource represents the creation source for a new instance.
+//
+// API extension: instances
+type InstanceSource struct {
Type string `json:"type" yaml:"type"`
Certificate string `json:"certificate" yaml:"certificate"`
@@ -148,3 +221,6 @@ type ContainerSource struct {
// API extension: container_copy_project
Project string `json:"project,omitempty" yaml:"project,omitempty"`
}
+
+// ContainerSource represents the creation source for a new container.
+type ContainerSource InstanceSource
diff --git a/shared/api/container_backup.go b/shared/api/instance_backup.go
similarity index 58%
rename from shared/api/container_backup.go
rename to shared/api/instance_backup.go
index 8fe35e9964..d44622ba8c 100644
--- a/shared/api/container_backup.go
+++ b/shared/api/instance_backup.go
@@ -2,18 +2,25 @@ package api
import "time"
-// ContainerBackupsPost represents the fields available for a new LXD container backup
-// API extension: container_backup
-type ContainerBackupsPost struct {
+// InstanceBackupsPost represents the fields available for a new LXD instance backup.
+//
+// API extension: instances
+type InstanceBackupsPost struct {
Name string `json:"name" yaml:"name"`
ExpiresAt time.Time `json:"expires_at" yaml:"expires_at"`
ContainerOnly bool `json:"container_only" yaml:"container_only"`
OptimizedStorage bool `json:"optimized_storage" yaml:"optimized_storage"`
}
-// ContainerBackup represents a LXD container backup
+// ContainerBackupsPost represents the fields available for a new LXD container backup.
+//
// API extension: container_backup
-type ContainerBackup struct {
+type ContainerBackupsPost InstanceBackupsPost
+
+// InstanceBackup represents a LXD instance backup.
+//
+// API extension: instances
+type InstanceBackup struct {
Name string `json:"name" yaml:"name"`
CreatedAt time.Time `json:"created_at" yaml:"created_at"`
ExpiresAt time.Time `json:"expires_at" yaml:"expires_at"`
@@ -21,9 +28,18 @@ type ContainerBackup struct {
OptimizedStorage bool `json:"optimized_storage" yaml:"optimized_storage"`
}
-// ContainerBackupPost represents the fields available for the renaming of a
-// container backup
+// ContainerBackup represents a LXD container backup.
+//
// API extension: container_backup
-type ContainerBackupPost struct {
+type ContainerBackup InstanceBackup
+
+// InstanceBackupPost represents the fields available for the renaming of a instance backup.
+// API extension: instances
+type InstanceBackupPost struct {
Name string `json:"name" yaml:"name"`
}
+
+// ContainerBackupPost represents the fields available for the renaming of a container backup.
+//
+// API extension: container_backup
+type ContainerBackupPost InstanceBackupPost
diff --git a/shared/api/instance_console.go b/shared/api/instance_console.go
new file mode 100644
index 0000000000..180b9ed40e
--- /dev/null
+++ b/shared/api/instance_console.go
@@ -0,0 +1,27 @@
+package api
+
+// InstanceConsoleControl represents a message on the instance console "control" socket.
+//
+// API extension: instances
+type InstanceConsoleControl struct {
+ Command string `json:"command" yaml:"command"`
+ Args map[string]string `json:"args" yaml:"args"`
+}
+
+// ContainerConsoleControl represents a message on the container console "control" socket.
+//
+// API extension: console
+type ContainerConsoleControl InstanceConsoleControl
+
+// InstanceConsolePost represents a LXD instance console request.
+//
+// API extension: instances
+type InstanceConsolePost struct {
+ Width int `json:"width" yaml:"width"`
+ Height int `json:"height" yaml:"height"`
+}
+
+// ContainerConsolePost represents a LXD container console request.
+//
+// API extension: console
+type ContainerConsolePost InstanceConsolePost
diff --git a/shared/api/container_exec.go b/shared/api/instance_exec.go
similarity index 67%
rename from shared/api/container_exec.go
rename to shared/api/instance_exec.go
index 7e724dc49f..2522e12f66 100644
--- a/shared/api/container_exec.go
+++ b/shared/api/instance_exec.go
@@ -1,14 +1,21 @@
package api
-// ContainerExecControl represents a message on the container exec "control" socket
-type ContainerExecControl struct {
+// InstanceExecControl represents a message on the instance exec "control" socket.
+//
+// API extension: instances
+type InstanceExecControl struct {
Command string `json:"command" yaml:"command"`
Args map[string]string `json:"args" yaml:"args"`
Signal int `json:"signal" yaml:"signal"`
}
-// ContainerExecPost represents a LXD container exec request
-type ContainerExecPost struct {
+// ContainerExecControl represents a message on the container exec "control" socket.
+type ContainerExecControl InstanceExecControl
+
+// InstanceExecPost represents a LXD instance exec request.
+//
+// API extension: instances
+type InstanceExecPost struct {
Command []string `json:"command" yaml:"command"`
WaitForWS bool `json:"wait-for-websocket" yaml:"wait-for-websocket"`
Interactive bool `json:"interactive" yaml:"interactive"`
@@ -24,3 +31,6 @@ type ContainerExecPost struct {
Group uint32 `json:"group" yaml:"group"`
Cwd string `json:"cwd" yaml:"cwd"`
}
+
+// ContainerExecPost represents a LXD container exec request.
+type ContainerExecPost InstanceExecPost
diff --git a/shared/api/container_snapshot.go b/shared/api/instance_snapshot.go
similarity index 56%
rename from shared/api/container_snapshot.go
rename to shared/api/instance_snapshot.go
index e68a0fb8cc..cc9045fbf7 100644
--- a/shared/api/container_snapshot.go
+++ b/shared/api/instance_snapshot.go
@@ -4,8 +4,10 @@ import (
"time"
)
-// ContainerSnapshotsPost represents the fields available for a new LXD container snapshot
-type ContainerSnapshotsPost struct {
+// InstanceSnapshotsPost represents the fields available for a new LXD instance snapshot.
+//
+// API extension: instances
+type InstanceSnapshotsPost struct {
Name string `json:"name" yaml:"name"`
Stateful bool `json:"stateful" yaml:"stateful"`
@@ -13,7 +15,22 @@ type ContainerSnapshotsPost struct {
ExpiresAt *time.Time `json:"expires_at" yaml:"expires_at"`
}
-// ContainerSnapshotPost represents the fields required to rename/move a LXD container snapshot
+// ContainerSnapshotsPost represents the fields available for a new LXD container snapshot.
+type ContainerSnapshotsPost InstanceSnapshotsPost
+
+// InstanceSnapshotPost represents the fields required to rename/move a LXD instance snapshot.
+//
+// API extension: instances
+type InstanceSnapshotPost struct {
+ Name string `json:"name" yaml:"name"`
+ Migration bool `json:"migration" yaml:"migration"`
+ Target *InstancePostTarget `json:"target" yaml:"target"`
+
+ // API extension: container_snapshot_stateful_migration
+ Live bool `json:"live,omitempty" yaml:"live,omitempty"`
+}
+
+// ContainerSnapshotPost represents the fields required to rename/move a LXD container snapshot.
type ContainerSnapshotPost struct {
Name string `json:"name" yaml:"name"`
Migration bool `json:"migration" yaml:"migration"`
@@ -23,9 +40,10 @@ type ContainerSnapshotPost struct {
Live bool `json:"live,omitempty" yaml:"live,omitempty"`
}
-// ContainerSnapshotPut represents the modifiable fields of a LXD container snapshot
-// API extension: snapshot_expiry
-type ContainerSnapshotPut struct {
+// InstanceSnapshotPut represents the modifiable fields of a LXD instance snapshot.
+//
+// API extension: instances
+type InstanceSnapshotPut struct {
Architecture string `json:"architecture" yaml:"architecture"`
Config map[string]string `json:"config" yaml:"config"`
Devices map[string]map[string]string `json:"devices" yaml:"devices"`
@@ -34,9 +52,16 @@ type ContainerSnapshotPut struct {
ExpiresAt time.Time `json:"expires_at" yaml:"expires_at"`
}
-// ContainerSnapshot represents a LXD conainer snapshot
-type ContainerSnapshot struct {
- ContainerSnapshotPut `yaml:",inline"`
+// ContainerSnapshotPut represents the modifiable fields of a LXD container snapshot.
+//
+// API extension: snapshot_expiry
+type ContainerSnapshotPut InstanceSnapshotPut
+
+// InstanceSnapshot represents a LXD instance snapshot.
+//
+// API extension: instances
+type InstanceSnapshot struct {
+ InstanceSnapshotPut `yaml:",inline"`
CreatedAt time.Time `json:"created_at" yaml:"created_at"`
ExpandedConfig map[string]string `json:"expanded_config" yaml:"expanded_config"`
@@ -46,8 +71,17 @@ type ContainerSnapshot struct {
Stateful bool `json:"stateful" yaml:"stateful"`
}
-// Writable converts a full ContainerSnapshot struct into a ContainerSnapshotPut struct
+// ContainerSnapshot represents a LXD container snapshot.
+type ContainerSnapshot InstanceSnapshot
+
+// Writable converts a full InstanceSnapshot struct into a InstanceSnapshotPut struct.
+// (filters read-only fields)
+func (c *InstanceSnapshot) Writable() InstanceSnapshotPut {
+ return c.InstanceSnapshotPut
+}
+
+// Writable converts a full ContainerSnapshot struct into a ContainerSnapshotPut struct.
// (filters read-only fields)
func (c *ContainerSnapshot) Writable() ContainerSnapshotPut {
- return c.ContainerSnapshotPut
+ return ContainerSnapshotPut(c.InstanceSnapshotPut)
}
diff --git a/shared/api/instance_state.go b/shared/api/instance_state.go
new file mode 100644
index 0000000000..9ddf3985c7
--- /dev/null
+++ b/shared/api/instance_state.go
@@ -0,0 +1,139 @@
+package api
+
+// InstanceStatePut represents the modifiable fields of a LXD instance's state
+//
+// API extension: container_cpu_time
+type InstanceStatePut struct {
+ Action string `json:"action" yaml:"action"`
+ Timeout int `json:"timeout" yaml:"timeout"`
+ Force bool `json:"force" yaml:"force"`
+ Stateful bool `json:"stateful" yaml:"stateful"`
+}
+
+// ContainerStatePut represents the modifiable fields of a LXD container's state.
+type ContainerStatePut InstanceStatePut
+
+// InstanceState represents a LXD instance's state.
+//
+// API extension: instances
+type InstanceState struct {
+ Status string `json:"status" yaml:"status"`
+ StatusCode StatusCode `json:"status_code" yaml:"status_code"`
+ Disk map[string]InstanceStateDisk `json:"disk" yaml:"disk"`
+ Memory InstanceStateMemory `json:"memory" yaml:"memory"`
+ Network map[string]InstanceStateNetwork `json:"network" yaml:"network"`
+ Pid int64 `json:"pid" yaml:"pid"`
+ Processes int64 `json:"processes" yaml:"processes"`
+
+ // API extension: container_cpu_time
+ CPU ContainerStateCPU `json:"cpu" yaml:"cpu"`
+}
+
+// ContainerState represents a LXD container's state.
+type ContainerState struct {
+ Status string `json:"status" yaml:"status"`
+ StatusCode StatusCode `json:"status_code" yaml:"status_code"`
+ Disk map[string]ContainerStateDisk `json:"disk" yaml:"disk"`
+ Memory ContainerStateMemory `json:"memory" yaml:"memory"`
+ Network map[string]ContainerStateNetwork `json:"network" yaml:"network"`
+ Pid int64 `json:"pid" yaml:"pid"`
+ Processes int64 `json:"processes" yaml:"processes"`
+
+ // API extension: container_cpu_time
+ CPU ContainerStateCPU `json:"cpu" yaml:"cpu"`
+}
+
+// InstanceStateDisk represents the disk information section of a LXD instance's state.
+type InstanceStateDisk struct {
+ Usage int64 `json:"usage" yaml:"usage"`
+}
+
+// ContainerStateDisk represents the disk information section of a LXD container's state.
+//
+// API extension: instances
+type ContainerStateDisk InstanceStateDisk
+
+// InstanceStateCPU represents the cpu information section of a LXD instance's state.
+//
+// API extension: instances
+type InstanceStateCPU struct {
+ Usage int64 `json:"usage" yaml:"usage"`
+}
+
+// ContainerStateCPU represents the cpu information section of a LXD container's state
+//
+// API extension: container_cpu_time
+type ContainerStateCPU InstanceStateCPU
+
+// InstanceStateMemory represents the memory information section of a LXD instance's state.
+//
+// API extension: instances
+type InstanceStateMemory struct {
+ Usage int64 `json:"usage" yaml:"usage"`
+ UsagePeak int64 `json:"usage_peak" yaml:"usage_peak"`
+ SwapUsage int64 `json:"swap_usage" yaml:"swap_usage"`
+ SwapUsagePeak int64 `json:"swap_usage_peak" yaml:"swap_usage_peak"`
+}
+
+// ContainerStateMemory represents the memory information section of a LXD container's state.
+type ContainerStateMemory InstanceStateMemory
+
+// InstanceStateNetwork represents the network information section of a LXD instance's state.
+//
+// API extension: instances
+type InstanceStateNetwork struct {
+ Addresses []InstanceStateNetworkAddress `json:"addresses" yaml:"addresses"`
+ Counters InstanceStateNetworkCounters `json:"counters" yaml:"counters"`
+ Hwaddr string `json:"hwaddr" yaml:"hwaddr"`
+ HostName string `json:"host_name" yaml:"host_name"`
+ Mtu int `json:"mtu" yaml:"mtu"`
+ State string `json:"state" yaml:"state"`
+ Type string `json:"type" yaml:"type"`
+}
+
+// ContainerStateNetwork represents the network information section of a LXD container's state.
+type ContainerStateNetwork struct {
+ Addresses []ContainerStateNetworkAddress `json:"addresses" yaml:"addresses"`
+ Counters ContainerStateNetworkCounters `json:"counters" yaml:"counters"`
+ Hwaddr string `json:"hwaddr" yaml:"hwaddr"`
+ HostName string `json:"host_name" yaml:"host_name"`
+ Mtu int `json:"mtu" yaml:"mtu"`
+ State string `json:"state" yaml:"state"`
+ Type string `json:"type" yaml:"type"`
+}
+
+// InstanceStateNetworkAddress represents a network address as part of the network section of a LXD instance's state.
+//
+// API extension: instances
+type InstanceStateNetworkAddress struct {
+ Family string `json:"family" yaml:"family"`
+ Address string `json:"address" yaml:"address"`
+ Netmask string `json:"netmask" yaml:"netmask"`
+ Scope string `json:"scope" yaml:"scope"`
+}
+
+// ContainerStateNetworkAddress represents a network address as part of the network section of a LXD container's state.
+type ContainerStateNetworkAddress struct {
+ Family string `json:"family" yaml:"family"`
+ Address string `json:"address" yaml:"address"`
+ Netmask string `json:"netmask" yaml:"netmask"`
+ Scope string `json:"scope" yaml:"scope"`
+}
+
+// InstanceStateNetworkCounters represents packet counters as part of the network section of a LXD instance's state.
+//
+// API extension: instances
+type InstanceStateNetworkCounters struct {
+ BytesReceived int64 `json:"bytes_received" yaml:"bytes_received"`
+ BytesSent int64 `json:"bytes_sent" yaml:"bytes_sent"`
+ PacketsReceived int64 `json:"packets_received" yaml:"packets_received"`
+ PacketsSent int64 `json:"packets_sent" yaml:"packets_sent"`
+}
+
+// ContainerStateNetworkCounters represents packet counters as part of the network section of a LXD container's state
+type ContainerStateNetworkCounters struct {
+ BytesReceived int64 `json:"bytes_received" yaml:"bytes_received"`
+ BytesSent int64 `json:"bytes_sent" yaml:"bytes_sent"`
+ PacketsReceived int64 `json:"packets_received" yaml:"packets_received"`
+ PacketsSent int64 `json:"packets_sent" yaml:"packets_sent"`
+}
More information about the lxc-devel
mailing list