The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/1766
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) ===
From 4c2678bf2e68c90dcde7d3fdf5b37e24f461aff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Wed, 16 Mar 2016 15:52:33 -0400 Subject: [PATCH 1/4] More strictly parse remote URLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #1763 Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxc/remote.go | 24 ++++++++++++--------- po/lxd.pot | 69 +++++++++++++++++++++++++++++++++++------------------------ 2 files changed, 55 insertions(+), 38 deletions(-) diff --git a/lxc/remote.go b/lxc/remote.go index 0c9cbca..6f54717 100644 --- a/lxc/remote.go +++ b/lxc/remote.go @@ -79,7 +79,7 @@ func getRemoteCertificate(address string) (*x509.Certificate, error) { // Retrieve the certificate if resp.TLS == nil || len(resp.TLS.PeerCertificates) == 0 { - return nil, fmt.Errorf("Unable to read remote TLS certificate") + return nil, fmt.Errorf(i18n.G("Unable to read remote TLS certificate")) } return resp.TLS.PeerCertificates[0], nil @@ -95,24 +95,28 @@ func (c *remoteCmd) addServer(config *lxd.Config, server string, addr string, ac config.Remotes = make(map[string]lxd.RemoteConfig) } - // Fast track simplestreams - if protocol == "simplestreams" { - config.Remotes[server] = lxd.RemoteConfig{Addr: addr, Public: true, Protocol: protocol} - return nil - } - /* Complex remote URL parsing */ remoteURL, err := url.Parse(addr) if err != nil { return err } + // Fast track simplestreams + if protocol == "simplestreams" { + if remoteURL.Scheme != "https" { + return fmt.Errorf(i18n.G("Only https URLs are supported for simplestreams")) + } + + config.Remotes[server] = lxd.RemoteConfig{Addr: addr, Public: true, Protocol: protocol} + return nil + } + if remoteURL.Scheme != "" { if remoteURL.Scheme != "unix" && remoteURL.Scheme != "https" { - rScheme = "https" - } else { - rScheme = remoteURL.Scheme + return fmt.Errorf(i18n.G("Invalid URL scheme \"%s\" in \"%s\""), remoteURL.Scheme, addr) } + + rScheme = remoteURL.Scheme } else if addr[0] == '/' { rScheme = "unix" } else { diff --git a/po/lxd.pot b/po/lxd.pot index 66686ae..c2ec8cf 100644 --- a/po/lxd.pot +++ b/po/lxd.pot @@ -7,7 +7,7 @@ msgid "" msgstr "Project-Id-Version: lxd\n" "Report-Msgid-Bugs-To: lxc-devel@lists.linuxcontainers.org\n" - "POT-Creation-Date: 2016-03-02 19:53-0500\n" + "POT-Creation-Date: 2016-03-16 15:52-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <l...@li.org>\n" @@ -90,11 +90,11 @@ msgstr "" msgid "ARCHITECTURE" msgstr "" -#: lxc/remote.go:52 +#: lxc/remote.go:53 msgid "Accept certificate" msgstr "" -#: lxc/remote.go:216 +#: lxc/remote.go:250 #, c-format msgid "Admin password for %s: " msgstr "" @@ -143,7 +143,7 @@ msgstr "" msgid "Cannot provide container name to list" msgstr "" -#: lxc/remote.go:166 +#: lxc/remote.go:200 #, c-format msgid "Certificate fingerprint: %x" msgstr "" @@ -155,7 +155,7 @@ msgid "Changes state of one or more containers to %s.\n" "lxc %s <name> [<name>...]" msgstr "" -#: lxc/remote.go:239 +#: lxc/remote.go:273 msgid "Client certificate stored at server: " msgstr "" @@ -205,7 +205,7 @@ msgstr "" msgid "Copying the image: %s" msgstr "" -#: lxc/remote.go:181 +#: lxc/remote.go:215 msgid "Could not create server cert dir" msgstr "" @@ -251,12 +251,12 @@ msgid "Delete containers or container snapshots.\n" "Destroy containers or snapshots with any attached data (configuration, snapshots, ...)." msgstr "" -#: lxc/config.go:606 +#: lxc/config.go:610 #, c-format msgid "Device %s added to %s" msgstr "" -#: lxc/config.go:634 +#: lxc/config.go:640 #, c-format msgid "Device %s removed from %s" msgstr "" @@ -384,6 +384,11 @@ msgid "Initialize a container from a particular image.\n" "lxc init ubuntu u1" msgstr "" +#: lxc/remote.go:116 +#, c-format +msgid "Invalid URL scheme \"%s\" in \"%s\"" +msgstr "" + #: lxc/init.go:30 lxc/init.go:35 msgid "Invalid configuration key" msgstr "" @@ -552,7 +557,7 @@ msgid "Manage files on a container.\n" "<source> in the case of pull, <target> in the case of push and <file> in the case of edit are <container name>/<path>" msgstr "" -#: lxc/remote.go:38 +#: lxc/remote.go:39 msgid "Manage remote LXD servers.\n" "\n" "lxc remote add <name> <url> [--accept-certificate] [--password=PASSWORD]\n" @@ -660,11 +665,11 @@ msgstr "" msgid "Must supply container name for: " msgstr "" -#: lxc/list.go:338 lxc/remote.go:323 +#: lxc/list.go:338 lxc/remote.go:357 msgid "NAME" msgstr "" -#: lxc/remote.go:297 lxc/remote.go:302 +#: lxc/remote.go:331 lxc/remote.go:336 msgid "NO" msgstr "" @@ -685,6 +690,10 @@ msgstr "" msgid "No fingerprint specified." msgstr "" +#: lxc/remote.go:107 +msgid "Only https URLs are supported for simplestreams" +msgstr "" + #: lxc/image.go:397 msgid "Only https:// is supported for remote image import." msgstr "" @@ -714,11 +723,11 @@ msgstr "" msgid "PROFILES" msgstr "" -#: lxc/remote.go:325 +#: lxc/remote.go:359 msgid "PROTOCOL" msgstr "" -#: lxc/image.go:592 lxc/remote.go:326 +#: lxc/image.go:592 lxc/remote.go:360 msgid "PUBLIC" msgstr "" @@ -804,7 +813,7 @@ msgstr "" msgid "Properties:" msgstr "" -#: lxc/remote.go:55 +#: lxc/remote.go:56 msgid "Public image server" msgstr "" @@ -819,7 +828,7 @@ msgid "Publish containers as images.\n" "lxc publish [remote:]container [remote:] [--alias=ALIAS]... [prop-key=prop-value]..." msgstr "" -#: lxc/remote.go:53 +#: lxc/remote.go:54 msgid "Remote admin password" msgstr "" @@ -849,19 +858,19 @@ msgstr "" msgid "STATE" msgstr "" -#: lxc/remote.go:327 +#: lxc/remote.go:361 msgid "STATIC" msgstr "" -#: lxc/remote.go:174 +#: lxc/remote.go:208 msgid "Server certificate NACKed by user" msgstr "" -#: lxc/remote.go:236 +#: lxc/remote.go:270 msgid "Server doesn't trust us after adding our cert" msgstr "" -#: lxc/remote.go:54 +#: lxc/remote.go:55 msgid "Server protocol (lxd or simplestreams)" msgstr "" @@ -979,10 +988,14 @@ msgstr "" msgid "UPLOAD DATE" msgstr "" -#: lxc/remote.go:324 +#: lxc/remote.go:358 msgid "URL" msgstr "" +#: lxc/remote.go:82 +msgid "Unable to read remote TLS certificate" +msgstr "" + #: lxc/image.go:323 #, c-format msgid "Uploaded: %s" @@ -1013,7 +1026,7 @@ msgstr "" msgid "Whether to show the expanded configuration" msgstr "" -#: lxc/remote.go:299 lxc/remote.go:304 +#: lxc/remote.go:333 lxc/remote.go:338 msgid "YES" msgstr "" @@ -1033,11 +1046,11 @@ msgstr "" msgid "can't copy to the same container name" msgstr "" -#: lxc/remote.go:287 +#: lxc/remote.go:321 msgid "can't remove the default remote" msgstr "" -#: lxc/remote.go:313 +#: lxc/remote.go:347 msgid "default" msgstr "" @@ -1075,7 +1088,7 @@ msgstr "" msgid "not all the profiles from the source exist on the target" msgstr "" -#: lxc/remote.go:167 +#: lxc/remote.go:201 msgid "ok (y/n)?" msgstr "" @@ -1084,22 +1097,22 @@ msgstr "" msgid "processing aliases failed %s\n" msgstr "" -#: lxc/remote.go:349 +#: lxc/remote.go:383 #, c-format msgid "remote %s already exists" msgstr "" -#: lxc/remote.go:279 lxc/remote.go:341 lxc/remote.go:376 lxc/remote.go:392 +#: lxc/remote.go:313 lxc/remote.go:375 lxc/remote.go:410 lxc/remote.go:426 #, c-format msgid "remote %s doesn't exist" msgstr "" -#: lxc/remote.go:262 +#: lxc/remote.go:296 #, c-format msgid "remote %s exists as <%s>" msgstr "" -#: lxc/remote.go:283 lxc/remote.go:345 lxc/remote.go:380 +#: lxc/remote.go:317 lxc/remote.go:379 lxc/remote.go:414 #, c-format msgid "remote %s is static and cannot be modified" msgstr "" From 4c19e958f613d01f83bad42eaaa9296d4abb86f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Wed, 16 Mar 2016 17:17:39 -0400 Subject: [PATCH 2/4] Fix devlxd access outside of an exec session MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #1751 Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd/devlxd.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lxd/devlxd.go b/lxd/devlxd.go index ecb28e8..ce8b00a 100644 --- a/lxd/devlxd.go +++ b/lxd/devlxd.go @@ -297,7 +297,7 @@ func findContainerForPid(pid int32, d *Daemon) (container, error) { if strings.HasPrefix(string(cmdline), "[lxc monitor]") { // container names can't have spaces parts := strings.Split(string(cmdline), " ") - name := parts[len(parts)-1] + name := strings.TrimSuffix(parts[len(parts)-1], "\x00") return containerLoadByName(d, name) } From 689d722e17808bed8899fc6ebaa22e013044b7ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Wed, 16 Mar 2016 17:42:13 -0400 Subject: [PATCH 3/4] Restrict /dev/lxd to uid 0 in the container MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #1751 Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd/devlxd.go | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/lxd/devlxd.go b/lxd/devlxd.go index ce8b00a..8991a67 100644 --- a/lxd/devlxd.go +++ b/lxd/devlxd.go @@ -85,18 +85,32 @@ var handlers = []devLxdHandler{ func hoistReq(f func(container, *http.Request) *devLxdResponse, d *Daemon) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { conn := extractUnderlyingConn(w) - pid, ok := pidMapper.m[conn] + cred, ok := pidMapper.m[conn] if !ok { http.Error(w, pidNotInContainerErr.Error(), 500) return } - c, err := findContainerForPid(pid, d) + c, err := findContainerForPid(cred.pid, d) if err != nil { http.Error(w, err.Error(), 500) return } + // Access control + rootUid := int64(0) + + idmapset, err := c.LastIdmapSet() + if err == nil && idmapset != nil { + uid, _ := idmapset.ShiftIntoNs(0, 0) + rootUid = int64(uid) + } + + if rootUid != cred.uid { + http.Error(w, "Access denied for non-root user", 401) + return + } + resp := f(c, r) if resp.code != http.StatusOK { http.Error(w, fmt.Sprintf("%s", resp.content), resp.code) @@ -185,21 +199,27 @@ func devLxdServer(d *Daemon) *http.Server { * from our http handlers, since there appears to be no way to pass information * around here. */ -var pidMapper = ConnPidMapper{m: map[*net.UnixConn]int32{}} +var pidMapper = ConnPidMapper{m: map[*net.UnixConn]*ucred{}} + +type ucred struct { + pid int32 + uid int64 + gid int64 +} type ConnPidMapper struct { - m map[*net.UnixConn]int32 + m map[*net.UnixConn]*ucred } func (m *ConnPidMapper) ConnStateHandler(conn net.Conn, state http.ConnState) { unixConn := conn.(*net.UnixConn) switch state { case http.StateNew: - pid, err := getPid(unixConn) + cred, err := getCred(unixConn) if err != nil { - shared.Debugf("Error getting pid for conn %s", err) + shared.Debugf("Error getting ucred for conn %s", err) } else { - m.m[unixConn] = pid + m.m[unixConn] = cred } case http.StateActive: return @@ -234,15 +254,15 @@ func extractUnderlyingFd(unixConnPtr *net.UnixConn) int { return int(fd.Int()) } -func getPid(conn *net.UnixConn) (int32, error) { +func getCred(conn *net.UnixConn) (*ucred, error) { fd := extractUnderlyingFd(conn) - _, _, pid, err := getUcred(fd) + uid, gid, pid, err := getUcred(fd) if err != nil { - return 0, err + return nil, err } - return pid, nil + return &ucred{pid, int64(uid), int64(gid)}, nil } /* From dea6b959e9a8173af63a8c974aaf1097b5eb6bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Wed, 16 Mar 2016 17:58:40 -0400 Subject: [PATCH 4/4] Return better errors for public and simplestream remotes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #1762 Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- client.go | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- lxc/remote.go | 4 +- 2 files changed, 201 insertions(+), 13 deletions(-) diff --git a/client.go b/client.go index 7decf89..9d4716f 100644 --- a/client.go +++ b/client.go @@ -493,18 +493,11 @@ func (c *Client) url(elem ...string) string { } func (c *Client) GetServerConfig() (*Response, error) { - return c.baseGet(c.url(shared.APIVersion)) -} - -func (c *Client) Finger() error { - shared.Debugf("Fingering the daemon") - _, err := c.GetServerConfig() - if err != nil { - return err + if c.Remote.Protocol == "simplestreams" { + return nil, fmt.Errorf("This function isn't supported by simplestreams remote.") } - shared.Debugf("Pong received") - return nil + return c.baseGet(c.url(shared.APIVersion)) } func (c *Client) AmTrusted() bool { @@ -550,6 +543,10 @@ func (c *Client) IsPublic() bool { } func (c *Client) ListContainers() ([]shared.ContainerInfo, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + resp, err := c.get("containers?recursion=1") if err != nil { return nil, err @@ -827,6 +824,10 @@ func (c *Client) ExportImage(image string, target string) (string, error) { } func (c *Client) PostImageURL(imageFile string, public bool, aliases []string) (string, error) { + if c.Remote.Public { + return "", fmt.Errorf("This function isn't supported by public remotes.") + } + source := shared.Jmap{ "type": "url", "mode": "pull", @@ -865,6 +866,10 @@ func (c *Client) PostImageURL(imageFile string, public bool, aliases []string) ( } func (c *Client) PostImage(imageFile string, rootfsFile string, properties []string, public bool, aliases []string, progressHandler func(percent int)) (string, error) { + if c.Remote.Public { + return "", fmt.Errorf("This function isn't supported by public remotes.") + } + uri := c.url(shared.APIVersion, "images") var err error @@ -1030,6 +1035,10 @@ func (c *Client) GetImageInfo(image string) (*shared.ImageInfo, error) { } func (c *Client) PutImageInfo(name string, p shared.BriefImageInfo) error { + if c.Remote.Public { + return fmt.Errorf("This function isn't supported by public remotes.") + } + _, err := c.put(fmt.Sprintf("images/%s", name), p, Sync) return err } @@ -1053,11 +1062,19 @@ func (c *Client) ListImages() ([]shared.ImageInfo, error) { } func (c *Client) DeleteImage(image string) error { + if c.Remote.Public { + return fmt.Errorf("This function isn't supported by public remotes.") + } + _, err := c.delete(fmt.Sprintf("images/%s", image), nil, Sync) return err } func (c *Client) PostAlias(alias string, desc string, target string) error { + if c.Remote.Public { + return fmt.Errorf("This function isn't supported by public remotes.") + } + body := shared.Jmap{"description": desc, "target": target, "name": alias} _, err := c.post("images/aliases", body, Sync) @@ -1065,6 +1082,10 @@ func (c *Client) PostAlias(alias string, desc string, target string) error { } func (c *Client) DeleteAlias(alias string) error { + if c.Remote.Public { + return fmt.Errorf("This function isn't supported by public remotes.") + } + _, err := c.delete(fmt.Sprintf("images/aliases/%s", alias), nil, Sync) return err } @@ -1089,6 +1110,10 @@ func (c *Client) ListAliases() (shared.ImageAliases, error) { } func (c *Client) CertificateList() ([]shared.CertInfo, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + resp, err := c.get("certificates?recursion=1") if err != nil { return nil, err @@ -1103,6 +1128,10 @@ func (c *Client) CertificateList() ([]shared.CertInfo, error) { } func (c *Client) AddMyCertToServer(pwd string) error { + if c.Remote.Public { + return fmt.Errorf("This function isn't supported by public remotes.") + } + body := shared.Jmap{"type": "client", "password": pwd} _, err := c.post("certificates", body, Sync) @@ -1110,12 +1139,20 @@ func (c *Client) AddMyCertToServer(pwd string) error { } func (c *Client) CertificateAdd(cert *x509.Certificate, name string) error { + if c.Remote.Public { + return fmt.Errorf("This function isn't supported by public remotes.") + } + b64 := base64.StdEncoding.EncodeToString(cert.Raw) _, err := c.post("certificates", shared.Jmap{"type": "client", "certificate": b64, "name": name}, Sync) return err } func (c *Client) CertificateRemove(fingerprint string) error { + if c.Remote.Public { + return fmt.Errorf("This function isn't supported by public remotes.") + } + _, err := c.delete(fmt.Sprintf("certificates/%s", fingerprint), nil, Sync) return err } @@ -1156,6 +1193,10 @@ func (c *Client) GetAlias(alias string) string { // Init creates a container from either a fingerprint or an alias; you must // provide at least one. func (c *Client) Init(name string, imgremote string, image string, profiles *[]string, config map[string]string, ephem bool) (*Response, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + var tmpremote *Client var err error @@ -1291,6 +1332,10 @@ func (c *Client) Init(name string, imgremote string, image string, profiles *[]s } func (c *Client) LocalCopy(source string, name string, config map[string]string, profiles []string, ephemeral bool) (*Response, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + body := shared.Jmap{ "source": shared.Jmap{ "type": "copy", @@ -1306,6 +1351,10 @@ func (c *Client) LocalCopy(source string, name string, config map[string]string, } func (c *Client) Monitor(types []string, handler func(interface{})) error { + if c.Remote.Public { + return fmt.Errorf("This function isn't supported by public remotes.") + } + url := c.BaseWSURL + path.Join("/", "1.0", "events") if len(types) != 0 { url += "?type=" + strings.Join(types, ",") @@ -1343,6 +1392,10 @@ func (c *Client) Exec(name string, cmd []string, env map[string]string, stdin io.ReadCloser, stdout io.WriteCloser, stderr io.WriteCloser, controlHandler func(*Client, *websocket.Conn)) (int, error) { + if c.Remote.Public { + return -1, fmt.Errorf("This function isn't supported by public remotes.") + } + body := shared.Jmap{ "command": cmd, "wait-for-websocket": true, @@ -1453,6 +1506,10 @@ func (c *Client) Exec(name string, cmd []string, env map[string]string, } func (c *Client) Action(name string, action shared.ContainerAction, timeout int, force bool, stateful bool) (*Response, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + body := shared.Jmap{ "action": action, "timeout": timeout, @@ -1466,6 +1523,10 @@ func (c *Client) Action(name string, action shared.ContainerAction, timeout int, } func (c *Client) Delete(name string) (*Response, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + var url string s := strings.SplitN(name, "/", 2) if len(s) == 2 { @@ -1493,6 +1554,10 @@ func (c *Client) ServerStatus() (*shared.ServerState, error) { } func (c *Client) ContainerInfo(name string) (*shared.ContainerInfo, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + ct := shared.ContainerInfo{} resp, err := c.get(fmt.Sprintf("containers/%s", name)) @@ -1508,6 +1573,10 @@ func (c *Client) ContainerInfo(name string) (*shared.ContainerInfo, error) { } func (c *Client) ContainerState(name string) (*shared.ContainerState, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + ct := shared.ContainerState{} resp, err := c.get(fmt.Sprintf("containers/%s/state", name)) @@ -1523,6 +1592,10 @@ func (c *Client) ContainerState(name string) (*shared.ContainerState, error) { } func (c *Client) GetLog(container string, log string) (io.Reader, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + uri := c.url(shared.APIVersion, "containers", container, "logs", log) resp, err := c.getRaw(uri) if err != nil { @@ -1533,6 +1606,10 @@ func (c *Client) GetLog(container string, log string) (io.Reader, error) { } func (c *Client) ProfileConfig(name string) (*shared.ProfileConfig, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + ct := shared.ProfileConfig{} resp, err := c.get(fmt.Sprintf("profiles/%s", name)) @@ -1548,6 +1625,10 @@ func (c *Client) ProfileConfig(name string) (*shared.ProfileConfig, error) { } func (c *Client) PushFile(container string, p string, gid int, uid int, mode os.FileMode, buf io.ReadSeeker) error { + if c.Remote.Public { + return fmt.Errorf("This function isn't supported by public remotes.") + } + query := url.Values{"path": []string{p}} uri := c.url(shared.APIVersion, "containers", container, "files") + "?" + query.Encode() @@ -1571,6 +1652,10 @@ func (c *Client) PushFile(container string, p string, gid int, uid int, mode os. } func (c *Client) PullFile(container string, p string) (int, int, os.FileMode, io.ReadCloser, error) { + if c.Remote.Public { + return 0, 0, 0, nil, fmt.Errorf("This function isn't supported by public remotes.") + } + uri := c.url(shared.APIVersion, "containers", container, "files") query := url.Values{"path": []string{p}} @@ -1585,6 +1670,10 @@ func (c *Client) PullFile(container string, p string) (int, int, os.FileMode, io } func (c *Client) GetMigrationSourceWS(container string) (*Response, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + body := shared.Jmap{"migration": true} url := fmt.Sprintf("containers/%s", container) if shared.IsSnapshot(container) { @@ -1600,6 +1689,10 @@ func (c *Client) GetMigrationSourceWS(container string) (*Response, error) { } func (c *Client) MigrateFrom(name string, operation string, certificate string, secrets map[string]string, architecture string, config map[string]string, devices shared.Devices, profiles []string, baseImage string, ephemeral bool) (*Response, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + source := shared.Jmap{ "type": "migration", "mode": "pull", @@ -1622,6 +1715,10 @@ func (c *Client) MigrateFrom(name string, operation string, certificate string, } func (c *Client) Rename(name string, newName string) (*Response, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + oldNameParts := strings.SplitN(name, "/", 2) newNameParts := strings.SplitN(newName, "/", 2) if len(oldNameParts) != len(newNameParts) { @@ -1672,16 +1769,28 @@ func (c *Client) WaitForSuccess(waitURL string) error { } func (c *Client) RestoreSnapshot(container string, snapshotName string, stateful bool) (*Response, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + body := shared.Jmap{"restore": snapshotName, "stateful": stateful} return c.put(fmt.Sprintf("containers/%s", container), body, Async) } func (c *Client) Snapshot(container string, snapshotName string, stateful bool) (*Response, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + body := shared.Jmap{"name": snapshotName, "stateful": stateful} return c.post(fmt.Sprintf("containers/%s/snapshots", container), body, Async) } func (c *Client) ListSnapshots(container string) ([]shared.SnapshotInfo, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + qUrl := fmt.Sprintf("containers/%s/snapshots?recursion=1", container) resp, err := c.get(qUrl) if err != nil { @@ -1721,6 +1830,10 @@ func (c *Client) GetServerConfigString() ([]string, error) { } func (c *Client) SetServerConfig(key string, value string) (*Response, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + ss, err := c.ServerStatus() if err != nil { return nil, err @@ -1732,6 +1845,10 @@ func (c *Client) SetServerConfig(key string, value string) (*Response, error) { } func (c *Client) UpdateServerConfig(ss shared.BriefServerState) (*Response, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + return c.put("", ss, Sync) } @@ -1739,6 +1856,10 @@ func (c *Client) UpdateServerConfig(ss shared.BriefServerState) (*Response, erro * return string array representing a container's full configuration */ func (c *Client) GetContainerConfig(container string) ([]string, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + var resp []string st, err := c.ContainerInfo(container) @@ -1759,6 +1880,10 @@ func (c *Client) GetContainerConfig(container string) ([]string, error) { } func (c *Client) SetContainerConfig(container, key, value string) error { + if c.Remote.Public { + return fmt.Errorf("This function isn't supported by public remotes.") + } + st, err := c.ContainerInfo(container) if err != nil { return err @@ -1784,6 +1909,10 @@ func (c *Client) SetContainerConfig(container, key, value string) error { } func (c *Client) UpdateContainerConfig(container string, st shared.BriefContainerInfo) error { + if c.Remote.Public { + return fmt.Errorf("This function isn't supported by public remotes.") + } + resp, err := c.put(fmt.Sprintf("containers/%s", container), st, Async) if err != nil { return err @@ -1793,6 +1922,10 @@ func (c *Client) UpdateContainerConfig(container string, st shared.BriefContaine } func (c *Client) ProfileCreate(p string) error { + if c.Remote.Public { + return fmt.Errorf("This function isn't supported by public remotes.") + } + body := shared.Jmap{"name": p} _, err := c.post("profiles", body, Sync) @@ -1800,11 +1933,19 @@ func (c *Client) ProfileCreate(p string) error { } func (c *Client) ProfileDelete(p string) error { + if c.Remote.Public { + return fmt.Errorf("This function isn't supported by public remotes.") + } + _, err := c.delete(fmt.Sprintf("profiles/%s", p), nil, Sync) return err } func (c *Client) GetProfileConfig(profile string) (map[string]string, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + st, err := c.ProfileConfig(profile) if err != nil { return nil, err @@ -1814,6 +1955,10 @@ func (c *Client) GetProfileConfig(profile string) (map[string]string, error) { } func (c *Client) SetProfileConfigItem(profile, key, value string) error { + if c.Remote.Public { + return fmt.Errorf("This function isn't supported by public remotes.") + } + st, err := c.ProfileConfig(profile) if err != nil { shared.Debugf("Error getting profile %s to update", profile) @@ -1831,6 +1976,10 @@ func (c *Client) SetProfileConfigItem(profile, key, value string) error { } func (c *Client) PutProfile(name string, profile shared.ProfileConfig) error { + if c.Remote.Public { + return fmt.Errorf("This function isn't supported by public remotes.") + } + if profile.Name != name { return fmt.Errorf("Cannot change profile name") } @@ -1840,6 +1989,10 @@ func (c *Client) PutProfile(name string, profile shared.ProfileConfig) error { } func (c *Client) ListProfiles() ([]string, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + resp, err := c.get("profiles") if err != nil { return nil, err @@ -1877,6 +2030,10 @@ func (c *Client) ListProfiles() ([]string, error) { } func (c *Client) ApplyProfile(container, profile string) (*Response, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + st, err := c.ContainerInfo(container) if err != nil { return nil, err @@ -1888,6 +2045,10 @@ func (c *Client) ApplyProfile(container, profile string) (*Response, error) { } func (c *Client) ContainerDeviceDelete(container, devname string) (*Response, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + st, err := c.ContainerInfo(container) if err != nil { return nil, err @@ -1899,6 +2060,10 @@ func (c *Client) ContainerDeviceDelete(container, devname string) (*Response, er } func (c *Client) ContainerDeviceAdd(container, devname, devtype string, props []string) (*Response, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + st, err := c.ContainerInfo(container) if err != nil { return nil, err @@ -1930,6 +2095,10 @@ func (c *Client) ContainerDeviceAdd(container, devname, devtype string, props [] } func (c *Client) ContainerListDevices(container string) ([]string, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + st, err := c.ContainerInfo(container) if err != nil { return nil, err @@ -1942,6 +2111,10 @@ func (c *Client) ContainerListDevices(container string) ([]string, error) { } func (c *Client) ProfileDeviceDelete(profile, devname string) (*Response, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + st, err := c.ProfileConfig(profile) if err != nil { return nil, err @@ -1957,6 +2130,10 @@ func (c *Client) ProfileDeviceDelete(profile, devname string) (*Response, error) } func (c *Client) ProfileDeviceAdd(profile, devname, devtype string, props []string) (*Response, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + st, err := c.ProfileConfig(profile) if err != nil { return nil, err @@ -1985,6 +2162,10 @@ func (c *Client) ProfileDeviceAdd(profile, devname, devtype string, props []stri } func (c *Client) ProfileListDevices(profile string) ([]string, error) { + if c.Remote.Public { + return nil, fmt.Errorf("This function isn't supported by public remotes.") + } + st, err := c.ProfileConfig(profile) if err != nil { return nil, err @@ -1994,7 +2175,6 @@ func (c *Client) ProfileListDevices(profile string) ([]string, error) { devs = append(devs, fmt.Sprintf("%s: %s", n, d["type"])) } return devs, nil - } // WebsocketDial attempts to dial a websocket to a LXD instance, parsing @@ -2015,6 +2195,10 @@ func WebsocketDial(dialer websocket.Dialer, url string) (*websocket.Conn, error) } func (c *Client) ProfileCopy(name, newname string, dest *Client) error { + if c.Remote.Public { + return fmt.Errorf("This function isn't supported by public remotes.") + } + st, err := c.ProfileConfig(name) if err != nil { return err @@ -2043,6 +2227,10 @@ func (c *Client) AsyncWaitMeta(resp *Response) (*shared.Jmap, error) { } func (c *Client) ImageFromContainer(cname string, public bool, aliases []string, properties map[string]string) (string, error) { + if c.Remote.Public { + return "", fmt.Errorf("This function isn't supported by public remotes.") + } + source := shared.Jmap{"type": "container", "name": cname} if shared.IsSnapshot(cname) { source["type"] = "snapshot" diff --git a/lxc/remote.go b/lxc/remote.go index 6f54717..8a7b5a3 100644 --- a/lxc/remote.go +++ b/lxc/remote.go @@ -184,7 +184,7 @@ func (c *remoteCmd) addServer(config *lxd.Config, server string, addr string, ac var certificate *x509.Certificate /* Attempt to connect using the system root CA */ - err = d.Finger() + _, err = d.GetServerConfig() if err != nil { // Failed to connect using the system CA, so retrieve the remote certificate certificate, err = getRemoteCertificate(addr) @@ -234,7 +234,7 @@ func (c *remoteCmd) addServer(config *lxd.Config, server string, addr string, ac if d.IsPublic() || public { config.Remotes[server] = lxd.RemoteConfig{Addr: addr, Public: true} - if err := d.Finger(); err != nil { + if _, err := d.GetServerConfig(); err != nil { return err }
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel