Project

General

Profile

Download (53.8 KB) Statistics
| Branch: | Revision:
1
#!/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
# https://www.origo.io/info/stabiledocs/licensing/stabile-open-source-license
7

    
8
BEGIN {
9
    open STDERR, '>>', '/dev/null' or die "Couldn't redirect STDERR: $!";
10
}
11

    
12
package Stabile::Piston;
13

    
14
use Error qw(:try);
15
use Socket;
16
use Data::UUID;
17
use File::Basename;
18
use Time::Local;
19
use Time::HiRes qw( time );
20
use LWP::Simple;
21
use lib dirname (__FILE__) . "/../cgi";
22
use Stabile;
23

    
24
$q = new CGI;
25
%params = $q->Vars;
26

    
27
my $servername = $ENV{'SERVER_NAME'};
28
$servername = "localhost" unless $servername;
29
my $serverip = scalar(inet_ntoa(inet_aton($servername)));
30

    
31
$backupdir = $Stabile::config->get('STORAGE_BACKUPDIR') || "/mnt/stabile/backups";
32
my $engineid = $Stabile::config->get('ENGINEID') || "";
33
#my $enginelinked = $Stabile::config->get('ENGINE_LINKED') || "";
34
$brutalsleep = $Stabile::config->get('BRUTAL_SLEEP') || "";
35
$amtpasswd = $Stabile::config->get('AMT_PASSWD') || "";
36

    
37
try {
38
	my $logentry = "";
39
	my @keys = keys %params;
40
	my @values = values %params;
41
	while ($#keys >= 0)
42
	{
43
		$key = pop(@keys); $value = pop(@values);
44
		$logentry .= "$key: $value; ";
45
	}
46
	$logentry .= "REMOTE_ADDR: $ENV{'REMOTE_ADDR'}; Time: $current_time";
47
	# $main::syslogit->('--', 'debug', $logentry);
48

    
49
	my $status = $params{'status'};
50
	my ($user, $uitab, $uiuuid, $uistatus, $plogentry) = split(/: /, uri_unescape($params{'logentry'}));
51
	my $uipath;
52

    
53
# We got a request for clearing the local log file
54
	if ($status eq "clearlog") {
55
		unlink $logfile;
56
		print "\nStatus=OK Log cleared\n";
57
		print end_html(), "\n";
58
		return;
59
	}
60

    
61
    my $mac = uri_unescape($params{'mac'});
62
	$mac =~ tr/[A-Z]/[a-z]/;
63
	$mac =~ s/:/-/g;	
64
	unless ($status eq 'permitopen' || $status eq 'listimagemaster' || $mac =~ /^(\S{2}-\S{2}-\S{2}-\S{2}-\S{2}-\S{2})$/) {throw Error::Simple ("Status=Error invalid mac address: $mac for $id $ENV{'REMOTE_ADDR'}")};
65
	my $filename = $1; # $filename now untainted
66
	my $file = "/mnt/stabile/tftp/pxelinux.cfg/01-$filename";
67
	$mac =~ s/-//g;
68

    
69
	my $ipmiip;
70
	$ipmiip = uri_unescape($params{'ipmiip'}) if ($params{'ipmiip'});
71
	
72
	unless (tie %register,'Tie::DBI', {
73
		db=>'mysql:steamregister',
74
		table=>'nodes',
75
		key=>'mac',
76
		autocommit=>0,
77
		CLOBBER=>3,
78
		user=>$dbiuser,
79
		password=>$dbipasswd}) {throw Error::Simple("Status=Error Register could not be accessed")};
80

    
81
	unless (tie %domreg,'Tie::DBI', {
82
		db=>'mysql:steamregister',
83
		table=>'domains',
84
		key=>'uuid',
85
		autocommit=>0,
86
		CLOBBER=>3,
87
		user=>$dbiuser,
88
		password=>$dbipasswd}) {throw Error::Simple("Status=Error Register could not be accessed")};
89

    
90
    unless (tie %imagereg,'Tie::DBI', {
91
        db=>'mysql:steamregister',
92
        table=>'images',
93
        key=>'path',
94
        autocommit=>0,
95
        CLOBBER=>3,
96
        user=>$dbiuser,
97
        password=>$dbipasswd}) {throw Error::Simple("Status=Image register could not be accessed")};
98

    
99
	unless (tie %idreg,'Tie::DBI', {
100
		db=>'mysql:steamregister',
101
		table=>'nodeidentities',
102
		key=>'identity',
103
		autocommit=>0,
104
		CLOBBER=>3,
105
		user=>$dbiuser,
106
		password=>$dbipasswd}) {throw Error::Simple("Status=Error Register could not be accessed")};
107

    
108
	if ($uiuuid) {
109
        if ($uitab eq 'images' && $imagereg{$uiuuid}) { # We got a path
110
            $uipath = $uiuuid;
111
            $uiuuid = $imagereg{$uipath}->{'uuid'};
112
        } else {
113
            $uiuuid =~ tr/[A-Z]/[a-z]/;
114
            $uiuuid =~ s/\%3a//g;
115
        }
116
	} else {
117
        $uiuuid = $mac;
118
	}
119

    
120

    
121
	if ($status eq "joining" && $mac) {
122
		print header(),
123
		     start_html('Updating Stabile node...'),
124
		     h1('Examining piston request...'),
125
		     hr;
126
		# A new node is trying to join
127
		# First find out which kind of nodes are needed
128

    
129
		my $id = $idreg{'default'}->{'hypervisor'};
130
		my $dist = $idreg{'default'}->{'dist'};
131
		my $path = $idreg{'default'}->{'path'};
132
		my $kernel = $idreg{'default'}->{'kernel'};
133
        $kernel = "-$kernel" if ($kernel);
134
#		untie %idreg;
135
		my $bootentry;
136
		
137
		unless ($dist) {$dist = "lucid"};
138

    
139
		unless (open(TEMP2, ">$file")) {throw Error::Simple("Status=Error boot file \"$file\" could not be created")};
140
		if ($dist eq 'lucid') {
141
			$bootentry = <<ENDBOOT;
142
prompt 0
143
default Stabile Node
144
label Stabile Node
145
kernel vmlinuz$kernel
146
ipappend 2
147
append initrd=initrd.img$kernel ro nomodeset root=/dev/nfs nfsroot=$serverip:$path netboot=nfs union=aufs boot=live ip=dhcp identity=$id acpi=force console=ttyS4,115200n81 console=ttyS1,115200n81 console=tty0 ipv6.disable=1 intel_iommu=on
148
ENDBOOT
149

    
150
    		print TEMP2 $bootentry . "\n";
151
	    	close(TEMP2);
152
		} elsif ($dist) {
153
			$bootentry = <<ENDBOOT;
154
prompt 0
155
default Stabile Node
156
label Stabile Node
157
kernel vmlinuz$kernel
158
ipappend 2
159
append initrd=initrd.img$kernel ro nomodeset root=/dev/nfs nfsroot=$serverip:$path netboot=nfs union=aufs boot=casper ip=dhcp identity=$id acpi=force console=ttyS4,115200n81 console=ttyS1,115200n81 console=tty0 ipv6.disable=1 intel_iommu=on disable_mtrr_cleanup
160
ENDBOOT
161

    
162
			print TEMP2 $bootentry . "\n";
163
			close(TEMP2);
164
		} else {throw Error::Simple("Status=Error no default node identity")};
165

    
166
		my $macname = $mac;
167
        $macname = $register{$mac}->{'name'} if ($register{$mac});
168
        $register{$mac} = {
169
            identity=>$id,
170
            timestamp=>$current_time,
171
            ip=>$ENV{'REMOTE_ADDR'},
172
            name=>$macname,
173
            cpucores=>$params{'cpucores'},
174
            cpucount=>$params{'cpucount'},
175
            cpuspeed=>$params{'cpuspeed'},
176
            cpuname=>uri_unescape($params{'cpuname'}),
177
            cpufamily=>$params{'cpufamily'},
178
            cpumodel=>$params{'cpumodel'},
179
            memtotal=>$params{'memtotal'},
180
            memfree=>$params{'memfree'},
181
            stortotal=>$params{'stortotal'},
182
            storfree=>$params{'storfree'},
183
            status=>$status,
184
            ipmiip=>$ipmiip
185
		};
186
		tied(%register)->commit;
187
		print "\nAssimilation=OK $mac\n";
188
		print end_html(), "\n";
189

    
190
# We got a request for updating a user's UI
191
	} elsif ($status eq "updateui") {
192
		print header();
193
		if ($user && $uitab eq "images" && $uiuuid && !($uistatus =~ /backingup/)) {
194
            $imagereg{$uipath}->{'status'} = $uistatus;
195
            tied(%imagereg)->commit();
196
            if ($plogentry =~ /Backed up/) { # An image was backed up from the node
197
                $imagereg{$uipath}->{'btime'} = $current_time;
198
                my $imguser = $imagereg{$uipath}->{'user'};
199
                my($fname, $dirpath, $suffix) = fileparse($uipath, (".vmdk", ".img", ".vhd", ".qcow", ".qcow2", ".vdi", ".iso"));
200
                my $subdir = "";
201
                if ($dirpath =~ /\/$user(\/.+)\//) {
202
                    $subdir = $1;
203
                }
204
                my $backupsize = getBackupSize($subdir, "$fname$suffix", $imguser);
205
                updateImageBilling($user, $uipath, "backed up", $backupsize);
206
            }
207
            if ($plogentry) {
208
				if ($plogentry =~ /Backup aborted/) {
209
					# A backup has been aborted - possibly a node was rebooted - update image status
210
					$Stabile::Images::user = $user;
211
					$Stabile::Images::console = 1;
212
					require "$Stabile::basedir/cgi/images.cgi";
213
					my $res = Stabile::Images::Updateregister($uipath, 'updateregister');
214
					$main::syslogit->($user, 'info', "Updated image status - $user, $uipath, $res");
215
					$uistatus = $res if ($res);
216
				}
217
				my $upd = {user=>$user, uuid=>$uiuuid, status=>$uistatus, message=>$plogentry, type=>'update', tab=>'images'};
218
				$upd->{'backup'} = $uipath if ($plogentry =~ /Backed up/);
219
				$main::updateUI->($upd);
220
                $main::syslogit->($user, 'info', "$plogentry $uiuuid ($uitab, $uistatus)");
221
                $plogentry = "";
222
            }
223
        } elsif ($uitab eq "servers" && $uiuuid) {
224
            if ($domreg{$uiuuid}) {
225
                $user = $domreg{$uiuuid}->{user};
226
                my $error = 0;
227
                if ($plogentry =~ /error/i || $plogentry =~ /not moved/i) { # There was an error moving the server
228
                    $domreg{$uiuuid}->{status} = 'inactive';
229
                    $error = 1;
230
                }
231
                my $sshcmd = $Stabile::sshcmd;
232
                my $cmd;
233
                my $dmacip = '';
234
                my $macip = $register{$mac}->{ip};
235
                if ($macip eq '10.0.0.1') {
236
                    $dmacip = `cat /tmp/$uiuuid.dest`;
237
                } else {
238
                    $dmacip = `$sshcmd $macip cat /tmp/$uiuuid.dest`;
239
                }
240
                chomp $dmacip;
241

    
242
                # Find the images left behind after move
243
                my @regkeys = (tied %imagereg)->select_where("domains = '$uiuuid'");
244
                if ($error) {
245
                    # Clean up - restore connection with images that failed to be moved to the new node
246
                    # We are using ssh even on local node because piston does not have privileged access
247
                    $cmd = qq[$sshcmd $macip "LIBVIRT_DEFAULT_URI=qemu:///system virsh list --uuid" | grep $uiuuid];
248
                    # Check that moved vm is actually running on destination node
249
                    my $running_on_old_node = `$cmd`;
250
                    unless ($running_on_old_node) { # Try again
251
                        sleep 5;
252
                        $running_on_old_node = `$cmd`;
253
                    }
254
                    chomp $running_on_old_node;
255
                    my $domimg = $domreg{$uiuuid}->{image};
256
                    my $domimg2 = $domreg{$uiuuid}->{image2};
257
                    my $domimg3 = $domreg{$uiuuid}->{image3};
258
                    my $domimg4 = $domreg{$uiuuid}->{image4};
259
                    foreach my $image (@regkeys) {
260
                        if ($imagereg{$image}->{status} =~ /moving/) { # Only deal with images that were being moved
261
                            if ($image eq $domimg || $image eq $domimg2 || $image eq $domimg3 || $image eq $domimg4
262
                            ) {
263
                                $imagereg{$image}->{status} = 'unused'; # This is an image that failed to be moved
264
                                if ($running_on_old_node) {
265
                                    my $imguuid = $imagereg{$image}->{uuid};
266
                                    my $res = `$sshcmd 10.0.0.1 "echo images/$imguuid/remove | /usr/local/bin/stash"`;
267
                                    $main::syslogit->($user, 'info', "Removing $image from node $mac");
268
                                } else {
269
                                    $main::syslogit->($user, 'info', "Not removing $image from node $mac, $domreg{$uiuuid}->{status}, $cmd");
270
                                }
271
                            } else {
272
                                $imagereg{$image}->{status} = 'used'; # This is an image that originally belonged to the server
273
                                my $imgname = $1 if ($image =~ /.+\/(.+\.qcow2)$/);
274
                                # Restore connection to image
275
                                if ($domimg =~ /$imgname/) {
276
                                    $domreg{$uiuuid}->{image} = $image;
277
                                } elsif ($domimg2 =~ /$imgname/) {
278
                                    $domreg{$uiuuid}->{image2} = $image;
279
                                } elsif ($domimg3 =~ /$imgname/) {
280
                                    $domreg{$uiuuid}->{image3} = $image;
281
                                } elsif ($domimg4 =~ /$imgname/) {
282
                                    $domreg{$uiuuid}->{image4} = $image;
283
                                }
284
                            }
285
                        }
286
                    }
287

    
288
                } else {
289
                    # Mark images left behind that no longer belongs to the server as unused and remove them if domain is running on the new node
290
                    # We are using ssh even on local node because piston does not have privileged access
291
                    $cmd = qq[$sshcmd $dmacip "LIBVIRT_DEFAULT_URI=qemu:///system virsh list --uuid" | grep $uiuuid];
292
                    # Check that moved vm is actually running on destination node
293
                    my $running_on_new_node = `$cmd`;
294
                    unless ($running_on_new_node) { # Try again
295
                        sleep 5;
296
                        $running_on_new_node = `$cmd`;
297
                    }
298
                    chomp $running_on_new_node;
299
                    if ($domreg{$uiuuid}->{mac} ne $mac && $running_on_new_node) { # We do not use domain status from DB since it takes a while to update
300
                        $running_on_new_node = 1;
301
                        $Stabile::Images::user = $user;
302
                        $Stabile::Images::console = 1;
303
                        require "$Stabile::basedir/cgi/images.cgi";
304
                    }
305
                    foreach my $image (@regkeys) {
306
                        if ($image ne $domreg{$uiuuid}->{image}
307
                            && $image ne $domreg{$uiuuid}->{image2}
308
                            && $image ne $domreg{$uiuuid}->{image3}
309
                            && $image ne $domreg{$uiuuid}->{image4}
310
                        ) {
311
                            $imagereg{$image}->{status} = 'unused';
312
                            if ($running_on_new_node) {
313
                                my $imguuid = $imagereg{$image}->{uuid};
314
                                my $res = `$sshcmd 10.0.0.1 "echo images/$imguuid/remove | /usr/local/bin/stash"`;
315
                                $main::syslogit->($user, 'info', "Removing $image from node $mac");
316
                            } else {
317
                                $main::syslogit->($user, 'info', "Not removing $image from node $mac, $domreg{$uiuuid}->{status}, $cmd");
318
                            }
319
                        } else {
320
                            $imagereg{$image}->{status} = 'used';
321
                        }
322
                    }
323
                }
324
                my $upd = {user=>$user, uuid=>$uiuuid, message=>$plogentry, type=>'update', tab=>'servers'};
325
                $main::updateUI->($upd);
326
                $main::syslogit->($user, 'info', "$plogentry $uiuuid ($uitab, $uistatus)");
327
                $plogentry = "";
328
            }
329
        }
330
# List the master associated with an image if any
331
	} elsif ($status eq "listimagemaster") {
332
		print header('text/xml');
333
		my $path = $params{'image'};
334
		$path = uri_unescape($path);
335
		my $master = $imagereg{$path}->{'master'};
336
		$master = uri_escape($master);
337
        print $master;
338
# We got a request for listing a domains xml description
339
	} elsif ($status eq "listxml") {
340
		print header('text/xml');
341
		my %xmlreg;
342
		unless (tie %xmlreg,'Tie::DBI', {
343
			db=>'mysql:steamregister',
344
			table=>'domainxml',
345
			key=>'uuid',
346
			autocommit=>0,
347
			CLOBBER=>3,
348
			user=>$dbiuser,
349
			password=>$dbipasswd}) {throw Error::Simple("Status=Error Register could not be accessed")};
350

    
351
		my $uuid = $params{'uuid'};
352
		unless ((defined $uuid) && ($uuid =~ /^(\S{8}-\S{4}-\S{4}-\S{4}-\S{12})$/)) {throw Error::Simple ("Status=Error invalid uuid: $uuid")};
353
		my $xml = $xmlreg{$uuid}->{'xml'};
354
		print uri_unescape($xml);
355
		untie %xmlreg;
356

    
357
# Update sshd_config to allow ssh port forwarding to consoles of a users vm's
358
	} elsif ($status eq "permitopen") {
359
		print header;
360
		my $user = $params{'user'};
361
        $user =~ /(.+)/; $user = $1; #untaint
362
		print start_html('Opening ports...');
363
		permitOpen($user);
364
		print end_html();
365

    
366
# A node is updating it's status
367
	} else {
368
		print header(),
369
		     start_html('Updating Stabile node...'),
370
		     h1('Examining piston request...'),
371
		     hr;
372
		# Look for action requests (from users)
373
		$action = $register{$mac}->{'action'};
374

    
375
        # Look for node tasks, only post requests, get requests generally only update this side
376
        if ($ENV{'REQUEST_METHOD'} eq 'POST') {
377
            $tasks = $register{$mac}->{'tasks'};
378
            $register{$mac}->{'tasks'} = '';
379
            tied(%register)->commit;
380
        }
381

    
382
		$maintenance = $register{$mac}->{'maintenance'};
383
		# If the node is shutting down or joining, don't reboot it
384
		if ($status eq "shutdown" || $status eq "joining") {
385
			$action = "";
386
		}
387
		my $dbstatus = $register{$mac}->{'status'};
388
		my $macname = $register{$mac}->{'name'};
389
		my $nodestatus = $status;
390
        $nodestatus = 'maintenance' if ($status eq 'running' && $maintenance);
391
		if (($dbstatus eq "maintenance" && $status ne "drowsing") || $dbstatus eq "sleeping" || $dbstatus eq "shuttingdown" || !$status || $status eq '--') {
392
            $nodestatus = $dbstatus;
393
		} elsif ( $status eq 'drowsing' && ($dbstatus eq 'running' || $dbstatus eq 'maintenance')) {
394
            if ($brutalsleep && (
395
                    ($register{$mac}->{'amtip'} && $register{$mac}->{'amtip'} ne '--')
396
                || ($register{$mac}->{'ipmiip'} && $register{$mac}->{'ipmiip'} ne '--')
397
                )) {
398
                my $sleepcmd;
399
                $uistatus = "asleep";
400
                print  "\nStatus=SWEETDREAMS";
401
                sleep 2;
402
                if ($register{$mac}->{'amtip'} && $register{$mac}->{'amtip'} ne '--') {
403
                    $sleepcmd = "echo 'y' | AMT_PASSWORD='$amtpasswd' /usr/bin/amttool $register{$mac}->{'amtip'} powerdown";
404
                } else {
405
                    $sleepcmd = "ipmitool -I lanplus -H $register{$mac}->{'ipmiip'} -U ADMIN -P ADMIN power off";
406
                }
407
                my $logmsg = "Node $mac marked for drowse ";
408
                $logmsg .= `$sleepcmd`;
409
                $logmsg =~ s/\n/ /g;
410
                $main::syslogit->('--', "info", $logmsg);
411
            }
412
            $nodestatus = 'asleep';
413
		}
414

    
415
        my %billing;
416

    
417
	# Look for info on whether if this node is waiting to receive vm's and activate the sender
418
        my $receive = uri_unescape($params{'receive'});
419
        if ($receive) {
420
            @uuids = split(/, */,$receive);
421
            foreach my $uuid (@uuids) {
422
                # Sender is the current node/mac running the vm
423
                my $sendmac = $domreg{$uuid}->{'mac'};
424
                my $rip = $register{$mac}->{'ip'};
425
                my $sendtasks = "MOVE $uuid $rip $mac $user\n". $register{$sendmac}->{'tasks'};
426
                chop $sendtasks;
427
                $register{$sendmac}->{'tasks'} .= $sendtasks;
428
            }
429
        }
430

    
431
        my $receivestor = uri_unescape($params{'receivestor'});
432
        if ($receivestor) {
433
            @uuids = split(/, */,$receivestor);
434
            foreach my $uuid (@uuids) {
435
                # Sender is the current node/mac running the vm
436
                my $sendmac = $domreg{$uuid}->{'mac'};
437
                my $rip = $register{$mac}->{'ip'};
438
                my $sendtasks = "MOVESTOR $uuid $rip $mac $user\n". $register{$sendmac}->{'tasks'};
439
                chop $sendtasks;
440
                $register{$sendmac}->{'tasks'} .= $sendtasks;
441
            }
442
        }
443

    
444
        my $returntasks = uri_unescape($params{'returntasks'});
445
        if ($returntasks && $returntasks ne "--") {
446
            $register{$mac}->{'tasks'} .= $returntasks; # Some tasks have failed, try again
447
        }
448

    
449
        # Don't update anything for node feedbacks from actions
450
        if ($status ne '--'
451
            && $status ne 'asleep'
452
            && $status ne 'awake'
453
            && $status ne 'shutdown'
454
            && $status ne 'reboot'
455
            && $status ne 'unjoin'
456
            && $status ne 'permitopen'
457
            && $status ne 'reload'
458
        ) {
459
    # Update basic parameters
460
            my $memfree = $params{'memfree'} || $register{$mac}->{'memfree'};
461
            my $memtotal = $params{'memtotal'} || $register{$mac}->{'memtotal'};
462
            my $cpuload = $params{'cpuload'} || $register{$mac}->{'cpuload'};
463
            my $cpucount = $params{'cpucount'} || $register{$mac}->{'cpucount'};
464
            my $cpucores = $params{'cpucores'} || $register{$mac}->{'cpucores'};
465
            my $nfsroot = uri_unescape($params{'nfsroot'}) || $register{$mac}->{'nfsroot'};
466
            my $kernel = uri_unescape($params{'kernel'}) || $register{$mac}->{'kernel'};
467
            my $reservedvcpus = 0;
468

    
469
            $register{$mac} = {
470
                timestamp=>$current_time,
471
                identity=>$params{'identity'},
472
                ip=>$ENV{'REMOTE_ADDR'},
473
                status=>$nodestatus,
474
                memfree=>$memfree,
475
                memtotal=>$memtotal,
476
                cpuload=>$cpuload,
477
                cpucount=>$cpucount,
478
                cpucores=>$cpucores,
479
    #            reservedvcpus=>0,
480
                nfsroot=>$nfsroot,
481
                kernel=>$kernel,
482
                action=>""
483
            };
484

    
485
            if ($ipmiip) {
486
                $register{$mac}->{'ipmiip'} = $ipmiip;
487
            }
488
            if ($params{'stortotal'} || $params{'stortotal'} eq "0") {
489
                $register{$mac}->{'stortotal'} = $params{'stortotal'};
490
                $register{$mac}->{'storfree'} = $params{'storfree'};
491
                $register{$mac}->{'stor'} = $params{'stor'};
492
            }
493
            tied(%register)->commit;
494

    
495
    # Look for supplied info on domains running on this node, and locally stored images, and update db
496
            my @keys = keys %params;
497
            my @values = values %params;
498
            my $vmvcpus = 0;
499
            my $vms = 0;
500
            my $vmuuids;
501
            my $vmnames;
502
            my $vmusers;
503
            my %reportedimgs;
504
            my $ug = new Data::UUID;
505
            my %nodedomains;
506
            while ($#keys >= 0)
507
            {
508
                $key = pop(@keys); $value = pop(@values);
509
                if ($key =~ m/dom(\d+)/) {
510
                    my $i = $1;
511
                    my $domstatus = $params{"domstate$i"};
512
                    $domreg{$value}->{'statustime'} = $current_time unless ($domreg{$value}->{'statustime'});
513
                    my $statedelta = $current_time - $domreg{$value}->{'statustime'}; # The number of seconds domain has been in same state
514
                    my $domdisplay = $params{"domdisplay$i"};
515
                    my $domport = $params{"domport$i"};
516
                    my $dbdomstatus = $domreg{$value}->{'status'};
517
                    my $dbdommac = $domreg{$value}->{'mac'};
518
                    my $dommac = $mac;
519
                    my $duser = $domreg{$value}->{'user'};
520
                    $nodedomains{$value} = 1;
521
                    $vms++;
522
                    $vmuuids .= "$value, ";
523
                    $vmnames .= "$domreg{$value}->{'name'}, ";
524
                    $vmusers .= "$domreg{$value}->{'user'}, ";
525
                    # Domain status has changed, evaluate if it warrants a ui update
526
                    if ($dbdomstatus =~ /moving/) {
527
    #				    $main::syslogit->($user, 'info', "MOVING: $domstatus/$dommac, $dbdomstatus/$dbdommac");
528
                    }
529
                    if ($dbdomstatus && $domstatus && ($dbdomstatus ne $domstatus)) {
530
                        # Transitional states like shuttingdown are not reported by hypervisor
531
                        # we only update db with permanent states when exiting a transitional hypervisor state or
532
                        # too much time has passed
533
                        if (($dbdomstatus eq "shuttingdown" && $domstatus eq "running" && $statedelta<120)
534
                            || ($dbdomstatus eq "starting" && $domstatus eq "inactive" && $statedelta<30)
535
                            || ($dbdomstatus eq "starting" && $domstatus eq "shutdown" && $statedelta<30)
536
                            || ($dbdomstatus eq "starting" && $domstatus eq "shutoff" && $statedelta<30)
537
                            || ($dbdomstatus eq "suspending" && $domstatus eq "running" && $statedelta<30)
538
                            || ($dbdomstatus eq "resuming" && $domstatus eq "paused" && $statedelta<30)
539
                        # When moving $dbdommac is the originating mac, wait 5 min for moves
540
                            || ($dbdomstatus =~ /moving/ && ($domstatus eq "running" || $domstatus eq "paused" || $domstatus eq "shutoff") && $dbdommac eq $mac && $statedelta<300)
541
                        # We only accept "running" as status from receiving mac
542
                            || ($dbdomstatus =~ /moving/ && ($domstatus ne "running") && $dbdommac ne $mac && $statedelta<300)
543
                            || ($domstatus eq "nostate")
544
                            || ($dbdomstatus eq "destroying" && $domstatus eq "running" && $statedelta<30)
545
                            || ($dbdomstatus eq "destroying" && $domstatus eq "paused" && $statedelta<30)
546
                            || ($dbdomstatus eq "upgrading" && $statedelta<600)
547
                        ) {
548
                            $domstatus = $dbdomstatus; # Keep the database status as status
549
                            $dommac = $dbdommac; # Keep originating mac as authoritative
550
                        } else {
551
                        # We have exited from a transition, update the UI
552
                            $domreg{$value}->{'statustime'} = $current_time;
553
                            $billing{$duser}->{'event'} .= "$domstatus $value\n";
554
                            $main::updateUI->({tab=>"servers", user=>"$duser", uuid=>$value, status=>$domstatus,
555
                                                mac=>$mac, macname=>$macname});
556
                            if ($enginelinked && $engineid) {
557
                                my $sysuuid = $domreg{$value}->{'uuid'};
558
                                my $sysstatus = $domstatus;
559
                                if ($domreg{$value}->{'system'} && $domreg{$value}->{'system'} ne '--') { # This is a system
560
                                    $sysuuid = $domreg{$value}->{'system'};
561
                                    unless (tie %sysreg,'Tie::DBI', {
562
                                        db=>'mysql:steamregister',
563
                                        table=>'systems',
564
                                        key=>'uuid',
565
                                        autocommit=>0,
566
                                        CLOBBER=>3,
567
                                        user=>$dbiuser,
568
                                        password=>$dbipasswd}) {throw Error::Simple("Status=ERROR System register could not be accessed")};
569
                                    # Check if we are dealing with the admin server
570
                                    if ($domreg{$value}->{'image'} ne $sysreg{$sysuuid}->{'image'}) {
571
                                        $sysuuid = '';
572
                                    }
573

    
574
                                    untie %sysreg;
575
                                }
576
                                if ($sysuuid) {
577
                                my $json_text = <<END
578
{"uuid": "$sysuuid" , "status": "$sysstatus"}
579
END
580
;
581
                                    print "\n" . $main::postAsyncToOrigo->($engineid, 'updateapps', "[$json_text]") . "\n";
582
                                }
583
                            }
584
                        }
585
                    }
586

    
587
                    # If a domain is shutoff or state is undetermined, dont't count it in billing
588
                    # if ($domstatus eq "shutoff" || $domstatus eq "inactive" ) {
589
                    if ($domstatus eq "shutoff" || $domstatus eq "inactive" ) {
590
                        $billing{$duser}->{'vcpu'} += 0;
591
                        $billing{$duser}->{'memory'} += 0;
592
                    # All other states count
593
                    } else {
594
                        $billing{$duser}->{'vcpu'} += $domreg{$value}->{'vcpu'};
595
                        $billing{$duser}->{'memory'} += $domreg{$value}->{'memory'};
596
                    }
597
                    # We don't update timestamp for moving domains, so if move fails, eventually they will be marked as inactive
598
                    my $timestamp = $current_time;
599
                    $timestamp = $domreg{$value}->{'timestamp'} if ($domstatus =~ /moving/);
600
                    $domreg{$value} = {
601
                        status=>$domstatus,
602
                        mac=>$dommac,
603
                        macname=>$register{$dommac}->{'name'},
604
                        macip=>$register{$dommac}->{'ip'},
605
                        maccpucores=>$register{$dommac}->{'cpucores'},
606
                        timestamp=>$timestamp
607
                    };
608
                    $domreg{$value}->{'mac'} = $dommac unless ($domstatus =~ /moving/);
609
                    $domreg{$value}->{'display'} = $domdisplay if $domdisplay;
610
                    $domreg{$value}->{'port'} = $domport if $domport;
611
                    if ($params{"domstate$i"} eq 'running') {$vmvcpus += $domreg{$value}->{'vcpu'}};
612
                # If a domain was moved, update permitted ports
613
                    if (($dbdomstatus =~ /moving/ && $domstatus eq "running" && $dbdommac ne $mac)) {
614
                        $main::syslogit->($duser, 'info', "Moved $domreg{$value}->{'name'} ($value) to $register{$dommac}->{'name'}");
615
                        permitOpen($duser);
616
                    }
617
                # Update status of server's images
618
                    my $image = $domreg{$value}->{'image'};
619
                    my $image2 = $domreg{$value}->{'image2'};
620
                    my $image3 = $domreg{$value}->{'image3'};
621
                    my $image4 = $domreg{$value}->{'image4'};
622
                    my $imgstatus = 'active'; # if server is running, moving, etc.
623
                    if ($domstatus eq 'paused') {
624
                        $imgstatus = 'paused'
625
                    } elsif ($domstatus eq "shutoff" || $domstatus eq "inactive")  {
626
                        $imgstatus = 'used'
627
                    }
628
                    print "$image for $domreg{$value}->{name} not in DB" unless ($imagereg{$image});
629
                    $imagereg{$image}->{'status'} = $imgstatus if ($imagereg{$image} && $imagereg{$image}->{'status'} !~ /backingup/ && $imagereg{$image}->{'status'} !~ /moving/);
630
                    $imagereg{$image2}->{'status'} = $imgstatus if ($image2 && $imagereg{$image2} && $image2 ne '--' && $imagereg{$image2}->{'status'} !~ /backingup/ && $imagereg{$image}->{'status'} !~ /moving/);
631
                    $imagereg{$image3}->{'status'} = $imgstatus if ($image3 && $imagereg{$image3} && $image3 ne '--' && $imagereg{$image3}->{'status'} !~ /backingup/ && $imagereg{$image}->{'status'} !~ /moving/);
632
                    $imagereg{$image4}->{'status'} = $imgstatus if ($image4 && $imagereg{$image4} && $image4 ne '--' && $imagereg{$image4}->{'status'} !~ /backingup/ && $imagereg{$image}->{'status'} !~ /moving/);
633

    
634
                } elsif ($key =~ m/img(\d+)/) {
635
            # The node is reporting about a locally stored image
636
                    my $f = uri_unescape($value);
637
                    my $size = $params{"size$1"};
638
                    my $realsize = $params{"realsize$1"};
639
                    my $virtualsize = $params{"virtualsize$1"};
640
                    my($fname, $dirpath, $suffix) = fileparse($f, (".vmdk", ".img", ".vhd", ".qcow", ".qcow2", ".vdi", ".iso"));
641
                    my $regimg = $imagereg{$f};
642
                    my $uuid = $regimg->{'uuid'};
643

    
644
                    my $storagepool = -1;
645
                    $f =~ m/\/mnt\/stabile\/node\/(.+?)\/.+/; # ungready matching
646
                    my $imguser = $1;
647

    
648
            # Create a new uuid if we are dealing with a new file in the file-system
649
                    if (!$uuid) {
650
                        $uuid = $ug->create_str() unless ($uuid);
651
                        $main::syslogit->($imguser, 'info', "Assigned new uuid $uuid to $f belonging to $imguser");
652
                    }
653

    
654
                    my $mtime = $newmtime || $regimg->{'mtime'};
655
                    my $name = $regimg->{'name'} || $fname;
656

    
657
                    my $subdir = "";
658
                    if ($dirpath =~ /\/$imguser(\/.+)\//) {
659
                        $subdir = $1;
660
                    }
661
                    my $bdu;
662
                    my $backupsize = 0;
663
                    my $imgpath = "$fname$suffix";
664
                    $imgpath = $1 if $cmdpath =~ /(.+)/; # untaint
665
                    $backupsize = getBackupSize($subdir, $imgpath, $imguser);
666
            # If image on node is attached to a domain, reserve vcpus for starting domain on node
667
                    my $imgdom = $regimg->{'domains'};
668
                    if ($imgdom && $domreg{$imgdom}) {
669
                        my $imgvcpus = $domreg{$imgdom}->{'vcpu'};
670
                        my $imgdomstatus = $domreg{$imgdom}->{'status'};
671
                        $reservedvcpus += $imgvcpus if ($imgdomstatus eq 'shutoff' || $imgdomstatus eq 'inactive');
672
                    }
673

    
674
                    $reportedimgs{$f} = 1;
675
                    if (($regimg->{'virtualsize'} == 0 && $virtualsize) || $regimg->{'status'} =~ /moving/) {
676
                        $reportedimgs{$f} = 2; # Mark that we should update the UI - this is a recently transferred image
677
                    }
678
                    if ($f && $imguser) {
679
                        my $imgstatus = $regimg->{'status'};
680
                        # This only happens first time after an image has been transferred manually to a node
681
                        if (!$imgstatus || $imgstatus eq '--' || $imgstatus eq 'cloning') {
682
                            $imgstatus = "unused";
683
                            my $imgdomains = $regimg->{'domains'};
684
                            my $imgdomainnames = $regimg->{'domainnames'};
685
                            (tied %domreg)->select_where("user = '$imguser' or user = 'common'") unless ($fulllist);
686
                            foreach my $dom (values %domreg) {
687
                                my $img = $dom->{'image'};
688
                                my $img2 = $dom->{'image2'};
689
                                my $img3 = $dom->{'image3'};
690
                                my $img4 = $dom->{'image4'};
691
                                if ($f eq $img || $f eq $img2 || $f eq $img3 || $f eq $img4) {
692
                                    $imgstatus = "active";
693
                                    my $domstatus = $dom->{'status'};
694
                                    if ($domstatus eq "shutoff" || $domstatus eq "inactive") {$imgstatus = "used";}
695
                                    elsif ($domstatus eq "paused") {$imgstatus = "paused";}
696
                                    $imgdomains = $dom->{'uuid'};
697
                                    $imgdomainnames = $dom->{'name'};
698
                                };
699
                            }
700
                            $imagereg{$f} = {
701
                                user=>$imguser,
702
                                type=>substr($suffix,1),
703
                                size=>$size,
704
                                realsize=>$realsize,
705
                                virtualsize=>$virtualsize,
706
                                backupsize=>$backupsize,
707
                                name=>$name,
708
                                uuid=>$uuid,
709
                                storagepool=>$storagepool,
710
                                mac=>$mac,
711
                                mtime=>$mtime,
712
                                status=>$imgstatus,
713
                                domains=>$imgdomains,
714
                                domainnames=>$imgdomainnames
715
                            }
716
                        } else {
717
                            $imagereg{$f} = {
718
                                user=>$imguser,
719
                                type=>substr($suffix,1),
720
                                size=>$size,
721
                                realsize=>$realsize,
722
                                virtualsize=>$virtualsize,
723
                                backupsize=>$backupsize,
724
                                name=>$name,
725
                                uuid=>$uuid,
726
                                storagepool=>$storagepool,
727
                                mac=>$mac,
728
                                mtime=>$mtime
729
                            }
730
                        }
731
                    }
732

    
733
                }
734
            }
735

    
736
            if ($params{'dominfo'} || $params{'dom1'}) {
737
                $register{$mac}->{'vms'} = $vms;
738
                $register{$mac}->{'vmvcpus'} = $vmvcpus;
739
                $register{$mac}->{'vmuuids'} = substr($vmuuids,0,-2);
740
                $register{$mac}->{'vmnames'} = substr($vmnames,0,-2);
741
                $register{$mac}->{'vmusers'} = substr($vmusers,0,-2);
742
            }
743
            if ($params{'stortotal'}) {
744
                $register{$mac}->{'reservedvcpus'} = $reservedvcpus;
745
            }
746

    
747
    # Clean up image db - remove images that are no longer on the node
748
            if ($params{'stortotal'} || $params{'stortotal'} eq "0") {
749
                my @regkeys = (tied %imagereg)->select_where("mac = '$mac'");
750
                foreach my $k (@regkeys) {
751
                    my $valref = $imagereg{$k};
752
                    if ( ($valref->{'storagepool'} == -1) && ($valref->{'mac'} eq $mac) && !($valref->{'status'} =~ /moving/) && !($valref->{'status'} =~ /cloning/) ) {
753
                        if ($reportedimgs{$valref->{'path'}} == 1) {
754
                        } elsif ($reportedimgs{$valref->{'path'}} == 2){
755
                            updateImageBilling($valref->{'user'}, $valref->{'path'}, "new image");
756
                        } else {
757
                            $main::updateUI->({tab=>"images", user=>$valref->{'user'}});
758
                            $main::syslogit->($valref->{'user'}, 'info', "Deleting image from db $valref->{'user'} - $reportedimgs{$valref->{'path'}} - $valref->{'path'} - $valref->{'status'} - $valref->{'mac'}");
759
                            delete $imagereg{$valref->{'path'}};
760
                            updateImageBilling($valref->{'user'}, $valref->{'path'}, "no image");
761
                        }
762
                    } elsif ($valref->{'storagepool'} == -1) {
763
                        ;
764
                    }
765
                }
766
            }
767

    
768
    # Clean up domain status, mark domains which are inactive or shuttingdown and not present on this node as shutoff
769
            my @regkeys = (tied %domreg)->select_where("mac = '$mac'");
770
            foreach my $domkey (@regkeys) {
771
                my $domref = $domreg{$domkey};
772
                if ($domref->{'mac'} eq $mac) {
773
                    if ($domref->{'status'} eq 'inactive' ||
774
                        ($domref->{'status'} eq 'shuttingdown' && $params{'memfree'} && !($nodedomains{$domref->{'uuid'}})) # domain has shut down, checking for param 'memfree' to make sure it's not just a status update from node
775
                    ) {
776
                        $domref->{'status'} = 'shutoff';
777
    #                    $main::updateUI->({tab=>"servers", user=>$domref->{'user'}, uuid=>$domref->{'uuid'}, status=>'shutoff',
778
    #                        message=>"shutoff ".$vmuuids."::".$domref->{'uuid'}});
779
                    }
780
                }
781
            }
782

    
783

    
784
    # Update billing
785
            my %billingreg;
786
            $monthtimestamp = timelocal(0,0,0,1,$mon,$year); #$sec,$min,$hour,$mday,$mon,$year
787
            # $monthtimestamp = timelocal(0,0,$hour,$mday,$mon,$year); #$sec,$min,$hour,$mday,$mon,$year
788
            unless (tie %userreg,'Tie::DBI', {
789
                db=>'mysql:steamregister',
790
                table=>'users',
791
                key=>'username',
792
                autocommit=>0,
793
                CLOBBER=>1,
794
                user=>$dbiuser,
795
                password=>$dbipasswd}) {return 0};
796
            my @pusers = keys %userreg;
797
            untie %userreg;
798
            unless (tie %billingreg,'Tie::DBI', {
799
                db=>'mysql:steamregister',
800
                table=>'billing_domains',
801
                key=>'usernodetime',
802
                autocommit=>0,
803
                CLOBBER=>3,
804
                user=>$dbiuser,
805
                password=>$dbipasswd}) {throw Error::Simple("Status=Error Billing register could not be accessed")};
806

    
807
            foreach my $puser (@pusers) {
808
                my $b = $billing{$puser};
809
                my $vcpu = $b->{'vcpu'};
810
                my $memory = $b->{'memory'};
811
                my $startvcpuavg = 0;
812
                my $startmemoryavg = 0;
813
                my $vcpuavg = 0;
814
                my $memoryavg = 0;
815
                my $starttimestamp = $current_time;
816

    
817
            # Are we just starting a new month
818
                if ($current_time - $monthtimestamp < 4*3600) {
819
                    $starttimestamp = $monthtimestamp;
820
                    $vcpuavg = $vcpu;
821
                    $startvcpuavg = $vcpu;
822
                    $memoryavg = $memory;
823
                    $startmemoryavg = $memory;
824
                }
825

    
826
                if ($billingreg{"$puser-$mac-$year-$month"}) {
827
                # Update timestamp and averages
828
                    $startvcpuavg = $billingreg{"$puser-$mac-$year-$month"}->{'startvcpuavg'};
829
                    $startmemoryavg = $billingreg{"$puser-$mac-$year-$month"}->{'startmemoryavg'};
830
                    $starttimestamp = $billingreg{"$puser-$mac-$year-$month"}->{'starttimestamp'};
831
                    $vcpuavg = ($startvcpuavg*($starttimestamp - $monthtimestamp) + $vcpu*($current_time - $starttimestamp)) /
832
                                    ($current_time - $monthtimestamp);
833
                    $memoryavg = ($startmemoryavg*($starttimestamp - $monthtimestamp) + $memory*($current_time - $starttimestamp)) /
834
                                    ($current_time - $monthtimestamp);
835

    
836
                    $billingreg{"$puser-$mac-$year-$month"}->{'vcpuavg'} = $vcpuavg;
837
                    $billingreg{"$puser-$mac-$year-$month"}->{'memoryavg'} = $memoryavg;
838
                    $billingreg{"$puser-$mac-$year-$month"}->{'timestamp'} = $current_time;
839
                }
840

    
841
                # No row found or something happened which justifies writing a new row
842
                if (!$billingreg{"$puser-$mac-$year-$month"}
843
                || ($vcpu != $billingreg{"$puser-$mac-$year-$month"}->{'vcpu'})
844
                || ($memory != $billingreg{"$puser-$mac-$year-$month"}->{'memory'})
845
                ) {
846
                    my $inc = 0;
847
                    if ($billingreg{"$puser-$mac-$year-$month"}) {
848
                        $startvcpuavg = $vcpuavg;
849
                        $startmemoryavg = $memoryavg;
850
                        $starttimestamp = $current_time;
851
                        $inc = $billingreg{"$puser-$mac-$year-$month"}->{'inc'};
852
                    }
853
                    # Write a new row
854
                    $billingreg{"$puser-$mac-$year-$month"} = {
855
                        vcpu=>$vcpu,
856
                        memory=>$memory,
857
                        vcpuavg=>$vcpuavg,
858
                        memoryavg=>$memoryavg,
859
                        startvcpuavg=>$startvcpuavg,
860
                        startmemoryavg=>$startmemoryavg,
861
                        timestamp=>$current_time,
862
                        starttimestamp=>$starttimestamp,
863
                        event=>$b->{'event'},
864
                        inc=>$inc+1,
865
                    };
866
                }
867
            }
868
            untie %billingreg;
869

    
870
            tied(%domreg)->commit;
871

    
872
		}
873
# Check if this node has tasks, and send them to the node them if any
874

    
875
		if ($tasks) {
876
    		my $sendtasks = '';
877
			@tasklist = split(/\n/,$tasks);
878
			$sendtasks .= "\n";
879
			foreach $thetask (@tasklist) {
880
			    my ($task,$user) = split(/ /, $tasks);
881
				if ($task eq 'reboot') {
882
					$sendtasks .= "\nStatus=REBOOT $user\n";
883
				} elsif ($task eq 'shutdown' || $task eq 'halt') {
884
					$sendtasks .= "\nStatus=HALT $user\n";
885
				} elsif ($task eq 'unjoin') {
886
					unlink $file;
887
					$sendtasks .= "\nStatus=UNJOIN $user\n";
888
				} elsif ($task eq 'reload') {
889
					$sendtasks .= "\nStatus=RELOAD $user\n";
890
				} elsif ($task eq 'wipe') {
891
					$sendtasks .= "\nStatus=WIPE $user\n";
892
				} elsif ($task eq 'sleep') {
893
					$sendtasks .= "\nStatus=SLEEP $user\n";
894
				} elsif ($task eq 'wake') {
895
					$sendtasks .= "\nStatus=WAKE $user\n";
896
				} else {
897
				     if ($task) {
898
                        $sendtasks .= "Status=$thetask\n";
899
                    }
900
				};
901
			}
902
            if ($sendtasks) {
903
                print  "\nStatus=OK $mac";
904
                print "$sendtasks";
905
                `echo "SENDING TASKS to $mac: $sendtasks" >> /var/log/stabile/steamExec.out`;
906
            }
907
		} else {
908
			print  "\nStatus=OK $mac\n";
909
			my $sleepafter = $idreg{'default'}->{'sleepafter'};
910
			$sleepafter = 60 * $sleepafter;
911
			print "Status=SLEEPAFTER ". $sleepafter . "\n";
912
		}
913
		print end_html(), "\n";
914
	}
915
	untie %register;
916
	untie %domreg;
917
	untie %imagereg;
918
	untie %idreg;
919

    
920
    if ($plogentry && $plogentry ne '' && $uistatus) {
921
        $uistatus = 'maintenance' if ($uistatus eq 'running' && $maintenance);
922
        $main::updateUI->({tab=>$uitab, user=>$user, uuid=>$uiuuid, status=>$uistatus, mac=>$mac, macname=>$macname}) unless ($status eq '--');
923
        $main::syslogit->($user, 'info', "$plogentry $uiuuid ($uitab, $uistatus)");
924
    }
925

    
926
} catch Error with {
927
	my $ex = shift;
928
	print "\n", "$ex->{-text} (line: $ex->{-line})", "\n";
929
} finally {
930
};
931

    
932
sub permitOpen {
933
    my ($user) = @_;
934
    my $permit;
935

    
936
    unless (tie %userreg,'Tie::DBI', {
937
        db=>'mysql:steamregister',
938
        table=>'users',
939
        key=>'username',
940
        autocommit=>0,
941
        CLOBBER=>1,
942
        user=>$dbiuser,
943
        password=>$dbipasswd}) {return 0};
944

    
945
    my $privileges = $userreg{$user}->{'privileges'};
946
    my $allowfrom = $userreg{$user}->{'allowfrom'};
947
    untie %userreg;
948

    
949
    my @allows = split(/,\s*/, $allowfrom);
950

    
951
    if ($privileges && (index($privileges,"r")!=-1 || index($privileges,"d")!=-1)) {
952
        ; # User is disabled or has only readonly access
953
    } elsif ($user) {
954
        my @regkeys = (tied %domreg)->select_where("user = '$user'");
955
        foreach my $k (@regkeys) {
956
            my $val = $domreg{$k};
957
        # Only include VM's belonging to current user
958
            if ($user eq $val->{'user'}) {
959
                # Only include drivers we have heard from in the last 20 secs
960
                #if ($current_time - ($val->{'timestamp'}) < 20) {
961
                    my $targetmac = $val->{'mac'};
962
                    my $targetip = $register{$targetmac}->{'ip'};
963
                    my $targetport = $val->{'port'};
964
                    if ($targetip && $targetport) {$permit .= " $targetip:$targetport";};
965
                #} else {
966
                #};
967
            }
968
        }
969
        $permit = " 192.168.0.254:8000" unless $permit;
970
    #    $main::syslogit->($user, 'info', "Allowed portforwarding for $user: $permit");
971

    
972
        open(TEMP1, "</etc/ssh/sshd_config") || (die "Problem reading sshd_config");
973
        open(TEMP2, ">/etc/ssh/sshd_config.new") || (die "Problem writing sshd_config");
974
        print TEMP2 "# Timestamp: $pretty_time\n";
975
        my $umatch = 0;
976
        my $allowusers;
977
        my $auser = $user;
978
        $auser =~ s/\@/\?/; # sshd_config does not support @'s in AllowUsers usernames
979
        if ($allowfrom) { # Only allow login from certain ip's
980
            $allowusers = "AllowUsers";
981
            foreach my $ip (@allows) {
982
                $ip = "$1*" if ($ip =~ /(\d+\.)0\.0\.0/);
983
                $ip = "$1*" if ($ip =~ /(\d+\.\d+\.)0\.0/);
984
                $ip = "$1*" if ($ip =~ /(\d+\.\d+\.\d+\.)0/);
985
                $allowusers .= " irigo-$auser\@$ip ";
986
            }
987
            $allowusers .= "\n";
988
        } else {
989
            $allowusers = "AllowUsers irigo-$auser\n"; # Allow from anywhere
990
        }
991

    
992
        my $matchuser = "irigo-$auser";
993
        $matchuser =~ tr/\?/./; # question marks don't work in regexp match
994
        while (<TEMP1>) {
995
            my $line = $_;
996

    
997
            if ($user && $line =~ m/Match User $matchuser/) {$umatch = 1;}
998
            elsif ($umatch && $line =~ m/Match User/) {$umatch = 0;}
999

    
1000
            if ($line =~ m/AllowUsers irigo\@localhost/) {
1001
                print TEMP2 $line;
1002
                print TEMP2 "$allowusers";
1003
                next;
1004
            }
1005
            if (!$umatch && !($line =~ /^AllowUsers $matchuser/) && !($line =~ m/^# Timestamp/)) {
1006
                print TEMP2 $line;
1007
            }
1008
        }
1009

    
1010
        print TEMP2 <<END1;
1011
Match User irigo-$user
1012
ForceCommand /usr/local/bin/permitOpen $user 1
1013
PermitOpen$permit
1014
END1
1015

    
1016
;
1017
    #ForceCommand /usr/bin/perl -e '\$|=1;while (1) { print scalar localtime() . "\\n";sleep 30}'
1018
        close(TEMP1);
1019
        close(TEMP2);
1020
        rename("/etc/ssh/sshd_config", "/etc/ssh/sshd_config.old") || print "Status=ERROR Don't have permission to rename sshd_config";
1021
        rename("/etc/ssh/sshd_config.new", "/etc/ssh/sshd_config") || print "Status=ERROR Don't have permission to rename sshd_config";
1022
        eval {$output = `/etc/init.d/ssh restart`; 1;}  or do {print "Status=ERROR $@";};
1023
    }
1024
}
1025

    
1026
sub trim{
1027
   my $string = shift;
1028
   $string =~ s/^\s+|\s+$//g;
1029
   return $string;
1030
}
1031

    
1032
sub updateImageBilling {
1033
    my ($user, $bpath, $status, $backupsize) = @_; # Update billing for specific image storage pool with either virtualsize and backupsize
1034

    
1035
    if ($backupsize) {
1036
        $imagereg{$bpath}->{'backupsize'} = $backupsize;
1037
    }
1038
    return "No user" unless ($user);
1039
    my $tenders = $Stabile::config->get('STORAGE_POOLS_ADDRESS_PATHS');
1040
    my @tenderlist = split(/,\s*/, $tenders);
1041
    my $tenderpaths = $Stabile::config->get('STORAGE_POOLS_LOCAL_PATHS') || "/mnt/stabile/images";
1042
    my @tenderpathslist = split(/,\s*/, $tenderpaths);
1043
    my $tendernames = $Stabile::config->get('STORAGE_POOLS_NAMES') || "Standard storage";
1044
    my @tendernameslist = split(/,\s*/, $tendernames);
1045
    my $storagepools = $Stabile::config->get('STORAGE_POOLS_DEFAULTS') || "0";
1046
    my $storagepool = 0;
1047
    if ($bpath =~ /\/mnt\/stabile\/node\//) {
1048
        $storagepool = -1;
1049
    } else {
1050
        my @spl = split(/,\s*/, $storagepools);
1051
        foreach my $p (@spl) {
1052
            if ($tenderlist[$p] && $tenderpathslist[$p] && $tendernameslist[$p]) {
1053
                my %pool = ("hostpath", $tenderlist[$p],
1054
                            "path", $tenderpathslist[$p],
1055
                            "name", $tendernameslist[$p],
1056
                            "rdiffenabled", $rdiffenabledlist[$p],
1057
                            "id", $p);
1058
                $spools[$p] = \%pool;
1059
                $storagepool = $p if ($bpath =~ /$tenderpathslist[$p]/)
1060
            }
1061
        }
1062
    }
1063

    
1064
    my %billing;
1065

    
1066
    my @regkeys = (tied %imagereg)->select_where("user = '$user' AND storagepool = '$storagepool'");
1067
    foreach my $k (@regkeys) {
1068
        my $valref = $imagereg{$k};
1069
        my %val = %{$valref}; # Deference and assign to new array, effectively cloning object
1070
        $val{'virtualsize'} += 0;
1071
        $val{'realsize'} += 0;
1072
        $val{'backupsize'} += 0;
1073

    
1074
        if ($val{'user'} eq $user && $val{'storagepool'} == $storagepool) {
1075
            $billing{$val{'storagepool'}}->{'virtualsize'} += $val{'virtualsize'};
1076
            $billing{$val{'storagepool'}}->{'realsize'} += $val{'realsize'};
1077
            $billing{$val{'storagepool'}}->{'backupsize'} += $val{'backupsize'};
1078
        }
1079
    }
1080

    
1081
    my %billingreg;
1082
    my $monthtimestamp = timelocal(0,0,0,1,$mon,$year); #$sec,$min,$hour,$mday,$mon,$year
1083

    
1084
    unless (tie %billingreg,'Tie::DBI', {
1085
        db=>'mysql:steamregister',
1086
        table=>'billing_images',
1087
        key=>'userstoragepooltime',
1088
        autocommit=>0,
1089
        CLOBBER=>3,
1090
        user=>$dbiuser,
1091
        password=>$dbipasswd}) {$main::syslogit->($user, 'info', "Status=Error Billing register could not be accessed")};
1092

    
1093
    my $b = $billing{$storagepool};
1094
    my $virtualsize = $b->{'virtualsize'};
1095
    my $realsize = $b->{'realsize'};
1096
    my $backupsize = $b->{'backupsize'};
1097
    my $startvirtualsizeavg = 0;
1098
    my $startrealsizeavg = 0;
1099
    my $startbackupsizeavg = 0;
1100
    my $starttimestamp = $current_time;
1101
    # No row found or something happened which justifies writing a new row
1102
    if ($b->{'event'} || !$billingreg{"$user-$storagepool-$year-$month"}
1103
    || ($b->{'virtualsize'} != $billingreg{"$user-$storagepool-$year-$month"}->{'virtualsize'})
1104
    || ($b->{'realsize'} != $billingreg{"$user-$storagepool-$year-$month"}->{'realsize'})
1105
    || ($b->{'backupsize'} != $billingreg{"$user-$storagepool-$year-$month"}->{'backupsize'})
1106
    ) {
1107
        my $inc = 0;
1108
        if ($billingreg{"$user-$storagepool-$year-$month"}) {
1109
            $startvirtualsizeavg = $billingreg{"$user-$storagepool-$year-$month"}->{'virtualsizeavg'};
1110
            $startrealsizeavg = $billingreg{"$user-$storagepool-$year-$month"}->{'realsizeavg'};
1111
            $startbackupsizeavg = $billingreg{"$user-$storagepool-$year-$month"}->{'backupsizeavg'};
1112
            $starttimestamp = $billingreg{"$user-$storagepool-$year-$month"}->{'timestamp'};
1113
            $inc = $billingreg{"$user-$storagepool-$year-$month"}->{'inc'};
1114
        # Copy the old row for archival purposes
1115
#            my %bill = %{$billingreg{"$user-$storagepool-$year-$month"}};
1116
#            $billingreg{"$user-$storagepool-$year-$month-$current_time"} = \%bill;
1117
        }
1118
        # Write a new row
1119
        $billingreg{"$user-$storagepool-$year-$month"} = {
1120
            virtualsize=>$virtualsize+0,
1121
            realsize=>$realsize+0,
1122
            backupsize=>$backupsize+0,
1123
            virtualsizeavg=>$startvirtualsizeavg,
1124
            realsizeavg=>$startrealsizeavg,
1125
            backupsizeavg=>$startbackupsizeavg,
1126
            timestamp=>$current_time,
1127
            startvirtualsizeavg=>$startvirtualsizeavg,
1128
            startrealsizeavg=>$startrealsizeavg,
1129
            startbackupsizeavg=>$startbackupsizeavg,
1130
            starttimestamp=>$starttimestamp,
1131
            event=>"$status $bpath",
1132
            inc=>$inc+1,
1133
        };
1134
    } else {
1135
    # Update timestamp and averages
1136
        $startvirtualsizeavg = $billingreg{"$user-$storagepool-$year-$month"}->{'startvirtualsizeavg'};
1137
        $startrealsizeavg = $billingreg{"$user-$storagepool-$year-$month"}->{'startrealsizeavg'};
1138
        $startbackupsizeavg = $billingreg{"$user-$storagepool-$year-$month"}->{'startbackupsizeavg'};
1139
        $starttimestamp = $billingreg{"$user-$storagepool-$year-$month"}->{'starttimestamp'};
1140
        my $virtualsizeavg = ($startvirtualsizeavg*($starttimestamp - $monthtimestamp) + $virtualsize*($current_time - $starttimestamp)) /
1141
                        ($current_time - $monthtimestamp);
1142
        my $realsizeavg = ($startrealsizeavg*($starttimestamp - $monthtimestamp) + $realsize*($current_time - $starttimestamp)) /
1143
                        ($current_time - $monthtimestamp);
1144
        my $backupsizeavg = ($startbackupsizeavg*($starttimestamp - $monthtimestamp) + $backupsize*($current_time - $starttimestamp)) /
1145
                        ($current_time - $monthtimestamp);
1146

    
1147
        $billingreg{"$user-$storagepool-$year-$month"}->{'virtualsizeavg'} = $virtualsizeavg;
1148
        $billingreg{"$user-$storagepool-$year-$month"}->{'realsizeavg'} = $realsizeavg;
1149
        $billingreg{"$user-$storagepool-$year-$month"}->{'backupsizeavg'} = $backupsizeavg;
1150
        $billingreg{"$user-$storagepool-$year-$month"}->{'timestamp'} = $current_time;
1151
    }
1152
    untie %billingreg;
1153
}
(1-1/2)