github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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 "gopkg.in/juju/names.v2" 9 10 "github.com/juju/juju/apiserver/params" 11 ) 12 13 // machineBlockDevicesChanged is called when the block devices of the scoped 14 // machine have been seen to have changed. This triggers a refresh of all 15 // block devices for attached volumes backing pending filesystems. 16 func machineBlockDevicesChanged(ctx *context) error { 17 volumeTags := make([]names.VolumeTag, 0, len(ctx.incompleteFilesystemParams)) 18 // We must query volumes for both incomplete filesystems 19 // and incomplete filesystem attachments, because even 20 // though a filesystem attachment cannot exist without a 21 // filesystem, the filesystem may be created and attached 22 // in different sessions, and there is no guarantee that 23 // the block device will remain attached to the machine 24 // in between. 25 for _, params := range ctx.incompleteFilesystemParams { 26 if params.Volume == (names.VolumeTag{}) { 27 // Filesystem is not volume-backed. 28 continue 29 } 30 if _, ok := ctx.volumeBlockDevices[params.Volume]; ok { 31 // Backing-volume's block device is already attached. 32 continue 33 } 34 volumeTags = append(volumeTags, params.Volume) 35 } 36 for _, params := range ctx.incompleteFilesystemAttachmentParams { 37 filesystem, ok := ctx.filesystems[params.Filesystem] 38 if !ok { 39 continue 40 } 41 if filesystem.Volume == (names.VolumeTag{}) { 42 // Filesystem is not volume-backed. 43 continue 44 } 45 if _, ok := ctx.volumeBlockDevices[filesystem.Volume]; ok { 46 // Backing-volume's block device is already attached. 47 continue 48 } 49 var found bool 50 for _, tag := range volumeTags { 51 if filesystem.Volume == tag { 52 found = true 53 break 54 } 55 } 56 if !found { 57 volumeTags = append(volumeTags, filesystem.Volume) 58 } 59 } 60 if len(volumeTags) == 0 { 61 return nil 62 } 63 return refreshVolumeBlockDevices(ctx, volumeTags) 64 } 65 66 // processPendingVolumeBlockDevices is called before waiting for any events, 67 // to force a block-device query for any volumes for which we have not 68 // previously observed block devices. 69 func processPendingVolumeBlockDevices(ctx *context) error { 70 if len(ctx.pendingVolumeBlockDevices) == 0 { 71 logger.Tracef("no pending volume block devices") 72 return nil 73 } 74 volumeTags := make([]names.VolumeTag, len(ctx.pendingVolumeBlockDevices)) 75 for i, tag := range ctx.pendingVolumeBlockDevices.SortedValues() { 76 volumeTags[i] = tag.(names.VolumeTag) 77 } 78 // Clear out the pending set, so we don't force-refresh again. 79 ctx.pendingVolumeBlockDevices = names.NewSet() 80 return refreshVolumeBlockDevices(ctx, volumeTags) 81 } 82 83 // refreshVolumeBlockDevices refreshes the block devices for the specified 84 // volumes. 85 func refreshVolumeBlockDevices(ctx *context, volumeTags []names.VolumeTag) error { 86 machineTag, ok := ctx.config.Scope.(names.MachineTag) 87 if !ok { 88 // This function should only be called by machine-scoped 89 // storage provisioners. 90 logger.Warningf("refresh block devices, expected machine tag, got %v", ctx.config.Scope) 91 return nil 92 } 93 ids := make([]params.MachineStorageId, len(volumeTags)) 94 for i, volumeTag := range volumeTags { 95 ids[i] = params.MachineStorageId{ 96 MachineTag: machineTag.String(), 97 AttachmentTag: volumeTag.String(), 98 } 99 } 100 results, err := ctx.config.Volumes.VolumeBlockDevices(ids) 101 if err != nil { 102 return errors.Annotate(err, "refreshing volume block devices") 103 } 104 for i, result := range results { 105 if result.Error == nil { 106 ctx.volumeBlockDevices[volumeTags[i]] = result.Result 107 for _, params := range ctx.incompleteFilesystemParams { 108 if params.Volume == volumeTags[i] { 109 updatePendingFilesystem(ctx, params) 110 } 111 } 112 for id, params := range ctx.incompleteFilesystemAttachmentParams { 113 filesystem, ok := ctx.filesystems[params.Filesystem] 114 if !ok { 115 continue 116 } 117 if filesystem.Volume == volumeTags[i] { 118 updatePendingFilesystemAttachment(ctx, id, params) 119 } 120 } 121 } else if params.IsCodeNotProvisioned(result.Error) || params.IsCodeNotFound(result.Error) { 122 // Either the volume (attachment) isn't provisioned, 123 // or the corresponding block device is not yet known. 124 // 125 // Neither of these errors is fatal; we just wait for 126 // the block device watcher to notify us again. 127 } else { 128 return errors.Annotatef( 129 err, "getting block device info for volume attachment %v", 130 ids[i], 131 ) 132 } 133 } 134 return nil 135 }