github.com/Cloud-Foundations/Dominator@v0.3.4/imageunpacker/unpacker/exportImage.go (about)

     1  package unpacker
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	"os"
     7  	"os/exec"
     8  	"os/user"
     9  	"path"
    10  	"strconv"
    11  	"syscall"
    12  	"time"
    13  
    14  	"github.com/Cloud-Foundations/Dominator/lib/format"
    15  	proto "github.com/Cloud-Foundations/Dominator/proto/imageunpacker"
    16  )
    17  
    18  var (
    19  	exportImageTool = flag.String("exportImageTool",
    20  		"/usr/local/etc/export-image", "Name of tool to export image")
    21  	exportImageUsername = flag.String("exportImageUsername",
    22  		"nobody", "Username to run as for export tool")
    23  )
    24  
    25  func (u *Unpacker) exportImage(streamName string,
    26  	exportType string, exportDestination string) error {
    27  	u.rwMutex.Lock()
    28  	u.updateUsageTimeWithLock()
    29  	streamInfo, err := u.setupStream(streamName)
    30  	u.rwMutex.Unlock()
    31  	defer u.updateUsageTime()
    32  	if err != nil {
    33  		return err
    34  	}
    35  	errorChannel := make(chan error)
    36  	request := requestType{
    37  		request:           requestExport,
    38  		exportType:        exportType,
    39  		exportDestination: exportDestination,
    40  		errorChannel:      errorChannel,
    41  	}
    42  	streamInfo.requestChannel <- request
    43  	return <-errorChannel
    44  }
    45  
    46  func (stream *streamManagerState) export(exportType string,
    47  	exportDestination string) error {
    48  	userInfo, err := user.Lookup(*exportImageUsername)
    49  	if err != nil {
    50  		return err
    51  	}
    52  	groupIds, err := userInfo.GroupIds()
    53  	if err != nil {
    54  		return err
    55  	}
    56  	if err := stream.getDevice(); err != nil {
    57  		return err
    58  	}
    59  	stream.unpacker.rwMutex.RLock()
    60  	device := stream.unpacker.pState.Devices[stream.streamInfo.DeviceId]
    61  	stream.unpacker.rwMutex.RUnlock()
    62  	if err := stream.unmount(); err != nil {
    63  		return err
    64  	}
    65  	stream.streamInfo.status = proto.StatusStreamExporting
    66  	defer func() {
    67  		stream.streamInfo.status = proto.StatusStreamNotMounted
    68  	}()
    69  	deviceFile, err := os.Open(path.Join("/dev", device.DeviceName))
    70  	if err != nil {
    71  		stream.streamInfo.dualLogger.Println("Error exporting: %s", err)
    72  		return fmt.Errorf("error exporting: %s", err)
    73  	}
    74  	defer deviceFile.Close()
    75  	cmd := exec.Command(*exportImageTool, exportType, exportDestination)
    76  	cmd.Stdin = deviceFile
    77  	uid, err := strconv.ParseUint(userInfo.Uid, 10, 32)
    78  	if err != nil {
    79  		return err
    80  	}
    81  	gid, err := strconv.ParseUint(userInfo.Gid, 10, 32)
    82  	if err != nil {
    83  		return err
    84  	}
    85  	gids := make([]uint32, 0, len(groupIds))
    86  	for _, groupId := range groupIds {
    87  		gid, err := strconv.ParseUint(groupId, 10, 32)
    88  		if err != nil {
    89  			return err
    90  		}
    91  		gids = append(gids, uint32(gid))
    92  	}
    93  	creds := &syscall.Credential{
    94  		Uid:    uint32(uid),
    95  		Gid:    uint32(gid),
    96  		Groups: gids,
    97  	}
    98  	cmd.SysProcAttr = &syscall.SysProcAttr{Credential: creds}
    99  	startTime := time.Now()
   100  	output, err := cmd.CombinedOutput()
   101  	if err != nil {
   102  		stream.streamInfo.dualLogger.Printf("Error exporting: %s: %s\n",
   103  			err, string(output))
   104  		return fmt.Errorf("error exporting: %s: %s", err, output)
   105  	}
   106  	stream.streamInfo.dualLogger.Printf(
   107  		"Exported(%s) type: %s dest: %s in %s\n",
   108  		stream.streamName, exportType, exportDestination,
   109  		format.Duration(time.Since(startTime)))
   110  	return nil
   111  }