• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kubevirt / kubevirt / 04b78ccb-48cd-4c0d-a660-86c4c0e4bbec

17 Mar 2025 09:11PM UTC coverage: 71.456% (-0.005%) from 71.461%
04b78ccb-48cd-4c0d-a660-86c4c0e4bbec

push

prow

web-flow
Merge pull request #14250 from iholder101/c_cleanup

Cleanup: Remove redundant size capacity, handle potential nil pointer dereference, replace an empty slice with nil

14 of 15 new or added lines in 7 files covered. (93.33%)

30 existing lines in 1 file now uncovered.

62111 of 86922 relevant lines covered (71.46%)

0.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.4
/pkg/virt-handler/cmd-client/client.go
1
/*
2
 * This file is part of the KubeVirt project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 *
16
 * Copyright 2017 Red Hat, Inc.
17
 *
18
 */
19

20
package cmdclient
21

22
//go:generate mockgen -source $GOFILE -package=$GOPACKAGE -destination=generated_mock_$GOFILE
23

24
/*
25
 ATTENTION: Rerun code generators when interface signatures are modified.
26
*/
27

28
import (
29
        "context"
30
        "errors"
31
        "fmt"
32
        "io"
33
        "net"
34
        "net/rpc"
35
        "os"
36
        "path/filepath"
37
        "syscall"
38
        "time"
39

40
        "google.golang.org/grpc"
41
        "google.golang.org/grpc/codes"
42
        "google.golang.org/grpc/status"
43

44
        "k8s.io/apimachinery/pkg/api/resource"
45
        "k8s.io/apimachinery/pkg/util/json"
46

47
        v1 "kubevirt.io/api/core/v1"
48
        "kubevirt.io/client-go/log"
49

50
        diskutils "kubevirt.io/kubevirt/pkg/ephemeral-disk-utils"
51
        com "kubevirt.io/kubevirt/pkg/handler-launcher-com"
52
        "kubevirt.io/kubevirt/pkg/handler-launcher-com/cmd/info"
53
        cmdv1 "kubevirt.io/kubevirt/pkg/handler-launcher-com/cmd/v1"
54
        grpcutil "kubevirt.io/kubevirt/pkg/util/net/grpc"
55
        "kubevirt.io/kubevirt/pkg/virt-launcher/virtwrap/api"
56
        "kubevirt.io/kubevirt/pkg/virt-launcher/virtwrap/stats"
57
)
58

59
var (
60
        // add older version when supported
61
        // don't use the variable in pkg/handler-launcher-com/cmd/v1/version.go in order to detect version mismatches early
62
        supportedCmdVersions = []uint32{1}
63
        baseDir              = "/var/run/kubevirt"
64
        podsBaseDir          = "/pods"
65
)
66

67
const StandardLauncherSocketFileName = "launcher-sock"
68
const StandardInitLauncherSocketFileName = "launcher-init-sock"
69
const StandardLauncherUnresponsiveFileName = "launcher-unresponsive"
70

71
type MigrationOptions struct {
72
        Bandwidth                resource.Quantity
73
        ProgressTimeout          int64
74
        CompletionTimeoutPerGiB  int64
75
        UnsafeMigration          bool
76
        AllowAutoConverge        bool
77
        AllowPostCopy            bool
78
        ParallelMigrationThreads *uint
79
        AllowWorkloadDisruption  bool
80
}
81

82
type LauncherClient interface {
83
        SyncVirtualMachine(vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error
84
        PauseVirtualMachine(vmi *v1.VirtualMachineInstance) error
85
        UnpauseVirtualMachine(vmi *v1.VirtualMachineInstance) error
86
        FreezeVirtualMachine(vmi *v1.VirtualMachineInstance, unfreezeTimeoutSeconds int32) error
87
        UnfreezeVirtualMachine(vmi *v1.VirtualMachineInstance) error
88
        SyncMigrationTarget(vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error
89
        ResetVirtualMachine(vmi *v1.VirtualMachineInstance) error
90
        SoftRebootVirtualMachine(vmi *v1.VirtualMachineInstance) error
91
        SignalTargetPodCleanup(vmi *v1.VirtualMachineInstance) error
92
        ShutdownVirtualMachine(vmi *v1.VirtualMachineInstance) error
93
        KillVirtualMachine(vmi *v1.VirtualMachineInstance) error
94
        MigrateVirtualMachine(vmi *v1.VirtualMachineInstance, options *MigrationOptions) error
95
        CancelVirtualMachineMigration(vmi *v1.VirtualMachineInstance) error
96
        FinalizeVirtualMachineMigration(vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error
97
        HotplugHostDevices(vmi *v1.VirtualMachineInstance) error
98
        DeleteDomain(vmi *v1.VirtualMachineInstance) error
99
        GetDomain() (*api.Domain, bool, error)
100
        GetDomainStats() (*stats.DomainStats, bool, error)
101
        GetGuestInfo() (*v1.VirtualMachineInstanceGuestAgentInfo, error)
102
        GetUsers() (v1.VirtualMachineInstanceGuestOSUserList, error)
103
        GetFilesystems() (v1.VirtualMachineInstanceFileSystemList, error)
104
        Exec(string, string, []string, int32) (int, string, error)
105
        Ping() error
106
        GuestPing(string, int32) error
107
        Close()
108
        VirtualMachineMemoryDump(vmi *v1.VirtualMachineInstance, dumpPath string) error
109
        GetQemuVersion() (string, error)
110
        SyncVirtualMachineCPUs(vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error
111
        GetSEVInfo() (*v1.SEVPlatformInfo, error)
112
        GetLaunchMeasurement(*v1.VirtualMachineInstance) (*v1.SEVMeasurementInfo, error)
113
        InjectLaunchSecret(*v1.VirtualMachineInstance, *v1.SEVSecretOptions) error
114
        SyncVirtualMachineMemory(vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error
115
}
116

117
type VirtLauncherClient struct {
118
        v1client cmdv1.CmdClient
119
        conn     *grpc.ClientConn
120
}
121

122
const (
123
        shortTimeout time.Duration = 5 * time.Second
124
        longTimeout  time.Duration = 20 * time.Second
125
)
126

127
func SetBaseDir(dir string) {
1✔
128
        baseDir = dir
1✔
129
}
1✔
130

131
func SetPodsBaseDir(baseDir string) {
1✔
132
        podsBaseDir = baseDir
1✔
133
}
1✔
134

135
func ListAllSockets() ([]string, error) {
1✔
136
        var socketFiles []string
1✔
137

1✔
138
        dirs, err := os.ReadDir(podsBaseDir)
1✔
139
        if err != nil {
1✔
140
                return nil, err
×
141
        }
×
142
        for _, dir := range dirs {
2✔
143
                if !dir.IsDir() {
1✔
144
                        continue
×
145
                }
146

147
                socketPath := SocketFilePathOnHost(dir.Name())
1✔
148
                exists, err := diskutils.FileExists(socketPath)
1✔
149
                if err != nil {
1✔
150
                        return socketFiles, err
×
151
                }
×
152

153
                if exists {
2✔
154
                        socketFiles = append(socketFiles, socketPath)
1✔
155
                }
1✔
156
        }
157

158
        return socketFiles, nil
1✔
159
}
160

161
func SocketsDirectory() string {
1✔
162
        return filepath.Join(baseDir, "sockets")
1✔
163
}
1✔
164

165
func IsSocketUnresponsive(socket string) bool {
1✔
166
        file := filepath.Join(filepath.Dir(socket), StandardLauncherUnresponsiveFileName)
1✔
167
        exists, _ := diskutils.FileExists(file)
1✔
168
        // if the unresponsive socket monitor marked this socket
1✔
169
        // as being unresponsive, return true
1✔
170
        if exists {
2✔
171
                return true
1✔
172
        }
1✔
173

174
        exists, _ = diskutils.FileExists(socket)
1✔
175
        // if the socket file doesn't exist, it's definitely unresponsive as well
1✔
176
        return !exists
1✔
177
}
178

179
func MarkSocketUnresponsive(socket string) error {
1✔
180
        file := filepath.Join(filepath.Dir(socket), StandardLauncherUnresponsiveFileName)
1✔
181
        f, err := os.Create(file)
1✔
182
        if err != nil {
1✔
183
                return err
×
184
        }
×
185
        f.Close()
1✔
186
        return nil
1✔
187
}
188

189
func SocketDirectoryOnHost(podUID string) string {
1✔
190
        return fmt.Sprintf("/%s/%s/volumes/kubernetes.io~empty-dir/sockets", podsBaseDir, podUID)
1✔
191
}
1✔
192

193
func SocketFilePathOnHost(podUID string) string {
1✔
194
        return fmt.Sprintf("%s/%s", SocketDirectoryOnHost(podUID), StandardLauncherSocketFileName)
1✔
195
}
1✔
196

197
// gets the cmd socket for a VMI
198
func FindPodDirOnHost(vmi *v1.VirtualMachineInstance) (string, error) {
1✔
199

1✔
200
        // It is possible for multiple pods to be active on a single VMI
1✔
201
        // during migrations. This loop will discover the active pod on
1✔
202
        // this particular local node if it exists. A active pod not
1✔
203
        // running on this node will not have a kubelet pods directory,
1✔
204
        // so it will not be found.
1✔
205
        for podUID := range vmi.Status.ActivePods {
2✔
206
                socketPodDir := SocketDirectoryOnHost(string(podUID))
1✔
207
                exists, _ := diskutils.FileExists(socketPodDir)
1✔
208
                if exists {
2✔
209
                        return socketPodDir, nil
1✔
210
                }
1✔
211
        }
212

213
        return "", fmt.Errorf("No command socketdir for vmi %s", vmi.UID)
×
214
}
215

216
// gets the cmd socket for a VMI
217
func FindSocketOnHost(vmi *v1.VirtualMachineInstance) (string, error) {
1✔
218
        socketsFound := 0
1✔
219
        foundSocket := ""
1✔
220
        // It is possible for multiple pods to be active on a single VMI
1✔
221
        // during migrations. This loop will discover the active pod on
1✔
222
        // this particular local node if it exists. A active pod not
1✔
223
        // running on this node will not have a kubelet pods directory,
1✔
224
        // so it will not be found.
1✔
225
        for podUID := range vmi.Status.ActivePods {
2✔
226
                socket := SocketFilePathOnHost(string(podUID))
1✔
227
                exists, _ := diskutils.FileExists(socket)
1✔
228
                if exists {
2✔
229
                        foundSocket = socket
1✔
230
                        socketsFound++
1✔
231
                }
1✔
232
        }
233

234
        if socketsFound == 1 {
2✔
235
                return foundSocket, nil
1✔
236
        } else if socketsFound > 1 {
2✔
237
                return "", fmt.Errorf("Found multiple sockets for vmi %s/%s. waiting for only one to exist", vmi.Namespace, vmi.Name)
×
238
        }
×
239

240
        return "", fmt.Errorf("No command socket found for vmi %s", vmi.UID)
1✔
241
}
242

243
func SocketOnGuest() string {
1✔
244
        sockFile := StandardLauncherSocketFileName
1✔
245
        return filepath.Join(SocketsDirectory(), sockFile)
1✔
246
}
1✔
247

248
func UninitializedSocketOnGuest() string {
×
249
        sockFile := StandardInitLauncherSocketFileName
×
250
        return filepath.Join(SocketsDirectory(), sockFile)
×
251
}
×
252

253
func NewClient(socketPath string) (LauncherClient, error) {
1✔
254
        // dial socket
1✔
255
        conn, err := grpcutil.DialSocket(socketPath)
1✔
256
        if err != nil {
2✔
257
                log.Log.Reason(err).Infof("failed to dial cmd socket: %s", socketPath)
1✔
258
                return nil, err
1✔
259
        }
1✔
260

261
        // create info client and find cmd version to use
262
        infoClient := info.NewCmdInfoClient(conn)
1✔
263
        return NewClientWithInfoClient(infoClient, conn)
1✔
264
}
265

266
func NewClientWithInfoClient(infoClient info.CmdInfoClient, conn *grpc.ClientConn) (LauncherClient, error) {
1✔
267
        ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
1✔
268
        defer cancel()
1✔
269
        info, err := infoClient.Info(ctx, &info.CmdInfoRequest{})
1✔
270
        if err != nil {
1✔
271
                return nil, fmt.Errorf("could not check cmd server version: %v", err)
×
272
        }
×
273
        version, err := com.GetHighestCompatibleVersion(info.SupportedCmdVersions, supportedCmdVersions)
1✔
274
        if err != nil {
2✔
275
                return nil, err
1✔
276
        }
1✔
277

278
        // create cmd client
279
        switch version {
1✔
280
        case 1:
1✔
281
                client := cmdv1.NewCmdClient(conn)
1✔
282
                return newV1Client(client, conn), nil
1✔
283
        default:
×
284
                return nil, fmt.Errorf("cmd client version %v not implemented yet", version)
×
285
        }
286
}
287

288
func newV1Client(client cmdv1.CmdClient, conn *grpc.ClientConn) LauncherClient {
1✔
289
        return &VirtLauncherClient{
1✔
290
                v1client: client,
1✔
291
                conn:     conn,
1✔
292
        }
1✔
293
}
1✔
294

295
func (c *VirtLauncherClient) Close() {
1✔
296
        c.conn.Close()
1✔
297
}
1✔
298

299
func (c *VirtLauncherClient) genericSendVMICmd(cmdName string,
300
        cmdFunc func(ctx context.Context, request *cmdv1.VMIRequest, opts ...grpc.CallOption) (*cmdv1.Response, error),
301
        vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error {
1✔
302

1✔
303
        vmiJson, err := json.Marshal(vmi)
1✔
304
        if err != nil {
1✔
305
                return err
×
306
        }
×
307

308
        request := &cmdv1.VMIRequest{
1✔
309
                Vmi: &cmdv1.VMI{
1✔
310
                        VmiJson: vmiJson,
1✔
311
                },
1✔
312
                Options: options,
1✔
313
        }
1✔
314

1✔
315
        ctx, cancel := context.WithTimeout(context.Background(), longTimeout)
1✔
316
        defer cancel()
1✔
317
        response, err := cmdFunc(ctx, request)
1✔
318

1✔
319
        err = handleError(err, cmdName, response)
1✔
320
        return err
1✔
321
}
322
func IsUnimplemented(err error) bool {
1✔
323
        if grpcStatus, ok := status.FromError(err); ok {
2✔
324
                if grpcStatus.Code() == codes.Unimplemented {
1✔
325
                        return true
×
326
                }
×
327
        }
328
        return false
1✔
329
}
330
func handleError(err error, cmdName string, response *cmdv1.Response) error {
1✔
331
        if IsDisconnected(err) {
2✔
332
                return err
1✔
333
        } else if IsUnimplemented(err) {
2✔
334
                return err
×
335
        } else if err != nil {
1✔
336
                msg := fmt.Sprintf("unknown error encountered sending command %s: %s", cmdName, err.Error())
×
337
                return fmt.Errorf(msg)
×
338
        } else if response != nil && !response.Success {
2✔
339
                return fmt.Errorf("server error. command %s failed: %q", cmdName, response.Message)
1✔
340
        }
1✔
341
        return nil
1✔
342
}
343

344
func IsDisconnected(err error) bool {
1✔
345
        if err == nil {
2✔
346
                return false
1✔
347
        }
1✔
348

349
        if err == rpc.ErrShutdown || err == io.ErrUnexpectedEOF || err == io.EOF {
1✔
350
                return true
×
351
        }
×
352

353
        if opErr, ok := err.(*net.OpError); ok {
1✔
354
                if syscallErr, ok := opErr.Err.(*os.SyscallError); ok {
×
355
                        // catches "connection reset by peer"
×
356
                        if syscallErr.Err == syscall.ECONNRESET {
×
357
                                return true
×
358
                        }
×
359
                }
360
        }
361

362
        if grpcStatus, ok := status.FromError(err); ok {
2✔
363

1✔
364
                // see https://github.com/grpc/grpc-go/blob/master/codes/codes.go
1✔
365
                switch grpcStatus.Code() {
1✔
366
                case codes.Canceled:
1✔
367
                        // e.g. v1client connection closing
1✔
368
                        return true
1✔
369
                }
370

371
        }
372

373
        return false
×
374
}
375

376
func (c *VirtLauncherClient) SyncVirtualMachine(vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error {
1✔
377
        return c.genericSendVMICmd("SyncVMI", c.v1client.SyncVirtualMachine, vmi, options)
1✔
378
}
1✔
379

380
func (c *VirtLauncherClient) PauseVirtualMachine(vmi *v1.VirtualMachineInstance) error {
1✔
381
        return c.genericSendVMICmd("Pause", c.v1client.PauseVirtualMachine, vmi, &cmdv1.VirtualMachineOptions{})
1✔
382
}
1✔
383

384
func (c *VirtLauncherClient) UnpauseVirtualMachine(vmi *v1.VirtualMachineInstance) error {
1✔
385
        return c.genericSendVMICmd("Unpause", c.v1client.UnpauseVirtualMachine, vmi, &cmdv1.VirtualMachineOptions{})
1✔
386
}
1✔
387

388
func (c *VirtLauncherClient) FreezeVirtualMachine(vmi *v1.VirtualMachineInstance, unfreezeTimeoutSeconds int32) error {
1✔
389
        vmiJson, err := json.Marshal(vmi)
1✔
390
        if err != nil {
1✔
391
                return err
×
392
        }
×
393

394
        request := &cmdv1.FreezeRequest{
1✔
395
                Vmi: &cmdv1.VMI{
1✔
396
                        VmiJson: vmiJson,
1✔
397
                },
1✔
398
                UnfreezeTimeoutSeconds: unfreezeTimeoutSeconds,
1✔
399
        }
1✔
400

1✔
401
        ctx, cancel := context.WithTimeout(context.Background(), longTimeout)
1✔
402
        defer cancel()
1✔
403
        response, err := c.v1client.FreezeVirtualMachine(ctx, request)
1✔
404

1✔
405
        err = handleError(err, "Freeze", response)
1✔
406
        return err
1✔
407
}
408

409
func (c *VirtLauncherClient) UnfreezeVirtualMachine(vmi *v1.VirtualMachineInstance) error {
1✔
410
        return c.genericSendVMICmd("Unfreeze", c.v1client.UnfreezeVirtualMachine, vmi, &cmdv1.VirtualMachineOptions{})
1✔
411
}
1✔
412

413
func (c *VirtLauncherClient) VirtualMachineMemoryDump(vmi *v1.VirtualMachineInstance, dumpPath string) error {
1✔
414
        vmiJson, err := json.Marshal(vmi)
1✔
415
        if err != nil {
1✔
416
                return err
×
417
        }
×
418

419
        request := &cmdv1.MemoryDumpRequest{
1✔
420
                Vmi: &cmdv1.VMI{
1✔
421
                        VmiJson: vmiJson,
1✔
422
                },
1✔
423
                DumpPath: dumpPath,
1✔
424
        }
1✔
425

1✔
426
        ctx, cancel := context.WithTimeout(context.Background(), longTimeout)
1✔
427
        defer cancel()
1✔
428
        response, err := c.v1client.VirtualMachineMemoryDump(ctx, request)
1✔
429
        err = handleError(err, "Memorydump", response)
1✔
430
        return err
1✔
431
}
432

433
func (c *VirtLauncherClient) SoftRebootVirtualMachine(vmi *v1.VirtualMachineInstance) error {
1✔
434
        return c.genericSendVMICmd("SoftReboot", c.v1client.SoftRebootVirtualMachine, vmi, &cmdv1.VirtualMachineOptions{})
1✔
435
}
1✔
436

437
func (c *VirtLauncherClient) ResetVirtualMachine(vmi *v1.VirtualMachineInstance) error {
1✔
438
        return c.genericSendVMICmd("Reset", c.v1client.ResetVirtualMachine, vmi, &cmdv1.VirtualMachineOptions{})
1✔
439
}
1✔
440

441
func (c *VirtLauncherClient) ShutdownVirtualMachine(vmi *v1.VirtualMachineInstance) error {
1✔
442
        return c.genericSendVMICmd("Shutdown", c.v1client.ShutdownVirtualMachine, vmi, &cmdv1.VirtualMachineOptions{})
1✔
443
}
1✔
444

445
func (c *VirtLauncherClient) KillVirtualMachine(vmi *v1.VirtualMachineInstance) error {
1✔
446
        return c.genericSendVMICmd("Kill", c.v1client.KillVirtualMachine, vmi, &cmdv1.VirtualMachineOptions{})
1✔
447
}
1✔
448

449
func (c *VirtLauncherClient) DeleteDomain(vmi *v1.VirtualMachineInstance) error {
×
450
        return c.genericSendVMICmd("Delete", c.v1client.DeleteVirtualMachine, vmi, &cmdv1.VirtualMachineOptions{})
×
451
}
×
452

453
func (c *VirtLauncherClient) MigrateVirtualMachine(vmi *v1.VirtualMachineInstance, options *MigrationOptions) error {
×
454

×
455
        vmiJson, err := json.Marshal(vmi)
×
456
        if err != nil {
×
457
                return err
×
458
        }
×
459

460
        optionsJson, err := json.Marshal(options)
×
461
        if err != nil {
×
462
                return err
×
463
        }
×
464

465
        request := &cmdv1.MigrationRequest{
×
466
                Vmi: &cmdv1.VMI{
×
467
                        VmiJson: vmiJson,
×
468
                },
×
469
                Options: optionsJson,
×
470
        }
×
471

×
472
        ctx, cancel := context.WithTimeout(context.Background(), longTimeout)
×
473
        defer cancel()
×
474
        response, err := c.v1client.MigrateVirtualMachine(ctx, request)
×
475

×
476
        err = handleError(err, "Migrate", response)
×
477
        return err
×
478

479
}
480

481
func (c *VirtLauncherClient) CancelVirtualMachineMigration(vmi *v1.VirtualMachineInstance) error {
×
482
        return c.genericSendVMICmd("CancelMigration", c.v1client.CancelVirtualMachineMigration, vmi, &cmdv1.VirtualMachineOptions{})
×
483
}
×
484

485
func (c *VirtLauncherClient) SyncMigrationTarget(vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error {
×
486
        return c.genericSendVMICmd("SyncMigrationTarget", c.v1client.SyncMigrationTarget, vmi, options)
×
487
}
×
488

489
func (c *VirtLauncherClient) SyncVirtualMachineCPUs(vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error {
×
490
        return c.genericSendVMICmd("SyncVirtualMachineCPUs", c.v1client.SyncVirtualMachineCPUs, vmi, options)
×
491
}
×
492

493
func (c *VirtLauncherClient) SignalTargetPodCleanup(vmi *v1.VirtualMachineInstance) error {
×
494
        return c.genericSendVMICmd("SignalTargetPodCleanup", c.v1client.SignalTargetPodCleanup, vmi, &cmdv1.VirtualMachineOptions{})
×
495
}
×
496

497
func (c *VirtLauncherClient) FinalizeVirtualMachineMigration(vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error {
1✔
498
        return c.genericSendVMICmd("FinalizeVirtualMachineMigration", c.v1client.FinalizeVirtualMachineMigration, vmi, options)
1✔
499
}
1✔
500

501
func (c *VirtLauncherClient) HotplugHostDevices(vmi *v1.VirtualMachineInstance) error {
×
502
        return c.genericSendVMICmd("HotplugHostDevices", c.v1client.HotplugHostDevices, vmi, &cmdv1.VirtualMachineOptions{})
×
503
}
×
504

505
func (c *VirtLauncherClient) GetDomain() (*api.Domain, bool, error) {
1✔
506

1✔
507
        domain := &api.Domain{}
1✔
508
        exists := false
1✔
509

1✔
510
        request := &cmdv1.EmptyRequest{}
1✔
511
        ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
1✔
512
        defer cancel()
1✔
513

1✔
514
        domainResponse, err := c.v1client.GetDomain(ctx, request)
1✔
515
        var response *cmdv1.Response
1✔
516
        if domainResponse != nil {
2✔
517
                response = domainResponse.Response
1✔
518
        }
1✔
519

520
        if err = handleError(err, "GetDomain", response); err != nil || domainResponse == nil {
1✔
521
                return domain, exists, err
×
522
        }
×
523

524
        if domainResponse.Domain != "" {
2✔
525
                if err := json.Unmarshal([]byte(domainResponse.Domain), domain); err != nil {
1✔
526
                        log.Log.Reason(err).Error("error unmarshalling domain")
×
527
                        return domain, exists, err
×
528
                }
×
529
                exists = true
1✔
530
        }
531
        return domain, exists, nil
1✔
532
}
533

534
func (c *VirtLauncherClient) GetQemuVersion() (string, error) {
1✔
535
        request := &cmdv1.EmptyRequest{}
1✔
536
        ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
1✔
537
        defer cancel()
1✔
538

1✔
539
        versionResponse, err := c.v1client.GetQemuVersion(ctx, request)
1✔
540
        var response *cmdv1.Response
1✔
541
        if versionResponse != nil {
2✔
542
                response = versionResponse.Response
1✔
543
        }
1✔
544
        if err = handleError(err, "GetQemuVersion", response); err != nil {
1✔
545
                return "", err
×
546
        }
×
547

548
        if versionResponse != nil && versionResponse.Version != "" {
2✔
549
                return versionResponse.Version, nil
1✔
550
        }
1✔
551

552
        log.Log.Reason(err).Error("error getting the qemu version")
×
553
        return "", errors.New("error getting the qemu version")
×
554
}
555

556
func (c *VirtLauncherClient) GetDomainStats() (*stats.DomainStats, bool, error) {
1✔
557
        stats := &stats.DomainStats{}
1✔
558
        exists := false
1✔
559

1✔
560
        request := &cmdv1.EmptyRequest{}
1✔
561
        ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
1✔
562
        defer cancel()
1✔
563

1✔
564
        domainStatsResponse, err := c.v1client.GetDomainStats(ctx, request)
1✔
565
        var response *cmdv1.Response
1✔
566
        if domainStatsResponse != nil {
2✔
567
                response = domainStatsResponse.Response
1✔
568
        }
1✔
569

570
        if err = handleError(err, "GetDomainStats", response); err != nil || domainStatsResponse == nil {
1✔
571
                return stats, exists, err
×
572
        }
×
573

574
        if domainStatsResponse.DomainStats != "" {
2✔
575
                if err := json.Unmarshal([]byte(domainStatsResponse.DomainStats), stats); err != nil {
1✔
576
                        log.Log.Reason(err).Error("error unmarshalling domain")
×
577
                        return stats, exists, err
×
578
                }
×
579
                exists = true
1✔
580
        }
581
        return stats, exists, nil
1✔
582
}
583

584
func (c *VirtLauncherClient) Ping() error {
1✔
585
        request := &cmdv1.EmptyRequest{}
1✔
586
        ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
1✔
587
        defer cancel()
1✔
588
        response, err := c.v1client.Ping(ctx, request)
1✔
589

1✔
590
        err = handleError(err, "Ping", response)
1✔
591
        return err
1✔
592
}
1✔
593

594
// GetGuestInfo is a counterpart for virt-launcher call to gather guest agent data
595
func (c *VirtLauncherClient) GetGuestInfo() (*v1.VirtualMachineInstanceGuestAgentInfo, error) {
×
596
        guestInfo := &v1.VirtualMachineInstanceGuestAgentInfo{}
×
597

×
598
        request := &cmdv1.EmptyRequest{}
×
599
        ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
×
600
        defer cancel()
×
601

×
602
        gaRespose, err := c.v1client.GetGuestInfo(ctx, request)
×
603
        var response *cmdv1.Response
×
604
        if gaRespose != nil {
×
605
                response = gaRespose.Response
×
606
        }
×
607

NEW
608
        if err = handleError(err, "GetGuestInfo", response); err != nil || gaRespose == nil {
×
609
                return guestInfo, err
×
610
        }
×
611

612
        if gaRespose.GuestInfoResponse != "" {
×
613
                if err := json.Unmarshal([]byte(gaRespose.GetGuestInfoResponse()), guestInfo); err != nil {
×
614
                        log.Log.Reason(err).Error("error unmarshalling guest agent response")
×
615
                        return guestInfo, err
×
616
                }
×
617
        }
618
        return guestInfo, nil
×
619
}
620

621
// GetUsers returns the list of the active users on the guest machine
622
func (c *VirtLauncherClient) GetUsers() (v1.VirtualMachineInstanceGuestOSUserList, error) {
1✔
623
        var userList []v1.VirtualMachineInstanceGuestOSUser
1✔
624

1✔
625
        request := &cmdv1.EmptyRequest{}
1✔
626
        ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
1✔
627
        defer cancel()
1✔
628

1✔
629
        uResponse, err := c.v1client.GetUsers(ctx, request)
1✔
630
        var response *cmdv1.Response
1✔
631
        if uResponse != nil {
2✔
632
                response = uResponse.Response
1✔
633
        }
1✔
634

635
        if err = handleError(err, "GetUsers", response); err != nil || uResponse == nil {
1✔
636
                return v1.VirtualMachineInstanceGuestOSUserList{}, err
×
637
        }
×
638

639
        if uResponse.GetGuestUserListResponse() != "" {
2✔
640
                if err := json.Unmarshal([]byte(uResponse.GetGuestUserListResponse()), &userList); err != nil {
1✔
641
                        log.Log.Reason(err).Error("error unmarshalling guest user list response")
×
642
                        return v1.VirtualMachineInstanceGuestOSUserList{}, err
×
643
                }
×
644
        }
645

646
        guestUserList := v1.VirtualMachineInstanceGuestOSUserList{
1✔
647
                Items: userList,
1✔
648
        }
1✔
649

1✔
650
        return guestUserList, nil
1✔
651
}
652

653
// GetFilesystems returns the list of active filesystems on the guest machine
654
func (c *VirtLauncherClient) GetFilesystems() (v1.VirtualMachineInstanceFileSystemList, error) {
1✔
655
        var fsList []v1.VirtualMachineInstanceFileSystem
1✔
656

1✔
657
        request := &cmdv1.EmptyRequest{}
1✔
658
        ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
1✔
659
        defer cancel()
1✔
660

1✔
661
        fsResponse, err := c.v1client.GetFilesystems(ctx, request)
1✔
662
        var response *cmdv1.Response
1✔
663
        if fsResponse != nil {
2✔
664
                response = fsResponse.Response
1✔
665
        }
1✔
666

667
        if err = handleError(err, "GetFilesystems", response); err != nil || fsResponse == nil {
1✔
668
                return v1.VirtualMachineInstanceFileSystemList{}, err
×
669
        }
×
670

671
        if fsResponse.GetGuestFilesystemsResponse() != "" {
2✔
672
                if err := json.Unmarshal([]byte(fsResponse.GetGuestFilesystemsResponse()), &fsList); err != nil {
1✔
673
                        log.Log.Reason(err).Error("error unmarshalling guest filesystem list response")
×
674
                        return v1.VirtualMachineInstanceFileSystemList{}, err
×
675
                }
×
676
        }
677

678
        filesystemList := v1.VirtualMachineInstanceFileSystemList{
1✔
679
                Items: fsList,
1✔
680
        }
1✔
681

1✔
682
        return filesystemList, nil
1✔
683
}
684

685
// Exec the command with args on the guest and return the resulting status code, stdOut and error
686
func (c *VirtLauncherClient) Exec(domainName, command string, args []string, timeoutSeconds int32) (int, string, error) {
1✔
687
        request := &cmdv1.ExecRequest{
1✔
688
                DomainName:     domainName,
1✔
689
                Command:        command,
1✔
690
                Args:           args,
1✔
691
                TimeoutSeconds: timeoutSeconds,
1✔
692
        }
1✔
693
        exitCode := -1
1✔
694
        stdOut := ""
1✔
695

1✔
696
        ctx, cancel := context.WithTimeout(
1✔
697
                context.Background(),
1✔
698
                // we give the context a bit more time as the timeout should kick
1✔
699
                // on the actual execution
1✔
700
                time.Duration(timeoutSeconds)*time.Second+shortTimeout,
1✔
701
        )
1✔
702
        defer cancel()
1✔
703

1✔
704
        resp, err := c.v1client.Exec(ctx, request)
1✔
705
        if resp == nil {
2✔
706
                return exitCode, stdOut, err
1✔
707
        }
1✔
708

709
        exitCode = int(resp.ExitCode)
1✔
710
        stdOut = resp.StdOut
1✔
711

1✔
712
        return exitCode, stdOut, err
1✔
713
}
714

715
func (c *VirtLauncherClient) GuestPing(domainName string, timeoutSeconds int32) error {
1✔
716
        request := &cmdv1.GuestPingRequest{
1✔
717
                DomainName:     domainName,
1✔
718
                TimeoutSeconds: timeoutSeconds,
1✔
719
        }
1✔
720
        ctx, cancel := context.WithTimeout(
1✔
721
                context.Background(),
1✔
722
                // we give the context a bit more time as the timeout should kick
1✔
723
                // on the actual execution
1✔
724
                time.Duration(timeoutSeconds)*time.Second+shortTimeout,
1✔
725
        )
1✔
726
        defer cancel()
1✔
727

1✔
728
        _, err := c.v1client.GuestPing(ctx, request)
1✔
729
        return err
1✔
730
}
1✔
731

732
func (c *VirtLauncherClient) GetSEVInfo() (*v1.SEVPlatformInfo, error) {
1✔
733
        request := &cmdv1.EmptyRequest{}
1✔
734
        ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
1✔
735
        defer cancel()
1✔
736

1✔
737
        sevInfoResponse, err := c.v1client.GetSEVInfo(ctx, request)
1✔
738
        if err = handleError(err, "GetSEVInfo", sevInfoResponse.GetResponse()); err != nil {
1✔
739
                return nil, err
×
740
        }
×
741

742
        sevPlatformInfo := &v1.SEVPlatformInfo{}
1✔
743
        if err := json.Unmarshal(sevInfoResponse.GetSevInfo(), sevPlatformInfo); err != nil {
1✔
744
                log.Log.Reason(err).Error("error unmarshalling SEV info response")
×
745
                return nil, err
×
746
        }
×
747

748
        return sevPlatformInfo, nil
1✔
749
}
750

751
func (c *VirtLauncherClient) GetLaunchMeasurement(vmi *v1.VirtualMachineInstance) (*v1.SEVMeasurementInfo, error) {
1✔
752
        vmiJson, err := json.Marshal(vmi)
1✔
753
        if err != nil {
1✔
754
                return nil, err
×
755
        }
×
756

757
        request := &cmdv1.VMIRequest{
1✔
758
                Vmi: &cmdv1.VMI{
1✔
759
                        VmiJson: vmiJson,
1✔
760
                },
1✔
761
        }
1✔
762

1✔
763
        ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
1✔
764
        defer cancel()
1✔
765

1✔
766
        launchMeasurementRespose, err := c.v1client.GetLaunchMeasurement(ctx, request)
1✔
767
        if err = handleError(err, "GetLaunchMeasurement", launchMeasurementRespose.GetResponse()); err != nil {
1✔
768
                return nil, err
×
769
        }
×
770

771
        sevMeasurementInfo := &v1.SEVMeasurementInfo{}
1✔
772
        if err := json.Unmarshal(launchMeasurementRespose.GetLaunchMeasurement(), sevMeasurementInfo); err != nil {
1✔
773
                log.Log.Reason(err).Error("error unmarshalling launch measurement response")
×
774
                return nil, err
×
775
        }
×
776

777
        return sevMeasurementInfo, nil
1✔
778
}
779

780
func (c *VirtLauncherClient) InjectLaunchSecret(vmi *v1.VirtualMachineInstance, sevSecretOptions *v1.SEVSecretOptions) error {
1✔
781
        vmiJson, err := json.Marshal(vmi)
1✔
782
        if err != nil {
1✔
783
                return err
×
784
        }
×
785

786
        optionsJson, err := json.Marshal(sevSecretOptions)
1✔
787
        if err != nil {
1✔
788
                return err
×
789
        }
×
790

791
        request := &cmdv1.InjectLaunchSecretRequest{
1✔
792
                Vmi: &cmdv1.VMI{
1✔
793
                        VmiJson: vmiJson,
1✔
794
                },
1✔
795
                Options: optionsJson,
1✔
796
        }
1✔
797

1✔
798
        ctx, cancel := context.WithTimeout(context.Background(), longTimeout)
1✔
799
        defer cancel()
1✔
800

1✔
801
        response, err := c.v1client.InjectLaunchSecret(ctx, request)
1✔
802

1✔
803
        return handleError(err, "InjectLaunchSecret", response)
1✔
804
}
805

806
func (c *VirtLauncherClient) SyncVirtualMachineMemory(vmi *v1.VirtualMachineInstance, options *cmdv1.VirtualMachineOptions) error {
1✔
807
        return c.genericSendVMICmd("SyncVirtualMachineMemory", c.v1client.SyncVirtualMachineMemory, vmi, options)
1✔
808
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc