github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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  	"launchpad.net/gnuflag"
    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/modelcmd"
    19  	statebackups "github.com/juju/juju/state/backups"
    20  )
    21  
    22  // APIClient represents the backups API client functionality used by
    23  // the backups command.
    24  type APIClient interface {
    25  	io.Closer
    26  	// Create sends an RPC request to create a new backup.
    27  	Create(notes string) (*params.BackupsMetadataResult, error)
    28  	// Info gets the backup's metadata.
    29  	Info(id string) (*params.BackupsMetadataResult, error)
    30  	// List gets all stored metadata.
    31  	List() (*params.BackupsListResult, error)
    32  	// Download pulls the backup archive file.
    33  	Download(id string) (io.ReadCloser, error)
    34  	// Upload pushes a backup archive to storage.
    35  	Upload(ar io.ReadSeeker, meta params.BackupsMetadataResult) (string, error)
    36  	// Remove removes the stored backup.
    37  	Remove(id string) error
    38  	// Restore will restore a backup with the given id into the controller.
    39  	Restore(string, backups.ClientConnection) error
    40  	// RestoreReader will restore a backup file into the controller.
    41  	RestoreReader(io.ReadSeeker, *params.BackupsMetadataResult, backups.ClientConnection) error
    42  }
    43  
    44  // CommandBase is the base type for backups sub-commands.
    45  type CommandBase struct {
    46  	// TODO(wallyworld) - remove Log when backup command is flattened.
    47  	Log *cmd.Log
    48  	modelcmd.ModelCommandBase
    49  }
    50  
    51  // NewAPIClient returns a client for the backups api endpoint.
    52  func (c *CommandBase) NewAPIClient() (APIClient, error) {
    53  	return newAPIClient(c)
    54  }
    55  
    56  // SetFlags implements Command.SetFlags.
    57  func (c *CommandBase) SetFlags(f *gnuflag.FlagSet) {
    58  	if c.Log != nil {
    59  		c.Log.AddFlags(f)
    60  	}
    61  }
    62  
    63  var newAPIClient = func(c *CommandBase) (APIClient, error) {
    64  	root, err := c.NewAPIRoot()
    65  	if err != nil {
    66  		return nil, errors.Trace(err)
    67  	}
    68  	return backups.NewClient(root)
    69  }
    70  
    71  // dumpMetadata writes the formatted backup metadata to stdout.
    72  func (c *CommandBase) dumpMetadata(ctx *cmd.Context, result *params.BackupsMetadataResult) {
    73  	fmt.Fprintf(ctx.Stdout, "backup ID:       %q\n", result.ID)
    74  	fmt.Fprintf(ctx.Stdout, "checksum:        %q\n", result.Checksum)
    75  	fmt.Fprintf(ctx.Stdout, "checksum format: %q\n", result.ChecksumFormat)
    76  	fmt.Fprintf(ctx.Stdout, "size (B):        %d\n", result.Size)
    77  	fmt.Fprintf(ctx.Stdout, "stored:          %v\n", result.Stored)
    78  
    79  	fmt.Fprintf(ctx.Stdout, "started:         %v\n", result.Started)
    80  	fmt.Fprintf(ctx.Stdout, "finished:        %v\n", result.Finished)
    81  	fmt.Fprintf(ctx.Stdout, "notes:           %q\n", result.Notes)
    82  
    83  	fmt.Fprintf(ctx.Stdout, "model ID:        %q\n", result.Model)
    84  	fmt.Fprintf(ctx.Stdout, "machine ID:      %q\n", result.Machine)
    85  	fmt.Fprintf(ctx.Stdout, "created on host: %q\n", result.Hostname)
    86  	fmt.Fprintf(ctx.Stdout, "juju version:    %v\n", result.Version)
    87  }
    88  
    89  // ArchiveReader can read a backup archive.
    90  type ArchiveReader interface {
    91  	io.ReadSeeker
    92  	io.Closer
    93  }
    94  
    95  func getArchive(filename string) (rc ArchiveReader, metaResult *params.BackupsMetadataResult, err error) {
    96  	defer func() {
    97  		if err != nil && rc != nil {
    98  			rc.Close()
    99  		}
   100  	}()
   101  	archive, err := os.Open(filename)
   102  	rc = archive
   103  	if err != nil {
   104  		return nil, nil, errors.Trace(err)
   105  	}
   106  
   107  	// Extract the metadata.
   108  	ad, err := statebackups.NewArchiveDataReader(archive)
   109  	if err != nil {
   110  		return nil, nil, errors.Trace(err)
   111  	}
   112  	_, err = archive.Seek(0, os.SEEK_SET)
   113  	if err != nil {
   114  		return nil, nil, errors.Trace(err)
   115  	}
   116  	meta, err := ad.Metadata()
   117  	if err != nil {
   118  		if !errors.IsNotFound(err) {
   119  			return nil, nil, errors.Trace(err)
   120  		}
   121  		meta, err = statebackups.BuildMetadata(archive)
   122  		if err != nil {
   123  			return nil, nil, errors.Trace(err)
   124  		}
   125  	}
   126  	// Make sure the file info is set.
   127  	fileMeta, err := statebackups.BuildMetadata(archive)
   128  	if err != nil {
   129  		return nil, nil, errors.Trace(err)
   130  	}
   131  	if meta.Size() == int64(0) {
   132  		if err := meta.SetFileInfo(fileMeta.Size(), "", ""); err != nil {
   133  			return nil, nil, errors.Trace(err)
   134  		}
   135  	}
   136  	if meta.Checksum() == "" {
   137  		err := meta.SetFileInfo(0, fileMeta.Checksum(), fileMeta.ChecksumFormat())
   138  		if err != nil {
   139  			return nil, nil, errors.Trace(err)
   140  		}
   141  	}
   142  	if meta.Finished == nil || meta.Finished.IsZero() {
   143  		meta.Finished = fileMeta.Finished
   144  	}
   145  	_, err = archive.Seek(0, os.SEEK_SET)
   146  	if err != nil {
   147  		return nil, nil, errors.Trace(err)
   148  	}
   149  
   150  	// Pack the metadata into a result.
   151  	// TODO(perrito666) change the identity of ResultfromMetadata to
   152  	// return a pointer.
   153  	mResult := apiserverbackups.ResultFromMetadata(meta)
   154  	metaResult = &mResult
   155  
   156  	return archive, metaResult, nil
   157  }