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 }