func (vd *volDriver) parseSnapID(r *http.Request) (api.SnapID, error) { vars := mux.Vars(r) if id, ok := vars["id"]; ok { return api.SnapID(id), nil } return api.BadSnapID, fmt.Errorf("could not parse snap ID") }
// Snap specified volume. IO to the underlying volume should be quiesced before // calling this function. // Errors ErrEnoEnt may be returned func (v *volumeClient) Snapshot(volumeID api.VolumeID, labels api.Labels) (api.SnapID, error) { var response api.SnapCreateResponse createReq := api.SnapCreateRequest{ ID: volumeID, Labels: labels, } err := v.c.Post().Resource(snapPath).Body(&createReq).Do().Unmarshal(&response) if err != nil { return api.SnapID(""), err } if response.Error != "" { return api.SnapID(""), errors.New(response.Error) } return response.ID, nil }
func TestSnapEnumerate(t *testing.T) { snapID := api.SnapID(snapName) id := api.VolumeID(volName) vol := api.Volume{ ID: id, Locator: api.VolumeLocator{Name: volName, VolumeLabels: labels}, State: api.VolumeAvailable, Spec: &api.VolumeSpec{}, } err := store.CreateVol(&vol) assert.NoError(t, err, "Failed in CreateVol") snap := api.VolumeSnap{ ID: snapID, VolumeID: id, SnapLabels: labels, } err = store.CreateSnap(&snap) assert.NoError(t, err, "Failed in CreateSnap") snaps, err := store.SnapEnumerate(api.VolumeLocator{Name: volName}, nil) assert.NoError(t, err, "Failed in Enumerate") assert.Equal(t, len(snaps), 1, "Number of snaps returned in enumerate should be 1") if len(snaps) == 1 { assert.Equal(t, snaps[0].ID, snap.ID, "Invalid snap returned in Enumerate") } snaps, err = store.SnapEnumerate(api.VolumeLocator{VolumeLabels: labels}, nil) assert.NoError(t, err, "Failed in Enumerate") assert.Equal(t, len(snaps), 1, "Number of snaps returned in enumerate should be 1") if len(snaps) == 1 { assert.Equal(t, snaps[0].ID, snap.ID, "Invalid snap returned in Enumerate") } snaps, err = store.SnapEnumerate(api.VolumeLocator{}, labels) assert.NoError(t, err, "Failed in Enumerate") assert.True(t, len(snaps) >= 1, "Number of snaps returned in enumerate should be at least 1") if len(snaps) == 1 { assert.Equal(t, snaps[0].ID, snap.ID, "Invalid snap returned in Enumerate") } snaps, err = store.SnapEnumerate(api.VolumeLocator{}, nil) assert.NoError(t, err, "Failed in Enumerate") assert.True(t, len(snaps) >= 1, "Number of snaps returned in enumerate should be at least 1") if len(snaps) == 1 { assert.Equal(t, snaps[0].ID, snap.ID, "Invalid snap returned in Enumerate") } err = store.DeleteSnap(snapID) assert.NoError(t, err, "Failed in Delete") snaps, err = store.SnapEnumerate(api.VolumeLocator{Name: volName}, nil) assert.NotNil(t, snaps, "Inspect returned nil snaps") assert.Equal(t, len(snaps), 0, "Number of snaps returned in enumerate should be 0") err = store.DeleteVol(id) assert.NoError(t, err, "Failed in Delete") }
func snapInspect(t *testing.T, ctx *Context) { fmt.Println("snapInspect") snaps, err := ctx.SnapInspect([]api.SnapID{ctx.snapID}) assert.NoError(t, err, "Failed in Inspect") assert.NotNil(t, snaps, "Nil snaps") assert.Equal(t, len(snaps), 1, "Expect 1 snaps actual %v snaps", len(snaps)) assert.Equal(t, snaps[0].ID, ctx.snapID, "Expect snapID %v actual %v", ctx.snapID, snaps[0].ID) snaps, err = ctx.SnapInspect([]api.SnapID{api.SnapID("shouldNotExist")}) assert.Equal(t, 0, len(snaps), "Expect 0 snaps actual %v snaps", len(snaps)) }
func (vd *volDriver) snapEnumerate(w http.ResponseWriter, r *http.Request) { var err error var labels api.Labels var ids []api.VolumeID var snaps []api.VolumeSnap method := "snapEnumerate" d, err := volume.Get(vd.name) if err != nil { vd.notFound(w, r) return } params := r.URL.Query() v := params[string(api.OptLabel)] if v != nil { if err = json.Unmarshal([]byte(v[0]), &labels); err != nil { e := fmt.Errorf("Failed to parse parse VolumeLabels: %s", err.Error()) vd.sendError(vd.name, method, w, e.Error(), http.StatusBadRequest) } } v, ok := params[string(api.OptSnapID)] if ok && v != nil { sids := make([]api.SnapID, len(params)) for i, s := range v { sids[i] = api.SnapID(s) } snaps, err = d.SnapInspect(sids) if err != nil { e := fmt.Errorf("Failed to inspect snaps: %s", err.Error()) vd.sendError(vd.name, method, w, e.Error(), http.StatusBadRequest) return } } else { v, ok = params[string(api.OptVolumeID)] if v != nil && ok { ids = make([]api.VolumeID, len(params)) for i, s := range v { ids[i] = api.VolumeID(s) } } snaps, err = d.SnapEnumerate(ids, labels) if err != nil { e := fmt.Errorf("Failed to enumerate snaps: %s", err.Error()) vd.sendError(vd.name, method, w, e.Error(), http.StatusBadRequest) return } } json.NewEncoder(w).Encode(snaps) }
func (v *volDriver) snapDelete(c *cli.Context) { fn := "delete" if len(c.Args()) < 1 { missingParameter(c, fn, "snapID", "Invalid number of arguments") return } v.volumeOptions(c) snapID := c.Args()[0] err := v.volDriver.SnapDelete(api.SnapID(snapID)) if err != nil { cmdError(c, fn, err) return } fmtOutput(c, &Format{UUID: []string{c.Args()[0]}}) }
// Snapshot create new subvolume from volume func (d *driver) Snapshot(volumeID api.VolumeID, labels api.Labels) (api.SnapID, error) { snapID := uuid.New() snap := &api.VolumeSnap{ ID: api.SnapID(snapID), VolumeID: volumeID, SnapLabels: labels, Ctime: time.Now(), } err := d.CreateSnap(snap) if err != nil { return api.BadSnapID, err } chaos.Now(koStrayCreate) err = d.btrfs.Create(snapID, string(volumeID)) if err != nil { return api.BadSnapID, err } return snap.ID, nil }
func (v *volDriver) snapInspect(c *cli.Context) { v.volumeOptions(c) fn := "inspect" if len(c.Args()) < 1 { missingParameter(c, fn, "snapID", "Invalid number of arguments") return } d := make([]api.SnapID, len(c.Args())) for i, v := range c.Args() { d[i] = api.SnapID(v) } snaps, err := v.volDriver.SnapInspect(d) if err != nil { cmdError(c, fn, err) return } cmdOutput(c, snaps) }
func (d *Driver) Snapshot(volumeID api.VolumeID, labels api.Labels) (api.SnapID, error) { dryRun := false awsID := string(volumeID) request := &ec2.CreateSnapshotInput{ VolumeID: &awsID, DryRun: &dryRun, } snap, err := d.ec2.CreateSnapshot(request) chaos.Now(koStrayCreate) volSnap := &api.VolumeSnap{ ID: api.SnapID(*snap.SnapshotID), VolumeID: volumeID, SnapLabels: labels, Ctime: time.Now(), } chaos.Now(koStrayCreate) err = d.CreateSnap(volSnap) if err != nil { return api.BadSnapID, err } return volSnap.ID, nil }
func TestSnapInspect(t *testing.T) { snapID := api.SnapID(snapName) id := api.VolumeID(volName) snap := api.VolumeSnap{ ID: snapID, VolumeID: id, SnapLabels: labels, } err := store.CreateSnap(&snap) assert.NoError(t, err, "Failed in CreateSnap") snaps, err := store.SnapInspect([]api.SnapID{snapID}) assert.NoError(t, err, "Failed in Inspect") assert.Equal(t, len(snaps), 1, "Number of snaps returned in Inspect should be 1") if len(snaps) == 1 { assert.Equal(t, snaps[0].ID, snap.ID, "Invalid snap returned in Enumerate") } err = store.DeleteSnap(snapID) assert.NoError(t, err, "Failed in Delete") snaps, err = store.SnapEnumerate(api.VolumeLocator{Name: volName}, nil) assert.Equal(t, len(snaps), 0, "Number of snaps returned in enumerate should be 1") }