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

tomponline on Github lxc-bot at linuxcontainers.org
Fri Sep 6 10:58:17 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 519 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190906/eaa1d46f/attachment-0001.bin>
-------------- next part --------------
From 074cc355a89dc10aca3823ca1f2b0d1c770b28c2 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 6 Sep 2019 11:38:53 +0100
Subject: [PATCH 1/5] lxd/api: Contructs endpoint alias routes

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/api.go | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/lxd/api.go b/lxd/api.go
index fb19a9975c..a22297b741 100644
--- a/lxd/api.go
+++ b/lxd/api.go
@@ -31,6 +31,16 @@ func RestServer(d *Daemon) *http.Server {
 
 	for _, c := range api10 {
 		d.createCmd(mux, "1.0", c)
+
+		// Create any alias endpoints using the same handlers as the parent endpoint but
+		// with a different path and name (so the handler can differentiate being called via
+		// a different endpoint) if it wants to.
+		for _, alias := range c.Aliases {
+			ac := c
+			ac.Name = alias.Name
+			ac.Path = alias.Path
+			d.createCmd(mux, "1.0", ac)
+		}
 	}
 
 	for _, c := range apiInternal {

From 2f222f2671ed752d3b701a5d83e51a70c423e917 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 6 Sep 2019 11:42:50 +0100
Subject: [PATCH 2/5] lxd/containers/get: Fixes comment

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/containers_get.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/containers_get.go b/lxd/containers_get.go
index d93190be33..e45c458aa5 100644
--- a/lxd/containers_get.go
+++ b/lxd/containers_get.go
@@ -28,7 +28,7 @@ func containersGet(d *Daemon, r *http.Request) Response {
 			logger.Debugf("DBERR: containersGet: error %q", err)
 			return SmartError(err)
 		}
-		// 1 s may seem drastic, but we really don't want to thrash
+		// 100 ms may seem drastic, but we really don't want to thrash
 		// perhaps we should use a random amount
 		time.Sleep(100 * time.Millisecond)
 	}

From 6d8941cf091863c653564eaeabbead28831fe824 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 6 Sep 2019 11:43:15 +0100
Subject: [PATCH 3/5] lxd/api/1.0: Renames container endpoint vars to instance
 prefix

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/api_1.0.go | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index 0b6e1a9db4..9bc2db9ea0 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -36,21 +36,21 @@ var api10 = []APIEndpoint{
 	clusterCmd,
 	clusterNodeCmd,
 	clusterNodesCmd,
-	containerBackupCmd,
-	containerBackupExportCmd,
-	containerBackupsCmd,
-	containerCmd,
-	containerConsoleCmd,
-	containerExecCmd,
-	containerFileCmd,
-	containerLogCmd,
-	containerLogsCmd,
-	containerMetadataCmd,
-	containerMetadataTemplatesCmd,
-	containersCmd,
-	containerSnapshotCmd,
-	containerSnapshotsCmd,
-	containerStateCmd,
+	instanceBackupCmd,
+	instanceBackupExportCmd,
+	instanceBackupsCmd,
+	instanceCmd,
+	instanceConsoleCmd,
+	instanceExecCmd,
+	instanceFileCmd,
+	instanceLogCmd,
+	instanceLogsCmd,
+	instanceMetadataCmd,
+	instanceMetadataTemplatesCmd,
+	instancesCmd,
+	instanceSnapshotCmd,
+	instanceSnapshotsCmd,
+	instanceStateCmd,
 	eventsCmd,
 	imageAliasCmd,
 	imageAliasesCmd,

From 26fca57b2a023299fb2b9aae013a0f3949e881e6 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 6 Sep 2019 11:44:26 +0100
Subject: [PATCH 4/5] lxd/daemon: Adds Name and Aliases support to APIEndpoint

The APIEndpoint struct has been modified as follows:

- Repurposes the Name field to represent the name of the endpoint rather than the path.
- Adds a Path field which is what the previous Name field was used for - the path template of the endpoint.
- Add an Aliases field which is contructed of APIEndpointAlias structs - allowing for a single endpoint to be exposed over multiple endpoint paths, each with a separate name.

This field naming scheme matches the concepts used in the gorilla mux router we use.

The purpose of this change is:

- To allow a single set of handler functions to be exposed at multiple URL paths.
- To allow the handler functions to access the name of the endpoint used to access the handler function. In case they need to behave differently based on which path was used (but without having to rely on examing the raw URL path which is unreliable).

The name of the endpoint can be accessed inside the handler function as follows:

 mux.CurrentRoute().GetName()

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/daemon.go | 34 ++++++++++++++++++++++++----------
 1 file changed, 24 insertions(+), 10 deletions(-)

diff --git a/lxd/daemon.go b/lxd/daemon.go
index dca17d0f9a..583af879ad 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -155,12 +155,20 @@ func DefaultDaemon() *Daemon {
 
 // APIEndpoint represents a URL in our API.
 type APIEndpoint struct {
-	Name   string
-	Get    APIEndpointAction
-	Put    APIEndpointAction
-	Post   APIEndpointAction
-	Delete APIEndpointAction
-	Patch  APIEndpointAction
+	Name    string             // Name for this endpoint.
+	Path    string             // Path pattern for this endpoint.
+	Aliases []APIEndpointAlias // Any aliases for this endpoint.
+	Get     APIEndpointAction
+	Put     APIEndpointAction
+	Post    APIEndpointAction
+	Delete  APIEndpointAction
+	Patch   APIEndpointAction
+}
+
+// APIEndpointAlias represents an alias URL of and APIEndpoint in our API.
+type APIEndpointAlias struct {
+	Name string // Name for this alias.
+	Path string // Path pattern for this alias.
 }
 
 // APIEndpointAction represents an action on an API endpoint.
@@ -338,13 +346,13 @@ func (d *Daemon) UnixSocket() string {
 
 func (d *Daemon) createCmd(restAPI *mux.Router, version string, c APIEndpoint) {
 	var uri string
-	if c.Name == "" {
+	if c.Path == "" {
 		uri = fmt.Sprintf("/%s", version)
 	} else {
-		uri = fmt.Sprintf("/%s/%s", version, c.Name)
+		uri = fmt.Sprintf("/%s/%s", version, c.Path)
 	}
 
-	restAPI.HandleFunc(uri, func(w http.ResponseWriter, r *http.Request) {
+	route := restAPI.HandleFunc(uri, func(w http.ResponseWriter, r *http.Request) {
 		w.Header().Set("Content-Type", "application/json")
 
 		// Block public API requests until we're done with basic
@@ -371,7 +379,7 @@ func (d *Daemon) createCmd(restAPI *mux.Router, version string, c APIEndpoint) {
 		// Reject internal queries to remote, non-cluster, clients
 		if version == "internal" && !shared.StringInSlice(protocol, []string{"unix", "cluster"}) {
 			// Except for the initial cluster accept request (done over trusted TLS)
-			if !trusted || c.Name != "cluster/accept" || protocol != "tls" {
+			if !trusted || c.Path != "cluster/accept" || protocol != "tls" {
 				logger.Warn("Rejecting remote internal API request", log.Ctx{"ip": r.RemoteAddr})
 				Forbidden(nil).Render(w)
 				return
@@ -455,6 +463,12 @@ func (d *Daemon) createCmd(restAPI *mux.Router, version string, c APIEndpoint) {
 			}
 		}
 	})
+
+	// If the endpoint has a canonical name then record it so it can be used to build URLS
+	// and accessed in the context of the request by the handler function.
+	if c.Name != "" {
+		route.Name(c.Name)
+	}
 }
 
 // have we setup shared mounts?

From 8802e6c344b9eade57b17c42167d14c6a68d0e01 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 6 Sep 2019 11:52:45 +0100
Subject: [PATCH 5/5] lxd: Adds /1.0/instances aliases of /1.0/containers
 routes

 - Renames Name property to Path property for all routes
 - Renames container routers to instance prefix
 - Adds new Name property to all instance endpoints
 - Adds equivalent container alias to all instance routes

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/api_cluster.go              | 12 ++---
 lxd/api_internal.go             | 18 ++++----
 lxd/api_project.go              |  4 +-
 lxd/certificates.go             |  4 +-
 lxd/container_logs.go           | 12 +++--
 lxd/container_post.go           |  2 +-
 lxd/containers.go               | 78 ++++++++++++++++++++++-----------
 lxd/events.go                   |  2 +-
 lxd/images.go                   | 14 +++---
 lxd/networks.go                 |  8 ++--
 lxd/operations.go               |  8 ++--
 lxd/profiles.go                 |  4 +-
 lxd/resources.go                |  4 +-
 lxd/storage_pools.go            |  4 +-
 lxd/storage_volumes.go          | 10 ++---
 lxd/storage_volumes_snapshot.go |  4 +-
 16 files changed, 109 insertions(+), 79 deletions(-)

diff --git a/lxd/api_cluster.go b/lxd/api_cluster.go
index 0caabc658c..544d417894 100644
--- a/lxd/api_cluster.go
+++ b/lxd/api_cluster.go
@@ -29,20 +29,20 @@ import (
 )
 
 var clusterCmd = APIEndpoint{
-	Name: "cluster",
+	Path: "cluster",
 
 	Get: APIEndpointAction{Handler: clusterGet, AccessHandler: AllowAuthenticated},
 	Put: APIEndpointAction{Handler: clusterPut},
 }
 
 var clusterNodesCmd = APIEndpoint{
-	Name: "cluster/members",
+	Path: "cluster/members",
 
 	Get: APIEndpointAction{Handler: clusterNodesGet, AccessHandler: AllowAuthenticated},
 }
 
 var clusterNodeCmd = APIEndpoint{
-	Name: "cluster/members/{name}",
+	Path: "cluster/members/{name}",
 
 	Delete: APIEndpointAction{Handler: clusterNodeDelete},
 	Get:    APIEndpointAction{Handler: clusterNodeGet, AccessHandler: AllowAuthenticated},
@@ -50,19 +50,19 @@ var clusterNodeCmd = APIEndpoint{
 }
 
 var internalClusterAcceptCmd = APIEndpoint{
-	Name: "cluster/accept",
+	Path: "cluster/accept",
 
 	Post: APIEndpointAction{Handler: internalClusterPostAccept},
 }
 
 var internalClusterRebalanceCmd = APIEndpoint{
-	Name: "cluster/rebalance",
+	Path: "cluster/rebalance",
 
 	Post: APIEndpointAction{Handler: internalClusterPostRebalance},
 }
 
 var internalClusterPromoteCmd = APIEndpoint{
-	Name: "cluster/promote",
+	Path: "cluster/promote",
 
 	Post: APIEndpointAction{Handler: internalClusterPostPromote},
 }
diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index 758f17b407..1f48eda280 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -48,56 +48,56 @@ var apiInternal = []APIEndpoint{
 }
 
 var internalShutdownCmd = APIEndpoint{
-	Name: "shutdown",
+	Path: "shutdown",
 
 	Put: APIEndpointAction{Handler: internalShutdown},
 }
 
 var internalReadyCmd = APIEndpoint{
-	Name: "ready",
+	Path: "ready",
 
 	Get: APIEndpointAction{Handler: internalWaitReady},
 }
 
 var internalContainerOnStartCmd = APIEndpoint{
-	Name: "containers/{id}/onstart",
+	Path: "containers/{id}/onstart",
 
 	Get: APIEndpointAction{Handler: internalContainerOnStart},
 }
 
 var internalContainerOnStopNSCmd = APIEndpoint{
-	Name: "containers/{id}/onstopns",
+	Path: "containers/{id}/onstopns",
 
 	Get: APIEndpointAction{Handler: internalContainerOnStopNS},
 }
 
 var internalContainerOnStopCmd = APIEndpoint{
-	Name: "containers/{id}/onstop",
+	Path: "containers/{id}/onstop",
 
 	Get: APIEndpointAction{Handler: internalContainerOnStop},
 }
 
 var internalSQLCmd = APIEndpoint{
-	Name: "sql",
+	Path: "sql",
 
 	Get:  APIEndpointAction{Handler: internalSQLGet},
 	Post: APIEndpointAction{Handler: internalSQLPost},
 }
 
 var internalContainersCmd = APIEndpoint{
-	Name: "containers",
+	Path: "containers",
 
 	Post: APIEndpointAction{Handler: internalImport},
 }
 
 var internalGarbageCollectorCmd = APIEndpoint{
-	Name: "gc",
+	Path: "gc",
 
 	Get: APIEndpointAction{Handler: internalGC},
 }
 
 var internalRAFTSnapshotCmd = APIEndpoint{
-	Name: "raft-snapshot",
+	Path: "raft-snapshot",
 
 	Get: APIEndpointAction{Handler: internalRAFTSnapshot},
 }
diff --git a/lxd/api_project.go b/lxd/api_project.go
index 12f0e76d2c..4802c1d15c 100644
--- a/lxd/api_project.go
+++ b/lxd/api_project.go
@@ -19,14 +19,14 @@ import (
 )
 
 var projectsCmd = APIEndpoint{
-	Name: "projects",
+	Path: "projects",
 
 	Get:  APIEndpointAction{Handler: projectsGet, AccessHandler: AllowAuthenticated},
 	Post: APIEndpointAction{Handler: projectsPost},
 }
 
 var projectCmd = APIEndpoint{
-	Name: "projects/{name}",
+	Path: "projects/{name}",
 
 	Delete: APIEndpointAction{Handler: projectDelete},
 	Get:    APIEndpointAction{Handler: projectGet, AccessHandler: AllowAuthenticated},
diff --git a/lxd/certificates.go b/lxd/certificates.go
index 2eb131311f..3630ec59ec 100644
--- a/lxd/certificates.go
+++ b/lxd/certificates.go
@@ -25,14 +25,14 @@ import (
 )
 
 var certificatesCmd = APIEndpoint{
-	Name: "certificates",
+	Path: "certificates",
 
 	Get:  APIEndpointAction{Handler: certificatesGet, AccessHandler: AllowAuthenticated},
 	Post: APIEndpointAction{Handler: certificatesPost, AllowUntrusted: true},
 }
 
 var certificateCmd = APIEndpoint{
-	Name: "certificates/{fingerprint}",
+	Path: "certificates/{fingerprint}",
 
 	Delete: APIEndpointAction{Handler: certificateDelete},
 	Get:    APIEndpointAction{Handler: certificateGet, AccessHandler: AllowAuthenticated},
diff --git a/lxd/container_logs.go b/lxd/container_logs.go
index 54d2d478ba..92e026d3e2 100644
--- a/lxd/container_logs.go
+++ b/lxd/container_logs.go
@@ -13,15 +13,19 @@ import (
 	"github.com/lxc/lxd/shared/version"
 )
 
-var containerLogCmd = APIEndpoint{
-	Name: "containers/{name}/logs/{file}",
+var instanceLogCmd = APIEndpoint{
+	Name:    "instanceLog",
+	Path:    "instances/{name}/logs/{file}",
+	Aliases: []APIEndpointAlias{{Name: "containerLog", Path: "containers/{name}/logs/{file}"}},
 
 	Delete: APIEndpointAction{Handler: containerLogDelete, AccessHandler: AllowProjectPermission("containers", "operate-containers")},
 	Get:    APIEndpointAction{Handler: containerLogGet, AccessHandler: AllowProjectPermission("containers", "view")},
 }
 
-var containerLogsCmd = APIEndpoint{
-	Name: "containers/{name}/logs",
+var instanceLogsCmd = APIEndpoint{
+	Name:    "instanceLogs",
+	Path:    "instances/{name}/logs",
+	Aliases: []APIEndpointAlias{{Name: "containerLogs", Path: "containers/{name}/logs"}},
 
 	Get: APIEndpointAction{Handler: containerLogsGet, AccessHandler: AllowProjectPermission("containers", "view")},
 }
diff --git a/lxd/container_post.go b/lxd/container_post.go
index 8bd33b2dfa..3865b646c1 100644
--- a/lxd/container_post.go
+++ b/lxd/container_post.go
@@ -21,7 +21,7 @@ import (
 )
 
 var internalClusterContainerMovedCmd = APIEndpoint{
-	Name: "cluster/container-moved/{name}",
+	Path: "cluster/container-moved/{name}",
 
 	Post: APIEndpointAction{Handler: internalClusterContainerMovedPost},
 }
diff --git a/lxd/containers.go b/lxd/containers.go
index 7468e3c33f..2bbb0897c1 100644
--- a/lxd/containers.go
+++ b/lxd/containers.go
@@ -16,15 +16,19 @@ import (
 	log "github.com/lxc/lxd/shared/log15"
 )
 
-var containersCmd = APIEndpoint{
-	Name: "containers",
+var instancesCmd = APIEndpoint{
+	Name:    "instances",
+	Path:    "instances",
+	Aliases: []APIEndpointAlias{{Name: "containers", Path: "containers"}},
 
 	Get:  APIEndpointAction{Handler: containersGet, AccessHandler: AllowProjectPermission("containers", "view")},
 	Post: APIEndpointAction{Handler: containersPost, AccessHandler: AllowProjectPermission("containers", "manage-containers")},
 }
 
-var containerCmd = APIEndpoint{
-	Name: "containers/{name}",
+var instanceCmd = APIEndpoint{
+	Name:    "instance",
+	Path:    "instances/{name}",
+	Aliases: []APIEndpointAlias{{Name: "container", Path: "containers/{name}"}},
 
 	Get:    APIEndpointAction{Handler: containerGet, AccessHandler: AllowProjectPermission("containers", "view")},
 	Put:    APIEndpointAction{Handler: containerPut, AccessHandler: AllowProjectPermission("containers", "manage-containers")},
@@ -33,30 +37,38 @@ var containerCmd = APIEndpoint{
 	Patch:  APIEndpointAction{Handler: containerPatch, AccessHandler: AllowProjectPermission("containers", "manage-containers")},
 }
 
-var containerStateCmd = APIEndpoint{
-	Name: "containers/{name}/state",
+var instanceStateCmd = APIEndpoint{
+	Name:    "instanceState",
+	Path:    "instances/{name}/state",
+	Aliases: []APIEndpointAlias{{Name: "containerState", Path: "containers/{name}/state"}},
 
 	Get: APIEndpointAction{Handler: containerState, AccessHandler: AllowProjectPermission("containers", "view")},
 	Put: APIEndpointAction{Handler: containerStatePut, AccessHandler: AllowProjectPermission("containers", "operate-containers")},
 }
 
-var containerFileCmd = APIEndpoint{
-	Name: "containers/{name}/files",
+var instanceFileCmd = APIEndpoint{
+	Name:    "instanceFile",
+	Path:    "instances/{name}/files",
+	Aliases: []APIEndpointAlias{{Name: "containerFile", Path: "containers/{name}/files"}},
 
 	Get:    APIEndpointAction{Handler: containerFileHandler, AccessHandler: AllowProjectPermission("containers", "operate-containers")},
 	Post:   APIEndpointAction{Handler: containerFileHandler, AccessHandler: AllowProjectPermission("containers", "operate-containers")},
 	Delete: APIEndpointAction{Handler: containerFileHandler, AccessHandler: AllowProjectPermission("containers", "operate-containers")},
 }
 
-var containerSnapshotsCmd = APIEndpoint{
-	Name: "containers/{name}/snapshots",
+var instanceSnapshotsCmd = APIEndpoint{
+	Name:    "instanceSnapshots",
+	Path:    "instances/{name}/snapshots",
+	Aliases: []APIEndpointAlias{{Name: "containerSnapshots", Path: "containers/{name}/snapshots"}},
 
 	Get:  APIEndpointAction{Handler: containerSnapshotsGet, AccessHandler: AllowProjectPermission("containers", "view")},
 	Post: APIEndpointAction{Handler: containerSnapshotsPost, AccessHandler: AllowProjectPermission("containers", "operate-containers")},
 }
 
-var containerSnapshotCmd = APIEndpoint{
-	Name: "containers/{name}/snapshots/{snapshotName}",
+var instanceSnapshotCmd = APIEndpoint{
+	Name:    "instanceSnapshot",
+	Path:    "instances/{name}/snapshots/{snapshotName}",
+	Aliases: []APIEndpointAlias{{Name: "containerSnapshot", Path: "containers/{name}/snapshots/{snapshotName}"}},
 
 	Get:    APIEndpointAction{Handler: containerSnapshotHandler, AccessHandler: AllowProjectPermission("containers", "operate-containers")},
 	Post:   APIEndpointAction{Handler: containerSnapshotHandler, AccessHandler: AllowProjectPermission("containers", "operate-containers")},
@@ -64,29 +76,37 @@ var containerSnapshotCmd = APIEndpoint{
 	Put:    APIEndpointAction{Handler: containerSnapshotHandler, AccessHandler: AllowProjectPermission("containers", "operate-containers")},
 }
 
-var containerConsoleCmd = APIEndpoint{
-	Name: "containers/{name}/console",
+var instanceConsoleCmd = APIEndpoint{
+	Name:    "instanceConsole",
+	Path:    "instances/{name}/console",
+	Aliases: []APIEndpointAlias{{Name: "containerConsole", Path: "containers/{name}/console"}},
 
 	Get:    APIEndpointAction{Handler: containerConsoleLogGet, AccessHandler: AllowProjectPermission("containers", "view")},
 	Post:   APIEndpointAction{Handler: containerConsolePost, AccessHandler: AllowProjectPermission("containers", "operate-containers")},
 	Delete: APIEndpointAction{Handler: containerConsoleLogDelete, AccessHandler: AllowProjectPermission("containers", "operate-containers")},
 }
 
-var containerExecCmd = APIEndpoint{
-	Name: "containers/{name}/exec",
+var instanceExecCmd = APIEndpoint{
+	Name:    "instanceExec",
+	Path:    "instances/{name}/exec",
+	Aliases: []APIEndpointAlias{{Name: "containerExec", Path: "containers/{name}/exec"}},
 
 	Post: APIEndpointAction{Handler: containerExecPost, AccessHandler: AllowProjectPermission("containers", "operate-containers")},
 }
 
-var containerMetadataCmd = APIEndpoint{
-	Name: "containers/{name}/metadata",
+var instanceMetadataCmd = APIEndpoint{
+	Name:    "instanceMetadata",
+	Path:    "instances/{name}/metadata",
+	Aliases: []APIEndpointAlias{{Name: "containerMetadata", Path: "containers/{name}/metadata"}},
 
 	Get: APIEndpointAction{Handler: containerMetadataGet, AccessHandler: AllowProjectPermission("containers", "view")},
 	Put: APIEndpointAction{Handler: containerMetadataPut, AccessHandler: AllowProjectPermission("containers", "manage-containers")},
 }
 
-var containerMetadataTemplatesCmd = APIEndpoint{
-	Name: "containers/{name}/metadata/templates",
+var instanceMetadataTemplatesCmd = APIEndpoint{
+	Name:    "instanceMetadataTemplates",
+	Path:    "instances/{name}/metadata/templates",
+	Aliases: []APIEndpointAlias{{Name: "containerMetadataTemplates", Path: "containers/{name}/metadata/templates"}},
 
 	Get:    APIEndpointAction{Handler: containerMetadataTemplatesGet, AccessHandler: AllowProjectPermission("containers", "view")},
 	Post:   APIEndpointAction{Handler: containerMetadataTemplatesPostPut, AccessHandler: AllowProjectPermission("containers", "manage-containers")},
@@ -94,23 +114,29 @@ var containerMetadataTemplatesCmd = APIEndpoint{
 	Delete: APIEndpointAction{Handler: containerMetadataTemplatesDelete, AccessHandler: AllowProjectPermission("containers", "manage-containers")},
 }
 
-var containerBackupsCmd = APIEndpoint{
-	Name: "containers/{name}/backups",
+var instanceBackupsCmd = APIEndpoint{
+	Name:    "instanceBackups",
+	Path:    "instances/{name}/backups",
+	Aliases: []APIEndpointAlias{{Name: "containerBackups", Path: "containers/{name}/backups"}},
 
 	Get:  APIEndpointAction{Handler: containerBackupsGet, AccessHandler: AllowProjectPermission("containers", "view")},
 	Post: APIEndpointAction{Handler: containerBackupsPost, AccessHandler: AllowProjectPermission("containers", "operate-containers")},
 }
 
-var containerBackupCmd = APIEndpoint{
-	Name: "containers/{name}/backups/{backupName}",
+var instanceBackupCmd = APIEndpoint{
+	Name:    "instanceBackup",
+	Path:    "instances/{name}/backups/{backupName}",
+	Aliases: []APIEndpointAlias{{Name: "containerBackup", Path: "containers/{name}/backups/{backupName}"}},
 
 	Get:    APIEndpointAction{Handler: containerBackupGet, AccessHandler: AllowProjectPermission("containers", "view")},
 	Post:   APIEndpointAction{Handler: containerBackupPost, AccessHandler: AllowProjectPermission("containers", "operate-containers")},
 	Delete: APIEndpointAction{Handler: containerBackupDelete, AccessHandler: AllowProjectPermission("containers", "operate-containers")},
 }
 
-var containerBackupExportCmd = APIEndpoint{
-	Name: "containers/{name}/backups/{backupName}/export",
+var instanceBackupExportCmd = APIEndpoint{
+	Name:    "instanceBackupExport",
+	Path:    "instances/{name}/backups/{backupName}/export",
+	Aliases: []APIEndpointAlias{{Name: "containerBackupExport", Path: "containers/{name}/backups/{backupName}/export"}},
 
 	Get: APIEndpointAction{Handler: containerBackupExportGet, AccessHandler: AllowProjectPermission("containers", "view")},
 }
diff --git a/lxd/events.go b/lxd/events.go
index 9bed552ca6..8040d20a4a 100644
--- a/lxd/events.go
+++ b/lxd/events.go
@@ -19,7 +19,7 @@ import (
 )
 
 var eventsCmd = APIEndpoint{
-	Name: "events",
+	Path: "events",
 
 	Get: APIEndpointAction{Handler: eventsGet, AccessHandler: AllowAuthenticated},
 }
diff --git a/lxd/images.go b/lxd/images.go
index efb35eee83..d5b97ecc89 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -44,14 +44,14 @@ import (
 )
 
 var imagesCmd = APIEndpoint{
-	Name: "images",
+	Path: "images",
 
 	Get:  APIEndpointAction{Handler: imagesGet, AllowUntrusted: true},
 	Post: APIEndpointAction{Handler: imagesPost, AccessHandler: AllowProjectPermission("images", "manage-images")},
 }
 
 var imageCmd = APIEndpoint{
-	Name: "images/{fingerprint}",
+	Path: "images/{fingerprint}",
 
 	Delete: APIEndpointAction{Handler: imageDelete, AccessHandler: AllowProjectPermission("images", "manage-images")},
 	Get:    APIEndpointAction{Handler: imageGet, AllowUntrusted: true},
@@ -60,32 +60,32 @@ var imageCmd = APIEndpoint{
 }
 
 var imageExportCmd = APIEndpoint{
-	Name: "images/{fingerprint}/export",
+	Path: "images/{fingerprint}/export",
 
 	Get: APIEndpointAction{Handler: imageExport, AllowUntrusted: true},
 }
 
 var imageSecretCmd = APIEndpoint{
-	Name: "images/{fingerprint}/secret",
+	Path: "images/{fingerprint}/secret",
 
 	Post: APIEndpointAction{Handler: imageSecret, AccessHandler: AllowProjectPermission("images", "view")},
 }
 
 var imageRefreshCmd = APIEndpoint{
-	Name: "images/{fingerprint}/refresh",
+	Path: "images/{fingerprint}/refresh",
 
 	Post: APIEndpointAction{Handler: imageRefresh, AccessHandler: AllowProjectPermission("images", "manage-images")},
 }
 
 var imageAliasesCmd = APIEndpoint{
-	Name: "images/aliases",
+	Path: "images/aliases",
 
 	Get:  APIEndpointAction{Handler: imageAliasesGet, AccessHandler: AllowProjectPermission("images", "view")},
 	Post: APIEndpointAction{Handler: imageAliasesPost, AccessHandler: AllowProjectPermission("images", "manage-images")},
 }
 
 var imageAliasCmd = APIEndpoint{
-	Name: "images/aliases/{name:.*}",
+	Path: "images/aliases/{name:.*}",
 
 	Delete: APIEndpointAction{Handler: imageAliasDelete, AccessHandler: AllowProjectPermission("images", "manage-images")},
 	Get:    APIEndpointAction{Handler: imageAliasGet, AllowUntrusted: true},
diff --git a/lxd/networks.go b/lxd/networks.go
index 2875232cbe..156c68efe3 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -36,14 +36,14 @@ import (
 var networkCreateLock sync.Mutex
 
 var networksCmd = APIEndpoint{
-	Name: "networks",
+	Path: "networks",
 
 	Get:  APIEndpointAction{Handler: networksGet, AccessHandler: AllowAuthenticated},
 	Post: APIEndpointAction{Handler: networksPost},
 }
 
 var networkCmd = APIEndpoint{
-	Name: "networks/{name}",
+	Path: "networks/{name}",
 
 	Delete: APIEndpointAction{Handler: networkDelete},
 	Get:    APIEndpointAction{Handler: networkGet, AccessHandler: AllowAuthenticated},
@@ -53,13 +53,13 @@ var networkCmd = APIEndpoint{
 }
 
 var networkLeasesCmd = APIEndpoint{
-	Name: "networks/{name}/leases",
+	Path: "networks/{name}/leases",
 
 	Get: APIEndpointAction{Handler: networkLeasesGet, AccessHandler: AllowAuthenticated},
 }
 
 var networkStateCmd = APIEndpoint{
-	Name: "networks/{name}/state",
+	Path: "networks/{name}/state",
 
 	Get: APIEndpointAction{Handler: networkStateGet, AccessHandler: AllowAuthenticated},
 }
diff --git a/lxd/operations.go b/lxd/operations.go
index 8539dae4aa..d0908e31e3 100644
--- a/lxd/operations.go
+++ b/lxd/operations.go
@@ -24,26 +24,26 @@ import (
 )
 
 var operationCmd = APIEndpoint{
-	Name: "operations/{id}",
+	Path: "operations/{id}",
 
 	Delete: APIEndpointAction{Handler: operationDelete, AccessHandler: AllowAuthenticated},
 	Get:    APIEndpointAction{Handler: operationGet, AccessHandler: AllowAuthenticated},
 }
 
 var operationsCmd = APIEndpoint{
-	Name: "operations",
+	Path: "operations",
 
 	Get: APIEndpointAction{Handler: operationsGet, AccessHandler: AllowAuthenticated},
 }
 
 var operationWait = APIEndpoint{
-	Name: "operations/{id}/wait",
+	Path: "operations/{id}/wait",
 
 	Get: APIEndpointAction{Handler: operationWaitGet, AccessHandler: AllowAuthenticated},
 }
 
 var operationWebsocket = APIEndpoint{
-	Name: "operations/{id}/websocket",
+	Path: "operations/{id}/websocket",
 
 	Get: APIEndpointAction{Handler: operationWebsocketGet, AllowUntrusted: true},
 }
diff --git a/lxd/profiles.go b/lxd/profiles.go
index 06755c2fcd..cc2354320d 100644
--- a/lxd/profiles.go
+++ b/lxd/profiles.go
@@ -22,14 +22,14 @@ import (
 )
 
 var profilesCmd = APIEndpoint{
-	Name: "profiles",
+	Path: "profiles",
 
 	Get:  APIEndpointAction{Handler: profilesGet, AccessHandler: AllowProjectPermission("profiles", "view")},
 	Post: APIEndpointAction{Handler: profilesPost, AccessHandler: AllowProjectPermission("profiles", "manage-profiles")},
 }
 
 var profileCmd = APIEndpoint{
-	Name: "profiles/{name}",
+	Path: "profiles/{name}",
 
 	Delete: APIEndpointAction{Handler: profileDelete, AccessHandler: AllowProjectPermission("profiles", "manage-profiles")},
 	Get:    APIEndpointAction{Handler: profileGet, AccessHandler: AllowProjectPermission("profiles", "view")},
diff --git a/lxd/resources.go b/lxd/resources.go
index 58e6a5a3ec..fba15ac86f 100644
--- a/lxd/resources.go
+++ b/lxd/resources.go
@@ -9,13 +9,13 @@ import (
 )
 
 var api10ResourcesCmd = APIEndpoint{
-	Name: "resources",
+	Path: "resources",
 
 	Get: APIEndpointAction{Handler: api10ResourcesGet, AccessHandler: AllowAuthenticated},
 }
 
 var storagePoolResourcesCmd = APIEndpoint{
-	Name: "storage-pools/{name}/resources",
+	Path: "storage-pools/{name}/resources",
 
 	Get: APIEndpointAction{Handler: storagePoolResourcesGet, AccessHandler: AllowAuthenticated},
 }
diff --git a/lxd/storage_pools.go b/lxd/storage_pools.go
index 741bdfa699..443323eee8 100644
--- a/lxd/storage_pools.go
+++ b/lxd/storage_pools.go
@@ -24,14 +24,14 @@ import (
 var storagePoolCreateLock sync.Mutex
 
 var storagePoolsCmd = APIEndpoint{
-	Name: "storage-pools",
+	Path: "storage-pools",
 
 	Get:  APIEndpointAction{Handler: storagePoolsGet, AccessHandler: AllowAuthenticated},
 	Post: APIEndpointAction{Handler: storagePoolsPost},
 }
 
 var storagePoolCmd = APIEndpoint{
-	Name: "storage-pools/{name}",
+	Path: "storage-pools/{name}",
 
 	Delete: APIEndpointAction{Handler: storagePoolDelete},
 	Get:    APIEndpointAction{Handler: storagePoolGet, AccessHandler: AllowAuthenticated},
diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go
index 815b32064f..e9baf04748 100644
--- a/lxd/storage_volumes.go
+++ b/lxd/storage_volumes.go
@@ -22,21 +22,21 @@ import (
 )
 
 var storagePoolVolumesCmd = APIEndpoint{
-	Name: "storage-pools/{name}/volumes",
+	Path: "storage-pools/{name}/volumes",
 
 	Get:  APIEndpointAction{Handler: storagePoolVolumesGet, AccessHandler: AllowAuthenticated},
 	Post: APIEndpointAction{Handler: storagePoolVolumesPost},
 }
 
 var storagePoolVolumesTypeCmd = APIEndpoint{
-	Name: "storage-pools/{name}/volumes/{type}",
+	Path: "storage-pools/{name}/volumes/{type}",
 
 	Get:  APIEndpointAction{Handler: storagePoolVolumesTypeGet, AccessHandler: AllowAuthenticated},
 	Post: APIEndpointAction{Handler: storagePoolVolumesTypePost},
 }
 
 var storagePoolVolumeTypeContainerCmd = APIEndpoint{
-	Name: "storage-pools/{pool}/volumes/container/{name:.*}",
+	Path: "storage-pools/{pool}/volumes/container/{name:.*}",
 
 	Delete: APIEndpointAction{Handler: storagePoolVolumeTypeContainerDelete},
 	Get:    APIEndpointAction{Handler: storagePoolVolumeTypeContainerGet, AccessHandler: AllowAuthenticated},
@@ -46,7 +46,7 @@ var storagePoolVolumeTypeContainerCmd = APIEndpoint{
 }
 
 var storagePoolVolumeTypeCustomCmd = APIEndpoint{
-	Name: "storage-pools/{pool}/volumes/custom/{name}",
+	Path: "storage-pools/{pool}/volumes/custom/{name}",
 
 	Delete: APIEndpointAction{Handler: storagePoolVolumeTypeCustomDelete},
 	Get:    APIEndpointAction{Handler: storagePoolVolumeTypeCustomGet, AccessHandler: AllowAuthenticated},
@@ -56,7 +56,7 @@ var storagePoolVolumeTypeCustomCmd = APIEndpoint{
 }
 
 var storagePoolVolumeTypeImageCmd = APIEndpoint{
-	Name: "storage-pools/{pool}/volumes/image/{name}",
+	Path: "storage-pools/{pool}/volumes/image/{name}",
 
 	Delete: APIEndpointAction{Handler: storagePoolVolumeTypeImageDelete},
 	Get:    APIEndpointAction{Handler: storagePoolVolumeTypeImageGet, AccessHandler: AllowAuthenticated},
diff --git a/lxd/storage_volumes_snapshot.go b/lxd/storage_volumes_snapshot.go
index 8c3c8b6de3..7a5ff87ee7 100644
--- a/lxd/storage_volumes_snapshot.go
+++ b/lxd/storage_volumes_snapshot.go
@@ -17,14 +17,14 @@ import (
 )
 
 var storagePoolVolumeSnapshotsTypeCmd = APIEndpoint{
-	Name: "storage-pools/{pool}/volumes/{type}/{name}/snapshots",
+	Path: "storage-pools/{pool}/volumes/{type}/{name}/snapshots",
 
 	Get:  APIEndpointAction{Handler: storagePoolVolumeSnapshotsTypeGet, AccessHandler: AllowAuthenticated},
 	Post: APIEndpointAction{Handler: storagePoolVolumeSnapshotsTypePost},
 }
 
 var storagePoolVolumeSnapshotTypeCmd = APIEndpoint{
-	Name: "storage-pools/{pool}/volumes/{type}/{name}/snapshots/{snapshotName}",
+	Path: "storage-pools/{pool}/volumes/{type}/{name}/snapshots/{snapshotName}",
 
 	Delete: APIEndpointAction{Handler: storagePoolVolumeSnapshotTypeDelete},
 	Get:    APIEndpointAction{Handler: storagePoolVolumeSnapshotTypeGet, AccessHandler: AllowAuthenticated},


More information about the lxc-devel mailing list