forked from kubevirt/kubevirt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
handler.go
140 lines (121 loc) · 3.3 KB
/
handler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package kubecli
import (
"encoding/json"
"fmt"
"net/url"
"k8s.io/api/core/v1"
k8smetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"io/ioutil"
"net/http"
virtv1 "kubevirt.io/kubevirt/pkg/api/v1"
)
func NewVirtHandlerClient(client KubevirtClient) VirtHandlerClient {
return &virtHandler{client}
}
type VirtHandlerClient interface {
ForNode(nodeName string) VirtHandlerConn
}
type VirtHandlerConn interface {
NodeMigrationDetails(vm *virtv1.VirtualMachine) (*virtv1.MigrationHostInfo, error)
ConnectionDetails() (ip string, port string, err error)
ConsoleURI(vm *virtv1.VirtualMachine) (*url.URL, error)
Pod() (pod *v1.Pod, err error)
}
type virtHandler struct {
client KubevirtClient
}
type virtHandlerConn struct {
client KubevirtClient
pod *v1.Pod
err error
}
func (v *virtHandler) ForNode(nodeName string) VirtHandlerConn {
pod, found, err := v.getVirtHandler(nodeName)
conn := &virtHandlerConn{}
if !found {
conn.err = fmt.Errorf("No virt-handler on node %s found", nodeName)
}
if err != nil {
conn.err = err
}
conn.pod = pod
conn.client = v.client
return conn
}
func (v *virtHandler) getVirtHandler(nodeName string) (*v1.Pod, bool, error) {
handlerNodeSelector := fields.ParseSelectorOrDie("spec.nodeName=" + nodeName)
labelSelector, err := labels.Parse("daemon in (virt-handler)")
if err != nil {
return nil, false, err
}
pods, err := v.client.CoreV1().Pods(v1.NamespaceAll).List(
k8smetav1.ListOptions{
FieldSelector: handlerNodeSelector.String(),
LabelSelector: labelSelector.String()})
if err != nil {
return nil, false, err
}
if len(pods.Items) > 1 {
return nil, false, fmt.Errorf("Expected to find one Pod, found %d Pods", len(pods.Items))
}
if len(pods.Items) == 0 {
return nil, false, nil
}
return &pods.Items[0], true, nil
}
func (v *virtHandlerConn) NodeMigrationDetails(vm *virtv1.VirtualMachine) (*virtv1.MigrationHostInfo, error) {
ip, port, err := v.ConnectionDetails()
if err != nil {
return nil, err
}
resp, err := http.Get(fmt.Sprintf("http://%s:%s/api/v1/namespaces/%s/virtualmachines/%s/migrationHostInfo",
ip,
port,
vm.ObjectMeta.Namespace,
vm.ObjectMeta.Name,
))
if err != nil {
return nil, err
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
migrationHostInfo := &virtv1.MigrationHostInfo{}
err = json.Unmarshal(body, migrationHostInfo)
if err != nil {
return nil, err
}
return migrationHostInfo, nil
}
func (v *virtHandlerConn) ConnectionDetails() (ip string, port string, err error) {
if v.err != nil {
err = v.err
return
}
// TODO depending on in which network namespace virt-handler runs, we might have to choose the NodeIPt d
ip = v.pod.Status.PodIP
// TODO get rid of the hardcoded port
port = "8185"
return
}
//TODO move the actual ws handling in here, and work with channels
func (v *virtHandlerConn) ConsoleURI(vm *virtv1.VirtualMachine) (*url.URL, error) {
ip, port, err := v.ConnectionDetails()
if err != nil {
return nil, err
}
return &url.URL{
Path: fmt.Sprintf("/api/v1/namespaces/%s/virtualmachines/%s/console", vm.ObjectMeta.Namespace, vm.ObjectMeta.Name),
Host: ip + ":" + port,
}, nil
}
func (v *virtHandlerConn) Pod() (pod *v1.Pod, err error) {
if v.err != nil {
err = v.err
return
}
return v.pod, err
}