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 }