[lxc-devel] [lxd/master] Various bugfixes (doc, makefile, interface names and URL escaping)

stgraber on Github lxc-bot at linuxcontainers.org
Wed Dec 6 05:13:47 UTC 2017


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/20171206/add9791f/attachment.bin>
-------------- next part --------------
From c4441a537cd1257a525dbd9cee4acd9ced0077fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 5 Dec 2017 18:29:40 -0500
Subject: [PATCH 1/4] doc: Fix markdown escaping for prlimits
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>
---
 doc/containers.md | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/doc/containers.md b/doc/containers.md
index 5e0855d8b..c232e4ec3 100644
--- a/doc/containers.md
+++ b/doc/containers.md
@@ -360,18 +360,18 @@ supported limit on their system. Some common limits are:
 
 Key                      | Resource          | Description
 :--                      | :---              | :----------
-limits.kernel.as         | RLIMIT_AS         | Maximum size of the process's virtual memory
-limits.kernel.core       | RLIMIT_CORE       | Maximum size of the process's coredump file
-limits.kernel.cpu        | RLIMIT_CPU        | Limit in seconds on the amount of cpu time the process can consume
-limits.kernel.data       | RLIMIT_DATA       | Maximum size of the process's data segment
-limits.kernel.fsize      | RLIMIT_FSIZE      | Maximum size of files the process may create
-limits.kernel.locks      | RLIMIT_LOCKS      | Limit on the number of file locks that this process may establish
-limits.kernel.memlock    | RLIMIT_MEMLOCK    | Limit on the number of bytes of memory that the process may lock in RAM
-limits.kernel.nice       | RLIMIT_NICE       | Maximum value to which the process's nice value can be raised
-limits.kernel.nofile     | RLIMIT_NOFILE     | Maximum number of open files for the process
-limits.kernel.nproc      | RLIMIT_NPROC      | Maximum number of processes that can be created for the user of the calling process
-limits.kernel.rtprio     | RLIMIT_RTPRIO     | Maximum value on the real-time-priority that maybe set for this process
-limits.kernel.sigpending | RLIMIT_SIGPENDING | Maximum number of signals that maybe queued for the user of the calling process
+limits.kernel.as         | RLIMIT\_AS         | Maximum size of the process's virtual memory
+limits.kernel.core       | RLIMIT\_CORE       | Maximum size of the process's coredump file
+limits.kernel.cpu        | RLIMIT\_CPU        | Limit in seconds on the amount of cpu time the process can consume
+limits.kernel.data       | RLIMIT\_DATA       | Maximum size of the process's data segment
+limits.kernel.fsize      | RLIMIT\_FSIZE      | Maximum size of files the process may create
+limits.kernel.locks      | RLIMIT\_LOCKS      | Limit on the number of file locks that this process may establish
+limits.kernel.memlock    | RLIMIT\_MEMLOCK    | Limit on the number of bytes of memory that the process may lock in RAM
+limits.kernel.nice       | RLIMIT\_NICE       | Maximum value to which the process's nice value can be raised
+limits.kernel.nofile     | RLIMIT\_NOFILE     | Maximum number of open files for the process
+limits.kernel.nproc      | RLIMIT\_NPROC      | Maximum number of processes that can be created for the user of the calling process
+limits.kernel.rtprio     | RLIMIT\_RTPRIO     | Maximum value on the real-time-priority that maybe set for this process
+limits.kernel.sigpending | RLIMIT\_SIGPENDING | Maximum number of signals that maybe queued for the user of the calling process
 
 A full list of all available limits can be found in the manpages for the
 `getrlimit(2)`/`setrlimit(2)` system calls. To specify a limit within the

From ac5d69d67ca5c5b0813b2865e9800e697b513468 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 5 Dec 2017 22:10:07 -0500
Subject: [PATCH 2/4] Makefile: Better detect sqlite3.h
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #4078

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 0491e8623..51b83c8ba 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ POTFILE=po/$(DOMAIN).pot
 # TODO: use git describe for versioning
 VERSION=$(shell grep "var Version" shared/version/flex.go | cut -d'"' -f2)
 ARCHIVE=lxd-$(VERSION).tar
-TAGS=$(shell test -e /usr/include/sqlite3.h && echo "-tags libsqlite3")
+TAGS=$(shell printf "\#include <sqlite3.h>\nvoid main(){}" | gcc -o /dev/null -xc - >/dev/null 2>&1 && echo "-tags libsqlite3")
 
 .PHONY: default
 default:

From edc4227e28b75775596324afda2eb62b06a83434 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 5 Dec 2017 22:18:50 -0500
Subject: [PATCH 3/4] networks: Extend allowed character set for interfaces
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #4042

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/networks_utils.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/networks_utils.go b/lxd/networks_utils.go
index fa7c0fd9b..20b9b9024 100644
--- a/lxd/networks_utils.go
+++ b/lxd/networks_utils.go
@@ -472,7 +472,7 @@ func networkValidName(value string) error {
 	}
 
 	// Validate the character set
-	match, _ := regexp.MatchString("^[-a-zA-Z0-9]*$", value)
+	match, _ := regexp.MatchString("^[-_a-zA-Z0-9.]*$", value)
 	if !match {
 		return fmt.Errorf("Interface name contains invalid characters")
 	}

From da8878bdaf644f797e7c0853c97592b2c0499e9e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 5 Dec 2017 23:54:18 -0500
Subject: [PATCH 4/4] client: URL escape all user input
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #4077

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 client/lxd_certificates.go    |  7 ++--
 client/lxd_containers.go      | 81 ++++++++++++++++++++-----------------------
 client/lxd_images.go          | 26 +++++++-------
 client/lxd_networks.go        |  9 ++---
 client/lxd_operations.go      |  9 ++---
 client/lxd_profiles.go        |  9 ++---
 client/lxd_storage_pools.go   |  9 ++---
 client/lxd_storage_volumes.go | 19 +++++-----
 8 files changed, 85 insertions(+), 84 deletions(-)

diff --git a/client/lxd_certificates.go b/client/lxd_certificates.go
index bf5349599..1c036b523 100644
--- a/client/lxd_certificates.go
+++ b/client/lxd_certificates.go
@@ -2,6 +2,7 @@ package lxd
 
 import (
 	"fmt"
+	"net/url"
 	"strings"
 
 	"github.com/lxc/lxd/shared/api"
@@ -47,7 +48,7 @@ func (r *ProtocolLXD) GetCertificate(fingerprint string) (*api.Certificate, stri
 	certificate := api.Certificate{}
 
 	// Fetch the raw value
-	etag, err := r.queryStruct("GET", fmt.Sprintf("/certificates/%s", fingerprint), nil, "", &certificate)
+	etag, err := r.queryStruct("GET", fmt.Sprintf("/certificates/%s", url.QueryEscape(fingerprint)), nil, "", &certificate)
 	if err != nil {
 		return nil, "", err
 	}
@@ -73,7 +74,7 @@ func (r *ProtocolLXD) UpdateCertificate(fingerprint string, certificate api.Cert
 	}
 
 	// Send the request
-	_, _, err := r.query("PUT", fmt.Sprintf("/certificates/%s", fingerprint), certificate, ETag)
+	_, _, err := r.query("PUT", fmt.Sprintf("/certificates/%s", url.QueryEscape(fingerprint)), certificate, ETag)
 	if err != nil {
 		return err
 	}
@@ -84,7 +85,7 @@ func (r *ProtocolLXD) UpdateCertificate(fingerprint string, certificate api.Cert
 // DeleteCertificate removes a certificate from the LXD trust store
 func (r *ProtocolLXD) DeleteCertificate(fingerprint string) error {
 	// Send the request
-	_, _, err := r.query("DELETE", fmt.Sprintf("/certificates/%s", fingerprint), nil, "")
+	_, _, err := r.query("DELETE", fmt.Sprintf("/certificates/%s", url.QueryEscape(fingerprint)), nil, "")
 	if err != nil {
 		return err
 	}
diff --git a/client/lxd_containers.go b/client/lxd_containers.go
index 50a52d28a..04585e135 100644
--- a/client/lxd_containers.go
+++ b/client/lxd_containers.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"io"
 	"net/http"
+	"net/url"
 	"strings"
 
 	"github.com/gorilla/websocket"
@@ -53,7 +54,7 @@ func (r *ProtocolLXD) GetContainer(name string) (*api.Container, string, error)
 	container := api.Container{}
 
 	// Fetch the raw value
-	etag, err := r.queryStruct("GET", fmt.Sprintf("/containers/%s", name), nil, "", &container)
+	etag, err := r.queryStruct("GET", fmt.Sprintf("/containers/%s", url.QueryEscape(name)), nil, "", &container)
 	if err != nil {
 		return nil, "", err
 	}
@@ -97,7 +98,7 @@ func (r *ProtocolLXD) tryCreateContainer(req api.ContainersPost, urls []string)
 			if operation == "" {
 				req.Source.Server = serverURL
 			} else {
-				req.Source.Operation = fmt.Sprintf("%s/1.0/operations/%s", serverURL, operation)
+				req.Source.Operation = fmt.Sprintf("%s/1.0/operations/%s", serverURL, url.QueryEscape(operation))
 			}
 
 			op, err := r.CreateContainer(req)
@@ -462,7 +463,7 @@ func (r *ProtocolLXD) proxyMigration(targetOp *Operation, targetSecrets map[stri
 // UpdateContainer updates the container definition
 func (r *ProtocolLXD) UpdateContainer(name string, container api.ContainerPut, ETag string) (*Operation, error) {
 	// Send the request
-	op, _, err := r.queryOperation("PUT", fmt.Sprintf("/containers/%s", name), container, ETag)
+	op, _, err := r.queryOperation("PUT", fmt.Sprintf("/containers/%s", url.QueryEscape(name)), container, ETag)
 	if err != nil {
 		return nil, err
 	}
@@ -478,7 +479,7 @@ func (r *ProtocolLXD) RenameContainer(name string, container api.ContainerPost)
 	}
 
 	// Send the request
-	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s", name), container, "")
+	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s", url.QueryEscape(name)), container, "")
 	if err != nil {
 		return nil, err
 	}
@@ -502,7 +503,7 @@ func (r *ProtocolLXD) tryMigrateContainer(source ContainerServer, name string, r
 		success := false
 		errors := []string{}
 		for _, serverURL := range urls {
-			req.Target.Operation = fmt.Sprintf("%s/1.0/operations/%s", serverURL, operation)
+			req.Target.Operation = fmt.Sprintf("%s/1.0/operations/%s", serverURL, url.QueryEscape(operation))
 
 			op, err := source.MigrateContainer(name, req)
 			if err != nil {
@@ -550,7 +551,7 @@ func (r *ProtocolLXD) MigrateContainer(name string, container api.ContainerPost)
 	}
 
 	// Send the request
-	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s", name), container, "")
+	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s", url.QueryEscape(name)), container, "")
 	if err != nil {
 		return nil, err
 	}
@@ -561,7 +562,7 @@ func (r *ProtocolLXD) MigrateContainer(name string, container api.ContainerPost)
 // DeleteContainer requests that LXD deletes the container
 func (r *ProtocolLXD) DeleteContainer(name string) (*Operation, error) {
 	// Send the request
-	op, _, err := r.queryOperation("DELETE", fmt.Sprintf("/containers/%s", name), nil, "")
+	op, _, err := r.queryOperation("DELETE", fmt.Sprintf("/containers/%s", url.QueryEscape(name)), nil, "")
 	if err != nil {
 		return nil, err
 	}
@@ -578,7 +579,7 @@ func (r *ProtocolLXD) ExecContainer(containerName string, exec api.ContainerExec
 	}
 
 	// Send the request
-	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s/exec", containerName), exec, "")
+	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s/exec", url.QueryEscape(containerName)), exec, "")
 	if err != nil {
 		return nil, err
 	}
@@ -701,7 +702,7 @@ func (r *ProtocolLXD) ExecContainer(containerName string, exec api.ContainerExec
 func (r *ProtocolLXD) GetContainerFile(containerName string, path string) (io.ReadCloser, *ContainerFileResponse, error) {
 	// Prepare the HTTP request
 	requestURL, err := shared.URLEncode(
-		fmt.Sprintf("%s/1.0/containers/%s/files", r.httpHost, containerName),
+		fmt.Sprintf("%s/1.0/containers/%s/files", r.httpHost, url.QueryEscape(containerName)),
 		map[string]string{"path": path})
 	if err != nil {
 		return nil, nil, err
@@ -786,13 +787,7 @@ func (r *ProtocolLXD) CreateContainerFile(containerName string, path string, arg
 	}
 
 	// Prepare the HTTP request
-	requestURL, err := shared.URLEncode(
-		fmt.Sprintf("%s/1.0/containers/%s/files", r.httpHost, containerName),
-		map[string]string{"path": path})
-	if err != nil {
-		return err
-	}
-	req, err := http.NewRequest("POST", requestURL, args.Content)
+	req, err := http.NewRequest("POST", fmt.Sprintf("%s/1.0/containers/%s/files?path=%s", r.httpHost, url.QueryEscape(containerName), url.QueryEscape(path)), args.Content)
 	if err != nil {
 		return err
 	}
@@ -845,7 +840,7 @@ func (r *ProtocolLXD) DeleteContainerFile(containerName string, path string) err
 	}
 
 	// Send the request
-	_, _, err := r.query("DELETE", fmt.Sprintf("/containers/%s/files?path=%s", containerName, path), nil, "")
+	_, _, err := r.query("DELETE", fmt.Sprintf("/containers/%s/files?path=%s", url.QueryEscape(containerName), url.QueryEscape(path)), nil, "")
 	if err != nil {
 		return err
 	}
@@ -858,15 +853,15 @@ func (r *ProtocolLXD) GetContainerSnapshotNames(containerName string) ([]string,
 	urls := []string{}
 
 	// Fetch the raw value
-	_, err := r.queryStruct("GET", fmt.Sprintf("/containers/%s/snapshots", containerName), nil, "", &urls)
+	_, err := r.queryStruct("GET", fmt.Sprintf("/containers/%s/snapshots", url.QueryEscape(containerName)), nil, "", &urls)
 	if err != nil {
 		return nil, err
 	}
 
 	// Parse it
 	names := []string{}
-	for _, url := range urls {
-		fields := strings.Split(url, fmt.Sprintf("/containers/%s/snapshots/", containerName))
+	for _, uri := range urls {
+		fields := strings.Split(uri, fmt.Sprintf("/containers/%s/snapshots/", url.QueryEscape(containerName)))
 		names = append(names, fields[len(fields)-1])
 	}
 
@@ -878,7 +873,7 @@ func (r *ProtocolLXD) GetContainerSnapshots(containerName string) ([]api.Contain
 	snapshots := []api.ContainerSnapshot{}
 
 	// Fetch the raw value
-	_, err := r.queryStruct("GET", fmt.Sprintf("/containers/%s/snapshots?recursion=1", containerName), nil, "", &snapshots)
+	_, err := r.queryStruct("GET", fmt.Sprintf("/containers/%s/snapshots?recursion=1", url.QueryEscape(containerName)), nil, "", &snapshots)
 	if err != nil {
 		return nil, err
 	}
@@ -891,7 +886,7 @@ func (r *ProtocolLXD) GetContainerSnapshot(containerName string, name string) (*
 	snapshot := api.ContainerSnapshot{}
 
 	// Fetch the raw value
-	etag, err := r.queryStruct("GET", fmt.Sprintf("/containers/%s/snapshots/%s", containerName, name), nil, "", &snapshot)
+	etag, err := r.queryStruct("GET", fmt.Sprintf("/containers/%s/snapshots/%s", url.QueryEscape(containerName), url.QueryEscape(name)), nil, "", &snapshot)
 	if err != nil {
 		return nil, "", err
 	}
@@ -902,7 +897,7 @@ func (r *ProtocolLXD) GetContainerSnapshot(containerName string, name string) (*
 // CreateContainerSnapshot requests that LXD creates a new snapshot for the container
 func (r *ProtocolLXD) CreateContainerSnapshot(containerName string, snapshot api.ContainerSnapshotsPost) (*Operation, error) {
 	// Send the request
-	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s/snapshots", containerName), snapshot, "")
+	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s/snapshots", url.QueryEscape(containerName)), snapshot, "")
 	if err != nil {
 		return nil, err
 	}
@@ -1100,7 +1095,7 @@ func (r *ProtocolLXD) RenameContainerSnapshot(containerName string, name string,
 	}
 
 	// Send the request
-	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s/snapshots/%s", containerName, name), container, "")
+	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s/snapshots/%s", url.QueryEscape(containerName), url.QueryEscape(name)), container, "")
 	if err != nil {
 		return nil, err
 	}
@@ -1124,7 +1119,7 @@ func (r *ProtocolLXD) tryMigrateContainerSnapshot(source ContainerServer, contai
 		success := false
 		errors := []string{}
 		for _, serverURL := range urls {
-			req.Target.Operation = fmt.Sprintf("%s/1.0/operations/%s", serverURL, operation)
+			req.Target.Operation = fmt.Sprintf("%s/1.0/operations/%s", serverURL, url.QueryEscape(operation))
 
 			op, err := source.MigrateContainerSnapshot(containerName, name, req)
 			if err != nil {
@@ -1166,7 +1161,7 @@ func (r *ProtocolLXD) MigrateContainerSnapshot(containerName string, name string
 	}
 
 	// Send the request
-	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s/snapshots/%s", containerName, name), container, "")
+	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s/snapshots/%s", url.QueryEscape(containerName), url.QueryEscape(name)), container, "")
 	if err != nil {
 		return nil, err
 	}
@@ -1177,7 +1172,7 @@ func (r *ProtocolLXD) MigrateContainerSnapshot(containerName string, name string
 // DeleteContainerSnapshot requests that LXD deletes the container snapshot
 func (r *ProtocolLXD) DeleteContainerSnapshot(containerName string, name string) (*Operation, error) {
 	// Send the request
-	op, _, err := r.queryOperation("DELETE", fmt.Sprintf("/containers/%s/snapshots/%s", containerName, name), nil, "")
+	op, _, err := r.queryOperation("DELETE", fmt.Sprintf("/containers/%s/snapshots/%s", url.QueryEscape(containerName), url.QueryEscape(name)), nil, "")
 	if err != nil {
 		return nil, err
 	}
@@ -1190,7 +1185,7 @@ func (r *ProtocolLXD) GetContainerState(name string) (*api.ContainerState, strin
 	state := api.ContainerState{}
 
 	// Fetch the raw value
-	etag, err := r.queryStruct("GET", fmt.Sprintf("/containers/%s/state", name), nil, "", &state)
+	etag, err := r.queryStruct("GET", fmt.Sprintf("/containers/%s/state", url.QueryEscape(name)), nil, "", &state)
 	if err != nil {
 		return nil, "", err
 	}
@@ -1201,7 +1196,7 @@ func (r *ProtocolLXD) GetContainerState(name string) (*api.ContainerState, strin
 // UpdateContainerState updates the container to match the requested state
 func (r *ProtocolLXD) UpdateContainerState(name string, state api.ContainerStatePut, ETag string) (*Operation, error) {
 	// Send the request
-	op, _, err := r.queryOperation("PUT", fmt.Sprintf("/containers/%s/state", name), state, ETag)
+	op, _, err := r.queryOperation("PUT", fmt.Sprintf("/containers/%s/state", url.QueryEscape(name)), state, ETag)
 	if err != nil {
 		return nil, err
 	}
@@ -1214,15 +1209,15 @@ func (r *ProtocolLXD) GetContainerLogfiles(name string) ([]string, error) {
 	urls := []string{}
 
 	// Fetch the raw value
-	_, err := r.queryStruct("GET", fmt.Sprintf("/containers/%s/logs", name), nil, "", &urls)
+	_, err := r.queryStruct("GET", fmt.Sprintf("/containers/%s/logs", url.QueryEscape(name)), nil, "", &urls)
 	if err != nil {
 		return nil, err
 	}
 
 	// Parse it
 	logfiles := []string{}
-	for _, url := range logfiles {
-		fields := strings.Split(url, fmt.Sprintf("/containers/%s/logs/", name))
+	for _, uri := range logfiles {
+		fields := strings.Split(uri, fmt.Sprintf("/containers/%s/logs/", url.QueryEscape(name)))
 		logfiles = append(logfiles, fields[len(fields)-1])
 	}
 
@@ -1234,7 +1229,7 @@ func (r *ProtocolLXD) GetContainerLogfiles(name string) ([]string, error) {
 // Note that it's the caller's responsibility to close the returned ReadCloser
 func (r *ProtocolLXD) GetContainerLogfile(name string, filename string) (io.ReadCloser, error) {
 	// Prepare the HTTP request
-	url := fmt.Sprintf("%s/1.0/containers/%s/logs/%s", r.httpHost, name, filename)
+	url := fmt.Sprintf("%s/1.0/containers/%s/logs/%s", r.httpHost, url.QueryEscape(name), url.QueryEscape(filename))
 	req, err := http.NewRequest("GET", url, nil)
 	if err != nil {
 		return nil, err
@@ -1265,7 +1260,7 @@ func (r *ProtocolLXD) GetContainerLogfile(name string, filename string) (io.Read
 // DeleteContainerLogfile deletes the requested logfile
 func (r *ProtocolLXD) DeleteContainerLogfile(name string, filename string) error {
 	// Send the request
-	_, _, err := r.query("DELETE", fmt.Sprintf("/containers/%s/logs/%s", name, filename), nil, "")
+	_, _, err := r.query("DELETE", fmt.Sprintf("/containers/%s/logs/%s", url.QueryEscape(name), url.QueryEscape(filename)), nil, "")
 	if err != nil {
 		return err
 	}
@@ -1281,7 +1276,7 @@ func (r *ProtocolLXD) GetContainerMetadata(name string) (*api.ImageMetadata, str
 
 	metadata := api.ImageMetadata{}
 
-	url := fmt.Sprintf("/containers/%s/metadata", name)
+	url := fmt.Sprintf("/containers/%s/metadata", url.QueryEscape(name))
 	etag, err := r.queryStruct("GET", url, nil, "", &metadata)
 	if err != nil {
 		return nil, "", err
@@ -1296,7 +1291,7 @@ func (r *ProtocolLXD) SetContainerMetadata(name string, metadata api.ImageMetada
 		return fmt.Errorf("The server is missing the required \"container_edit_metadata\" API extension")
 	}
 
-	url := fmt.Sprintf("/containers/%s/metadata", name)
+	url := fmt.Sprintf("/containers/%s/metadata", url.QueryEscape(name))
 	_, _, err := r.query("PUT", url, metadata, ETag)
 	if err != nil {
 		return err
@@ -1313,7 +1308,7 @@ func (r *ProtocolLXD) GetContainerTemplateFiles(containerName string) ([]string,
 
 	templates := []string{}
 
-	url := fmt.Sprintf("/containers/%s/metadata/templates", containerName)
+	url := fmt.Sprintf("/containers/%s/metadata/templates", url.QueryEscape(containerName))
 	_, err := r.queryStruct("GET", url, nil, "", &templates)
 	if err != nil {
 		return nil, err
@@ -1328,7 +1323,7 @@ func (r *ProtocolLXD) GetContainerTemplateFile(containerName string, templateNam
 		return nil, fmt.Errorf("The server is missing the required \"container_edit_metadata\" API extension")
 	}
 
-	url := fmt.Sprintf("%s/1.0/containers/%s/metadata/templates?path=%s", r.httpHost, containerName, templateName)
+	url := fmt.Sprintf("%s/1.0/containers/%s/metadata/templates?path=%s", r.httpHost, url.QueryEscape(containerName), url.QueryEscape(templateName))
 	req, err := http.NewRequest("GET", url, nil)
 	if err != nil {
 		return nil, err
@@ -1371,7 +1366,7 @@ func (r *ProtocolLXD) setContainerTemplateFile(containerName string, templateNam
 		return fmt.Errorf("The server is missing the required \"container_edit_metadata\" API extension")
 	}
 
-	url := fmt.Sprintf("%s/1.0/containers/%s/metadata/templates?path=%s", r.httpHost, containerName, templateName)
+	url := fmt.Sprintf("%s/1.0/containers/%s/metadata/templates?path=%s", r.httpHost, url.QueryEscape(containerName), url.QueryEscape(templateName))
 	req, err := http.NewRequest(httpMethod, url, content)
 	if err != nil {
 		return err
@@ -1400,7 +1395,7 @@ func (r *ProtocolLXD) DeleteContainerTemplateFile(name string, templateName stri
 	if !r.HasExtension("container_edit_metadata") {
 		return fmt.Errorf("The server is missing the required \"container_edit_metadata\" API extension")
 	}
-	_, _, err := r.query("DELETE", fmt.Sprintf("/containers/%s/metadata/templates?path=%s", name, templateName), nil, "")
+	_, _, err := r.query("DELETE", fmt.Sprintf("/containers/%s/metadata/templates?path=%s", url.QueryEscape(name), url.QueryEscape(templateName)), nil, "")
 	return err
 }
 
@@ -1411,7 +1406,7 @@ func (r *ProtocolLXD) ConsoleContainer(containerName string, console api.Contain
 	}
 
 	// Send the request
-	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s/console", containerName), console, "")
+	op, _, err := r.queryOperation("POST", fmt.Sprintf("/containers/%s/console", url.QueryEscape(containerName)), console, "")
 	if err != nil {
 		return nil, err
 	}
@@ -1482,7 +1477,7 @@ func (r *ProtocolLXD) GetContainerConsoleLog(containerName string, args *Contain
 	}
 
 	// Prepare the HTTP request
-	url := fmt.Sprintf("%s/1.0/containers/%s/console", r.httpHost, containerName)
+	url := fmt.Sprintf("%s/1.0/containers/%s/console", r.httpHost, url.QueryEscape(containerName))
 	req, err := http.NewRequest("GET", url, nil)
 	if err != nil {
 		return nil, err
@@ -1517,7 +1512,7 @@ func (r *ProtocolLXD) DeleteContainerConsoleLog(containerName string, args *Cont
 	}
 
 	// Send the request
-	_, _, err := r.query("DELETE", fmt.Sprintf("/containers/%s/console", containerName), nil, "")
+	_, _, err := r.query("DELETE", fmt.Sprintf("/containers/%s/console", url.QueryEscape(containerName)), nil, "")
 	if err != nil {
 		return err
 	}
diff --git a/client/lxd_images.go b/client/lxd_images.go
index d01c27da1..8d0889640 100644
--- a/client/lxd_images.go
+++ b/client/lxd_images.go
@@ -77,9 +77,9 @@ func (r *ProtocolLXD) GetPrivateImage(fingerprint string, secret string) (*api.I
 	image := api.Image{}
 
 	// Build the API path
-	path := fmt.Sprintf("/images/%s", fingerprint)
+	path := fmt.Sprintf("/images/%s", url.QueryEscape(fingerprint))
 	if secret != "" {
-		path = fmt.Sprintf("%s?secret=%s", path, secret)
+		path = fmt.Sprintf("%s?secret=%s", path, url.QueryEscape(secret))
 	}
 
 	// Fetch the raw value
@@ -102,13 +102,13 @@ func (r *ProtocolLXD) GetPrivateImageFile(fingerprint string, secret string, req
 	resp := ImageFileResponse{}
 
 	// Build the URL
-	url := fmt.Sprintf("%s/1.0/images/%s/export", r.httpHost, fingerprint)
+	uri := fmt.Sprintf("%s/1.0/images/%s/export", r.httpHost, url.QueryEscape(fingerprint))
 	if secret != "" {
-		url = fmt.Sprintf("%s?secret=%s", url, secret)
+		uri = fmt.Sprintf("%s?secret=%s", uri, url.QueryEscape(secret))
 	}
 
 	// Prepare the download request
-	request, err := http.NewRequest("GET", url, nil)
+	request, err := http.NewRequest("GET", uri, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -271,7 +271,7 @@ func (r *ProtocolLXD) GetImageAlias(name string) (*api.ImageAliasesEntry, string
 	alias := api.ImageAliasesEntry{}
 
 	// Fetch the raw value
-	etag, err := r.queryStruct("GET", fmt.Sprintf("/images/aliases/%s", name), nil, "", &alias)
+	etag, err := r.queryStruct("GET", fmt.Sprintf("/images/aliases/%s", url.QueryEscape(name)), nil, "", &alias)
 	if err != nil {
 		return nil, "", err
 	}
@@ -570,7 +570,7 @@ func (r *ProtocolLXD) CopyImage(source ImageServer, image api.Image, args *Image
 // UpdateImage updates the image definition
 func (r *ProtocolLXD) UpdateImage(fingerprint string, image api.ImagePut, ETag string) error {
 	// Send the request
-	_, _, err := r.query("PUT", fmt.Sprintf("/images/%s", fingerprint), image, ETag)
+	_, _, err := r.query("PUT", fmt.Sprintf("/images/%s", url.QueryEscape(fingerprint)), image, ETag)
 	if err != nil {
 		return err
 	}
@@ -581,7 +581,7 @@ func (r *ProtocolLXD) UpdateImage(fingerprint string, image api.ImagePut, ETag s
 // DeleteImage requests that LXD removes an image from the store
 func (r *ProtocolLXD) DeleteImage(fingerprint string) (*Operation, error) {
 	// Send the request
-	op, _, err := r.queryOperation("DELETE", fmt.Sprintf("/images/%s", fingerprint), nil, "")
+	op, _, err := r.queryOperation("DELETE", fmt.Sprintf("/images/%s", url.QueryEscape(fingerprint)), nil, "")
 	if err != nil {
 		return nil, err
 	}
@@ -596,7 +596,7 @@ func (r *ProtocolLXD) RefreshImage(fingerprint string) (*Operation, error) {
 	}
 
 	// Send the request
-	op, _, err := r.queryOperation("POST", fmt.Sprintf("/images/%s/refresh", fingerprint), nil, "")
+	op, _, err := r.queryOperation("POST", fmt.Sprintf("/images/%s/refresh", url.QueryEscape(fingerprint)), nil, "")
 	if err != nil {
 		return nil, err
 	}
@@ -607,7 +607,7 @@ func (r *ProtocolLXD) RefreshImage(fingerprint string) (*Operation, error) {
 // CreateImageSecret requests that LXD issues a temporary image secret
 func (r *ProtocolLXD) CreateImageSecret(fingerprint string) (*Operation, error) {
 	// Send the request
-	op, _, err := r.queryOperation("POST", fmt.Sprintf("/images/%s/secret", fingerprint), nil, "")
+	op, _, err := r.queryOperation("POST", fmt.Sprintf("/images/%s/secret", url.QueryEscape(fingerprint)), nil, "")
 	if err != nil {
 		return nil, err
 	}
@@ -629,7 +629,7 @@ func (r *ProtocolLXD) CreateImageAlias(alias api.ImageAliasesPost) error {
 // UpdateImageAlias updates the image alias definition
 func (r *ProtocolLXD) UpdateImageAlias(name string, alias api.ImageAliasesEntryPut, ETag string) error {
 	// Send the request
-	_, _, err := r.query("PUT", fmt.Sprintf("/images/aliases/%s", name), alias, ETag)
+	_, _, err := r.query("PUT", fmt.Sprintf("/images/aliases/%s", url.QueryEscape(name)), alias, ETag)
 	if err != nil {
 		return err
 	}
@@ -640,7 +640,7 @@ func (r *ProtocolLXD) UpdateImageAlias(name string, alias api.ImageAliasesEntryP
 // RenameImageAlias renames an existing image alias
 func (r *ProtocolLXD) RenameImageAlias(name string, alias api.ImageAliasesEntryPost) error {
 	// Send the request
-	_, _, err := r.query("POST", fmt.Sprintf("/images/aliases/%s", name), alias, "")
+	_, _, err := r.query("POST", fmt.Sprintf("/images/aliases/%s", url.QueryEscape(name)), alias, "")
 	if err != nil {
 		return err
 	}
@@ -651,7 +651,7 @@ func (r *ProtocolLXD) RenameImageAlias(name string, alias api.ImageAliasesEntryP
 // DeleteImageAlias removes an alias from the LXD image store
 func (r *ProtocolLXD) DeleteImageAlias(name string) error {
 	// Send the request
-	_, _, err := r.query("DELETE", fmt.Sprintf("/images/aliases/%s", name), nil, "")
+	_, _, err := r.query("DELETE", fmt.Sprintf("/images/aliases/%s", url.QueryEscape(name)), nil, "")
 	if err != nil {
 		return err
 	}
diff --git a/client/lxd_networks.go b/client/lxd_networks.go
index cbc3fd30a..84ea4703c 100644
--- a/client/lxd_networks.go
+++ b/client/lxd_networks.go
@@ -2,6 +2,7 @@ package lxd
 
 import (
 	"fmt"
+	"net/url"
 	"strings"
 
 	"github.com/lxc/lxd/shared/api"
@@ -45,7 +46,7 @@ func (r *ProtocolLXD) GetNetwork(name string) (*api.Network, string, error) {
 	network := api.Network{}
 
 	// Fetch the raw value
-	etag, err := r.queryStruct("GET", fmt.Sprintf("/networks/%s", name), nil, "", &network)
+	etag, err := r.queryStruct("GET", fmt.Sprintf("/networks/%s", url.QueryEscape(name)), nil, "", &network)
 	if err != nil {
 		return nil, "", err
 	}
@@ -71,7 +72,7 @@ func (r *ProtocolLXD) CreateNetwork(network api.NetworksPost) error {
 // UpdateNetwork updates the network to match the provided Network struct
 func (r *ProtocolLXD) UpdateNetwork(name string, network api.NetworkPut, ETag string) error {
 	// Send the request
-	_, _, err := r.query("PUT", fmt.Sprintf("/networks/%s", name), network, ETag)
+	_, _, err := r.query("PUT", fmt.Sprintf("/networks/%s", url.QueryEscape(name)), network, ETag)
 	if err != nil {
 		return err
 	}
@@ -82,7 +83,7 @@ func (r *ProtocolLXD) UpdateNetwork(name string, network api.NetworkPut, ETag st
 // RenameNetwork renames an existing network entry
 func (r *ProtocolLXD) RenameNetwork(name string, network api.NetworkPost) error {
 	// Send the request
-	_, _, err := r.query("POST", fmt.Sprintf("/networks/%s", name), network, "")
+	_, _, err := r.query("POST", fmt.Sprintf("/networks/%s", url.QueryEscape(name)), network, "")
 	if err != nil {
 		return err
 	}
@@ -93,7 +94,7 @@ func (r *ProtocolLXD) RenameNetwork(name string, network api.NetworkPost) error
 // DeleteNetwork deletes an existing network
 func (r *ProtocolLXD) DeleteNetwork(name string) error {
 	// Send the request
-	_, _, err := r.query("DELETE", fmt.Sprintf("/networks/%s", name), nil, "")
+	_, _, err := r.query("DELETE", fmt.Sprintf("/networks/%s", url.QueryEscape(name)), nil, "")
 	if err != nil {
 		return err
 	}
diff --git a/client/lxd_operations.go b/client/lxd_operations.go
index f585196dc..d5886214b 100644
--- a/client/lxd_operations.go
+++ b/client/lxd_operations.go
@@ -2,6 +2,7 @@ package lxd
 
 import (
 	"fmt"
+	"net/url"
 	"strings"
 
 	"github.com/gorilla/websocket"
@@ -55,7 +56,7 @@ func (r *ProtocolLXD) GetOperation(uuid string) (*api.Operation, string, error)
 	op := api.Operation{}
 
 	// Fetch the raw value
-	etag, err := r.queryStruct("GET", fmt.Sprintf("/operations/%s", uuid), nil, "", &op)
+	etag, err := r.queryStruct("GET", fmt.Sprintf("/operations/%s", url.QueryEscape(uuid)), nil, "", &op)
 	if err != nil {
 		return nil, "", err
 	}
@@ -65,9 +66,9 @@ func (r *ProtocolLXD) GetOperation(uuid string) (*api.Operation, string, error)
 
 // GetOperationWebsocket returns a websocket connection for the provided operation
 func (r *ProtocolLXD) GetOperationWebsocket(uuid string, secret string) (*websocket.Conn, error) {
-	path := fmt.Sprintf("/operations/%s/websocket", uuid)
+	path := fmt.Sprintf("/operations/%s/websocket", url.QueryEscape(uuid))
 	if secret != "" {
-		path = fmt.Sprintf("%s?secret=%s", path, secret)
+		path = fmt.Sprintf("%s?secret=%s", path, url.QueryEscape(secret))
 	}
 
 	return r.websocket(path)
@@ -76,7 +77,7 @@ func (r *ProtocolLXD) GetOperationWebsocket(uuid string, secret string) (*websoc
 // DeleteOperation deletes (cancels) a running operation
 func (r *ProtocolLXD) DeleteOperation(uuid string) error {
 	// Send the request
-	_, _, err := r.query("DELETE", fmt.Sprintf("/operations/%s", uuid), nil, "")
+	_, _, err := r.query("DELETE", fmt.Sprintf("/operations/%s", url.QueryEscape(uuid)), nil, "")
 	if err != nil {
 		return err
 	}
diff --git a/client/lxd_profiles.go b/client/lxd_profiles.go
index a11f4cb3f..bcaa8848f 100644
--- a/client/lxd_profiles.go
+++ b/client/lxd_profiles.go
@@ -2,6 +2,7 @@ package lxd
 
 import (
 	"fmt"
+	"net/url"
 	"strings"
 
 	"github.com/lxc/lxd/shared/api"
@@ -47,7 +48,7 @@ func (r *ProtocolLXD) GetProfile(name string) (*api.Profile, string, error) {
 	profile := api.Profile{}
 
 	// Fetch the raw value
-	etag, err := r.queryStruct("GET", fmt.Sprintf("/profiles/%s", name), nil, "", &profile)
+	etag, err := r.queryStruct("GET", fmt.Sprintf("/profiles/%s", url.QueryEscape(name)), nil, "", &profile)
 	if err != nil {
 		return nil, "", err
 	}
@@ -69,7 +70,7 @@ func (r *ProtocolLXD) CreateProfile(profile api.ProfilesPost) error {
 // UpdateProfile updates the profile to match the provided Profile struct
 func (r *ProtocolLXD) UpdateProfile(name string, profile api.ProfilePut, ETag string) error {
 	// Send the request
-	_, _, err := r.query("PUT", fmt.Sprintf("/profiles/%s", name), profile, ETag)
+	_, _, err := r.query("PUT", fmt.Sprintf("/profiles/%s", url.QueryEscape(name)), profile, ETag)
 	if err != nil {
 		return err
 	}
@@ -80,7 +81,7 @@ func (r *ProtocolLXD) UpdateProfile(name string, profile api.ProfilePut, ETag st
 // RenameProfile renames an existing profile entry
 func (r *ProtocolLXD) RenameProfile(name string, profile api.ProfilePost) error {
 	// Send the request
-	_, _, err := r.query("POST", fmt.Sprintf("/profiles/%s", name), profile, "")
+	_, _, err := r.query("POST", fmt.Sprintf("/profiles/%s", url.QueryEscape(name)), profile, "")
 	if err != nil {
 		return err
 	}
@@ -91,7 +92,7 @@ func (r *ProtocolLXD) RenameProfile(name string, profile api.ProfilePost) error
 // DeleteProfile deletes a profile
 func (r *ProtocolLXD) DeleteProfile(name string) error {
 	// Send the request
-	_, _, err := r.query("DELETE", fmt.Sprintf("/profiles/%s", name), nil, "")
+	_, _, err := r.query("DELETE", fmt.Sprintf("/profiles/%s", url.QueryEscape(name)), nil, "")
 	if err != nil {
 		return err
 	}
diff --git a/client/lxd_storage_pools.go b/client/lxd_storage_pools.go
index 661371efe..8e10288f1 100644
--- a/client/lxd_storage_pools.go
+++ b/client/lxd_storage_pools.go
@@ -2,6 +2,7 @@ package lxd
 
 import (
 	"fmt"
+	"net/url"
 	"strings"
 
 	"github.com/lxc/lxd/shared/api"
@@ -51,7 +52,7 @@ func (r *ProtocolLXD) GetStoragePool(name string) (*api.StoragePool, string, err
 	pool := api.StoragePool{}
 
 	// Fetch the raw value
-	etag, err := r.queryStruct("GET", fmt.Sprintf("/storage-pools/%s", name), nil, "", &pool)
+	etag, err := r.queryStruct("GET", fmt.Sprintf("/storage-pools/%s", url.QueryEscape(name)), nil, "", &pool)
 	if err != nil {
 		return nil, "", err
 	}
@@ -81,7 +82,7 @@ func (r *ProtocolLXD) CreateStoragePool(pool api.StoragePoolsPost) error {
 // UpdateStoragePool updates the pool to match the provided StoragePool struct
 func (r *ProtocolLXD) UpdateStoragePool(name string, pool api.StoragePoolPut, ETag string) error {
 	// Send the request
-	_, _, err := r.query("PUT", fmt.Sprintf("/storage-pools/%s", name), pool, ETag)
+	_, _, err := r.query("PUT", fmt.Sprintf("/storage-pools/%s", url.QueryEscape(name)), pool, ETag)
 	if err != nil {
 		return err
 	}
@@ -92,7 +93,7 @@ func (r *ProtocolLXD) UpdateStoragePool(name string, pool api.StoragePoolPut, ET
 // DeleteStoragePool deletes a storage pool
 func (r *ProtocolLXD) DeleteStoragePool(name string) error {
 	// Send the request
-	_, _, err := r.query("DELETE", fmt.Sprintf("/storage-pools/%s", name), nil, "")
+	_, _, err := r.query("DELETE", fmt.Sprintf("/storage-pools/%s", url.QueryEscape(name)), nil, "")
 	if err != nil {
 		return err
 	}
@@ -109,7 +110,7 @@ func (r *ProtocolLXD) GetStoragePoolResources(name string) (*api.ResourcesStorag
 	res := api.ResourcesStoragePool{}
 
 	// Fetch the raw value
-	_, err := r.queryStruct("GET", fmt.Sprintf("/storage-pools/%s/resources", name), nil, "", &res)
+	_, err := r.queryStruct("GET", fmt.Sprintf("/storage-pools/%s/resources", url.QueryEscape(name)), nil, "", &res)
 	if err != nil {
 		return nil, err
 	}
diff --git a/client/lxd_storage_volumes.go b/client/lxd_storage_volumes.go
index 92f88cccf..1aa576e7f 100644
--- a/client/lxd_storage_volumes.go
+++ b/client/lxd_storage_volumes.go
@@ -2,6 +2,7 @@ package lxd
 
 import (
 	"fmt"
+	"net/url"
 	"strings"
 
 	"github.com/lxc/lxd/shared/api"
@@ -18,15 +19,15 @@ func (r *ProtocolLXD) GetStoragePoolVolumeNames(pool string) ([]string, error) {
 	urls := []string{}
 
 	// Fetch the raw value
-	_, err := r.queryStruct("GET", fmt.Sprintf("/storage-pools/%s/volumes", pool), nil, "", &urls)
+	_, err := r.queryStruct("GET", fmt.Sprintf("/storage-pools/%s/volumes", url.QueryEscape(pool)), nil, "", &urls)
 	if err != nil {
 		return nil, err
 	}
 
 	// Parse it
 	names := []string{}
-	for _, url := range urls {
-		fields := strings.Split(url, fmt.Sprintf("/storage-pools/%s/volumes/", pool))
+	for _, uri := range urls {
+		fields := strings.Split(uri, fmt.Sprintf("/storage-pools/%s/volumes/", url.QueryEscape(pool)))
 		names = append(names, fields[len(fields)-1])
 	}
 
@@ -38,7 +39,7 @@ func (r *ProtocolLXD) GetStoragePoolVolumes(pool string) ([]api.StorageVolume, e
 	volumes := []api.StorageVolume{}
 
 	// Fetch the raw value
-	_, err := r.queryStruct("GET", fmt.Sprintf("/storage-pools/%s/volumes?recursion=1", pool), nil, "", &volumes)
+	_, err := r.queryStruct("GET", fmt.Sprintf("/storage-pools/%s/volumes?recursion=1", url.QueryEscape(pool)), nil, "", &volumes)
 	if err != nil {
 		return nil, err
 	}
@@ -51,7 +52,7 @@ func (r *ProtocolLXD) GetStoragePoolVolume(pool string, volType string, name str
 	volume := api.StorageVolume{}
 
 	// Fetch the raw value
-	etag, err := r.queryStruct("GET", fmt.Sprintf("/storage-pools/%s/volumes/%s/%s", pool, volType, name), nil, "", &volume)
+	etag, err := r.queryStruct("GET", fmt.Sprintf("/storage-pools/%s/volumes/%s/%s", url.QueryEscape(pool), url.QueryEscape(volType), url.QueryEscape(name)), nil, "", &volume)
 	if err != nil {
 		return nil, "", err
 	}
@@ -62,7 +63,7 @@ func (r *ProtocolLXD) GetStoragePoolVolume(pool string, volType string, name str
 // CreateStoragePoolVolume defines a new storage volume
 func (r *ProtocolLXD) CreateStoragePoolVolume(pool string, volume api.StorageVolumesPost) error {
 	// Send the request
-	_, _, err := r.query("POST", fmt.Sprintf("/storage-pools/%s/volumes/%s", pool, volume.Type), volume, "")
+	_, _, err := r.query("POST", fmt.Sprintf("/storage-pools/%s/volumes/%s", url.QueryEscape(pool), url.QueryEscape(volume.Type)), volume, "")
 	if err != nil {
 		return err
 	}
@@ -73,7 +74,7 @@ func (r *ProtocolLXD) CreateStoragePoolVolume(pool string, volume api.StorageVol
 // UpdateStoragePoolVolume updates the volume to match the provided StoragePoolVolume struct
 func (r *ProtocolLXD) UpdateStoragePoolVolume(pool string, volType string, name string, volume api.StorageVolumePut, ETag string) error {
 	// Send the request
-	_, _, err := r.query("PUT", fmt.Sprintf("/storage-pools/%s/volumes/%s/%s", pool, volType, name), volume, ETag)
+	_, _, err := r.query("PUT", fmt.Sprintf("/storage-pools/%s/volumes/%s/%s", url.QueryEscape(pool), url.QueryEscape(volType), url.QueryEscape(name)), volume, ETag)
 	if err != nil {
 		return err
 	}
@@ -84,7 +85,7 @@ func (r *ProtocolLXD) UpdateStoragePoolVolume(pool string, volType string, name
 // DeleteStoragePoolVolume deletes a storage pool
 func (r *ProtocolLXD) DeleteStoragePoolVolume(pool string, volType string, name string) error {
 	// Send the request
-	_, _, err := r.query("DELETE", fmt.Sprintf("/storage-pools/%s/volumes/%s/%s", pool, volType, name), nil, "")
+	_, _, err := r.query("DELETE", fmt.Sprintf("/storage-pools/%s/volumes/%s/%s", url.QueryEscape(pool), url.QueryEscape(volType), url.QueryEscape(name)), nil, "")
 	if err != nil {
 		return err
 	}
@@ -99,7 +100,7 @@ func (r *ProtocolLXD) RenameStoragePoolVolume(pool string, volType string, name
 	}
 
 	// Send the request
-	_, _, err := r.query("POST", fmt.Sprintf("/storage-pools/%s/volumes/%s/%s", pool, volType, name), volume, "")
+	_, _, err := r.query("POST", fmt.Sprintf("/storage-pools/%s/volumes/%s/%s", url.QueryEscape(pool), url.QueryEscape(volType), url.QueryEscape(name)), volume, "")
 	if err != nil {
 		return err
 	}


More information about the lxc-devel mailing list