github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/worker/storageprovisioner/blockdevices.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package storageprovisioner 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/names" 9 "github.com/juju/utils/set" 10 11 "github.com/juju/juju/apiserver/params" 12 ) 13 14 // machineBlockDevicesChanged is called when the block devices of the scoped 15 // machine have been seen to have changed. This triggers a refresh of all 16 // block devices for attached volumes backing pending filesystems. 17 func machineBlockDevicesChanged(ctx *context) error { 18 if len(ctx.pendingFilesystems) == 0 { 19 return nil 20 } 21 volumeTags := make([]names.VolumeTag, 0, len(ctx.pendingFilesystems)) 22 for _, params := range ctx.pendingFilesystems { 23 if params.Volume == (names.VolumeTag{}) { 24 // Filesystem is not volume-backed. 25 continue 26 } 27 if _, ok := ctx.volumeBlockDevices[params.Volume]; ok { 28 // Backing-volume's block device is already attached. 29 continue 30 } 31 volumeTags = append(volumeTags, params.Volume) 32 } 33 if len(volumeTags) == 0 { 34 return nil 35 } 36 return refreshVolumeBlockDevices(ctx, volumeTags) 37 } 38 39 // processPendingVolumeBlockDevices is called before waiting for any events, 40 // to force a block-device query for any volumes for which we have not 41 // previously observed block devices. 42 func processPendingVolumeBlockDevices(ctx *context) error { 43 if len(ctx.pendingVolumeBlockDevices) == 0 { 44 logger.Tracef("no pending volume block devices") 45 return nil 46 } 47 volumeTags := make([]names.VolumeTag, len(ctx.pendingVolumeBlockDevices)) 48 for i, tag := range ctx.pendingVolumeBlockDevices.SortedValues() { 49 volumeTags[i] = tag.(names.VolumeTag) 50 } 51 // Clear out the pending set, so we don't force-refresh again. 52 ctx.pendingVolumeBlockDevices = set.NewTags() 53 return refreshVolumeBlockDevices(ctx, volumeTags) 54 } 55 56 // refreshVolumeBlockDevices refreshes the block devices for the specified 57 // volumes. 58 func refreshVolumeBlockDevices(ctx *context, volumeTags []names.VolumeTag) error { 59 machineTag, ok := ctx.scope.(names.MachineTag) 60 if !ok { 61 // This function should only be called by machine-scoped 62 // storage provisioners. 63 panic(errors.New("expected machine tag")) 64 } 65 ids := make([]params.MachineStorageId, len(volumeTags)) 66 for i, volumeTag := range volumeTags { 67 ids[i] = params.MachineStorageId{ 68 MachineTag: machineTag.String(), 69 AttachmentTag: volumeTag.String(), 70 } 71 } 72 results, err := ctx.volumeAccessor.VolumeBlockDevices(ids) 73 if err != nil { 74 return errors.Annotate(err, "refreshing volume block devices") 75 } 76 for i, result := range results { 77 if result.Error == nil { 78 ctx.volumeBlockDevices[volumeTags[i]] = result.Result 79 } else if params.IsCodeNotProvisioned(result.Error) || params.IsCodeNotFound(result.Error) { 80 // Either the volume (attachment) isn't provisioned, 81 // or the corresponding block device is not yet known. 82 // 83 // Neither of these errors is fatal; we just wait for 84 // the block device watcher to notify us again. 85 } else { 86 return errors.Annotatef( 87 err, "getting block device info for volume attachment %v", 88 ids[i], 89 ) 90 } 91 } 92 return nil 93 }