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  }