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