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  }