Skip to content
This repository has been archived by the owner on Sep 22, 2020. It is now read-only.

torusctl: support create volume from another volume's snapshot #403

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions block/volume.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package block

import (
"fmt"
"io"
"os"
"time"

"github.com/coreos/pkg/progressutil"
"github.com/coreos/torus"
"github.com/coreos/torus/blockset"
"github.com/coreos/torus/models"
Expand Down Expand Up @@ -32,6 +38,56 @@ func CreateBlockVolume(mds torus.MetadataService, volume string, size uint64) er
})
}

func CreateBlockFromSnapshot(srv *torus.Server, origvol, origsnap, newvol string, progress bool) error {
// open original snapshot
srcVol, err := OpenBlockVolume(srv, origvol)
if err != nil {
return fmt.Errorf("couldn't open block volume %s: %v", origvol, err)
}
bfsrc, err := srcVol.OpenSnapshot(origsnap)
if err != nil {
return fmt.Errorf("couldn't open snapshot: %v", err)
}
size := bfsrc.Size()

// create new volume
err = CreateBlockVolume(srv.MDS, newvol, size)
if err != nil {
return fmt.Errorf("error creating volume %s: %v", newvol, err)
}
blockvolDist, err := OpenBlockVolume(srv, newvol)
if err != nil {
return fmt.Errorf("couldn't open block volume %s: %v", newvol, err)
}
bfdist, err := blockvolDist.OpenBlockFile()
if err != nil {
return fmt.Errorf("couldn't open blockfile %s: %v", newvol, err)
}
defer bfdist.Close()

if progress {
pb := progressutil.NewCopyProgressPrinter()
pb.AddCopy(bfsrc, newvol, int64(size), bfdist)
err := pb.PrintAndWait(os.Stderr, 500*time.Millisecond, nil)
if err != nil {
return fmt.Errorf("couldn't copy: %v", err)
}
} else {
n, err := io.Copy(bfdist, bfsrc)
if err != nil {
return fmt.Errorf("couldn't copy: %v", err)
}
if n != int64(size) {
return fmt.Errorf("copied size %d doesn't match original size %d", n, size)
}
}
err = bfdist.Sync()
if err != nil {
return fmt.Errorf("couldn't sync: %v", err)
}
return nil
}

func OpenBlockVolume(s *torus.Server, volume string) (*BlockVolume, error) {
vol, err := s.MDS.GetVolume(volume)
if err != nil {
Expand Down
17 changes: 17 additions & 0 deletions cmd/torusctl/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"os"

"github.com/coreos/torus"
"github.com/coreos/torus/internal/flagconfig"
"github.com/spf13/cobra"
)
Expand All @@ -20,8 +21,24 @@ var blockCreateCommand = &cobra.Command{
Run: volumeCreateBlockAction,
}

var blockCreateFromSnapshotCommand = &cobra.Command{
Use: "from-snapshot VOLUME@SNAPSHOT_NAME NEW_NAME",
Short: "create a block volume from snapshot",
Long: "creates a block volume named NAME from snapshot",
Run: func(cmd *cobra.Command, args []string) {
err := volumeCreateBlockFromSnapshotAction(cmd, args)
if err == torus.ErrUsage {
cmd.Usage()
os.Exit(1)
} else if err != nil {
die("%v", err)
}
},
}

func init() {
blockCommand.AddCommand(blockCreateCommand)
blockCreateCommand.AddCommand(blockCreateFromSnapshotCommand)
flagconfig.AddConfigFlags(blockCommand.PersistentFlags())
}

Expand Down
37 changes: 37 additions & 0 deletions cmd/torusctl/volume.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package main

import (
"fmt"
"os"

"github.com/coreos/torus"
"github.com/coreos/torus/block"
"github.com/dustin/go-humanize"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -33,10 +35,27 @@ var volumeCreateBlockCommand = &cobra.Command{
Run: volumeCreateBlockAction,
}

var volumeCreateBlockFromSnapshotCommand = &cobra.Command{
Use: "from-snapshot VOLUME@SNAPSHOT_NAME NEW_NAME",
Short: "create a block volume from snapshot",
Long: "creates a block volume named NAME from snapshot",
Run: func(cmd *cobra.Command, args []string) {
err := volumeCreateBlockFromSnapshotAction(cmd, args)
if err == torus.ErrUsage {
cmd.Usage()
os.Exit(1)
} else if err != nil {
die("%v", err)
}
},
}

func init() {
volumeCommand.AddCommand(volumeDeleteCommand)
volumeCommand.AddCommand(volumeListCommand)
volumeCommand.AddCommand(volumeCreateBlockCommand)
volumeCreateBlockCommand.AddCommand(volumeCreateBlockFromSnapshotCommand)
volumeCreateBlockFromSnapshotCommand.Flags().BoolVarP(&progress, "progress", "p", false, "show progress")
volumeListCommand.Flags().BoolVarP(&outputAsCSV, "csv", "", false, "output as csv instead")
volumeListCommand.Flags().BoolVarP(&outputAsSI, "si", "", false, "output sizes in powers of 1000")
}
Expand Down Expand Up @@ -109,3 +128,21 @@ func volumeCreateBlockAction(cmd *cobra.Command, args []string) {
die("error creating volume %s: %v", args[0], err)
}
}

func volumeCreateBlockFromSnapshotAction(cmd *cobra.Command, args []string) error {
if len(args) != 2 {
return torus.ErrUsage
}
snapshot := args[0]
newVolName := args[1]

vol := ParseSnapName(snapshot)
if vol.Snapshot == "" {
return fmt.Errorf("can't restore a snapshot without a name, please use the form VOLUME@SNAPSHOT_NAME")
}

srv := createServer()
defer srv.Close()

return block.CreateBlockFromSnapshot(srv, vol.Volume, vol.Snapshot, newVolName, progress)
}