github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/cmd/vm-control/replaceVmImage.go (about)

     1  package main
     2  
     3  import (
     4  	"bufio"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"net"
     9  
    10  	"github.com/Cloud-Foundations/Dominator/lib/log"
    11  	"github.com/Cloud-Foundations/Dominator/lib/srpc"
    12  	proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor"
    13  )
    14  
    15  func replaceVmImageSubcommand(args []string, logger log.DebugLogger) error {
    16  	if err := replaceVmImage(args[0], logger); err != nil {
    17  		return fmt.Errorf("Error replacing VM image: %s", err)
    18  	}
    19  	return nil
    20  }
    21  
    22  func callReplaceVmImage(client *srpc.Client,
    23  	request proto.ReplaceVmImageRequest, reply *proto.ReplaceVmImageResponse,
    24  	imageReader io.Reader, logger log.DebugLogger) error {
    25  	conn, err := client.Call("Hypervisor.ReplaceVmImage")
    26  	if err != nil {
    27  		return err
    28  	}
    29  	defer conn.Close()
    30  	if err := conn.Encode(request); err != nil {
    31  		return err
    32  	}
    33  	// Stream any required data.
    34  	if imageReader != nil {
    35  		logger.Debugln(0, "uploading image")
    36  		if _, err := io.Copy(conn, imageReader); err != nil {
    37  			return err
    38  		}
    39  	}
    40  	if err := conn.Flush(); err != nil {
    41  		return err
    42  	}
    43  	for {
    44  		var response proto.ReplaceVmImageResponse
    45  		if err := conn.Decode(&response); err != nil {
    46  			return err
    47  		}
    48  		if response.Error != "" {
    49  			return errors.New(response.Error)
    50  		}
    51  		if response.ProgressMessage != "" {
    52  			logger.Debugln(0, response.ProgressMessage)
    53  		}
    54  		if response.Final {
    55  			*reply = response
    56  			return nil
    57  		}
    58  	}
    59  }
    60  
    61  func replaceVmImage(vmHostname string, logger log.DebugLogger) error {
    62  	if vmIP, hypervisor, err := lookupVmAndHypervisor(vmHostname); err != nil {
    63  		return err
    64  	} else {
    65  		return replaceVmImageOnHypervisor(hypervisor, vmIP, logger)
    66  	}
    67  }
    68  
    69  func replaceVmImageOnHypervisor(hypervisor string, ipAddr net.IP,
    70  	logger log.DebugLogger) error {
    71  	request := proto.ReplaceVmImageRequest{
    72  		DhcpTimeout:      *dhcpTimeout,
    73  		IpAddress:        ipAddr,
    74  		MinimumFreeBytes: uint64(minFreeBytes),
    75  		RoundupPower:     *roundupPower,
    76  	}
    77  	var imageReader io.Reader
    78  	if *imageName != "" {
    79  		request.ImageName = *imageName
    80  		request.ImageTimeout = *imageTimeout
    81  		request.SkipBootloader = *skipBootloader
    82  	} else if *imageURL != "" {
    83  		request.ImageURL = *imageURL
    84  	} else if *imageFile != "" {
    85  		file, size, err := getReader(*imageFile)
    86  		if err != nil {
    87  			return err
    88  		} else {
    89  			defer file.Close()
    90  			request.ImageDataSize = uint64(size)
    91  			imageReader = bufio.NewReader(io.LimitReader(file, size))
    92  		}
    93  	} else {
    94  		return errors.New("no image specified")
    95  	}
    96  	client, err := dialHypervisor(hypervisor)
    97  	if err != nil {
    98  		return err
    99  	}
   100  	defer client.Close()
   101  	var reply proto.ReplaceVmImageResponse
   102  	err = callReplaceVmImage(client, request, &reply, imageReader, logger)
   103  	if err != nil {
   104  		return err
   105  	}
   106  	return nil
   107  }