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