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  }