]> git.proxmox.com Git - qemu-server.git/blob - PVE/API2/Qemu/Agent.pm
implement set-user-password guest agent api call
[qemu-server.git] / PVE / API2 / Qemu / Agent.pm
1 package PVE::API2::Qemu::Agent;
2
3 use strict;
4 use warnings;
5
6 use PVE::RESTHandler;
7 use PVE::JSONSchema qw(get_standard_option);
8 use PVE::QemuServer;
9 use PVE::QemuServer::Agent qw(agent_available);
10 use MIME::Base64 qw(encode_base64 decode_base64);
11 use JSON;
12
13 use base qw(PVE::RESTHandler);
14
15 # list of commands
16 # will generate one api endpoint per command
17 # needs a 'method' property and optionally a 'perms' property (default VM.Monitor)
18 my $guest_agent_commands = {
19 'ping' => {
20 method => 'POST',
21 },
22 'get-time' => {
23 method => 'GET',
24 },
25 'info' => {
26 method => 'GET',
27 },
28 'fsfreeze-status' => {
29 method => 'POST',
30 },
31 'fsfreeze-freeze' => {
32 method => 'POST',
33 },
34 'fsfreeze-thaw' => {
35 method => 'POST',
36 },
37 'fstrim' => {
38 method => 'POST',
39 },
40 'network-get-interfaces' => {
41 method => 'GET',
42 },
43 'get-vcpus' => {
44 method => 'GET',
45 },
46 'get-fsinfo' => {
47 method => 'GET',
48 },
49 'get-memory-blocks' => {
50 method => 'GET',
51 },
52 'get-memory-block-info' => {
53 method => 'GET',
54 },
55 'suspend-hybrid' => {
56 method => 'POST',
57 },
58 'suspend-ram' => {
59 method => 'POST',
60 },
61 'suspend-disk' => {
62 method => 'POST',
63 },
64 'shutdown' => {
65 method => 'POST',
66 },
67 # added since qemu 2.9
68 'get-host-name' => {
69 method => 'GET',
70 },
71 'get-osinfo' => {
72 method => 'GET',
73 },
74 'get-users' => {
75 method => 'GET',
76 },
77 'get-timezone' => {
78 method => 'GET',
79 },
80 };
81
82 __PACKAGE__->register_method({
83 name => 'index',
84 path => '',
85 proxyto => 'node',
86 method => 'GET',
87 description => "Qemu Agent command index.",
88 permissions => {
89 user => 'all',
90 },
91 parameters => {
92 additionalProperties => 1,
93 properties => {
94 node => get_standard_option('pve-node'),
95 vmid => get_standard_option('pve-vmid', {
96 completion => \&PVE::QemuServer::complete_vmid_running }),
97 },
98 },
99 returns => {
100 type => 'array',
101 items => {
102 type => "object",
103 properties => {},
104 },
105 links => [ { rel => 'child', href => '{name}' } ],
106 description => "Returns the list of Qemu Agent commands",
107 },
108 code => sub {
109 my ($param) = @_;
110
111 my $result = [];
112
113 my $cmds = [keys %$guest_agent_commands];
114 push @$cmds, qw(
115 set-user-password
116 );
117
118 for my $cmd ( sort @$cmds) {
119 push @$result, { name => $cmd };
120 }
121
122 return $result;
123 }});
124
125 sub register_command {
126 my ($class, $command, $method, $perm) = @_;
127
128 die "no method given\n" if !$method;
129 die "no command given\n" if !defined($command);
130
131 my $permission;
132
133 if (ref($perm) eq 'HASH') {
134 $permission = $perm;
135 } else {
136 $perm //= 'VM.Monitor';
137 $permission = { check => [ 'perm', '/vms/{vmid}', [ $perm ]]};
138 }
139
140 my $parameters = {
141 additionalProperties => 0,
142 properties => {
143 node => get_standard_option('pve-node'),
144 vmid => get_standard_option('pve-vmid', {
145 completion => \&PVE::QemuServer::complete_vmid_running }),
146 command => {
147 type => 'string',
148 description => "The QGA command.",
149 enum => [ sort keys %$guest_agent_commands ],
150 },
151 },
152 };
153
154 my $description = "Execute Qemu Guest Agent commands.";
155 my $name = 'agent';
156
157 if ($command ne '') {
158 $description = "Execute $command.";
159 $name = $command;
160 delete $parameters->{properties}->{command};
161 }
162
163 __PACKAGE__->register_method({
164 name => $name,
165 path => $command,
166 method => $method,
167 protected => 1,
168 proxyto => 'node',
169 description => $description,
170 permissions => $permission,
171 parameters => $parameters,
172 returns => {
173 type => 'object',
174 description => "Returns an object with a single `result` property.",
175 },
176 code => sub {
177 my ($param) = @_;
178
179 my $vmid = $param->{vmid};
180
181 my $conf = PVE::QemuConfig->load_config ($vmid); # check if VM exists
182
183 agent_available($vmid, $conf);
184
185 my $cmd = $param->{command} // $command;
186 my $res = PVE::QemuServer::vm_mon_cmd($vmid, "guest-$cmd");
187
188 return { result => $res };
189 }});
190 }
191
192 # old {vmid}/agent POST endpoint, here for compatibility
193 __PACKAGE__->register_command('', 'POST');
194
195 for my $cmd (sort keys %$guest_agent_commands) {
196 my $props = $guest_agent_commands->{$cmd};
197 __PACKAGE__->register_command($cmd, $props->{method}, $props->{perms});
198 }
199
200 # commands with parameters are complicated and we want to register them manually
201 __PACKAGE__->register_method({
202 name => 'set-user-password',
203 path => 'set-user-password',
204 method => 'POST',
205 protected => 1,
206 proxyto => 'node',
207 description => "Sets the password for the given user to the given password",
208 permissions => { check => [ 'perm', '/vms/{vmid}', [ 'VM.Monitor' ]]},
209 parameters => {
210 additionalProperties => 0,
211 properties => {
212 node => get_standard_option('pve-node'),
213 vmid => get_standard_option('pve-vmid', {
214 completion => \&PVE::QemuServer::complete_vmid_running }),
215 username => {
216 type => 'string',
217 description => 'The user to set the password for.'
218 },
219 password => {
220 type => 'string',
221 description => 'The new password.',
222 minLength => 5,
223 maxLength => 64,
224 },
225 crypted => {
226 type => 'boolean',
227 description => 'set to 1 if the password has already been passed through crypt()',
228 optional => 1,
229 default => 0,
230 },
231 },
232 },
233 returns => {
234 type => 'object',
235 description => "Returns an object with a single `result` property.",
236 },
237 code => sub {
238 my ($param) = @_;
239
240 my $vmid = $param->{vmid};
241
242 my $crypted = $param->{crypted} // 0;
243 my $args = {
244 username => $param->{username},
245 password => encode_base64($param->{password}),
246 crypted => $crypted ? JSON::true : JSON::false,
247 };
248 my $res = agent_cmd($vmid, "set-user-password", %$args, 'cannot set user password');
249
250 return { result => $res };
251 }});
252
253 1;