コード例 #1
0
ファイル: containers_post.go プロジェクト: joker042/lxd
func createFromNone(d *Daemon, req *containerPostReq) Response {
	args := DbCreateContainerArgs{
		d:        d,
		name:     req.Name,
		ctype:    cTypeRegular,
		config:   req.Config,
		profiles: req.Profiles,
		ephem:    req.Ephemeral,
	}

	_, err := dbCreateContainer(args)
	if err != nil {
		return SmartError(err)
	}

	run := shared.OperationWrap(func() error {
		c, err := newLxdContainer(req.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}
}
コード例 #2
0
ファイル: container_put.go プロジェクト: joker042/lxd
/*
 * Update configuration, or, if 'restore:snapshot-name' is present, restore
 * the named snapshot
 */
func containerPut(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	c, err := newLxdContainer(name, d)
	if err != nil {
		return NotFound
	}

	configRaw := containerConfigReq{}
	if err := json.NewDecoder(r.Body).Decode(&configRaw); err != nil {
		return BadRequest(err)
	}

	var do = func() error { return nil }

	if configRaw.Restore == "" {
		// Update container configuration
		do = func() error {
			return containerReplaceConfig(d, c, name, configRaw)
		}
	} else {
		// Snapshot Restore
		do = func() error {
			return containerSnapRestore(d, name, configRaw.Restore)
		}
	}

	return AsyncResponse(shared.OperationWrap(do), nil)
}
コード例 #3
0
ファイル: container_post.go プロジェクト: rockstar/lxd
func containerPost(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	c, err := containerLXDLoad(d, name)
	if err != nil {
		return SmartError(err)
	}

	buf, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return InternalError(err)
	}

	body := containerPostBody{}
	if err := json.Unmarshal(buf, &body); err != nil {
		return BadRequest(err)
	}

	if body.Migration {
		ws, err := NewMigrationSource(c)
		if err != nil {
			return InternalError(err)
		}

		return AsyncResponseWithWs(ws, nil)
	}

	run := func(id string) error {
		return c.Rename(body.Name)
	}

	return AsyncResponse(shared.OperationWrap(run), nil)
}
コード例 #4
0
ファイル: container_snapshot.go プロジェクト: Ramzec/lxd
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)

	_, err = os.Stat(newDir)
	if !os.IsNotExist(err) {
		return InternalError(err)
	} else if err == nil {
		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)
}
コード例 #5
0
ファイル: container_post.go プロジェクト: Ramzec/lxd
func containerPost(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	c, err := newLxdContainer(name, d)
	if err != nil {
		return SmartError(err)
	}

	buf, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return InternalError(err)
	}

	body := containerPostBody{}
	if err := json.Unmarshal(buf, &body); err != nil {
		return BadRequest(err)
	}

	if body.Migration {
		ws, err := migration.NewMigrationSource(c.c)
		if err != nil {
			return InternalError(err)
		}

		return AsyncResponseWithWs(ws, nil)
	} else {
		if c.c.Running() {
			return BadRequest(fmt.Errorf("renaming of running container not allowed"))
		}

		args := DbCreateContainerArgs{
			d:            d,
			name:         body.Name,
			ctype:        cTypeRegular,
			config:       c.config,
			profiles:     c.profiles,
			ephem:        c.ephemeral,
			baseImage:    c.config["volatile.baseImage"],
			architecture: c.architecture,
		}

		_, err := dbCreateContainer(args)
		if err != nil {
			return SmartError(err)
		}

		run := func() error {
			oldPath := fmt.Sprintf("%s/", shared.VarPath("lxc", c.name))
			newPath := fmt.Sprintf("%s/", shared.VarPath("lxc", body.Name))

			if err := os.Rename(oldPath, newPath); err != nil {
				return err
			}

			removeContainer(d, c.name)
			return nil
		}

		return AsyncResponse(shared.OperationWrap(run), nil)
	}
}
コード例 #6
0
ファイル: container_snapshot.go プロジェクト: rockstar/lxd
func containerSnapshotsPost(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]

	/*
	 * snapshot is a three step operation:
	 * 1. choose a new name
	 * 2. copy the database info over
	 * 3. copy over the rootfs
	 */
	c, err := containerLXDLoad(d, name)
	if err != nil {
		return SmartError(err)
	}

	raw := shared.Jmap{}
	if err := json.NewDecoder(r.Body).Decode(&raw); err != nil {
		return BadRequest(err)
	}

	snapshotName, err := raw.GetString("name")
	if err != nil || snapshotName == "" {
		// come up with a name
		i := nextSnapshot(d, name)
		snapshotName = fmt.Sprintf("snap%d", i)
	}

	stateful, err := raw.GetBool("stateful")
	if err != nil {
		return BadRequest(err)
	}

	fullName := name +
		shared.SnapshotDelimiter +
		snapshotName

	snapshot := func(id string) error {
		config := c.Config()
		args := containerLXDArgs{
			Ctype:        cTypeSnapshot,
			Config:       config,
			Profiles:     c.Profiles(),
			Ephemeral:    c.IsEphemeral(),
			BaseImage:    config["volatile.base_image"],
			Architecture: c.Architecture(),
			Devices:      c.Devices(),
		}

		_, err := containerLXDCreateAsSnapshot(d, fullName, args, c, stateful)
		if err != nil {
			return err
		}

		return nil
	}

	return AsyncResponse(shared.OperationWrap(snapshot), nil)
}
コード例 #7
0
ファイル: containers_post.go プロジェクト: destitutus/lxd
func createFromImage(d *Daemon, req *containerPostReq) Response {
	var hash string
	var err error
	var run func() shared.OperationResult

	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 = dbImageAliasGet(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 := d.ImageDownload(req.Source.Server, hash, req.Source.Secret, true)
		if err != nil {
			return InternalError(err)
		}
	}

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

	args := containerLXDArgs{
		Ctype:        cTypeRegular,
		Config:       req.Config,
		Profiles:     req.Profiles,
		Ephemeral:    req.Ephemeral,
		BaseImage:    hash,
		Architecture: imgInfo.Architecture,
	}

	run = shared.OperationWrap(func() error {
		_, err := containerLXDCreateFromImage(d, req.Name, args, hash)
		return err
	})

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

	return &asyncResponse{run: run, resources: resources}
}
コード例 #8
0
ファイル: container_put.go プロジェクト: RuneTM/lxd
/*
 * Update configuration, or, if 'restore:snapshot-name' is present, restore
 * the named snapshot
 */
func containerPut(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	c, err := newLxdContainer(name, d)
	if err != nil {
		return NotFound
	}

	configRaw := containerConfigReq{}
	if err := json.NewDecoder(r.Body).Decode(&configRaw); err != nil {
		return BadRequest(err)
	}

	var do = func() error { return nil }

	if configRaw.Restore == "" {
		// Update container configuration
		do = func() error {
			preDevList, err := dbDevicesGet(d.db, name, false)
			if err != nil {
				return err
			}
			if err := validateConfig(c, configRaw.Devices); err != nil {
				return err
			}
			tx, err := containerReplaceConfig(d, c, name, configRaw)
			if err != nil {
				return err
			}

			if !c.c.Running() {
				return txCommit(tx)
			}

			// apply new devices
			postDevList := configRaw.Devices
			if err != nil {
				tx.Rollback()
				return err
			}

			if err := devicesApplyDeltaLive(tx, c, preDevList, postDevList); err != nil {
				tx.Rollback()
				return err
			}
			return txCommit(tx)
		}
	} else {
		// Snapshot Restore
		do = func() error {
			return containerSnapRestore(d, name, configRaw.Restore)
		}
	}

	return AsyncResponse(shared.OperationWrap(do), nil)
}
コード例 #9
0
ファイル: container_state.go プロジェクト: rrva/lxd
func containerStatePut(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]

	raw := containerStatePutReq{}

	// We default to -1 (i.e. no timeout) here instead of 0 (instant
	// timeout).
	raw.Timeout = -1

	if err := json.NewDecoder(r.Body).Decode(&raw); err != nil {
		return BadRequest(err)
	}

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

	var do func() error
	switch shared.ContainerAction(raw.Action) {
	case shared.Start:
		do = func() error {
			if err = c.Start(); err != nil {
				return err
			}
			return nil
		}
	case shared.Stop:
		if raw.Timeout == 0 || raw.Force {
			do = func() error {
				if err = c.Stop(); err != nil {
					return err
				}
				return nil
			}
		} else {
			do = func() error {
				if err = c.Shutdown(time.Duration(raw.Timeout) * time.Second); err != nil {
					return err
				}
				return nil
			}
		}
	case shared.Restart:
		do = c.Reboot
	case shared.Freeze:
		do = c.Freeze
	case shared.Unfreeze:
		do = c.Unfreeze
	default:
		return BadRequest(fmt.Errorf("unknown action %s", raw.Action))
	}

	return AsyncResponse(shared.OperationWrap(do), nil)
}
コード例 #10
0
ファイル: container_delete.go プロジェクト: rrva/lxd
func containerDelete(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	c, err := containerLXDLoad(d, name)
	if err != nil {
		return SmartError(err)
	}

	rmct := func() error {
		return c.Delete()
	}

	return AsyncResponse(shared.OperationWrap(rmct), nil)
}
コード例 #11
0
ファイル: container_delete.go プロジェクト: kostyll/lxd
func containerDelete(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	_, err := dbGetContainerId(d.db, name)
	if err != nil {
		return SmartError(err)
	}

	rmct := func() error {
		return removeContainer(d, name)
	}

	return AsyncResponse(shared.OperationWrap(rmct), nil)
}
コード例 #12
0
ファイル: container_snapshot.go プロジェクト: rockstar/lxd
func snapshotPost(r *http.Request, sc container, containerName 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)
	}

	rename := func(id string) error {
		return sc.Rename(containerName + shared.SnapshotDelimiter + newName)
	}
	return AsyncResponse(shared.OperationWrap(rename), nil)
}
コード例 #13
0
ファイル: container_delete.go プロジェクト: rockstar/lxd
func containerDelete(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	c, err := containerLXDLoad(d, name)
	if err != nil {
		return SmartError(err)
	}

	if c.IsRunning() {
		return BadRequest(fmt.Errorf("container is running"))
	}

	rmct := func(id string) error {
		return c.Delete()
	}

	return AsyncResponse(shared.OperationWrap(rmct), nil)
}
コード例 #14
0
ファイル: containers_post.go プロジェクト: destitutus/lxd
func createFromNone(d *Daemon, req *containerPostReq) Response {
	args := containerLXDArgs{
		Ctype:     cTypeRegular,
		Config:    req.Config,
		Profiles:  req.Profiles,
		Ephemeral: req.Ephemeral,
	}

	run := shared.OperationWrap(func() error {
		_, err := containerLXDCreateAsEmpty(d, req.Name, args)
		return err
	})

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

	return &asyncResponse{run: run, resources: resources}
}
コード例 #15
0
ファイル: container_delete.go プロジェクト: RuneTM/lxd
func containerDelete(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	_, err := dbContainerIDGet(d.db, name)
	if err != nil {
		return SmartError(err)
	}

	// TODO: i have added this not sure its a good idea (pcdummy)
	c, err := newLxdContainer(name, d)
	if err != nil {
		return SmartError(err)
	}

	rmct := func() error {
		return removeContainer(d, c)
	}

	return AsyncResponse(shared.OperationWrap(rmct), nil)
}
コード例 #16
0
ファイル: container_put.go プロジェクト: tidzo/lxd
/*
 * Update configuration, or, if 'restore:snapshot-name' is present, restore
 * the named snapshot
 */
func containerPut(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	c, err := containerLXDLoad(d, name)
	if err != nil {
		return NotFound
	}

	configRaw := containerConfigReq{}
	if err := json.NewDecoder(r.Body).Decode(&configRaw); err != nil {
		return BadRequest(err)
	}

	var do = func() error { return nil }

	if configRaw.Restore == "" {
		// Update container configuration
		do = func() error {
			args := containerLXDArgs{
				Config:   configRaw.Config,
				Devices:  configRaw.Devices,
				Profiles: configRaw.Profiles}
			err = c.ConfigReplace(args)
			if err != nil {
				return err
			}

			return nil
		}
	} else {
		// Snapshot Restore
		do = func() error {
			return containerSnapRestore(d, name, configRaw.Restore)
		}
	}

	return AsyncResponse(shared.OperationWrap(do), nil)
}
コード例 #17
0
ファイル: containers_post.go プロジェクト: joker042/lxd
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}
}
コード例 #18
0
ファイル: container_snapshot.go プロジェクト: rockstar/lxd
func snapshotDelete(sc container, name string) Response {
	remove := func(id string) error {
		return sc.Delete()
	}
	return AsyncResponse(shared.OperationWrap(remove), nil)
}
コード例 #19
0
ファイル: images.go プロジェクト: rockstar/lxd
func imagesPost(d *Daemon, r *http.Request) Response {
	var err error

	// create a directory under which we keep everything while building
	builddir, err := ioutil.TempDir(shared.VarPath("images"), "lxd_build_")
	if err != nil {
		return InternalError(err)
	}

	cleanup := func(path string, fd *os.File) {
		if fd != nil {
			fd.Close()
		}

		if err := os.RemoveAll(path); err != nil {
			shared.Debugf("Error deleting temporary directory \"%s\": %s", path, err)
		}
	}

	// Store the post data to disk
	post, err := ioutil.TempFile(builddir, "lxd_post_")
	if err != nil {
		cleanup(builddir, nil)
		return InternalError(err)
	}

	_, err = io.Copy(post, r.Body)
	if err != nil {
		cleanup(builddir, post)
		return InternalError(err)
	}

	// Is this a container request?
	post.Seek(0, 0)
	decoder := json.NewDecoder(post)
	req := imagePostReq{}
	err = decoder.Decode(&req)
	imageUpload := err != nil

	if !imageUpload && !shared.StringInSlice(req.Source["type"], []string{"container", "snapshot", "image"}) {
		cleanup(builddir, post)
		return InternalError(fmt.Errorf("Invalid images JSON"))
	}

	// Begin background operation
	run := shared.OperationWrap(func(id string) error {
		var info shared.ImageInfo

		// Setup the cleanup function
		defer cleanup(builddir, post)

		/* Processing image copy from remote */
		if !imageUpload && req.Source["type"] == "image" {
			metadata, err := imgPostRemoteInfo(d, req)
			if err != nil {
				return err
			}

			updateOperation(id, metadata)
			return nil
		}

		if imageUpload {
			/* Processing image upload */
			info, err = getImgPostInfo(d, r, builddir, post)
			if err != nil {
				return err
			}
		} else {
			/* Processing image creation from container */
			info, err = imgPostContInfo(d, r, req, builddir)
			if err != nil {
				return err
			}
		}

		metadata, err := imageBuildFromInfo(d, info)
		if err != nil {
			return err
		}

		updateOperation(id, metadata)
		return nil
	})

	return &asyncResponse{run: run}
}
コード例 #20
0
ファイル: containers_post.go プロジェクト: RuneTM/lxd
func createFromImage(d *Daemon, req *containerPostReq) Response {
	var hash string
	var err error
	var run func() shared.OperationResult

	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 = dbImageAliasGet(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("containers", req.Name)
	if shared.PathExists(dpath) {
		return InternalError(fmt.Errorf("Container exists"))
	}

	name := req.Name

	args := containerLXDArgs{
		Ctype:        cTypeRegular,
		Config:       req.Config,
		Profiles:     req.Profiles,
		Ephemeral:    req.Ephemeral,
		BaseImage:    hash,
		Architecture: imgInfo.Architecture,
	}

	_, err = dbContainerCreate(d.db, name, args)
	if err != nil {
		return SmartError(err)
	}

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

	run = shared.OperationWrap(func() error {
		err := d.Storage.ContainerCreate(c, hash)
		if err != nil {
			removeContainer(d, c)
		}
		return err
	})

	resources := make(map[string][]string)
	resources["containers"] = []string{c.name}

	return &asyncResponse{run: run, resources: resources}
}
コード例 #21
0
ファイル: container_snapshot.go プロジェクト: Ramzec/lxd
func containerSnapshotsPost(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]

	/*
	 * snapshot is a three step operation:
	 * 1. choose a new name
	 * 2. copy the database info over
	 * 3. copy over the rootfs
	 */
	c, err := newLxdContainer(name, d)
	if err != nil {
		return SmartError(err)
	}

	raw := shared.Jmap{}
	if err := json.NewDecoder(r.Body).Decode(&raw); err != nil {
		return BadRequest(err)
	}

	snapshotName, err := raw.GetString("name")
	if err != nil || snapshotName == "" {
		// come up with a name
		i := nextSnapshot(d, name)
		snapshotName = fmt.Sprintf("snap%d", i)
	}

	stateful, err := raw.GetBool("stateful")
	if err != nil {
		return BadRequest(err)
	}

	fullName := fmt.Sprintf("%s/%s", name, snapshotName)
	snapDir := snapshotDir(c, snapshotName)
	if shared.PathExists(snapDir) {
		return Conflict
	}

	err = os.MkdirAll(snapDir, 0700)
	if err != nil {
		return InternalError(err)
	}

	snapshot := func() error {

		StateDir := snapshotStateDir(c, snapshotName)
		err = os.MkdirAll(StateDir, 0700)
		if err != nil {
			return err
		}

		if stateful {
			// TODO - shouldn't we freeze for the duration of rootfs snapshot below?
			if !c.c.Running() {
				return fmt.Errorf("Container not running\n")
			}
			opts := lxc.CheckpointOptions{Directory: StateDir, Stop: true, Verbose: true}
			if err := c.c.Checkpoint(opts); err != nil {
				return err
			}
		}

		/* Create the db info */
		args := DbCreateContainerArgs{
			d:            d,
			name:         fullName,
			ctype:        cTypeSnapshot,
			config:       c.config,
			profiles:     c.profiles,
			ephem:        c.ephemeral,
			baseImage:    c.config["volatile.baseImage"],
			architecture: c.architecture,
		}

		_, err := dbCreateContainer(args)
		if err != nil {
			return err
		}

		/* Create the directory and rootfs, set perms */
		/* Copy the rootfs */
		oldPath := fmt.Sprintf("%s/", shared.VarPath("lxc", name, "rootfs"))
		newPath := snapshotRootfsDir(c, snapshotName)
		err = exec.Command("rsync", "-a", "--devices", oldPath, newPath).Run()
		return err
	}

	return AsyncResponse(shared.OperationWrap(snapshot), nil)
}
コード例 #22
0
ファイル: container_snapshot.go プロジェクト: Ramzec/lxd
func snapshotDelete(d *Daemon, c *lxdContainer, name string) Response {
	dbRemoveSnapshot(d, c.name, name)
	dir := snapshotDir(c, name)
	remove := func() error { return os.RemoveAll(dir) }
	return AsyncResponse(shared.OperationWrap(remove), nil)
}