Skip to content

Commit

Permalink
Merge pull request kubevirt#886 from davidvossel/fix_881
Browse files Browse the repository at this point in the history
Add functional test to verify pod termination
  • Loading branch information
Artyom Lukianov authored Apr 11, 2018
2 parents 9ee8de4 + d45a4bb commit a4a5194
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 11 deletions.
2 changes: 2 additions & 0 deletions cmd/registry-disk-v1alpha/entry-point.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

# https://fedoraproject.org/wiki/Scsi-target-utils_Quickstart_Guide

trap 'echo "Graceful exit"; exit 0' SIGINT SIGQUIT SIGTERM

if [ -z "$COPY_PATH" ]; then
echo "COPY_PATH variable not set"
exit 1
Expand Down
22 changes: 20 additions & 2 deletions cmd/virt-launcher/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
#!/bin/bash
set +e

_term() {
echo "caught signal"
kill -TERM "$virt_launcher_pid" 2>/dev/null
}

trap _term SIGTERM SIGINT SIGQUIT

# HACK
# Try to create /dev/kvm if not present
if [ ! -e /dev/kvm ]; then
Expand All @@ -10,13 +17,24 @@ fi
chown :qemu /dev/kvm
chmod 660 /dev/kvm


# Cockpit/OCP hack to all shoing the vm terminal
mv /usr/bin/sh /usr/bin/sh.orig
mv /sh.sh /usr/bin/sh
chmod +x /usr/bin/sh

./virt-launcher $@
./virt-launcher $@ &
virt_launcher_pid=$!
while true; do
if ! [ -d /proc/$virt_launcher_pid ]; then
break;
fi
sleep 1
done
# call wait after we know the pid has exited in order
# to get the return code. If we call wait before the pid
# exits, wait will actually return early when we forward
# the trapped signal in _trap(). We don't want that.
wait -n $virt_launcher_pid
rc=$?

echo "virt-launcher exited with code $rc"
Expand Down
27 changes: 18 additions & 9 deletions pkg/virt-launcher/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,16 @@ func NewProcessMonitor(commandPrefix string,
}
}

func (mon *monitor) isGracePeriodExpired() bool {
if mon.gracePeriodStartTime != 0 {
now := time.Now().UTC().Unix()
if (now - mon.gracePeriodStartTime) > int64(mon.gracePeriod) {
return true
}
}
return false
}

func (mon *monitor) refresh() {
if mon.isDone {
log.Log.Error("Called refresh after done!")
Expand All @@ -187,6 +197,8 @@ func (mon *monitor) refresh() {

log.Log.Debugf("Refreshing. CommandPrefix %s pid %d", mon.commandPrefix, mon.pid)

expired := mon.isGracePeriodExpired()

// is the process there?
if mon.pid == 0 {
var err error
Expand All @@ -200,6 +212,9 @@ func (mon *monitor) refresh() {
if mon.timeout > 0 && elapsed >= mon.timeout {
log.Log.Infof("%s not found after timeout", mon.commandPrefix)
mon.isDone = true
} else if expired {
log.Log.Infof("%s not found after grace period expired", mon.commandPrefix)
mon.isDone = true
}
return
}
Expand All @@ -219,12 +234,9 @@ func (mon *monitor) refresh() {
return
}

if mon.gracePeriodStartTime != 0 {
now := time.Now().UTC().Unix()
if (now - mon.gracePeriodStartTime) > int64(mon.gracePeriod) {
log.Log.Infof("Grace Period expired, shutting down.")
mon.shutdownCallback(mon.pid)
}
if expired {
log.Log.Infof("Grace Period expired, shutting down.")
mon.shutdownCallback(mon.pid)
}

return
Expand Down Expand Up @@ -252,9 +264,6 @@ func (mon *monitor) monitorLoop(startTimeout time.Duration, signalChan chan os.S
mon.refresh()
case s := <-signalChan:
log.Log.Infof("Received signal %d.", s)
if mon.pid == 0 {
continue
}

if mon.gracePeriodStartTime != 0 {
continue
Expand Down
24 changes: 24 additions & 0 deletions pkg/virt-launcher/monitor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,30 @@ var _ = Describe("VirtLauncher", func() {
Expect(exited).To(Equal(true))
})

It("verify monitor loop exits when signal arrives and no pid is present", func() {
signalChannel := make(chan os.Signal, 1)
done := make(chan string)

go func() {
mon.monitorLoop(1*time.Second, signalChannel)
done <- "exit"
}()

time.Sleep(time.Second)

signalChannel <- syscall.SIGQUIT
noExitCheck := time.After(5 * time.Second)
exited := false

select {
case <-noExitCheck:
case <-done:
exited = true
}

Expect(exited).To(Equal(true))
})

It("verify graceful shutdown trigger works", func() {
signalChannel := make(chan os.Signal, 1)
done := make(chan string)
Expand Down
27 changes: 27 additions & 0 deletions tests/vmlifecycle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (

"kubevirt.io/kubevirt/pkg/api/v1"
"kubevirt.io/kubevirt/pkg/kubecli"
"kubevirt.io/kubevirt/pkg/virt-controller/services"
"kubevirt.io/kubevirt/tests"
)

Expand Down Expand Up @@ -351,6 +352,32 @@ var _ = Describe("Vmlifecycle", func() {
})

Describe("Delete a VM", func() {
Context("with an active pod.", func() {
It("should result in pod being terminated", func(done Done) {

By("Creating the VM")
obj, err := virtClient.VM(tests.NamespaceTestDefault).Create(vm)
Expect(err).ToNot(HaveOccurred())
tests.WaitForSuccessfulVMStart(obj)

By("Verifying VM's pod is active")
pods, err := virtClient.CoreV1().Pods(tests.NamespaceTestDefault).List(services.UnfinishedVMPodSelector(vm))
Expect(err).ToNot(HaveOccurred())
Expect(len(pods.Items)).To(Equal(1))

By("Deleting the VM")
Expect(virtClient.VM(vm.Namespace).Delete(obj.Name, &metav1.DeleteOptions{})).To(Succeed())

By("Verifying VM's pod terminates")
Eventually(func() int {
pods, err := virtClient.CoreV1().Pods(tests.NamespaceTestDefault).List(services.UnfinishedVMPodSelector(vm))
Expect(err).ToNot(HaveOccurred())
return len(pods.Items)
}, 75, 0.5).Should(Equal(0))

close(done)
}, 90)
})
Context("with grace period greater than 0", func() {
It("should run graceful shutdown", func(done Done) {
nodes, err := virtClient.CoreV1().Nodes().List(metav1.ListOptions{})
Expand Down

0 comments on commit a4a5194

Please sign in to comment.