func (c *fingerCmd) run(config *lxd.Config, args []string) error { if len(args) > 1 { return errArgs } var remote string if len(args) == 1 { remote = config.ParseRemote(args[0]) } else { remote = config.DefaultRemote } // NewClient will finger the server to test the connection before returning. _, err := lxd.NewClient(config, remote) return err }
func (c *fingerCmd) run(config *lxd.Config, args []string) error { if len(args) > 1 { return errArgs } var remote string if len(args) == 1 { remote = config.ParseRemote(args[0]) } else { remote = config.DefaultRemote } // New client may or may not need to connect to the remote host, but // client.ServerStatus will at least request the basic information from // the server. client, err := lxd.NewClient(config, remote) if err != nil { return err } _, err = client.ServerStatus() return err }
func (c *configCmd) run(config *lxd.Config, args []string) error { if len(args) < 1 { return errArgs } switch args[0] { case "unset": if len(args) < 2 { return errArgs } // 2 args means we're unsetting a server key if len(args) == 2 { key := args[1] c, err := lxd.NewClient(config, config.DefaultRemote) if err != nil { return err } _, err = c.SetServerConfig(key, "") return err } // 3 args is a container config key args = append(args, "") return doSet(config, args) case "set": if len(args) < 3 { return errArgs } // 3 args means we're setting a server key if len(args) == 3 { key := args[1] c, err := lxd.NewClient(config, config.DefaultRemote) if err != nil { return err } _, err = c.SetServerConfig(key, args[2]) return err } // 4 args is a container config key return doSet(config, args) case "trust": if len(args) < 2 { return errArgs } switch args[1] { case "list": var remote string if len(args) == 3 { remote = config.ParseRemote(args[2]) } else { remote = config.DefaultRemote } d, err := lxd.NewClient(config, remote) if err != nil { return err } trust, err := d.CertificateList() if err != nil { return err } data := [][]string{} for _, cert := range trust { fp := cert.Fingerprint[0:12] certBlock, _ := pem.Decode([]byte(cert.Certificate)) cert, err := x509.ParseCertificate(certBlock.Bytes) if err != nil { return err } const layout = "Jan 2, 2006 at 3:04pm (MST)" issue := cert.NotBefore.Format(layout) expiry := cert.NotAfter.Format(layout) data = append(data, []string{fp, cert.Subject.CommonName, issue, expiry}) } table := tablewriter.NewWriter(os.Stdout) table.SetHeader([]string{"FINGERPRINT", "COMMON NAME", "ISSUE DATE", "EXPIRY DATE"}) for _, v := range data { table.Append(v) } table.Render() return nil case "add": var remote string if len(args) < 3 { return fmt.Errorf(gettext.Gettext("No cert provided to add")) } else if len(args) == 4 { remote = config.ParseRemote(args[2]) } else { remote = config.DefaultRemote } d, err := lxd.NewClient(config, remote) if err != nil { return err } fname := args[len(args)-1] cert, err := shared.ReadCert(fname) if err != nil { return err } name, _ := shared.SplitExt(fname) return d.CertificateAdd(cert, name) case "remove": var remote string if len(args) < 3 { return fmt.Errorf(gettext.Gettext("No fingerprint specified.")) } else if len(args) == 4 { remote = config.ParseRemote(args[2]) } else { remote = config.DefaultRemote } d, err := lxd.NewClient(config, remote) if err != nil { return err } return d.CertificateRemove(args[len(args)-1]) default: return fmt.Errorf(gettext.Gettext("Unkonwn config trust command %s"), args[1]) } case "show": remote := config.DefaultRemote container := "" if len(args) > 1 { remote, container = config.ParseRemoteAndContainer(args[1]) } d, err := lxd.NewClient(config, remote) if err != nil { return err } var data []byte if len(args) == 1 || container == "" { config, err := d.ServerStatus() if err != nil { return err } brief := config.BriefState() data, err = yaml.Marshal(&brief) } else { config, err := d.ContainerStatus(container, false) if err != nil { return err } brief := config.BriefState() data, err = yaml.Marshal(&brief) } fmt.Printf("%s", data) return nil case "get": if len(args) != 3 { return errArgs } remote, container := config.ParseRemoteAndContainer(args[1]) d, err := lxd.NewClient(config, remote) if err != nil { return err } resp, err := d.ContainerStatus(container, false) if err != nil { return err } fmt.Printf("%s: %s\n", args[2], resp.Config[args[2]]) return nil case "profile": case "device": if len(args) < 2 { return errArgs } switch args[1] { case "list": return deviceList(config, "container", args) case "add": return deviceAdd(config, "container", args) case "remove": return deviceRm(config, "container", args) case "show": return deviceShow(config, "container", args) default: return errArgs } case "edit": if len(args) != 2 { return errArgs } remote, container := config.ParseRemoteAndContainer(args[1]) d, err := lxd.NewClient(config, remote) if err != nil { return err } return doConfigEdit(d, container) default: return errArgs } return errArgs }
func (c *remoteCmd) addServer(config *lxd.Config, server string, addr string, acceptCert bool, password string, public bool, protocol string) error { var rScheme string var rHost string var rPort string // Setup the remotes list if config.Remotes == nil { 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 } if remoteURL.Scheme != "" { if remoteURL.Scheme != "unix" && remoteURL.Scheme != "https" { rScheme = "https" } else { rScheme = remoteURL.Scheme } } else if addr[0] == '/' { rScheme = "unix" } else { if !shared.PathExists(addr) { rScheme = "https" } else { rScheme = "unix" } } if remoteURL.Host != "" { rHost = remoteURL.Host } else { rHost = addr } host, port, err := net.SplitHostPort(rHost) if err == nil { rHost = host rPort = port } else { rPort = shared.DefaultPort } if rScheme == "unix" { if addr[0:5] == "unix:" { if addr[0:7] == "unix://" { if len(addr) > 8 { rHost = addr[8:] } else { rHost = "" } } else { rHost = addr[6:] } } rPort = "" } if strings.Contains(rHost, ":") && !strings.HasPrefix(rHost, "[") { rHost = fmt.Sprintf("[%s]", rHost) } if rPort != "" { addr = rScheme + "://" + rHost + ":" + rPort } else { addr = rScheme + "://" + rHost } /* Actually add the remote */ config.Remotes[server] = lxd.RemoteConfig{Addr: addr, Protocol: protocol} remote := config.ParseRemote(server) d, err := lxd.NewClient(config, remote) if err != nil { return err } if len(addr) > 5 && addr[0:5] == "unix:" { // NewClient succeeded so there was a lxd there (we fingered // it) so just accept it return nil } var certificate *x509.Certificate /* Attempt to connect using the system root CA */ err = d.Finger() if err != nil { // Failed to connect using the system CA, so retrieve the remote certificate certificate, err = getRemoteCertificate(addr) if err != nil { return err } } if certificate != nil { if !acceptCert { digest := sha256.Sum256(certificate.Raw) fmt.Printf(i18n.G("Certificate fingerprint: %x")+"\n", digest) fmt.Printf(i18n.G("ok (y/n)?") + " ") line, err := shared.ReadStdin() if err != nil { return err } if len(line) < 1 || line[0] != 'y' && line[0] != 'Y' { return fmt.Errorf(i18n.G("Server certificate NACKed by user")) } } dnam := d.Config.ConfigPath("servercerts") err := os.MkdirAll(dnam, 0750) if err != nil { return fmt.Errorf(i18n.G("Could not create server cert dir")) } certf := fmt.Sprintf("%s/%s.crt", dnam, d.Name) certOut, err := os.Create(certf) if err != nil { return err } pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certificate.Raw}) certOut.Close() // Setup a new connection, this time with the remote certificate d, err = lxd.NewClient(config, remote) if err != nil { return err } } if d.IsPublic() || public { config.Remotes[server] = lxd.RemoteConfig{Addr: addr, Public: true} if err := d.Finger(); err != nil { return err } return nil } if d.AmTrusted() { // server already has our cert, so we're done return nil } if password == "" { fmt.Printf(i18n.G("Admin password for %s: "), server) pwd, err := terminal.ReadPassword(0) if err != nil { /* We got an error, maybe this isn't a terminal, let's try to * read it as a file */ pwd, err = shared.ReadStdin() if err != nil { return err } } fmt.Println("") password = string(pwd) } err = d.AddMyCertToServer(password) if err != nil { return err } if !d.AmTrusted() { return fmt.Errorf(i18n.G("Server doesn't trust us after adding our cert")) } fmt.Println(i18n.G("Client certificate stored at server: "), server) return nil }
func addServer(config *lxd.Config, server string, addr string, acceptCert bool, password string, public bool) error { var r_scheme string var r_host string var r_port string /* Complex remote URL parsing */ remote_url, err := url.Parse(addr) if err != nil { return err } if remote_url.Scheme != "" { if remote_url.Scheme != "unix" && remote_url.Scheme != "https" { r_scheme = "https" } else { r_scheme = remote_url.Scheme } } else if addr[0] == '/' { r_scheme = "unix" } else { if !shared.PathExists(addr) { r_scheme = "https" } else { r_scheme = "unix" } } if remote_url.Host != "" { r_host = remote_url.Host } else { r_host = addr } host, port, err := net.SplitHostPort(r_host) if err == nil { r_host = host r_port = port } else { r_port = shared.DefaultPort } if r_scheme == "unix" { if addr[0:5] == "unix:" { if addr[0:7] == "unix://" { if len(addr) > 8 { r_host = addr[8:] } else { r_host = "" } } else { r_host = addr[6:] } } r_port = "" } if strings.Contains(r_host, ":") && !strings.HasPrefix(r_host, "[") { r_host = fmt.Sprintf("[%s]", r_host) } if r_port != "" { addr = r_scheme + "://" + r_host + ":" + r_port } else { addr = r_scheme + "://" + r_host } if config.Remotes == nil { config.Remotes = make(map[string]lxd.RemoteConfig) } /* Actually add the remote */ config.Remotes[server] = lxd.RemoteConfig{Addr: addr} remote := config.ParseRemote(server) c, err := lxd.NewClient(config, remote) if err != nil { return err } if len(addr) > 5 && addr[0:5] == "unix:" { // NewClient succeeded so there was a lxd there (we fingered // it) so just accept it return nil } /* grab the server's cert */ err = c.Finger() if err != nil { return err } if !acceptCert { // Try to use the CAs on localhost to verify the cert so we // don't have to bother the user. digest, err := c.TryVerifyServerCert(host) if err != nil { fmt.Printf(i18n.G("Certificate fingerprint: %x")+"\n", digest) fmt.Printf(i18n.G("ok (y/n)?") + " ") line, err := shared.ReadStdin() if err != nil { return err } if len(line) < 1 || line[0] != 'y' && line[0] != 'Y' { return fmt.Errorf(i18n.G("Server certificate NACKed by user")) } } } err = c.SaveCert(host) if err != nil { return err } if c.IsPublic() || public { config.Remotes[server] = lxd.RemoteConfig{Addr: addr, Public: true} if err := c.Finger(); err != nil { return err } return nil } if c.AmTrusted() { // server already has our cert, so we're done return nil } if password == "" { fmt.Printf(i18n.G("Admin password for %s: "), server) pwd, err := terminal.ReadPassword(0) if err != nil { /* We got an error, maybe this isn't a terminal, let's try to * read it as a file */ pwd, err = shared.ReadStdin() if err != nil { return err } } fmt.Println("") password = string(pwd) } err = c.AddMyCertToServer(password) if err != nil { return err } if !c.AmTrusted() { return fmt.Errorf(i18n.G("Server doesn't trust us after adding our cert")) } fmt.Println(i18n.G("Client certificate stored at server: "), server) return nil }
func (c *configCmd) run(config *lxd.Config, args []string) error { if len(args) < 1 { return errArgs } switch args[0] { case "unset": if len(args) < 2 { return errArgs } // 2 args means we're unsetting a server key if len(args) == 2 { key := args[1] c, err := lxd.NewClient(config, "") if err != nil { return err } _, err = c.SetServerConfig(key, "") return err } // 3 args is a container config key args = append(args, "") return doSet(config, args) case "set": if len(args) < 3 { return errArgs } // 3 args means we're setting a server key if len(args) == 3 { key := args[1] c, err := lxd.NewClient(config, "") if err != nil { return err } _, err = c.SetServerConfig(key, args[2]) return err } // 4 args is a container config key return doSet(config, args) case "trust": if len(args) < 2 { return errArgs } switch args[1] { case "list": var remote string if len(args) == 3 { remote = config.ParseRemote(args[2]) } else { remote = config.DefaultRemote } d, err := lxd.NewClient(config, remote) if err != nil { return err } trust, err := d.CertificateList() if err != nil { return err } for _, fingerprint := range trust { fmt.Println(fmt.Sprintf("%s", fingerprint)) } return nil case "add": var remote string if len(args) < 3 { return fmt.Errorf(gettext.Gettext("No cert provided to add")) } else if len(args) == 4 { remote = config.ParseRemote(args[2]) } else { remote = config.DefaultRemote } d, err := lxd.NewClient(config, remote) if err != nil { return err } fname := args[len(args)-1] cert, err := shared.ReadCert(fname) if err != nil { return err } name, _ := shared.SplitExt(fname) return d.CertificateAdd(cert, name) case "remove": var remote string if len(args) < 3 { return fmt.Errorf(gettext.Gettext("No fingerprint specified.")) } else if len(args) == 4 { remote = config.ParseRemote(args[2]) } else { remote = config.DefaultRemote } d, err := lxd.NewClient(config, remote) if err != nil { return err } return d.CertificateRemove(args[len(args)-1]) default: return fmt.Errorf(gettext.Gettext("Unkonwn config trust command %s"), args[1]) } case "show": remote := "" container := "" if len(args) > 1 { remote, container = config.ParseRemoteAndContainer(args[1]) if container == "" { return fmt.Errorf(gettext.Gettext("Show for remotes is not yet supported\n")) } } d, err := lxd.NewClient(config, remote) if err != nil { return err } var data []byte if len(args) == 1 || container == "" { config, err := d.ServerStatus() if err != nil { return err } brief := config.BriefState() data, err = yaml.Marshal(&brief) } else { config, err := d.ContainerStatus(container, false) if err != nil { return err } brief := config.BriefState() data, err = yaml.Marshal(&brief) } fmt.Printf("%s", data) return nil case "get": if len(args) != 3 { return errArgs } remote, container := config.ParseRemoteAndContainer(args[1]) d, err := lxd.NewClient(config, remote) if err != nil { return err } resp, err := d.ContainerStatus(container, false) if err != nil { return err } fmt.Printf("%s: %s\n", args[2], resp.Config[args[2]]) return nil case "profile": case "device": if len(args) < 2 { return errArgs } switch args[1] { case "list": return deviceList(config, "container", args) case "add": return deviceAdd(config, "container", args) case "remove": return deviceRm(config, "container", args) case "show": return deviceShow(config, "container", args) default: return errArgs } case "edit": if len(args) != 2 { return errArgs } remote, container := config.ParseRemoteAndContainer(args[1]) d, err := lxd.NewClient(config, remote) if err != nil { return err } return doConfigEdit(d, container) default: return errArgs } return errArgs }
func (c *imageCmd) run(config *lxd.Config, args []string) error { var remote string if len(args) < 1 { return errArgs } switch args[0] { case "alias": if len(args) < 2 { return errArgs } return c.doImageAlias(config, args) case "copy": /* copy [<remote>:]<image> [<rmeote>:]<image> */ if len(args) != 3 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { inName = "default" } destRemote, outName := config.ParseRemoteAndContainer(args[2]) if outName != "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } dest, err := lxd.NewClient(config, destRemote) if err != nil { return err } progressHandler := func(progress string) { fmt.Printf(i18n.G("Copying the image: %s")+"\r", progress) } err = d.CopyImage(inName, dest, c.copyAliases, c.addAliases, c.publicImage, c.autoUpdate, progressHandler) if err == nil { fmt.Println(i18n.G("Image copied successfully!")) } return err case "delete": /* delete [<remote>:]<image> [<remote>:][<image>...] */ if len(args) < 2 { return errArgs } for _, arg := range args[1:] { remote, inName := config.ParseRemoteAndContainer(arg) if inName == "" { inName = "default" } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := c.dereferenceAlias(d, inName) err = d.DeleteImage(image) if err != nil { return err } } return nil case "info": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { inName = "default" } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := c.dereferenceAlias(d, inName) info, err := d.GetImageInfo(image) if err != nil { return err } public := i18n.G("no") if info.Public { public = i18n.G("yes") } autoUpdate := i18n.G("disabled") if info.AutoUpdate { autoUpdate = i18n.G("enabled") } fmt.Printf(i18n.G("Fingerprint: %s")+"\n", info.Fingerprint) fmt.Printf(i18n.G("Size: %.2fMB")+"\n", float64(info.Size)/1024.0/1024.0) fmt.Printf(i18n.G("Architecture: %s")+"\n", info.Architecture) fmt.Printf(i18n.G("Public: %s")+"\n", public) fmt.Printf(i18n.G("Timestamps:") + "\n") const layout = "2006/01/02 15:04 UTC" if info.CreationDate.UTC().Unix() != 0 { fmt.Printf(" "+i18n.G("Created: %s")+"\n", info.CreationDate.UTC().Format(layout)) } fmt.Printf(" "+i18n.G("Uploaded: %s")+"\n", info.UploadDate.UTC().Format(layout)) if info.ExpiryDate.UTC().Unix() != 0 { fmt.Printf(" "+i18n.G("Expires: %s")+"\n", info.ExpiryDate.UTC().Format(layout)) } else { fmt.Printf(" " + i18n.G("Expires: never") + "\n") } fmt.Println(i18n.G("Properties:")) for key, value := range info.Properties { fmt.Printf(" %s: %s\n", key, value) } fmt.Println(i18n.G("Aliases:")) for _, alias := range info.Aliases { fmt.Printf(" - %s\n", alias.Name) } fmt.Printf(i18n.G("Auto update: %s")+"\n", autoUpdate) if info.Source != nil { fmt.Println(i18n.G("Source:")) fmt.Printf(" Server: %s\n", info.Source.Server) fmt.Printf(" Protocol: %s\n", info.Source.Protocol) fmt.Printf(" Alias: %s\n", info.Source.Alias) } return nil case "import": if len(args) < 2 { return errArgs } var fingerprint string var imageFile string var rootfsFile string var properties []string var remote string for _, arg := range args[1:] { split := strings.Split(arg, "=") if len(split) == 1 || shared.PathExists(arg) { if strings.HasSuffix(arg, ":") { remote = config.ParseRemote(arg) } else { if imageFile == "" { imageFile = args[1] } else { rootfsFile = arg } } } else { properties = append(properties, arg) } } if remote == "" { remote = config.DefaultRemote } if imageFile == "" { imageFile = args[1] properties = properties[1:] } d, err := lxd.NewClient(config, remote) if err != nil { return err } handler := func(percent int) { fmt.Printf(i18n.G("Transferring image: %d%%")+"\r", percent) if percent == 100 { fmt.Printf("\n") } } if strings.HasPrefix(imageFile, "https://") { progressHandler := func(progress string) { fmt.Printf(i18n.G("Importing the image: %s")+"\r", progress) } fingerprint, err = d.PostImageURL(imageFile, properties, c.publicImage, c.addAliases, progressHandler) } else if strings.HasPrefix(imageFile, "http://") { return fmt.Errorf(i18n.G("Only https:// is supported for remote image import.")) } else { fingerprint, err = d.PostImage(imageFile, rootfsFile, properties, c.publicImage, c.addAliases, handler) } if err != nil { return err } fmt.Printf(i18n.G("Image imported with fingerprint: %s")+"\n", fingerprint) return nil case "list": filters := []string{} if len(args) > 1 { result := strings.SplitN(args[1], ":", 2) if len(result) == 1 { filters = append(filters, args[1]) remote, _ = config.ParseRemoteAndContainer("") } else { remote, _ = config.ParseRemoteAndContainer(args[1]) } } else { remote, _ = config.ParseRemoteAndContainer("") } if len(args) > 2 { for _, filter := range args[2:] { filters = append(filters, filter) } } d, err := lxd.NewClient(config, remote) if err != nil { return err } var images []shared.ImageInfo allImages, err := d.ListImages() if err != nil { return err } for _, image := range allImages { if !c.imageShouldShow(filters, &image) { continue } images = append(images, image) } return c.showImages(images, filters) case "edit": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { inName = "default" } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := c.dereferenceAlias(d, inName) if image == "" { image = inName } return c.doImageEdit(d, image) case "export": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { inName = "default" } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := c.dereferenceAlias(d, inName) target := "." if len(args) > 2 { target = args[2] } outfile, err := d.ExportImage(image, target) if err != nil { return err } if target != "-" { fmt.Printf(i18n.G("Output is in %s")+"\n", outfile) } return nil case "show": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { inName = "default" } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := c.dereferenceAlias(d, inName) info, err := d.GetImageInfo(image) if err != nil { return err } properties := info.Brief() data, err := yaml.Marshal(&properties) fmt.Printf("%s", data) return err default: return errArgs } }
func (c *imageCmd) run(config *lxd.Config, args []string) error { var remote string if len(args) < 1 { return errArgs } switch args[0] { case "alias": if len(args) < 2 { return errArgs } return doImageAlias(config, args) case "copy": /* copy [<remote>:]<image> [<rmeote>:]<image> */ if len(args) != 3 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } destRemote, outName := config.ParseRemoteAndContainer(args[2]) if outName != "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } dest, err := lxd.NewClient(config, destRemote) if err != nil { return err } image := dereferenceAlias(d, inName) return d.CopyImage(image, dest, copyAliases, addAliases, publicImage) case "delete": /* delete [<remote>:]<image> */ if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) err = d.DeleteImage(image) return err case "info": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) info, err := d.GetImageInfo(image) if err != nil { return err } fmt.Printf(gettext.Gettext("Fingerprint: %s")+"\n", info.Fingerprint) public := gettext.Gettext("no") if shared.InterfaceToBool(info) { public = gettext.Gettext("yes") } fmt.Printf(gettext.Gettext("Size: %.2vMB")+"\n", float64(info.Size)/1024.0/1024.0) arch, _ := shared.ArchitectureName(info.Architecture) fmt.Printf(gettext.Gettext("Architecture: %s")+"\n", arch) fmt.Printf(gettext.Gettext("Public: %s")+"\n", public) fmt.Printf(gettext.Gettext("Timestamps:") + "\n") const layout = "2006/01/02 15:04 UTC" if info.CreationDate != 0 { fmt.Printf(" "+gettext.Gettext("Created: %s")+"\n", time.Unix(info.CreationDate, 0).UTC().Format(layout)) } fmt.Printf(" "+gettext.Gettext("Uploaded: %s")+"\n", time.Unix(info.UploadDate, 0).UTC().Format(layout)) if info.ExpiryDate != 0 { fmt.Printf(" "+gettext.Gettext("Expires: %s")+"\n", time.Unix(info.ExpiryDate, 0).UTC().Format(layout)) } else { fmt.Printf(" " + gettext.Gettext("Expires: never") + "\n") } fmt.Println(gettext.Gettext("Properties:")) for key, value := range info.Properties { fmt.Printf(" %s: %s\n", key, value) } fmt.Println(gettext.Gettext("Aliases:")) for _, alias := range info.Aliases { fmt.Printf(" - %s\n", alias.Name) } return nil case "import": if len(args) < 2 { return errArgs } var imageFile string var rootfsFile string var properties []string var remote string for _, arg := range args[1:] { split := strings.Split(arg, "=") if len(split) == 1 || shared.PathExists(arg) { if strings.HasSuffix(arg, ":") { remote = config.ParseRemote(arg) } else { if imageFile == "" { imageFile = args[1] } else { rootfsFile = arg } } } else { properties = append(properties, arg) } } if imageFile == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } fingerprint, err := d.PostImage(imageFile, rootfsFile, properties, publicImage, addAliases) if err != nil { return err } fmt.Printf(gettext.Gettext("Image imported with fingerprint: %s")+"\n", fingerprint) return nil case "list": if len(args) > 1 { remote, _ = config.ParseRemoteAndContainer(args[1]) } else { remote, _ = config.ParseRemoteAndContainer("") } d, err := lxd.NewClient(config, remote) if err != nil { return err } images, err := d.ListImages() if err != nil { return err } return showImages(images) case "edit": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) if image == "" { image = inName } if !terminal.IsTerminal(syscall.Stdin) { contents, err := ioutil.ReadAll(os.Stdin) if err != nil { return err } newdata := shared.BriefImageInfo{} err = yaml.Unmarshal(contents, &newdata) if err != nil { return err } return d.PutImageInfo(image, newdata) } info, err := d.GetImageInfo(image) if err != nil { return err } properties := info.BriefInfo() editor := os.Getenv("VISUAL") if editor == "" { editor = os.Getenv("EDITOR") if editor == "" { editor = "vi" } } data, err := yaml.Marshal(&properties) f, err := ioutil.TempFile("", "lxd_lxc_image_") if err != nil { return err } fname := f.Name() if err = f.Chmod(0600); err != nil { f.Close() os.Remove(fname) return err } f.Write([]byte(imageEditHelp + "\n")) f.Write(data) f.Close() defer os.Remove(fname) for { cmdParts := strings.Fields(editor) cmd := exec.Command(cmdParts[0], append(cmdParts[1:], fname)...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr err = cmd.Run() if err != nil { return err } contents, err := ioutil.ReadFile(fname) if err != nil { return err } newdata := shared.BriefImageInfo{} err = yaml.Unmarshal(contents, &newdata) if err != nil { fmt.Fprintf(os.Stderr, gettext.Gettext("YAML parse error %v")+"\n", err) fmt.Println(gettext.Gettext("Press enter to open the editor again")) _, err := os.Stdin.Read(make([]byte, 1)) if err != nil { return err } continue } err = d.PutImageInfo(image, newdata) break } return err case "export": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) target := "." if len(args) > 2 { target = args[2] } _, outfile, err := d.ExportImage(image, target) if err != nil { return err } if target != "-" { fmt.Printf(gettext.Gettext("Output is in %s")+"\n", outfile) } return nil case "show": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) info, err := d.GetImageInfo(image) if err != nil { return err } properties := info.BriefInfo() data, err := yaml.Marshal(&properties) fmt.Printf("%s", data) return err default: return fmt.Errorf(gettext.Gettext("Unknown image command %s"), args[0]) } }
func addServer(config *lxd.Config, server string, addr string, acceptCert bool, password string) error { var r_scheme string var r_host string var r_port string remote_url, err := url.Parse(addr) if err != nil { return err } if remote_url.Scheme != "" { if remote_url.Scheme != "unix" && remote_url.Scheme != "https" { r_scheme = "https" } else { r_scheme = remote_url.Scheme } } else if addr[0] == '/' { r_scheme = "unix" } else { if !shared.PathExists(addr) { r_scheme = "https" } else { r_scheme = "unix" } } if remote_url.Host != "" { r_host = remote_url.Host } else { r_host = addr } host, port, err := net.SplitHostPort(r_host) if err == nil { r_host = host r_port = port } else { r_port = shared.DefaultPort } if r_scheme == "unix" { if addr[0:5] == "unix:" { if addr[0:7] == "unix://" { r_host = addr[8:] } else { r_host = addr[6:] } } r_port = "" } if strings.Contains(r_host, ":") && !strings.HasPrefix(r_host, "[") { r_host = fmt.Sprintf("[%s]", r_host) } if r_port != "" { addr = r_scheme + "://" + r_host + ":" + r_port } else { addr = r_scheme + "://" + r_host } if config.Remotes == nil { config.Remotes = make(map[string]lxd.RemoteConfig) } config.Remotes[server] = lxd.RemoteConfig{Addr: addr} remote := config.ParseRemote(server) c, err := lxd.NewClient(config, remote) if err != nil { return err } if len(addr) > 5 && addr[0:5] == "unix:" { // NewClient succeeded so there was a lxd there (we fingered // it) so just accept it return nil } err = c.UserAuthServerCert(host, acceptCert) if err != nil { return err } if c.AmTrusted() { // server already has our cert, so we're done return nil } if password == "" { fmt.Printf(gettext.Gettext("Admin password for %s: "), server) pwd, err := terminal.ReadPassword(0) if err != nil { /* We got an error, maybe this isn't a terminal, let's try to * read it as a file */ pwd, err = shared.ReadStdin() if err != nil { return err } } fmt.Printf("\n") password = string(pwd) } err = c.AddMyCertToServer(password) if err != nil { return err } if !c.AmTrusted() { return fmt.Errorf(gettext.Gettext("Server doesn't trust us after adding our cert")) } fmt.Println(gettext.Gettext("Client certificate stored at server: "), server) return nil }
func (c *imageCmd) run(config *lxd.Config, args []string) error { var remote string if len(args) < 1 { return errArgs } switch args[0] { case "alias": if len(args) < 2 { return errArgs } return doImageAlias(config, args) case "copy": /* copy [<remote>:]<image> [<rmeote>:]<image> */ if len(args) != 3 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } destRemote, outName := config.ParseRemoteAndContainer(args[2]) if outName != "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } dest, err := lxd.NewClient(config, destRemote) if err != nil { return err } image := dereferenceAlias(d, inName) progressHandler := func(progress string) { fmt.Printf(i18n.G("Copying the image: %s")+"\r", progress) } return d.CopyImage(image, dest, copyAliases, addAliases, publicImage, progressHandler) case "delete": /* delete [<remote>:]<image> */ if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) err = d.DeleteImage(image) return err case "info": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) info, err := d.GetImageInfo(image) if err != nil { return err } fmt.Printf(i18n.G("Fingerprint: %s")+"\n", info.Fingerprint) public := i18n.G("no") // FIXME: InterfaceToBool is there for backward compatibility if shared.InterfaceToBool(info) { public = i18n.G("yes") } fmt.Printf(i18n.G("Size: %.2fMB")+"\n", float64(info.Size)/1024.0/1024.0) arch, _ := shared.ArchitectureName(info.Architecture) fmt.Printf(i18n.G("Architecture: %s")+"\n", arch) fmt.Printf(i18n.G("Public: %s")+"\n", public) fmt.Printf(i18n.G("Timestamps:") + "\n") const layout = "2006/01/02 15:04 UTC" if info.CreationDate != 0 { fmt.Printf(" "+i18n.G("Created: %s")+"\n", time.Unix(info.CreationDate, 0).UTC().Format(layout)) } fmt.Printf(" "+i18n.G("Uploaded: %s")+"\n", time.Unix(info.UploadDate, 0).UTC().Format(layout)) if info.ExpiryDate != 0 { fmt.Printf(" "+i18n.G("Expires: %s")+"\n", time.Unix(info.ExpiryDate, 0).UTC().Format(layout)) } else { fmt.Printf(" " + i18n.G("Expires: never") + "\n") } fmt.Println(i18n.G("Properties:")) for key, value := range info.Properties { fmt.Printf(" %s: %s\n", key, value) } fmt.Println(i18n.G("Aliases:")) for _, alias := range info.Aliases { fmt.Printf(" - %s\n", alias.Name) } return nil case "import": if len(args) < 2 { return errArgs } var fingerprint string var imageFile string var rootfsFile string var properties []string var remote string for _, arg := range args[1:] { split := strings.Split(arg, "=") if len(split) == 1 || shared.PathExists(arg) { if strings.HasSuffix(arg, ":") { remote = config.ParseRemote(arg) } else { if imageFile == "" { imageFile = args[1] } else { rootfsFile = arg } } } else { properties = append(properties, arg) } } if remote == "" { remote = config.DefaultRemote } if imageFile == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } if strings.HasPrefix(imageFile, "https://") { fingerprint, err = d.PostImageURL(imageFile, publicImage, addAliases) } else if strings.HasPrefix(imageFile, "http://") { return fmt.Errorf(i18n.G("Only https:// is supported for remote image import.")) } else { fingerprint, err = d.PostImage(imageFile, rootfsFile, properties, publicImage, addAliases) } if err != nil { return err } fmt.Printf(i18n.G("Image imported with fingerprint: %s")+"\n", fingerprint) return nil case "list": filters := []string{} if len(args) > 1 { result := strings.SplitN(args[1], ":", 2) if len(result) == 1 { filters = append(filters, args[1]) remote, _ = config.ParseRemoteAndContainer("") } else { remote, _ = config.ParseRemoteAndContainer(args[1]) } } else { remote, _ = config.ParseRemoteAndContainer("") } if len(args) > 2 { for _, filter := range args[2:] { filters = append(filters, filter) } } d, err := lxd.NewClient(config, remote) if err != nil { return err } images, err := d.ListImages() if err != nil { return err } return showImages(images, filters) case "edit": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) if image == "" { image = inName } return doImageEdit(d, image) case "export": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) target := "." if len(args) > 2 { target = args[2] } _, outfile, err := d.ExportImage(image, target) if err != nil { return err } if target != "-" { fmt.Printf(i18n.G("Output is in %s")+"\n", outfile) } return nil case "show": if len(args) < 2 { return errArgs } remote, inName := config.ParseRemoteAndContainer(args[1]) if inName == "" { return errArgs } d, err := lxd.NewClient(config, remote) if err != nil { return err } image := dereferenceAlias(d, inName) info, err := d.GetImageInfo(image) if err != nil { return err } properties := info.BriefInfo() data, err := yaml.Marshal(&properties) fmt.Printf("%s", data) return err default: return errArgs } }
func (c *configCmd) run(config *lxd.Config, args []string) error { if len(args) < 1 { return errArgs } switch args[0] { case "unset": if len(args) < 2 { return errArgs } // Deal with local server if len(args) == 2 { c, err := lxd.NewClient(config, config.DefaultRemote) if err != nil { return err } ss, err := c.ServerStatus() if err != nil { return err } _, ok := ss.Config[args[1]] if !ok { return fmt.Errorf(i18n.G("Can't unset key '%s', it's not currently set."), args[1]) } _, err = c.SetServerConfig(args[1], "") return err } // Deal with remote server remote, container := config.ParseRemoteAndContainer(args[1]) if container == "" { c, err := lxd.NewClient(config, remote) if err != nil { return err } ss, err := c.ServerStatus() if err != nil { return err } _, ok := ss.Config[args[1]] if !ok { return fmt.Errorf(i18n.G("Can't unset key '%s', it's not currently set."), args[1]) } _, err = c.SetServerConfig(args[2], "") return err } // Deal with container args = append(args, "") return c.doSet(config, args, true) case "set": if len(args) < 3 { return errArgs } // Deal with local server if len(args) == 3 { c, err := lxd.NewClient(config, config.DefaultRemote) if err != nil { return err } _, err = c.SetServerConfig(args[1], args[2]) return err } // Deal with remote server remote, container := config.ParseRemoteAndContainer(args[1]) if container == "" { c, err := lxd.NewClient(config, remote) if err != nil { return err } _, err = c.SetServerConfig(args[2], args[3]) return err } // Deal with container return c.doSet(config, args, false) case "trust": if len(args) < 2 { return errArgs } switch args[1] { case "list": var remote string if len(args) == 3 { remote = config.ParseRemote(args[2]) } else { remote = config.DefaultRemote } d, err := lxd.NewClient(config, remote) if err != nil { return err } trust, err := d.CertificateList() if err != nil { return err } data := [][]string{} for _, cert := range trust { fp := cert.Fingerprint[0:12] certBlock, _ := pem.Decode([]byte(cert.Certificate)) if certBlock == nil { return fmt.Errorf(i18n.G("Invalid certificate")) } cert, err := x509.ParseCertificate(certBlock.Bytes) if err != nil { return err } const layout = "Jan 2, 2006 at 3:04pm (MST)" issue := cert.NotBefore.Format(layout) expiry := cert.NotAfter.Format(layout) data = append(data, []string{fp, cert.Subject.CommonName, issue, expiry}) } table := tablewriter.NewWriter(os.Stdout) table.SetAutoWrapText(false) table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetRowLine(true) table.SetHeader([]string{ i18n.G("FINGERPRINT"), i18n.G("COMMON NAME"), i18n.G("ISSUE DATE"), i18n.G("EXPIRY DATE")}) sort.Sort(SortImage(data)) table.AppendBulk(data) table.Render() return nil case "add": var remote string if len(args) < 3 { return fmt.Errorf(i18n.G("No certificate provided to add")) } else if len(args) == 4 { remote = config.ParseRemote(args[2]) } else { remote = config.DefaultRemote } d, err := lxd.NewClient(config, remote) if err != nil { return err } fname := args[len(args)-1] cert, err := shared.ReadCert(fname) if err != nil { return err } name, _ := shared.SplitExt(fname) return d.CertificateAdd(cert, name) case "remove": var remote string if len(args) < 3 { return fmt.Errorf(i18n.G("No fingerprint specified.")) } else if len(args) == 4 { remote = config.ParseRemote(args[2]) } else { remote = config.DefaultRemote } d, err := lxd.NewClient(config, remote) if err != nil { return err } return d.CertificateRemove(args[len(args)-1]) default: return errArgs } case "show": remote := config.DefaultRemote container := "" if len(args) > 1 { remote, container = config.ParseRemoteAndContainer(args[1]) } d, err := lxd.NewClient(config, remote) if err != nil { return err } var data []byte if len(args) == 1 || container == "" { config, err := d.ServerStatus() if err != nil { return err } brief := config.Brief() data, err = yaml.Marshal(&brief) } else { var brief shared.BriefContainerInfo if shared.IsSnapshot(container) { config, err := d.SnapshotInfo(container) if err != nil { return err } brief = shared.BriefContainerInfo{ Profiles: config.Profiles, Config: config.Config, Devices: config.Devices, Ephemeral: config.Ephemeral, } if c.expanded { brief = shared.BriefContainerInfo{ Profiles: config.Profiles, Config: config.ExpandedConfig, Devices: config.ExpandedDevices, Ephemeral: config.Ephemeral, } } } else { config, err := d.ContainerInfo(container) if err != nil { return err } brief = config.Brief() if c.expanded { brief = config.BriefExpanded() } } data, err = yaml.Marshal(&brief) if err != nil { return err } } fmt.Printf("%s", data) return nil case "get": if len(args) > 3 || len(args) < 2 { return errArgs } remote := config.DefaultRemote container := "" key := args[1] if len(args) > 2 { remote, container = config.ParseRemoteAndContainer(args[1]) key = args[2] } d, err := lxd.NewClient(config, remote) if err != nil { return err } if container != "" { resp, err := d.ContainerInfo(container) if err != nil { return err } fmt.Println(resp.Config[key]) } else { resp, err := d.ServerStatus() if err != nil { return err } value := resp.Config[key] if value == nil { value = "" } else if value == true { value = "true" } else if value == false { value = "false" } fmt.Println(value) } return nil case "profile": case "device": if len(args) < 2 { return errArgs } switch args[1] { case "list": return c.deviceList(config, "container", args) case "add": return c.deviceAdd(config, "container", args) case "remove": return c.deviceRm(config, "container", args) case "get": return c.deviceGet(config, "container", args) case "set": return c.deviceSet(config, "container", args) case "unset": return c.deviceUnset(config, "container", args) case "show": return c.deviceShow(config, "container", args) default: return errArgs } case "edit": if len(args) < 1 { return errArgs } remote := config.DefaultRemote container := "" if len(args) > 1 { remote, container = config.ParseRemoteAndContainer(args[1]) } d, err := lxd.NewClient(config, remote) if err != nil { return err } if len(args) == 1 || container == "" { return c.doDaemonConfigEdit(d) } return c.doContainerConfigEdit(d, container) default: return errArgs } return errArgs }
func (c *configCmd) run(config *lxd.Config, args []string) error { if len(args) < 1 { return errArgs } switch args[0] { case "unset": if len(args) < 2 { return errArgs } // Deal with local server if len(args) == 2 { c, err := lxd.NewClient(config, config.DefaultRemote) if err != nil { return err } _, err = c.SetServerConfig(args[1], "") return err } // Deal with remote server remote, container := config.ParseRemoteAndContainer(args[1]) if container == "" { c, err := lxd.NewClient(config, remote) if err != nil { return err } _, err = c.SetServerConfig(args[2], "") return err } // Deal with container args = append(args, "") return doSet(config, args) case "set": if len(args) < 3 { return errArgs } // Deal with local server if len(args) == 3 { c, err := lxd.NewClient(config, config.DefaultRemote) if err != nil { return err } _, err = c.SetServerConfig(args[1], args[2]) return err } // Deal with remote server remote, container := config.ParseRemoteAndContainer(args[1]) if container == "" { c, err := lxd.NewClient(config, remote) if err != nil { return err } _, err = c.SetServerConfig(args[2], args[3]) return err } // Deal with container return doSet(config, args) case "trust": if len(args) < 2 { return errArgs } switch args[1] { case "list": var remote string if len(args) == 3 { remote = config.ParseRemote(args[2]) } else { remote = config.DefaultRemote } d, err := lxd.NewClient(config, remote) if err != nil { return err } trust, err := d.CertificateList() if err != nil { return err } data := [][]string{} for _, cert := range trust { fp := cert.Fingerprint[0:12] certBlock, _ := pem.Decode([]byte(cert.Certificate)) cert, err := x509.ParseCertificate(certBlock.Bytes) if err != nil { return err } const layout = "Jan 2, 2006 at 3:04pm (MST)" issue := cert.NotBefore.Format(layout) expiry := cert.NotAfter.Format(layout) data = append(data, []string{fp, cert.Subject.CommonName, issue, expiry}) } table := tablewriter.NewWriter(os.Stdout) table.SetHeader([]string{ i18n.G("FINGERPRINT"), i18n.G("COMMON NAME"), i18n.G("ISSUE DATE"), i18n.G("EXPIRY DATE")}) for _, v := range data { table.Append(v) } table.Render() return nil case "add": var remote string if len(args) < 3 { return fmt.Errorf(i18n.G("No certificate provided to add")) } else if len(args) == 4 { remote = config.ParseRemote(args[2]) } else { remote = config.DefaultRemote } d, err := lxd.NewClient(config, remote) if err != nil { return err } fname := args[len(args)-1] cert, err := shared.ReadCert(fname) if err != nil { return err } name, _ := shared.SplitExt(fname) return d.CertificateAdd(cert, name) case "remove": var remote string if len(args) < 3 { return fmt.Errorf(i18n.G("No fingerprint specified.")) } else if len(args) == 4 { remote = config.ParseRemote(args[2]) } else { remote = config.DefaultRemote } d, err := lxd.NewClient(config, remote) if err != nil { return err } return d.CertificateRemove(args[len(args)-1]) default: return errArgs } case "show": remote := config.DefaultRemote container := "" if len(args) > 1 { remote, container = config.ParseRemoteAndContainer(args[1]) } d, err := lxd.NewClient(config, remote) if err != nil { return err } var data []byte if len(args) == 1 || container == "" { config, err := d.ServerStatus() if err != nil { return err } brief := config.BriefState() data, err = yaml.Marshal(&brief) } else { config, err := d.ContainerStatus(container) if err != nil { return err } brief := config.BriefState() if expanded { brief = config.BriefStateExpanded() } data, err = yaml.Marshal(&brief) } fmt.Printf("%s", data) return nil case "get": if len(args) > 3 || len(args) < 2 { return errArgs } remote := config.DefaultRemote container := "" key := args[1] if len(args) > 2 { remote, container = config.ParseRemoteAndContainer(args[1]) key = args[2] } d, err := lxd.NewClient(config, remote) if err != nil { return err } if container != "" { resp, err := d.ContainerStatus(container) if err != nil { return err } fmt.Printf("%s: %s\n", key, resp.Config[key]) } else { resp, err := d.ServerStatus() if err != nil { return err } value := resp.Config[key] if value == nil { value = "" } else if value == true { value = "true" } else if value == false { value = "false" } fmt.Printf("%s: %s\n", key, value) } return nil case "profile": case "device": if len(args) < 2 { return errArgs } switch args[1] { case "list": return deviceList(config, "container", args) case "add": return deviceAdd(config, "container", args) case "remove": return deviceRm(config, "container", args) case "show": return deviceShow(config, "container", args) default: return errArgs } case "edit": if len(args) != 2 { return errArgs } remote, container := config.ParseRemoteAndContainer(args[1]) d, err := lxd.NewClient(config, remote) if err != nil { return err } return doConfigEdit(d, container) default: return errArgs } return errArgs }
func addServer(config *lxd.Config, server string, addr string, acceptCert bool, password string, public bool) error { var r_scheme string var r_host string var r_port string /* Complex remote URL parsing */ remote_url, err := url.Parse(addr) if err != nil { return err } if remote_url.Scheme != "" { if remote_url.Scheme != "unix" && remote_url.Scheme != "https" { r_scheme = "https" } else { r_scheme = remote_url.Scheme } } else if addr[0] == '/' { r_scheme = "unix" } else { if !shared.PathExists(addr) { r_scheme = "https" } else { r_scheme = "unix" } } if remote_url.Host != "" { r_host = remote_url.Host } else { r_host = addr } host, port, err := net.SplitHostPort(r_host) if err == nil { r_host = host r_port = port } else { r_port = shared.DefaultPort } if r_scheme == "unix" { if addr[0:5] == "unix:" { if addr[0:7] == "unix://" { r_host = addr[8:] } else { r_host = addr[6:] } } r_port = "" } if strings.Contains(r_host, ":") && !strings.HasPrefix(r_host, "[") { r_host = fmt.Sprintf("[%s]", r_host) } if r_port != "" { addr = r_scheme + "://" + r_host + ":" + r_port } else { addr = r_scheme + "://" + r_host } if config.Remotes == nil { config.Remotes = make(map[string]lxd.RemoteConfig) } /* Actually add the remote */ config.Remotes[server] = lxd.RemoteConfig{Addr: addr, Public: public} remote := config.ParseRemote(server) c, err := lxd.NewClient(config, remote) if err != nil { return err } if len(addr) > 5 && addr[0:5] == "unix:" { // NewClient succeeded so there was a lxd there (we fingered // it) so just accept it return nil } err = c.UserAuthServerCert(host, acceptCert) if err != nil { return err } if public { if err := c.Finger(); err != nil { return err } return nil } if c.AmTrusted() { // server already has our cert, so we're done return nil } if password == "" { return fmt.Errorf(gettext.Gettext("You need to add a password")) } err = c.AddMyCertToServer(password) if err != nil { return err } if !c.AmTrusted() { return fmt.Errorf(gettext.Gettext("Server doesn't trust us after adding our cert")) } fmt.Println(gettext.Gettext("Client certificate stored at server: "), server) return nil }