Skip to content

Commit

Permalink
Merge 9a2c3fc into 2a43f5b
Browse files Browse the repository at this point in the history
  • Loading branch information
stu-gott committed Mar 3, 2017
2 parents 2a43f5b + 9a2c3fc commit 480358a
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 2 deletions.
85 changes: 83 additions & 2 deletions pkg/virt-controller/services/template.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
package services

import (
"fmt"
"strconv"
"strings"

kubeapi "k8s.io/client-go/pkg/api"
kubev1 "k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/apis/batch"
metav1 "k8s.io/client-go/pkg/apis/meta/v1"

"kubevirt.io/kubevirt/pkg/api/v1"
"kubevirt.io/kubevirt/pkg/logging"
"kubevirt.io/kubevirt/pkg/precond"
"strconv"
"strings"
)

type TemplateService interface {
RenderLaunchManifest(*v1.VM) (*kubev1.Pod, error)
RenderMigrationJob(*v1.VM, *kubev1.Node, *kubev1.Node) (*batch.Job, error)
}

type templateService struct {
Expand Down Expand Up @@ -62,6 +70,79 @@ func (t *templateService) RenderLaunchManifest(vm *v1.VM) (*kubev1.Pod, error) {
return &pod, nil
}

func (t *templateService) RenderMigrationJob(vm *v1.VM, sourceNode *kubev1.Node, targetNode *kubev1.Node) (*batch.Job, error) {
srcAddr := ""
dstAddr := ""
for _, addr := range sourceNode.Status.Addresses {
if addr.Type == kubev1.NodeHostName {
srcAddr = addr.Address
break
}
}
if srcAddr == "" {
for _, addr := range sourceNode.Status.Addresses {
if addr.Type == kubev1.NodeInternalIP {
srcAddr = addr.Address
break
}
}
}
if srcAddr == "" {
err := fmt.Errorf("migration source node is unreachable")
logging.DefaultLogger().Error().Msg("migration target node is unreachable")
return nil, err
}
srcUri := fmt.Sprintf("qemu+tcp://%s", srcAddr)

for _, addr := range targetNode.Status.Addresses {
if addr.Type == kubev1.NodeHostName {
dstAddr = addr.Address
break
}
}
if dstAddr == "" {
for _, addr := range targetNode.Status.Addresses {
if addr.Type == kubev1.NodeInternalIP {
dstAddr = addr.Address
break
}
}
}
if dstAddr == "" {
err := fmt.Errorf("migration target node is unreachable")
logging.DefaultLogger().Error().Msg("migration target node is unreachable")
return nil, err
}
destUri := fmt.Sprintf("qemu+tcp://%s", dstAddr)

job := batch.Job{
ObjectMeta: kubeapi.ObjectMeta{
GenerateName: "virt-migration",
},
TypeMeta: metav1.TypeMeta{
Kind: "Job",
},
Spec: batch.JobSpec{
Template: kubeapi.PodTemplateSpec{
Spec: kubeapi.PodSpec{
RestartPolicy: kubeapi.RestartPolicyNever,
Containers: []kubeapi.Container{
kubeapi.Container{
Name: "virt-migration",
Image: "kubevirt/virt-handler:devel",
Command: []string{
"virsh", "migrate", vm.Spec.Domain.Name, destUri, srcUri,
},
},
},
},
},
},
}

return &job, nil
}

func NewTemplateService(launcherImage string) (TemplateService, error) {
precond.MustNotBeEmpty(launcherImage)
svc := templateService{
Expand Down
121 changes: 121 additions & 0 deletions pkg/virt-controller/services/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
coreapi "k8s.io/client-go/pkg/api"
corev1 "k8s.io/client-go/pkg/api/v1"
"kubevirt.io/kubevirt/pkg/api/v1"
)
Expand Down Expand Up @@ -56,6 +57,126 @@ var _ = Describe("Template", func() {
Expect(pod.Spec.Containers[0].Command).To(Equal([]string{"/virt-launcher", "-qemu-timeout", "60s"}))
})
})
Context("migration", func() {
var (
srcHost = corev1.NodeAddress{}
srcIp = corev1.NodeAddress{}
destHost = corev1.NodeAddress{}
destIp = corev1.NodeAddress{}
srcNode = corev1.Node{}
srcNodeIp = corev1.Node{}
destNodeIp = corev1.Node{}
destNode = corev1.Node{}
)

BeforeEach(func() {
srcHost = corev1.NodeAddress{
Type: corev1.NodeHostName,
Address: "src-node.kubevirt.io",
}
srcIp = corev1.NodeAddress{
Type: corev1.NodeInternalIP,
Address: "127.0.0.2",
}
destHost = corev1.NodeAddress{
Type: corev1.NodeHostName,
Address: "dest-node.kubevirt.io",
}
destIp = corev1.NodeAddress{
Type: corev1.NodeInternalIP,
Address: "127.0.0.3",
}
// Note: the IP's are listed before the hostnames on srcNode and destNode
// so that we can ensure we test the priority order of selection
srcNode = corev1.Node{
Status: corev1.NodeStatus{
Addresses: []corev1.NodeAddress{srcIp, srcHost},
},
}
destNode = corev1.Node{
Status: corev1.NodeStatus{
Addresses: []corev1.NodeAddress{destIp, destHost},
},
}
srcNodeIp = corev1.Node{
Status: corev1.NodeStatus{
Addresses: []corev1.NodeAddress{srcIp},
},
}
destNodeIp = corev1.Node{
Status: corev1.NodeStatus{
Addresses: []corev1.NodeAddress{destIp},
},
}
})

Context("migration template with correct parameters", func() {
It("should never restart", func() {
vm := v1.NewMinimalVM("testvm")

job, err := svc.RenderMigrationJob(vm, &srcNode, &destNode)
Expect(err).ToNot(HaveOccurred())
Expect(job.Spec.Template.Spec.RestartPolicy).To(Equal(coreapi.RestartPolicyNever))
})
It("should prefer DNS name over IP for source", func() {
vm := v1.NewMinimalVM("testvm")
job, err := svc.RenderMigrationJob(vm, &srcNode, &destNodeIp)
Expect(err).ToNot(HaveOccurred())
refCommand := []string{
"virsh", "migrate", "testvm",
"qemu+tcp://127.0.0.3", "qemu+tcp://src-node.kubevirt.io"}
Expect(job.Spec.Template.Spec.Containers[0].Command).To(Equal(refCommand))
})
It("should prefer DNS name over IP for target", func() {
vm := v1.NewMinimalVM("testvm")
job, err := svc.RenderMigrationJob(vm, &srcNodeIp, &destNode)
Expect(err).ToNot(HaveOccurred())
refCommand := []string{
"virsh", "migrate", "testvm",
"qemu+tcp://dest-node.kubevirt.io", "qemu+tcp://127.0.0.2"}
Expect(job.Spec.Template.Spec.Containers[0].Command).To(Equal(refCommand))
})
It("should use the first address it finds", func() {
vm := v1.NewMinimalVM("testvm")
// These are contrived nodes with conflicting addresses, so not
// defined at the context scope to ensure they're not re-used
node1 := corev1.Node{
Status: corev1.NodeStatus{
Addresses: []corev1.NodeAddress{srcHost, destHost},
},
}
node2 := corev1.Node{
Status: corev1.NodeStatus{
Addresses: []corev1.NodeAddress{srcIp, destIp},
},
}
job, err := svc.RenderMigrationJob(vm, &node1, &node2)
Expect(err).ToNot(HaveOccurred())
refCommand := []string{
"virsh", "migrate", "testvm",
"qemu+tcp://127.0.0.2", "qemu+tcp://src-node.kubevirt.io"}
Expect(job.Spec.Template.Spec.Containers[0].Command).To(Equal(refCommand))
})
})
Context("migration template with incorrect parameters", func() {
It("should error on missing source address", func() {
vm := v1.NewMinimalVM("testvm")
node1 := corev1.Node{}
node2 := destNodeIp
job, err := svc.RenderMigrationJob(vm, &node1, &node2)
Expect(err).To(HaveOccurred())
Expect(job).To(BeNil())
})
It("should error on missing destination address", func() {
vm := v1.NewMinimalVM("testvm")
node1 := srcNodeIp
node2 := corev1.Node{}
job, err := svc.RenderMigrationJob(vm, &node1, &node2)
Expect(err).To(HaveOccurred())
Expect(job).To(BeNil())
})
})
})
})

})

0 comments on commit 480358a

Please sign in to comment.