github.com/Cloud-Foundations/Dominator@v0.3.4/imageunpacker/unpacker/addDevice.go (about) 1 package unpacker 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "path/filepath" 8 "time" 9 10 "github.com/Cloud-Foundations/Dominator/lib/mbr" 11 "github.com/Cloud-Foundations/Dominator/lib/stringutil" 12 ) 13 14 var sysfsDirectory = "/sys/block" 15 16 func (u *Unpacker) addDevice(deviceId string) error { 17 u.updateUsageTime() 18 scannedDevices, err := scanDevices() 19 if err != nil { 20 return err 21 } 22 u.rwMutex.Lock() 23 defer u.rwMutex.Unlock() 24 defer u.updateUsageTimeWithLock() 25 for device := range u.scannedDevices { 26 delete(scannedDevices, device) 27 } 28 if len(scannedDevices) < 1 { 29 return errors.New("no new devices found") 30 } 31 if len(scannedDevices) > 1 { 32 return errors.New("too many new devices found") 33 } 34 var deviceName string 35 for d := range scannedDevices { 36 deviceName = d 37 } 38 return u.addSpecfiedDevice(deviceId, deviceName) 39 } 40 41 // This must be called with the lock held. 42 func (u *Unpacker) addSpecfiedDevice(deviceId, deviceName string) error { 43 device := deviceInfo{DeviceName: deviceName} 44 if err := updateDeviceSize(&device); err != nil { 45 return err 46 } 47 // Create a single partition. This is needed so that GRUB has a place to 48 // live (between the MBR and first/only partition). 49 devicePath := filepath.Join("/dev", deviceName) 50 u.logger.Printf("partitioning: %s\n", devicePath) 51 if err := mbr.WriteDefault(devicePath, mbr.TABLE_TYPE_MSDOS); err != nil { 52 return err 53 } 54 device.partitionTimestamp = time.Now() 55 u.pState.Devices[deviceId] = device 56 return u.writeStateWithLock() 57 } 58 59 func (u *Unpacker) prepareForAddDevice() error { 60 scannedDevices, err := scanDevices() 61 if err != nil { 62 return err 63 } 64 u.rwMutex.Lock() 65 defer u.rwMutex.Unlock() 66 u.scannedDevices = scannedDevices 67 return nil 68 } 69 70 func scanDevices() (map[string]struct{}, error) { 71 file, err := os.Open(sysfsDirectory) 72 if err != nil { 73 return nil, err 74 } 75 defer file.Close() 76 names, err := file.Readdirnames(-1) 77 if err != nil { 78 return nil, err 79 } 80 return stringutil.ConvertListToMap(names, true), nil 81 } 82 83 func updateDeviceSize(device *deviceInfo) error { 84 deviceBlocks, err := readSysfsUint64( 85 filepath.Join(sysfsDirectory, device.DeviceName, "size")) 86 if err != nil { 87 return err 88 } 89 device.size = deviceBlocks * 512 90 return nil 91 } 92 93 func readSysfsUint64(filename string) (uint64, error) { 94 file, err := os.Open(filename) 95 if err != nil { 96 return 0, err 97 } 98 defer file.Close() 99 var value uint64 100 nScanned, err := fmt.Fscanf(file, "%d", &value) 101 if err != nil { 102 return 0, err 103 } 104 if nScanned < 1 { 105 return 0, fmt.Errorf("only read %d values from: %s", nScanned, filename) 106 } 107 return value, nil 108 }