github.com/Cloud-Foundations/Dominator@v0.3.4/imageunpacker/unpacker/associateWithDevice.go (about) 1 package unpacker 2 3 import ( 4 "errors" 5 "os" 6 "path/filepath" 7 "syscall" 8 9 proto "github.com/Cloud-Foundations/Dominator/proto/imageunpacker" 10 ) 11 12 func (u *Unpacker) associateStreamWithDevice(streamName string, 13 deviceId string) error { 14 defer u.updateUsageTime() 15 u.rwMutex.Lock() 16 u.updateUsageTimeWithLock() 17 streamInfo, err := u.setupStream(streamName) 18 u.rwMutex.Unlock() 19 if err != nil { 20 return err 21 } 22 errorChannel := make(chan error) 23 request := requestType{ 24 request: requestAssociateWithDevice, 25 deviceId: deviceId, 26 errorChannel: errorChannel, 27 } 28 streamInfo.requestChannel <- request 29 return <-errorChannel 30 } 31 32 func (stream *streamManagerState) associateWithDevice(deviceId string) error { 33 streamInfo := stream.streamInfo 34 switch streamInfo.status { 35 case proto.StatusStreamNoDevice: 36 // OK to associate. 37 case proto.StatusStreamNotMounted: 38 // OK to (re)associate. 39 case proto.StatusStreamMounted: 40 // OK to (re)associate. 41 case proto.StatusStreamScanning: 42 return errors.New("stream scan in progress") 43 case proto.StatusStreamScanned: 44 // OK to (re)associate. 45 case proto.StatusStreamFetching: 46 return errors.New("fetch in progress") 47 case proto.StatusStreamUpdating: 48 return errors.New("update in progress") 49 case proto.StatusStreamPreparing: 50 return errors.New("preparing to capture") 51 case proto.StatusStreamNoFileSystem: 52 // OK to (re)associate. 53 default: 54 panic("invalid status") 55 } 56 return stream.selectDevice(deviceId) 57 } 58 59 func (stream *streamManagerState) selectDevice(deviceId string) error { 60 streamInfo := stream.streamInfo 61 u := stream.unpacker 62 u.rwMutex.Lock() 63 defer u.rwMutex.Unlock() 64 if streamInfo.DeviceId == deviceId { 65 return nil 66 } 67 switch streamInfo.status { 68 case proto.StatusStreamNoDevice: 69 // Nothing to unmount. 70 case proto.StatusStreamNotMounted: 71 // Not mounted. 72 case proto.StatusStreamNoFileSystem: 73 // Nothing to unmount. 74 default: 75 // Mounted: unmount it. 76 mountPoint := filepath.Join(stream.unpacker.baseDir, "mnt") 77 if err := syscall.Unmount(mountPoint, 0); err != nil { 78 return err 79 } 80 streamInfo.status = proto.StatusStreamNotMounted 81 } 82 if deviceId == "" { 83 return stream.getDeviceWithLock() 84 } 85 if device, ok := u.pState.Devices[deviceId]; !ok { 86 return errors.New("unknown device ID: " + deviceId) 87 } else { 88 if device.StreamName != "" { 89 return errors.New( 90 "device ID: " + deviceId + " used by: " + device.StreamName) 91 } 92 if streamInfo.DeviceId != "" { // Disassociate with existing device. 93 if device, ok := u.pState.Devices[streamInfo.DeviceId]; ok { 94 device.eraseFileSystem() 95 device.StreamName = "" 96 u.pState.Devices[streamInfo.DeviceId] = device 97 } 98 } 99 device.StreamName = stream.streamName 100 u.pState.Devices[deviceId] = device 101 streamInfo.DeviceId = deviceId 102 streamInfo.status = proto.StatusStreamNoFileSystem 103 stream.rootLabel = "" 104 return u.writeStateWithLock() 105 } 106 } 107 108 func (device deviceInfo) eraseFileSystem() { 109 rootDevice, err := getPartition(filepath.Join("/dev", device.DeviceName)) 110 if err != nil { 111 return 112 } 113 if file, err := os.OpenFile(rootDevice, os.O_WRONLY, 0); err != nil { 114 return 115 } else { 116 defer file.Close() 117 file.Write(make([]byte, 65536)) 118 } 119 }