github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/cmd/juju/backups/backups.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package backups
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"os"
    10  
    11  	"github.com/juju/cmd"
    12  	"github.com/juju/errors"
    13  
    14  	"github.com/juju/juju/api/backups"
    15  	apiserverbackups "github.com/juju/juju/apiserver/backups"
    16  	"github.com/juju/juju/apiserver/params"
    17  	"github.com/juju/juju/cmd/envcmd"
    18  	statebackups "github.com/juju/juju/state/backups"
    19  )
    20  
    21  var backupsDoc = `
    22  "juju backups" is used to manage backups of the state of a juju environment.
    23  `
    24  
    25  const backupsPurpose = "create, manage, and restore backups of juju's state"
    26  
    27  // Command is the top-level command wrapping all backups functionality.
    28  type Command struct {
    29  	cmd.SuperCommand
    30  }
    31  
    32  // NewCommand returns a new backups super-command.
    33  func NewCommand() cmd.Command {
    34  	backupsCmd := Command{
    35  		SuperCommand: *cmd.NewSuperCommand(
    36  			cmd.SuperCommandParams{
    37  				Name:        "backups",
    38  				Doc:         backupsDoc,
    39  				UsagePrefix: "juju",
    40  				Purpose:     backupsPurpose,
    41  			},
    42  		),
    43  	}
    44  	backupsCmd.Register(envcmd.Wrap(&CreateCommand{}))
    45  	backupsCmd.Register(envcmd.Wrap(&InfoCommand{}))
    46  	backupsCmd.Register(envcmd.Wrap(&ListCommand{}))
    47  	backupsCmd.Register(envcmd.Wrap(&DownloadCommand{}))
    48  	backupsCmd.Register(envcmd.Wrap(&UploadCommand{}))
    49  	backupsCmd.Register(envcmd.Wrap(&RemoveCommand{}))
    50  	backupsCmd.Register(envcmd.Wrap(&RestoreCommand{}))
    51  	return &backupsCmd
    52  }
    53  
    54  // APIClient represents the backups API client functionality used by
    55  // the backups command.
    56  type APIClient interface {
    57  	io.Closer
    58  	// Create sends an RPC request to create a new backup.
    59  	Create(notes string) (*params.BackupsMetadataResult, error)
    60  	// Info gets the backup's metadata.
    61  	Info(id string) (*params.BackupsMetadataResult, error)
    62  	// List gets all stored metadata.
    63  	List() (*params.BackupsListResult, error)
    64  	// Download pulls the backup archive file.
    65  	Download(id string) (io.ReadCloser, error)
    66  	// Upload pushes a backup archive to storage.
    67  	Upload(ar io.Reader, meta params.BackupsMetadataResult) (string, error)
    68  	// Remove removes the stored backup.
    69  	Remove(id string) error
    70  	// Restore will restore a backup with the given id into the state server.
    71  	Restore(string, backups.ClientConnection) error
    72  	// Restore will restore a backup file into the state server.
    73  	RestoreReader(io.Reader, *params.BackupsMetadataResult, backups.ClientConnection) error
    74  }
    75  
    76  // CommandBase is the base type for backups sub-commands.
    77  type CommandBase struct {
    78  	envcmd.EnvCommandBase
    79  }
    80  
    81  // NewAPIClient returns a client for the backups api endpoint.
    82  func (c *CommandBase) NewAPIClient() (APIClient, error) {
    83  	return newAPIClient(c)
    84  }
    85  
    86  var newAPIClient = func(c *CommandBase) (APIClient, error) {
    87  	root, err := c.NewAPIRoot()
    88  	if err != nil {
    89  		return nil, errors.Trace(err)
    90  	}
    91  	return backups.NewClient(root), nil
    92  }
    93  
    94  // dumpMetadata writes the formatted backup metadata to stdout.
    95  func (c *CommandBase) dumpMetadata(ctx *cmd.Context, result *params.BackupsMetadataResult) {
    96  	fmt.Fprintf(ctx.Stdout, "backup ID:       %q\n", result.ID)
    97  	fmt.Fprintf(ctx.Stdout, "checksum:        %q\n", result.Checksum)
    98  	fmt.Fprintf(ctx.Stdout, "checksum format: %q\n", result.ChecksumFormat)
    99  	fmt.Fprintf(ctx.Stdout, "size (B):        %d\n", result.Size)
   100  	fmt.Fprintf(ctx.Stdout, "stored:          %v\n", result.Stored)
   101  
   102  	fmt.Fprintf(ctx.Stdout, "started:         %v\n", result.Started)
   103  	fmt.Fprintf(ctx.Stdout, "finished:        %v\n", result.Finished)
   104  	fmt.Fprintf(ctx.Stdout, "notes:           %q\n", result.Notes)
   105  
   106  	fmt.Fprintf(ctx.Stdout, "environment ID:  %q\n", result.Environment)
   107  	fmt.Fprintf(ctx.Stdout, "machine ID:      %q\n", result.Machine)
   108  	fmt.Fprintf(ctx.Stdout, "created on host: %q\n", result.Hostname)
   109  	fmt.Fprintf(ctx.Stdout, "juju version:    %v\n", result.Version)
   110  }
   111  
   112  func getArchive(filename string) (rc io.ReadCloser, metaResult *params.BackupsMetadataResult, err error) {
   113  	defer func() {
   114  		if err != nil && rc != nil {
   115  			rc.Close()
   116  		}
   117  	}()
   118  	archive, err := os.Open(filename)
   119  	rc = archive
   120  	if err != nil {
   121  		return nil, nil, errors.Trace(err)
   122  	}
   123  
   124  	// Extract the metadata.
   125  	ad, err := statebackups.NewArchiveDataReader(archive)
   126  	if err != nil {
   127  		return nil, nil, errors.Trace(err)
   128  	}
   129  	_, err = archive.Seek(0, os.SEEK_SET)
   130  	if err != nil {
   131  		return nil, nil, errors.Trace(err)
   132  	}
   133  	meta, err := ad.Metadata()
   134  	if err != nil {
   135  		if !errors.IsNotFound(err) {
   136  			return nil, nil, errors.Trace(err)
   137  		}
   138  		meta, err = statebackups.BuildMetadata(archive)
   139  		if err != nil {
   140  			return nil, nil, errors.Trace(err)
   141  		}
   142  	}
   143  	// Make sure the file info is set.
   144  	fileMeta, err := statebackups.BuildMetadata(archive)
   145  	if err != nil {
   146  		return nil, nil, errors.Trace(err)
   147  	}
   148  	if meta.Size() == int64(0) {
   149  		if err := meta.SetFileInfo(fileMeta.Size(), "", ""); err != nil {
   150  			return nil, nil, errors.Trace(err)
   151  		}
   152  	}
   153  	if meta.Checksum() == "" {
   154  		err := meta.SetFileInfo(0, fileMeta.Checksum(), fileMeta.ChecksumFormat())
   155  		if err != nil {
   156  			return nil, nil, errors.Trace(err)
   157  		}
   158  	}
   159  	if meta.Finished == nil || meta.Finished.IsZero() {
   160  		meta.Finished = fileMeta.Finished
   161  	}
   162  	_, err = archive.Seek(0, os.SEEK_SET)
   163  	if err != nil {
   164  		return nil, nil, errors.Trace(err)
   165  	}
   166  
   167  	// Pack the metadata into a result.
   168  	// TODO(perrito666) change the identity of ResultfromMetadata to
   169  	// return a pointer.
   170  	mResult := apiserverbackups.ResultFromMetadata(meta)
   171  	metaResult = &mResult
   172  
   173  	return archive, metaResult, nil
   174  }