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  }