func activateIfNeeded() error { // Don't start a full daemon, we just need DB access d := &Daemon{ IsMock: false, imagesDownloading: map[string]chan bool{}, imagesDownloadingLock: sync.RWMutex{}, } err := initializeDbObject(d, shared.VarPath("lxd.db")) if err != nil { return err } // Look for network socket value, err := d.ConfigValueGet("core.https_address") if err != nil { return err } if value != "" { shared.Debugf("Daemon has core.https_address set, activating...") _, err := lxd.NewClient(&lxd.DefaultConfig, "local") return err } // Look for auto-started or previously started containers d.IdmapSet, err = shared.DefaultIdmapSet() if err != nil { return err } result, err := dbContainersList(d.db, cTypeRegular) if err != nil { return err } for _, name := range result { c, err := containerLoadByName(d, name) if err != nil { return err } config := c.ExpandedConfig() lastState := config["volatile.last_state.power"] autoStart := config["boot.autostart"] if lastState == "RUNNING" || lastState == "Running" || autoStart == "true" { shared.Debugf("Daemon has auto-started containers, activating...") _, err := lxd.NewClient(&lxd.DefaultConfig, "local") return err } } shared.Debugf("No need to start the daemon now.") 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 waitReady() error { if *timeout < 0 { *timeout = 15 } finger := make(chan error, 1) go func() { for { c, err := lxd.NewClient(&lxd.DefaultConfig, "local") if err != nil { time.Sleep(500 * 1e6 * time.Nanosecond) continue } err = c.Finger() if err != nil { time.Sleep(500 * 1e6 * time.Nanosecond) continue } finger <- nil return } }() select { case <-finger: break case <-time.After(time.Second * time.Duration(*timeout)): return fmt.Errorf("LXD still not running after %ds timeout.", *timeout) } 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 run(args []string) error { // Parse command line gnuflag.Parse(true) if len(os.Args) == 1 || !shared.StringInSlice(os.Args[1], []string{"spawn", "delete"}) { fmt.Printf("Usage: %s spawn [--count=COUNT] [--image=IMAGE] [--privileged=BOOL] [--parallel=COUNT]\n", os.Args[0]) fmt.Printf(" %s delete [--parallel=COUNT]\n\n", os.Args[0]) gnuflag.Usage() fmt.Printf("\n") return fmt.Errorf("An action (spawn or delete) must be passed.") } // Connect to LXD c, err := lxd.NewClient(&lxd.DefaultConfig, "local") if err != nil { return err } switch os.Args[1] { case "spawn": return spawnContainers(c, *argCount, *argImage, *argPrivileged) case "delete": return deleteContainers(c) } return nil }
func waitReady() error { var timeout int if *argTimeout == -1 { timeout = 15 } else { timeout = *argTimeout } finger := make(chan error, 1) go func() { for { _, err := lxd.NewClient(&lxd.DefaultConfig, "local") if err != nil { time.Sleep(500 * time.Millisecond) continue } finger <- nil return } }() select { case <-finger: break case <-time.After(time.Second * time.Duration(timeout)): return fmt.Errorf("LXD still not running after %ds timeout.", timeout) } return nil }
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 (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 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 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 *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 *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]) } else { iRemote, iName = config.ParseRemoteAndContainer("") } 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(gettext.Gettext("Container published with fingerprint %s")+"\n", fp) } return err }
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 *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 *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 callHook(args []string) error { if len(args) < 4 { return fmt.Errorf("Invalid arguments") } path := args[1] id := args[2] state := args[3] target := "" err := os.Setenv("LXD_DIR", path) if err != nil { return err } c, err := lxd.NewClient(&lxd.DefaultConfig, "local") if err != nil { return err } url := fmt.Sprintf("%s/internal/containers/%s/on%s", c.BaseURL, id, state) if state == "stop" { target = os.Getenv("LXC_TARGET") if target == "" { target = "unknown" } url = fmt.Sprintf("%s?target=%s", url, target) } req, err := http.NewRequest("GET", url, nil) if err != nil { return err } raw, err := c.Http.Do(req) if err != nil { return err } _, err = lxd.HoistResponse(raw, lxd.Sync) if err != nil { return err } if target == "reboot" { return fmt.Errorf("Reboot must be handled by LXD.") } return nil }
func cmdWaitReady() error { var timeout int if *argTimeout == -1 { timeout = 15 } else { timeout = *argTimeout } finger := make(chan error, 1) go func() { for { c, err := lxd.NewClient(&lxd.DefaultConfig, "local") if err != nil { time.Sleep(500 * time.Millisecond) continue } req, err := http.NewRequest("GET", c.BaseURL+"/internal/ready", nil) if err != nil { time.Sleep(500 * time.Millisecond) continue } raw, err := c.Http.Do(req) if err != nil { time.Sleep(500 * time.Millisecond) continue } _, err = lxd.HoistResponse(raw, lxd.Sync) if err != nil { time.Sleep(500 * time.Millisecond) continue } finger <- nil return } }() select { case <-finger: break case <-time.After(time.Second * time.Duration(timeout)): return fmt.Errorf("LXD still not running after %ds timeout.", timeout) } 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 (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 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 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 run() error { // Usage if len(os.Args) == 1 { fmt.Fprintf(os.Stderr, "Usage: %s create <path> [-auto-start]\n", os.Args[0]) fmt.Fprintf(os.Stderr, " %s destroy\n", os.Args[0]) fmt.Fprintf(os.Stderr, " %s generate-map <path>\n", os.Args[0]) fmt.Fprintf(os.Stderr, " %s generate-dns <format>\n", os.Args[0]) fmt.Fprintf(os.Stderr, " %s start\n", os.Args[0]) fmt.Fprintf(os.Stderr, " %s status\n", os.Args[0]) fmt.Fprintf(os.Stderr, " %s stop\n", os.Args[0]) fmt.Fprintf(os.Stderr, "\nArguments:\n") flag.PrintDefaults() fmt.Fprintf(os.Stderr, "\n") return fmt.Errorf("A command must be provided.") } // Parse the arguments flag.Parse() // Connect to LXD c, err := lxd.NewClient(&lxd.DefaultConfig, "local") if err != nil { return err } // Commands switch os.Args[1] { case "create": return cmdCreate(c, os.Args[2:]) case "destroy": return cmdDestroy(c, os.Args[2:]) case "generate-map": return cmdGenerateMap(c, os.Args[2:]) case "generate-dns": return cmdGenerateDNS(c, os.Args[2:]) case "start": return cmdStart(c, os.Args[2:]) case "status": return cmdStatus(c, os.Args[2:]) case "stop": return cmdStop(c, os.Args[2:]) } 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 *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 }