github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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/utils/set" 9 "gopkg.in/juju/names.v2" 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.incompleteFilesystemParams) == 0 { 19 return nil 20 } 21 volumeTags := make([]names.VolumeTag, 0, len(ctx.incompleteFilesystemParams)) 22 // We only need to query volumes for incomplete filesystems, 23 // and not incomplete filesystem attachments, because a 24 // filesystem attachment cannot exist without a filesystem. 25 // Therefore, the block device must have existed before 26 // the filesystem attachment. Upon restarting the worker, 27 // witnessing an already-provisioned filesystem will trigger 28 // a refresh of the block device for the backing volume. 29 for _, params := range ctx.incompleteFilesystemParams { 30 if params.Volume == (names.VolumeTag{}) { 31 // Filesystem is not volume-backed. 32 continue 33 } 34 if _, ok := ctx.volumeBlockDevices[params.Volume]; ok { 35 // Backing-volume's block device is already attached. 36 continue 37 } 38 volumeTags = append(volumeTags, params.Volume) 39 } 40 if len(volumeTags) == 0 { 41 return nil 42 } 43 return refreshVolumeBlockDevices(ctx, volumeTags) 44 } 45 46 // processPendingVolumeBlockDevices is called before waiting for any events, 47 // to force a block-device query for any volumes for which we have not 48 // previously observed block devices. 49 func processPendingVolumeBlockDevices(ctx *context) error { 50 if len(ctx.pendingVolumeBlockDevices) == 0 { 51 logger.Tracef("no pending volume block devices") 52 return nil 53 } 54 volumeTags := make([]names.VolumeTag, len(ctx.pendingVolumeBlockDevices)) 55 for i, tag := range ctx.pendingVolumeBlockDevices.SortedValues() { 56 volumeTags[i] = tag.(names.VolumeTag) 57 } 58 // Clear out the pending set, so we don't force-refresh again. 59 ctx.pendingVolumeBlockDevices = set.NewTags() 60 return refreshVolumeBlockDevices(ctx, volumeTags) 61 } 62 63 // refreshVolumeBlockDevices refreshes the block devices for the specified 64 // volumes. 65 func refreshVolumeBlockDevices(ctx *context, volumeTags []names.VolumeTag) error { 66 machineTag, ok := ctx.config.Scope.(names.MachineTag) 67 if !ok { 68 // This function should only be called by machine-scoped 69 // storage provisioners. 70 panic(errors.New("expected machine tag")) 71 } 72 ids := make([]params.MachineStorageId, len(volumeTags)) 73 for i, volumeTag := range volumeTags { 74 ids[i] = params.MachineStorageId{ 75 MachineTag: machineTag.String(), 76 AttachmentTag: volumeTag.String(), 77 } 78 } 79 results, err := ctx.config.Volumes.VolumeBlockDevices(ids) 80 if err != nil { 81 return errors.Annotate(err, "refreshing volume block devices") 82 } 83 for i, result := range results { 84 if result.Error == nil { 85 ctx.volumeBlockDevices[volumeTags[i]] = result.Result 86 for _, params := range ctx.incompleteFilesystemParams { 87 if params.Volume == volumeTags[i] { 88 updatePendingFilesystem(ctx, params) 89 } 90 } 91 for id, params := range ctx.incompleteFilesystemAttachmentParams { 92 filesystem, ok := ctx.filesystems[params.Filesystem] 93 if !ok { 94 continue 95 } 96 if filesystem.Volume == volumeTags[i] { 97 updatePendingFilesystemAttachment(ctx, id, params) 98 } 99 } 100 } else if params.IsCodeNotProvisioned(result.Error) || params.IsCodeNotFound(result.Error) { 101 // Either the volume (attachment) isn't provisioned, 102 // or the corresponding block device is not yet known. 103 // 104 // Neither of these errors is fatal; we just wait for 105 // the block device watcher to notify us again. 106 } else { 107 return errors.Annotatef( 108 err, "getting block device info for volume attachment %v", 109 ids[i], 110 ) 111 } 112 } 113 return nil 114 }