github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/apiserver/diskmanager/diskmanager.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package diskmanager 5 6 import ( 7 "github.com/juju/names" 8 9 "github.com/juju/juju/apiserver/common" 10 "github.com/juju/juju/apiserver/params" 11 "github.com/juju/juju/state" 12 "github.com/juju/juju/storage" 13 ) 14 15 func init() { 16 common.RegisterStandardFacade("DiskManager", 2, NewDiskManagerAPI) 17 } 18 19 // DiskManagerAPI provides access to the DiskManager API facade. 20 type DiskManagerAPI struct { 21 st stateInterface 22 authorizer common.Authorizer 23 getAuthFunc common.GetAuthFunc 24 } 25 26 var getState = func(st *state.State) stateInterface { 27 return stateShim{st} 28 } 29 30 // NewDiskManagerAPI creates a new server-side DiskManager API facade. 31 func NewDiskManagerAPI( 32 st *state.State, 33 resources *common.Resources, 34 authorizer common.Authorizer, 35 ) (*DiskManagerAPI, error) { 36 37 if !authorizer.AuthMachineAgent() { 38 return nil, common.ErrPerm 39 } 40 41 authEntityTag := authorizer.GetAuthTag() 42 getAuthFunc := func() (common.AuthFunc, error) { 43 return func(tag names.Tag) bool { 44 // A machine agent can always access its own machine. 45 return tag == authEntityTag 46 }, nil 47 } 48 49 return &DiskManagerAPI{ 50 st: getState(st), 51 authorizer: authorizer, 52 getAuthFunc: getAuthFunc, 53 }, nil 54 } 55 56 func (d *DiskManagerAPI) SetMachineBlockDevices(args params.SetMachineBlockDevices) (params.ErrorResults, error) { 57 result := params.ErrorResults{ 58 Results: make([]params.ErrorResult, len(args.MachineBlockDevices)), 59 } 60 canAccess, err := d.getAuthFunc() 61 if err != nil { 62 return result, err 63 } 64 for i, arg := range args.MachineBlockDevices { 65 tag, err := names.ParseMachineTag(arg.Machine) 66 if err != nil { 67 result.Results[i].Error = common.ServerError(common.ErrPerm) 68 continue 69 } 70 if !canAccess(tag) { 71 err = common.ErrPerm 72 } else { 73 // TODO(axw) create volumes for block devices without matching 74 // volumes, if and only if the block device has a serial. Under 75 // the assumption of unique (to a machine) serial IDs, this 76 // gives us a guaranteed *persistently* unique way of identifying 77 // the volume. 78 // 79 // NOTE: we must predicate the above on there being no unprovisioned 80 // volume attachments for the machine, otherwise we would have 81 // a race between the volume attachment info being recorded and 82 // the diskmanager publishing block devices and erroneously creating 83 // volumes. 84 err = d.st.SetMachineBlockDevices(tag.Id(), stateBlockDeviceInfo(arg.BlockDevices)) 85 // TODO(axw) set volume/filesystem attachment info. 86 } 87 result.Results[i].Error = common.ServerError(err) 88 } 89 return result, nil 90 } 91 92 func stateBlockDeviceInfo(devices []storage.BlockDevice) []state.BlockDeviceInfo { 93 result := make([]state.BlockDeviceInfo, len(devices)) 94 for i, dev := range devices { 95 result[i] = state.BlockDeviceInfo{ 96 dev.DeviceName, 97 dev.DeviceLinks, 98 dev.Label, 99 dev.UUID, 100 dev.HardwareId, 101 dev.BusAddress, 102 dev.Size, 103 dev.FilesystemType, 104 dev.InUse, 105 dev.MountPoint, 106 } 107 } 108 return result 109 }