func readLibvirtVM(HostIpAddress string, UUIDString string) (VirtualMachine, error) { var conn libvirt.VirConnection var err error ok := ipaddressConnectionCache.Check(HostIpAddress) if ok == false { conn, err = libvirt.NewVirConnection("qemu+ssh://root@" + HostIpAddress + "/system") if err != nil { return VirtualMachine{}, err } ipaddressConnectionCache.Set(HostIpAddress, conn) } else { //?How to deal with connection's not alive conn = ipaddressConnectionCache.Get(HostIpAddress).(libvirt.VirConnection) if ok, _ := conn.IsAlive(); !ok { log.Printf("remote %s is not alive", HostIpAddress) conn, err = libvirt.NewVirConnection("qemu+ssh://root@" + HostIpAddress + "/system") if err != nil { ipaddressConnectionCache.Delete(HostIpAddress) return VirtualMachine{}, err } /*TODO Write Lock*/ ipaddressConnectionCache.Set(HostIpAddress, conn) } } domain, err := conn.LookupByUUIDString(UUIDString) if err != nil { return VirtualMachine{}, err } vm := fillVmData(domain, conn) return vm, nil }
func registerRebootAndGetVncPort(name string, ip string, conn libvirt.VirConnection) string { var domain libvirt.VirDomain domain, err := conn.LookupByName(name) if err != nil { log.Println("FAIL: find running domain to start vncviewer") return "" } defer domain.Free() xmlData, _ := domain.GetXMLDesc() v := utils.ParseDomainXML(xmlData) /* to get VNC port */ var vncPort string if v.Devices.Graphics.VNCPort == "-1" { log.Println("FAIL:Can not get vnc port") return "" } vncPort = v.Devices.Graphics.VNCPort ret := libvirt.ConnectDomainEventRegister(conn, domain, libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, libvirt.LifeCycleCallBackType(myrebootcallback)) if ret == -1 { fmt.Println("can not autoreboot") } else { callbackMap.Set(name, ret) } vncAddress := ip + ":" + vncPort //e.g. http://147.2.207.233/vnc_auto.html?title=lwang-n1-sle12rc1&path=websockify?ip=147.2.207.233:5902 log.Println(fmt.Sprintf("/vnc_auto.html?title=%s&path=websockify?ip=%s", name, vncAddress)) return fmt.Sprintf("/vnc_auto.html?title=%s&path=websockify?ip=%s", name, vncAddress) }
func startVNCviewer(conn libvirt.VirConnection, name string, hostIPAddress string) { fmt.Println("would bring up vncviewer...") var domain libvirt.VirDomain domain, err := conn.LookupByName(name) if err != nil { fmt.Println("FAIL: find running domain to start vncviewer") return } defer domain.Free() xmlData, _ := domain.GetXMLDesc() v := utils.ParseDomainXML(xmlData) /* to get VNC port */ var vncPort string if v.Devices.Graphics.VNCPort == "-1" { fmt.Println("FAIL:Can not get vnc port") return } vncPort = v.Devices.Graphics.VNCPort ret := libvirt.ConnectDomainEventRegister(conn, domain, libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, libvirt.LifeCycleCallBackType(myrebootcallback)) if ret == -1 { fmt.Println("can not autoreboot") return } fmt.Println("RUNNING: vncviewer " + hostIPAddress + ":" + vncPort) cmd := exec.Command("vncviewer", hostIPAddress+":"+vncPort) //Run will block err = cmd.Run() if err != nil { fmt.Println("FAIL:can not start vncviewer") fmt.Println(err) return } fmt.Println("vncviewer is quiting") time.Sleep(3 * time.Second) //re run vncviewer cmd.Run() }
func createRemoteBootPool(conn libvirt.VirConnection) (libvirt.VirStoragePool, error) { // Test volume pool // create vol from pool and Upload var pool libvirt.VirStoragePool pool, err := conn.StoragePoolLookupByName("boot-scratch") if err != nil { // pool not existed // create on pool named "boot-scrath" // TODO log.Println("pool not exist") //poolXML, _:= ioutil.ReadFile("./pool.xml") poolXML := POOXML pool, err = conn.StoragePoolDefineXML(string(poolXML)) if err != nil { return libvirt.VirStoragePool{}, err } } return pool, nil }
func VmInstall(conn libvirt.VirConnection, vmname string, url string, autoyast string, imageSize uint64, ch chan string) { //check input if len(vmname) <= 0 { reportFail(ch, "Name too short") return } if imageSize == 0 { reportFail(ch, "disk size too short") } //sender close the channel if ch != nil { defer close(ch) } pool, err := createRemoteBootPool(conn) defer pool.Free() //url := "http://mirror.bej.suse.com/dist/install/SLP/SLE-12-Server-Beta10/x86_64/DVD1" linuxSurfix := "/boot/x86_64/loader/linux" initrdSurfix := "/boot/x86_64/loader/initrd" // Download linux and initrd image from remote reportStatus(ch, "Downloading linux image") m := DownloadManager{} m.Regsiter(HTTPDownloader{}) linuxContent, err := m.Download(url + linuxSurfix) if err != nil { reportFail(ch, err.Error()) return } reportStatus(ch, "Downloading initrd image") initrdContent, err := m.Download(url + initrdSurfix) if err != nil { reportFail(ch, err.Error()) return } //prepare two temporary name for linux;initrd image temp := generateFourRandom() bootImageName := vmname + temp + ".image" bootInitrdName := vmname + temp + ".initrd" // create remote boot linux storage from temp pool linuxVolume, err := createVolume(pool, Storage{Name: bootImageName, Size: uint64(len(linuxContent)), Type: "raw"}) if err != nil { reportFail(ch, err.Error()) return } defer linuxVolume.Free() defer linuxVolume.Delete() linuxPath, _ := linuxVolume.GetPath() // create remote boot initrd storage from temp pool initrdVolume, err := createVolume(pool, Storage{Name: bootInitrdName, Size: uint64(len(initrdContent)), Type: "raw"}) if err != nil { reportFail(ch, err.Error()) return } defer initrdVolume.Free() defer initrdVolume.Delete() initrdPath, _ := initrdVolume.GetPath() var stream libvirt.VirStream stream, err = conn.StreamNew() if err != nil { reportFail(ch, err.Error()) return } defer stream.Free() //Upload to remote reportStatus(ch, "sending linuxVolume") if err := SendLocalToRemote(stream, linuxVolume, linuxContent); err != nil { reportFail(ch, err.Error()) return } reportStatus(ch, "sending initrd") if err := SendLocalToRemote(stream, initrdVolume, initrdContent); err != nil { reportFail(ch, err.Error()) return } // create image reportStatus(ch, "creating remote imaging...") dataPool, err := conn.StoragePoolLookupByName("default") if err != nil { reportFail(ch, err.Error()) return } defer dataPool.Free() //var imageSize uint64 = 8589934592 //8G realImageName := vmname + ".img" imageVolume, err := createVolume(dataPool, Storage{Name: realImageName, Size: imageSize, Type: "qcow2"}) if err != nil { reportFail(ch, err.Error()) return } defer imageVolume.Free() imagePath, _ := imageVolume.GetPath() log.Println("Create remote VirtualMachine") reportStatus(ch, "Create remote VirtualMachine") // create boot xml var xml string // add autoyast var installArg string if len(autoyast) > 0 { installArg = url + " autoyast=" + autoyast } else { installArg = url } domain := Domain{Name: vmname, Kernel: linuxPath, Initrd: initrdPath, Image: imagePath, Install: installArg} if xml, err = domain.Encode(); err != nil { reportFail(ch, err.Error()) return } // create booting vm bootingDomain, err := conn.CreateXML(xml) if err != nil { reportFail(ch, err.Error()) return } defer bootingDomain.Free() // get xml from remote // create new defined xml if xml, err = bootingDomain.GetXMLDesc(); err != nil { reportFail(ch, err.Error()) return } /* change xml a bit using regex lines, I do not want to parse the xml file * 1. change os section to boot from hd * 2. change destory section */ /* (?s) is used to let . match newline(\n) */ osSection := regexp.MustCompile("(?s)<os>.*</os>") onBoot := regexp.MustCompile("(?s)<on_reboot>.*</on_reboot>") onCrash := regexp.MustCompile("(?s)<on_crash>.*</on_crash>") xml = osSection.ReplaceAllString(xml, OSSECTION) xml = onBoot.ReplaceAllString(xml, ONBOOT) xml = onCrash.ReplaceAllString(xml, ONCRASH) newPersistentDomain, err := conn.DefineXML(xml) if err != nil { reportFail(ch, err.Error()) return } log.Println(newPersistentDomain) defer newPersistentDomain.Free() reportSuccess(ch) }
func readLibvirtPysicalMachine(hosts []*PhysicalMachine) { /* get libvirt connections */ numLiveHost := 0 var conn libvirt.VirConnection /* use this type in chanStruct */ type connResult struct { host *PhysicalMachine conn libvirt.VirConnection existing bool } connChan := make(chan connResult) var numGoroutines = 0 for _, host := range hosts { ok := ipaddressConnectionCache.Check(host.IpAddress) if ok == false { numGoroutines++ go func(host *PhysicalMachine) { conn, err := libvirt.NewVirConnection("qemu+ssh://root@" + host.IpAddress + "/system") if err != nil { checkErr(err, fmt.Sprintf("failed to connect to %s", host.IpAddress)) host.Existing = false connChan <- connResult{host: host, existing: false} return } connChan <- connResult{host: host, conn: conn, existing: true} }(host) } else { /* existing a conn which is alive */ conn = ipaddressConnectionCache.Get(host.IpAddress).(libvirt.VirConnection) if ok, _ := conn.IsAlive(); ok { host.VirConn = conn host.Existing = true numLiveHost++ /* existing a conn which is dead */ } else { log.Printf("remove %s is not alive", host.IpAddress) host.Existing = false ipaddressConnectionCache.Delete(host.IpAddress) /* TODO ?if close the connectin */ conn.CloseConnection() } } } for i := 0; i < numGoroutines; i++ { r := <-connChan if r.existing { r.host.VirConn = r.conn r.host.Existing = true /*Write Lock*/ ipaddressConnectionCache.Set(r.host.IpAddress, r.conn) numLiveHost++ } } /* all the PhysicalMachines are ready, VirConnection was connected now */ /* receive data from VirConnections */ done := make(chan bool) for _, host := range hosts { if host.Existing == false { continue } go func(host *PhysicalMachine) { domains, _ := host.VirConn.ListAllDomains() for _, virdomain := range domains { vm := fillVmData(virdomain, conn) vm.HostIpAddress = host.IpAddress if vm.Active == true { vm.VNCAddress = host.IpAddress } //will not have any operations on vm, virdomain could be freeed virdomain.Free() host.VirtualMachines = append(host.VirtualMachines, &vm) } done <- true }(host) } /* wait for all ListAllDomains finish */ for i := 0; i < numLiveHost; i++ { <-done } }