Skip to content

Commit

Permalink
Merge pull request kubevirt#520 from cynepco3hahue/update_spice_host_…
Browse files Browse the repository at this point in the history
…ip_after_migration

Update spice host address after migration
  • Loading branch information
rmohr authored Nov 3, 2017
2 parents f4bcab2 + 8340868 commit 52b6cc2
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 39 deletions.
3 changes: 0 additions & 3 deletions pkg/virt-controller/watch/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,11 +268,9 @@ func (md *MigrationController) execute(key string) error {
return nil
}

// FIXME, the final state updates must come from virt-handler
switch migrationPod.Status.Phase {
case k8sv1.PodFailed:
eventMsg := fmt.Sprintf("Failed migrating VM from %s to %s", vm.Status.NodeName, targetPod.Spec.NodeName)
vm.Status.Phase = kubev1.Running
vm.Status.MigrationNodeName = ""
if _, err = md.vmService.PutVm(vm); err != nil {
return err
Expand All @@ -283,7 +281,6 @@ func (md *MigrationController) execute(key string) error {
eventMsg := fmt.Sprintf("Finished migrating VM from %s to %s", vm.Status.NodeName, targetPod.Spec.NodeName)
vm.Status.NodeName = targetPod.Spec.NodeName
vm.Status.MigrationNodeName = ""
vm.Status.Phase = kubev1.Running
if vm.ObjectMeta.Labels == nil {
vm.ObjectMeta.Labels = map[string]string{}
}
Expand Down
117 changes: 81 additions & 36 deletions tests/spice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"net"
"strconv"
"strings"
"time"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
Expand All @@ -49,6 +50,51 @@ var _ = Describe("Vmlifecycle", func() {
tests.PanicOnError(err)
var vm *v1.VirtualMachine

getVmNode := func() string {
obj, err := virtClient.RestClient().Get().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Name(vm.GetObjectMeta().GetName()).Do().Get()
Expect(err).ToNot(HaveOccurred())
return obj.(*v1.VirtualMachine).Status.NodeName
}

checkSpiceConnection := func() {
raw, err := virtClient.RestClient().Get().Resource("virtualmachines").SetHeader("Accept", rest.MIME_INI).SubResource("spice").Namespace(tests.NamespaceTestDefault).Name(vm.GetObjectMeta().GetName()).Do().Raw()
Expect(err).To(BeNil())
spiceINI, err := ini.Load(raw)
Expect(err).NotTo(HaveOccurred())
spice := v1.SpiceInfo{}
Expect(spiceINI.Section("virt-viewer").MapTo(&spice)).To(Succeed())

proxy := strings.TrimPrefix(spice.Proxy, "http://")
host := fmt.Sprintf("%s:%d", spice.Host, spice.Port)

// Let's see if we can connect to the spice port through the proxy
conn, err := net.Dial("tcp", proxy)
Expect(err).To(BeNil())
conn.Write([]byte("CONNECT " + host + " HTTP/1.1\r\n"))
conn.Write([]byte("Host: " + host + "\r\n"))
conn.Write([]byte("\r\n"))
line, err := bufio.NewReader(conn).ReadString('\n')
Expect(err).To(BeNil())
Expect(strings.TrimSpace(line)).To(Equal("HTTP/1.1 200 Connection established"))

// Let's send a spice handshake
conn.Write(newSpiceHandshake())

// Let's parse the response
var i int32
x := make([]byte, 4, 4)
io.ReadFull(conn, x)
Expect(string(x)).To(Equal("REDQ")) // spice magic
binary.Read(conn, binary.LittleEndian, &i)
Expect(i).To(Equal(int32(2)), "Major version does not match.")
binary.Read(conn, binary.LittleEndian, &i)
Expect(i).To(Equal(int32(2)), "Minor version does not match.")
binary.Read(conn, binary.LittleEndian, &i)
Expect(i).To(BeNumerically(">", 4), "Message not long enough.")
binary.Read(conn, binary.LittleEndian, &i)
Expect(i).To(Equal(int32(0)), "Message status is not OK.") // 0 is equal to OK
}

BeforeEach(func() {
vm = tests.NewRandomVMWithSpice()
tests.BeforeTestCleanup()
Expand Down Expand Up @@ -111,42 +157,7 @@ var _ = Describe("Vmlifecycle", func() {
// Block until the VM is running
tests.WaitForSuccessfulVMStart(obj)

raw, err := virtClient.RestClient().Get().Resource("virtualmachines").SetHeader("Accept", rest.MIME_INI).SubResource("spice").Namespace(tests.NamespaceTestDefault).Name(vm.GetObjectMeta().GetName()).Do().Raw()
Expect(err).To(BeNil())
spiceINI, err := ini.Load(raw)
Expect(err).NotTo(HaveOccurred())
spice := v1.SpiceInfo{}
Expect(spiceINI.Section("virt-viewer").MapTo(&spice)).To(Succeed())

proxy := strings.TrimPrefix(spice.Proxy, "http://")
host := fmt.Sprintf("%s:%d", spice.Host, spice.Port)

// Let's see if we can connect to the spice port through the proxy
conn, err := net.Dial("tcp", proxy)
Expect(err).To(BeNil())
conn.Write([]byte("CONNECT " + host + " HTTP/1.1\r\n"))
conn.Write([]byte("Host: " + host + "\r\n"))
conn.Write([]byte("\r\n"))
line, err := bufio.NewReader(conn).ReadString('\n')
Expect(err).To(BeNil())
Expect(strings.TrimSpace(line)).To(Equal("HTTP/1.1 200 Connection established"))

// Let's send a spice handshake
conn.Write(newSpiceHandshake())

// Let's parse the response
var i int32
x := make([]byte, 4, 4)
io.ReadFull(conn, x)
Expect(string(x)).To(Equal("REDQ")) // spice magic
binary.Read(conn, binary.LittleEndian, &i)
Expect(i).To(Equal(int32(2)), "Major version does not match.")
binary.Read(conn, binary.LittleEndian, &i)
Expect(i).To(Equal(int32(2)), "Minor version does not match.")
binary.Read(conn, binary.LittleEndian, &i)
Expect(i).To(BeNumerically(">", 4), "Message not long enough.")
binary.Read(conn, binary.LittleEndian, &i)
Expect(i).To(Equal(int32(0)), "Message status is not OK.") // 0 is equal to OK
checkSpiceConnection()

close(done)
}, 30)
Expand Down Expand Up @@ -181,6 +192,40 @@ var _ = Describe("Vmlifecycle", func() {
}, 30)
})

Context("Migrate VM with spice connection", func() {

BeforeEach(func() {
if len(tests.GetReadyNodes()) < 2 {
Skip("To test migrations, at least two nodes need to be active")
}
// Create the VM
result := virtClient.RestClient().Post().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Body(vm).Do()
obj, err := result.Get()
Expect(err).To(BeNil())

// Block until the VM is running
tests.WaitForSuccessfulVMStart(obj)
})

It("should allow accessing the spice device on the VM", func() {
sourceNode := getVmNode()

migration := tests.NewRandomMigrationForVm(vm)
err = virtClient.RestClient().Post().Resource("migrations").Namespace(tests.NamespaceTestDefault).Body(migration).Do().Error()
Expect(err).ToNot(HaveOccurred())

Eventually(getVmNode, 30*time.Second, time.Second).ShouldNot(Equal(sourceNode))

Eventually(func() v1.VMPhase {
obj, err := virtClient.RestClient().Get().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Name(vm.GetObjectMeta().GetName()).Do().Get()
Expect(err).ToNot(HaveOccurred())
fetchedVM := obj.(*v1.VirtualMachine)
return fetchedVM.Status.Phase
}, 10*time.Second, time.Second).Should(Equal(v1.Running))

checkSpiceConnection()
})
})
})

func newSpiceHandshake() []byte {
Expand Down

0 comments on commit 52b6cc2

Please sign in to comment.