github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/apiserver/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  	"io"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/loggo"
    11  	"gopkg.in/juju/names.v2"
    12  	"gopkg.in/mgo.v2"
    13  
    14  	"github.com/juju/juju/apiserver/common"
    15  	"github.com/juju/juju/apiserver/facade"
    16  	"github.com/juju/juju/apiserver/params"
    17  	"github.com/juju/juju/controller"
    18  	"github.com/juju/juju/environs/config"
    19  	"github.com/juju/juju/mongo"
    20  	"github.com/juju/juju/permission"
    21  	"github.com/juju/juju/state"
    22  	"github.com/juju/juju/state/backups"
    23  )
    24  
    25  var logger = loggo.GetLogger("juju.apiserver.backups")
    26  
    27  // Backend exposes state.State functionality needed by the backups Facade.
    28  type Backend interface {
    29  	IsController() bool
    30  	Machine(id string) (*state.Machine, error)
    31  	MachineSeries(id string) (string, error)
    32  	MongoConnectionInfo() *mongo.MongoInfo
    33  	MongoSession() *mgo.Session
    34  	MongoVersion() (string, error)
    35  	ModelTag() names.ModelTag
    36  	ControllerTag() names.ControllerTag
    37  	ModelConfig() (*config.Config, error)
    38  	ControllerConfig() (controller.Config, error)
    39  	StateServingInfo() (state.StateServingInfo, error)
    40  	RestoreInfo() *state.RestoreInfo
    41  }
    42  
    43  // API serves backup-specific API methods.
    44  type API struct {
    45  	backend Backend
    46  	paths   *backups.Paths
    47  
    48  	// machineID is the ID of the machine where the API server is running.
    49  	machineID string
    50  }
    51  
    52  // NewAPI creates a new instance of the Backups API facade.
    53  func NewAPI(backend Backend, resources facade.Resources, authorizer facade.Authorizer) (*API, error) {
    54  	isControllerAdmin, err := authorizer.HasPermission(permission.SuperuserAccess, backend.ControllerTag())
    55  	if err != nil && !errors.IsNotFound(err) {
    56  		return nil, errors.Trace(err)
    57  	}
    58  
    59  	if !authorizer.AuthClient() || !isControllerAdmin {
    60  		return nil, common.ErrPerm
    61  	}
    62  
    63  	// For now, backup operations are only permitted on the controller environment.
    64  	if !backend.IsController() {
    65  		return nil, errors.New("backups are not supported for hosted models")
    66  	}
    67  
    68  	// Get the backup paths.
    69  	dataDir, err := extractResourceValue(resources, "dataDir")
    70  	if err != nil {
    71  		return nil, errors.Trace(err)
    72  	}
    73  	logsDir, err := extractResourceValue(resources, "logDir")
    74  	if err != nil {
    75  		return nil, errors.Trace(err)
    76  	}
    77  	paths := backups.Paths{
    78  		DataDir: dataDir,
    79  		LogsDir: logsDir,
    80  	}
    81  
    82  	// Build the API.
    83  	machineID, err := extractResourceValue(resources, "machineID")
    84  	if err != nil {
    85  		return nil, errors.Trace(err)
    86  	}
    87  	b := API{
    88  		backend:   backend,
    89  		paths:     &paths,
    90  		machineID: machineID,
    91  	}
    92  	return &b, nil
    93  }
    94  
    95  func extractResourceValue(resources facade.Resources, key string) (string, error) {
    96  	res := resources.Get(key)
    97  	strRes, ok := res.(common.StringResource)
    98  	if !ok {
    99  		if res == nil {
   100  			strRes = ""
   101  		} else {
   102  			return "", errors.Errorf("invalid %s resource: %v", key, res)
   103  		}
   104  	}
   105  	return strRes.String(), nil
   106  }
   107  
   108  var newBackups = func(backend Backend) (backups.Backups, io.Closer) {
   109  	stor := backups.NewStorage(backend)
   110  	return backups.NewBackups(stor), stor
   111  }
   112  
   113  // ResultFromMetadata updates the result with the information in the
   114  // metadata value.
   115  func ResultFromMetadata(meta *backups.Metadata) params.BackupsMetadataResult {
   116  	var result params.BackupsMetadataResult
   117  
   118  	result.ID = meta.ID()
   119  
   120  	result.Checksum = meta.Checksum()
   121  	result.ChecksumFormat = meta.ChecksumFormat()
   122  	result.Size = meta.Size()
   123  	if meta.Stored() != nil {
   124  		result.Stored = *(meta.Stored())
   125  	}
   126  
   127  	result.Started = meta.Started
   128  	if meta.Finished != nil {
   129  		result.Finished = *meta.Finished
   130  	}
   131  	result.Notes = meta.Notes
   132  
   133  	result.Model = meta.Origin.Model
   134  	result.Machine = meta.Origin.Machine
   135  	result.Hostname = meta.Origin.Hostname
   136  	result.Version = meta.Origin.Version
   137  	result.Series = meta.Origin.Series
   138  
   139  	// TODO(wallyworld) - remove these ASAP
   140  	// These are only used by the restore CLI when re-bootstrapping.
   141  	// We will use a better solution but the way restore currently
   142  	// works, we need them and they are no longer available via
   143  	// bootstrap config. We will need to ifx how re-bootstrap deals
   144  	// with these keys to address the issue.
   145  	result.CACert = meta.CACert
   146  	result.CAPrivateKey = meta.CAPrivateKey
   147  
   148  	return result
   149  }
   150  
   151  // MetadataFromResult returns a new Metadata based on the result. The ID
   152  // of the metadata is not set. Call meta.SetID() if that is desired.
   153  // Likewise with Stored and meta.SetStored().
   154  func MetadataFromResult(result params.BackupsMetadataResult) *backups.Metadata {
   155  	meta := backups.NewMetadata()
   156  	meta.Started = result.Started
   157  	if !result.Finished.IsZero() {
   158  		meta.Finished = &result.Finished
   159  	}
   160  	meta.Origin.Model = result.Model
   161  	meta.Origin.Machine = result.Machine
   162  	meta.Origin.Hostname = result.Hostname
   163  	meta.Origin.Version = result.Version
   164  	meta.Origin.Series = result.Series
   165  	meta.Notes = result.Notes
   166  	meta.SetFileInfo(result.Size, result.Checksum, result.ChecksumFormat)
   167  	return meta
   168  }