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