github.com/Cloud-Foundations/Dominator@v0.3.4/imageunpacker/unpacker/streamManager.go (about) 1 package unpacker 2 3 import ( 4 "fmt" 5 "io" 6 "os/exec" 7 "path/filepath" 8 "strconv" 9 "strings" 10 11 "github.com/Cloud-Foundations/Dominator/lib/log/serverlogger" 12 "github.com/Cloud-Foundations/Dominator/lib/log/teelogger" 13 "github.com/Cloud-Foundations/Dominator/lib/logbuf" 14 "github.com/Cloud-Foundations/Dominator/lib/wsyscall" 15 proto "github.com/Cloud-Foundations/Dominator/proto/imageunpacker" 16 ) 17 18 // This must be called with the lock held. 19 func (u *Unpacker) setupStream(streamName string) (*imageStreamInfo, error) { 20 streamInfo := u.pState.ImageStreams[streamName] 21 if streamInfo == nil { 22 streamInfo = &imageStreamInfo{} 23 u.pState.ImageStreams[streamName] = streamInfo 24 if err := u.writeStateWithLock(); err != nil { 25 return nil, err 26 } 27 } 28 if streamInfo.streamLogger == nil { 29 options := logbuf.GetStandardOptions() 30 options.Directory = "" 31 options.HttpServeMux = nil 32 streamInfo.streamLogger = serverlogger.NewWithOptions(streamName, 33 options, serverlogger.GetStandardFlags()) 34 streamInfo.dualLogger = teelogger.New(u.logger, streamInfo.streamLogger) 35 } 36 if streamInfo.requestChannel == nil { 37 var rootLabel string 38 var err error 39 if streamInfo.DeviceId != "" { 40 rootLabel, err = u.getExt2fsLabel(streamInfo) 41 if err == nil && strings.HasPrefix(rootLabel, "rootfs@") { 42 streamInfo.status = proto.StatusStreamNotMounted 43 } else { 44 streamInfo.status = proto.StatusStreamNoFileSystem 45 rootLabel = "" 46 } 47 } 48 requestChannel := make(chan requestType) 49 streamInfo.requestChannel = requestChannel 50 go u.streamManager(streamName, streamInfo, rootLabel, requestChannel) 51 } 52 return streamInfo, nil 53 } 54 55 // This must be called with the lock held. 56 func (u *Unpacker) getExt2fsLabel(streamInfo *imageStreamInfo) (string, error) { 57 device := u.pState.Devices[streamInfo.DeviceId] 58 deviceNode := filepath.Join("/dev", device.DeviceName) 59 rootDevice, err := getPartition(deviceNode) 60 if err != nil { 61 return "", err 62 } 63 return getExt2fsLabel(rootDevice) 64 } 65 66 func (u *Unpacker) streamManager(streamName string, 67 streamInfo *imageStreamInfo, rootLabel string, 68 requestChannel <-chan requestType) { 69 if err := wsyscall.UnshareMountNamespace(); err != nil { 70 panic("Unable to unshare mount namespace: " + err.Error()) 71 } 72 stream := streamManagerState{ 73 unpacker: u, 74 streamName: streamName, 75 streamInfo: streamInfo, 76 rootLabel: rootLabel, 77 } 78 keepManaging := true 79 for keepManaging { 80 u.rwMutex.Lock() 81 streamInfo.scannedFS = stream.fileSystem 82 u.rwMutex.Unlock() 83 select { 84 case request := <-requestChannel: 85 var err error 86 switch request.request { 87 case requestAssociateWithDevice: 88 err = stream.associateWithDevice(request.deviceId) 89 case requestScan: 90 err = stream.scan(request.skipIfPrepared) 91 case requestUnpack: 92 err = stream.unpack(request.imageName, request.desiredFS) 93 case requestPrepareForCapture: 94 err = stream.prepareForCapture() 95 case requestPrepareForCopy: 96 err = stream.prepareForCopy() 97 case requestExport: 98 err = stream.export(request.exportType, 99 request.exportDestination) 100 case requestGetRaw: 101 err = stream.getRaw(request.readerChannel) 102 case requestForget: 103 err = stream.forget() 104 keepManaging = false 105 default: 106 panic("unknown request: " + strconv.Itoa(request.request)) 107 } 108 request.errorChannel <- err 109 if err != nil { 110 streamInfo.dualLogger.Println(err) 111 } 112 } 113 } 114 streamInfo.dualLogger.Printf("Unmanaged(%s)\n", streamName) 115 } 116 117 func (u *Unpacker) getStream(streamName string) *imageStreamInfo { 118 u.rwMutex.RLock() 119 defer u.rwMutex.RUnlock() 120 return u.pState.ImageStreams[streamName] 121 } 122 123 func getExt2fsLabel(device string) (string, error) { 124 cmd := exec.Command("e2label", device) 125 if output, err := cmd.CombinedOutput(); err != nil { 126 return "", fmt.Errorf("error getting label: %s: %s", err, output) 127 } else { 128 return strings.TrimSpace(string(output)), nil 129 } 130 } 131 132 func (u *Unpacker) writeStreamHtml(writer io.Writer, streamName string) { 133 streamInfo := u.getStream(streamName) 134 if streamInfo != nil { 135 streamInfo.streamLogger.WriteHtml(writer) 136 } 137 }