github.com/Cloud-Foundations/Dominator@v0.3.4/imageunpacker/unpacker/prepareForCapture.go (about)

     1  package unpacker
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"syscall"
     9  	"time"
    10  
    11  	"github.com/Cloud-Foundations/Dominator/lib/filesystem"
    12  	"github.com/Cloud-Foundations/Dominator/lib/filesystem/util"
    13  	"github.com/Cloud-Foundations/Dominator/lib/format"
    14  	proto "github.com/Cloud-Foundations/Dominator/proto/imageunpacker"
    15  )
    16  
    17  func scanBootDirectory(rootDir string) (*filesystem.FileSystem, error) {
    18  	file, err := os.Open(filepath.Join(rootDir, "boot"))
    19  	if err != nil {
    20  		return nil, err
    21  	}
    22  	defer file.Close()
    23  	names, err := file.Readdirnames(-1)
    24  	if err != nil {
    25  		return nil, err
    26  	}
    27  	bootInode := &filesystem.DirectoryInode{}
    28  	for _, name := range names {
    29  		bootInode.EntryList = append(bootInode.EntryList,
    30  			&filesystem.DirectoryEntry{Name: name})
    31  	}
    32  	bootEntry := &filesystem.DirectoryEntry{Name: "boot"}
    33  	bootEntry.SetInode(bootInode)
    34  	fs := &filesystem.FileSystem{
    35  		DirectoryInode: filesystem.DirectoryInode{
    36  			EntryList: []*filesystem.DirectoryEntry{bootEntry},
    37  		},
    38  	}
    39  	return fs, nil
    40  }
    41  
    42  func (u *Unpacker) prepareForCapture(streamName string) error {
    43  	u.updateUsageTime()
    44  	defer u.updateUsageTime()
    45  	streamInfo := u.getStream(streamName)
    46  	if streamInfo == nil {
    47  		return errors.New("unknown stream")
    48  	}
    49  	errorChannel := make(chan error)
    50  	request := requestType{
    51  		request:      requestPrepareForCapture,
    52  		errorChannel: errorChannel,
    53  	}
    54  	streamInfo.requestChannel <- request
    55  	return <-errorChannel
    56  }
    57  
    58  func (stream *streamManagerState) prepareForCapture() error {
    59  	if err := stream.getDevice(); err != nil {
    60  		return err
    61  	}
    62  	mountPoint := filepath.Join(stream.unpacker.baseDir, "mnt")
    63  	if err := stream.mount(mountPoint); err != nil {
    64  		return err
    65  	}
    66  	streamInfo := stream.streamInfo
    67  	switch streamInfo.status {
    68  	case proto.StatusStreamNoDevice:
    69  		return errors.New("no device")
    70  	case proto.StatusStreamNotMounted:
    71  		return errors.New("not mounted")
    72  	case proto.StatusStreamMounted:
    73  		// Start preparing.
    74  	case proto.StatusStreamScanning:
    75  		return errors.New("stream scan in progress")
    76  	case proto.StatusStreamScanned:
    77  		return errors.New("stream not idle")
    78  	case proto.StatusStreamFetching:
    79  		return errors.New("fetch in progress")
    80  	case proto.StatusStreamUpdating:
    81  		return errors.New("update in progress")
    82  	case proto.StatusStreamPreparing:
    83  		return errors.New("already preparing to capture")
    84  	default:
    85  		panic("invalid status")
    86  	}
    87  	streamInfo.status = proto.StatusStreamPreparing
    88  	startTime := time.Now()
    89  	err := stream.capture()
    90  	if err != nil {
    91  		stream.streamInfo.status = proto.StatusStreamMounted
    92  		return err
    93  	}
    94  	stream.streamInfo.status = proto.StatusStreamNotMounted
    95  	streamInfo.dualLogger.Printf("Prepared for capture(%s) in %s\n",
    96  		stream.streamName, format.Duration(time.Since(startTime)))
    97  	return nil
    98  }
    99  
   100  func (stream *streamManagerState) capture() error {
   101  	stream.unpacker.rwMutex.RLock()
   102  	device := stream.unpacker.pState.Devices[stream.streamInfo.DeviceId]
   103  	stream.unpacker.rwMutex.RUnlock()
   104  	deviceNode := filepath.Join("/dev", device.DeviceName)
   105  	logger := stream.streamInfo.dualLogger
   106  	logger.Printf("Preparing for capture(%s) on %s with label: %s\n",
   107  		stream.streamName, deviceNode, stream.rootLabel)
   108  	// First clean out debris.
   109  	mountPoint := filepath.Join(stream.unpacker.baseDir, "mnt")
   110  	subdDir := filepath.Join(mountPoint, ".subd")
   111  	if err := os.RemoveAll(subdDir); err != nil {
   112  		return err
   113  	}
   114  	fs, err := scanBootDirectory(mountPoint)
   115  	if err != nil {
   116  		logger.Printf("Error scanning boot directory: %s\n", err)
   117  		return fmt.Errorf("error getting scanning boot directory: %s", err)
   118  	}
   119  	err = util.MakeBootable(fs, deviceNode, stream.rootLabel, mountPoint,
   120  		"net.ifnames=0", false, logger)
   121  	if err != nil {
   122  		logger.Printf("Error preparing: %s", err)
   123  		return fmt.Errorf("error preparing: %s", err)
   124  	}
   125  	if err := syscall.Unmount(mountPoint, 0); err != nil {
   126  		return err
   127  	}
   128  	syscall.Sync()
   129  	return nil
   130  }