1 |
95b003ff
|
Origo
|
#!/usr/bin/perl
|
2 |
|
|
|
3 |
|
|
# All rights reserved and Copyright (c) 2020 Origo Systems ApS.
|
4 |
|
|
# This file is provided with no warranty, and is subject to the terms and conditions defined in the license file LICENSE.md.
|
5 |
|
|
# The license file is part of this source code package and its content is also available at:
|
6 |
48fcda6b
|
Origo
|
# https://www.stabile.io/info/stabiledocs/licensing/stabile-open-source-license
|
7 |
95b003ff
|
Origo
|
|
8 |
|
|
package Stabile::Users;
|
9 |
|
|
|
10 |
|
|
use Error qw(:try);
|
11 |
|
|
use Time::Local;
|
12 |
|
|
# use Time::HiRes qw( time );
|
13 |
|
|
use Config::Simple;
|
14 |
|
|
use Text::CSV_XS qw( csv );
|
15 |
|
|
use Proc::Daemon;
|
16 |
|
|
use MIME::Lite;
|
17 |
|
|
use File::Basename;
|
18 |
|
|
use Data::Password qw(:all);
|
19 |
4aef7ef6
|
hq
|
use Geo::IP;
|
20 |
95b003ff
|
Origo
|
use lib dirname (__FILE__);
|
21 |
|
|
use Stabile;
|
22 |
|
|
|
23 |
|
|
$engineid = $Stabile::config->get('ENGINEID') || "";
|
24 |
|
|
$enginename = $Stabile::config->get('ENGINENAME') || "";
|
25 |
|
|
#$enginelinked = $Stabile::config->get('ENGINE_LINKED') || "";
|
26 |
|
|
$showcost = $Stabile::config->get('SHOW_COST') || "";
|
27 |
|
|
$cur = $Stabile::config->get('CURRENCY') || "USD";
|
28 |
|
|
$engineuser = $Stabile::config->get('ENGINEUSER') || "";
|
29 |
|
|
$externaliprangestart = $Stabile::config->get('EXTERNAL_IP_RANGE_START') || "";
|
30 |
|
|
$externaliprangeend = $Stabile::config->get('EXTERNAL_IP_RANGE_END') || "";
|
31 |
|
|
$proxyiprangestart = $Stabile::config->get('PROXY_IP_RANGE_START') || "";
|
32 |
|
|
$proxyiprangeend = $Stabile::config->get('PROXY_IP_RANGE_END') || "";
|
33 |
|
|
$proxygw = $Stabile::config->get('PROXY_GW') || "";
|
34 |
|
|
|
35 |
|
|
$uiuuid;
|
36 |
|
|
$uistatus;
|
37 |
|
|
$help = 0; # If this is set, functions output help
|
38 |
|
|
|
39 |
|
|
#our %options=();
|
40 |
|
|
# -a action -h help -u uuid -m match pattern -f full list, i.e. all users
|
41 |
|
|
# -v verbose, include HTTP headers -s impersonate subaccount -t target [uuid or image]
|
42 |
|
|
# -g args to gearman task
|
43 |
|
|
#Getopt::Std::getopts("a:hfu:g:m:vs:t:", \%options);
|
44 |
|
|
|
45 |
|
|
try {
|
46 |
|
|
Init(); # Perform various initalization tasks
|
47 |
|
|
process() if ($package);
|
48 |
|
|
|
49 |
|
|
} catch Error with {
|
50 |
|
|
my $ex = shift;
|
51 |
|
|
print header('text/html', '500 Internal Server Error') unless ($console);
|
52 |
|
|
if ($ex->{-text}) {
|
53 |
|
|
print "Got error: ", $ex->{-text}, " on line ", $ex->{-line}, "\n";
|
54 |
|
|
} else {
|
55 |
|
|
print "Status=ERROR\n";
|
56 |
|
|
}
|
57 |
|
|
} finally {
|
58 |
|
|
};
|
59 |
|
|
|
60 |
|
|
1;
|
61 |
|
|
|
62 |
|
|
sub getObj {
|
63 |
|
|
my %h = %{@_[0]};
|
64 |
|
|
$console = 1 if $h{"console"};
|
65 |
|
|
$api = 1 if $h{"api"};
|
66 |
|
|
my $username = $h{"username"} || $h{"uuid"};
|
67 |
|
|
my $obj;
|
68 |
|
|
$action = $action || $h{'action'};
|
69 |
|
|
if ($action=~ /engine$|updateclientui$|updateui$/) {
|
70 |
|
|
$obj = \%h;
|
71 |
|
|
$obj->{pwd} = $obj->{password} if ($obj->{password});
|
72 |
|
|
} else {
|
73 |
|
|
$obj = $register{$username};
|
74 |
|
|
my %hobj = %{$register{$username}};
|
75 |
|
|
$obj = \%hobj; # We do this to get around a weird problem with freeze...
|
76 |
|
|
my @props = qw ( restorefile engineid enginename engineurl username user password pwd fullname email
|
77 |
|
|
opemail alertemail phone opphone opfullname allowfrom allowinternalapi privileges accounts accountsprivileges
|
78 |
54401133
|
hq
|
storagepools memoryquota storagequota nodestoragequota vcpuquota externalipquota rxquota txquota billto dnsdomains appstoreurl totpsecret );
|
79 |
95b003ff
|
Origo
|
foreach my $prop (@props) {
|
80 |
|
|
if (defined $h{$prop}) {
|
81 |
|
|
$obj->{$prop} = $h{$prop};
|
82 |
|
|
}
|
83 |
|
|
}
|
84 |
|
|
}
|
85 |
|
|
return $obj;
|
86 |
|
|
}
|
87 |
|
|
|
88 |
|
|
sub Init {
|
89 |
|
|
# Tie database tables to hashes
|
90 |
|
|
unless ( tie(%register,'Tie::DBI', Hash::Merge::merge({table=>'users', key=>'username'}, $Stabile::dbopts)) ) {return "Unable to access users register"};
|
91 |
|
|
|
92 |
|
|
# simplify globals initialized in Stabile.pm
|
93 |
|
|
$tktuser = $tktuser || $Stabile::tktuser;
|
94 |
|
|
$user = $user || $Stabile::user;
|
95 |
|
|
|
96 |
|
|
$fullname = $register{$user}->{'fullname'};
|
97 |
|
|
$email = $register{$user}->{'email'};
|
98 |
|
|
$opemail = $register{$user}->{'opemail'};
|
99 |
|
|
$alertemail = $register{$user}->{'alertemail'};
|
100 |
|
|
$phone = $register{$user}->{'phone'};
|
101 |
|
|
$opphone = $register{$user}->{'opphone'};
|
102 |
|
|
$opfullname = $register{$user}->{'opfullname'};
|
103 |
|
|
$allowfrom = $register{$user}->{'allowfrom'};
|
104 |
|
|
$allowinternalapi = $register{$user}->{'allowinternalapi'};
|
105 |
|
|
$lastlogin = $register{$user}->{'lastlogin'};
|
106 |
|
|
$lastloginfrom = $register{$user}->{'lastloginfrom'};
|
107 |
|
|
|
108 |
|
|
# if ($register{$user}->{'lastlogin'} ne $tkt) {
|
109 |
|
|
# $register{$user}->{'lastlogin'} = time;
|
110 |
|
|
# $register{$user}->{'lastloginfrom'} = $ENV{'REMOTE_ADDR'};
|
111 |
|
|
# $register{$user}->{'lasttkt'} = $tkt;
|
112 |
|
|
# }
|
113 |
|
|
|
114 |
|
|
$Stabile::userstoragequota = 0+ $register{$user}->{'storagequota'};
|
115 |
|
|
$Stabile::usernodestoragequota = 0+ $register{$user}->{'nodestoragequota'};
|
116 |
|
|
$usermemoryquota = 0+ $register{$user}->{'memoryquota'};
|
117 |
|
|
$uservcpuquota = 0+ $register{$user}->{'vcpuquota'};
|
118 |
|
|
$userexternalipquota = 0+ $register{$user}->{'externalipquota'};
|
119 |
|
|
$userrxquota = 0+ $register{$user}->{'rxquota'};
|
120 |
|
|
$usertxquota = 0+ $register{$user}->{'txquota'};
|
121 |
|
|
|
122 |
|
|
$storagequota = $Stabile::userstoragequota || $defaultstoragequota;
|
123 |
|
|
$nodestoragequota = $Stabile::usernodestoragequota || $defaultnodestoragequota;
|
124 |
|
|
$memoryquota = $usermemoryquota || $defaultmemoryquota;
|
125 |
|
|
$vcpuquota = $uservcpuquota || $defaultvcpuquota;
|
126 |
|
|
$externalipquota = $userexternalipquota || $defaultexternalipquota;
|
127 |
|
|
$rxquota = $userrxquota || $defaultrxquota;
|
128 |
|
|
$txquota = $usertxquota || $defaulttxquota;
|
129 |
|
|
|
130 |
|
|
# Create aliases of functions
|
131 |
|
|
*header = \&CGI::header;
|
132 |
|
|
|
133 |
|
|
*Unlinkengine = \&Linkengine;
|
134 |
|
|
*Updateengine = \&Linkengine;
|
135 |
|
|
*Saveengine = \&Linkengine;
|
136 |
|
|
*Syncusers = \&Linkengine;
|
137 |
|
|
|
138 |
|
|
*do_help = \&action;
|
139 |
|
|
*do_show = \&do_uuidshow;
|
140 |
|
|
*do_delete = \&do_remove;
|
141 |
|
|
*do_tablelist = \&do_list;
|
142 |
|
|
*do_billingstatus = \&do_billing;
|
143 |
|
|
*do_usage = \&do_billing;
|
144 |
|
|
*do_usagestatus = \&do_billing;
|
145 |
|
|
*do_billingavgstatus = \&do_billing;
|
146 |
|
|
*do_usageavgstatus = \&do_billing;
|
147 |
|
|
*do_upgradeengine = \&privileged_action;
|
148 |
|
|
*do_gear_upgradeengine = \&do_gear_action;
|
149 |
|
|
*do_backupengine = \&privileged_action;
|
150 |
|
|
*do_gear_backupengine = \&do_gear_action;
|
151 |
|
|
*do_restoreengine = \&privileged_action;
|
152 |
|
|
*do_gear_restoreengine = \&do_gear_action;
|
153 |
|
|
*do_releasepressure = \&privileged_action_async;
|
154 |
|
|
*do_gear_releasepressure = \&do_gear_action;
|
155 |
|
|
|
156 |
|
|
*do_linkengine = \&privileged_action;
|
157 |
|
|
*do_gear_linkengine = \&do_gear_action;
|
158 |
|
|
*do_saveengine = \&privileged_action_async;
|
159 |
|
|
*do_gear_saveengine = \&do_gear_action;
|
160 |
|
|
*do_unlinkengine = \&privileged_action;
|
161 |
|
|
*do_gear_unlinkengine = \&do_gear_action;
|
162 |
|
|
*do_updateengine = \&privileged_action;
|
163 |
|
|
*do_syncusers = \&privileged_action;
|
164 |
|
|
*do_gear_updateengine = \&do_gear_action;
|
165 |
|
|
*do_gear_syncusers = \&do_gear_action;
|
166 |
|
|
*do_deleteentirely = \&privileged_action;
|
167 |
|
|
*do_gear_deleteentirely = \&do_gear_action;
|
168 |
|
|
*do_vent = \&privileged_action;
|
169 |
|
|
*do_gear_vent = \&do_gear_action;
|
170 |
|
|
*do_updateui = \&privileged_action;
|
171 |
|
|
*do_gear_updateui = \&do_gear_action;
|
172 |
|
|
}
|
173 |
|
|
|
174 |
|
|
sub do_listaccounts {
|
175 |
|
|
my ($uuid, $action, $obj) = @_;
|
176 |
|
|
if ($help) {
|
177 |
|
|
return <<END
|
178 |
|
|
GET:common:
|
179 |
|
|
List other user accounts current user has access to use and switch to. This is an internal method which includes html
|
180 |
|
|
specifically for use with Dojo.
|
181 |
|
|
END
|
182 |
|
|
}
|
183 |
|
|
my $common = $params{'common'};
|
184 |
|
|
my %bhash;
|
185 |
|
|
my @accounts = split(/,\s*/, $register{$tktuser}->{'accounts'});
|
186 |
|
|
my @accountsprivs = split(/,\s*/, $register{$tktuser}->{'accountsprivileges'});
|
187 |
|
|
for my $i (0 .. $#accounts) {
|
188 |
|
|
$bhash{$accounts[$i]} = {
|
189 |
|
|
id=>$accounts[$i],
|
190 |
|
|
privileges=>$accountsprivs[$i] || 'r'
|
191 |
|
|
} if ($register{$accounts[$i]}); # Only include accounts that exist on this engine
|
192 |
|
|
};
|
193 |
|
|
$bhash{$tktuser} = {id=>$tktuser, privileges=>$privileges};
|
194 |
|
|
delete $bhash{$user};
|
195 |
|
|
$bhash{'common'} = {id=>'common', privileges=>'--'} if ($common);
|
196 |
|
|
my @bvalues = values %bhash;
|
197 |
|
|
unshift(@bvalues, {id=>$user, privileges=>$privileges});
|
198 |
|
|
my $logout = {privileges=>'', id=>'<span class="glyphicon glyphicon-log-out" aria-hidden="true" style="font-size:15px;color:#3c3c3c; vertical-align:top; margin-top:8px;"></span> Log out '};
|
199 |
|
|
push(@bvalues, $logout) unless ($common);
|
200 |
|
|
$postreply = "{\"identifier\": \"id\",\"label\": \"id\", \"items\":" . JSON::to_json(\@bvalues, {pretty=>1}) . "}";
|
201 |
|
|
return $postreply;
|
202 |
|
|
}
|
203 |
|
|
|
204 |
|
|
sub do_listids {
|
205 |
|
|
my ($uuid, $action, $obj) = @_;
|
206 |
|
|
if ($help) {
|
207 |
|
|
return <<END
|
208 |
|
|
GET::
|
209 |
|
|
List other user accounts current user has read access to. Call with flat=1 if you want a flat array.
|
210 |
|
|
END
|
211 |
|
|
}
|
212 |
|
|
require "$Stabile::basedir/cgi/images.cgi";
|
213 |
|
|
my $backupdevice = Stabile::Images::Getbackupdevice('', 'getbackupdevice');
|
214 |
|
|
my $imagesdevice = Stabile::Images::Getimagesdevice('', 'getimagesdevice');
|
215 |
|
|
my $mounts = `cat /proc/mounts | grep zfs`;
|
216 |
|
|
my %engine_h;
|
217 |
|
|
my $zbackupavailable = ( (($mounts =~ /$backupdevice\/backup (\S+) zfs/) && ($mounts =~ /$imagesdevice\/images (\S+) zfs/) )?1:'');
|
218 |
|
|
my $jsontext = qq|{"identifier": "id","label": "id", "items":[| .
|
219 |
|
|
qq|{"id": "$user", "privileges": "$privileges", "userprivileges": "$dbprivileges", "tktuser": "$tktuser", |.
|
220 |
|
|
qq|"storagequota": $storagequota, "nodestoragequota": $nodestoragequota, "memoryquota": $memoryquota, "vcpuquota": $vcpuquota, |.
|
221 |
|
|
qq|"fullname": "$fullname", "email": "$email", "opemail": "$opemail", "alertemail": "$alertemail", |.
|
222 |
|
|
qq|"phone": "$phone", "opphone": "$opphone", "opfullname": "$opfullname", "appstoreurl": "$appstoreurl", |.
|
223 |
71b897d3
|
hq
|
qq|"allowfrom": "$allowfrom", "lastlogin": "$lastlogin", "lastloginfrom": "$lastloginfrom", "allowinternalapi": "$allowinternalapi", "billto": "$billto", |.
|
224 |
45cc3024
|
hq
|
qq|"dnsdomain": "$dnsdomain", "appstoreurl": "$appstoreurl", |;
|
225 |
95b003ff
|
Origo
|
|
226 |
|
|
if ($isadmin && $engineid) {
|
227 |
|
|
$engine_h{"engineid"} = $engineid;
|
228 |
|
|
$engine_h{"engineuser"} = $engineuser;
|
229 |
|
|
$engine_h{"externaliprangestart"} = $externaliprangestart;
|
230 |
|
|
$engine_h{"externaliprangeend"} = $externaliprangeend;
|
231 |
|
|
$engine_h{"proxyiprangestart"} = $proxyiprangestart;
|
232 |
|
|
$engine_h{"proxyiprangeend"} = $proxyiprangeend;
|
233 |
|
|
$engine_h{"proxygw"} = $proxygw;
|
234 |
|
|
|
235 |
|
|
$engine_h{"disablesnat"} = $disablesnat;
|
236 |
|
|
$engine_h{"imagesdevice"} = $imagesdevice;
|
237 |
|
|
$engine_h{"backupdevice"} = $backupdevice;
|
238 |
|
|
|
239 |
|
|
my $nodecfg = new Config::Simple("/etc/stabile/nodeconfig.cfg");
|
240 |
|
|
my $readlimit = $nodecfg->param('VM_READ_LIMIT'); # e.g. 125829120 = 120 * 1024 * 1024 = 120 MB / s
|
241 |
|
|
my $writelimit = $nodecfg->param('VM_WRITE_LIMIT');
|
242 |
|
|
my $iopsreadlimit = $nodecfg->param('VM_IOPS_READ_LIMIT'); # e.g. 1000 IOPS
|
243 |
|
|
my $iopswritelimit = $nodecfg->param('VM_IOPS_WRITE_LIMIT');
|
244 |
|
|
$engine_h{"vmreadlimit"} = $readlimit;
|
245 |
|
|
$engine_h{"vmwritelimit"} = $writelimit;
|
246 |
|
|
$engine_h{"vmiopsreadlimit"} = $iopsreadlimit;
|
247 |
|
|
$engine_h{"vmiopswritelimit"} = $iopswritelimit;
|
248 |
|
|
|
249 |
|
|
$engine_h{"zfsavailable"} = $zbackupavailable;
|
250 |
|
|
$engine_h{"downloadmasters"} = $downloadmasters;
|
251 |
|
|
}
|
252 |
6fdc8676
|
hq
|
if (-e "/var/www/stabile/static/img/logo-icon-" . $ENV{HTTP_HOST} . ".png") {
|
253 |
|
|
$jsontext .= qq|"favicon": "/stabile/static/img/logo-icon-$ENV{HTTP_HOST}.png", |;
|
254 |
|
|
}
|
255 |
c899e439
|
Origo
|
$engine_h{"enginename"} = $enginename;
|
256 |
|
|
$engine_h{"enginelinked"} = $enginelinked;
|
257 |
95b003ff
|
Origo
|
$jsontext .= "\"showcost\": \"$showcost\", ";
|
258 |
|
|
$jsontext .= "\"externalipquota\": $externalipquota, \"rxquota\": $rxquota, \"txquota\": $txquota, ";
|
259 |
|
|
$jsontext .= qq|"defaultstoragequota": $defaultstoragequota, "defaultnodestoragequota": $defaultnodestoragequota, "defaultmemoryquota": $defaultmemoryquota, "defaultvcpuquota": $defaultvcpuquota, |;
|
260 |
|
|
$jsontext .= "\"defaultexternalipquota\": $defaultexternalipquota, \"defaultrxquota\": $defaultrxquota, \"defaulttxquota\": $defaulttxquota, ";
|
261 |
|
|
$jsontext .= qq|"engine": | . to_json(\%engine_h);
|
262 |
|
|
$jsontext .= "}, ";
|
263 |
|
|
|
264 |
|
|
$jsontext .= "{\"id\": \"common\", \"privileges\": \"--\"," .
|
265 |
|
|
"\"fullname\": \"--\", \"email\": \"--\"," .
|
266 |
|
|
"\"storagequota\": 0, \"memoryquota\": 0, \"vcpuquota\": 0, \"externalipquota\": 0," .
|
267 |
|
|
"\"rxquota\": 0, \"txquota\": 0}";
|
268 |
|
|
|
269 |
|
|
$jsontext .= ", {\"id\": \"$billto\"}" if ($billto && $billto ne '--');
|
270 |
|
|
|
271 |
|
|
foreach my $aid (keys %ahash) {
|
272 |
|
|
my $privs = $ahash{$aid};
|
273 |
|
|
$jsontext .= qq|, {"id": "$aid", "privileges": "$privs"}| unless ($aid eq $user || $aid eq $billto);
|
274 |
|
|
}
|
275 |
|
|
|
276 |
|
|
$jsontext .= "]}";
|
277 |
|
|
# Create ui_update link in case we are logging in with a remotely generated ticket, i.e. not passing through login.cgi
|
278 |
|
|
`/bin/ln -s ../ui_update.cgi ../cgi/ui_update/$user~ui_update.cgi` unless (-e "../cgi/ui_update/$user~ui_update.cgi");
|
279 |
|
|
$postreply = to_json(from_json($jsontext), {pretty=>1});
|
280 |
|
|
return $postreply;
|
281 |
|
|
}
|
282 |
|
|
|
283 |
|
|
|
284 |
|
|
sub do_listengines{
|
285 |
|
|
my ($uuid, $action, $obj) = @_;
|
286 |
|
|
if ($help) {
|
287 |
|
|
return <<END
|
288 |
|
|
GET::
|
289 |
|
|
List other engines user has access to
|
290 |
|
|
END
|
291 |
|
|
}
|
292 |
|
|
if ($enginelinked) {
|
293 |
|
|
require LWP::Simple;
|
294 |
|
|
my $browser = LWP::UserAgent->new;
|
295 |
|
|
$browser->agent('stabile/1.0b');
|
296 |
|
|
$browser->protocols_allowed( [ 'http','https'] );
|
297 |
|
|
|
298 |
|
|
my $tktcfg = ConfigReader::Simple->new($Stabile::auth_tkt_conf, [qw(TKTAuthSecret)]);
|
299 |
|
|
my $tktkey = $tktcfg->get('TKTAuthSecret') || '';
|
300 |
|
|
|
301 |
|
|
$postreq->{'engineid'} = $engineid;
|
302 |
2a63870a
|
Christian Orellana
|
# $postreq->{'user'} = $tktuser;
|
303 |
|
|
$postreq->{'user'} = $user;
|
304 |
95b003ff
|
Origo
|
$postreq->{'enginetkthash'} = Digest::SHA::sha512_hex($tktkey);
|
305 |
|
|
|
306 |
48fcda6b
|
Origo
|
my $content = $browser->post("https://www.stabile.io/irigo/engine.cgi?action=listengines", $postreq)->content();
|
307 |
95b003ff
|
Origo
|
if ($content =~ /ERROR:(.+)"/) {
|
308 |
|
|
$postreply = qq|{"identifier": "url", "label": "name", "items": [{"url": "# $1", "name": "$enginename"}]}|;
|
309 |
|
|
} else {
|
310 |
|
|
$postreply = qq|{"identifier": "url", "label": "name", "items": $content}|;
|
311 |
|
|
}
|
312 |
|
|
} else {
|
313 |
|
|
$postreply = qq|{"identifier": "url", "label": "name", "items": [{"url": "#", "name": "$enginename"}]}|;
|
314 |
|
|
}
|
315 |
|
|
return $postreply;
|
316 |
|
|
}
|
317 |
|
|
|
318 |
|
|
sub do_billing {
|
319 |
|
|
my ($uuid, $action, $obj) = @_;
|
320 |
|
|
if ($help) {
|
321 |
|
|
return <<END
|
322 |
|
|
GET:uuid,username,month,startmonth,endmonth,format:
|
323 |
d24d9a01
|
hq
|
List usage data, optionally for specific server/system [uuid] or user [username]. May be called as usage, usagestatus or usageavgstatus.
|
324 |
95b003ff
|
Origo
|
When called as "usage", format may be csv, in which case startmonth and endmonth may be specified.
|
325 |
|
|
END
|
326 |
|
|
}
|
327 |
|
|
my $buser = $params{'user'} || $params{'username'} || $user;
|
328 |
|
|
my $bmonth = $params{'month'} || $month;
|
329 |
|
|
$bmonth = substr("0$bmonth", -2);
|
330 |
|
|
my $byear = $params{'year'} || $year;
|
331 |
|
|
my $vcpu=0, $memory=0, $virtualsize=0, $nodevirtualsize=0, $backupsize=0, $externalip=0;
|
332 |
|
|
my $rx = 0;
|
333 |
|
|
my $tx = 0;
|
334 |
|
|
my $vcpuavg = 0;
|
335 |
|
|
my $externalipavg = 0;
|
336 |
|
|
$uuid = '' if ($register{$uuid}); # check if $uuid was set to $user because no actual uuid passed
|
337 |
|
|
|
338 |
|
|
if ($user eq $buser || index($privileges,"a")!=-1) {
|
339 |
|
|
my %stats = collectBillingData( $uuid, $buser, $bmonth, $byear, $showcost );
|
340 |
|
|
my $memoryquotagb = int(0.5 + 100*$memoryquota/1024)/100;
|
341 |
|
|
my $storagequotagb = int(0.5 + 100*$storagequota/1024)/100;
|
342 |
|
|
my $nodestoragequotagb = int(0.5 + 100*$nodestoragequota/1024)/100;
|
343 |
|
|
my $irigo_cost = ($showcost?"showcost":"hidecost");
|
344 |
|
|
|
345 |
|
|
if ($action eq "billing" || $action eq "usage") {
|
346 |
|
|
if ($params{'format'} eq 'csv') {
|
347 |
|
|
$postreply = header("text/plain");
|
348 |
|
|
my $startmonth = $params{'startmonth'} || 1;
|
349 |
|
|
my $endmonth = $params{'endmonth'} || $bmonth;
|
350 |
|
|
my @vals;
|
351 |
|
|
for (my $i=$startmonth; $i<=$endmonth; $i++) {
|
352 |
|
|
my $m = substr("0$i", -2);
|
353 |
|
|
my %mstats = collectBillingData( $uuid, $buser, $m, $byear, $showcost );
|
354 |
|
|
push @vals, \%mstats;
|
355 |
|
|
}
|
356 |
|
|
csv(in => \@vals, out => \my $csvdata);
|
357 |
|
|
$postreply .= $csvdata;
|
358 |
|
|
} else {
|
359 |
|
|
my $json_text = JSON::to_json(\%stats, {pretty => 1});
|
360 |
|
|
$postreply = "$json_text";
|
361 |
|
|
}
|
362 |
|
|
|
363 |
|
|
} elsif ($action eq "billingstatus" || $action eq "usagestatus") {
|
364 |
2a63870a
|
Christian Orellana
|
my $virtualsizegb = $stats{'virtualsize'};
|
365 |
|
|
my $backupsizegb = $stats{'backupsize'};
|
366 |
|
|
my $externalip = $stats{'externalip'};
|
367 |
|
|
my $memorygb = $stats{'memory'};
|
368 |
|
|
my $nodevirtualsizegb = $stats{'nodevirtualsize'};
|
369 |
95b003ff
|
Origo
|
$rx = $stats{'rx'};
|
370 |
|
|
$tx = $stats{'tx'};
|
371 |
|
|
$vcpu = $stats{'vcpu'};
|
372 |
|
|
|
373 |
|
|
my $res;
|
374 |
|
|
if ($params{'format'} eq 'html') {
|
375 |
|
|
$postreply .= header("text/html");
|
376 |
|
|
$res .= qq[<tr><th>Ressource</th><th>Quantity</th><th class="$irigo_cost">Cost/month</th><th>Quota</th></tr>];
|
377 |
|
|
$res .= qq[<tr><td>vCPU's:</td><td align="right">$vcpu</td><td align="right" class="$irigo_cost">$cur ] . int(0.5+$vcpu*$vcpuprice) . qq[</td><td align="right">$vcpuquota</td></tr>];
|
378 |
|
|
$res .= qq[<tr><td>Memory:</td><td align="right">$memorygb GB</td><td align="right" class="$irigo_cost">$cur ] . int(0.5+$memorygb*$memoryprice) . qq[</td><td align="right">$memoryquotagb GB</td></tr>];
|
379 |
|
|
$res .= qq[<tr><td>Shared storage:</td><td align="right">$virtualsizegb GB</td><td align="right" class="$irigo_cost">$cur ] . int(0.5+$virtualsizegb*$storageprice) . qq[</td><td align="right">$storagequotagb GB</td></tr>];
|
380 |
|
|
$res .= qq[<tr><td>Node storage:</td><td align="right">$nodevirtualsizegb GB</td><td align="right" class="$irigo_cost">$cur ] . int(0.5+$nodevirtualsizegb*$nodestorageprice) . qq[</td><td align="right">$nodestoragequotagb GB</td></tr>];
|
381 |
8d7785ff
|
Origo
|
$res .= qq[<tr><td>Backup storage (est.):</td><td align="right">$backupsizegb GB</td><td align="right" class="$irigo_cost">$cur ] . int(0.5+$backupsizegb*$storageprice) . qq[</td><td align="right">∞</td></tr>];
|
382 |
95b003ff
|
Origo
|
$res .= qq[<tr><td>External IP addresses:</td><td align="right">$externalip</td><td align="right" class="$irigo_cost">$cur ] . int(0.5+$externalip*$externalipprice) . qq[</td><td align="right">$externalipquota</td></tr>];
|
383 |
|
|
if (!$uuid) {
|
384 |
8d7785ff
|
Origo
|
$res .= qq[<tr><td>Network traffic out:</td><td align="right">] . $rx . qq[ GB</td><td align="right" class="$irigo_cost">$cur 0</td><td align="right">] . int(0.5 + $rxquota/1024/1024) . qq[ GB</td></tr>];
|
385 |
|
|
$res .= qq[<tr><td>Network traffic in:</td><td align="right">] . $tx . qq[ GB</td><td align="right" class="$irigo_cost">$cur 0</td><td align="right">] . int(0.5 + $txquota/1024/1024) . qq[ GB</td></tr>];
|
386 |
95b003ff
|
Origo
|
}
|
387 |
|
|
|
388 |
|
|
$res =~ s/-1/∞/g;
|
389 |
|
|
$res =~ s/>0 .B<\/td><\/tr>/>∞<\/td><\/tr>/g;
|
390 |
|
|
$postreply .= qq[<table cellspacing="0" noframe="void" norules="rows" class="systemTables">$res</table>];
|
391 |
|
|
} else {
|
392 |
|
|
my $bill = {
|
393 |
|
|
vcpus => {quantity => $vcpu, quota => $vcpuquota},
|
394 |
|
|
memory => {quantity => $memorygb, unit => 'GB', quota => $memoryquotagb},
|
395 |
|
|
shared_storage => {quantity => $virtualsizegb, unit => 'GB', quota => $storagequotagb},
|
396 |
|
|
node_storage => {quantity => $nodevirtualsizegb, unit => 'GB', quota => $nodestoragequotagb},
|
397 |
|
|
backup_storage => {quantity => $backupsizegb, unit => 'GB'},
|
398 |
|
|
external_ips => {quantity => $externalip, quota => $externalipquota},
|
399 |
8d7785ff
|
Origo
|
network_traffic_out => {quantity => $rx, unit => 'GB', quota => int(0.5 + $rxquota/1024/1024)},
|
400 |
|
|
network_traffic_in => {quantity => $tx, unit => 'GB', quota => int(0.5 + $txquota/1024/1024)}
|
401 |
95b003ff
|
Origo
|
};
|
402 |
|
|
if ($showcost) {
|
403 |
|
|
$bill->{vcpus}->{cost} = int(0.5+$vcpu*$vcpuprice);
|
404 |
|
|
$bill->{memory}->{cost} = int(0.5+$memorygb*$memoryprice);
|
405 |
|
|
$bill->{shared_storage}->{cost} = int(0.5+$virtualsizegb*$storageprice);
|
406 |
|
|
$bill->{node_storage}->{cost} = int(0.5+$nodevirtualsizegb*$nodestorageprice);
|
407 |
|
|
$bill->{backup_storage}->{cost} = int(0.5+$backupsizegb*$storageprice);
|
408 |
|
|
$bill->{external_ips}->{cost} = int(0.5+$externalip*$externalipprice);
|
409 |
|
|
$bill->{currency} = $cur;
|
410 |
|
|
$bill->{username} = $buser;
|
411 |
|
|
}
|
412 |
|
|
$postreply .= to_json($bill, {pretty=>1});
|
413 |
|
|
}
|
414 |
|
|
} elsif ($action eq "billingavgstatus" || $action eq "usageavgstatus") {
|
415 |
2a63870a
|
Christian Orellana
|
my $virtualsizeavggb = $stats{'virtualsizeavg'};
|
416 |
|
|
my $backupsizeavggb = $stats{'backupsizeavg'};
|
417 |
|
|
my $memoryavggb = $stats{'memoryavg'};
|
418 |
|
|
my $nodevirtualsizeavggb = $stats{'nodevirtualsizeavg'};
|
419 |
95b003ff
|
Origo
|
$vcpuavg = $stats{'vcpuavg'};
|
420 |
|
|
$externalipavg = $stats{'externalipavg'};
|
421 |
|
|
$rx = $stats{'rx'};
|
422 |
|
|
$tx = $stats{'tx'};
|
423 |
|
|
if ($params{'format'} eq 'html') {
|
424 |
|
|
$postreply .= header("text/html");
|
425 |
|
|
my $res;
|
426 |
|
|
$res .= qq[<tr><th>Ressource</th><th>Quantity</th><th class="$irigo_cost">Cost/month</th><th>Quota</th></tr>];
|
427 |
|
|
$res .= qq[<tr><td>vCPU's:</td><td align="right">] . int(0.5+100*$vcpuavg)/100 . qq[</td><td align="right" class="$irigo_cost">$cur ] . int(0.5+$vcpuavg*$vcpuprice) . qq[</td><td align="right">$vcpuquota</td></tr>];
|
428 |
|
|
$res .= qq[<tr><td>Memory:</td><td align="right">$memoryavggb GB</td><td align="right" class="$irigo_cost">$cur ] . int(0.5+$memoryavggb*$memoryprice) . qq[</td><td align="right">$memoryquotagb GB</td></tr>];
|
429 |
|
|
$res .= qq[<tr><td>Shared storage:</td><td align="right">$virtualsizeavggb GB</td><td align="right" class="$irigo_cost">$cur ] . int(0.5+$virtualsizeavggb*$storageprice) . qq[</td><td align="right">$storagequotagb GB</td></tr>];
|
430 |
|
|
$res .= qq[<tr><td>Node storage:</td><td align="right">$nodevirtualsizeavggb GB</td><td align="right" class="$irigo_cost">$cur ] . int(0.5+$nodevirtualsizeavggb*$nodestorageprice) . qq[</td><td align="right">$nodestoragequotagb GB</td></tr>];
|
431 |
8d7785ff
|
Origo
|
$res .= qq[<tr><td>Backup storage (est.):</td><td align="right">$backupsizeavggb GB</td><td align="right" class="$irigo_cost">$cur ] . int(0.5+$backupsizeavggb*$storageprice) . qq[</td><td align="right">∞</td></tr>];
|
432 |
95b003ff
|
Origo
|
$res .= qq[<tr><td>External IP addresses:</td><td align="right">] . int(0.5+100*$externalipavg)/100 . qq[</td><td align="right" class="$irigo_cost">$cur ] . int(0.5+$externalipavg*$externalipprice) . qq[</td><td align="right">$externalipquota</td></tr>];
|
433 |
|
|
$res .= qq[<tr><td>Network traffic in:</td><td align="right">] . int(0.5 + $rx) . qq[ GB</td><td align="right" class="$irigo_cost">$cur 0</td><td align="right">] . int(0.5 + $rxquota/1024/1024) . qq[ GB</td></tr>];
|
434 |
|
|
$res .= qq[<tr><td>Network traffic out:</td><td align="right">] . int(0.5 + $tx) . qq[ GB</td><td align="right" class="$irigo_cost">$cur 0</td><td align="right">] . int(0.5 + $txquota/1024/1024) . qq[ GB</td></tr>];
|
435 |
|
|
|
436 |
|
|
$res =~ s/-1/∞/g;
|
437 |
|
|
$res =~ s/>0 .B<\/td><\/tr>/>∞<\/td><\/tr>/g;
|
438 |
|
|
$postreply .= qq[<table cellspacing="0" noframe="void" norules="rows" class="systemTables">$res</table>];
|
439 |
|
|
} else {
|
440 |
|
|
my $bill = {
|
441 |
|
|
vcpus => {quantity => $vcpuavg, quota => $vcpuquota},
|
442 |
|
|
memory => {quantity => $memoryavggb, unit => 'GB', quota => $memoryquotagb},
|
443 |
|
|
shared_storage => {quantity => $virtualsizeavggb, unit => 'GB', quota => $storagequotagb},
|
444 |
|
|
node_storage => {quantity => $nodevirtualsizeavggb, unit => 'GB', quota => $nodestoragequotagb},
|
445 |
|
|
backup_storage => {quantity => $backupsizeavggb, unit => 'GB'},
|
446 |
|
|
external_ips => {quantity => $externalipavg, quota => $externalipquota},
|
447 |
|
|
network_traffic_out => {quantity => int(0.5 + $rx), unit => 'GB', quota => int(0.5 + $rxquota/1024/1024)},
|
448 |
|
|
network_traffic_in => {quantity => int(0.5 + $tx), unit => 'GB', quota => int(0.5 + $txquota/1024/1024)}
|
449 |
|
|
};
|
450 |
|
|
if ($showcost) {
|
451 |
|
|
$bill->{vcpus}->{cost} = int(0.5+$vcpuavg*$vcpuprice);
|
452 |
|
|
$bill->{memory}->{cost} = int(0.5+$memoryavggb*$memoryprice);
|
453 |
|
|
$bill->{shared_storage}->{cost} = int(0.5+$virtualsizeavggb*$storageprice);
|
454 |
|
|
$bill->{node_storage}->{cost} = int(0.5+$nodevirtualsizeavggb*$nodestorageprice);
|
455 |
|
|
$bill->{backup_storage}->{cost} = int(0.5+$backupsizeavggb*$storageprice);
|
456 |
|
|
$bill->{external_ips}->{cost} = int(0.5+$externalipavg*$externalipprice);
|
457 |
|
|
$bill->{currency} = $cur;
|
458 |
|
|
$bill->{username} = $buser;
|
459 |
|
|
}
|
460 |
|
|
$postreply .= to_json($bill, {pretty=>1});
|
461 |
|
|
}
|
462 |
|
|
}
|
463 |
|
|
} else {
|
464 |
|
|
$postreply .= "Status=ERROR no privileges!!\n";
|
465 |
|
|
}
|
466 |
|
|
return $postreply;
|
467 |
|
|
}
|
468 |
|
|
|
469 |
|
|
sub do_listenginebackups {
|
470 |
|
|
my ($uuid, $action, $obj) = @_;
|
471 |
|
|
if ($help) {
|
472 |
|
|
return <<END
|
473 |
|
|
GET::
|
474 |
48fcda6b
|
Origo
|
List the backups of this engine's configuration in the registry.
|
475 |
95b003ff
|
Origo
|
END
|
476 |
|
|
}
|
477 |
|
|
if ($enginelinked) {
|
478 |
|
|
require LWP::Simple;
|
479 |
|
|
my $browser = LWP::UserAgent->new;
|
480 |
|
|
$browser->agent('stabile/1.0b');
|
481 |
|
|
$browser->protocols_allowed( [ 'http','https'] );
|
482 |
|
|
|
483 |
|
|
my $tktcfg = ConfigReader::Simple->new($Stabile::auth_tkt_conf, [qw(TKTAuthSecret)]);
|
484 |
|
|
my $tktkey = $tktcfg->get('TKTAuthSecret') || '';
|
485 |
|
|
|
486 |
|
|
$postreq->{'engineid'} = $engineid;
|
487 |
|
|
$postreq->{'enginetkthash'} = Digest::SHA::sha512_hex($tktkey);
|
488 |
|
|
|
489 |
48fcda6b
|
Origo
|
my $content = $browser->post("https://www.stabile.io/irigo/engine.cgi?action=listbackups", $postreq)->content();
|
490 |
95b003ff
|
Origo
|
if ($content =~ /\[\]/) {
|
491 |
|
|
$postreply = qq|{"identifier": "path", "label": "name", "items": [{"path": "#", "name": "No backups"}]}|;
|
492 |
|
|
} else {
|
493 |
|
|
$postreply = qq|{"identifier": "path", "label": "name", "items": $content}|;
|
494 |
|
|
}
|
495 |
|
|
} else {
|
496 |
|
|
$postreply = qq|{"identifier": "path", "label": "name", "items": [{"path": "#", "name": "Engine not linked"}]}|;
|
497 |
|
|
}
|
498 |
|
|
return $postreply;
|
499 |
|
|
}
|
500 |
|
|
|
501 |
|
|
sub Backupengine {
|
502 |
|
|
my ($uuid, $action, $obj) = @_;
|
503 |
|
|
if ($help) {
|
504 |
|
|
return <<END
|
505 |
|
|
GET::
|
506 |
48fcda6b
|
Origo
|
Backup this engine's configuration to the registry.
|
507 |
95b003ff
|
Origo
|
END
|
508 |
|
|
}
|
509 |
|
|
my $backupname = "$enginename.$engineid.$pretty_time";
|
510 |
|
|
$backupname =~ tr/:/-/; # tar has a problem with colons in filenames
|
511 |
|
|
if (-e "/tmp/$backupname.tgz") {
|
512 |
|
|
$postreply .= "Status=ERROR Engine is already being backed up";
|
513 |
|
|
} else {
|
514 |
|
|
$res .= `mysqldump --ignore-table=steamregister.nodeidentities steamregister > /etc/stabile/steamregister.sql`;
|
515 |
|
|
$res .= `cp /etc/apache2/conf-available/auth_tkt_cgi.conf /etc/stabile`;
|
516 |
|
|
$res .= `cp /etc/apache2/ssl/*.crt /etc/stabile`;
|
517 |
|
|
$res .= `cp /etc/apache2/ssl/*.pem /etc/stabile`;
|
518 |
|
|
$res .= `cp /etc/apache2/ssl/*.key /etc/stabile`;
|
519 |
|
|
$res .= `cp /etc/hosts.allow /etc/stabile`;
|
520 |
|
|
$res .= `cp /etc/mon/mon.cf /etc/stabile`;
|
521 |
|
|
|
522 |
|
|
# copy default node configuration to /etc/stabile
|
523 |
|
|
unless ( tie(%register,'Tie::DBI', Hash::Merge::merge({table=>'nodeidentities', key=>'identity'}, $Stabile::dbopts)) ) {return "Unable to access identity register"};
|
524 |
|
|
|
525 |
|
|
my $defaultpath = $idreg{'default'}->{'path'} . "/casper/filesystem.dir/etc/stabile/nodeconfig.cfg";
|
526 |
|
|
$res .= `cp $defaultpath /etc/stabile`;
|
527 |
|
|
|
528 |
|
|
# Make tarball
|
529 |
|
|
my $cmd = qq[(cd /etc/stabile; /bin/tar -czf "/tmp/$backupname.tgz" * 2>/dev/null)];
|
530 |
|
|
$res .= `$cmd`;
|
531 |
|
|
|
532 |
|
|
my $tktcfg = ConfigReader::Simple->new($Stabile::auth_tkt_conf, [qw(TKTAuthSecret)]);
|
533 |
|
|
my $tktkey = $tktcfg->get('TKTAuthSecret') || '';
|
534 |
|
|
my $enginetkthash = Digest::SHA::sha512_hex($tktkey);
|
535 |
|
|
|
536 |
48fcda6b
|
Origo
|
my $res = `/usr/bin/curl -k -F engineid=$engineid -F enginetkthash=$enginetkthash -F filedata=@"/tmp/$backupname.tgz" https://www.stabile.io/irigo/engine.cgi?action=backup`;
|
537 |
95b003ff
|
Origo
|
if ($res =~ /OK: $backupname.tgz received/) {
|
538 |
48fcda6b
|
Origo
|
$postreply .= "Status=OK Engine configuration saved to the registry";
|
539 |
|
|
$main::syslogit->($user, "info", "Engine configuration saved to the registry");
|
540 |
95b003ff
|
Origo
|
unlink("/tmp/$backupname.tgz");
|
541 |
|
|
} else {
|
542 |
48fcda6b
|
Origo
|
$postreply .= "Status=ERROR Problem backing configuration up to the registry\n$res\n";
|
543 |
95b003ff
|
Origo
|
}
|
544 |
|
|
}
|
545 |
|
|
return $postreply;
|
546 |
|
|
}
|
547 |
|
|
|
548 |
|
|
sub Upgradeengine {
|
549 |
|
|
my ($uuid, $action, $obj) = @_;
|
550 |
|
|
if ($help) {
|
551 |
|
|
return <<END
|
552 |
|
|
GET::
|
553 |
48fcda6b
|
Origo
|
Try to upgrade this engine to latest release from the registry
|
554 |
95b003ff
|
Origo
|
END
|
555 |
|
|
}
|
556 |
4aef7ef6
|
hq
|
$postreply = "Status=OK Requesting upgrade of Stabile\n";
|
557 |
|
|
print header("text/plain"), $postreply;
|
558 |
95b003ff
|
Origo
|
`echo "UPGRADE=1" >> /etc/stabile/config.cfg` unless ( `grep ^UPGRADE=1 /etc/stabile/config.cfg`);
|
559 |
4aef7ef6
|
hq
|
my $cmd = "echo 'sleep 5 ; /usr/bin/pkill pressurecontrol' | at now";
|
560 |
|
|
system($cmd);
|
561 |
|
|
exit 0;
|
562 |
95b003ff
|
Origo
|
}
|
563 |
|
|
|
564 |
|
|
sub do_billengine {
|
565 |
|
|
my ($uuid, $action, $obj) = @_;
|
566 |
|
|
if ($help) {
|
567 |
|
|
return <<END
|
568 |
|
|
GET::
|
569 |
48fcda6b
|
Origo
|
Submit billing data for this engine to the registry.
|
570 |
95b003ff
|
Origo
|
END
|
571 |
|
|
}
|
572 |
|
|
require LWP::Simple;
|
573 |
|
|
my $browser = LWP::UserAgent->new;
|
574 |
|
|
$browser->agent('stabile/1.0b');
|
575 |
|
|
$browser->protocols_allowed( [ 'http','https'] );
|
576 |
|
|
|
577 |
|
|
my $bmonth = $params{'month'} || $month;
|
578 |
|
|
$bmonth = substr("0$bmonth", -2);
|
579 |
|
|
my $byear = $params{'year'} || $year;
|
580 |
|
|
$showcost = 1;
|
581 |
|
|
|
582 |
|
|
my $tktcfg = ConfigReader::Simple->new($Stabile::auth_tkt_conf, [qw(TKTAuthSecret)]);
|
583 |
|
|
my $tktkey = $tktcfg->get('TKTAuthSecret') || '';
|
584 |
|
|
my $tkthash = Digest::SHA::sha512_hex($tktkey);
|
585 |
|
|
|
586 |
|
|
my $postreq = ();
|
587 |
|
|
my %bill;
|
588 |
|
|
my @regvalues = values %register; # Sort by id
|
589 |
|
|
foreach my $valref (@regvalues) {
|
590 |
d24d9a01
|
hq
|
my $cuser = $valref->{'username'};
|
591 |
|
|
my %stats = collectBillingData( '', $cuser, $bmonth, $byear, $showcost );
|
592 |
|
|
$bill{"$cuser-$byear-$bmonth"} = \%stats;
|
593 |
95b003ff
|
Origo
|
}
|
594 |
|
|
$postreq->{'engineid'} = $engineid;
|
595 |
|
|
$postreq->{'enginetkthash'} = $tkthash;
|
596 |
|
|
$postreq->{'keywords'} = JSON::to_json(\%bill, {pretty=>1});
|
597 |
48fcda6b
|
Origo
|
my $url = "https://www.stabile.io/irigo/engine.cgi";
|
598 |
95b003ff
|
Origo
|
$content = $browser->post($url, $postreq)->content();
|
599 |
|
|
$postreply = "Status=OK Billed this engine ($engineid)\n";
|
600 |
|
|
$postreply .= "$postreq->{'keywords'}\n$content";
|
601 |
|
|
return $postreply;
|
602 |
|
|
}
|
603 |
|
|
|
604 |
|
|
sub Linkengine {
|
605 |
|
|
my ($uuid, $action, $obj) = @_;
|
606 |
|
|
if ($help) {
|
607 |
|
|
return <<END
|
608 |
|
|
PUT:username,password,engineid,enginename,engineurl:
|
609 |
48fcda6b
|
Origo
|
Links engine to the registry
|
610 |
95b003ff
|
Origo
|
END
|
611 |
|
|
}
|
612 |
|
|
return "Status=Error Not allowed\n" unless ($isadmin || ($user eq $engineuser));
|
613 |
|
|
my $linkaction = 'update';
|
614 |
|
|
$linkaction = 'link' if ($action eq 'linkengine');
|
615 |
|
|
$linkaction = 'unlink' if ($action eq 'unlinkengine');
|
616 |
|
|
$linkaction = 'update' if ($action eq 'updateengine');
|
617 |
|
|
$linkaction = 'update' if ($action eq 'syncusers');
|
618 |
|
|
|
619 |
|
|
require LWP::Simple;
|
620 |
|
|
my $browser = LWP::UserAgent->new;
|
621 |
|
|
$browser->agent('stabile/1.0b');
|
622 |
|
|
$browser->protocols_allowed( [ 'http','https'] );
|
623 |
|
|
|
624 |
|
|
my $tktcfg = ConfigReader::Simple->new($Stabile::auth_tkt_conf, [qw(TKTAuthSecret)]);
|
625 |
|
|
my $tktkey = $tktcfg->get('TKTAuthSecret') || '';
|
626 |
|
|
|
627 |
|
|
my $postreq = ();
|
628 |
|
|
$postreq->{'user'} = $user || $obj->{'username'};
|
629 |
|
|
$postreq->{'engineid'} = $obj->{'engineid'} || $engineid;
|
630 |
|
|
$postreq->{'pwd'} = $obj->{'pwd'} if ($obj->{'pwd'});
|
631 |
|
|
$postreq->{'enginename'} = $obj->{'enginename'} if ($obj->{'enginename'});
|
632 |
|
|
$postreq->{'engineurl'} = $obj->{'engineurl'} if ($obj->{'engineurl'});
|
633 |
|
|
if ($tktkey) {
|
634 |
|
|
if ($action eq 'linkengine') {
|
635 |
48fcda6b
|
Origo
|
$main::syslogit->($user, "info", "Linking engine with the registry");
|
636 |
95b003ff
|
Origo
|
$postreq->{'enginetktkey'} = $tktkey;
|
637 |
|
|
} else {
|
638 |
|
|
$postreq->{'enginetkthash'} = Digest::SHA::sha512_hex($tktkey);
|
639 |
|
|
}
|
640 |
|
|
}
|
641 |
48fcda6b
|
Origo
|
if ($action eq "saveengine") { # Save request from the registry - don't post back
|
642 |
|
|
# Pressurecontrol reads new configuration data from the registry, simply reload it
|
643 |
95b003ff
|
Origo
|
my $pressureon = !(`systemctl is-active pressurecontrol` =~ /inactive/);
|
644 |
|
|
$postreply = ($pressureon)? "Status=OK Engine updating...\n":"Status=OK Engine not updating because pressurecontrol not active\n";
|
645 |
|
|
$postreply .= `systemctl restart pressurecontrol` if ($pressureon);
|
646 |
|
|
} else {
|
647 |
|
|
my $res;
|
648 |
|
|
my $cfg = new Config::Simple("/etc/stabile/config.cfg");
|
649 |
|
|
if ($action eq 'linkengine' || $action eq 'syncusers') {
|
650 |
48fcda6b
|
Origo
|
# Send engine users to the registry
|
651 |
95b003ff
|
Origo
|
my @vals = values %register;
|
652 |
|
|
my $json = JSON::to_json(\@vals);
|
653 |
|
|
$json =~ s/null/""/g;
|
654 |
|
|
$json = URI::Escape::uri_escape($json);
|
655 |
|
|
$postreq->{'POSTDATA'} = $json;
|
656 |
|
|
}
|
657 |
|
|
if ($action eq 'linkengine' || $action eq 'updateengine') {
|
658 |
|
|
# Update name in config file
|
659 |
|
|
if ($postreq->{'enginename'} && $cfg->param("ENGINENAME") ne $postreq->{'enginename'}) {
|
660 |
|
|
$cfg->param("ENGINENAME", $postreq->{'enginename'});
|
661 |
|
|
$cfg->save();
|
662 |
|
|
}
|
663 |
48fcda6b
|
Origo
|
# Send entire engine config file to the registry
|
664 |
95b003ff
|
Origo
|
my %cfghash = $cfg->vars();
|
665 |
|
|
foreach my $param (keys %cfghash) {
|
666 |
|
|
$param =~ /default\.(.+)/; # Get rid of default. prefix
|
667 |
|
|
if ($1) {
|
668 |
|
|
my $k = $1;
|
669 |
|
|
my @cvals = $cfg->param($param);
|
670 |
|
|
my $cval = join(", ", @cvals);
|
671 |
|
|
$postreq->{$k} = URI::Escape::uri_escape($cval);
|
672 |
|
|
}
|
673 |
|
|
}
|
674 |
48fcda6b
|
Origo
|
# Send entire engine piston config file to the registry
|
675 |
95b003ff
|
Origo
|
my $nodeconfigfile = "/mnt/stabile/tftp/bionic/casper/filesystem.dir/etc/stabile/nodeconfig.cfg";
|
676 |
|
|
if (-e $nodeconfigfile) {
|
677 |
|
|
my $pistoncfg = new Config::Simple($nodeconfigfile);
|
678 |
|
|
%cfghash = $pistoncfg->vars();
|
679 |
|
|
foreach my $param (keys %cfghash) {
|
680 |
|
|
$param =~ /default\.(.+)/; # Get rid of default. prefix
|
681 |
|
|
if ($1) {
|
682 |
|
|
my $k = $1;
|
683 |
|
|
my @cvals = $pistoncfg->param($param);
|
684 |
|
|
my $cval = join(", ", @cvals);
|
685 |
|
|
$postreq->{$k} = URI::Escape::uri_escape($cval);
|
686 |
|
|
}
|
687 |
|
|
}
|
688 |
|
|
}
|
689 |
|
|
}
|
690 |
|
|
if ($linkaction eq 'link' || $enginelinked) {
|
691 |
48fcda6b
|
Origo
|
my $content = $browser->post("https://www.stabile.io/irigo/engine.cgi?action=$linkaction", $postreq)->content();
|
692 |
95b003ff
|
Origo
|
if ($content =~ /(Engine linked|Engine not linked|Engine unlinked|Engine updated|Unknown engine|Invalid credentials .+\.)/i) {
|
693 |
|
|
$res = "Status=OK $1";
|
694 |
|
|
my $linked = 1;
|
695 |
|
|
$linked = 0 unless ($content =~ /Engine linked/i || $content =~ /Engine updated/i);
|
696 |
|
|
$cfg->param("ENGINE_LINKED", $linked);
|
697 |
|
|
$cfg->save();
|
698 |
48fcda6b
|
Origo
|
} elsif ($action eq 'syncusers' || $action eq 'linkengine') { # If we send user list to the registry we get merged list back
|
699 |
95b003ff
|
Origo
|
if ($content =~ /^\[/) { # Sanity check to see if we got json back
|
700 |
|
|
$res .= "Status=OK Engine linked\n" if ($action eq 'linkengine');
|
701 |
48fcda6b
|
Origo
|
# Update engine users with users from the registry
|
702 |
|
|
$res .= updateEngineUsers($content);
|
703 |
|
|
$res .= "Status=OK Users synced with registry\n";
|
704 |
95b003ff
|
Origo
|
$main::updateUI->({ tab => 'users', type=>'update', user=>$user});
|
705 |
|
|
}
|
706 |
48fcda6b
|
Origo
|
$res .= "$content" unless ($res =~ /Status=OK/); # Only add if there are problems
|
707 |
95b003ff
|
Origo
|
}
|
708 |
|
|
$postreply = $res;
|
709 |
|
|
$content =~ s/\n/ - /;
|
710 |
|
|
$res =~ s/\n/ - /;
|
711 |
64c667ea
|
hq
|
# $main::syslogit->($user, "info", "$content");
|
712 |
|
|
$main::syslogit->($user, "info", "Synced users");
|
713 |
95b003ff
|
Origo
|
} else {
|
714 |
|
|
$postreply .= "Status=OK Engine not linked, saving name\n";
|
715 |
|
|
}
|
716 |
|
|
}
|
717 |
|
|
return $postreply;
|
718 |
|
|
}
|
719 |
|
|
|
720 |
|
|
sub Releasepressure {
|
721 |
|
|
my ($uuid, $action, $obj) = @_;
|
722 |
|
|
if ($help) {
|
723 |
|
|
return <<END
|
724 |
|
|
GET::
|
725 |
|
|
Restarts pressurecontrol.
|
726 |
|
|
END
|
727 |
|
|
}
|
728 |
|
|
my $res;
|
729 |
|
|
unless (`systemctl is-active pressurecontrol` =~ /inactive/) {
|
730 |
|
|
my $daemon = Proc::Daemon->new(
|
731 |
|
|
work_dir => '/usr/local/bin',
|
732 |
|
|
exec_command => "systemctl restart pressurecontrol"
|
733 |
|
|
) or do {$postreply .= "Status=ERROR $@\n";};
|
734 |
|
|
my $pid = $daemon->Init();
|
735 |
|
|
# $res = `systemctl restart pressurecontrol`;
|
736 |
|
|
return "Status=OK Venting...\n";
|
737 |
|
|
} else {
|
738 |
|
|
return "Status=OK Not venting\n";
|
739 |
|
|
}
|
740 |
|
|
}
|
741 |
|
|
|
742 |
|
|
sub do_enable {
|
743 |
|
|
my ($uuid, $action, $obj) = @_;
|
744 |
|
|
if ($help) {
|
745 |
|
|
return <<END
|
746 |
|
|
GET:username:
|
747 |
|
|
Enable a user.
|
748 |
|
|
END
|
749 |
|
|
}
|
750 |
|
|
my $username = $obj->{'username'};
|
751 |
71b897d3
|
hq
|
return unless ($username);
|
752 |
95b003ff
|
Origo
|
if ($isadmin || ($user eq $engineuser)) {
|
753 |
71b897d3
|
hq
|
# Create user on this engine if not yet created
|
754 |
|
|
do_save($username, 'save', $obj);
|
755 |
95b003ff
|
Origo
|
my $uprivileges = $register{$username}->{'privileges'};
|
756 |
|
|
$uprivileges =~ s/d//;
|
757 |
|
|
$uprivileges .= 'n' unless ($uprivileges =~ /n/);# These are constant sources of problems - enable by default when enabling users to alleviate situation
|
758 |
|
|
$register{$username}->{'privileges'} = $uprivileges;
|
759 |
|
|
$register{$username}->{'allowinternalapi'} = 1;
|
760 |
|
|
$postreply .= "Status=OK User $username enabled\n";
|
761 |
|
|
} else {
|
762 |
|
|
$postreply .= "Status=ERROR Not allowed\n";
|
763 |
|
|
}
|
764 |
|
|
$uiuuid = $username;
|
765 |
|
|
return $postreply;
|
766 |
|
|
}
|
767 |
|
|
|
768 |
|
|
sub do_disable {
|
769 |
|
|
my ($uuid, $action, $obj) = @_;
|
770 |
|
|
if ($help) {
|
771 |
|
|
return <<END
|
772 |
|
|
GET:username:
|
773 |
|
|
Disable a user.
|
774 |
|
|
END
|
775 |
|
|
}
|
776 |
|
|
my $username = $obj->{'username'};
|
777 |
|
|
if ($isadmin || ($user eq $engineuser)) {
|
778 |
|
|
my $uprivileges = $register{$username}->{'privileges'};
|
779 |
|
|
$uprivileges .= 'd' unless ($uprivileges =~ /d/);
|
780 |
|
|
$register{$username}->{'privileges'} = $uprivileges;
|
781 |
|
|
$postreply .= "Stream=OK User $username disabled, halting servers...\n";
|
782 |
|
|
require "$Stabile::basedir/cgi/servers.cgi";
|
783 |
|
|
$Stabile::Servers::console = 1;
|
784 |
|
|
$postreply .= Stabile::Servers::destroyUserServers($username,1);
|
785 |
|
|
`/bin/rm /tmp/$username~*.tasks`;
|
786 |
|
|
} else {
|
787 |
|
|
$postreply .= "Status=ERROR Not allowed\n";
|
788 |
|
|
}
|
789 |
|
|
$uiuuid = $username;
|
790 |
|
|
return $postreply;
|
791 |
|
|
}
|
792 |
|
|
|
793 |
|
|
sub Updateui {
|
794 |
|
|
my ($uuid, $action, $obj) = @_;
|
795 |
|
|
if ($help) {
|
796 |
|
|
return <<END
|
797 |
|
|
GET:username,message,tab:
|
798 |
|
|
Update the UI for given user if logged into UI.
|
799 |
|
|
END
|
800 |
|
|
}
|
801 |
|
|
my $username = $obj->{'username'} || $user;
|
802 |
|
|
my $message = $obj->{'message'};
|
803 |
|
|
my $tab = $obj->{'tab'} || 'home';
|
804 |
|
|
if ($isadmin || ($username eq $user) || ($user eq $engineuser)) {
|
805 |
|
|
$postreply = $main::updateUI->({ tab => $tab, user => $username, message =>$message, type=>'update'});
|
806 |
|
|
} else {
|
807 |
|
|
$postreply = "Status=ERROR Not allowed\n";
|
808 |
|
|
}
|
809 |
|
|
}
|
810 |
|
|
|
811 |
|
|
sub do_updateclientui {
|
812 |
|
|
my ($uuid, $action, $obj) = @_;
|
813 |
|
|
if ($help) {
|
814 |
|
|
return <<END
|
815 |
6fdc8676
|
hq
|
GET:username,message,tab,type:
|
816 |
95b003ff
|
Origo
|
Update the UI for given user if logged into UI.
|
817 |
|
|
END
|
818 |
|
|
}
|
819 |
|
|
my $username = $obj->{'username'} || $user;
|
820 |
|
|
my $message = $obj->{'message'};
|
821 |
|
|
my $tab = $obj->{'tab'} || 'home';
|
822 |
6fdc8676
|
hq
|
my $type= $obj->{'type'} || 'update';
|
823 |
95b003ff
|
Origo
|
if ($isadmin || ($username eq $user) || ($user eq $engineuser)) {
|
824 |
6fdc8676
|
hq
|
$postreply = $main::updateUI->({ tab => $tab, user => $username, message =>$message, type=>$type});
|
825 |
95b003ff
|
Origo
|
} else {
|
826 |
|
|
$postreply = "Status=ERROR Not allowed\n";
|
827 |
|
|
}
|
828 |
|
|
}
|
829 |
|
|
|
830 |
|
|
sub Vent {
|
831 |
|
|
my ($uuid, $action, $obj) = @_;
|
832 |
|
|
if ($help) {
|
833 |
|
|
return <<END
|
834 |
|
|
GET::
|
835 |
|
|
Restart pressurecontrol.
|
836 |
|
|
END
|
837 |
|
|
}
|
838 |
|
|
`systemctl restart pressurecontrol`;
|
839 |
|
|
$postreply = "Status=OK Restarting pressurecontrol\n";
|
840 |
|
|
return $postreply;
|
841 |
|
|
}
|
842 |
|
|
|
843 |
|
|
sub Deleteentirely {
|
844 |
|
|
my ($uuid, $action, $obj) = @_;
|
845 |
|
|
if ($help) {
|
846 |
|
|
return <<END
|
847 |
|
|
GET:username:
|
848 |
|
|
Deletes a user and all the user's servers, images, networks etc. Warning: This destroys data
|
849 |
|
|
END
|
850 |
|
|
}
|
851 |
|
|
my $username = $obj->{'username'};
|
852 |
|
|
my $reply = "Status=OK Removed $username\n";
|
853 |
|
|
if (($isadmin || ($user eq $engineuser)) && $register{$username} && !($register{$username}->{'privileges'} =~ /a/) && !($username eq $engineuser)) {
|
854 |
|
|
#Never delete admins
|
855 |
|
|
my @dusers = ($username);
|
856 |
|
|
# Add list of subusers - does not look like a good idea
|
857 |
|
|
# foreach my $u (values %register) {
|
858 |
|
|
# push @dusers, $u->{'username'} if ($u->{'billto'} && $u->{'billto'} eq $username);
|
859 |
|
|
# };
|
860 |
|
|
|
861 |
|
|
foreach my $uname (@dusers) {
|
862 |
|
|
next if ($register{$uname}->{privileges} =~ /a/); #Never delete admins
|
863 |
|
|
$main::updateUI->({ tab => 'users', type=>'update', user=>$user, username=>$username, status=>'deleting'});
|
864 |
|
|
|
865 |
|
|
$postreply .= "Stream=OK Deleting user $uname and all associated data!!!\n";
|
866 |
|
|
|
867 |
|
|
require "$Stabile::basedir/cgi/servers.cgi";
|
868 |
|
|
$Stabile::Servers::console = 1;
|
869 |
|
|
|
870 |
|
|
require "$Stabile::basedir/cgi/systems.cgi";
|
871 |
|
|
$Stabile::Systems::console = 1;
|
872 |
|
|
Stabile::Systems::removeusersystems($uname);
|
873 |
|
|
Stabile::Servers::removeUserServers($uname);
|
874 |
|
|
|
875 |
|
|
require "$Stabile::basedir/cgi/images.cgi";
|
876 |
|
|
$Stabile::Images::console = 1;
|
877 |
|
|
$postreply .= Stabile::Images::removeUserImages($uname);
|
878 |
|
|
|
879 |
|
|
require "$Stabile::basedir/cgi/networks.cgi";
|
880 |
|
|
$Stabile::Networks::console = 1;
|
881 |
|
|
Stabile::Networks::Removeusernetworks($uname);
|
882 |
|
|
|
883 |
|
|
remove($uname);
|
884 |
|
|
$reply = "$reply\n$postreply";
|
885 |
|
|
|
886 |
|
|
# Also remove billing data, so next user with same username does not get old billing data
|
887 |
|
|
`echo "delete from billing_domains where usernodetime like '$uname-%';" | mysql steamregister`;
|
888 |
|
|
`echo "delete from billing_images where userstoragepooltime like '$uname-%';" | mysql steamregister`;
|
889 |
|
|
`echo "delete from billing_networks where useridtime like '$uname-%';" | mysql steamregister`;
|
890 |
|
|
}
|
891 |
48fcda6b
|
Origo
|
$main::updateUI->({tab => 'users', type=>'update', user=>$user});
|
892 |
95b003ff
|
Origo
|
|
893 |
|
|
} else {
|
894 |
|
|
$postreply .= "Stream=ERROR Cannot delete user $username - you cannot delete administrators!\n";
|
895 |
|
|
$reply = $postreply;
|
896 |
|
|
}
|
897 |
|
|
return $reply;
|
898 |
|
|
}
|
899 |
|
|
|
900 |
|
|
sub do_save {
|
901 |
71b897d3
|
hq
|
my ($username, $action, $obj) = @_;
|
902 |
95b003ff
|
Origo
|
if ($help) {
|
903 |
|
|
return <<END
|
904 |
a439a9c4
|
hq
|
POST:username, password, privileges, fullname, email, opemail, alertemail, phone, opphone, opfullname, allowfrom, allowinternalapi, accounts, accountsprivileges, storagepools, memoryquota, storagequota, nodestoragequota, vcpuquota, externalipquota, rxquota, txquota:
|
905 |
71b897d3
|
hq
|
Saves a user. If [username] does not exist, it is created if privileges allow this. [password] can be plaintext or a SHA256 hash.
|
906 |
95b003ff
|
Origo
|
END
|
907 |
|
|
}
|
908 |
71b897d3
|
hq
|
$username = $username || $obj->{"username"};
|
909 |
95b003ff
|
Origo
|
unless ($username && (($user eq $username) || $isadmin || ($user eq $engineuser))) {
|
910 |
|
|
$postreply = "Status=ERROR Please provide a valid username\n";
|
911 |
|
|
return $postreply;
|
912 |
|
|
}
|
913 |
|
|
my $password = '';
|
914 |
|
|
my $reguser = $register{$username};
|
915 |
|
|
if ($obj->{"password"} && $obj->{"password"} ne '--') {
|
916 |
|
|
if (length $obj->{'password'} == 86) {
|
917 |
|
|
$password = $obj->{"password"}; # This is already encoded
|
918 |
|
|
} else {
|
919 |
|
|
$password = $obj->{"password"};
|
920 |
|
|
$MAXLEN = 20;
|
921 |
|
|
my $msg = IsBadPassword($password);
|
922 |
|
|
if ($msg) {
|
923 |
|
|
$postreply = "Status=Error $msg - please choose a stronger password\n";
|
924 |
|
|
$postmsg = "$msg - please choose a stronger password";
|
925 |
|
|
return $postreply;
|
926 |
|
|
} else {
|
927 |
|
|
$password = Digest::SHA::sha512_base64($password);
|
928 |
|
|
}
|
929 |
|
|
}
|
930 |
|
|
} else {
|
931 |
|
|
$password = $reguser->{'password'};
|
932 |
|
|
}
|
933 |
|
|
my $fullname = $obj->{"fullname"} || $reguser->{'fullname'};
|
934 |
|
|
my $email = $obj->{"email"} || $reguser->{'email'};
|
935 |
|
|
my $opemail = $obj->{"opemail"} || $reguser->{'opemail'};
|
936 |
|
|
my $alertemail = $obj->{"alertemail"} || $reguser->{'alertemail'};
|
937 |
|
|
my $phone = $obj->{"phone"} || $reguser->{'phone'};
|
938 |
|
|
my $opphone = $obj->{"opphone"} || $reguser->{'opphone'};
|
939 |
|
|
my $opfullname = $obj->{"opfullname"} || $reguser->{'opfullname'};
|
940 |
4aef7ef6
|
hq
|
my $allowfrom = $obj->{"allowfrom"};
|
941 |
705b5366
|
hq
|
my $totpsecret = $reguser->{'totpsecret'};
|
942 |
|
|
$totpsecret = $obj->{"totpsecret"} if (defined $obj->{"totpsecret"});
|
943 |
95b003ff
|
Origo
|
my $allowinternalapi = $obj->{"allowinternalapi"} || $reguser->{'allowinternalapi'};
|
944 |
|
|
|
945 |
4aef7ef6
|
hq
|
if (defined $obj->{"allowfrom"}) {
|
946 |
95b003ff
|
Origo
|
my @allows = split(/(,\s*|\s+)/, $allowfrom);
|
947 |
|
|
$allowfrom = '';
|
948 |
4aef7ef6
|
hq
|
my %allowshash;
|
949 |
95b003ff
|
Origo
|
foreach my $ip (@allows) {
|
950 |
4aef7ef6
|
hq
|
$allowshash{"$1$2"} = 1 if ($ip =~ /(\d+\.\d+\.\d+\.\d+)(\/\d+)?/);
|
951 |
|
|
if ($ip =~ /\w\w/) { # Check if we are dealing with a country code
|
952 |
|
|
$ip = uc $ip;
|
953 |
|
|
my $geoip = Geo::IP->new(GEOIP_MEMORY_CACHE);
|
954 |
|
|
my $tz = $geoip->time_zone($ip, '');
|
955 |
|
|
$allowshash{$ip} = 1 if ($tz); # We have a valid country code
|
956 |
|
|
}
|
957 |
95b003ff
|
Origo
|
}
|
958 |
4aef7ef6
|
hq
|
$allowfrom = join(", ", sort(keys %allowshash));
|
959 |
95b003ff
|
Origo
|
}
|
960 |
|
|
|
961 |
|
|
my $uprivileges = $reguser->{'privileges'};
|
962 |
|
|
my $uaccounts = $reguser->{'accounts'};
|
963 |
|
|
my $uaccountsprivileges = $reguser->{'accountsprivileges'};
|
964 |
|
|
my $storagepools = $reguser->{'storagepools'};
|
965 |
|
|
my $memoryquota = $reguser->{'memoryquota'};
|
966 |
|
|
my $storagequota = $reguser->{'storagequota'};
|
967 |
|
|
my $nodestoragequota = $reguser->{'nodestoragequota'};
|
968 |
|
|
my $vcpuquota = $reguser->{'vcpuquota'};
|
969 |
|
|
my $externalipquota = $reguser->{'externalipquota'};
|
970 |
|
|
my $rxquota = $reguser->{'rxquota'};
|
971 |
|
|
my $txquota = $reguser->{'txquota'};
|
972 |
|
|
my $tasks = $reguser->{'tasks'};
|
973 |
|
|
my $ubillto = $reguser->{'billto'};
|
974 |
45cc3024
|
hq
|
my $udnsdomains = $reguser->{'dnsdomains'};
|
975 |
|
|
my $uappstoreurl = $reguser->{'appstoreurl'}; $uappstoreurl = '' if ($uappstoreurl eq '--');
|
976 |
95b003ff
|
Origo
|
my $created = $reguser->{'created'} || $current_time; # set created timestamp for new users
|
977 |
|
|
|
978 |
|
|
# Only allow admins to change user privileges and quotas
|
979 |
|
|
if ($isadmin || $user eq $engineuser) {
|
980 |
|
|
$uprivileges = $obj->{"privileges"} || $reguser->{'privileges'};
|
981 |
|
|
$uprivileges = '' if ($uprivileges eq '--');
|
982 |
|
|
$uprivileges = 'n' if (!$reguser->{'username'} && !$uprivileges); # Allow new users to use node storage unless explicitly disallowed
|
983 |
|
|
$uprivileges =~ tr/adnrpu//cd; # filter out non-valid privileges
|
984 |
|
|
$uprivileges =~ s/(.)(?=.*?\1)//g; # filter out duplicates using positive lookahead
|
985 |
|
|
$storagepools = ($obj->{"storagepools"} || $obj->{"storagepools"} eq '0')?$obj->{"storagepools"} : $reguser->{'storagepools'};
|
986 |
|
|
$memoryquota = (defined $obj->{"memoryquota"}) ? $obj->{"memoryquota"} : $reguser->{'memoryquota'};
|
987 |
|
|
$storagequota = (defined $obj->{"storagequota"}) ? $obj->{"storagequota"} : $reguser->{'storagequota'};
|
988 |
|
|
$nodestoragequota = (defined $obj->{"nodestoragequota"}) ? $obj->{"nodestoragequota"} : $reguser->{'nodestoragequota'};
|
989 |
|
|
$vcpuquota = (defined $obj->{"vcpuquota"}) ? $obj->{"vcpuquota"} : $reguser->{'vcpuquota'};
|
990 |
|
|
$externalipquota = (defined $obj->{"externalipquota"}) ? $obj->{"externalipquota"} : $reguser->{'externalipquota'};
|
991 |
|
|
$rxquota = (defined $obj->{"rxquota"}) ? $obj->{"rxquota"} : $reguser->{'rxquota'};
|
992 |
|
|
$txquota = (defined $obj->{"txquota"}) ? $obj->{"txquota"} : $reguser->{'txquota'};
|
993 |
|
|
$tasks = $obj->{"tasks"} || $reguser->{'tasks'};
|
994 |
|
|
$ubillto = $obj->{"billto"} || $reguser->{'billto'};
|
995 |
45cc3024
|
hq
|
$udnsdomains = $obj->{"dnsdomains"} || $udnsdomains; $udnsdomains = '' if ($udnsdomains eq '--');
|
996 |
|
|
$uappstoreurl = $obj->{"appstoreurl"} || $uappstoreurl;
|
997 |
95b003ff
|
Origo
|
$uaccounts = $obj->{"accounts"} || $reguser->{'accounts'};
|
998 |
|
|
$uaccountsprivileges = $obj->{"accountsprivileges"} || $reguser->{'accountsprivileges'};
|
999 |
a439a9c4
|
hq
|
my @ua = split(/, ?/, $uaccounts);
|
1000 |
|
|
my @up = split(/, ?/, $uaccountsprivileges);
|
1001 |
95b003ff
|
Origo
|
my @ua2 = ();
|
1002 |
|
|
my @up2 = ();
|
1003 |
|
|
my $i = 0;
|
1004 |
|
|
foreach my $u (@ua) {
|
1005 |
|
|
if ($register{$u} && ($u ne $username)) {
|
1006 |
|
|
push @ua2, $u;
|
1007 |
|
|
my $uprivs = $up[$i] || 'u';
|
1008 |
|
|
$uprivs =~ tr/adnrpu//cd; # filter out non-valid privileges
|
1009 |
|
|
$uprivs =~ s/(.)(?=.*?\1)//g; # filter out duplicates using positive lookahead
|
1010 |
|
|
push @up2, $uprivs;
|
1011 |
|
|
}
|
1012 |
|
|
$i++;
|
1013 |
|
|
}
|
1014 |
|
|
$uaccounts = join(", ", @ua2);
|
1015 |
|
|
$uaccountsprivileges = join(", ", @up2);
|
1016 |
|
|
}
|
1017 |
|
|
|
1018 |
|
|
# Sanity checks
|
1019 |
|
|
if (
|
1020 |
|
|
($fullname && length $fullname > 255)
|
1021 |
|
|
|| ($password && length $password > 255)
|
1022 |
|
|
) {
|
1023 |
|
|
$postreply .= "Status=ERROR Bad data: $username\n";
|
1024 |
|
|
return $postreply;
|
1025 |
|
|
}
|
1026 |
|
|
# Only allow new users to be created by admins, i.e. no auto-registration
|
1027 |
|
|
if ($reguser->{'username'} || $isadmin) {
|
1028 |
|
|
$register{$username} = {
|
1029 |
|
|
password => $password,
|
1030 |
|
|
fullname => $fullname,
|
1031 |
|
|
email => $email,
|
1032 |
|
|
opemail => $opemail,
|
1033 |
|
|
alertemail => $alertemail,
|
1034 |
|
|
phone => $phone,
|
1035 |
|
|
opphone => $opphone,
|
1036 |
|
|
opfullname => $opfullname,
|
1037 |
|
|
allowfrom => $allowfrom,
|
1038 |
54401133
|
hq
|
totpsecret => $totpsecret,
|
1039 |
95b003ff
|
Origo
|
privileges => $uprivileges,
|
1040 |
|
|
accounts => $uaccounts,
|
1041 |
|
|
accountsprivileges => $uaccountsprivileges,
|
1042 |
|
|
storagepools => $storagepools,
|
1043 |
|
|
memoryquota => $memoryquota+0,
|
1044 |
|
|
storagequota => $storagequota+0,
|
1045 |
|
|
nodestoragequota => $nodestoragequota+0,
|
1046 |
|
|
vcpuquota => $vcpuquota+0,
|
1047 |
|
|
externalipquota => $externalipquota+0,
|
1048 |
|
|
rxquota => $rxquota+0,
|
1049 |
|
|
txquota => $txquota+0,
|
1050 |
|
|
tasks => $tasks,
|
1051 |
|
|
allowinternalapi => $allowinternalapi || 1, # specify '--' to explicitly disallow
|
1052 |
|
|
billto => $ubillto,
|
1053 |
45cc3024
|
hq
|
dnsdomains => $udnsdomains,
|
1054 |
|
|
appstoreurl => $uappstoreurl,
|
1055 |
|
|
created => $created,
|
1056 |
95b003ff
|
Origo
|
modified => $current_time,
|
1057 |
|
|
action => ""
|
1058 |
|
|
};
|
1059 |
|
|
my %uref = %{$register{$username}};
|
1060 |
|
|
$uref{result} = "OK";
|
1061 |
|
|
$uref{password} = "";
|
1062 |
|
|
$uref{status} = ($uprivileges =~ /d/)?'disabled':'enabled';
|
1063 |
|
|
$postreply = JSON::to_json(\%uref, { pretty => 1 });
|
1064 |
|
|
# $postreply =~ s/""/"--"/g;
|
1065 |
|
|
$postreply =~ s/null/""/g;
|
1066 |
|
|
# $postreply =~ s/\x/ /g;
|
1067 |
|
|
}
|
1068 |
|
|
return $postreply;
|
1069 |
|
|
}
|
1070 |
|
|
|
1071 |
|
|
sub do_list {
|
1072 |
|
|
my ($uuid, $action, $obj) = @_;
|
1073 |
|
|
if ($help) {
|
1074 |
|
|
return <<END
|
1075 |
|
|
GET::
|
1076 |
|
|
List users registered on this engine.
|
1077 |
|
|
END
|
1078 |
|
|
}
|
1079 |
|
|
my $userfilter;
|
1080 |
|
|
my $usermatch;
|
1081 |
|
|
my $propmatch;
|
1082 |
|
|
if ($uripath =~ /users(\.cgi)?\/(\?|)(me|this)/) {
|
1083 |
|
|
$usermatch = $user;
|
1084 |
|
|
$propmatch = $4 if ($uripath =~ /users(\.cgi)?\/(\?|)(me|this)\/(.+)/);
|
1085 |
|
|
} elsif ($uripath =~ /users(\.cgi)?\/(\?|)(username)/) {
|
1086 |
|
|
$userfilter = $3 if ($uripath =~ /users(\.cgi)?\/\??username(:|=)(.+)/);
|
1087 |
|
|
$userfilter = $1 if ($userfilter =~ /(.*)\*/);
|
1088 |
|
|
} elsif ($uripath =~ /users(\.cgi)?\/(\S+)/) {
|
1089 |
|
|
$usermatch = $2;
|
1090 |
|
|
$propmatch = $4 if ($uripath =~ /users(\.cgi)?\/(\S+)\/(.+)/);
|
1091 |
|
|
}
|
1092 |
|
|
|
1093 |
|
|
my @regvalues = (sort {$a->{'id'} <=> $b->{'id'}} values %register); # Sort by id
|
1094 |
|
|
my @curregvalues;
|
1095 |
|
|
|
1096 |
|
|
foreach my $valref (@regvalues) {
|
1097 |
|
|
my $reguser = $valref->{'username'};
|
1098 |
|
|
if ($user eq $reguser || $isadmin) {
|
1099 |
|
|
next if ($reguser eq 'irigo' || $reguser eq 'guest');
|
1100 |
|
|
my %val = %{$valref}; # Deference and assign to new ass array, effectively cloning object
|
1101 |
54401133
|
hq
|
$val{'password'} = '';
|
1102 |
|
|
$val{'status'} = ($val{'privileges'} =~ /d/)?'disabled':'enabled';
|
1103 |
|
|
if ((!$userfilter && !$usermatch) || ($userfilter && $reguser =~ /$userfilter/) || $reguser eq $usermatch) {
|
1104 |
|
|
push @curregvalues,\%val;
|
1105 |
|
|
}
|
1106 |
95b003ff
|
Origo
|
}
|
1107 |
|
|
}
|
1108 |
|
|
if ($action eq 'tablelist') {
|
1109 |
|
|
my $t2 = Text::SimpleTable->new(14,32,24,10);
|
1110 |
|
|
|
1111 |
|
|
$t2->row('username', 'fullname', 'lastlogin', 'privileges');
|
1112 |
|
|
$t2->hr;
|
1113 |
|
|
my $pattern = $options{m};
|
1114 |
|
|
foreach $rowref (@curregvalues){
|
1115 |
|
|
if ($pattern) {
|
1116 |
|
|
my $rowtext = $rowref->{'username'} . " " . $rowref->{'fullname'} . " " . $rowref->{'lastlogin'}
|
1117 |
|
|
. " " . $rowref->{'privileges'};
|
1118 |
|
|
$rowtext .= " " . $rowref->{'mac'} if ($isadmin);
|
1119 |
|
|
next unless ($rowtext =~ /$pattern/i);
|
1120 |
|
|
}
|
1121 |
|
|
$t2->row($rowref->{'username'}, $rowref->{'fullname'}||'--', localtime($rowref->{'lastlogin'})||'--',
|
1122 |
|
|
$rowref->{'privileges'}||'--');
|
1123 |
|
|
}
|
1124 |
|
|
#$t2->row('common', '--', '--', '--');
|
1125 |
|
|
#$t2->row('all', '--', '--', '--') if (index($privileges,"a")!=-1);
|
1126 |
|
|
$postreply .= $t2->draw;
|
1127 |
|
|
} elsif ($console) {
|
1128 |
|
|
$postreply = Dumper(\@curregvalues);
|
1129 |
|
|
} else {
|
1130 |
|
|
my $json_text;
|
1131 |
|
|
if ($propmatch) {
|
1132 |
|
|
$json_text = JSON::to_json($curregvalues[0]->{$propmatch}, {allow_nonref=>1});
|
1133 |
|
|
} else {
|
1134 |
|
|
$json_text = JSON::to_json(\@curregvalues, {pretty=>1});
|
1135 |
|
|
}
|
1136 |
|
|
$json_text =~ s/"--"/""/g;
|
1137 |
|
|
$json_text =~ s/null/""/g;
|
1138 |
|
|
# $json_text =~ s/\x/ /g;
|
1139 |
|
|
$postreply = qq|{"identifier": "username", "label": "username", "items": | unless ($usermatch || $action ne 'listusers');
|
1140 |
|
|
$postreply .= $json_text;
|
1141 |
|
|
$postreply .= "}\n" unless ($usermatch || $action ne 'listusers');
|
1142 |
|
|
}
|
1143 |
|
|
return $postreply;
|
1144 |
|
|
}
|
1145 |
|
|
|
1146 |
|
|
sub do_uuidlookup {
|
1147 |
|
|
if ($help) {
|
1148 |
|
|
return <<END
|
1149 |
|
|
GET:uuid:
|
1150 |
|
|
Simple action for looking up a username (uuid) or part of a username and returning the complete username.
|
1151 |
|
|
END
|
1152 |
|
|
}
|
1153 |
|
|
my $u = $options{u};
|
1154 |
|
|
$u = $params{'uuid'} unless ($u || $u eq '0');
|
1155 |
|
|
if ($u || $u eq '0') {
|
1156 |
|
|
foreach my $uuid (keys %register) {
|
1157 |
|
|
if ($uuid =~ /^$u/) {
|
1158 |
|
|
return "$uuid\n" if ($uuid eq $user || index($privileges,"a")!=-1);
|
1159 |
|
|
}
|
1160 |
|
|
}
|
1161 |
|
|
}
|
1162 |
|
|
}
|
1163 |
|
|
|
1164 |
|
|
sub do_uuidshow {
|
1165 |
|
|
if ($help) {
|
1166 |
|
|
return <<END
|
1167 |
|
|
GET:uuid:
|
1168 |
|
|
Simple action for showing a single user. Pass username as uuid.
|
1169 |
|
|
END
|
1170 |
|
|
}
|
1171 |
|
|
my $u = $options{u};
|
1172 |
|
|
$u = $params{'uuid'} unless ($u || $u eq '0');
|
1173 |
|
|
if ($u eq $user || index($privileges,"a")!=-1) {
|
1174 |
|
|
foreach my $uuid (keys %register) {
|
1175 |
|
|
if ($uuid =~ /^$u/) {
|
1176 |
|
|
my %hash = %{$register{$uuid}};
|
1177 |
|
|
delete $hash{'action'};
|
1178 |
|
|
my $dump = to_json(\%hash, {pretty=>1});
|
1179 |
|
|
$dump =~ s/undef/"--"/g;
|
1180 |
|
|
return $dump;
|
1181 |
|
|
}
|
1182 |
|
|
}
|
1183 |
|
|
}
|
1184 |
|
|
}
|
1185 |
|
|
|
1186 |
|
|
sub Restoreengine {
|
1187 |
|
|
my ($uuid, $action, $obj) = @_;
|
1188 |
|
|
if ($help) {
|
1189 |
|
|
return <<END
|
1190 |
|
|
GET:restorefile:
|
1191 |
|
|
Restores this engine's configuration from "restorefile", which must be one of the paths listed in listenginebackups
|
1192 |
|
|
END
|
1193 |
|
|
}
|
1194 |
|
|
if (!$isadmin) {
|
1195 |
|
|
$postreply = "Status=ERROR You must be an administrator in order to restore this engine";
|
1196 |
|
|
} else {
|
1197 |
|
|
my $tktcfg = ConfigReader::Simple->new($Stabile::auth_tkt_conf, [qw(TKTAuthSecret)]);
|
1198 |
|
|
my $tktkey = $tktcfg->get('TKTAuthSecret') || '';
|
1199 |
|
|
my $enginetkthash = Digest::SHA::sha512_hex($tktkey);
|
1200 |
|
|
|
1201 |
|
|
my $restoredir = "/etc";
|
1202 |
|
|
my $dbname = "steamregister";
|
1203 |
|
|
my $restorefile = $obj->{'restorefile'};
|
1204 |
|
|
|
1205 |
|
|
if ($restorefile && !($restorefile =~ /\//)) {
|
1206 |
|
|
my $urifile = URI::Escape::uri_escape($restorefile);
|
1207 |
48fcda6b
|
Origo
|
my $uri = "https://www.stabile.io/irigo/engine.cgi";
|
1208 |
95b003ff
|
Origo
|
my $cmd = qq|/usr/bin/curl -f --cookie -O -L -F action=getbackup -F restorefile=$urifile -F engineid=$engineid -F enginetkthash=$enginetkthash "$uri" > "/tmp/$restorefile"|;
|
1209 |
|
|
my $res = `$cmd`;
|
1210 |
|
|
if (-s "/tmp/$restorefile") {
|
1211 |
|
|
$res .= `(mkdir $restoredir/stabile; cd $restoredir/stabile; /bin/tar -zxf "/tmp/$restorefile")`;
|
1212 |
|
|
$res .= `/usr/bin/mysql -e "create database $dbname;"`;
|
1213 |
|
|
$res .= `/usr/bin/mysql $dbname < $restoredir/stabile/steamregister.sql`;
|
1214 |
|
|
$res .= `cp -b $restoredir/stabile/hosts.allow /etc/hosts.allow`;
|
1215 |
|
|
$res .= `cp -b $restoredir/stabile/auth_tkt_cgi.conf /etc/apache2/conf.d/`;
|
1216 |
|
|
$res .= `cp -b $restoredir/stabile/*.crt /etc/apache2/ssl/`;
|
1217 |
|
|
$res .= `cp -b $restoredir/stabile/*.key /etc/apache2/ssl/`;
|
1218 |
|
|
$res .= `cp -b $restoredir/stabile/mon.cf /etc/mon/`;
|
1219 |
|
|
$res .= `service apache2 reload`;
|
1220 |
|
|
|
1221 |
|
|
# Restore default node configuration
|
1222 |
|
|
unless ( tie(%idreg,'Tie::DBI', Hash::Merge::merge({table=>'nodeidentities', key=>'identity'}, $Stabile::dbopts)) ) {return "Unable to access identity register"};
|
1223 |
|
|
my $defaultpath = $idreg{'default'}->{'path'} . "/casper/filesystem.dir/etc/stabile/nodeconfig.cfg";
|
1224 |
|
|
untie %idreg;
|
1225 |
|
|
$res .= `cp $restoredir/stabile/nodeconfig.cfg $defaultpath`;
|
1226 |
48fcda6b
|
Origo
|
$main::syslogit->($user, "info", "Engine configuration $restorefile restored from the registry");
|
1227 |
|
|
$postreply .= "Status=OK Engine configuration $restorefile restored from the registry - reloading UI\n";
|
1228 |
95b003ff
|
Origo
|
} else {
|
1229 |
|
|
$postreply .= "Status=ERROR Restore failed, $restorefile not found...\n";
|
1230 |
|
|
}
|
1231 |
|
|
} else {
|
1232 |
|
|
$postreply .= "Status=ERROR You must select a restore file\n";
|
1233 |
|
|
}
|
1234 |
|
|
}
|
1235 |
|
|
return $postreply;
|
1236 |
|
|
}
|
1237 |
|
|
|
1238 |
|
|
# Print list of available actions on objects
|
1239 |
|
|
sub do_plainhelp {
|
1240 |
|
|
my $res;
|
1241 |
|
|
$res .= header('text/plain') unless $console;
|
1242 |
|
|
$res .= <<END
|
1243 |
|
|
new [username="name", password="password"]
|
1244 |
|
|
* enable: Enables a disabled user
|
1245 |
|
|
* disable: Disables a user, disallowing login
|
1246 |
|
|
* remove: Deletes a user, leaving servers, images, networks etc. untouched
|
1247 |
|
|
* deleteentirely: Deletes a user and all the user's servers, images, networks etc. Warning: This destroys data
|
1248 |
|
|
|
1249 |
|
|
END
|
1250 |
|
|
;
|
1251 |
|
|
}
|
1252 |
|
|
|
1253 |
8d7785ff
|
Origo
|
sub do_cleanbillingdata {
|
1254 |
|
|
my ($uuid, $action, $obj) = @_;
|
1255 |
|
|
if ($help) {
|
1256 |
|
|
return <<END
|
1257 |
|
|
GET:year,dryrun,cleanup:
|
1258 |
|
|
Deletes billing from [year]. Default is current year-2. Set dryrun to do a test run. Set cleanup to remove invalid entries.
|
1259 |
|
|
END
|
1260 |
|
|
}
|
1261 |
|
|
return "Status=Error Not allowed\n" unless ($isadmin);
|
1262 |
|
|
|
1263 |
|
|
my $y = $params{'year'} || ($year-2);
|
1264 |
|
|
my $dryrun = $params{'dryrun'};
|
1265 |
|
|
my $cleanup = $params{'cleanup'};
|
1266 |
|
|
my $pattern = qq|like '%-$y-__'|;
|
1267 |
|
|
if ($cleanup) {
|
1268 |
|
|
$pattern = qq|not like '%-____-__'|;
|
1269 |
|
|
$y = '';
|
1270 |
|
|
}
|
1271 |
|
|
|
1272 |
|
|
unless ( tie(%bnetworksreg,'Tie::DBI', Hash::Merge::merge({table=>'billing_networks', key=>'useridtime'}, $Stabile::dbopts)) ) {return "Status=Error Unable to access billing register"};
|
1273 |
|
|
my @bkeys = (tied %bnetworksreg)->select_where("useridtime $pattern");
|
1274 |
|
|
$postreply .= "Status=OK -- this is only a test run ---\n" if ($dryrun);
|
1275 |
|
|
$postreply .= "Status=OK Cleaning " . scalar @bkeys . " $y network rows\n";
|
1276 |
|
|
foreach my $bkey (@bkeys) {
|
1277 |
|
|
$postreply .= "Status=OK removing $bnetworksreg{$bkey}->{useridtime}\n";
|
1278 |
|
|
delete($bnetworksreg{$bkey}) unless ($dryrun);
|
1279 |
|
|
}
|
1280 |
|
|
untie(%bnetworksreg);
|
1281 |
|
|
|
1282 |
|
|
unless ( tie(%bimagesreg,'Tie::DBI', Hash::Merge::merge({table=>'billing_images', key=>'userstoragepooltime'}, $Stabile::dbopts)) ) {return "Status=Error Unable to access billing register"};
|
1283 |
|
|
my @bkeys = (tied %bimagesreg)->select_where("userstoragepooltime $pattern");
|
1284 |
|
|
$postreply .= "Status=OK Cleaning " . scalar @bkeys . " $y image rows\n";
|
1285 |
|
|
foreach my $bkey (@bkeys) {
|
1286 |
|
|
$postreply .= "Status=OK removing $bimagesreg{$bkey}->{userstoragepooltime}\n";
|
1287 |
|
|
delete($bimagesreg{$bkey}) unless ($dryrun);
|
1288 |
|
|
}
|
1289 |
|
|
untie(%bimagesreg);
|
1290 |
|
|
|
1291 |
|
|
unless ( tie(%bserversreg,'Tie::DBI', Hash::Merge::merge({table=>'billing_domains', key=>'usernodetime'}, $Stabile::dbopts)) ) {return "Status=Error Unable to access billing register"};
|
1292 |
|
|
my @bkeys = (tied %bserversreg)->select_where("usernodetime $pattern");
|
1293 |
|
|
$postreply .= "Status=OK Cleaning " . scalar @bkeys . " $y server rows\n";
|
1294 |
|
|
foreach my $bkey (@bkeys) {
|
1295 |
|
|
$postreply .= "Status=OK removing $bserversreg{$bkey}->{usernodetime}\n";
|
1296 |
|
|
delete($bserversreg{$bkey}) unless ($dryrun);
|
1297 |
|
|
}
|
1298 |
|
|
untie(%bserversreg);
|
1299 |
|
|
|
1300 |
|
|
return $postreply;
|
1301 |
|
|
|
1302 |
|
|
}
|
1303 |
|
|
|
1304 |
95b003ff
|
Origo
|
sub collectBillingData {
|
1305 |
|
|
my ( $curuuid, $buser, $bmonth, $byear, $showcost ) = @_;
|
1306 |
|
|
|
1307 |
8d7785ff
|
Origo
|
my $vcpu=0;
|
1308 |
95b003ff
|
Origo
|
my $rx = 0;
|
1309 |
|
|
my $tx = 0;
|
1310 |
|
|
my $vcpuavg = 0;
|
1311 |
8d7785ff
|
Origo
|
my $memory = 0;
|
1312 |
95b003ff
|
Origo
|
my $memoryavg = 0;
|
1313 |
8d7785ff
|
Origo
|
my $backupsize = 0;
|
1314 |
95b003ff
|
Origo
|
my $backupsizeavg = 0;
|
1315 |
8d7785ff
|
Origo
|
my $nodevirtualsize = 0;
|
1316 |
95b003ff
|
Origo
|
my $nodevirtualsizeavg = 0;
|
1317 |
8d7785ff
|
Origo
|
my $virtualsize = 0;
|
1318 |
95b003ff
|
Origo
|
my $virtualsizeavg = 0;
|
1319 |
8d7785ff
|
Origo
|
my $externalip = 0;
|
1320 |
95b003ff
|
Origo
|
my $externalipavg = 0;
|
1321 |
|
|
|
1322 |
|
|
my $prevmonth = $bmonth-1;
|
1323 |
|
|
my $prevyear = $byear;
|
1324 |
|
|
if ($prevmonth == 0) {$prevmonth=12; $prevyear--;};
|
1325 |
|
|
$prevmonth = substr("0" . $prevmonth, -2);
|
1326 |
|
|
my $prev_rx = 0;
|
1327 |
|
|
my $prev_tx = 0;
|
1328 |
|
|
# List pricing for a single system/server
|
1329 |
|
|
if ($curuuid) {
|
1330 |
|
|
unless ( tie(%domreg,'Tie::DBI', Hash::Merge::merge({table=>'domains'}, $Stabile::dbopts)) ) {return "Unable to access domains register"};
|
1331 |
|
|
unless ( tie(%imagereg,'Tie::DBI', Hash::Merge::merge({table=>'images',key=>'path'}, $Stabile::dbopts)) ) {return "Unable to access images register"};
|
1332 |
|
|
unless ( tie(%networkreg,'Tie::DBI', Hash::Merge::merge({table=>'networks'}, $Stabile::dbopts)) ) {return "Unable to access networks register"};
|
1333 |
|
|
|
1334 |
|
|
my @domains;
|
1335 |
|
|
my $isserver = 1 if ($domreg{$curuuid});
|
1336 |
|
|
if ($isserver) {
|
1337 |
|
|
@domains = $domreg{$curuuid};
|
1338 |
|
|
} else {
|
1339 |
|
|
@domains = values %domreg;
|
1340 |
|
|
}
|
1341 |
|
|
foreach my $valref (@domains) {
|
1342 |
|
|
if ($valref->{'system'} eq $curuuid || $isserver) {
|
1343 |
|
|
$memory += $valref->{'memory'};
|
1344 |
|
|
$vcpu += $valref->{'vcpu'};
|
1345 |
|
|
my $image = $valref->{'image'};
|
1346 |
|
|
my $storagepool;
|
1347 |
|
|
if ($imagereg{$image}) {
|
1348 |
|
|
$storagepool = $imagereg{$image}->{'storagepool'};
|
1349 |
|
|
if ($storagepool == -1) {
|
1350 |
|
|
$nodevirtualsize += $imagereg{$image}->{'virtualsize'};
|
1351 |
|
|
} else {
|
1352 |
|
|
$virtualsize += $imagereg{$image}->{'virtualsize'};
|
1353 |
|
|
}
|
1354 |
|
|
$backupsize += $imagereg{$image}->{'backupsize'};
|
1355 |
|
|
}
|
1356 |
|
|
$image = $valref->{'image2'};
|
1357 |
|
|
if ($imagereg{$image}) {
|
1358 |
|
|
$storagepool = $imagereg{$image}->{'storagepool'};
|
1359 |
|
|
if ($storagepool == -1) {
|
1360 |
|
|
$nodevirtualsize += $imagereg{$image}->{'virtualsize'};
|
1361 |
|
|
} else {
|
1362 |
|
|
$virtualsize += $imagereg{$image}->{'virtualsize'};
|
1363 |
|
|
}
|
1364 |
|
|
$backupsize += $imagereg{$image}->{'backupsize'};
|
1365 |
|
|
}
|
1366 |
|
|
my $networkuuid = $valref->{'networkuuid1'};
|
1367 |
|
|
my $networktype = $networkreg{$networkuuid}->{'type'};
|
1368 |
|
|
$externalip++ if ($networktype eq 'externalip'|| $networktype eq 'ipmapping');
|
1369 |
|
|
$networkuuid = $valref->{'networkuuid2'};
|
1370 |
|
|
if ($networkreg{$networkuuid}) {
|
1371 |
|
|
$networktype = $networkreg{$networkuuid}->{'type'};
|
1372 |
2a63870a
|
Christian Orellana
|
$externalip++ if ($networktype eq 'externalip'|| $networktype eq 'ipmapping');
|
1373 |
95b003ff
|
Origo
|
}
|
1374 |
|
|
}
|
1375 |
|
|
}
|
1376 |
|
|
untie %domreg;
|
1377 |
|
|
untie %imagereg;
|
1378 |
|
|
untie %networkreg;
|
1379 |
|
|
|
1380 |
|
|
# List pricing for all servers
|
1381 |
|
|
} else {
|
1382 |
d24d9a01
|
hq
|
# Network billing
|
1383 |
95b003ff
|
Origo
|
unless ( tie(%bnetworksreg,'Tie::DBI', Hash::Merge::merge({table=>'billing_networks', key=>'useridtime'}, $Stabile::dbopts)) ) {return "Unable to access billing register"};
|
1384 |
|
|
unless ( tie(%networkreg,'Tie::DBI', Hash::Merge::merge({table=>'networks'}, $Stabile::dbopts)) ) {return "Unable to access networks register"};
|
1385 |
|
|
|
1386 |
d24d9a01
|
hq
|
# Build list of the user's network id's
|
1387 |
95b003ff
|
Origo
|
my %usernetworks;
|
1388 |
8d7785ff
|
Origo
|
my @nkeys = (tied %networkreg)->select_where("user = '$buser'");
|
1389 |
95b003ff
|
Origo
|
foreach $network (@nkeys) {
|
1390 |
|
|
my $id = $networkreg{$network}->{'id'};
|
1391 |
|
|
$usernetworks{$id} = $id unless ($usernetworks{$id} || $id==0 || $id==1);
|
1392 |
|
|
}
|
1393 |
|
|
untie %networkreg;
|
1394 |
|
|
|
1395 |
|
|
foreach $id (keys %usernetworks) {
|
1396 |
|
|
my $networkobj = $bnetworksreg{"$buser-$id-$byear-$bmonth"};
|
1397 |
|
|
my $prevnetworkobj = $bnetworksreg{"$buser-$id-$prevyear-$prevmonth"};
|
1398 |
|
|
$externalip += $networkobj->{'externalip'};
|
1399 |
|
|
$externalipavg += $networkobj->{'externalipavg'};
|
1400 |
|
|
$rx += $networkobj->{'rx'};
|
1401 |
|
|
$tx += $networkobj->{'tx'};
|
1402 |
|
|
$prev_rx += $prevnetworkobj->{'rx'};
|
1403 |
|
|
$prev_tx += $prevnetworkobj->{'tx'};
|
1404 |
|
|
}
|
1405 |
|
|
untie %bnetworksreg;
|
1406 |
|
|
|
1407 |
|
|
# Image billing
|
1408 |
|
|
|
1409 |
|
|
unless ( tie(%bimagesreg,'Tie::DBI', Hash::Merge::merge({table=>'billing_images', key=>'userstoragepooltime'}, $Stabile::dbopts)) ) {return "Unable to access billing register"};
|
1410 |
|
|
|
1411 |
|
|
# Build list of the users storage pools
|
1412 |
|
|
my $storagepools = $Stabile::config->get('STORAGE_POOLS_DEFAULTS') || "0";
|
1413 |
|
|
my $upools = $register{$buser}->{'storagepools'}; # Prioritized list of users storage pools as numbers, e.g. "0,2,1"
|
1414 |
8d7785ff
|
Origo
|
$storagepools = $upools if ($upools && $upools ne '--');
|
1415 |
95b003ff
|
Origo
|
my @spl = split(/,\s*/, $storagepools);
|
1416 |
|
|
my $bimageobj = $bimagesreg{"$buser--1-$byear-$bmonth"};
|
1417 |
|
|
$backupsize = $bimageobj->{'backupsize'}+0;
|
1418 |
|
|
$nodevirtualsize = $bimageobj->{'virtualsize'}+0;
|
1419 |
|
|
$backupsizeavg = $bimageobj->{'backupsizeavg'}+0;
|
1420 |
|
|
$nodevirtualsizeavg = $bimageobj->{'virtualsizeavg'}+0;
|
1421 |
|
|
foreach $pool (@spl) {
|
1422 |
|
|
$bimageobj = $bimagesreg{"$buser-$pool-$byear-$bmonth"};
|
1423 |
|
|
$virtualsize += $bimageobj->{'virtualsize'};
|
1424 |
|
|
$backupsize += $bimageobj->{'backupsize'};
|
1425 |
|
|
$virtualsizeavg += $bimageobj->{'virtualsizeavg'};
|
1426 |
|
|
$backupsizeavg += $bimageobj->{'backupsizeavg'};
|
1427 |
|
|
}
|
1428 |
|
|
untie %bimagesreg;
|
1429 |
|
|
|
1430 |
|
|
# Server billing
|
1431 |
|
|
|
1432 |
|
|
unless ( tie(%bserversreg,'Tie::DBI', Hash::Merge::merge({table=>'billing_domains', key=>'usernodetime'}, $Stabile::dbopts)) ) {return "Unable to access billing register"};
|
1433 |
|
|
unless ( tie(%nodereg,'Tie::DBI', Hash::Merge::merge({table=>'nodes', key=>'mac'}, $Stabile::dbopts)) ) {return "Unable to access billing register"};
|
1434 |
|
|
|
1435 |
c899e439
|
Origo
|
my @usernodes = keys %nodereg;
|
1436 |
95b003ff
|
Origo
|
untie %nodereg;
|
1437 |
|
|
|
1438 |
|
|
my @nodebills;
|
1439 |
c899e439
|
Origo
|
foreach $mac (@usernodes) {
|
1440 |
95b003ff
|
Origo
|
my $bserverobj = $bserversreg{"$buser-$mac-$byear-$bmonth"};
|
1441 |
|
|
$vcpu += $bserverobj->{'vcpu'};
|
1442 |
|
|
$memory += $bserverobj->{'memory'};
|
1443 |
|
|
$vcpuavg += $bserverobj->{'vcpuavg'};
|
1444 |
|
|
$memoryavg += $bserverobj->{'memoryavg'};
|
1445 |
|
|
}
|
1446 |
|
|
untie %bserversreg;
|
1447 |
|
|
}
|
1448 |
|
|
|
1449 |
|
|
my $uservcpuprice = 0+ $register{$user}->{'vcpuprice'};
|
1450 |
|
|
my $usermemoryprice = 0+ $register{$user}->{'memoryprice'};
|
1451 |
|
|
my $userstorageprice = 0+ $register{$user}->{'storageprice'};
|
1452 |
|
|
my $usernodestorageprice = 0+ $register{$user}->{'nodestorageprice'};
|
1453 |
|
|
my $userexternalipprice = 0+ $register{$user}->{'externalipprice'};
|
1454 |
|
|
|
1455 |
|
|
$vcpuprice = $uservcpuprice || $Stabile::config->get('VCPU_PRICE') + 0;
|
1456 |
|
|
$memoryprice = $usermemoryprice || $Stabile::config->get('MEMORY_PRICE') + 0;
|
1457 |
|
|
$storageprice = $userstorageprice || $Stabile::config->get('STORAGE_PRICE') + 0;
|
1458 |
|
|
$nodestorageprice = $usernodestorageprice || $Stabile::config->get('NODESTORAGE_PRICE') + 0;
|
1459 |
|
|
$externalipprice = $userexternalipprice || $Stabile::config->get('EXTERNALIP_PRICE') + 0;
|
1460 |
|
|
|
1461 |
|
|
my $memorygb = int(0.5 + 100*$memory/1024)/100;
|
1462 |
|
|
my $virtualsizegb = int(0.5 + 100*$virtualsize/1024/1024/1024)/100;
|
1463 |
|
|
my $nodevirtualsizegb = int(0.5 + 100*$nodevirtualsize/1024/1024/1024)/100;
|
1464 |
|
|
my $backupsizegb = int(0.5 + 100*$backupsize/1024/1024/1024)/100;
|
1465 |
|
|
|
1466 |
|
|
my $totalprice = int(0.5 + 100*($vcpu*$vcpuprice + $memorygb*$memoryprice + $virtualsizegb*$storageprice
|
1467 |
|
|
+ $nodevirtualsizegb*$nodestorageprice + $backupsizegb*$storageprice + $externalip*$externalipprice)) /100;
|
1468 |
|
|
|
1469 |
|
|
my $memoryavggb = int(0.5 + 100*$memoryavg/1024)/100;
|
1470 |
|
|
my $virtualsizeavggb = int(0.5 + 100*$virtualsizeavg/1024/1024/1024)/100;
|
1471 |
|
|
my $nodevirtualsizeavggb = int(0.5 + 100*$nodevirtualsizeavg/1024/1024/1024)/100;
|
1472 |
|
|
my $backupsizeavggb = int(0.5 + 100*$backupsizeavg/1024/1024/1024)/100;
|
1473 |
|
|
|
1474 |
|
|
my $monfac = 1;
|
1475 |
|
|
if ($bmonth == $month) {
|
1476 |
|
|
# Find 00:00 of first day of month - http://www.perlmonks.org/?node_id=97120
|
1477 |
|
|
my $fstamp = POSIX::mktime(0,0,0,1,$mon,$year-1900,0,0,-1);
|
1478 |
|
|
my $lstamp = POSIX::mktime(0,0,0,1,$mon+1,$year-1900,0,0,-1);
|
1479 |
|
|
$monfac = ($current_time-$fstamp)/($lstamp-$fstamp);
|
1480 |
|
|
}
|
1481 |
|
|
|
1482 |
|
|
my $totalpriceavg = int(0.5 + 100*$monfac * ($vcpuavg*$vcpuprice + $memoryavggb*$memoryprice + $virtualsizeavggb*$storageprice
|
1483 |
|
|
+ $nodevirtualsizeavggb*$nodestorageprice + $backupsizeavggb*$storageprice + $externalipavg*$externalipprice)) /100;
|
1484 |
|
|
|
1485 |
|
|
$prev_rx = 0 if ($prev_rx>$rx); # Something is fishy
|
1486 |
|
|
$prev_tx = 0 if ($prev_tx>$tx);
|
1487 |
|
|
my $rxgb = int(0.5 + 100*($rx-$prev_rx)/1024**3)/100;
|
1488 |
|
|
my $txgb = int(0.5 + 100*($tx-$prev_tx)/1024**3)/100;
|
1489 |
|
|
|
1490 |
|
|
my %stats;
|
1491 |
|
|
$stats{'virtualsize'} = $virtualsizegb;
|
1492 |
|
|
$stats{'backupsize'} = $backupsizegb;
|
1493 |
|
|
$stats{'externalip'} = $externalip;
|
1494 |
|
|
$stats{'memory'} = $memorygb;
|
1495 |
|
|
$stats{'month'} = $bmonth;
|
1496 |
|
|
$stats{'nodevirtualsize'} = $nodevirtualsizegb;
|
1497 |
|
|
$stats{'rx'} = $rxgb;
|
1498 |
|
|
$stats{'tx'} = $txgb;
|
1499 |
|
|
$stats{'username'} = $buser;
|
1500 |
|
|
$stats{'vcpu'} = $vcpu;
|
1501 |
|
|
$stats{'year'} = $byear;
|
1502 |
|
|
$stats{'totalcost'} = "$cur $totalprice" if ($showcost);
|
1503 |
|
|
$stats{'curtotal'} = $totalprice if ($showcost);
|
1504 |
|
|
|
1505 |
|
|
if (!$curuuid) {
|
1506 |
|
|
$stats{'virtualsizeavg'} = $virtualsizeavggb;
|
1507 |
|
|
$stats{'backupsizeavg'} = $backupsizeavggb;
|
1508 |
|
|
$stats{'memoryavg'} = $memoryavggb;
|
1509 |
|
|
$stats{'nodevirtualsizeavg'} = $nodevirtualsizeavggb;
|
1510 |
|
|
$stats{'vcpuavg'} = int(0.5 + 100*$vcpuavg)/100;
|
1511 |
|
|
$stats{'externalipavg'} = int(0.5 + 100*$externalipavg)/100;
|
1512 |
|
|
$stats{'totalcostavg'} = "$cur $totalpriceavg" if ($showcost);
|
1513 |
|
|
}
|
1514 |
|
|
return %stats;
|
1515 |
|
|
}
|
1516 |
|
|
|
1517 |
|
|
sub do_resetpassword {
|
1518 |
|
|
my ($uuid, $action, $obj) = @_;
|
1519 |
|
|
if ($help) {
|
1520 |
|
|
return <<END
|
1521 |
|
|
GET:username:
|
1522 |
|
|
Sends an email to a user with a link to reset his password. The user must have a valid email address.
|
1523 |
|
|
END
|
1524 |
|
|
}
|
1525 |
|
|
my $username = $obj->{'username'} || $user;
|
1526 |
|
|
if ($register{$username} && ($username eq $user || $isadmin)) {
|
1527 |
|
|
my $mailaddrs = $register{$username}->{'email'};
|
1528 |
|
|
$mailaddrs = $username if (!$mailaddrs && $username =~ /\@/);
|
1529 |
|
|
if ($mailaddrs) {
|
1530 |
|
|
require (dirname(__FILE__)) . "/../auth/Apache/AuthTkt.pm";
|
1531 |
|
|
my $tktname = 'auth_' . substr($engineid, 0, 8);
|
1532 |
|
|
my $at = Apache::AuthTkt->new(conf => $ENV{MOD_AUTH_TKT_CONF});
|
1533 |
|
|
my $tkt = $at->ticket(uid => $username, digest_type => 'SHA512', tokens => '', debug => 0);
|
1534 |
|
|
# my $valid = $at->valid_ticket($tkt);
|
1535 |
|
|
|
1536 |
|
|
my $mailhtml = <<END;
|
1537 |
|
|
<!DOCTYPE html
|
1538 |
|
|
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
1539 |
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
1540 |
|
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
|
1541 |
|
|
<head>
|
1542 |
|
|
<title>Password reset</title>
|
1543 |
|
|
<meta http-equiv="Pragma" content="no-cache" />
|
1544 |
|
|
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" />
|
1545 |
|
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
1546 |
|
|
</head>
|
1547 |
|
|
<body class="tundra">
|
1548 |
|
|
<div>
|
1549 |
|
|
<div class="well" style="margin:20px;">
|
1550 |
|
|
<h3 style="color: #e74c3c!important; margin-bottom:30px;">You requested a password reset at $enginename</h3>
|
1551 |
|
|
To log in and set a new password, please click <a href="$baseurl/auth/autologin?$tktname=$tkt\&back=#chpwd">here</a>.<br>
|
1552 |
|
|
<div>Thanks,<br>your friendly infrastructure services</div>
|
1553 |
|
|
</div>
|
1554 |
|
|
</div>
|
1555 |
|
|
</div>
|
1556 |
|
|
</body>
|
1557 |
|
|
</html>
|
1558 |
|
|
END
|
1559 |
|
|
;
|
1560 |
|
|
my $msg = MIME::Lite->new(
|
1561 |
|
|
From => "$enginename",
|
1562 |
|
|
To => $mailaddrs,
|
1563 |
|
|
Type => 'multipart/alternative',
|
1564 |
|
|
Subject => "Password reset on $enginename",
|
1565 |
|
|
);
|
1566 |
|
|
# my $att_text = MIME::Lite->new(
|
1567 |
|
|
# Type => 'text',
|
1568 |
|
|
# Data => $mailtext,
|
1569 |
|
|
# Encoding => 'quoted-printable',
|
1570 |
|
|
# );
|
1571 |
|
|
# $att_text->attr('content-type' => 'text/plain; charset=UTF-8');
|
1572 |
|
|
# $msg->attach($att_text);
|
1573 |
|
|
my $att_html = MIME::Lite->new(
|
1574 |
|
|
Type => 'text',
|
1575 |
|
|
Data => $mailhtml,
|
1576 |
|
|
Encoding => 'quoted-printable',
|
1577 |
|
|
);
|
1578 |
|
|
$att_html->attr('content-type' => 'text/html; charset=UTF-8');
|
1579 |
|
|
$msg->attach($att_html);
|
1580 |
|
|
my $res = $msg->send;
|
1581 |
|
|
$postreply = "Status=OK Password reset email sent to $mailaddrs\n";
|
1582 |
|
|
} else {
|
1583 |
|
|
$postreply = "Status=Error user does not have a registered email address\n";
|
1584 |
|
|
}
|
1585 |
|
|
} else {
|
1586 |
|
|
$postreply = "Status=Error invalid data submitted\n";
|
1587 |
|
|
}
|
1588 |
|
|
return $postreply;
|
1589 |
|
|
}
|
1590 |
|
|
|
1591 |
|
|
sub do_changepassword {
|
1592 |
|
|
my ($uuid, $action, $obj) = @_;
|
1593 |
|
|
if ($help) {
|
1594 |
|
|
return <<END
|
1595 |
|
|
GET:username,password:
|
1596 |
|
|
Changes the password for a user.
|
1597 |
|
|
END
|
1598 |
|
|
}
|
1599 |
|
|
my $username = $obj->{'username'} || $user;
|
1600 |
|
|
my $password = $obj->{'password'};
|
1601 |
|
|
if ($password && $register{$username} && ($username eq $user || $isadmin)) {
|
1602 |
|
|
$MAXLEN = 20;
|
1603 |
|
|
var $msg = IsBadPassword($password);
|
1604 |
|
|
if ($msg) {
|
1605 |
|
|
$postreply = "Status=Error $msg - please choose a stronger password\n";
|
1606 |
|
|
} else {
|
1607 |
|
|
$password = Digest::SHA::sha512_base64($password);
|
1608 |
|
|
$register{$username}->{'password'} = $password;
|
1609 |
|
|
$postreply = "Status=OK Password changed for $username\n";
|
1610 |
|
|
}
|
1611 |
|
|
} else {
|
1612 |
|
|
$postreply = "Status=Error invalid data submitted\n";
|
1613 |
|
|
}
|
1614 |
|
|
return $postreply;
|
1615 |
|
|
}
|
1616 |
|
|
|
1617 |
|
|
sub do_remove {
|
1618 |
|
|
my ($uuid, $action, $obj) = @_;
|
1619 |
|
|
if ($help) {
|
1620 |
|
|
return <<END
|
1621 |
|
|
GET:username:
|
1622 |
|
|
Removes a user.
|
1623 |
|
|
END
|
1624 |
|
|
}
|
1625 |
|
|
my $username = $obj->{'username'};
|
1626 |
|
|
$postreply = remove($username);
|
1627 |
|
|
return $postreply;
|
1628 |
|
|
}
|
1629 |
|
|
|
1630 |
|
|
sub remove {
|
1631 |
|
|
my $username = shift;
|
1632 |
|
|
if (!$isadmin && ($user ne $engineuser)) {
|
1633 |
|
|
$postreply .= "Status=ERROR You are not allowed to remove user $username\n";
|
1634 |
|
|
} elsif ($register{$username}) {
|
1635 |
|
|
delete $register{$username};
|
1636 |
|
|
tied(%register)->commit;
|
1637 |
|
|
`/bin/rm /tmp/$username~*.tasks`;
|
1638 |
|
|
unlink "../cgi/ui_update/$username~ui_update.cgi" if (-e "../cgi/ui_update/$username~ui_update.cgi");
|
1639 |
|
|
$main::syslogit->($user, "info", "Deleted user $username from db");
|
1640 |
|
|
if ($console) {
|
1641 |
|
|
$postreply .= "Status=OK Deleted user $username\n";
|
1642 |
|
|
} else {
|
1643 |
|
|
# $main::updateUI->({ tab => 'users', type=>'update', user=>$user});
|
1644 |
|
|
return "{}";
|
1645 |
|
|
}
|
1646 |
|
|
return $postreply;
|
1647 |
|
|
} else {
|
1648 |
|
|
$postreply .= "Status=ERROR No such user: $username\n";
|
1649 |
|
|
}
|
1650 |
|
|
}
|
1651 |
|
|
|
1652 |
48fcda6b
|
Origo
|
# Update engine users with users received from the registry
|
1653 |
95b003ff
|
Origo
|
sub updateEngineUsers {
|
1654 |
|
|
my ($json_text) = @_;
|
1655 |
|
|
return unless ($isadmin || ($user eq $engineuser));
|
1656 |
|
|
my $res;
|
1657 |
|
|
my $json = JSON->new;
|
1658 |
|
|
$json->utf8([1]);
|
1659 |
|
|
my $json_obj = $json->decode($json_text);
|
1660 |
|
|
my @ulist = @$json_obj;
|
1661 |
|
|
my @efields = qw(password
|
1662 |
|
|
address city company country email fullname phone
|
1663 |
eb31fb38
|
hq
|
state zip alertemail opemail opfullname opphone billto
|
1664 |
95b003ff
|
Origo
|
memoryquota storagequota vcpuquota externalipquota rxquota txquota nodestoragequota
|
1665 |
54401133
|
hq
|
accounts accountsprivileges privileges modified dnsdomains appstoreurl totpsecret
|
1666 |
95b003ff
|
Origo
|
);
|
1667 |
48fcda6b
|
Origo
|
my $ures;
|
1668 |
|
|
my $ucount = 0;
|
1669 |
95b003ff
|
Origo
|
foreach my $u (@ulist) {
|
1670 |
|
|
my $username = $u->{'username'};
|
1671 |
|
|
if (!$register{$username} && $u->{'password'}) {
|
1672 |
|
|
$register{$username} = {
|
1673 |
|
|
username => $username,
|
1674 |
d24d9a01
|
hq
|
password => $u->{'password'},
|
1675 |
|
|
allowinternalapi => 1
|
1676 |
95b003ff
|
Origo
|
};
|
1677 |
48fcda6b
|
Origo
|
$ures .= " *";
|
1678 |
95b003ff
|
Origo
|
}
|
1679 |
|
|
next unless ($register{$username});
|
1680 |
|
|
next if ($register{$username}->{'modified'} && $register{$username}->{'modified'} > $u->{'modified'});
|
1681 |
|
|
foreach my $efield (@efields) {
|
1682 |
|
|
if ($efield eq 'privileges') {
|
1683 |
|
|
$u->{$efield} =~ tr/adnrpu//cd; # filter out non-valid privileges
|
1684 |
|
|
}
|
1685 |
|
|
if (defined $u->{$efield}) {
|
1686 |
|
|
$u->{$efield} += 0 if ($efield =~ /(quota|price)$/);
|
1687 |
|
|
$register{$username}->{$efield} = $u->{$efield};
|
1688 |
|
|
}
|
1689 |
|
|
delete $u->{$efield} if (defined $u->{$efield} && $u->{$efield} eq '' && $efield ne 'password')
|
1690 |
|
|
}
|
1691 |
48fcda6b
|
Origo
|
$ures .= "$username ($u->{'fullname'}), ";
|
1692 |
|
|
$ucount++;
|
1693 |
95b003ff
|
Origo
|
my $uid = `id -u irigo-$username`; chomp $uid;
|
1694 |
|
|
if (!$uid) { # Check user has system account for disk quotas
|
1695 |
|
|
$main::syslogit->($user, "info", "Adding system user $username");
|
1696 |
|
|
`/usr/sbin/useradd -m "irigo-$username"`;
|
1697 |
104449f5
|
Origo
|
`echo "[User]\nSystemAccount=true" > /var/lib/AccountsService/users/irigo-$username`; # Don't show in login screen
|
1698 |
95b003ff
|
Origo
|
}
|
1699 |
|
|
|
1700 |
|
|
}
|
1701 |
48fcda6b
|
Origo
|
$ures = substr($res, 0, -2) . "\n";
|
1702 |
705b5366
|
hq
|
$res .= "Status=OK Received $ucount updates on " .(scalar(@ulist)). " registry users\n";
|
1703 |
95b003ff
|
Origo
|
return $res;
|
1704 |
|
|
}
|
1705 |
|
|
|
1706 |
|
|
sub sendEngineUser {
|
1707 |
|
|
my ($username) = @_;
|
1708 |
|
|
if ($enginelinked) {
|
1709 |
48fcda6b
|
Origo
|
# Send engine user to the registry
|
1710 |
95b003ff
|
Origo
|
require LWP::Simple;
|
1711 |
|
|
my $browser = LWP::UserAgent->new;
|
1712 |
|
|
$browser->agent('stabile/1.0b');
|
1713 |
|
|
$browser->protocols_allowed( [ 'http','https'] );
|
1714 |
|
|
|
1715 |
|
|
my $tktcfg = ConfigReader::Simple->new($Stabile::auth_tkt_conf, [qw(TKTAuthSecret)]);
|
1716 |
|
|
my $tktkey = $tktcfg->get('TKTAuthSecret') || '';
|
1717 |
|
|
my $tkthash = Digest::SHA::sha512_hex($tktkey);
|
1718 |
|
|
my $json = '[' . JSON::to_json(\%{$register{$username}}) . ']';
|
1719 |
|
|
$json =~ s/null/""/g;
|
1720 |
|
|
# $json = uri_escape_utf8($json);
|
1721 |
|
|
$json = URI::Escape::uri_escape($json);
|
1722 |
48fcda6b
|
Origo
|
my $posturl = "https://www.stabile.io/irigo/engine.cgi?action=update";
|
1723 |
95b003ff
|
Origo
|
my $postreq = ();
|
1724 |
|
|
$postreq->{'POSTDATA'} = $json;
|
1725 |
|
|
$postreq->{'engineid'} = $engineid;
|
1726 |
|
|
$postreq->{'enginetkthash'} = $tkthash;
|
1727 |
|
|
|
1728 |
|
|
# my $req = HTTP::Request->new(POST => $posturl);
|
1729 |
|
|
# $req->content_type("application/json; charset='utf8'");
|
1730 |
|
|
# $req->content($postreq);
|
1731 |
|
|
|
1732 |
|
|
$content = $browser->post($posturl, $postreq)->content();
|
1733 |
|
|
# $content = $browser->post($posturl, 'Content-type' => 'text/plain;charset=utf-8', Content => $postreq)->content();
|
1734 |
|
|
# $content = $browser->request($req)->content();
|
1735 |
|
|
my $fullname = $register{$username}->{'fullname'};
|
1736 |
|
|
$fullname = Encode::decode('utf8', $fullname);
|
1737 |
71b897d3
|
hq
|
return "Updated $fullname in registry\n";
|
1738 |
95b003ff
|
Origo
|
}
|
1739 |
|
|
} |