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