]> git.proxmox.com Git - qemu-server.git/blame - PVE/QemuServer/Agent.pm
fix #2244: Allow timeout for guest-agent shutdown
[qemu-server.git] / PVE / QemuServer / Agent.pm
CommitLineData
3824765e
DC
1package PVE::QemuServer::Agent;
2
3use strict;
4use warnings;
804fffdf 5
3824765e 6use PVE::QemuServer;
8efdf418
DC
7use MIME::Base64 qw(decode_base64);
8use JSON;
3824765e
DC
9use base 'Exporter';
10
11our @EXPORT_OK = qw(
12check_agent_error
13agent_available
14agent_cmd
15);
16
17sub check_agent_error {
18 my ($result, $errmsg, $noerr) = @_;
19
20 $errmsg //= '';
21 my $error = '';
22 if (ref($result) eq 'HASH' && $result->{error} && $result->{error}->{desc}) {
804fffdf 23 $error = "Agent error: $result->{error}->{desc}\n";
3824765e 24 } elsif (!defined($result)) {
804fffdf 25 $error = "Agent error: $errmsg\n";
3824765e
DC
26 }
27
28 if ($error) {
29 die $error if !$noerr;
30
31 warn $error;
32 return undef;
33 }
34
35 return 1;
36}
37
38sub agent_available {
39 my ($vmid, $conf, $noerr) = @_;
40
41 eval {
804fffdf 42 die "No QEMU guest agent configured\n" if !defined($conf->{agent});
3824765e 43 die "VM $vmid is not running\n" if !PVE::QemuServer::check_running($vmid);
804fffdf 44 die "QEMU guest agent is not running\n" if !PVE::QemuServer::qga_check_running($vmid, 1);
3824765e
DC
45 };
46
47 if (my $err = $@) {
48 die $err if !$noerr;
49 return undef;
50 }
51
52 return 1;
53}
54
55# loads config, checks if available, executes command, checks for errors
56sub agent_cmd {
57 my ($vmid, $cmd, $params, $errormsg, $noerr) = @_;
58
59 my $conf = PVE::QemuConfig->load_config($vmid); # also checks if VM exists
60 agent_available($vmid, $conf, $noerr);
61
62 my $res = PVE::QemuServer::vm_mon_cmd($vmid, "guest-$cmd", %$params);
63 check_agent_error($res, $errormsg, $noerr);
64
65 return $res;
66}
67
8efdf418
DC
68sub qemu_exec {
69 my ($vmid, $cmd) = @_;
70
71
72 my $path = shift @$cmd;
73 my $arguments = $cmd;
74
75 my $args = {
76 path => $path,
77 arg => $arguments,
78 'capture-output' => JSON::true,
79 };
80 my $res = agent_cmd($vmid, "exec", $args, "can't execute command '$path $arguments'");
81
82 return $res;
83}
84
85sub qemu_exec_status {
86 my ($vmid, $pid) = @_;
87
88 my $res = agent_cmd($vmid, "exec-status", { pid => $pid }, "can't get exec status for '$pid'");
89
90 if ($res->{'out-data'}) {
91 my $decoded = eval { decode_base64($res->{'out-data'}) };
92 warn $@ if $@;
93 if (defined($decoded)) {
94 $res->{'out-data'} = $decoded;
95 }
96 }
97
98 if ($res->{'err-data'}) {
99 my $decoded = eval { decode_base64($res->{'err-data'}) };
100 warn $@ if $@;
101 if (defined($decoded)) {
102 $res->{'err-data'} = $decoded;
103 }
104 }
105
106 # convert JSON::Boolean to 1/0
107 foreach my $d (keys %$res) {
108 if (JSON::is_bool($res->{$d})) {
109 $res->{$d} = ($res->{$d})? 1 : 0;
110 }
111 }
112
113 return $res;
114}
115
3824765e 1161;