github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/imageunpacker/unpacker/streamManager.go (about) 1 package unpacker 2 3 import ( 4 "fmt" 5 "os/exec" 6 "path/filepath" 7 "strconv" 8 "strings" 9 10 "github.com/Cloud-Foundations/Dominator/lib/wsyscall" 11 proto "github.com/Cloud-Foundations/Dominator/proto/imageunpacker" 12 ) 13 14 // This must be called with the lock held. 15 func (u *Unpacker) setupStream(streamName string) (*imageStreamInfo, error) { 16 streamInfo := u.pState.ImageStreams[streamName] 17 if streamInfo == nil { 18 streamInfo = &imageStreamInfo{} 19 u.pState.ImageStreams[streamName] = streamInfo 20 if err := u.writeStateWithLock(); err != nil { 21 return nil, err 22 } 23 } 24 if streamInfo.requestChannel == nil { 25 var rootLabel string 26 var err error 27 if streamInfo.DeviceId != "" { 28 rootLabel, err = u.getExt2fsLabel(streamInfo) 29 if err == nil && strings.HasPrefix(rootLabel, "rootfs@") { 30 streamInfo.status = proto.StatusStreamNotMounted 31 } else { 32 streamInfo.status = proto.StatusStreamNoFileSystem 33 rootLabel = "" 34 } 35 } 36 requestChannel := make(chan requestType) 37 streamInfo.requestChannel = requestChannel 38 go u.streamManager(streamName, streamInfo, rootLabel, requestChannel) 39 } 40 return streamInfo, nil 41 } 42 43 // This must be called with the lock held. 44 func (u *Unpacker) getExt2fsLabel(streamInfo *imageStreamInfo) (string, error) { 45 device := u.pState.Devices[streamInfo.DeviceId] 46 deviceNode := filepath.Join("/dev", device.DeviceName) 47 rootDevice, err := getPartition(deviceNode) 48 if err != nil { 49 return "", err 50 } 51 return getExt2fsLabel(rootDevice) 52 } 53 54 func (u *Unpacker) streamManager(streamName string, 55 streamInfo *imageStreamInfo, rootLabel string, 56 requestChannel <-chan requestType) { 57 if err := wsyscall.UnshareMountNamespace(); err != nil { 58 panic("Unable to unshare mount namesace: " + err.Error()) 59 } 60 stream := streamManagerState{ 61 unpacker: u, 62 streamName: streamName, 63 streamInfo: streamInfo, 64 rootLabel: rootLabel, 65 } 66 for { 67 u.rwMutex.Lock() 68 streamInfo.scannedFS = stream.fileSystem 69 u.rwMutex.Unlock() 70 select { 71 case request := <-requestChannel: 72 var err error 73 switch request.request { 74 case requestAssociateWithDevice: 75 err = stream.associateWithDevice(request.deviceId) 76 case requestScan: 77 err = stream.scan(request.skipIfPrepared) 78 case requestUnpack: 79 err = stream.unpack(request.imageName, request.desiredFS) 80 case requestPrepareForCapture: 81 err = stream.prepareForCapture() 82 case requestPrepareForCopy: 83 err = stream.prepareForCopy() 84 case requestExport: 85 err = stream.export(request.exportType, 86 request.exportDestination) 87 default: 88 panic("unknown request: " + strconv.Itoa(request.request)) 89 } 90 request.errorChannel <- err 91 if err != nil { 92 u.logger.Println(err) 93 } 94 } 95 } 96 } 97 98 func (u *Unpacker) getStream(streamName string) *imageStreamInfo { 99 u.rwMutex.RLock() 100 defer u.rwMutex.RUnlock() 101 return u.pState.ImageStreams[streamName] 102 } 103 104 func getExt2fsLabel(device string) (string, error) { 105 cmd := exec.Command("e2label", device) 106 if output, err := cmd.CombinedOutput(); err != nil { 107 return "", fmt.Errorf("error getting label: %s: %s", err, output) 108 } else { 109 return strings.TrimSpace(string(output)), nil 110 } 111 }