github.com/Cloud-Foundations/Dominator@v0.3.4/cmd/vm-control/debugVmImage.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "io" 6 "net" 7 "time" 8 9 "github.com/Cloud-Foundations/Dominator/lib/errors" 10 "github.com/Cloud-Foundations/Dominator/lib/format" 11 "github.com/Cloud-Foundations/Dominator/lib/log" 12 "github.com/Cloud-Foundations/Dominator/lib/srpc" 13 proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor" 14 ) 15 16 func debugVmImageSubcommand(args []string, logger log.DebugLogger) error { 17 if err := debugVmImage(args[0], logger); err != nil { 18 return fmt.Errorf("error starting VM with debug image: %s", err) 19 } 20 return nil 21 } 22 23 func debugVmImage(vmHostname string, logger log.DebugLogger) error { 24 if vmIP, hypervisor, err := lookupVmAndHypervisor(vmHostname); err != nil { 25 return err 26 } else { 27 return debugVmImageOnHypervisor(hypervisor, vmIP, logger) 28 } 29 } 30 31 func debugVmImageOnHypervisor(hypervisor string, ipAddr net.IP, 32 logger log.DebugLogger) error { 33 request := proto.DebugVmImageRequest{ 34 DhcpTimeout: *dhcpTimeout, 35 IpAddress: ipAddr, 36 MinimumFreeBytes: uint64(minFreeBytes), 37 RoundupPower: *roundupPower, 38 } 39 var imageReader io.Reader 40 if *imageName != "" { 41 request.ImageName = *imageName 42 request.ImageTimeout = *imageTimeout 43 if overlayFiles, err := loadOverlayFiles(); err != nil { 44 return err 45 } else { 46 request.OverlayFiles = overlayFiles 47 } 48 } else if *imageURL != "" { 49 request.ImageURL = *imageURL 50 } else if *imageFile != "" { 51 file, size, err := getReader(*imageFile) 52 if err != nil { 53 return err 54 } else { 55 defer file.Close() 56 request.ImageDataSize = uint64(size) 57 imageReader = file 58 } 59 } else { 60 return errors.New("no image specified") 61 } 62 client, err := dialHypervisor(hypervisor) 63 if err != nil { 64 return err 65 } 66 defer client.Close() 67 var reply proto.DebugVmImageResponse 68 err = callDebugVmImage(client, request, &reply, imageReader, 69 int64(request.ImageDataSize), logger) 70 if err != nil { 71 return err 72 } 73 if reply.DhcpTimedOut { 74 return errors.New("DHCP ACK timed out") 75 } 76 if *dhcpTimeout > 0 { 77 logger.Debugln(0, "Received DHCP ACK") 78 } 79 return maybeWatchVm(client, hypervisor, ipAddr, logger) 80 } 81 82 func callDebugVmImage(client *srpc.Client, 83 request proto.DebugVmImageRequest, 84 reply *proto.DebugVmImageResponse, imageReader io.Reader, 85 imageSize int64, logger log.DebugLogger) error { 86 conn, err := client.Call("Hypervisor.DebugVmImage") 87 if err != nil { 88 return fmt.Errorf("error calling Hypervisor.DebugVmImage: %s", err) 89 } 90 defer conn.Close() 91 if err := conn.Encode(request); err != nil { 92 return fmt.Errorf("error encoding request: %s", err) 93 } 94 // Stream any required data. 95 if imageReader != nil { 96 logger.Debugln(0, "uploading image") 97 startTime := time.Now() 98 if nCopied, err := io.CopyN(conn, imageReader, imageSize); err != nil { 99 return fmt.Errorf("error uploading image: %s got %d of %d bytes", 100 err, nCopied, imageSize) 101 } else { 102 duration := time.Since(startTime) 103 speed := uint64(float64(nCopied) / duration.Seconds()) 104 logger.Debugf(0, "uploaded image in %s (%s/s)\n", 105 format.Duration(duration), format.FormatBytes(speed)) 106 } 107 } 108 response, err := processDebugVmImageResponses(conn, logger) 109 *reply = response 110 return err 111 } 112 113 func processDebugVmImageResponses(conn *srpc.Conn, 114 logger log.DebugLogger) (proto.DebugVmImageResponse, error) { 115 var zeroResponse proto.DebugVmImageResponse 116 if err := conn.Flush(); err != nil { 117 return zeroResponse, fmt.Errorf("error flushing: %s", err) 118 } 119 for { 120 var response proto.DebugVmImageResponse 121 if err := conn.Decode(&response); err != nil { 122 return zeroResponse, fmt.Errorf("error decoding: %s", err) 123 } 124 if response.Error != "" { 125 return zeroResponse, errors.New(response.Error) 126 } 127 if response.ProgressMessage != "" { 128 logger.Debugln(0, response.ProgressMessage) 129 } 130 if response.Final { 131 return response, nil 132 } 133 } 134 }