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