Пример #1
0
func main() {
	if err := run(); err != nil {
		// The action we take depends on the error we get.
		msg := fmt.Sprintf(i18n.G("error: %v"), err)
		switch t := err.(type) {
		case *url.Error:
			switch u := t.Err.(type) {
			case *net.OpError:
				if u.Op == "dial" && u.Net == "unix" {
					switch errno := u.Err.(type) {
					case syscall.Errno:
						switch errno {
						case syscall.ENOENT:
							msg = i18n.G("LXD socket not found; is LXD running?")
						case syscall.ECONNREFUSED:
							msg = i18n.G("Connection refused; is LXD running?")
						case syscall.EACCES:
							msg = i18n.G("Permisson denied, are you in the lxd group?")
						default:
							msg = fmt.Sprintf("%d %s", uintptr(errno), errno.Error())
						}
					}
				}
			}
		}

		fmt.Fprintln(os.Stderr, fmt.Sprintf("%s", msg))
		os.Exit(1)
	}
}
Пример #2
0
func (c *publishCmd) flags() {
	gnuflag.BoolVar(&c.makePublic, "public", false, i18n.G("Make the image public"))
	gnuflag.Var(&c.pAliases, "alias", i18n.G("New alias to define at target"))
	gnuflag.BoolVar(&c.Force, "force", false, i18n.G("Stop the container if currently running"))
	gnuflag.BoolVar(&c.Force, "f", false, i18n.G("Stop the container if currently running"))
	gnuflag.StringVar(&c.compression_algorithm, "compression", "", i18n.G("Define a compression algorithm: for image or none"))
}
Пример #3
0
Файл: image.go Проект: vahe/lxd
func (c *imageCmd) flags() {
	gnuflag.BoolVar(&c.publicImage, "public", false, i18n.G("Make image public"))
	gnuflag.BoolVar(&c.copyAliases, "copy-aliases", false, i18n.G("Copy aliases from source"))
	gnuflag.BoolVar(&c.autoUpdate, "auto-update", false, i18n.G("Keep the image up to date after initial copy"))
	gnuflag.Var(&c.addAliases, "alias", i18n.G("New alias to define at target"))
	gnuflag.StringVar(&c.format, "format", "table", i18n.G("Format"))
}
Пример #4
0
Файл: list.go Проект: vahe/lxd
func (c *listCmd) typeColumnData(cInfo shared.ContainerInfo, cState *shared.ContainerState, cSnaps []shared.SnapshotInfo) string {
	if cInfo.Ephemeral {
		return i18n.G("EPHEMERAL")
	} else {
		return i18n.G("PERSISTENT")
	}
}
Пример #5
0
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
}
Пример #6
0
func (c *actionCmd) flags() {
	if c.hasTimeout {
		gnuflag.IntVar(&c.timeout, "timeout", -1, i18n.G("Time to wait for the container before killing it."))
		gnuflag.BoolVar(&c.force, "force", false, i18n.G("Force the container to shutdown."))
		gnuflag.BoolVar(&c.stateful, "stateful", false, i18n.G("Store the container state (only for stop)."))
		gnuflag.BoolVar(&c.stateless, "stateless", false, i18n.G("Ignore the container state (only forstart)."))
	}
}
Пример #7
0
Файл: image.go Проект: vahe/lxd
func (c *imageCmd) showImages(images []shared.ImageInfo, filters []string) error {
	switch c.format {
	case listFormatTable:
		data := [][]string{}
		for _, image := range images {
			if !c.imageShouldShow(filters, &image) {
				continue
			}

			shortest := c.shortestAlias(image.Aliases)
			if len(image.Aliases) > 1 {
				shortest = fmt.Sprintf(i18n.G("%s (%d more)"), shortest, len(image.Aliases)-1)
			}
			fp := image.Fingerprint[0:12]
			public := i18n.G("no")
			description := c.findDescription(image.Properties)

			if image.Public {
				public = i18n.G("yes")
			}

			const layout = "Jan 2, 2006 at 3:04pm (MST)"
			uploaded := image.UploadDate.UTC().Format(layout)
			size := fmt.Sprintf("%.2fMB", float64(image.Size)/1024.0/1024.0)
			data = append(data, []string{shortest, fp, public, description, image.Architecture, size, uploaded})
		}

		table := tablewriter.NewWriter(os.Stdout)
		table.SetAutoWrapText(false)
		table.SetAlignment(tablewriter.ALIGN_LEFT)
		table.SetRowLine(true)
		table.SetHeader([]string{
			i18n.G("ALIAS"),
			i18n.G("FINGERPRINT"),
			i18n.G("PUBLIC"),
			i18n.G("DESCRIPTION"),
			i18n.G("ARCH"),
			i18n.G("SIZE"),
			i18n.G("UPLOAD DATE")})
		sort.Sort(SortImage(data))
		table.AppendBulk(data)
		table.Render()
	case listFormatJSON:
		data := make([]*shared.ImageInfo, len(images))
		for i := range images {
			data[i] = &images[i]
		}
		enc := json.NewEncoder(os.Stdout)
		err := enc.Encode(data)
		if err != nil {
			return err
		}
	default:
		return fmt.Errorf("invalid format %q", c.format)
	}

	return nil
}
Пример #8
0
Файл: config.go Проект: vahe/lxd
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
}
Пример #9
0
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
}
Пример #10
0
func (c *deleteCmd) promptDelete(name string) error {
	reader := bufio.NewReader(os.Stdin)
	fmt.Printf(i18n.G("Remove %s (yes/no): "), name)
	input, _ := reader.ReadString('\n')
	input = strings.TrimSuffix(input, "\n")
	if !shared.StringInSlice(strings.ToLower(input), []string{i18n.G("yes")}) {
		return fmt.Errorf(i18n.G("User aborted delete operation."))
	}

	return nil
}
Пример #11
0
func execIfAliases(config *lxd.Config, origArgs []string) {
	newArgs, expanded := expandAlias(config, origArgs)
	if !expanded {
		return
	}

	path, err := exec.LookPath(origArgs[0])
	if err != nil {
		fmt.Fprintf(os.Stderr, i18n.G("processing aliases failed %s\n"), err)
		os.Exit(5)
	}
	ret := syscall.Exec(path, newArgs, syscall.Environ())
	fmt.Fprintf(os.Stderr, i18n.G("processing aliases failed %s\n"), ret)
	os.Exit(5)
}
Пример #12
0
func (c *networkCmd) doNetworkDetach(client *lxd.Client, name string, args []string) error {
	if len(args) < 1 || len(args) > 2 {
		return errArgs
	}

	containerName := args[0]
	devName := ""
	if len(args) > 1 {
		devName = args[1]
	}

	container, err := client.ContainerInfo(containerName)
	if err != nil {
		return err
	}

	if devName == "" {
		for n, d := range container.Devices {
			if d["type"] == "nic" && d["parent"] == name {
				if devName != "" {
					return fmt.Errorf(i18n.G("More than one device matches, specify the device name."))
				}

				devName = n
			}
		}
	}

	if devName == "" {
		return fmt.Errorf(i18n.G("No device found for this network"))
	}

	device, ok := container.Devices[devName]
	if !ok {
		return fmt.Errorf(i18n.G("The specified device doesn't exist"))
	}

	if device["type"] != "nic" || device["parent"] != name {
		return fmt.Errorf(i18n.G("The specified device doesn't match the network"))
	}

	resp, err := client.ContainerDeviceDelete(containerName, devName)
	if err != nil {
		return err
	}

	return client.WaitForSuccess(resp.Operation)
}
Пример #13
0
Файл: config.go Проект: vahe/lxd
func (c *configCmd) 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
	}
	if which != "profile" {
		err = client.WaitForSuccess(resp.Operation)
	}
	if err == nil {
		fmt.Printf(i18n.G("Device %s removed from %s")+"\n", devname, name)
	}
	return err
}
Пример #14
0
func (c *configCmd) 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(i18n.G("Device %s added to %s")+"\n", devname, name)
	if which == "profile" {
		return nil
	}
	return client.WaitForSuccess(resp.Operation)
}
Пример #15
0
func getRemoteCertificate(address string) (*x509.Certificate, error) {
	// Setup a permissive TLS config
	tlsConfig, err := shared.GetTLSConfig("", "", nil)
	if err != nil {
		return nil, err
	}

	tlsConfig.InsecureSkipVerify = true
	tr := &http.Transport{
		TLSClientConfig: tlsConfig,
		Dial:            shared.RFC3493Dialer,
		Proxy:           shared.ProxyFromEnvironment,
	}

	// Connect
	client := &http.Client{Transport: tr}
	resp, err := client.Get(address)
	if err != nil {
		return nil, err
	}

	// Retrieve the certificate
	if resp.TLS == nil || len(resp.TLS.PeerCertificates) == 0 {
		return nil, fmt.Errorf(i18n.G("Unable to read remote TLS certificate"))
	}

	return resp.TLS.PeerCertificates[0], nil
}
Пример #16
0
func (c *imageCmd) usage() string {
	return i18n.G(
		`Manipulate container images.

In LXD containers are created from images. Those images were themselves
either generated from an existing container or downloaded from an image
server.

When using remote images, LXD will automatically cache images for you
and remove them upon expiration.

The image unique identifier is the hash (sha-256) of its representation
as a compressed tarball (or for split images, the concatenation of the
metadata and rootfs tarballs).

Images can be referenced by their full hash, shortest unique partial
hash or alias name (if one is set).


lxc image import <tarball> [rootfs tarball|URL] [remote:] [--public] [--created-at=ISO-8601] [--expires-at=ISO-8601] [--fingerprint=FINGERPRINT] [prop=value]
    Import an image tarball (or tarballs) into the LXD image store.

lxc image copy [remote:]<image> <remote>: [--alias=ALIAS].. [--copy-aliases] [--public] [--auto-update]
    Copy an image from one LXD daemon to another over the network.

    The auto-update flag instructs the server to keep this image up to
    date. It requires the source to be an alias and for it to be public.

lxc image delete [remote:]<image>
    Delete an image from the LXD image store.

lxc image export [remote:]<image>
    Export an image from the LXD image store into a distributable tarball.

lxc image info [remote:]<image>
    Print everything LXD knows about a given image.

lxc image list [remote:] [filter]
    List images in the LXD image store. Filters may be of the
    <key>=<value> form for property based filtering, or part of the image
    hash or part of the image alias name.

lxc image show [remote:]<image>
    Yaml output of the user modifiable properties of an image.

lxc image edit [remote:]<image>
    Edit image, either by launching external editor or reading STDIN.
    Example: lxc image edit <image> # launch editor
             cat image.yml | lxc image edit <image> # read from image.yml

lxc image alias create [remote:]<alias> <fingerprint>
    Create a new alias for an existing image.

lxc image alias delete [remote:]<alias>
    Delete an alias.

lxc image alias list [remote:] [filter]
    List the aliases. Filters may be part of the image hash or part of the image alias name.
`)
}
Пример #17
0
func (c *profileCmd) usage() string {
	return i18n.G(
		`Manage configuration profiles.

lxc profile list [filters]                     List available profiles.
lxc profile show <profile>                     Show details of a profile.
lxc profile create <profile>                   Create a profile.
lxc profile copy <profile> <remote>            Copy the profile to the specified remote.
lxc profile get <profile> <key>                Get profile configuration.
lxc profile set <profile> <key> <value>        Set profile configuration.
lxc profile delete <profile>                   Delete a profile.
lxc profile edit <profile>
    Edit profile, either by launching external editor or reading STDIN.
    Example: lxc profile edit <profile> # launch editor
             cat profile.yml | lxc profile edit <profile> # read from profile.yml
lxc profile apply <container> <profiles>
    Apply a comma-separated list of profiles to a container, in order.
    All profiles passed in this call (and only those) will be applied
    to the specified container.
    Example: lxc profile apply foo default,bar # Apply default and bar
             lxc profile apply foo default # Only default is active
             lxc profile apply '' # no profiles are applied anymore
             lxc profile apply bar,default # Apply default second now

Devices:
lxc profile device list <profile>              List devices in the given profile.
lxc profile device show <profile>              Show full device details in the given profile.
lxc profile device remove <profile> <name>     Remove a device from a profile.
lxc profile device add <profile name> <device name> <device type> [key=value]...
    Add a profile device, such as a disk or a nic, to the containers
    using the specified profile.`)
}
Пример #18
0
func (c *profileCmd) doProfileDelete(client *lxd.Client, p string) error {
	err := client.ProfileDelete(p)
	if err == nil {
		fmt.Printf(i18n.G("Profile %s deleted")+"\n", p)
	}
	return err
}
Пример #19
0
func (c *listCmd) usage() string {
	return i18n.G(
		`Lists the available resources.

lxc list [resource] [filters] [-c columns] [--fast]

The filters are:
* A single keyword like "web" which will list any container with "web" in its name.
* A key/value pair referring to a configuration item. For those, the namespace can be abreviated to the smallest unambiguous identifier:
* "user.blah=abc" will list all containers with the "blah" user property set to "abc"
* "u.blah=abc" will do the same
* "security.privileged=1" will list all privileged containers
* "s.privileged=1" will do the same

The columns are:
* 4 - IPv4 address
* 6 - IPv6 address
* a - architecture
* c - creation date
* n - name
* p - pid of container init process
* P - profiles
* s - state
* S - number of snapshots
* t - type (persistent or ephemeral)

Default column layout: ns46tS
Fast column layout: nsacPt`)
}
Пример #20
0
Файл: init.go Проект: vahe/lxd
func (c *initCmd) checkNetwork(d *lxd.Client, name string) {
	ct, err := d.ContainerInfo(name)
	if err != nil {
		return
	}

	for _, d := range ct.ExpandedDevices {
		if d["type"] == "nic" {
			return
		}
	}

	fmt.Fprintf(os.Stderr, "\n"+i18n.G("The container you are starting doesn’t have any network attached to it.")+"\n")
	fmt.Fprintf(os.Stderr, "  "+i18n.G("To create a new network, use: lxc network create")+"\n")
	fmt.Fprintf(os.Stderr, "  "+i18n.G("To assign a network to a container, use: lxc network assign")+"\n\n")
}
Пример #21
0
func (c *profileCmd) doProfileAssign(client *lxd.Client, d string, p string) error {
	resp, err := client.AssignProfile(d, p)
	if err != nil {
		return err
	}

	err = client.WaitForSuccess(resp.Operation)
	if err == nil {
		if p == "" {
			p = i18n.G("(none)")
		}
		fmt.Printf(i18n.G("Profiles %s applied to %s")+"\n", p, d)
	}

	return err
}
Пример #22
0
func (c *profileCmd) doProfileRemove(client *lxd.Client, d string, p string) error {
	ct, err := client.ContainerInfo(d)
	if err != nil {
		return err
	}

	if !shared.StringInSlice(p, ct.Profiles) {
		return fmt.Errorf("Profile %s isn't currently applied to %s", p, d)
	}

	profiles := []string{}
	for _, profile := range ct.Profiles {
		if profile == p {
			continue
		}

		profiles = append(profiles, profile)
	}

	ct.Profiles = profiles

	err = client.UpdateContainerConfig(d, ct.Brief())
	if err != nil {
		return err
	}

	fmt.Printf(i18n.G("Profile %s removed from %s")+"\n", p, d)

	return err
}
Пример #23
0
func (c *listCmd) usage() string {
	return i18n.G(
		`Lists the available resources.

lxc list [resource] [filters] [--format table|json] [-c columns] [--fast]

The filters are:
* A single keyword like "web" which will list any container with a name starting by "web".
* A regular expression on the container name. (e.g. .*web.*01$)
* A key/value pair referring to a configuration item. For those, the namespace can be abreviated to the smallest unambiguous identifier:
 * "user.blah=abc" will list all containers with the "blah" user property set to "abc".
 * "u.blah=abc" will do the same
 * "security.privileged=1" will list all privileged containers
 * "s.privileged=1" will do the same
* A regular expression matching a configuration item or its value. (e.g. volatile.eth0.hwaddr=00:16:3e:.*)

Columns for table format are:
* 4 - IPv4 address
* 6 - IPv6 address
* a - architecture
* c - creation date
* l - last used date
* n - name
* p - pid of container init process
* P - profiles
* s - state
* S - number of snapshots
* t - type (persistent or ephemeral)

Default column layout: ns46tS
Fast column layout: nsacPt`)
}
Пример #24
0
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(i18n.G("'/' not allowed in snapshot name"))
	}

	resp, err := d.Snapshot(name, snapname, c.stateful)
	if err != nil {
		return err
	}

	return d.WaitForSuccess(resp.Operation)
}
Пример #25
0
func (c *deleteCmd) usage() string {
	return i18n.G(
		`Delete containers or snapshots.

lxc delete [remote:]<container>[/<snapshot>] [remote:][<container>[/<snapshot>]...]

Destroy containers or snapshots with any attached data (configuration, snapshots, ...).`)
}
Пример #26
0
func (c *networkCmd) doNetworkDelete(client *lxd.Client, name string) error {
	err := client.NetworkDelete(name)
	if err == nil {
		fmt.Printf(i18n.G("Network %s deleted")+"\n", name)
	}

	return err
}
Пример #27
0
func (c *infoCmd) usage() string {
	return i18n.G(
		`List information on containers.

This will support remotes and images as well, but only containers for now.

lxc info [<remote>:]container [--show-log]`)
}
Пример #28
0
func (c *execCmd) usage() string {
	return i18n.G(
		`Execute the specified command in a container.

lxc exec [remote:]container [--mode=auto|interactive|non-interactive] [--env EDITOR=/usr/bin/vim]... <command>

Mode defaults to non-interactive, interactive mode is selected if both stdin AND stdout are terminals (stderr is ignored).`)
}
Пример #29
0
Файл: image.go Проект: vahe/lxd
func (c *imageCmd) imageEditHelp() string {
	return i18n.G(
		`### This is a yaml representation of the image properties.
### Any line starting with a '# will be ignored.
###
### Each property is represented by a single line:
### An example would be:
###  description: My custom image`)
}
Пример #30
0
Файл: main.go Проект: vahe/lxd
func main() {
	if err := run(); err != nil {
		msg := fmt.Sprintf(i18n.G("error: %v"), err)

		lxdErr := lxd.GetLocalLXDErr(err)
		switch lxdErr {
		case syscall.ENOENT:
			msg = i18n.G("LXD socket not found; is LXD installed and running?")
		case syscall.ECONNREFUSED:
			msg = i18n.G("Connection refused; is LXD running?")
		case syscall.EACCES:
			msg = i18n.G("Permission denied, are you in the lxd group?")
		}

		fmt.Fprintln(os.Stderr, fmt.Sprintf("%s", msg))
		os.Exit(1)
	}
}