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