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  }