[lxc-devel] [lxd/master] Fix volume creation API

stgraber on Github lxc-bot at linuxcontainers.org
Wed Jul 4 03:20:27 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180704/df258bcd/attachment.bin>
-------------- next part --------------
From dd82f404a5728d69cbc6de375f8f7b8e55e09fd8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 3 Jul 2018 12:25:44 -0400
Subject: [PATCH 1/3] lxc/cluster: Remove bad alias
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxc/cluster.go | 1 -
 1 file changed, 1 deletion(-)

diff --git a/lxc/cluster.go b/lxc/cluster.go
index ce7e7e8ef..ec20cfe6b 100644
--- a/lxc/cluster.go
+++ b/lxc/cluster.go
@@ -285,7 +285,6 @@ type cmdClusterEnable struct {
 func (c *cmdClusterEnable) Command() *cobra.Command {
 	cmd := &cobra.Command{}
 	cmd.Use = i18n.G("enable [<remote>:] <name>")
-	cmd.Aliases = []string{"rm"}
 	cmd.Short = i18n.G("Enable clustering on a single non-clustered LXD instance")
 	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
 		`Enable clustering on a single non-clustered LXD instance

From 4fe32c14dba37d872712cc27138f5edd3266509b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 3 Jul 2018 21:13:25 -0400
Subject: [PATCH 2/3] doc: Fix storage volume examples
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #4723

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 doc/rest-api.md | 46 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 42 insertions(+), 4 deletions(-)

diff --git a/doc/rest-api.md b/doc/rest-api.md
index 7bbdd984c..3c8d2f98e 100644
--- a/doc/rest-api.md
+++ b/doc/rest-api.md
@@ -219,7 +219,8 @@ won't work and PUT needs to be used instead.
        * [`/1.0/storage-pools/<name>`](#10storage-poolsname)
          * [`/1.0/storage-pools/<name>/resources`](#10storage-poolsnameresources)
          * [`/1.0/storage-pools/<name>/volumes`](#10storage-poolsnamevolumes)
-           * [`/1.0/storage-pools/<pool>/volumes/<type>/<name>`](#10storage-poolspoolvolumestypename)
+           * [`/1.0/storage-pools/<name>/volumes/<type>`](#10storage-poolsnamevolumestype)
+             * [`/1.0/storage-pools/<pool>/volumes/<type>/<name>`](#10storage-poolspoolvolumestypename)
      * [`/1.0/resources`](#10resources)
      * [`/1.0/cluster`](#10cluster)
        * [`/1.0/cluster/members`](#10clustermembers)
@@ -2431,7 +2432,6 @@ Input:
 
     {
         "config": {},
-        "pool": "pool1",
         "name": "vol1",
         "type": "custom"
     }
@@ -2440,7 +2440,6 @@ Input (when copying a volume):
 
     {
         "config": {},
-        "pool": "pool1",
         "name": "vol1",
         "type": "custom"
         "source": {
@@ -2454,7 +2453,6 @@ Input (when migrating a volume):
 
     {
         "config": {},
-        "pool": "pool1",
         "name": "vol1",
         "type": "custom"
         "source": {
@@ -2465,6 +2463,46 @@ Input (when migrating a volume):
         }
     }
 
+## `/1.0/storage-pools/<pool>/volumes/<type>`
+### POST
+ * Description: create a new storage volume of a particular type on a given storage pool
+ * Introduced: with API extension `storage`
+ * Authentication: trusted
+ * Operation: sync or async (when copying an existing volume)
+ * Return: standard return value or standard error
+
+Input:
+
+    {
+        "config": {},
+        "name": "vol1",
+    }
+
+Input (when copying a volume):
+
+    {
+        "config": {},
+        "name": "vol1",
+        "source": {
+            "pool": "pool2",
+            "name": "vol2",
+            "type": "copy"
+        }
+    }
+
+Input (when migrating a volume):
+
+    {
+        "config": {},
+        "name": "vol1",
+        "source": {
+            "pool": "pool2",
+            "name": "vol2",
+            "type": "migration"
+            "mode": "pull",                                                 # One of "pull" (default), "push", "relay"
+        }
+    }
+
 ## `/1.0/storage-pools/<pool>/volumes/<type>/<name>`
 ### POST
  * Description: rename a storage volume on a given storage pool

From c87dac872d473d1b03e442d923693835dc877136 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 3 Jul 2018 23:19:48 -0400
Subject: [PATCH 3/3] lxd/storage: Fix volume creation API
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #4723

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/storage_volumes.go | 64 ++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 57 insertions(+), 7 deletions(-)

diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go
index ef97153d5..8d7ac4fc4 100644
--- a/lxd/storage_volumes.go
+++ b/lxd/storage_volumes.go
@@ -67,7 +67,7 @@ func storagePoolVolumesGet(d *Daemon, r *http.Request) Response {
 	return SyncResponse(true, volumes)
 }
 
-var storagePoolVolumesCmd = Command{name: "storage-pools/{name}/volumes", get: storagePoolVolumesGet}
+var storagePoolVolumesCmd = Command{name: "storage-pools/{name}/volumes", get: storagePoolVolumesGet, post: storagePoolVolumesPost}
 
 // /1.0/storage-pools/{name}/volumes/{type}
 // List all storage volumes of a given volume type for a given storage pool.
@@ -138,7 +138,7 @@ func storagePoolVolumesTypeGet(d *Daemon, r *http.Request) Response {
 }
 
 // /1.0/storage-pools/{name}/volumes/{type}
-// Create a storage volume of a given volume type in a given storage pool.
+// Create a storage volume in a given storage pool.
 func storagePoolVolumesTypePost(d *Daemon, r *http.Request) Response {
 	response := ForwardedResponseIfTargetIsRemote(d, r)
 	if response != nil {
@@ -162,11 +162,7 @@ func storagePoolVolumesTypePost(d *Daemon, r *http.Request) Response {
 		return BadRequest(fmt.Errorf("Storage volume names may not contain slashes"))
 	}
 
-	// Check that the user gave use a storage volume type for the storage
-	// volume we are about to create.
-	if req.Type == "" {
-		return BadRequest(fmt.Errorf("you must provide a storage volume type of the storage volume"))
-	}
+	req.Type = mux.Vars(r)["type"]
 
 	// We currently only allow to create storage volumes of type
 	// storagePoolVolumeTypeCustom. So check, that nothing else was
@@ -218,6 +214,60 @@ func doVolumeCreateOrCopy(d *Daemon, poolName string, req *api.StorageVolumesPos
 	}
 
 	return OperationResponse(op)
+
+}
+
+// /1.0/storage-pools/{name}/volumes/{type}
+// Create a storage volume of a given volume type in a given storage pool.
+func storagePoolVolumesPost(d *Daemon, r *http.Request) Response {
+	response := ForwardedResponseIfTargetIsRemote(d, r)
+	if response != nil {
+		return response
+	}
+
+	req := api.StorageVolumesPost{}
+
+	// Parse the request.
+	err := json.NewDecoder(r.Body).Decode(&req)
+	if err != nil {
+		return BadRequest(err)
+	}
+
+	// Sanity checks.
+	if req.Name == "" {
+		return BadRequest(fmt.Errorf("No name provided"))
+	}
+
+	if strings.Contains(req.Name, "/") {
+		return BadRequest(fmt.Errorf("Storage volume names may not contain slashes"))
+	}
+
+	// Check that the user gave use a storage volume type for the storage
+	// volume we are about to create.
+	if req.Type == "" {
+		return BadRequest(fmt.Errorf("You must provide a storage volume type of the storage volume"))
+	}
+
+	// We currently only allow to create storage volumes of type
+	// storagePoolVolumeTypeCustom. So check, that nothing else was
+	// requested.
+	if req.Type != storagePoolVolumeTypeNameCustom {
+		return BadRequest(fmt.Errorf(`Currently not allowed to create `+
+			`storage volumes of type %s`, req.Type))
+	}
+
+	poolName := mux.Vars(r)["name"]
+
+	switch req.Source.Type {
+	case "":
+		return doVolumeCreateOrCopy(d, poolName, &req)
+	case "copy":
+		return doVolumeCreateOrCopy(d, poolName, &req)
+	case "migration":
+		return doVolumeMigration(d, poolName, &req)
+	default:
+		return BadRequest(fmt.Errorf("unknown source type %s", req.Source.Type))
+	}
 }
 
 func doVolumeMigration(d *Daemon, poolName string, req *api.StorageVolumesPost) Response {


More information about the lxc-devel mailing list