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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
|
package main
import (
"errors"
"fmt"
"net/http"
"os"
"time"
pb "go.wit.com/lib/protobuf/virtbuf"
"go.wit.com/lib/virtigolib"
"go.wit.com/log"
// "libvirt.org/go/libvirt"
"libvirt.org/go/libvirtxml"
)
// attempts to import the *libvirt.Domain directly from the hypervisor
func importDomain(w http.ResponseWriter, r *http.Request) (string, error) {
var result string
domainName := r.URL.Query().Get("domainName")
force := r.URL.Query().Get("force")
if domainName == "" {
result = "importDomain() failed. name is blank " + r.URL.Path
log.Warn(result)
fmt.Fprintln(w, result)
return "", errors.New(result)
}
// a LocalOnly record should already have been created by hypervisor.Poll()
d := me.cluster.FindDropletByName(domainName)
if d == nil {
result = "libvirt domain " + domainName + " could not be found on any hypervisor\n"
log.Info(result)
fmt.Fprintln(w, result)
return result, errors.New(result)
}
// if it's not local only, don't attempt this for now
if d.LocalOnly == "" {
if force == "true" {
result = "LocalOnly is blank. force=true. PROCEEDING WITH DANGER\n"
log.Warn(result)
fmt.Fprint(w, result)
} else {
result = "LocalOnly is blank. SKIP. merge not supported yet. force=" + force
log.Log(WARN, result)
fmt.Fprintln(w, result)
return result, errors.New(result)
}
}
/*
// it probably doesn't really matter what the state it
if d.Current.State != pb.DropletState_OFF {
result := "error: libvirt domain " + name + " is not off"
log.Info(result)
fmt.Fprintln(w, result)
return result, errors.New(result)
}
*/
// get the hypervisor record for what it's worth
h := findHypervisorByName(d.Current.Hypervisor)
if h == nil {
result = "unknown hypervisor = " + d.Current.Hypervisor
log.Log(WARN, result)
fmt.Fprintln(w, result)
return result, errors.New(result)
}
// exports and builds a libvirt.Domain from the hypervisor
domcfg, err := ExportLibvirtDomain(h.pb, domainName)
if err != nil {
result = fmt.Sprintf("ExportLibvirtDomain() failed", err)
log.Warn(result)
fmt.Fprintln(w, result)
return "", err
}
// merges and updates the droplet protobuf based on the libvirt XML
events, err := virtigolib.MergelibvirtDomain(d, domcfg)
if err != nil {
result = fmt.Sprintf("MerglibvirtDomain() failed for", d.Hostname, err)
log.Warn(result)
fmt.Fprintln(w, result)
return "", errors.New(result)
}
// check what was non-standard and make a note of it. Save it in the protobuf
s, err := virtigolib.DumpNonStandardXML(domcfg)
if err != nil {
result = s + "\n"
result = fmt.Sprintln("DumpNonStandardXML() on", domcfg.Name, "failed for", err)
log.Info(result)
return "", err
}
result += s
// everything worked. add the events
for _, e := range events {
me.cluster.AddEvent(e)
}
result += fmt.Sprintln("importDomain() worked")
// remote LocalOnly flag
d.LocalOnly = ""
// probably be safe and don't let this move around the cluster
d.PreferredHypervisor = d.Current.Hypervisor
log.Log(WARN, result)
fmt.Fprintln(w, result)
log.Warn("Everything worked. Saving config files")
if err := me.cluster.ConfigSave(); err != nil {
log.Warn("configsave error", err)
os.Exit(-1)
}
return result, nil
}
// this must be bool in string because accumulated output is sometimes
// written to STDOUT, sometimes to http
func (h *HyperT) importDomain(d *pb.Droplet) (bool, string) {
ready, result := me.cluster.DropletReady(d)
if !ready {
return false, result
}
url := "http://" + h.pb.Hostname + ":2520/import?domain=" + d.Hostname
var msg string
var data []byte
msg = d.FormatJSON()
data = []byte(msg) // Convert the string to []byte
req, err := httpPost(url, data)
if err != nil {
return false, fmt.Sprintln("error:", err)
}
log.Info("http post url:", url)
log.Info("http post data:", msg)
result = "EVENT import droplet url: " + url + "\n"
result += "EVENT import droplet response: " + string(req)
// increment the counter for a start attempt working
d.Current.StartAttempts += 1
// mark the cluster as unstable so droplet starts can be throttled
me.unstable = time.Now()
return true, result
}
func ExportLibvirtDomain(h *pb.Hypervisor, domainName string) (*libvirtxml.Domain, error) {
// attempt to get the domain record from virtigo
xml, err := postImportDomain(h.Hostname, domainName)
if err != nil {
log.Warn(err)
return nil, err
}
// convert the xml into a libvirt object
domcfg := &libvirtxml.Domain{}
err = domcfg.Unmarshal(string(xml))
if err != nil {
log.Warn("Unmarshal failed", domainName, err)
return nil, err
}
return domcfg, nil
}
func postImportDomain(hypervisor string, domain string) ([]byte, error) {
url := "http://" + hypervisor + ":2520/import?domain=" + domain
var msg string
var data []byte
msg = "import " + domain
data = []byte(msg) // Convert the string to []byte
req, err := httpPost(url, data)
if err != nil {
return nil, err
}
return req, nil
}
|