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 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(op *operation) error { return sc.Rename(containerName + shared.SnapshotDelimiter + newName) } 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 certificateFingerprintPatch(d *Daemon, r *http.Request) Response { fingerprint := mux.Vars(r)["fingerprint"] oldEntry, err := doCertificateGet(d, fingerprint) if err != nil { return SmartError(err) } fingerprint = oldEntry.Fingerprint err = etagCheck(r, oldEntry) if err != nil { return PreconditionFailed(err) } req := oldEntry reqRaw := shared.Jmap{} if err := json.NewDecoder(r.Body).Decode(&reqRaw); err != nil { return BadRequest(err) } // Get name value, err := reqRaw.GetString("name") if err == nil { req.Name = value } // Get type value, err = reqRaw.GetString("type") if err == nil { req.Type = value } return doCertificateUpdate(d, fingerprint, req) }
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 aliasPatch(d *Daemon, r *http.Request) Response { // Get current value name := mux.Vars(r)["name"] id, alias, err := dbImageAliasGet(d.db, name, true) if err != nil { return SmartError(err) } // Validate ETag err = etagCheck(r, alias) if err != nil { return PreconditionFailed(err) } req := shared.Jmap{} if err := json.NewDecoder(r.Body).Decode(&req); err != nil { return BadRequest(err) } _, ok := req["target"] if ok { target, err := req.GetString("target") if err != nil { return BadRequest(err) } alias.Target = target } _, ok = req["description"] if ok { description, err := req.GetString("description") if err != nil { return BadRequest(err) } alias.Description = description } imageId, _, err := dbImageGet(d.db, alias.Target, false, false) if err != nil { return SmartError(err) } err = dbImageAliasUpdate(d.db, id, imageId, alias.Description) if err != nil { return SmartError(err) } return EmptySyncResponse }
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 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 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 }
func profilePatch(d *Daemon, r *http.Request) Response { // Get the profile name := mux.Vars(r)["name"] id, profile, err := dbProfileGet(d.db, name) if err != nil { return InternalError(fmt.Errorf("Failed to retrieve profile='%s'", name)) } // Validate the ETag err = etagCheck(r, profile) 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 := profilesPostReq{} if err := json.NewDecoder(rdr2).Decode(&req); err != nil { return BadRequest(err) } // Get Description _, err = reqRaw.GetString("description") if err != nil { req.Description = profile.Description } // Get Config if req.Config == nil { req.Config = profile.Config } else { for k, v := range profile.Config { _, ok := req.Config[k] if !ok { req.Config[k] = v } } } // Get Devices if req.Devices == nil { req.Devices = profile.Devices } else { for k, v := range profile.Devices { _, ok := req.Devices[k] if !ok { req.Devices[k] = v } } } return doProfileUpdate(d, name, id, profile, req) }