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 snapshotPost(d *Daemon, r *http.Request, sc container, containerName string) Response { raw := shared.Jmap{} if err := json.NewDecoder(r.Body).Decode(&raw); err != nil { return BadRequest(err) } migration, err := raw.GetBool("migration") if err == nil && migration { ws, err := NewMigrationSource(sc) if err != nil { return SmartError(err) } resources := map[string][]string{} resources["containers"] = []string{containerName} op, err := operationCreate(operationClassWebsocket, resources, ws.Metadata(), ws.Do, nil, ws.Connect) if err != nil { return InternalError(err) } return OperationResponse(op) } newName, err := raw.GetString("name") if err != nil { return BadRequest(err) } fullName := containerName + shared.SnapshotDelimiter + newName // Check that the name isn't already in use id, _ := dbContainerId(d.db, fullName) if id > 0 { return Conflict } rename := func(op *operation) error { return sc.Rename(fullName) } resources := map[string][]string{} resources["containers"] = []string{containerName} op, err := operationCreate(operationClassTask, resources, nil, rename, nil, nil) if err != nil { return InternalError(err) } return OperationResponse(op) }
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 := containerLoadByName(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(op *operation) error { config := c.ExpandedConfig() args := containerArgs{ Name: fullName, Ctype: cTypeSnapshot, Config: config, Profiles: c.Profiles(), Ephemeral: c.IsEphemeral(), BaseImage: config["volatile.base_image"], Architecture: c.Architecture(), Devices: c.ExpandedDevices(), } _, err := containerCreateAsSnapshot(d, args, c, stateful) if err != nil { return err } return nil } resources := map[string][]string{} resources["containers"] = []string{name} op, err := operationCreate(operationClassTask, resources, nil, snapshot, nil, nil) if err != nil { return InternalError(err) } return OperationResponse(op) }
func containerPatch(d *Daemon, r *http.Request) Response { // Get the container name := mux.Vars(r)["name"] c, err := containerLoadByName(d, name) if err != nil { return NotFound } // Validate the ETag etag := []interface{}{c.Architecture(), c.LocalConfig(), c.LocalDevices(), c.IsEphemeral(), c.Profiles()} err = etagCheck(r, etag) if err != nil { return PreconditionFailed(err) } body, err := ioutil.ReadAll(r.Body) if err != nil { return InternalError(err) } rdr1 := ioutil.NopCloser(bytes.NewBuffer(body)) rdr2 := ioutil.NopCloser(bytes.NewBuffer(body)) reqRaw := shared.Jmap{} if err := json.NewDecoder(rdr1).Decode(&reqRaw); err != nil { return BadRequest(err) } req := containerPutReq{} if err := json.NewDecoder(rdr2).Decode(&req); err != nil { return BadRequest(err) } if req.Restore != "" { return BadRequest(fmt.Errorf("Can't call PATCH in restore mode.")) } // Check if architecture was passed var architecture int _, err = reqRaw.GetString("architecture") if err != nil { architecture = c.Architecture() } else { architecture, err = shared.ArchitectureId(req.Architecture) if err != nil { architecture = 0 } } // Check if ephemeral was passed _, err = reqRaw.GetBool("ephemeral") if err != nil { req.Ephemeral = c.IsEphemeral() } // Check if profiles was passed if req.Profiles == nil { req.Profiles = c.Profiles() } // Check if config was passed if req.Config == nil { req.Config = c.LocalConfig() } else { for k, v := range c.LocalConfig() { _, ok := req.Config[k] if !ok { req.Config[k] = v } } } // Check if devices was passed if req.Devices == nil { req.Devices = c.LocalDevices() } else { for k, v := range c.LocalDevices() { _, ok := req.Devices[k] if !ok { req.Devices[k] = v } } } // Update container configuration args := containerArgs{ Architecture: architecture, Config: req.Config, Devices: req.Devices, Ephemeral: req.Ephemeral, Profiles: req.Profiles} err = c.Update(args, false) if err != nil { return SmartError(err) } return EmptySyncResponse }
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 imagePatch(d *Daemon, r *http.Request) Response { // Get current value fingerprint := mux.Vars(r)["fingerprint"] id, info, err := dbImageGet(d.db, fingerprint, false, false) if err != nil { return SmartError(err) } // Validate ETag etag := []interface{}{info.Public, info.AutoUpdate, info.Properties} err = etagCheck(r, etag) if err != nil { return PreconditionFailed(err) } body, err := ioutil.ReadAll(r.Body) if err != nil { return InternalError(err) } rdr1 := ioutil.NopCloser(bytes.NewBuffer(body)) rdr2 := ioutil.NopCloser(bytes.NewBuffer(body)) reqRaw := shared.Jmap{} if err := json.NewDecoder(rdr1).Decode(&reqRaw); err != nil { return BadRequest(err) } req := imagePutReq{} if err := json.NewDecoder(rdr2).Decode(&req); err != nil { return BadRequest(err) } // Get AutoUpdate autoUpdate, err := reqRaw.GetBool("auto_update") if err == nil { info.AutoUpdate = autoUpdate } // Get Public public, err := reqRaw.GetBool("public") if err == nil { info.Public = public } // Get Properties _, ok := reqRaw["properties"] if ok { properties := req.Properties for k, v := range info.Properties { _, ok := req.Properties[k] if !ok { properties[k] = v } } info.Properties = properties } err = dbImageUpdate(d.db, id, info.Filename, info.Size, info.Public, info.AutoUpdate, info.Architecture, info.CreationDate, info.ExpiryDate, info.Properties) if err != nil { return SmartError(err) } return EmptySyncResponse }