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} }
/* * 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) }
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) }
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) }
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) } }
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) }
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} }
/* * 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) }
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) }
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) }
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) }
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) }
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) }
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} }
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) }
/* * 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) }
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} }
func snapshotDelete(sc container, name string) Response { remove := func(id string) error { return sc.Delete() } return AsyncResponse(shared.OperationWrap(remove), nil) }
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} }
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} }
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) }
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) }