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