Skip to content

Commit

Permalink
Added paused checks to console, vnc and migrate; added more functests
Browse files Browse the repository at this point in the history
Signed-off-by: Marc Sluiter <[email protected]>
  • Loading branch information
slintes committed Nov 5, 2019
1 parent f8fb98f commit bad7772
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 34 deletions.
1 change: 1 addition & 0 deletions pkg/virt-api/rest/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ go_library(
"//vendor/github.com/emicklei/go-restful:go_default_library",
"//vendor/github.com/golang/mock/gomock:go_default_library",
"//vendor/k8s.io/api/authorization/v1beta1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
Expand Down
21 changes: 18 additions & 3 deletions pkg/virt-api/rest/subresource.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ import (
"strings"
"sync"

"kubevirt.io/kubevirt/pkg/controller"

"github.com/emicklei/go-restful"

v12 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
k8smetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
Expand All @@ -43,6 +43,7 @@ import (
"kubevirt.io/client-go/kubecli"
"kubevirt.io/client-go/log"
clientutil "kubevirt.io/client-go/util"
"kubevirt.io/kubevirt/pkg/controller"
)

type SubresourceAPIApp struct {
Expand Down Expand Up @@ -272,6 +273,10 @@ func (app *SubresourceAPIApp) VNCRequestHandler(request *restful.Request, respon
log.Log.Object(vmi).Reason(err).Error("Can't establish VNC connection.")
return err, http.StatusBadRequest
}
condManager := controller.NewVirtualMachineInstanceConditionManager()
if condManager.HasCondition(vmi, v1.VirtualMachineInstancePaused) {
return fmt.Errorf("VMI is paused"), http.StatusForbidden
}
return nil, 0
}
getConsoleURL := func(vmi *v1.VirtualMachineInstance, conn kubecli.VirtHandlerConn) (string, error) {
Expand All @@ -289,7 +294,10 @@ func (app *SubresourceAPIApp) getVirtHandlerConnForVMI(vmi *v1.VirtualMachineIns

func (app *SubresourceAPIApp) ConsoleRequestHandler(request *restful.Request, response *restful.Response) {
validate := func(vmi *v1.VirtualMachineInstance) (error, int) {
// always valid
condManager := controller.NewVirtualMachineInstanceConditionManager()
if condManager.HasCondition(vmi, v1.VirtualMachineInstancePaused) {
return fmt.Errorf("VMI is paused"), http.StatusForbidden
}
return nil, 0
}
getConsoleURL := func(vmi *v1.VirtualMachineInstance, conn kubecli.VirtHandlerConn) (string, error) {
Expand Down Expand Up @@ -376,6 +384,13 @@ func (app *SubresourceAPIApp) MigrateVMRequestHandler(request *restful.Request,
return
}

for _, c := range vm.Status.Conditions {
if c.Type == v1.VirtualMachinePaused && c.Status == v12.ConditionTrue {
response.WriteError(http.StatusForbidden, fmt.Errorf("VM is paused"))
return
}
}

createMigrationJob := func() error {
_, err := app.virtCli.VirtualMachineInstanceMigration(namespace).Create(&v1.VirtualMachineInstanceMigration{
ObjectMeta: k8smetav1.ObjectMeta{
Expand Down
198 changes: 177 additions & 21 deletions tests/pausing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,18 @@
package tests_test

import (
"fmt"
"strings"
"time"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

expect "github.com/google/goexpect"

k8sv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource"
v12 "k8s.io/apimachinery/pkg/apis/meta/v1"

v1 "kubevirt.io/client-go/api/v1"
Expand Down Expand Up @@ -167,59 +173,209 @@ var _ = Describe("[rfe_id:3064][crit:medium][vendor:[email protected]][level:com
err := command()
Expect(err.Error()).To(ContainSubstring("VMI is not paused"))
})
})

When("paused via virtctl", func() {
It("[test_id:3085]should be stopped successfully", func() {

runVM()

By("pausing the VM")
By("Pausing the VM")
command := tests.NewRepeatableVirtctlCommand("pause", "vm", "--namespace", tests.NamespaceTestDefault, vm.Name)
Expect(command()).To(Succeed())
tests.WaitForVMCondition(virtClient, vm, v1.VirtualMachinePaused, 30)

By("stopping the VM")
By("Stopping the VM")
command = tests.NewRepeatableVirtctlCommand("stop", "--namespace", tests.NamespaceTestDefault, vm.Name)
Expect(command()).To(Succeed())
tests.WaitForVMCondition(virtClient, vm, v1.VirtualMachinePaused, 30)

By("checking deletion of VMI")
By("Checking deletion of VMI")
Eventually(func() bool {
_, err = virtClient.VirtualMachineInstance(vm.Namespace).Get(vm.Name, &v12.GetOptions{})
if errors.IsNotFound(err) {
return true
}
Expect(err).ToNot(HaveOccurred())
return false
}, 300*time.Second, 1*time.Second).Should(BeTrue(), "The VMI did not disappear")

By("checking status of VM")
By("Checking status of VM")
Eventually(func() bool {
vm, err := virtClient.VirtualMachine(vm.Namespace).Get(vm.Name, &v12.GetOptions{})
Expect(err).ToNot(HaveOccurred())
return vm.Status.Ready
}, 300*time.Second, 1*time.Second).Should(BeFalse())

})
})

When("paused via virtctl", func() {
It("should gracefully handle being started again", func() {

runVM()

By("Pausing the VM")
command := tests.NewRepeatableVirtctlCommand("pause", "vm", "--namespace", tests.NamespaceTestDefault, vm.Name)
Expect(command()).To(Succeed())
tests.WaitForVMCondition(virtClient, vm, v1.VirtualMachinePaused, 30)

By("Starting the VM")
command = tests.NewRepeatableVirtctlCommand("start", "--namespace", tests.NamespaceTestDefault, vm.Name)
err = command()
Expect(err.Error()).To(ContainSubstring("VM is already running"))

})

It("should be restarted successfully into unpaused state", func() {

runVM()

vmi, err := virtClient.VirtualMachineInstance(vm.Namespace).Get(vm.Name, &v12.GetOptions{})
Expect(err).ToNot(HaveOccurred())

oldId := vmi.UID

By("Pausing the VM")
command := tests.NewRepeatableVirtctlCommand("pause", "vm", "--namespace", tests.NamespaceTestDefault, vm.Name)
Expect(command()).To(Succeed())
tests.WaitForVMCondition(virtClient, vm, v1.VirtualMachinePaused, 30)

By("Restarting the VM")
command = tests.NewRepeatableVirtctlCommand("restart", "--namespace", tests.NamespaceTestDefault, vm.Name)
Expect(command()).To(Succeed())

By("Checking deletion of VMI")
Eventually(func() bool {
newVMI, err := virtClient.VirtualMachineInstance(vm.Namespace).Get(vm.Name, &v12.GetOptions{})
if errors.IsNotFound(err) || (err == nil && newVMI.UID != oldId) {
return true
}
Expect(err).ToNot(HaveOccurred())
return false
}, 300*time.Second, 1*time.Second).Should(BeTrue(), "The VMI did not disappear")

By("Waiting for for new VMI to start")
newVMI := v1.NewMinimalVMIWithNS(vm.Namespace, vm.Name)
tests.WaitForSuccessfulVMIStartWithTimeout(newVMI, 300)

By("Ensuring unpaused state")
tests.WaitForVMConditionRemovedOrFalse(virtClient, vm, v1.VirtualMachinePaused, 30)
tests.WaitForVMIConditionRemovedOrFalse(virtClient, newVMI, v1.VirtualMachineInstancePaused, 30)

})

It("[test_id:3086]should not be migrated", func() {

// TODO does not work yet
//runVM()
//
//By("pausing the VM")
//command := tests.NewRepeatableVirtctlCommand("pause", "vm", "--namespace", tests.NamespaceTestDefault, vm.Name)
//Expect(command()).To(Succeed())
//tests.WaitForVMCondition(virtClient, vm, v1.VirtualMachinePaused, 30)
//
//By("trying to migrate the VM")
//command = tests.NewRepeatableVirtctlCommand("migrate", "--namespace", tests.NamespaceTestDefault, vm.Name)
//// TODO check error message
//Expect(command()).ToNot(Succeed())
runVM()

By("Pausing the VM")
command := tests.NewRepeatableVirtctlCommand("pause", "vm", "--namespace", tests.NamespaceTestDefault, vm.Name)
Expect(command()).To(Succeed())
tests.WaitForVMCondition(virtClient, vm, v1.VirtualMachinePaused, 30)

By("Trying to migrate the VM")
command = tests.NewRepeatableVirtctlCommand("migrate", "--namespace", tests.NamespaceTestDefault, vm.Name)
err = command()
Expect(err.Error()).To(ContainSubstring("VM is paused"))

})

It("[test_id:3083]should gracefully handle console connection", func() {

runVM()

By("Pausing the VM")
command := tests.NewRepeatableVirtctlCommand("pause", "vm", "--namespace", tests.NamespaceTestDefault, vm.Name)
Expect(command()).To(Succeed())
tests.WaitForVMCondition(virtClient, vm, v1.VirtualMachinePaused, 30)

By("Trying to console into the VM")
_, err = virtClient.VirtualMachineInstance(vm.ObjectMeta.Namespace).SerialConsole(vm.ObjectMeta.Name, 10)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("VMI is paused"))

})

It("[test_id:3084]should gracefully handle vnc connection", func() {

runVM()

By("Pausing the VM")
command := tests.NewRepeatableVirtctlCommand("pause", "vm", "--namespace", tests.NamespaceTestDefault, vm.Name)
Expect(command()).To(Succeed())
tests.WaitForVMCondition(virtClient, vm, v1.VirtualMachinePaused, 30)

By("Trying to vnc into the VM")
_, err = virtClient.VirtualMachineInstance(vm.ObjectMeta.Namespace).VNC(vm.ObjectMeta.Name)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("VMI is paused"))

})
})
})

Context("A long running process", func() {

startProcess := func(expecter expect.Expecter) string {
By("Start a long running process")
res, err := expecter.ExpectBatch([]expect.Batcher{
&expect.BSnd{S: "sleep 5&\n"},
&expect.BExp{R: ".*\n"}, // command
&expect.BExp{R: ".*\n"}, // result
&expect.BExp{R: ".*# "}, // prompt
&expect.BSnd{S: `pgrep -f "sleep 5"` + "\n"},
&expect.BExp{R: ".*\n"}, // command
&expect.BExp{R: ".*\n"}, // result
&expect.BExp{R: ".*# "}, // prompt
}, 15*time.Second)
Expect(err).ToNot(HaveOccurred())
fmt.Fprintf(GinkgoWriter, "a:%+v\n", res)
return strings.TrimSpace(res[4].Match[0])
}

checkProcess := func(expecter expect.Expecter) string {
By("Checking the long running process")
res, err := expecter.ExpectBatch([]expect.Batcher{
&expect.BSnd{S: `pgrep -f "sleep 5"` + "\n"},
&expect.BExp{R: ".*\n"}, // command
&expect.BExp{R: ".*\n"}, // result
&expect.BExp{R: ".*# "}, // prompt
}, 15*time.Second)
Expect(err).ToNot(HaveOccurred())
fmt.Fprintf(GinkgoWriter, "b:%+v\n", res)
return strings.TrimSpace(res[1].Match[0])
}

It("[test_id:3090]should be continued after the VMI is unpaused", func() {

By("Starting a Fedora VMI")
vmi := tests.NewRandomFedoraVMIWitGuestAgent()
vmi.Spec.Domain.Resources.Requests[k8sv1.ResourceMemory] = resource.MustParse(fedoraVMSize)
vmi = tests.RunVMIAndExpectLaunch(vmi, 360)
tests.WaitAgentConnected(virtClient, vmi)

expecter, expecterErr := tests.LoggedInFedoraExpecter(vmi)
Expect(expecterErr).ToNot(HaveOccurred())
defer expecter.Close()

By("Starting a process")
startPid := startProcess(expecter)
Expect(startPid).ToNot(BeEmpty())

By("Pausing the VMI")
command := tests.NewRepeatableVirtctlCommand("pause", "vmi", "--namespace", tests.NamespaceTestDefault, vmi.Name)
Expect(command()).To(Succeed())
tests.WaitForVMICondition(virtClient, vmi, v1.VirtualMachineInstancePaused, 30)

By("Waiting longer than the process normally runs")
time.Sleep(7 * time.Second)

By("Unpausing the VMI")
command = tests.NewRepeatableVirtctlCommand("unpause", "vmi", "--namespace", tests.NamespaceTestDefault, vmi.Name)
Expect(command()).To(Succeed())
tests.WaitForVMIConditionRemovedOrFalse(virtClient, vmi, v1.VirtualMachineInstancePaused, 30)

By("Checking the process")
checkPid := checkProcess(expecter)

Expect(checkPid).To(Equal(startPid))

})
})
})
23 changes: 13 additions & 10 deletions tests/windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,12 @@ const (
winrmCliCmd = "winrm-cli"
)

var _ = Describe("Windows VirtualMachineInstance", func() {
tests.FlagParse()

virtClient, err := kubecli.GetKubevirtClient()
tests.PanicOnError(err)

var windowsVMI *v1.VirtualMachineInstance

var getWindowsVMISpec = func() v1.VirtualMachineInstanceSpec {
gracePeriod := int64(0)
spinlocks := uint32(8191)
firmware := types.UID(windowsFirmware)
_false := false
windowsVMISpec := v1.VirtualMachineInstanceSpec{
return v1.VirtualMachineInstanceSpec{
TerminationGracePeriodSeconds: &gracePeriod,
Domain: v1.DomainSpec{
CPU: &v1.CPU{Cores: 2},
Expand Down Expand Up @@ -116,14 +109,24 @@ var _ = Describe("Windows VirtualMachineInstance", func() {
},
}

}

var _ = Describe("Windows VirtualMachineInstance", func() {
tests.FlagParse()

virtClient, err := kubecli.GetKubevirtClient()
tests.PanicOnError(err)

var windowsVMI *v1.VirtualMachineInstance

tests.BeforeAll(func() {
tests.SkipIfNoWindowsImage(virtClient)
})

BeforeEach(func() {
tests.BeforeTestCleanup()
windowsVMI = tests.NewRandomVMI()
windowsVMI.Spec = windowsVMISpec
windowsVMI.Spec = getWindowsVMISpec()
tests.AddExplicitPodNetworkInterface(windowsVMI)
windowsVMI.Spec.Domain.Devices.Interfaces[0].Model = "e1000"
})
Expand Down

0 comments on commit bad7772

Please sign in to comment.