func (c *launchCmd) 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 { remote, name = config.ParseRemoteAndContainer("") } d, err := lxd.NewClient(config, remote) if err != nil { return err } /* * requested_empty_profiles means user requested empty * !requested_empty_profiles but len(profArgs) == 0 means use profile default */ var resp *lxd.Response profiles := []string{} for _, p := range profArgs { profiles = append(profiles, p) } if !requested_empty_profiles && len(profiles) == 0 { resp, err = d.Init(name, iremote, image, nil, configMap, ephem) } else { resp, err = d.Init(name, iremote, image, &profiles, configMap, ephem) } if err != nil { return err } if name == "" { op, err := resp.MetadataAsOperation() if err != nil { return fmt.Errorf(i18n.G("didn't get any affected image, container or snapshot from server")) } containers, ok := op.Resources["containers"] if !ok || len(containers) == 0 { return fmt.Errorf(i18n.G("didn't get any affected image, container or snapshot from server")) } var version string toScan := strings.Replace(containers[0], "/", " ", -1) count, err := fmt.Sscanf(toScan, " %s containers %s", &version, &name) if err != nil { return err } if count != 2 { return fmt.Errorf(i18n.G("bad number of things scanned from image, container or snapshot")) } if version != shared.APIVersion { return fmt.Errorf(i18n.G("got bad version")) } } fmt.Printf(i18n.G("Creating %s")+" ", name) if err = d.WaitForSuccess(resp.Operation); err != nil { return err } fmt.Println(i18n.G("done.")) fmt.Printf(i18n.G("Starting %s")+" ", name) resp, err = d.Action(name, shared.Start, -1, false) if err != nil { return err } err = d.WaitForSuccess(resp.Operation) if err != nil { fmt.Println(i18n.G("error.")) return fmt.Errorf("%s\n"+i18n.G("Try `lxc info --show-log %s` for more info"), err, name) } fmt.Println(i18n.G("done.")) 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 { remote, name = config.ParseRemoteAndContainer("") } d, err := lxd.NewClient(config, remote) if err != nil { return err } // TODO: implement the syntax for supporting other image types/remotes /* * initRequestedEmptyProfiles means user requested empty * !initRequestedEmptyProfiles but len(profArgs) == 0 means use profile default */ profiles := []string{} for _, p := range c.profArgs { profiles = append(profiles, p) } var resp *lxd.Response if name == "" { fmt.Printf(i18n.G("Creating the container") + "\n") } else { fmt.Printf(i18n.G("Creating %s")+"\n", name) } iremote, image = c.guessImage(config, d, remote, iremote, image) devicesMap := map[string]shared.Device{} if c.network != "" { network, err := d.NetworkGet(c.network) if err != nil { return err } if network.Type == "bridge" { devicesMap[c.network] = shared.Device{"type": "nic", "nictype": "bridged", "parent": c.network} } else { devicesMap[c.network] = shared.Device{"type": "nic", "nictype": "macvlan", "parent": c.network} } } if !initRequestedEmptyProfiles && len(profiles) == 0 { resp, err = d.Init(name, iremote, image, nil, configMap, devicesMap, c.ephem) } else { resp, err = d.Init(name, iremote, image, &profiles, configMap, devicesMap, c.ephem) } if err != nil { return err } c.initProgressTracker(d, resp.Operation) err = d.WaitForSuccess(resp.Operation) if err != nil { return err } else { op, err := resp.MetadataAsOperation() if err != nil { return fmt.Errorf(i18n.G("didn't get any affected image, container or snapshot from server")) } containers, ok := op.Resources["containers"] if !ok || len(containers) == 0 { return fmt.Errorf(i18n.G("didn't get any affected image, container or snapshot from server")) } if len(containers) == 1 && name == "" { fields := strings.Split(containers[0], "/") fmt.Printf(i18n.G("Container name is: %s")+"\n", fields[len(fields)-1]) } } c.checkNetwork(d, name) 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 { remote, name = config.ParseRemoteAndContainer("") } 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 name == "" { fmt.Printf(i18n.G("Creating") + " ") } else { fmt.Printf(i18n.G("Creating %s")+" ", name) } if !requested_empty_profiles && len(profiles) == 0 { resp, err = d.Init(name, iremote, image, nil, configMap, ephem) } else { resp, err = d.Init(name, iremote, image, &profiles, configMap, ephem) } if err != nil { return err } err = d.WaitForSuccess(resp.Operation) if err != nil { fmt.Println(i18n.G("error.")) return err } else { op, err := resp.MetadataAsOperation() if err != nil { return fmt.Errorf(i18n.G("didn't get any affected image, container or snapshot from server")) } containers, ok := op.Resources["containers"] if !ok || len(containers) == 0 { return fmt.Errorf(i18n.G("didn't get any affected image, container or snapshot from server")) } if len(containers) == 1 && name == "" { cname := path.Base(containers[0]) fmt.Println(cname, i18n.G("done.")) } else { fmt.Println(i18n.G("done.")) } } return nil }
func (c *copyCmd) copyContainer(config *lxd.Config, sourceResource string, destResource string, keepVolatile bool, ephemeral int) error { sourceRemote, sourceName := config.ParseRemoteAndContainer(sourceResource) destRemote, destName := config.ParseRemoteAndContainer(destResource) if sourceName == "" { return fmt.Errorf(i18n.G("you must specify a source container name")) } if destName == "" && destResource != "" { destName = sourceName } source, err := lxd.NewClient(config, sourceRemote) if err != nil { return err } var status struct { Architecture string Devices shared.Devices Config map[string]string Profiles []string } // TODO: presumably we want to do this for copying snapshots too? We // need to think a bit more about how we track the baseImage in the // face of LVM and snapshots in general; this will probably make more // sense once that work is done. baseImage := "" if !shared.IsSnapshot(sourceName) { result, err := source.ContainerInfo(sourceName) if err != nil { return err } status.Architecture = result.Architecture status.Devices = result.Devices status.Config = result.Config status.Profiles = result.Profiles } else { result, err := source.SnapshotInfo(sourceName) if err != nil { return err } status.Architecture = result.Architecture status.Devices = result.Devices status.Config = result.Config status.Profiles = result.Profiles } if c.profArgs != nil { status.Profiles = append(status.Profiles, c.profArgs...) } if configMap != nil { for key, value := range configMap { status.Config[key] = value } } baseImage = status.Config["volatile.base_image"] if !keepVolatile { for k := range status.Config { if strings.HasPrefix(k, "volatile") { delete(status.Config, k) } } } // Do a local copy if the remotes are the same, otherwise do a migration if sourceRemote == destRemote { if sourceName == destName { return fmt.Errorf(i18n.G("can't copy to the same container name")) } cp, err := source.LocalCopy(sourceName, destName, status.Config, status.Profiles, ephemeral == 1) if err != nil { return err } err = source.WaitForSuccess(cp.Operation) if err != nil { return err } if destResource == "" { op, err := cp.MetadataAsOperation() if err != nil { return fmt.Errorf(i18n.G("didn't get any affected image, container or snapshot from server")) } containers, ok := op.Resources["containers"] if !ok || len(containers) == 0 { return fmt.Errorf(i18n.G("didn't get any affected image, container or snapshot from server")) } fields := strings.Split(containers[0], "/") fmt.Printf(i18n.G("Container name is: %s")+"\n", fields[len(fields)-1]) } return nil } dest, err := lxd.NewClient(config, destRemote) if err != nil { return err } sourceProfs := shared.NewStringSet(status.Profiles) destProfs := []string{} profiles, err := dest.ListProfiles() if err != nil { return err } for _, profile := range profiles { destProfs = append(destProfs, profile.Name) } if !sourceProfs.IsSubset(shared.NewStringSet(destProfs)) { return fmt.Errorf(i18n.G("not all the profiles from the source exist on the target")) } if ephemeral == -1 { ct, err := source.ContainerInfo(sourceName) if err != nil { return err } if ct.Ephemeral { ephemeral = 1 } else { ephemeral = 0 } } sourceWSResponse, err := source.GetMigrationSourceWS(sourceName) if err != nil { return err } secrets := map[string]string{} op, err := sourceWSResponse.MetadataAsOperation() if err != nil { return err } for k, v := range *op.Metadata { secrets[k] = v.(string) } addresses, err := source.Addresses() if err != nil { return err } /* Since we're trying a bunch of different network ports that * may be invalid, we can get "bad handshake" errors when the * websocket code tries to connect. If the first error is a * real error, but the subsequent errors are only network * errors, we should try to report the first real error. Of * course, if all the errors are websocket errors, let's just * report that. */ for _, addr := range addresses { var migration *lxd.Response sourceWSUrl := "https://" + addr + sourceWSResponse.Operation migration, err = dest.MigrateFrom(destName, sourceWSUrl, source.Certificate, secrets, status.Architecture, status.Config, status.Devices, status.Profiles, baseImage, ephemeral == 1, false, source, sourceWSResponse.Operation) if err != nil { continue } if err := source.WaitForSuccess(sourceWSResponse.Operation); err != nil { return err } // If push mode is implemented then MigrateFrom will return a // non-waitable operation. So this needs to be conditionalized // on pull mode. if err = dest.WaitForSuccess(migration.Operation); err != nil { return err } if destResource == "" { op, err := migration.MetadataAsOperation() if err != nil { return fmt.Errorf(i18n.G("didn't get any affected image, container or snapshot from server")) } containers, ok := op.Resources["containers"] if !ok || len(containers) == 0 { return fmt.Errorf(i18n.G("didn't get any affected image, container or snapshot from server")) } fields := strings.Split(containers[0], "/") fmt.Printf(i18n.G("Container name is: %s")+"\n", fields[len(fields)-1]) } return nil } return err }
func (c *launchCmd) 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 { remote, name = config.ParseRemoteAndContainer("") } d, err := lxd.NewClient(config, remote) if err != nil { return err } /* * initRequestedEmptyProfiles means user requested empty * !initRequestedEmptyProfiles but len(profArgs) == 0 means use profile default */ var resp *lxd.Response profiles := []string{} for _, p := range c.init.profArgs { profiles = append(profiles, p) } iremote, image = c.init.guessImage(config, d, remote, iremote, image) devicesMap := map[string]shared.Device{} if c.init.network != "" { network, err := d.NetworkGet(c.init.network) if err != nil { return err } if network.Type == "bridge" { devicesMap[c.init.network] = shared.Device{"type": "nic", "nictype": "bridged", "parent": c.init.network} } else { devicesMap[c.init.network] = shared.Device{"type": "nic", "nictype": "macvlan", "parent": c.init.network} } } if !initRequestedEmptyProfiles && len(profiles) == 0 { resp, err = d.Init(name, iremote, image, nil, configMap, devicesMap, c.init.ephem) } else { resp, err = d.Init(name, iremote, image, &profiles, configMap, devicesMap, c.init.ephem) } if err != nil { return err } progress := ProgressRenderer{} c.init.initProgressTracker(d, &progress, resp.Operation) if name == "" { op, err := resp.MetadataAsOperation() if err != nil { return fmt.Errorf(i18n.G("didn't get any affected image, container or snapshot from server")) } containers, ok := op.Resources["containers"] if !ok || len(containers) == 0 { return fmt.Errorf(i18n.G("didn't get any affected image, container or snapshot from server")) } var version string toScan := strings.Replace(containers[0], "/", " ", -1) count, err := fmt.Sscanf(toScan, " %s containers %s", &version, &name) if err != nil { return err } if count != 2 { return fmt.Errorf(i18n.G("bad number of things scanned from image, container or snapshot")) } if version != shared.APIVersion { return fmt.Errorf(i18n.G("got bad version")) } } fmt.Printf(i18n.G("Creating %s")+"\n", name) if err = d.WaitForSuccess(resp.Operation); err != nil { return err } progress.Done("") c.init.checkNetwork(d, name) fmt.Printf(i18n.G("Starting %s")+"\n", name) resp, err = d.Action(name, shared.Start, -1, false, false) if err != nil { return err } err = d.WaitForSuccess(resp.Operation) if err != nil { prettyName := name if remote != "" { prettyName = fmt.Sprintf("%s:%s", remote, name) } return fmt.Errorf("%s\n"+i18n.G("Try `lxc info --show-log %s` for more info"), err, prettyName) } return nil }