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  }