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