github.com/Cloud-Foundations/Dominator@v0.3.4/cmd/vm-control/copyVm.go (about)

     1  package main
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  
     8  	hyperclient "github.com/Cloud-Foundations/Dominator/hypervisor/client"
     9  	"github.com/Cloud-Foundations/Dominator/lib/log"
    10  	"github.com/Cloud-Foundations/Dominator/lib/srpc"
    11  	hyper_proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor"
    12  )
    13  
    14  func copyVmSubcommand(args []string, logger log.DebugLogger) error {
    15  	if err := copyVm(args[0], logger); err != nil {
    16  		return fmt.Errorf("error copying VM: %s", err)
    17  	}
    18  	return nil
    19  }
    20  
    21  func copyVm(vmHostname string, logger log.DebugLogger) error {
    22  	if vmIP, hypervisor, err := searchVmAndHypervisor(vmHostname); err != nil {
    23  		return err
    24  	} else {
    25  		return copyVmFromHypervisor(hypervisor, vmIP, logger)
    26  	}
    27  }
    28  
    29  func callCopyVm(client *srpc.Client, request hyper_proto.CopyVmRequest,
    30  	reply *hyper_proto.CopyVmResponse, logger log.DebugLogger) error {
    31  	conn, err := client.Call("Hypervisor.CopyVm")
    32  	if err != nil {
    33  		return fmt.Errorf("error calling Hypervisor.CopyVm: %s", err)
    34  	}
    35  	defer conn.Close()
    36  	if err := conn.Encode(request); err != nil {
    37  		return fmt.Errorf("error encoding CopyVm request: %s", err)
    38  	}
    39  	if err := conn.Flush(); err != nil {
    40  		return fmt.Errorf("error flushing CopyVm request: %s", err)
    41  	}
    42  	for {
    43  		var response hyper_proto.CopyVmResponse
    44  		if err := conn.Decode(&response); err != nil {
    45  			return fmt.Errorf("error decoding CopyVm response: %s", err)
    46  		}
    47  		if response.Error != "" {
    48  			return errors.New(response.Error)
    49  		}
    50  		if response.ProgressMessage != "" {
    51  			logger.Debugln(0, response.ProgressMessage)
    52  		}
    53  		if response.Final {
    54  			*reply = response
    55  			return nil
    56  		}
    57  	}
    58  }
    59  
    60  func copyVmFromHypervisor(sourceHypervisorAddress string, vmIP net.IP,
    61  	logger log.DebugLogger) error {
    62  	sourceHypervisor, err := dialHypervisor(sourceHypervisorAddress)
    63  	if err != nil {
    64  		return err
    65  	}
    66  	defer sourceHypervisor.Close()
    67  	sourceVmInfo, err := hyperclient.GetVmInfo(sourceHypervisor, vmIP)
    68  	if err != nil {
    69  		return err
    70  	}
    71  	vmInfo := createVmInfoFromFlags()
    72  	vmInfo.ConsoleType = sourceVmInfo.ConsoleType
    73  	vmInfo.DestroyProtection = vmInfo.DestroyProtection ||
    74  		sourceVmInfo.DestroyProtection
    75  	if vmInfo.Hostname == "" {
    76  		vmInfo.Hostname = sourceVmInfo.Hostname
    77  	}
    78  	if vmInfo.MemoryInMiB < 1 {
    79  		vmInfo.MemoryInMiB = sourceVmInfo.MemoryInMiB
    80  	}
    81  	if vmInfo.MilliCPUs < 1 {
    82  		vmInfo.MilliCPUs = sourceVmInfo.MilliCPUs
    83  	}
    84  	if len(vmInfo.OwnerGroups) < 1 {
    85  		vmInfo.OwnerGroups = sourceVmInfo.OwnerGroups
    86  	}
    87  	if len(vmInfo.OwnerUsers) < 1 {
    88  		vmInfo.OwnerUsers = sourceVmInfo.OwnerUsers
    89  	}
    90  	if len(vmInfo.Tags) < 1 {
    91  		vmInfo.Tags = sourceVmInfo.Tags
    92  	}
    93  	if len(vmInfo.SecondarySubnetIDs) < 1 {
    94  		vmInfo.SecondarySubnetIDs = sourceVmInfo.SecondarySubnetIDs
    95  	}
    96  	if vmInfo.SubnetId == "" {
    97  		vmInfo.SubnetId = sourceVmInfo.SubnetId
    98  	}
    99  	accessToken, err := getVmAccessTokenClient(sourceHypervisor, vmIP)
   100  	if err != nil {
   101  		return err
   102  	}
   103  	defer discardAccessToken(sourceHypervisor, vmIP)
   104  	destHypervisorAddress, err := getHypervisorAddress(vmInfo)
   105  	if err != nil {
   106  		return err
   107  	}
   108  	destHypervisor, err := dialHypervisor(destHypervisorAddress)
   109  	if err != nil {
   110  		return err
   111  	}
   112  	defer destHypervisor.Close()
   113  	request := hyper_proto.CopyVmRequest{
   114  		AccessToken:      accessToken,
   115  		IpAddress:        vmIP,
   116  		SkipMemoryCheck:  *skipMemoryCheck,
   117  		SourceHypervisor: sourceHypervisorAddress,
   118  		VmInfo:           vmInfo,
   119  	}
   120  	var reply hyper_proto.CopyVmResponse
   121  	logger.Debugf(0, "copying VM to %s\n", destHypervisorAddress)
   122  	if err := callCopyVm(destHypervisor, request, &reply, logger); err != nil {
   123  		return err
   124  	}
   125  	err = hyperclient.AcknowledgeVm(destHypervisor, reply.IpAddress)
   126  	if err != nil {
   127  		return fmt.Errorf("error acknowledging VM: %s", err)
   128  	}
   129  	fmt.Println(reply.IpAddress)
   130  	return nil
   131  }