]> git.proxmox.com Git - pve-manager.git/blame - PVE/API2Tools.pm
bump version to 5.1-37
[pve-manager.git] / PVE / API2Tools.pm
CommitLineData
19a6b9f1
DM
1package PVE::API2Tools;
2
3use strict;
4use warnings;
a3eff2d9
DM
5use Net::IP;
6
3c54bc91 7use PVE::Exception qw(raise_param_exc);
2ba6d822 8use PVE::Tools;
eb6d7497 9use PVE::INotify;
3c54bc91 10use PVE::Cluster;
2ba6d822 11use Digest::MD5 qw(md5_hex);
446b9669
DM
12use URI;
13use URI::Escape;
b289829f 14use PVE::SafeSyslog;
2ba6d822
DM
15
16my $hwaddress;
17
18sub get_hwaddress {
19
20 return $hwaddress if defined ($hwaddress);
21
22 my $fn = '/etc/ssh/ssh_host_rsa_key.pub';
23 my $sshkey = PVE::Tools::file_get_contents($fn);
24 $hwaddress = uc(md5_hex($sshkey));
25
26 return $hwaddress;
27}
19a6b9f1 28
16b69b6c
DM
29sub extract_node_stats {
30 my ($node, $members, $rrd) = @_;
31
32 my $entry = {
33 id => "node/$node",
34 node => $node,
35 type => "node",
b67e6398 36 status => 'unknown',
16b69b6c
DM
37 };
38
39 if (my $d = $rrd->{"pve2-node/$node"}) {
40
41 if (!$members || # no cluster
42 ($members->{$node} && $members->{$node}->{online})) {
43 $entry->{uptime} = ($d->[0] || 0) + 0;
44 $entry->{cpu} = ($d->[5] || 0) + 0;
45 $entry->{mem} = ($d->[8] || 0) + 0;
46 $entry->{disk} = ($d->[12] || 0) + 0;
b67e6398 47 $entry->{status} = 'online';
16b69b6c
DM
48 }
49 $entry->{level} = $d->[1];
50 $entry->{maxcpu} = ($d->[4] || 0) + 0;
51 $entry->{maxmem} = ($d->[7] || 0) + 0;
52 $entry->{maxdisk} = ($d->[11] || 0) + 0;
53 }
54
b67e6398
DC
55 if ($members && $members->{$node} &&
56 !$members->{$node}->{online}) {
57 $entry->{status} = 'offline';
58 }
59
16b69b6c
DM
60 return $entry;
61}
19a6b9f1
DM
62
63sub extract_vm_stats {
64 my ($vmid, $data, $rrd) = @_;
65
66 my $entry = {
67 id => "$data->{type}/$vmid",
68 vmid => $vmid + 0,
69 node => $data->{node},
70 type => $data->{type},
30cdb0ca 71 status => 'unknown',
19a6b9f1
DM
72 };
73
90c3fae4
DM
74 my $d;
75
76 if ($d = $rrd->{"pve2-vm/$vmid"}) {
19a6b9f1
DM
77
78 $entry->{uptime} = ($d->[0] || 0) + 0;
79 $entry->{name} = $d->[1];
3c353ed2 80 $entry->{status} = $entry->{uptime} ? 'running' : 'stopped';
19a6b9f1
DM
81 $entry->{maxcpu} = ($d->[3] || 0) + 0;
82 $entry->{cpu} = ($d->[4] || 0) + 0;
83 $entry->{maxmem} = ($d->[5] || 0) + 0;
84 $entry->{mem} = ($d->[6] || 0) + 0;
85 $entry->{maxdisk} = ($d->[7] || 0) + 0;
86 $entry->{disk} = ($d->[8] || 0) + 0;
cf497f7d
AD
87 $entry->{netin} = ($d->[9] || 0) + 0;
88 $entry->{netout} = ($d->[10] || 0) + 0;
89 $entry->{diskread} = ($d->[11] || 0) + 0;
90 $entry->{diskwrite} = ($d->[12] || 0) + 0;
3c353ed2 91
90c3fae4 92 } elsif ($d = $rrd->{"pve2.3-vm/$vmid"}) {
3c353ed2
DM
93
94 $entry->{uptime} = ($d->[0] || 0) + 0;
95 $entry->{name} = $d->[1];
96 $entry->{status} = $d->[2];
97 $entry->{template} = $d->[3] + 0;
98
99 $entry->{maxcpu} = ($d->[5] || 0) + 0;
100 $entry->{cpu} = ($d->[6] || 0) + 0;
101 $entry->{maxmem} = ($d->[7] || 0) + 0;
102 $entry->{mem} = ($d->[8] || 0) + 0;
103 $entry->{maxdisk} = ($d->[9] || 0) + 0;
104 $entry->{disk} = ($d->[10] || 0) + 0;
105 $entry->{netin} = ($d->[11] || 0) + 0;
106 $entry->{netout} = ($d->[12] || 0) + 0;
107 $entry->{diskread} = ($d->[13] || 0) + 0;
108 $entry->{diskwrite} = ($d->[14] || 0) + 0;
19a6b9f1
DM
109 };
110
111 return $entry;
ff5fcc8a 112}
19a6b9f1
DM
113
114sub extract_storage_stats {
115 my ($storeid, $scfg, $node, $rrd) = @_;
116
117 my $entry = {
118 id => "storage/$node/$storeid",
119 storage => $storeid,
120 node => $node,
121 type => 'storage',
88466808 122 status => 'unknown',
19a6b9f1
DM
123 };
124
125 if (my $d = $rrd->{"pve2-storage/$node/$storeid"}) {
126 $entry->{maxdisk} = ($d->[1] || 0) + 0;
127 $entry->{disk} = ($d->[2] || 0) + 0;
88466808
DC
128 $entry->{status} = 'available';
129 if ($entry->{disk} > 0 && $entry->{maxdisk} > 0) {
130 my $usage = $entry->{disk} / $entry->{maxdisk};
131
132 if ($usage >= 0.9) {
133 $entry->{status} = 'full';
134 } elsif ($usage >= 0.6) {
135 $entry->{status} = 'nearfull';
136 }
137 }
19a6b9f1
DM
138 }
139
140 return $entry;
ff5fcc8a 141}
19a6b9f1 142
446b9669
DM
143sub parse_http_proxy {
144 my ($proxyenv) = @_;
145
146 my $uri = URI->new($proxyenv);
147
148 my $scheme = $uri->scheme;
149 my $host = $uri->host;
150 my $port = $uri->port || 3128;
151
152 my ($username, $password);
153
154 if (defined(my $p_auth = $uri->userinfo())) {
155 ($username, $password) = map URI::Escape::uri_unescape($_), split(":", $p_auth, 2);
156 }
157
158 return ("$host:$port", $username, $password);
159}
160
b289829f
DM
161sub run_spiceterm {
162 my ($authpath, $permissions, $vmid, $node, $proxy, $title, $shcmd) = @_;
163
164 my $rpcenv = PVE::RPCEnvironment::get();
165
166 my $authuser = $rpcenv->get_user();
b289829f 167
eb6d7497
WB
168 my $nodename = PVE::INotify::nodename();
169 my $family = PVE::Tools::get_host_address_family($nodename);
170 my $port = PVE::Tools::next_spice_port($family);
eb7cd2ce
DM
171
172 my ($ticket, undef, $remote_viewer_config) =
173 PVE::AccessControl::remote_viewer_config($authuser, $vmid, $node, $proxy, $title, $port);
b289829f 174
14e306a9 175 my $timeout = 40;
b289829f
DM
176
177 my $cmd = ['/usr/bin/spiceterm', '--port', $port, '--addr', '127.0.0.1',
178 '--timeout', $timeout, '--authpath', $authpath,
179 '--permissions', $permissions];
180
181 my $dcconf = PVE::Cluster::cfs_read_file('datacenter.cfg');
182 push @$cmd, '--keymap', $dcconf->{keyboard} if $dcconf->{keyboard};
183
184 push @$cmd, '--', @$shcmd;
185
186 my $realcmd = sub {
187 my $upid = shift;
188
189 syslog ('info', "starting spiceterm $upid - $title\n");
190
191 my $cmdstr = join (' ', @$cmd);
192 syslog ('info', "launch command: $cmdstr");
193
3fa0b222 194 eval {
b289829f 195 foreach my $k (keys %ENV) {
3fa0b222 196 next if $k eq 'PATH' || $k eq 'TERM' || $k eq 'USER' || $k eq 'HOME' || $k eq 'LANG' || $k eq 'LANGUAGE' ;
b289829f
DM
197 delete $ENV{$k};
198 }
199 $ENV{PWD} = '/';
200 $ENV{SPICE_TICKET} = $ticket;
3fa0b222 201
b0d4b407 202 PVE::Tools::run_command($cmd, errmsg => 'spiceterm failed\n', keeplocale => 1);
b289829f
DM
203 };
204 if (my $err = $@) {
205 syslog ('err', $err);
206 }
207
208 return;
209 };
210
211 if ($vmid) {
212 $rpcenv->fork_worker('spiceproxy', $vmid, $authuser, $realcmd);
213 } else {
214 $rpcenv->fork_worker('spiceshell', undef, $authuser, $realcmd);
215 }
eb7cd2ce 216
b289829f
DM
217 PVE::Tools::wait_for_vnc_port($port);
218
eb7cd2ce 219 return $remote_viewer_config;
b289829f
DM
220}
221
a3eff2d9
DM
222sub read_proxy_config {
223
224 my $conffile = "/etc/default/pveproxy";
225
226 # Note: evaluate with bash
227 my $shcmd = ". $conffile;\n";
228 $shcmd .= 'echo \"ALLOW_FROM:\$ALLOW_FROM\";';
229 $shcmd .= 'echo \"DENY_FROM:\$DENY_FROM\";';
230 $shcmd .= 'echo \"POLICY:\$POLICY\";';
231 $shcmd .= 'echo \"CIPHERS:\$CIPHERS\";';
41196653 232 $shcmd .= 'echo \"DHPARAMS:\$DHPARAMS\";';
a3eff2d9
DM
233
234 my $data = -f $conffile ? `bash -c "$shcmd"` : '';
235
236 my $res = {};
237
238 while ($data =~ s/^(.*)\n//) {
239 my ($key, $value) = split(/:/, $1, 2);
240 next if !$value;
241 if ($key eq 'ALLOW_FROM' || $key eq 'DENY_FROM') {
242 my $ips = [];
243 foreach my $ip (split(/,/, $value)) {
244 $ip = "0/0" if $ip eq 'all';
245 push @$ips, Net::IP->new($ip) || die Net::IP::Error() . "\n";
246 }
247 $res->{$key} = $ips;
248 } elsif ($key eq 'POLICY') {
249 die "unknown policy '$value'\n" if $value !~ m/^(allow|deny)$/;
250 $res->{$key} = $value;
251 } elsif ($key eq 'CIPHERS') {
252 $res->{$key} = $value;
41196653
FG
253 } elsif ($key eq 'DHPARAMS') {
254 $res->{$key} = $value;
a3eff2d9
DM
255 } else {
256 # silently skip everythin else?
257 }
258 }
259
260 return $res;
261}
262
3c54bc91
DM
263sub resolve_proxyto {
264 my ($rpcenv, $proxyto_callback, $proxyto, $uri_param) = @_;
265
266 my $node;
267 if ($proxyto_callback) {
268 $node = $proxyto_callback->($rpcenv, $proxyto, $uri_param);
269 die "internal error - proxyto_callback returned nothing\n"
270 if !$node;
271 } else {
272 $node = $uri_param->{$proxyto};
273 raise_param_exc({ $proxyto => "proxyto parameter does not exists"})
274 if !$node;
275 }
276 return $node;
277}
278
19a6b9f1 2791;