]> git.proxmox.com Git - pve-manager.git/blob - PVE/API2Tools.pm
4218c406aa3b831ba206f0e6e996729d074882f0
[pve-manager.git] / PVE / API2Tools.pm
1 package PVE::API2Tools;
2
3 use strict;
4 use warnings;
5 use Net::IP;
6
7 use PVE::Exception qw(raise_param_exc);
8 use PVE::Tools;
9 use PVE::INotify;
10 use PVE::Cluster;
11 use PVE::DataCenterConfig;
12 use PVE::RPCEnvironment;
13 use Digest::MD5 qw(md5_hex);
14 use URI;
15 use URI::Escape;
16 use PVE::SafeSyslog;
17
18 my $hwaddress;
19
20 sub get_hwaddress {
21
22 return $hwaddress if defined ($hwaddress);
23
24 my $fn = '/etc/ssh/ssh_host_rsa_key.pub';
25 my $sshkey = PVE::Tools::file_get_contents($fn);
26 $hwaddress = uc(md5_hex($sshkey));
27
28 return $hwaddress;
29 }
30
31 sub extract_node_stats {
32 my ($node, $members, $rrd, $exclude_stats) = @_;
33
34 my $entry = {
35 id => "node/$node",
36 node => $node,
37 type => "node",
38 status => 'unknown',
39 };
40
41 if (my $d = $rrd->{"pve2-node/$node"}) {
42
43 if (!$members || # no cluster
44 ($members->{$node} && $members->{$node}->{online})) {
45 if (!$exclude_stats) {
46 $entry->{uptime} = ($d->[0] || 0) + 0;
47 $entry->{cpu} = ($d->[5] || 0) + 0;
48 $entry->{mem} = ($d->[8] || 0) + 0;
49 $entry->{disk} = ($d->[12] || 0) + 0;
50 }
51 $entry->{status} = 'online';
52 }
53 $entry->{level} = $d->[1];
54 if (!$exclude_stats) {
55 $entry->{maxcpu} = ($d->[4] || 0) + 0;
56 $entry->{maxmem} = ($d->[7] || 0) + 0;
57 $entry->{maxdisk} = ($d->[11] || 0) + 0;
58 }
59 }
60
61 if ($members && $members->{$node} &&
62 !$members->{$node}->{online}) {
63 $entry->{status} = 'offline';
64 }
65
66 return $entry;
67 }
68
69 sub extract_vm_stats {
70 my ($vmid, $data, $rrd) = @_;
71
72 my $entry = {
73 id => "$data->{type}/$vmid",
74 vmid => $vmid + 0,
75 node => $data->{node},
76 type => $data->{type},
77 status => 'unknown',
78 };
79
80 my $d;
81
82 if ($d = $rrd->{"pve2-vm/$vmid"}) {
83
84 $entry->{uptime} = ($d->[0] || 0) + 0;
85 $entry->{name} = $d->[1];
86 $entry->{status} = $entry->{uptime} ? 'running' : 'stopped';
87 $entry->{maxcpu} = ($d->[3] || 0) + 0;
88 $entry->{cpu} = ($d->[4] || 0) + 0;
89 $entry->{maxmem} = ($d->[5] || 0) + 0;
90 $entry->{mem} = ($d->[6] || 0) + 0;
91 $entry->{maxdisk} = ($d->[7] || 0) + 0;
92 $entry->{disk} = ($d->[8] || 0) + 0;
93 $entry->{netin} = ($d->[9] || 0) + 0;
94 $entry->{netout} = ($d->[10] || 0) + 0;
95 $entry->{diskread} = ($d->[11] || 0) + 0;
96 $entry->{diskwrite} = ($d->[12] || 0) + 0;
97
98 } elsif ($d = $rrd->{"pve2.3-vm/$vmid"}) {
99
100 $entry->{uptime} = ($d->[0] || 0) + 0;
101 $entry->{name} = $d->[1];
102 $entry->{status} = $d->[2];
103 $entry->{template} = $d->[3] + 0;
104
105 $entry->{maxcpu} = ($d->[5] || 0) + 0;
106 $entry->{cpu} = ($d->[6] || 0) + 0;
107 $entry->{maxmem} = ($d->[7] || 0) + 0;
108 $entry->{mem} = ($d->[8] || 0) + 0;
109 $entry->{maxdisk} = ($d->[9] || 0) + 0;
110 $entry->{disk} = ($d->[10] || 0) + 0;
111 $entry->{netin} = ($d->[11] || 0) + 0;
112 $entry->{netout} = ($d->[12] || 0) + 0;
113 $entry->{diskread} = ($d->[13] || 0) + 0;
114 $entry->{diskwrite} = ($d->[14] || 0) + 0;
115 };
116
117 return $entry;
118 }
119
120 sub extract_storage_stats {
121 my ($storeid, $scfg, $node, $rrd) = @_;
122
123 my $entry = {
124 id => "storage/$node/$storeid",
125 storage => $storeid,
126 node => $node,
127 type => 'storage',
128 status => 'unknown',
129 shared => $scfg->{shared} || 0,
130 };
131
132 if (my $d = $rrd->{"pve2-storage/$node/$storeid"}) {
133 $entry->{maxdisk} = ($d->[1] || 0) + 0;
134 $entry->{disk} = ($d->[2] || 0) + 0;
135 $entry->{status} = 'available';
136 }
137
138 return $entry;
139 }
140
141 sub parse_http_proxy {
142 my ($proxyenv) = @_;
143
144 my $uri = URI->new($proxyenv);
145
146 my $scheme = $uri->scheme;
147 my $host = $uri->host;
148 my $port = $uri->port || 3128;
149
150 my ($username, $password);
151
152 if (defined(my $p_auth = $uri->userinfo())) {
153 ($username, $password) = map URI::Escape::uri_unescape($_), split(":", $p_auth, 2);
154 }
155
156 return ("$host:$port", $username, $password);
157 }
158
159 sub run_spiceterm {
160 my ($authpath, $permissions, $vmid, $node, $proxy, $title, $shcmd) = @_;
161
162 my $rpcenv = PVE::RPCEnvironment::get();
163
164 my $authuser = $rpcenv->get_user();
165
166 my $nodename = PVE::INotify::nodename();
167 my $family = PVE::Tools::get_host_address_family($nodename);
168 my $port = PVE::Tools::next_spice_port($family);
169
170 my ($ticket, undef, $remote_viewer_config) =
171 PVE::AccessControl::remote_viewer_config($authuser, $vmid, $node, $proxy, $title, $port);
172
173 my $timeout = 40;
174
175 my $cmd = ['/usr/bin/spiceterm', '--port', $port, '--addr', 'localhost',
176 '--timeout', $timeout, '--authpath', $authpath,
177 '--permissions', $permissions];
178
179 my $dcconf = PVE::Cluster::cfs_read_file('datacenter.cfg');
180 push @$cmd, '--keymap', $dcconf->{keyboard} if $dcconf->{keyboard};
181
182 push @$cmd, '--', @$shcmd;
183
184 my $realcmd = sub {
185 my $upid = shift;
186
187 syslog ('info', "starting spiceterm $upid - $title\n");
188
189 my $cmdstr = join (' ', @$cmd);
190 syslog ('info', "launch command: $cmdstr");
191
192 eval {
193 foreach my $k (keys %ENV) {
194 next if $k eq 'PATH' || $k eq 'TERM' || $k eq 'USER' || $k eq 'HOME' || $k eq 'LANG' || $k eq 'LANGUAGE' ;
195 delete $ENV{$k};
196 }
197 $ENV{PWD} = '/';
198 $ENV{SPICE_TICKET} = $ticket;
199
200 PVE::Tools::run_command($cmd, errmsg => 'spiceterm failed\n', keeplocale => 1);
201 };
202 if (my $err = $@) {
203 syslog ('err', $err);
204 }
205
206 return;
207 };
208
209 if ($vmid) {
210 $rpcenv->fork_worker('spiceproxy', $vmid, $authuser, $realcmd);
211 } else {
212 $rpcenv->fork_worker('spiceshell', undef, $authuser, $realcmd);
213 }
214
215 PVE::Tools::wait_for_vnc_port($port);
216
217 return $remote_viewer_config;
218 }
219
220 sub resolve_proxyto {
221 my ($rpcenv, $proxyto_callback, $proxyto, $uri_param) = @_;
222
223 my $node;
224 if ($proxyto_callback) {
225 $node = $proxyto_callback->($rpcenv, $proxyto, $uri_param);
226 die "internal error - proxyto_callback returned nothing\n"
227 if !$node;
228 } else {
229 $node = $uri_param->{$proxyto};
230 raise_param_exc({ $proxyto => "proxyto parameter does not exists"})
231 if !$node;
232 }
233 return $node;
234 }
235
236 sub get_resource_pool_guest_members {
237 my ($pool) = @_;
238
239 my $usercfg = PVE::Cluster::cfs_read_file("user.cfg");
240
241 my $vmlist = PVE::Cluster::get_vmlist() || {};
242 my $idlist = $vmlist->{ids} || {};
243
244 my $data = $usercfg->{pools}->{$pool};
245
246 die "pool '$pool' does not exist\n" if !$data;
247
248 my $pool_members = [ grep { $idlist->{$_} } keys %{$data->{vms}} ];
249
250 return $pool_members;
251 }
252
253 1;