Exemplo n.º 1
0
func containerDeleteSnapshots(d *Daemon, cname string) error {
	prefix := fmt.Sprintf("%s/", cname)
	length := len(prefix)
	q := "SELECT name, id FROM containers WHERE type=? AND SUBSTR(name,1,?)=?"
	var id int
	var sname string
	inargs := []interface{}{cTypeSnapshot, length, prefix}
	outfmt := []interface{}{sname, id}
	results, err := dbQueryScan(d.db, q, inargs, outfmt)
	if err != nil {
		return err
	}

	var ids []int

	backingFs, err := shared.GetFilesystem(shared.VarPath("lxc", cname))
	if err != nil && !os.IsNotExist(err) {
		shared.Debugf("Error cleaning up snapshots: %s\n", err)
		return err
	}

	for _, r := range results {
		sname = r[0].(string)
		id = r[1].(int)
		ids = append(ids, id)
		cdir := shared.VarPath("lxc", cname, "snapshots", sname)

		if backingFs == "btrfs" {
			exec.Command("btrfs", "subvolume", "delete", cdir).Run()
		}
		os.RemoveAll(cdir)
	}

	for _, id := range ids {
		_, err = dbExec(d.db, "DELETE FROM containers WHERE id=?", id)
		if err != nil {
			return err
		}
	}

	return nil
}
Exemplo n.º 2
0
func removeContainerPath(d *Daemon, name string) error {
	cpath := shared.VarPath("lxc", name)

	backingFs, err := shared.GetFilesystem(cpath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}

		shared.Debugf("Error cleaning up %s: %s\n", cpath, err)
		return err
	}

	vgname, vgnameIsSet, err := getServerConfigValue(d, "core.lvm_vg_name")
	if err != nil {
		return fmt.Errorf("Error checking server config: %v", err)
	}

	if vgnameIsSet {
		err = shared.LVMRemoveLV(vgname, name)
		if err != nil {
			return fmt.Errorf("failed to remove deleted container LV: %v", err)
		}

	} else if backingFs == "btrfs" && btrfsIsSubvolume(cpath) {
		if err := btrfsDeleteSubvol(cpath); err != nil {
			return err
		}
	}

	err = os.RemoveAll(cpath)
	if err != nil {
		shared.Debugf("Error cleaning up %s: %s\n", cpath, err)
		return err
	}

	return nil
}
Exemplo n.º 3
0
func createFromImage(d *Daemon, req *containerPostReq) Response {
	var hash string
	var err error
	var run func() shared.OperationResult

	backingFs, err := shared.GetFilesystem(d.lxcpath)
	if err != nil {
		return InternalError(err)
	}

	if req.Source.Alias != "" {
		if req.Source.Mode == "pull" && req.Source.Server != "" {
			hash, err = remoteGetImageFingerprint(d, req.Source.Server, req.Source.Alias)
			if err != nil {
				return InternalError(err)
			}
		} else {

			hash, err = dbAliasGet(d.db, req.Source.Alias)
			if err != nil {
				return InternalError(err)
			}
		}
	} else if req.Source.Fingerprint != "" {
		hash = req.Source.Fingerprint
	} else {
		return BadRequest(fmt.Errorf("must specify one of alias or fingerprint for init from image"))
	}

	if req.Source.Server != "" {
		err := ensureLocalImage(d, req.Source.Server, hash, req.Source.Secret)
		if err != nil {
			return InternalError(err)
		}
	}

	imgInfo, err := dbImageGet(d.db, hash, false)
	if err != nil {
		return SmartError(err)
	}
	hash = imgInfo.Fingerprint

	dpath := shared.VarPath("lxc", req.Name)
	if shared.PathExists(dpath) {
		return InternalError(fmt.Errorf("Container exists"))
	}

	name := req.Name

	args := DbCreateContainerArgs{
		d:            d,
		name:         name,
		ctype:        cTypeRegular,
		config:       req.Config,
		profiles:     req.Profiles,
		ephem:        req.Ephemeral,
		baseImage:    hash,
		architecture: imgInfo.Architecture,
	}

	_, err = dbCreateContainer(args)
	if err != nil {
		removeContainerPath(d, name)
		return SmartError(err)
	}

	c, err := newLxdContainer(name, d)
	if err != nil {
		removeContainer(d, name)
		return SmartError(err)
	}

	vgname, vgnameIsSet, err := getServerConfigValue(d, "core.lvm_vg_name")
	if err != nil {
		return InternalError(fmt.Errorf("Error checking server config: %v", err))
	}

	if vgnameIsSet && shared.PathExists(fmt.Sprintf("%s.lv", shared.VarPath("images", hash))) {
		run = shared.OperationWrap(func() error {

			lvpath, err := shared.LVMCreateSnapshotLV(name, hash, vgname)
			if err != nil {
				return fmt.Errorf("Error creating snapshot of source LV '%s/%s': %s", vgname, hash, err)
			}

			destPath := shared.VarPath("lxc", name)
			err = os.MkdirAll(destPath, 0700)
			if err != nil {
				return fmt.Errorf("Error creating container directory: %v", err)
			}

			if !c.isPrivileged() {
				output, err := exec.Command("mount", "-o", "discard", lvpath, destPath).CombinedOutput()
				if err != nil {
					return fmt.Errorf("Error mounting snapshot LV: %v\noutput:'%s'", err, output)
				}

				if err = shiftRootfs(c, c.name, d); err != nil {
					return fmt.Errorf("Error in shiftRootfs: %v", err)
				}

				cpath := shared.VarPath("lxc", c.name)
				output, err = exec.Command("umount", cpath).CombinedOutput()
				if err != nil {
					return fmt.Errorf("Error unmounting '%s' after shiftRootfs: %v", cpath, err)
				}
			}

			return nil
		})

	} else if backingFs == "btrfs" && shared.PathExists(fmt.Sprintf("%s.btrfs", shared.VarPath("images", hash))) {
		run = shared.OperationWrap(func() error {
			if _, err := btrfsCopyImage(hash, name, d); err != nil {
				return err
			}

			if !c.isPrivileged() {
				err = shiftRootfs(c, name, d)
				if err != nil {
					return err
				}
			}

			err = templateApply(c, "create")
			if err != nil {
				return err
			}

			return nil
		})

	} else {
		rootfsPath := fmt.Sprintf("%s/rootfs", dpath)
		err = os.MkdirAll(rootfsPath, 0700)
		if err != nil {
			return InternalError(fmt.Errorf("Error creating rootfs directory"))
		}

		run = shared.OperationWrap(func() error {
			if err := extractImage(hash, name, d); err != nil {
				return err
			}

			if !c.isPrivileged() {
				err = shiftRootfs(c, name, d)
				if err != nil {
					return err
				}
			}

			err = templateApply(c, "create")
			if err != nil {
				return err
			}

			return nil
		})
	}

	resources := make(map[string][]string)
	resources["containers"] = []string{req.Name}

	return &asyncResponse{run: run, resources: resources}
}
Exemplo n.º 4
0
Arquivo: daemon.go Projeto: Ramzec/lxd
// StartDaemon starts the shared daemon with the provided configuration.
func StartDaemon(listenAddr string) (*Daemon, error) {
	d := &Daemon{}

	d.lxcpath = shared.VarPath("lxc")
	err := os.MkdirAll(shared.VarPath("/"), 0755)
	if err != nil {
		return nil, err
	}
	err = os.MkdirAll(d.lxcpath, 0755)
	if err != nil {
		return nil, err
	}

	d.BackingFs, err = shared.GetFilesystem(d.lxcpath)
	if err != nil {
		shared.Debugf("Error detecting backing fs: %s\n", err)
	}

	certf, keyf, err := readMyCert()
	if err != nil {
		return nil, err
	}
	d.certf = certf
	d.keyf = keyf

	err = initDb(d)
	if err != nil {
		return nil, err
	}

	readSavedClientCAList(d)

	d.mux = mux.NewRouter()

	d.mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		SyncResponse(true, []string{"/1.0"}).Render(w)
	})

	for _, c := range api10 {
		d.createCmd("1.0", c)
	}

	d.mux.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		shared.Debugf("sending top level 404: %s", r.URL)
		w.Header().Set("Content-Type", "application/json")
		NotFound.Render(w)
	})

	d.IdmapSet, err = shared.DefaultIdmapSet()
	if err != nil {
		shared.Logf("error reading idmap: %s", err.Error())
		shared.Logf("operations requiring idmap will not be available")
	} else {
		shared.Debugf("Default uid/gid map:")
		for _, lxcmap := range d.IdmapSet.ToLxcString() {
			shared.Debugf(" - " + lxcmap)
		}
	}

	tlsConfig, err := shared.GetTLSConfig(d.certf, d.keyf)
	if err != nil {
		return nil, err
	}

	listeners, err := activation.Listeners(false)
	if err != nil {
		return nil, err
	}

	var localSockets []net.Listener
	var remoteSockets []net.Listener

	if len(listeners) > 0 {
		shared.Debugf("LXD is socket activated.\n")

		for _, listener := range listeners {
			if _, err := os.Stat(listener.Addr().String()); err == nil {
				localSockets = append(localSockets, listener)
			} else {
				tlsListener := tls.NewListener(listener, tlsConfig)
				remoteSockets = append(remoteSockets, tlsListener)
			}
		}
	} else {
		shared.Debugf("LXD isn't socket activated.\n")

		localSocketPath := shared.VarPath("unix.socket")

		// If the socket exists, let's try to connect to it and see if there's
		// a lxd running.
		if _, err := os.Stat(localSocketPath); err == nil {
			c := &lxd.Config{Remotes: map[string]lxd.RemoteConfig{}}
			_, err := lxd.NewClient(c, "")
			if err != nil {
				shared.Debugf("Detected old but dead unix socket, deleting it...")
				// Connecting failed, so let's delete the socket and
				// listen on it ourselves.
				err = os.Remove(localSocketPath)
				if err != nil {
					return nil, err
				}
			}
		}

		unixAddr, err := net.ResolveUnixAddr("unix", localSocketPath)
		if err != nil {
			return nil, fmt.Errorf("cannot resolve unix socket address: %v", err)
		}

		unixl, err := net.ListenUnix("unix", unixAddr)
		if err != nil {
			return nil, fmt.Errorf("cannot listen on unix socket: %v", err)
		}

		if err := os.Chmod(localSocketPath, 0660); err != nil {
			return nil, err
		}

		gid, err := shared.GroupId(*group)
		if err != nil {
			return nil, err
		}

		if err := os.Chown(localSocketPath, os.Getuid(), gid); err != nil {
			return nil, err
		}

		localSockets = append(localSockets, unixl)

		if listenAddr != "" {
			tcpl, err := tls.Listen("tcp", listenAddr, tlsConfig)
			if err != nil {
				return nil, fmt.Errorf("cannot listen on unix socket: %v", err)
			}

			remoteSockets = append(remoteSockets, tcpl)
		}
	}

	d.localSockets = localSockets
	d.remoteSockets = remoteSockets
	d.devlxd, err = createAndBindDevLxd()
	if err != nil {
		return nil, err
	}

	containersRestart(d)
	containersWatch(d)

	d.tomb.Go(func() error {
		for _, socket := range d.localSockets {
			shared.Debugf(" - binding local socket: %s\n", socket.Addr())
			d.tomb.Go(func() error { return http.Serve(socket, d.mux) })
		}
		for _, socket := range d.remoteSockets {
			shared.Debugf(" - binding remote socket: %s\n", socket.Addr())
			d.tomb.Go(func() error { return http.Serve(socket, d.mux) })
		}

		d.tomb.Go(func() error {
			server := devLxdServer(d)
			return server.Serve(d.devlxd)
		})
		return nil
	})

	return d, nil
}
Exemplo n.º 5
0
Arquivo: api10.go Projeto: Ramzec/lxd
func api10Get(d *Daemon, r *http.Request) Response {
	body := shared.Jmap{"api_compat": shared.APICompat}

	if d.isTrustedClient(r) {
		body["auth"] = "trusted"

		uname := syscall.Utsname{}
		if err := syscall.Uname(&uname); err != nil {
			return InternalError(err)
		}

		backing_fs, err := shared.GetFilesystem(d.lxcpath)
		if err != nil {
			return InternalError(err)
		}

		env := shared.Jmap{
			"lxc_version": lxc.Version(),
			"lxd_version": shared.Version,
			"driver":      "lxc",
			"backing_fs":  backing_fs}

		/*
		 * Based on: https://groups.google.com/forum/#!topic/golang-nuts/Jel8Bb-YwX8
		 * there is really no better way to do this, which is
		 * unfortunate. Also, we ditch the more accepted CharsToString
		 * version in that thread, since it doesn't seem as portable,
		 * viz. github issue #206.
		 */
		kernelVersion := ""
		for _, c := range uname.Release {
			if c == 0 {
				break
			}
			kernelVersion += string(byte(c))
		}

		env["kernel_version"] = kernelVersion
		body["environment"] = env

		serverConfig, err := getServerConfig(d)
		if err != nil {
			return InternalError(err)
		}

		config := shared.Jmap{}

		for key, value := range serverConfig {
			if key == "core.trust_password" {
				config[key] = true
			} else {
				config[key] = value
			}
		}

		body["config"] = config
	} else {
		body["auth"] = "untrusted"
	}

	return SyncResponse(true, body)
}