func deviceAdd(config *lxd.Config, which string, args []string) error { if len(args) < 5 { return errArgs } remote, name := config.ParseRemoteAndContainer(args[2]) client, err := lxd.NewClient(config, remote) if err != nil { return err } devname := args[3] devtype := args[4] var props []string if len(args) > 5 { props = args[5:] } else { props = []string{} } var resp *lxd.Response if which == "profile" { resp, err = client.ProfileDeviceAdd(name, devname, devtype, props) } else { resp, err = client.ContainerDeviceAdd(name, devname, devtype, props) } if err != nil { return err } fmt.Printf(gettext.Gettext("Device %s added to %s\n"), devname, name) if which == "profile" { return nil } return client.WaitForSuccess(resp.Operation) }
func (c *moveCmd) run(config *lxd.Config, args []string) error { if len(args) != 2 { return errArgs } sourceRemote, sourceName := config.ParseRemoteAndContainer(args[0]) destRemote, destName := config.ParseRemoteAndContainer(args[1]) // As an optimization, if the source an destination are the same, do // this via a simple rename. This only works for containers that aren't // running, containers that are running should be live migrated (of // course, this changing of hostname isn't supported right now, so this // simply won't work). if sourceRemote == destRemote { source, err := lxd.NewClient(config, sourceRemote) if err != nil { return err } rename, err := source.Rename(sourceName, destName) if err != nil { return err } return source.WaitForSuccess(rename.Operation) } // A move is just a copy followed by a delete; however, we want to // keep the volatile entries around since we are moving the container. if err := copyContainer(config, args[0], args[1], true, -1); err != nil { return err } return commands["delete"].run(config, args[:1]) }
func doSet(config *lxd.Config, args []string) error { if len(args) != 4 { return errArgs } // [[lxc config]] set dakara:c1 limits.memory 200000 remote, container := config.ParseRemoteAndContainer(args[1]) d, err := lxd.NewClient(config, remote) if err != nil { return err } key := args[2] value := args[3] if !terminal.IsTerminal(int(syscall.Stdin)) && value == "-" { buf, err := ioutil.ReadAll(os.Stdin) if err != nil { return fmt.Errorf("Can't read from stdin: %s", err) } value = string(buf[:]) } return d.SetContainerConfig(container, key, value) }
func deviceRm(config *lxd.Config, which string, args []string) error { if len(args) < 4 { return errArgs } remote, name := config.ParseRemoteAndContainer(args[2]) client, err := lxd.NewClient(config, remote) if err != nil { return err } devname := args[3] var resp *lxd.Response if which == "profile" { resp, err = client.ProfileDeviceDelete(name, devname) } else { resp, err = client.ContainerDeviceDelete(name, devname) } if err != nil { return err } fmt.Printf(gettext.Gettext("Device %s removed from %s\n"), devname, name) if which == "profile" { return nil } return client.WaitForSuccess(resp.Operation) }
func (c *actionCmd) run(config *lxd.Config, args []string) error { if len(args) == 0 { return errArgs } for _, nameArg := range args { remote, name := config.ParseRemoteAndContainer(nameArg) d, err := lxd.NewClient(config, remote) if err != nil { return err } resp, err := d.Action(name, c.action, timeout, force) if err != nil { return err } if resp.Type != lxd.Async { return fmt.Errorf(gettext.Gettext("bad result type from action")) } if err := d.WaitForSuccess(resp.Operation); err != nil { return fmt.Errorf("%s\n"+gettext.Gettext("Try `lxc info --show-log %s` for more info"), err, name) } } return nil }
func (c *monitorCmd) run(config *lxd.Config, args []string) error { var remote string if len(args) > 1 { return errArgs } if len(args) == 0 { remote, _ = config.ParseRemoteAndContainer("") } else { remote, _ = config.ParseRemoteAndContainer(args[0]) } d, err := lxd.NewClient(config, remote) if err != nil { return err } handler := func(message interface{}) { render, err := yaml.Marshal(&message) if err != nil { return } fmt.Printf("%s\n\n", render) } return d.Monitor(typeArgs, handler) }
func (c *snapshotCmd) run(config *lxd.Config, args []string) error { if len(args) < 1 { return errArgs } var snapname string if len(args) < 2 { snapname = "" } else { snapname = args[1] } remote, name := config.ParseRemoteAndContainer(args[0]) d, err := lxd.NewClient(config, remote) if err != nil { return err } // we don't allow '/' in snapshot names if shared.IsSnapshot(snapname) { return fmt.Errorf(gettext.Gettext("'/' not allowed in snapshot name\n")) } resp, err := d.Snapshot(name, snapname, c.stateful) if err != nil { return err } return d.WaitForSuccess(resp.Operation) }
func (c *deleteCmd) run(config *lxd.Config, args []string) error { if len(args) == 0 { return errArgs } for _, nameArg := range args { remote, name := config.ParseRemoteAndContainer(nameArg) d, err := lxd.NewClient(config, remote) if err != nil { return err } if c.interactive { err := c.promptDelete(name) if err != nil { return err } } if shared.IsSnapshot(name) { return c.doDelete(d, name) } ct, err := d.ContainerInfo(name) if err != nil { return err } if ct.StatusCode != 0 && ct.StatusCode != shared.Stopped { if !c.force { return fmt.Errorf(i18n.G("The container is currently running, stop it first or pass --force.")) } resp, err := d.Action(name, shared.Stop, -1, true, false) if err != nil { return err } op, err := d.WaitFor(resp.Operation) if err != nil { return err } if op.StatusCode == shared.Failure { return fmt.Errorf(i18n.G("Stopping container failed!")) } if ct.Ephemeral == true { return nil } } if err := c.doDelete(d, name); err != nil { return err } } return nil }
func (c *execCmd) run(config *lxd.Config, args []string) error { if len(args) < 2 { return errArgs } remote, name := config.ParseRemoteAndContainer(args[0]) d, err := lxd.NewClient(config, remote) if err != nil { return err } env := map[string]string{"HOME": "/root", "USER": "******"} myEnv := os.Environ() for _, ent := range myEnv { if strings.HasPrefix(ent, "TERM=") { env["TERM"] = ent[len("TERM="):] } } for _, arg := range envArgs { pieces := strings.SplitN(arg, "=", 2) value := "" if len(pieces) > 1 { value = pieces[1] } env[pieces[0]] = value } cfd := syscall.Stdout var oldttystate *terminal.State if terminal.IsTerminal(cfd) { oldttystate, err = terminal.MakeRaw(cfd) if err != nil { return err } defer terminal.Restore(cfd, oldttystate) } ret, err := d.Exec(name, args[1:], env, os.Stdin, os.Stdout, os.Stderr) if err != nil { return err } if oldttystate != nil { /* A bit of a special case here: we want to exit with the same code as * the process inside the container, so we explicitly exit here * instead of returning an error. * * Additionally, since os.Exit() exits without running deferred * functions, we restore the terminal explicitly. */ terminal.Restore(cfd, oldttystate) } /* we get the result of waitpid() here so we need to transform it */ os.Exit(ret >> 8) return fmt.Errorf(gettext.Gettext("unreachable return reached")) }
func (c *configCmd) deviceSet(config *lxd.Config, which string, args []string) error { if len(args) < 6 { return errArgs } remote, name := config.ParseRemoteAndContainer(args[2]) client, err := lxd.NewClient(config, remote) if err != nil { return err } devname := args[3] key := args[4] value := args[5] if which == "profile" { st, err := client.ProfileConfig(name) if err != nil { return err } dev, ok := st.Devices[devname] if !ok { return fmt.Errorf(i18n.G("The device doesn't exist")) } dev[key] = value st.Devices[devname] = dev err = client.PutProfile(name, *st) if err != nil { return err } } else { st, err := client.ContainerInfo(name) if err != nil { return err } dev, ok := st.Devices[devname] if !ok { return fmt.Errorf(i18n.G("The device doesn't exist")) } dev[key] = value st.Devices[devname] = dev err = client.UpdateContainerConfig(name, st.Brief()) if err != nil { return err } } return err }
func (c *actionCmd) run(config *lxd.Config, args []string) error { if len(args) == 0 { return errArgs } state := false // Only store state if asked to if c.action == "stop" && c.stateful { state = true } for _, nameArg := range args { remote, name := config.ParseRemoteAndContainer(nameArg) d, err := lxd.NewClient(config, remote) if err != nil { return err } if name == "" { return fmt.Errorf(i18n.G("Must supply container name for: ")+"\"%s\"", nameArg) } if c.action == shared.Start || c.action == shared.Stop { current, err := d.ContainerInfo(name) if err != nil { return err } // "start" for a frozen container means "unfreeze" if current.StatusCode == shared.Frozen { c.action = shared.Unfreeze } // Always restore state (if present) unless asked not to if c.action == shared.Start && current.Stateful && !c.stateless { state = true } } resp, err := d.Action(name, c.action, c.timeout, c.force, state) if err != nil { return err } if resp.Type != lxd.Async { return fmt.Errorf(i18n.G("bad result type from action")) } if err := d.WaitForSuccess(resp.Operation); err != nil { return fmt.Errorf("%s\n"+i18n.G("Try `lxc info --show-log %s` for more info"), err, name) } } return nil }
func (c *publishCmd) run(config *lxd.Config, args []string) error { var cRemote string var cName string iName := "" iRemote := "" properties := map[string]string{} firstprop := 1 // first property is arg[2] if arg[1] is image remote, else arg[1] if len(args) < 1 { return errArgs } cRemote, cName = config.ParseRemoteAndContainer(args[0]) if len(args) >= 2 && !strings.Contains(args[1], "=") { firstprop = 2 iRemote, iName = config.ParseRemoteAndContainer(args[1]) } if cName == "" { return fmt.Errorf(gettext.Gettext("Container name is mandatory")) } if iName != "" { return fmt.Errorf(gettext.Gettext("There is no \"image name\". Did you want an alias?")) } if cRemote != iRemote { /* * Get the source remote to export the container over a websocket, * pass that ws to the dest remote, and have it import it as an * image */ return fmt.Errorf(gettext.Gettext("Publish to remote server is not supported yet")) } d, err := lxd.NewClient(config, iRemote) if err != nil { return err } for i := firstprop; i < len(args); i++ { entry := strings.SplitN(args[i], "=", 2) if len(entry) < 2 { return errArgs } properties[entry[0]] = entry[1] } fp, err := d.ImageFromContainer(cName, makePublic, pAliases, properties) if err == nil { fmt.Printf("Container published with fingerprint %s\n", fp) } return err }
func (c *profileCmd) run(config *lxd.Config, args []string) error { if len(args) < 1 { return errArgs } if args[0] == "list" { return doProfileList(config, args) } if len(args) < 2 { return errArgs } remote, profile := config.ParseRemoteAndContainer(args[1]) client, err := lxd.NewClient(config, remote) if err != nil { return err } switch args[0] { case "create": return doProfileCreate(client, profile) case "delete": return doProfileDelete(client, profile) case "device": return doProfileDevice(config, args) case "edit": return doProfileEdit(client, profile) case "apply": container := profile switch len(args) { case 2: profile = "" case 3: profile = args[2] default: return errArgs } return doProfileApply(client, container, profile) case "get": return doProfileGet(client, profile, args[2:]) case "set": return doProfileSet(client, profile, args[2:]) case "unset": return doProfileSet(client, profile, args[2:]) case "copy": return doProfileCopy(config, client, profile, args[2:]) case "show": return doProfileShow(client, profile) default: return fmt.Errorf(gettext.Gettext("unknown profile cmd %s"), args[0]) } }
func (c *networkCmd) doNetworkList(config *lxd.Config, args []string) error { var remote string if len(args) > 1 { var name string remote, name = config.ParseRemoteAndContainer(args[1]) if name != "" { return fmt.Errorf(i18n.G("Cannot provide container name to list")) } } else { remote = config.DefaultRemote } client, err := lxd.NewClient(config, remote) if err != nil { return err } networks, err := client.ListNetworks() if err != nil { return err } data := [][]string{} for _, network := range networks { if shared.StringInSlice(network.Type, []string{"loopback", "unknown"}) { continue } strManaged := i18n.G("NO") if network.Managed { strManaged = i18n.G("YES") } strUsedBy := fmt.Sprintf("%d", len(network.UsedBy)) data = append(data, []string{network.Name, network.Type, strManaged, strUsedBy}) } table := tablewriter.NewWriter(os.Stdout) table.SetAutoWrapText(false) table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetRowLine(true) table.SetHeader([]string{ i18n.G("NAME"), i18n.G("TYPE"), i18n.G("MANAGED"), i18n.G("USED BY")}) sort.Sort(byName(data)) table.AppendBulk(data) table.Render() return nil }
func generateClientCertificate(config *lxd.Config) error { // Generate a client certificate if necessary. The default repositories are // either local or public, neither of which requires a client certificate. // Generation of the cert is delayed to avoid unnecessary overhead, e.g in // testing scenarios where only the default repositories are used. certf := config.ConfigPath("client.crt") keyf := config.ConfigPath("client.key") if !shared.PathExists(certf) || !shared.PathExists(keyf) { fmt.Fprintf(os.Stderr, i18n.G("Generating a client certificate. This may take a minute...")+"\n") return shared.FindOrGenCert(certf, keyf, true) } return nil }
func (c *listCmd) run(config *lxd.Config, args []string) error { var remote string name := "" filters := []string{} if len(args) != 0 { filters = args if strings.Contains(args[0], ":") && !strings.Contains(args[0], "=") { remote, name = config.ParseRemoteAndContainer(args[0]) filters = args[1:] } else if !strings.Contains(args[0], "=") { remote = config.DefaultRemote name = args[0] } } filters = append(filters, name) if remote == "" { remote = config.DefaultRemote } d, err := lxd.NewClient(config, remote) if err != nil { return err } var cts []shared.ContainerInfo ctslist, err := d.ListContainers() if err != nil { return err } for _, cinfo := range ctslist { if !c.shouldShow(filters, &cinfo) { continue } cts = append(cts, cinfo) } columns, err := c.parseColumns() if err != nil { return err } return c.listContainers(d, cts, filters, columns) }
func doProfileCopy(config *lxd.Config, client *lxd.Client, p string, args []string) error { if len(args) != 1 { return errArgs } remote, newname := config.ParseRemoteAndContainer(args[0]) if newname == "" { newname = p } dest, err := lxd.NewClient(config, remote) if err != nil { return err } return client.ProfileCopy(p, newname, dest) }
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 doSet(config *lxd.Config, args []string) error { if len(args) != 4 { return errArgs } // [[lxc config]] set dakara:c1 limits.memory 200000 remote, container := config.ParseRemoteAndContainer(args[1]) d, err := lxd.NewClient(config, remote) if err != nil { return err } key := args[2] value := args[3] return d.SetContainerConfig(container, key, value) }
func (c *networkCmd) run(config *lxd.Config, args []string) error { if len(args) < 1 { return errArgs } if args[0] == "list" { return c.doNetworkList(config, args) } if len(args) < 2 { return errArgs } remote, network := config.ParseRemoteAndContainer(args[1]) client, err := lxd.NewClient(config, remote) if err != nil { return err } switch args[0] { case "attach": return c.doNetworkAttach(client, network, args[2:]) case "attach-profile": return c.doNetworkAttachProfile(client, network, args[2:]) case "create": return c.doNetworkCreate(client, network, args[2:]) case "delete": return c.doNetworkDelete(client, network) case "detach": return c.doNetworkDetach(client, network, args[2:]) case "detach-profile": return c.doNetworkDetachProfile(client, network, args[2:]) case "edit": return c.doNetworkEdit(client, network) case "get": return c.doNetworkGet(client, network, args[2:]) case "set": return c.doNetworkSet(client, network, args[2:]) case "unset": return c.doNetworkSet(client, network, args[2:]) case "show": return c.doNetworkShow(client, network) default: return errArgs } }
func (c *deleteCmd) run(config *lxd.Config, args []string) error { if len(args) == 0 { return errArgs } for _, nameArg := range args { remote, name := config.ParseRemoteAndContainer(nameArg) d, err := lxd.NewClient(config, remote) if err != nil { return err } ct, err := d.ContainerStatus(name) if err != nil { // Could be a snapshot return doDelete(d, name) } if ct.Status.StatusCode != shared.Stopped { resp, err := d.Action(name, shared.Stop, -1, true) if err != nil { return err } op, err := d.WaitFor(resp.Operation) if err != nil { return err } if op.StatusCode == shared.Failure { return fmt.Errorf(gettext.Gettext("Stopping container failed!")) } if ct.Ephemeral == true { return nil } } if err := doDelete(d, name); err != nil { return err } } return nil }
func (c *initCmd) run(config *lxd.Config, args []string) error { if len(args) > 2 || len(args) < 1 { return errArgs } iremote, image := config.ParseRemoteAndContainer(args[0]) var name string var remote string if len(args) == 2 { remote, name = config.ParseRemoteAndContainer(args[1]) } else { name = "" remote = "" } d, err := lxd.NewClient(config, remote) if err != nil { return err } // TODO: implement the syntax for supporting other image types/remotes /* * requested_empty_profiles means user requested empty * !requested_empty_profiles but len(profArgs) == 0 means use profile default */ profiles := []string{} for _, p := range profArgs { profiles = append(profiles, p) } var resp *lxd.Response if !requested_empty_profiles && len(profiles) == 0 { resp, err = d.Init(name, iremote, image, nil, ephem) } else { resp, err = d.Init(name, iremote, image, &profiles, ephem) } if err != nil { return err } return d.WaitForSuccess(resp.Operation) }
func (c *listCmd) run(config *lxd.Config, args []string) error { var remote string name := "" filters := []string{} if len(args) != 0 { filters = args if strings.Contains(args[0], ":") { remote, name = config.ParseRemoteAndContainer(args[0]) filters = args[1:] } else if !strings.Contains(args[0], "=") { remote = config.DefaultRemote name = args[0] } } if remote == "" { remote = config.DefaultRemote } d, err := lxd.NewClient(config, remote) if err != nil { return err } var cts []shared.ContainerInfo ctslist, err := d.ListContainers() if err != nil { return err } if name == "" { cts = ctslist } else { for _, cinfo := range ctslist { if len(cinfo.State.Name) >= len(name) && cinfo.State.Name[0:len(name)] == name { cts = append(cts, cinfo) } } } return listContainers(cts, filters, len(cts) == 1) }
func (c *configCmd) deviceGet(config *lxd.Config, which string, args []string) error { if len(args) < 5 { return errArgs } remote, name := config.ParseRemoteAndContainer(args[2]) client, err := lxd.NewClient(config, remote) if err != nil { return err } devname := args[3] key := args[4] if which == "profile" { st, err := client.ProfileConfig(name) if err != nil { return err } dev, ok := st.Devices[devname] if !ok { return fmt.Errorf(i18n.G("The device doesn't exist")) } fmt.Println(dev[key]) } else { st, err := client.ContainerInfo(name) if err != nil { return err } dev, ok := st.Devices[devname] if !ok { return fmt.Errorf(i18n.G("The device doesn't exist")) } fmt.Println(dev[key]) } return nil }
func doImageAlias(config *lxd.Config, args []string) error { var remote string switch args[1] { case "list": /* alias list [<remote>:] */ if len(args) > 2 { remote, _ = config.ParseRemoteAndContainer(args[2]) } else { remote, _ = config.ParseRemoteAndContainer("") } d, err := lxd.NewClient(config, remote) if err != nil { return err } resp, err := d.ListAliases() if err != nil { return err } showAliases(resp) return nil case "create": /* alias create [<remote>:]<alias> <target> */ if len(args) < 4 { return errArgs } remote, alias := config.ParseRemoteAndContainer(args[2]) target := args[3] d, err := lxd.NewClient(config, remote) if err != nil { return err } /* TODO - what about description? */ err = d.PostAlias(alias, alias, target) return err case "delete": /* alias delete [<remote>:]<alias> */ if len(args) < 3 { return errArgs } remote, alias := config.ParseRemoteAndContainer(args[2]) d, err := lxd.NewClient(config, remote) if err != nil { return err } err = d.DeleteAlias(alias) return err } return errArgs }
func (c *infoCmd) run(config *lxd.Config, args []string) error { var remote string var cName string if len(args) == 1 { remote, cName = config.ParseRemoteAndContainer(args[0]) } else { remote, cName = config.ParseRemoteAndContainer("") } d, err := lxd.NewClient(config, remote) if err != nil { return err } if cName == "" { return remoteInfo(d) } else { return containerInfo(d, cName, c.showLog) } }
func (c *profileCmd) doProfileList(config *lxd.Config, args []string) error { var remote string if len(args) > 1 { var name string remote, name = config.ParseRemoteAndContainer(args[1]) if name != "" { return fmt.Errorf(i18n.G("Cannot provide container name to list")) } } else { remote = config.DefaultRemote } client, err := lxd.NewClient(config, remote) if err != nil { return err } profiles, err := client.ListProfiles() if err != nil { return err } data := [][]string{} for _, profile := range profiles { strUsedBy := fmt.Sprintf("%d", len(profile.UsedBy)) data = append(data, []string{profile.Name, strUsedBy}) } table := tablewriter.NewWriter(os.Stdout) table.SetAutoWrapText(false) table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetRowLine(true) table.SetHeader([]string{ i18n.G("NAME"), i18n.G("USED BY")}) sort.Sort(byName(data)) table.AppendBulk(data) table.Render() return nil }
func providerConfigure(d *schema.ResourceData) (interface{}, error) { remote := d.Get("remote").(string) scheme := d.Get("scheme").(string) daemon_addr := "" switch scheme { case "unix": daemon_addr = fmt.Sprintf("unix:%s", d.Get("address")) case "https": daemon_addr = fmt.Sprintf("https://%s:%s", d.Get("address"), d.Get("port")) default: err := fmt.Errorf("Invalid scheme: %s", scheme) return nil, err } // build LXD config config := lxd.Config{ ConfigDir: os.ExpandEnv("$HOME/.config/lxc"), Remotes: make(map[string]lxd.RemoteConfig), } config.Remotes[remote] = lxd.RemoteConfig{Addr: daemon_addr} log.Printf("[DEBUG] LXD Config: %#v", config) if scheme == "https" { // validate certifictes exist certf := config.ConfigPath("client.crt") keyf := config.ConfigPath("client.key") if !shared.PathExists(certf) || !shared.PathExists(keyf) { err := fmt.Errorf("Certificate or key not found:\n\t%s\n\t%s", certf, keyf) return nil, err } serverCertf := config.ServerCertPath(remote) if !shared.PathExists(serverCertf) { err := fmt.Errorf("Server certificate not found:\n\t%s", serverCertf) return nil, err } } client, err := lxd.NewClient(&config, remote) if err != nil { err := fmt.Errorf("Could not create LXD client: %s", err) return nil, err } log.Printf("[DEBUG] LXD Client: %#v", client) if err := validateClient(client); err != nil { return nil, err } lxdProv := LxdProvider{ Remote: remote, Client: client, } return &lxdProv, nil }
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 checkFiles(c *gc.C, cfg lxdclient.Config) { var certificate lxdclient.Cert if cfg.Remote.Cert != nil { certificate = *cfg.Remote.Cert } filename := filepath.Join(cfg.Dirname, "client.crt") c.Logf("reading cert PEM from %q", filename) certPEM, err := ioutil.ReadFile(filename) c.Assert(err, jc.ErrorIsNil) c.Check(string(certPEM), gc.Equals, string(certificate.CertPEM)) filename = filepath.Join(cfg.Dirname, "client.key") c.Logf("reading key PEM from %q", filename) keyPEM, err := ioutil.ReadFile(filename) c.Assert(err, jc.ErrorIsNil) c.Check(string(keyPEM), gc.Equals, string(certificate.KeyPEM)) filename = filepath.Join(cfg.Dirname, "config.yml") c.Logf("reading config from %q", filename) configData, err := ioutil.ReadFile(filename) c.Assert(err, jc.ErrorIsNil) var config lxd.Config err = goyaml.Unmarshal(configData, &config) c.Assert(err, jc.ErrorIsNil) c.Check(config.Aliases, gc.HasLen, 0) config.Aliases = nil c.Check(config, jc.DeepEquals, lxd.Config{ DefaultRemote: "local", Remotes: map[string]lxd.RemoteConfig{ "local": lxd.LocalRemote, cfg.Remote.Name: lxd.RemoteConfig{ Addr: "https://" + cfg.Remote.Host + ":8443", Public: false, }, }, Aliases: nil, }) }