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 }