1
19
20 package kubecli
21
22 import (
23 "context"
24 "fmt"
25 "net/http"
26 "net/url"
27 "strconv"
28 "strings"
29 "time"
30
31 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32 "k8s.io/apimachinery/pkg/types"
33 "k8s.io/client-go/kubernetes"
34 "k8s.io/client-go/rest"
35
36 v1 "kubevirt.io/api/core/v1"
37 kvcorev1 "kubevirt.io/client-go/generated/kubevirt/clientset/versioned/typed/core/v1"
38 )
39
40 func (k *kubevirt) VirtualMachineInstance(namespace string) VirtualMachineInstanceInterface {
41 return &vmis{
42 VirtualMachineInstanceInterface: k.GeneratedKubeVirtClient().KubevirtV1().VirtualMachineInstances(namespace),
43 restClient: k.restClient,
44 config: k.config,
45 clientSet: k.Clientset,
46 namespace: namespace,
47 resource: "virtualmachineinstances",
48 }
49 }
50
51 type vmis struct {
52 kvcorev1.VirtualMachineInstanceInterface
53 restClient *rest.RESTClient
54 config *rest.Config
55 clientSet *kubernetes.Clientset
56 namespace string
57 resource string
58 master string
59 kubeconfig string
60 }
61
62 func (v *vmis) USBRedir(name string) (kvcorev1.StreamInterface, error) {
63 return kvcorev1.AsyncSubresourceHelper(v.config, v.resource, v.namespace, name, "usbredir", url.Values{})
64 }
65
66 func (v *vmis) VNC(name string) (kvcorev1.StreamInterface, error) {
67 return kvcorev1.AsyncSubresourceHelper(v.config, v.resource, v.namespace, name, "vnc", url.Values{})
68 }
69
70 func (v *vmis) PortForward(name string, port int, protocol string) (kvcorev1.StreamInterface, error) {
71 return kvcorev1.AsyncSubresourceHelper(v.config, v.resource, v.namespace, name, buildPortForwardResourcePath(port, protocol), url.Values{})
72 }
73
74 func buildPortForwardResourcePath(port int, protocol string) string {
75 resource := strings.Builder{}
76 resource.WriteString("portforward/")
77 resource.WriteString(strconv.Itoa(port))
78
79 if len(protocol) > 0 {
80 resource.WriteString("/")
81 resource.WriteString(protocol)
82 }
83
84 return resource.String()
85 }
86
87 type connectionStruct struct {
88 con kvcorev1.StreamInterface
89 err error
90 }
91
92 func (v *vmis) SerialConsole(name string, options *kvcorev1.SerialConsoleOptions) (kvcorev1.StreamInterface, error) {
93
94 if options != nil && options.ConnectionTimeout != 0 {
95 timeoutChan := time.Tick(options.ConnectionTimeout)
96 connectionChan := make(chan connectionStruct)
97
98 go func() {
99 for {
100
101 select {
102 case <-timeoutChan:
103 connectionChan <- connectionStruct{
104 con: nil,
105 err: fmt.Errorf("Timeout trying to connect to the virtual machine instance"),
106 }
107 return
108 default:
109 }
110
111 con, err := kvcorev1.AsyncSubresourceHelper(v.config, v.resource, v.namespace, name, "console", url.Values{})
112 if err != nil {
113 asyncSubresourceError, ok := err.(*kvcorev1.AsyncSubresourceError)
114
115 if !ok || asyncSubresourceError.GetStatusCode() != http.StatusBadRequest {
116 connectionChan <- connectionStruct{con: nil, err: err}
117 return
118 }
119
120 time.Sleep(1 * time.Second)
121 continue
122 }
123
124 connectionChan <- connectionStruct{con: con, err: nil}
125 return
126 }
127 }()
128 conStruct := <-connectionChan
129 return conStruct.con, conStruct.err
130 } else {
131 return kvcorev1.AsyncSubresourceHelper(v.config, v.resource, v.namespace, name, "console", url.Values{})
132 }
133 }
134
135 func (v *vmis) Get(ctx context.Context, name string, options metav1.GetOptions) (vmi *v1.VirtualMachineInstance, err error) {
136 vmi, err = v.VirtualMachineInstanceInterface.Get(ctx, name, options)
137 vmi.SetGroupVersionKind(v1.VirtualMachineInstanceGroupVersionKind)
138 return
139 }
140
141 func (v *vmis) List(ctx context.Context, options metav1.ListOptions) (vmiList *v1.VirtualMachineInstanceList, err error) {
142 vmiList, err = v.VirtualMachineInstanceInterface.List(ctx, options)
143 for i := range vmiList.Items {
144 vmiList.Items[i].SetGroupVersionKind(v1.VirtualMachineInstanceGroupVersionKind)
145 }
146 return
147 }
148
149 func (v *vmis) Create(ctx context.Context, vmi *v1.VirtualMachineInstance, opts metav1.CreateOptions) (result *v1.VirtualMachineInstance, err error) {
150 result, err = v.VirtualMachineInstanceInterface.Create(ctx, vmi, opts)
151 result.SetGroupVersionKind(v1.VirtualMachineInstanceGroupVersionKind)
152 return
153 }
154
155 func (v *vmis) Update(ctx context.Context, vmi *v1.VirtualMachineInstance, opts metav1.UpdateOptions) (result *v1.VirtualMachineInstance, err error) {
156 result, err = v.VirtualMachineInstanceInterface.Update(ctx, vmi, opts)
157 result.SetGroupVersionKind(v1.VirtualMachineInstanceGroupVersionKind)
158 return
159 }
160
161 func (v *vmis) Delete(ctx context.Context, name string, options metav1.DeleteOptions) error {
162 return v.VirtualMachineInstanceInterface.Delete(ctx, name, options)
163 }
164
165 func (v *vmis) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, patchOptions metav1.PatchOptions, subresources ...string) (result *v1.VirtualMachineInstance, err error) {
166 return v.VirtualMachineInstanceInterface.Patch(ctx, name, pt, data, patchOptions, subresources...)
167 }
168
169 func (v *vmis) VSOCK(name string, options *v1.VSOCKOptions) (kvcorev1.StreamInterface, error) {
170 if options == nil || options.TargetPort == 0 {
171 return nil, fmt.Errorf("target port is required but not provided")
172 }
173 queryParams := url.Values{}
174 queryParams.Add("port", strconv.FormatUint(uint64(options.TargetPort), 10))
175 useTLS := true
176 if options.UseTLS != nil {
177 useTLS = *options.UseTLS
178 }
179 queryParams.Add("tls", strconv.FormatBool(useTLS))
180 return kvcorev1.AsyncSubresourceHelper(v.config, v.resource, v.namespace, name, "vsock", queryParams)
181 }
182
View as plain text