Beispiel #1
0
func unpackImage(d *Daemon, imagefname string, destpath string) error {
	err := unpack(d, imagefname, destpath)
	if err != nil {
		return err
	}

	rootfsPath := fmt.Sprintf("%s/rootfs", destpath)
	if shared.PathExists(imagefname + ".rootfs") {
		err = os.MkdirAll(rootfsPath, 0755)
		if err != nil {
			return fmt.Errorf("Error creating rootfs directory")
		}

		err = unpack(d, imagefname+".rootfs", rootfsPath)
		if err != nil {
			return err
		}
	}

	if !shared.PathExists(rootfsPath) {
		return fmt.Errorf("Image is missing a rootfs: %s", imagefname)
	}

	return nil
}
Beispiel #2
0
// Copy imagefile and btrfs file out of the tmpdir
func pullOutImagefiles(d *Daemon, builddir string, fingerprint string) error {
	imagefname := filepath.Join(builddir, fingerprint)
	imagerootfsfname := filepath.Join(builddir, fingerprint+".rootfs")
	finalName := shared.VarPath("images", fingerprint)
	finalrootfsName := shared.VarPath("images", fingerprint+".rootfs")

	if shared.PathExists(imagerootfsfname) {
		err := os.Rename(imagerootfsfname, finalrootfsName)
		if err != nil {
			return err
		}
	}

	err := os.Rename(imagefname, finalName)
	if err != nil {
		return err
	}

	lvsymlink := fmt.Sprintf("%s.lv", imagefname)
	if shared.PathExists(lvsymlink) {
		dst := shared.VarPath("images", fmt.Sprintf("%s.lv", fingerprint))
		return os.Rename(lvsymlink, dst)
	}

	switch d.BackingFs {
	case "btrfs":
		subvol := fmt.Sprintf("%s.btrfs", imagefname)
		dst := shared.VarPath("images", fmt.Sprintf("%s.btrfs", fingerprint))
		if err := os.Rename(subvol, dst); err != nil {
			return err
		}
	}

	return nil
}
Beispiel #3
0
func storageForFilename(d *Daemon, filename string) (storage, error) {
	config := make(map[string]interface{})
	storageType := storageTypeDir

	if d.IsMock {
		return newStorageWithConfig(d, storageTypeMock, config)
	}

	filesystem, err := filesystemDetect(filename)
	if err != nil {
		return nil, fmt.Errorf("couldn't detect filesystem for '%s': %v", filename, err)
	}

	if shared.PathExists(filename + ".lv") {
		storageType = storageTypeLvm
		lvPath, err := os.Readlink(filename + ".lv")
		if err != nil {
			return nil, fmt.Errorf("couldn't read link dest for '%s': %v", filename+".lv", err)
		}
		vgname := filepath.Base(filepath.Dir(lvPath))
		config["vgName"] = vgname
	} else if shared.PathExists(filename + ".zfs") {
		storageType = storageTypeZfs
	} else if shared.PathExists(filename+".btrfs") || filesystem == "btrfs" {
		storageType = storageTypeBtrfs
	}

	return newStorageWithConfig(d, storageType, config)
}
Beispiel #4
0
/*
 * Export the container to a unshifted tarfile containing:
 * dir/
 *     metadata.yaml
 *     rootfs/
 */
func (c *containerLXD) ExportToTar(snap string, w io.Writer) error {
	if snap == "" && c.IsRunning() {
		return fmt.Errorf("Cannot export a running container as image")
	}

	idmap, err := c.LastIdmapSetGet()
	if err != nil {
		return err
	}

	if idmap != nil {
		if err := idmap.UnshiftRootfs(c.RootfsPathGet()); err != nil {
			return err
		}

		defer idmap.ShiftRootfs(c.RootfsPathGet())
	}

	tw := tar.NewWriter(w)

	// keep track of the first path we saw for each path with nlink>1
	linkmap := map[uint64]string{}

	cDir := c.PathGet("")

	// Path inside the tar image is the pathname starting after cDir
	offset := len(cDir) + 1

	writeToTar := func(path string, fi os.FileInfo, err error) error {
		if err := c.tarStoreFile(linkmap, offset, tw, path, fi); err != nil {
			shared.Debugf("Error tarring up %s: %s", path, err)
			return err
		}
		return nil
	}

	fnam := filepath.Join(cDir, "metadata.yaml")
	if shared.PathExists(fnam) {
		fi, err := os.Lstat(fnam)
		if err != nil {
			shared.Debugf("Error statting %s during exportToTar", fnam)
			tw.Close()
			return err
		}
		if err := c.tarStoreFile(linkmap, offset, tw, fnam, fi); err != nil {
			shared.Debugf("Error writing to tarfile: %s", err)
			tw.Close()
			return err
		}
	}
	fnam = filepath.Join(cDir, "rootfs")
	filepath.Walk(fnam, writeToTar)
	fnam = filepath.Join(cDir, "templates")
	if shared.PathExists(fnam) {
		filepath.Walk(fnam, writeToTar)
	}
	return tw.Close()
}
Beispiel #5
0
func doNetworkGet(d *Daemon, name string) (shared.NetworkConfig, error) {
	// Get some information
	osInfo, _ := net.InterfaceByName(name)
	_, dbInfo, _ := dbNetworkGet(d.db, name)

	// Sanity check
	if osInfo == nil && dbInfo == nil {
		return shared.NetworkConfig{}, os.ErrNotExist
	}

	// Prepare the response
	n := shared.NetworkConfig{}
	n.Name = name
	n.UsedBy = []string{}
	n.Config = map[string]string{}

	// Look for containers using the interface
	cts, err := dbContainersList(d.db, cTypeRegular)
	if err != nil {
		return shared.NetworkConfig{}, err
	}

	for _, ct := range cts {
		c, err := containerLoadByName(d, ct)
		if err != nil {
			return shared.NetworkConfig{}, err
		}

		if networkIsInUse(c, n.Name) {
			n.UsedBy = append(n.UsedBy, fmt.Sprintf("/%s/containers/%s", shared.APIVersion, ct))
		}
	}

	// Set the device type as needed
	if osInfo != nil && shared.IsLoopback(osInfo) {
		n.Type = "loopback"
	} else if dbInfo != nil || shared.PathExists(fmt.Sprintf("/sys/class/net/%s/bridge", n.Name)) {
		if dbInfo != nil {
			n.Managed = true
			n.Config = dbInfo.Config
		}

		n.Type = "bridge"
	} else if shared.PathExists(fmt.Sprintf("/sys/class/net/%s/device", n.Name)) {
		n.Type = "physical"
	} else if shared.PathExists(fmt.Sprintf("/sys/class/net/%s/bonding", n.Name)) {
		n.Type = "bond"
	} else {
		_, err := exec.Command("ovs-vsctl", "br-exists", n.Name).CombinedOutput()
		if err == nil {
			n.Type = "bridge"
		} else {
			n.Type = "unknown"
		}
	}

	return n, nil
}
Beispiel #6
0
func (s *storageZfs) ContainerRename(container container, newName string) error {
	oldName := container.Name()

	// Unmount the filesystem
	err := s.zfsUnmount(fmt.Sprintf("containers/%s", oldName))
	if err != nil {
		return err
	}

	// Rename the filesystem
	err = s.zfsRename(fmt.Sprintf("containers/%s", oldName), fmt.Sprintf("containers/%s", newName))
	if err != nil {
		return err
	}

	// Update to the new mountpoint
	err = s.zfsSet(fmt.Sprintf("containers/%s", newName), "mountpoint", shared.VarPath(fmt.Sprintf("containers/%s.zfs", newName)))
	if err != nil {
		return err
	}

	// In case ZFS didn't mount the filesystem, do it ourselves
	err = s.zfsMount(fmt.Sprintf("containers/%s", newName))
	if err != nil {
		return err
	}

	// In case the change of mountpoint didn't remove the old path, do it ourselves
	if shared.PathExists(shared.VarPath(fmt.Sprintf("containers/%s.zfs", oldName))) {
		err = os.Remove(shared.VarPath(fmt.Sprintf("containers/%s.zfs", oldName)))
		if err != nil {
			return err
		}
	}

	// Remove the old symlink
	err = os.Remove(shared.VarPath(fmt.Sprintf("containers/%s", oldName)))
	if err != nil {
		return err
	}

	// Create a new symlink
	err = os.Symlink(shared.VarPath(fmt.Sprintf("containers/%s.zfs", newName)), shared.VarPath(fmt.Sprintf("containers/%s", newName)))
	if err != nil {
		return err
	}

	// Rename the snapshot path
	if shared.PathExists(shared.VarPath(fmt.Sprintf("snapshots/%s", oldName))) {
		err = os.Rename(shared.VarPath(fmt.Sprintf("snapshots/%s", oldName)), shared.VarPath(fmt.Sprintf("snapshots/%s", newName)))
		if err != nil {
			return err
		}
	}

	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
}
Beispiel #8
0
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
}
Beispiel #9
0
func storageLVMGetThinPoolUsers(d *Daemon) ([]string, error) {
	results := []string{}
	vgname, err := d.ConfigValueGet("storage.lvm_vg_name")
	if err != nil {
		return results, fmt.Errorf("Error getting lvm_vg_name config")
	}
	if vgname == "" {
		return results, nil
	}
	poolname, err := d.ConfigValueGet("storage.lvm_thinpool_name")
	if err != nil {
		return results, fmt.Errorf("Error getting lvm_thinpool_name config")
	}
	if poolname == "" {
		return results, nil
	}

	cNames, err := dbContainersList(d.db, cTypeRegular)
	if err != nil {
		return results, err
	}
	for _, cName := range cNames {
		var lvLinkPath string
		if strings.Contains(cName, shared.SnapshotDelimiter) {
			lvLinkPath = shared.VarPath("snapshots", fmt.Sprintf("%s.lv", cName))
		} else {
			lvLinkPath = shared.VarPath("containers", fmt.Sprintf("%s.lv", cName))
		}

		if shared.PathExists(lvLinkPath) {
			results = append(results, cName)
		}
	}

	imageNames, err := dbImagesGet(d.db, false)
	if err != nil {
		return results, err
	}

	for _, imageName := range imageNames {
		imageLinkPath := shared.VarPath("images", fmt.Sprintf("%s.lv", imageName))
		if shared.PathExists(imageLinkPath) {
			results = append(results, imageName)
		}
	}

	return results, nil

}
Beispiel #10
0
/*
 * subvolSnapshot creates a snapshot of "source" to "dest"
 * the result will be readonly if "readonly" is True.
 */
func (s *storageBtrfs) subvolSnapshot(
	source string, dest string, readonly bool) error {

	parentDestPath := filepath.Dir(dest)
	if !shared.PathExists(parentDestPath) {
		if err := os.MkdirAll(parentDestPath, 0700); err != nil {
			return err
		}
	}

	if shared.PathExists(dest) {
		if err := os.Remove(dest); err != nil {
			return err
		}
	}

	var output []byte
	var err error
	if readonly {
		output, err = exec.Command(
			"btrfs",
			"subvolume",
			"snapshot",
			"-r",
			source,
			dest).CombinedOutput()
	} else {
		output, err = exec.Command(
			"btrfs",
			"subvolume",
			"snapshot",
			source,
			dest).CombinedOutput()
	}
	if err != nil {
		s.log.Error(
			"subvolume snapshot failed",
			log.Ctx{"source": source, "dest": dest, "output": string(output)},
		)
		return fmt.Errorf(
			"subvolume snapshot failed, source=%s, dest=%s, output=%s",
			source,
			dest,
			string(output),
		)
	}

	return err
}
Beispiel #11
0
/*
 * Export the container under @dir.  It will look like:
 * dir/
 *     metadata.yaml
 *     rootfs/
 */
func (d *lxdContainer) exportToDir(snap, dir string) error {
	if snap != "" && d.c.Running() {
		return fmt.Errorf("Cannot export a running container as image")
	}

	source := shared.VarPath("lxc", d.name, "metadata.yaml")
	dest := fmt.Sprintf("%s/metadata.yaml", dir)
	if shared.PathExists(source) {
		if err := shared.CopyFile(dest, source); err != nil {
			return err
		}
	}

	if snap != "" {
		source = snapshotRootfsDir(d, snap)
	} else {
		source = shared.VarPath("lxc", d.name, "rootfs")
	}

	// rsync the rootfs
	err := exec.Command("rsync", "-a", "--devices", source, dir).Run()
	if err != nil {
		return err
	}

	// unshift
	if !d.isPrivileged() {
		rootfs := fmt.Sprintf("%s/rootfs", dir)
		err = d.idmapset.UnshiftRootfs(rootfs)
	}
	return err
}
Beispiel #12
0
func (s *storageDir) ContainerSnapshotRename(
	snapshotContainer container, newName string) error {

	oldPath := snapshotContainer.PathGet("")
	newPath := snapshotContainer.PathGet(newName)

	// Create the new parent.
	if strings.Contains(snapshotContainer.NameGet(), "/") {
		if !shared.PathExists(filepath.Dir(newPath)) {
			os.MkdirAll(filepath.Dir(newPath), 0700)
		}
	}

	// Now rename the snapshot.
	if err := os.Rename(oldPath, newPath); err != nil {
		return err
	}

	// Remove the old parent (on container rename) if its empty.
	if strings.Contains(snapshotContainer.NameGet(), "/") {
		if ok, _ := shared.PathIsEmpty(filepath.Dir(oldPath)); ok {
			os.Remove(filepath.Dir(oldPath))
		}
	}

	return nil
}
Beispiel #13
0
func (s *storageLvm) ContainerSnapshotStart(container container) error {
	srcName := containerNameToLVName(container.Name())
	destName := containerNameToLVName(container.Name() + "/rw")

	shared.Log.Debug(
		"Creating snapshot",
		log.Ctx{"srcName": srcName, "destName": destName})

	lvpath, err := s.createSnapshotLV(destName, srcName, false)
	if err != nil {
		return fmt.Errorf("Error creating snapshot LV: %v", err)
	}

	destPath := container.Path("")
	if !shared.PathExists(destPath) {
		if err := os.MkdirAll(destPath, 0755); err != nil {
			return fmt.Errorf("Error creating container directory: %v", err)
		}
	}

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

	return nil
}
Beispiel #14
0
func (s *storageLvm) ContainerCreateFromImage(
	container container, imageFingerprint string) error {

	imageLVFilename := shared.VarPath(
		"images", fmt.Sprintf("%s.lv", imageFingerprint))

	if !shared.PathExists(imageLVFilename) {
		if err := s.ImageCreate(imageLVFilename); err != nil {
			return err
		}
	}

	containerName := containerNameToLVName(container.Name())

	lvpath, err := s.createSnapshotLV(containerName, imageFingerprint, false)
	if err != nil {
		return err
	}

	destPath := container.Path("")
	if err := os.MkdirAll(destPath, 0755); err != nil {
		return fmt.Errorf("Error creating container directory: %v", err)
	}

	dst := shared.VarPath("containers", fmt.Sprintf("%s.lv", container.Name()))
	err = os.Symlink(lvpath, dst)
	if err != nil {
		return err
	}

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

	if !container.IsPrivileged() {
		if err = s.shiftRootfs(container); err != nil {
			output, err2 := exec.Command("umount", destPath).CombinedOutput()
			if err2 != nil {
				return fmt.Errorf("Error in umount: '%s' while cleaning up after error in shiftRootfs: '%s'\n umount output: '%s'", err2, err, output)
			}
			s.ContainerDelete(container)
			return fmt.Errorf("Error in shiftRootfs: %v", err)
		}
	}

	err = container.TemplateApply("create")
	if err != nil {
		s.log.Error("Error in create template during ContainerCreateFromImage, continuing to unmount",
			log.Ctx{"err": err})
	}

	output, umounterr := exec.Command("umount", destPath).CombinedOutput()
	if umounterr != nil {
		return fmt.Errorf("Error unmounting '%s' after shiftRootfs: %v", destPath, umounterr)
	}

	return err
}
Beispiel #15
0
func imageLoadStreamCache(d *Daemon) error {
	imageStreamCacheLock.Lock()
	defer imageStreamCacheLock.Unlock()

	if !shared.PathExists(shared.CachePath("simplestreams.yaml")) {
		return nil
	}

	content, err := ioutil.ReadFile(shared.CachePath("simplestreams.yaml"))
	if err != nil {
		return err
	}

	err = yaml.Unmarshal(content, imageStreamCache)
	if err != nil {
		return err
	}

	for url, entry := range imageStreamCache {
		if entry.ss == nil {
			ss, err := shared.SimpleStreamsClient(url, d.proxy)
			if err != nil {
				return err
			}

			entry.ss = ss
		}
	}

	return nil
}
Beispiel #16
0
Datei: util.go Projekt: vahe/lxd
func loadModule(module string) error {
	if shared.PathExists(fmt.Sprintf("/sys/module/%s", module)) {
		return nil
	}

	return shared.RunCommand("modprobe", module)
}
Beispiel #17
0
func snapshotPost(r *http.Request, c *lxdContainer, oldName string) Response {
	raw := shared.Jmap{}
	if err := json.NewDecoder(r.Body).Decode(&raw); err != nil {
		return BadRequest(err)
	}

	newName, err := raw.GetString("name")
	if err != nil {
		return BadRequest(err)
	}

	oldDir := snapshotDir(c, oldName)
	newDir := snapshotDir(c, newName)

	if shared.PathExists(newDir) {
		return Conflict
	}

	/*
	 * TODO: do we need to do something more intelligent here? We probably
	 * shouldn't do anything for stateful snapshots, since changing the fs
	 * out from under criu will cause it to fail, but it may be useful to
	 * do something for stateless ones.
	 */
	rename := func() error { return os.Rename(oldDir, newDir) }
	return AsyncResponse(shared.OperationWrap(rename), nil)
}
Beispiel #18
0
func snapshotHandler(d *Daemon, r *http.Request) Response {
	containerName := mux.Vars(r)["name"]
	c, err := newLxdContainer(containerName, d)
	if err != nil {
		return SmartError(err)
	}

	snapshotName := mux.Vars(r)["snapshotName"]
	dir := snapshotDir(c, snapshotName)

	if !shared.PathExists(dir) {
		return NotFound
	}

	switch r.Method {
	case "GET":
		return snapshotGet(c, snapshotName)
	case "POST":
		return snapshotPost(r, c, snapshotName)
	case "DELETE":
		return snapshotDelete(d, c, snapshotName)
	default:
		return NotFound
	}
}
Beispiel #19
0
func (s *storageBtrfs) ContainerCreate(
	container *lxdContainer, imageFingerprint string) error {

	imageSubvol := fmt.Sprintf(
		"%s.btrfs",
		shared.VarPath("images", imageFingerprint))

	if !shared.PathExists(imageSubvol) {
		if err := s.ImageCreate(imageFingerprint); err != nil {
			return err
		}
	}

	err := s.subvolSnapshot(imageSubvol, container.PathGet(), false)
	if err != nil {
		return err
	}

	if !container.isPrivileged() {
		err = shiftRootfs(container, s.d)
		if err != nil {
			return err
		}
	} else {
		if err := os.Chmod(container.PathGet(), 0700); err != nil {
			return err
		}
	}

	return templateApply(container, "create")
}
Beispiel #20
0
func (s *storageLvm) ContainerSnapshotStart(container container) error {
	srcName := containerNameToLVName(container.Name())
	destName := containerNameToLVName(container.Name() + "/rw")

	shared.Log.Debug(
		"Creating snapshot",
		log.Ctx{"srcName": srcName, "destName": destName})

	lvpath, err := s.createSnapshotLV(destName, srcName, false)
	if err != nil {
		return fmt.Errorf("Error creating snapshot LV: %v", err)
	}

	destPath := container.Path()
	if !shared.PathExists(destPath) {
		if err := os.MkdirAll(destPath, 0755); err != nil {
			return fmt.Errorf("Error creating container directory: %v", err)
		}
	}

	err = s.tryMount(lvpath, container.Path(), "ext4", 0, "discard")
	if err != nil {
		return fmt.Errorf(
			"Error mounting snapshot LV path='%s': %v",
			container.Path(),
			err)
	}

	return nil
}
Beispiel #21
0
func (s *storageBtrfs) ContainerCreateFromImage(
	container container, imageFingerprint string) error {

	imageSubvol := fmt.Sprintf(
		"%s.btrfs",
		shared.VarPath("images", imageFingerprint))

	// Create the btrfs subvol of the image first if it doesn exists.
	if !shared.PathExists(imageSubvol) {
		if err := s.ImageCreate(imageFingerprint); err != nil {
			return err
		}
	}

	// Now make a snapshot of the image subvol
	err := s.subvolsSnapshot(imageSubvol, container.Path(), false)
	if err != nil {
		return err
	}

	if !container.IsPrivileged() {
		if err = s.shiftRootfs(container); err != nil {
			s.ContainerDelete(container)
			return err
		}
	} else {
		if err := os.Chmod(container.Path(), 0700); err != nil {
			return err
		}
	}

	return container.TemplateApply("create")
}
Beispiel #22
0
func (s *storageZfs) ImageDelete(fingerprint string) error {
	fs := fmt.Sprintf("images/%s", fingerprint)

	removable, err := s.zfsSnapshotRemovable(fs, "readonly")

	if err != nil {
		return err
	}

	if removable {
		err := s.zfsDestroy(fs)
		if err != nil {
			return err
		}
	} else {
		err := s.zfsSet(fs, "mountpoint", "none")
		if err != nil {
			return err
		}

		err = s.zfsRename(fs, fmt.Sprintf("deleted/%s", fs))
		if err != nil {
			return err
		}
	}

	if shared.PathExists(shared.VarPath(fs + ".zfs")) {
		os.Remove(shared.VarPath(fs + ".zfs"))
	}
	return nil
}
Beispiel #23
0
func (s *storageBtrfs) subvolCreate(subvol string) error {
	parentDestPath := filepath.Dir(subvol)
	if !shared.PathExists(parentDestPath) {
		if err := os.MkdirAll(parentDestPath, 0700); err != nil {
			return err
		}
	}

	output, err := exec.Command(
		"btrfs",
		"subvolume",
		"create",
		subvol).CombinedOutput()
	if err != nil {
		s.log.Debug(
			"subvolume create failed",
			log.Ctx{"subvol": subvol, "output": string(output)},
		)
		return fmt.Errorf(
			"btrfs subvolume create failed, subvol=%s, output%s",
			subvol,
			string(output),
		)
	}

	return nil
}
Beispiel #24
0
// ContainerSnapshotRename renames a snapshot of a container.
func (s *storageBtrfs) ContainerSnapshotRename(
	snapshotContainer container, newName string) error {

	oldPath := snapshotContainer.Path()
	newPath := containerPath(newName, true)

	// Create the new parent.
	if !shared.PathExists(filepath.Dir(newPath)) {
		os.MkdirAll(filepath.Dir(newPath), 0700)
	}

	// Now rename the snapshot.
	if !s.isSubvolume(oldPath) {
		if err := os.Rename(oldPath, newPath); err != nil {
			return err
		}
	} else {
		if err := s.subvolsSnapshot(oldPath, newPath, true); err != nil {
			return err
		}
		if err := s.subvolsDelete(oldPath); err != nil {
			return err
		}
	}

	// Remove the old parent (on container rename) if its empty.
	if ok, _ := shared.PathIsEmpty(filepath.Dir(oldPath)); ok {
		os.Remove(filepath.Dir(oldPath))
	}

	return nil
}
Beispiel #25
0
func (s *storageLvm) ContainerSnapshotRename(
	snapshotContainer container, newContainerName string) error {
	oldName := containerNameToLVName(snapshotContainer.NameGet())
	newName := containerNameToLVName(newContainerName)
	output, err := s.renameLV(oldName, newName)
	if err != nil {
		s.log.Error("Failed to rename a snapshot LV",
			log.Ctx{"oldName": oldName, "newName": newName, "err": err, "output": string(output)})
		return fmt.Errorf("Failed to rename a container LV, oldName='%s', newName='%s', err='%s'", oldName, newName, err)
	}

	oldPath := snapshotContainer.PathGet("")
	oldSymPath := fmt.Sprintf("%s.lv", oldPath)
	newPath := snapshotContainer.PathGet(newName)
	newSymPath := fmt.Sprintf("%s.lv", newPath)

	if err := os.Rename(oldSymPath, newSymPath); err != nil {
		s.log.Error("Failed to rename symlink", log.Ctx{"oldSymPath": oldSymPath, "newSymPath": newSymPath, "err": err})
		return fmt.Errorf("Failed to rename symlink err='%s'", err)
	}

	if strings.Contains(snapshotContainer.NameGet(), "/") {
		if !shared.PathExists(filepath.Dir(newPath)) {
			os.MkdirAll(filepath.Dir(newPath), 0700)
		}
	}

	if strings.Contains(snapshotContainer.NameGet(), "/") {
		if ok, _ := shared.PathIsEmpty(filepath.Dir(oldPath)); ok {
			os.Remove(filepath.Dir(oldPath))
		}
	}

	return nil
}
Beispiel #26
0
func snapshotGet(sc container, name string) Response {
	body := shared.Jmap{
		"name":          name,
		"creation_date": sc.CreationDate().Unix(),
		"stateful":      shared.PathExists(sc.StatePath())}
	return SyncResponse(true, body)
}
Beispiel #27
0
/*
 * Export the container to a unshifted tarfile containing:
 * dir/
 *     metadata.yaml
 *     rootfs/
 */
func (d *lxdContainer) exportToTar(snap string, w io.Writer) error {
	if snap != "" && d.c.Running() {
		return fmt.Errorf("Cannot export a running container as image")
	}

	tw := tar.NewWriter(w)

	// keep track of the first path we saw for each path with nlink>1
	linkmap := map[uint64]string{}

	cDir := shared.VarPath("lxc", d.name)

	// Path inside the tar image is the pathname starting after cDir
	offset := len(cDir) + 1

	fnam := filepath.Join(cDir, "metadata.yaml")
	writeToTar := func(path string, fi os.FileInfo, err error) error {
		if err := d.tarStoreFile(linkmap, offset, tw, path, fi); err != nil {
			shared.Debugf("error tarring up %s: %s\n", path, err)
			return err
		}
		return nil
	}

	fnam = filepath.Join(cDir, "metadata.yaml")
	if shared.PathExists(fnam) {
		fi, err := os.Lstat(fnam)
		if err != nil {
			shared.Debugf("Error statting %s during exportToTar\n", fnam)
			tw.Close()
			return err
		}
		if err := d.tarStoreFile(linkmap, offset, tw, fnam, fi); err != nil {
			shared.Debugf("exportToTar: error writing to tarfile: %s\n", err)
			tw.Close()
			return err
		}
	}
	fnam = filepath.Join(cDir, "rootfs")
	filepath.Walk(fnam, writeToTar)
	fnam = filepath.Join(cDir, "templates")
	if shared.PathExists(fnam) {
		filepath.Walk(fnam, writeToTar)
	}
	return tw.Close()
}
Beispiel #28
0
func imageDelete(d *Daemon, r *http.Request) Response {
	fingerprint := mux.Vars(r)["fingerprint"]

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

	fname := shared.VarPath("images", imgInfo.Fingerprint)
	err = os.Remove(fname)
	if err != nil {
		shared.Debugf("Error deleting image file %s: %s\n", fname, err)
	}

	fmetaname := shared.VarPath("images", imgInfo.Fingerprint+".rootfs")
	if shared.PathExists(fmetaname) {
		err = os.Remove(fmetaname)
		if err != nil {
			shared.Debugf("Error deleting image file %s: %s\n", fmetaname, 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 {
		err = shared.LVMRemoveLV(vgname, imgInfo.Fingerprint)
		if err != nil {
			return InternalError(fmt.Errorf("Failed to remove deleted image LV: %v", err))
		}

		lvsymlink := fmt.Sprintf("%s.lv", fname)
		err = os.Remove(lvsymlink)
		if err != nil {
			return InternalError(fmt.Errorf("Failed to remove symlink to deleted image LV: '%s': %v", lvsymlink, err))
		}
	} else if d.BackingFs == "btrfs" {
		subvol := fmt.Sprintf("%s.btrfs", fname)
		btrfsDeleteSubvol(subvol)
	}

	tx, err := dbBegin(d.db)
	if err != nil {
		return InternalError(err)
	}

	_, _ = tx.Exec("DELETE FROM images_aliases WHERE image_id=?", imgInfo.Id)
	_, _ = tx.Exec("DELETE FROM images_properties WHERE image_id?", imgInfo.Id)
	_, _ = tx.Exec("DELETE FROM images WHERE id=?", imgInfo.Id)

	if err := txCommit(tx); err != nil {
		return InternalError(err)
	}

	return EmptySyncResponse
}
Beispiel #29
0
func networkCreate(routers Routers) error {
	vethInterfaces, bridgeInterfaces, err := networkInterfaces(routers)
	if err != nil {
		return err
	}

	for _, veth := range vethInterfaces {
		if !shared.PathExists(fmt.Sprintf("/sys/class/net/%s-1", veth)) && !shared.PathExists(fmt.Sprintf("/sys/class/net/%s-2", veth)) {
			out, err := exec.Command("ip", "link", "add", "dev", fmt.Sprintf("%s-1", veth), "type", "veth", "peer", "name", fmt.Sprintf("%s-2", veth)).CombinedOutput()
			if err != nil {
				return fmt.Errorf("Failed to create veth device: %s", out)
			}
		}

		if shared.PathExists(fmt.Sprintf("/sys/class/net/%s-1", veth)) {
			out, err := exec.Command("ip", "link", "set", "dev", fmt.Sprintf("%s-1", veth), "up").CombinedOutput()
			if err != nil {
				return fmt.Errorf("Failed to bring veth device up: %s", out)
			}
		}

		if shared.PathExists(fmt.Sprintf("/sys/class/net/%s-2", veth)) {
			out, err := exec.Command("ip", "link", "set", "dev", fmt.Sprintf("%s-2", veth), "up").CombinedOutput()
			if err != nil {
				return fmt.Errorf("Failed to bring veth device up: %s", out)
			}
		}
	}

	for _, bridge := range bridgeInterfaces {
		if !shared.PathExists(fmt.Sprintf("/sys/class/net/%s", bridge)) {
			out, err := exec.Command("ip", "link", "add", "dev", bridge, "type", "bridge").CombinedOutput()
			if err != nil {
				return fmt.Errorf("Failed to create bridge device: %s", out)
			}
		}

		out, err := exec.Command("ip", "link", "set", "dev", bridge, "up").CombinedOutput()
		if err != nil {
			return fmt.Errorf("Failed to bring bridge device up: %s", out)
		}
	}

	return nil
}
Beispiel #30
0
func (s *storageZfs) Init(config map[string]interface{}) (storage, error) {
	s.sType = storageTypeZfs
	s.sTypeName = storageTypeToString(s.sType)

	err := s.initShared()
	if err != nil {
		return s, err
	}

	if config["zfsPool"] == nil {
		zfsPool, err := s.d.ConfigValueGet("storage.zfs_pool_name")
		if err != nil {
			return s, fmt.Errorf("Error checking server config: %v", err)
		}

		if zfsPool == "" {
			return s, fmt.Errorf("ZFS isn't enabled")
		}

		s.zfsPool = zfsPool
	} else {
		s.zfsPool = config["zfsPool"].(string)
	}

	out, err := exec.LookPath("zfs")
	if err != nil || len(out) == 0 {
		return s, fmt.Errorf("The 'zfs' tool isn't available")
	}

	err = s.zfsCheckPool(s.zfsPool)
	if err != nil {
		if shared.PathExists(shared.VarPath("zfs.img")) {
			_, _ = exec.Command("modprobe", "zfs").CombinedOutput()

			output, err := exec.Command("zpool", "import",
				"-d", shared.VarPath(), s.zfsPool).CombinedOutput()
			if err != nil {
				return s, fmt.Errorf("Unable to import the ZFS pool: %s", output)
			}
		} else {
			return s, err
		}
	}

	output, err := exec.Command("zfs", "get", "version", "-H", "-o", "value", s.zfsPool).CombinedOutput()
	if err != nil {
		return s, fmt.Errorf("The 'zfs' tool isn't working properly")
	}

	count, err := fmt.Sscanf(string(output), "%s\n", &s.sTypeVersion)
	if err != nil || count != 1 {
		return s, fmt.Errorf("The 'zfs' tool isn't working properly")
	}

	return s, nil
}