github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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 }