Project

General

Profile

Download (57.1 KB) Statistics
| Branch: | Revision:
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
# https://www.origo.io/info/stabiledocs/licensing/stabile-open-source-license
7
8
package Stabile::Steamexec;
9
10
use Tie::DBI;
11
use URI::Escape;
12
use File::Basename;
13
use File::Copy;
14
use File::Rsync;
15
use Proc::ProcessTable;
16
use Sys::Syslog qw( :DEFAULT setlogsock);
17
use ConfigReader::Simple;
18
use Time::Local;
19
use XML::Simple;
20
use Data::Dumper;
21
use Data::UUID;
22
use lib '/var/www/stabile/cgi';
23
use Stabile;
24
25
my $arg1 = shift if $ARGV[0];
26
my $status = shift if $ARGV[0];
27
my $oldstatus = shift if $ARGV[0];
28
my $path1 = shift if $ARGV[0];
29
my $path2 = shift if $ARGV[0];
30
my $cmd1 =  shift if $ARGV[0];
31
my $cmd2 =  shift if $ARGV[0];
32
#my $cmd = join(" ", @ARGV); # The rest
33
my $res;
34
my $dsnap1;
35
my $fstab = "/etc/fstab";
36
my $debugfile = "/var/log/stabile/steamExec.out";
37
my $localpath;
38
my $localpath2;
39
my $localstatus;
40
my $localstatus2;
41
my $newvirtualsize;
42
my $newbackupsize;
43
my $newvirtualsize2;
44
my $newbackupsize2;
45 8d7785ff Origo
my $uimsg = '';
46 95b003ff Origo
47
my $config = ConfigReader::Simple->new("/etc/stabile/config.cfg",
48
    [qw(RDIFF-BACKUP_ENABLED STORAGE_BACKUPDIR
49
    STORAGE_POOLS_ADDRESS_PATHS STORAGE_POOLS_LOCAL_PATHS
50
    STORAGE_POOLS_NAMES STORAGE_POOLS_DEFAULTS STORAGE_POOLS_RDIFF-BACKUP_ENABLED
51
    RDIFF-BACKUP_USERS DBI_USER DBI_PASSWD ENGINE_LINKED
52
    ENGINE_DATA_NIC)]);
53
54
$base = "/var/www/stabile";
55
$base = `cat /etc/stabile/basedir` if -e "/etc/stabile/basedir";
56
chomp $base;
57
my $logfile = "/var/log/stabile/steam.log";
58
my $dbiuser =  $config->get('DBI_USER') || "irigo";
59
my $dbipasswd = $config->get('DBI_PASSWD') || "";
60
61
my $backupdir = $config->get('STORAGE_BACKUPDIR') || "/mnt/stabile/backups";
62
my $tenders = $config->get('STORAGE_POOLS_ADDRESS_PATHS');
63
my @tenderlist = split(/,\s*/, $tenders);
64
my $tenderpaths = $config->get('STORAGE_POOLS_LOCAL_PATHS') || "/mnt/stabile/images";
65
my @tenderpathslist = split(/,\s*/, $tenderpaths);
66
my $tendernames = $config->get('STORAGE_POOLS_NAMES') || "Standard storage";
67
my @tendernameslist = split(/,\s*/, $tendernames);
68 2a63870a Christian Orellana
my $opentcpports = $config->get('OPEN_TCP_PORTS');
69
my $openudpports = $config->get('OPEN_UDP_PORTS');
70 95b003ff Origo
71
$sshcmd = "ssh -l irigo -i /var/www/.ssh/id_rsa_www -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no";
72
73
$current_time = time;
74
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($current_time);
75
$year += 1900;
76
$month = substr("0" . ($mon+1), -2);
77
$pretty_time = sprintf "%4d-%02d-%02d@%02d:%02d:%02d",$year,$mon+1,$mday,$hour,$min,$sec;
78
79
if (lc($arg1) eq "backupallimages" ) {
80
     debuglog("Backing up all images...");
81
     backupAllImages();
82
} elsif (lc($arg1) eq "backupengine" ) {
83
     if ($config->get('ENGINE_LINKED')) {
84 48fcda6b Origo
         debuglog("Backing up engine configuration...");
85 95b003ff Origo
         print `echo users/backupengine | stash`;
86
     } else {
87
         print "Engine not linked. Not backing up configuration.\n";
88
     }
89
} elsif (lc($arg1) eq "billengine" ) {
90
#     debuglog("Updating billing data on origo.io...");
91
     print `echo users/billengine | stash`;
92
} elsif (lc($arg1) eq "updatenetworkbilling" ) {
93
#     debuglog("Updating billing for all networks...");
94
     updateBillingAllNetworks();
95
} elsif (lc($arg1) eq "updateimagebilling" ) {
96
#     debuglog("Updating billing for all images...");
97
     updateBillingAllImages();
98
99
} elsif (lc($arg1) eq "updatedownloads" ) {
100 a439a9c4 hq
    print `REMOTE_USER=irigo $base/cgi/images.cgi -a gear_updatedownloads`;
101 95b003ff Origo
102
} elsif (lc($arg1) eq "releaseolddhcpleases" ) {
103
    releaseOldDhcpLeases();
104 64c667ea hq
} elsif (lc($arg1) eq "refreshimages" ) {
105
    print `REMOTE_USER=irigo $base/cgi/images.cgi -a updateregister -f`;
106 95b003ff Origo
} elsif (lc($arg1) eq "updateimagestatus" ) {
107
    # Incoming params: $status $oldstatus $path1 $path2
108
    # Function params: $localpath, $localstatus, $newvirtualsize, $newbackupsize
109
    updateImageStatus($status, $oldstatus, $path1, $path2);
110
} elsif (lc($arg1) eq "updatebackingfile" ) {
111
    # Incoming params: $status $oldstatus $path1 $path2
112
    # Function params: $localpath, $localstatus, $newvirtualsize, $newbackupsize
113
    updateBackingFile($status);
114
} elsif (lc($arg1) eq "unmountallimages" ) {
115
    debuglog("Unmounting all images...");
116
    print "Unmounting all images - hang on...\n";
117
    unmountAllImages();
118 2a63870a Christian Orellana
} elsif (lc($arg1) eq "backupallfuel" ) {
119
    debuglog("Backup up fuel for all users...");
120
    print "Backup up fuel for all users, hang on...\n";
121
    backupAllFuel();
122 95b003ff Origo
} elsif (lc($arg1) eq "post-wake") {
123
    debuglog("Running post-wake routines...");
124
    print `REMOTE_USER=irigo $base/cgi/networks.cgi -a gear_restoreall`;
125
} elsif (lc($arg1) eq "post-boot") {
126 2a63870a Christian Orellana
    my $baseip;
127
    if ($opentcpports || $openudpports) {
128
        my $basedom = `awk -F'[/:]' '/https:/{print \$4}' /etc/stabile/baseurl`;
129
        chomp $basedom;
130 71b897d3 hq
        if ($basedom =~ /\d+\.\d+\.\d+\.\d+/) {
131
            $baseip = $basedom;
132
        } else {
133 64c667ea hq
            $baseip = `dig +short \@1.1.1.1 $basedom | tail -n1`;
134
        #    $baseip = `dig +short $basedom | tail -n1`;
135 71b897d3 hq
            chomp $baseip;
136
        }
137 2a63870a Christian Orellana
        $baseip = '' if ($baseip =~ /^127/);
138 64c667ea hq
        print "Hardening access to $baseip\n";
139 2a63870a Christian Orellana
    }
140
    if (($opentcpports || $openudpports) && $baseip) {
141
        print `iptables -D INPUT -p icmp --icmp-type 8 -s 0/0 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT 2>/dev/null`;
142
        print `iptables -I INPUT -p icmp --icmp-type 8 -s 0/0 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT`;
143
        print `iptables -D OUTPUT -p icmp --icmp-type 0 -d 0/0 -m state --state ESTABLISHED,RELATED -j ACCEPT 2>/dev/null`;
144
        print `iptables -I OUTPUT -p icmp --icmp-type 0 -d 0/0 -m state --state ESTABLISHED,RELATED -j ACCEPT`;
145
        print `iptables -D INPUT -m conntrack -j ACCEPT --ctstate RELATED,ESTABLISHED 2>/dev/null`;
146
        print `iptables -I INPUT -m conntrack -j ACCEPT --ctstate RELATED,ESTABLISHED`;
147
        print `iptables -D INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 2>/dev/null`;
148
        print `iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT`;
149 64c667ea hq
150
        print `iptables -D INPUT -s 10.0.0.1 -j ACCEPT 2>/dev/null`;
151
        print `iptables -I INPUT -s 10.0.0.1 -j ACCEPT`;
152
        print `iptables -D INPUT -s 127.0.0.1 -j ACCEPT 2>/dev/null`;
153
        print `iptables -I INPUT -s 127.0.0.1 -j ACCEPT`;
154
155
#        print `iptables -D INPUT -d $baseip -j DROP 2>/dev/null`;
156
#        print `iptables -A INPUT -d $baseip -j DROP`;
157
158
        print `iptables -D INPUT -j DROP 2>/dev/null`;
159
        print `iptables -A INPUT -j DROP`;
160 2a63870a Christian Orellana
    }
161
    if ($opentcpports && $baseip) {
162
        print "Allowing incoming TCP traffic to $baseip for ports $opentcpports\n";
163
        my $ports = join(",",split(/, ?/, $opentcpports));
164
        print `iptables -D INPUT -p tcp -m tcp -m multiport --dports $ports -j ACCEPT 2>/dev/null`;
165
        print `iptables -I INPUT -p tcp -m tcp -m multiport --dports $ports -j ACCEPT`;
166
    }
167
    if ($openudpports && $baseip) {
168
        print "Allowing incoming UDP traffic to $baseip for ports $openudpports\n";
169
        my $ports = join(",",split(/, ?/, $openudpports));
170 ca937547 hq
        print `iptables -D INPUT -p udp -m udp -m multiport --dports $ports -j ACCEPT 2>/dev/null`;
171
        print `iptables -I INPUT -p udp -m udp -m multiport --dports $ports -j ACCEPT`;
172 2a63870a Christian Orellana
    }
173 95b003ff Origo
    if (`pgrep pressurecontrol`) {
174
        debuglog("Running post-boot routines...");
175 a439a9c4 hq
        print `REMOTE_USER=irigo $base/cgi/networks.cgi -a gear_restoreall`;
176
        print `REMOTE_USER=irigo $base/cgi/servers.cgi -a gear_autostartall`;
177
        print `REMOTE_USER=irigo $base/cgi/images.cgi -a gear_updatedownloads`;
178 95b003ff Origo
    } else {
179
        debuglog("Not running post-boot routines...");
180
    }
181
} elsif (lc($arg1) eq "pre-shutdown") {
182 2a63870a Christian Orellana
    debuglog("Running pre-shutdown routines...");
183 95b003ff Origo
    unmountAllImages();
184 2a63870a Christian Orellana
    debuglog("Halting nodes...");
185
    `echo "nodes/haltall" | /usr/local/bin/stash`;
186 95b003ff Origo
    #updateBillingAllNetworks();
187
} elsif (lc($arg1) eq "daily") {
188
    debuglog("Running daily maintenance routine...");
189
    backupAllImages();
190
    updateBillingAllNetworks();
191
    unmountAllImages();
192
} elsif (lc($arg1) eq "restoreallnetworks" ) {
193
    debuglog("Restoring all networks...");
194
    print "Restoring all networks - hang on...\n";
195
    print `REMOTE_USER=irigo $base/cgi/networks.cgi -a gear_restoreall`;
196
} elsif (lc($arg1) eq "showautostart" ) {
197
    print "Showing autostart servers - hang on...\n";
198
    print `REMOTE_USER=irigo $base/cgi/servers.cgi -a showautostart`;
199
} elsif (lc($arg1) eq "autostartservers" ) {
200
    debuglog("Autostarting servers...");
201
    print "Autostarting servers - hang on...\n";
202
    print `REMOTE_USER=irigo $base/cgi/servers.cgi -a autostartall`;
203
} elsif (lc($arg1) eq "resetmonitoring" ) {
204
    debuglog("Resetting monitoring...");
205
    print "Resetting monitoring - hang on...\n";
206
    print `REMOTE_USER=irigo $base/cgi/systems.cgi -a resetmonitoring`;
207
} elsif ($arg1 && $status && $path1) {
208
    debuglog("$arg1 : $status : $oldstatus : $path1 : $path2 : $cmd1 : $cmd2");
209
    if ($status eq "snapshotting") {
210
        # $res .= `/bin/echo "$status" > "$path1.meta"`;
211
        my $macip;
212
        $localpath = $path1;
213
        if ($localpath =~ m/(\d+\.\d+\.\d+\.\d+)\:(\/.+)/) {
214
            $macip = $1;
215
            $localpath = $2;
216
            my $esc_localpath = shell_esc_chars($localpath);
217
            $res .= `$sshcmd $macip "sudo /usr/bin/qemu-img snapshot -c snap1 $esc_localpath"`;
218
        } else {
219
            $res .= `/usr/bin/qemu-img snapshot -c snap1 "$path1"`;
220
        }
221
        $dsnap1 = $path2;
222
        $localstatus = $oldstatus;
223
    } elsif ($status eq "unsnapping") {
224
        my $macip;
225
        $localpath = $path1;
226
        if ($localpath =~ m/(\d+\.\d+\.\d+\.\d+)\:(\/.+)/) {
227
            $macip = $1;
228
            $localpath = $2;
229
            my $esc_localpath = shell_esc_chars($localpath);
230
            $res .= `$sshcmd $macip "sudo /usr/bin/qemu-img snapshot -d snap1 $esc_localpath"`;
231
        } else {
232
            $res .= `/usr/bin/qemu-img snapshot -d snap1 "$path1"`;
233
        }
234
        $dsnap1 = "--";
235
        $localstatus = $oldstatus;
236
    } elsif ($status eq "reverting") {
237
        my $macip;
238
        $localpath = $path1;
239
        if ($localpath =~ m/(\d+\.\d+\.\d+\.\d+)\:(\/.+)/) {
240
            $macip = $1;
241
            $localpath = $2;
242
            my $esc_localpath = shell_esc_chars($localpath);
243
            $res .= `$sshcmd $macip "sudo /usr/bin/qemu-img snapshot -a snap1 $esc_localpath"`;
244
        } else {
245
            $res .= `/usr/bin/qemu-img snapshot -a snap1 "$path1"`;
246
        }
247
        $localstatus = $oldstatus;
248
    } elsif ($status eq "injecting") {
249
        $localpath = $path1;
250
        $localpath2 = $path2;
251
        my $esc_localpath = shell_esc_chars($localpath);
252
253
        # Find out if we are dealing with a Windows image
254
        my $xml = `bash -c '/usr/bin/virt-inspector -a "$esc_localpath"'`;
255
        #my $xml = `bash -c '/usr/bin/virt-inspector -a "$esc_localpath"' 2>&1`;
256
        # $res .= $xml . "\n";
257
        my $xmlref;
258
        my $osname;
259
        $xmlref = XMLin($xml) if ($xml =~ /^<\?xml/);
260
        $osname = $xmlref->{operatingsystem}->{name} if ($xmlref);
261
        if ($xmlref && $osname eq 'windows') {
262
            $res .= "We are dealing with a Windows image - trying to fix registry\n";
263
            my $upath = $esc_localpath;
264
            # We need write privileges
265
            $res .= `chmod 666 "$upath"`;
266
            # First try to merge storage registry keys into Windows registry. If not a windows vm it simply fails.
267
            $res .= `bash -c 'cat /usr/share/stabile/mergeide.reg | /usr/bin/virt-win-reg --merge "$upath"' 2>&1`;
268
            # Then try to merge the critical device keys. This has been removed in win8 and 2012, so will simply fail for these.
269
            $res .= `bash -c 'cat /usr/share/stabile/mergeide-CDDB.reg | /usr/bin/virt-win-reg --merge "$upath"' 2>&1`;
270
            if ($res) { debuglog($res); $res = ''; }
271
272
            # Try to copy viostor.sys into image
273
            my @winpaths = (
274
                '/Windows/System32/drivers',
275
                '/WINDOWS/system32/drivers/viostor.sys',
276
                '/WINDOWS/System32/drivers/viostor.sys',
277
                '/WINNT/system32/drivers/viostor.sys'
278
            );
279
            foreach my $winpath (@winpaths) {
280
                $res .= "Trying $winpath\n";
281
                my $lscmd = qq|bash -c 'virt-ls -a "$upath" "$winpath"'|;
282
                debuglog("$res"); $res = '';
283
                my $drivers = `$lscmd`;
284
                if ($drivers =~ /viostor/i) {
285
                    $res .= "OK: viostor already installed in $winpath in $upath\n";
286
                    debuglog($res); $res = '';
287
                    syslogit('info', "viostor already installed in $winpath in $upath");
288
                    last;
289
                } elsif ($drivers) {
290
                    my $cmd = qq|bash -c 'guestfish -i -a "$upath" upload /usr/share/stabile/VIOSTOR.SYS $winpath/viostor.sys' 2>&1|;
291
                    my $error = `$cmd`;
292
                    if ($error) {
293
                        $res .= "Error injecting virtio drivers into $upath: $error\n";
294
                        debuglog($res); $res = '';
295
                        syslogit('info', "Error injecting virtio drivers into $upath: $error");
296
                    } else {
297
                        $res .= "Injected virtio drivers into $upath";
298
                        debuglog($res); $res = '';
299
                        syslogit('info', "Injected virtio drivers into $upath");
300
                    }
301
                    last;
302
                } else {
303
                    $res .= "No drivers found in $winpath\n";
304
                    debuglog($res); $res = '';
305
                }
306
            }
307
308
        } else {
309
            $res .= "No Windows OS found ($osname) in image, not injecting drivers: $esc_localpath\n";
310
            syslogit('info', "No Windows OS found ($osname) in image, not injecting drivers: $esc_localpath");
311
        }
312
        $localstatus = $oldstatus;
313
    } elsif ($status eq "converting") {
314
        $localpath = $path1;
315
        $localpath2 = $path2;
316
        my $esc_localpath2 = shell_esc_chars($localpath2);
317
        my $upath = $esc_localpath2;
318
319
        my $macip;
320
        if ($localpath =~ m/(\d+\.\d+\.\d+\.\d+)\:(\/.+)/) {
321
            $macip = $1;
322
            $localpath = $2;
323
            my $esc_localpath = shell_esc_chars($localpath);
324
            my $esc_localpath2 = shell_esc_chars($localpath2);
325
            $res .= `$sshcmd $macip "/usr/bin/qemu-img convert $esc_localpath -O qcow2 $esc_localpath2"`;
326
        } else {
327
            my $mpath;
328
            if (substr($path1,-5) eq '.vmdk' && ( -s (substr($path1,0,-5) . "-flat.vmdk") ) ) {
329
                my $pathname = substr($path1,0,-5);
330 2a63870a Christian Orellana
                $mpath = "\"$pathname-flat.vmdk\" ";
331
            # } elsif (substr($path1,-5) eq '.vmdk' && ( -s (substr($path1,0,-5) . "-s001.vmdk")) ) {
332
            #     my $pathname = substr($path1,0,-5);
333
            #     my $i = 1;
334
            #     my $num = '001';
335
            #     while (-e "$pathname-s$num.vmdk") {
336
            #         $mpath .= "\"$pathname-s$num.vmdk\" ";
337
            #         $i++;
338
            #     	$num = substr("00$i", -3);
339
            #     }
340 95b003ff Origo
            } else {
341
                $mpath = "\"$path1\"";
342
            }
343
344
            $res .= qq|Firing /usr/bin/qemu-img convert $mpath -O qcow2 "$path2"\n|;
345
            $res .= `/usr/bin/qemu-img convert $mpath -O qcow2 "$path2"`;
346
347
            # Setting real UID: $< to UID: $>
348
            # $< = $>;
349
350
            # Find out if we are dealing with a Windows image
351
            my $xml = `bash -c '/usr/bin/virt-inspector -a "$esc_localpath2"'`;
352
            # my $xml = `bash -c '/usr/bin/virt-inspector -a "$esc_localpath2"' 2>&1`;
353
            # $res .= $xml . "\n";
354
            my $xmlref;
355
            my $osname;
356
            $xmlref = XMLin($xml) if ($xml =~ /^<\?xml/);
357
            $osname = $xmlref->{operatingsystem}->{name} if ($xmlref);
358
            if ($xmlref && $osname eq 'windows') {
359
                $res .= "We are converting a Windows image - trying to fix registry\n";
360
                # We need write privileges
361
                $res .= `chmod 666 "$upath"`;
362
                # First try to merge storage registry keys into Windows registry. If not a windows vm it simply fails.
363
                $res .= `bash -c 'cat /usr/share/stabile/mergeide.reg | /usr/bin/virt-win-reg --merge "$upath"' 2>&1`;
364
                # Then try to merge the critical device keys. This has been removed in win8 and 2012, so will simply fail for these.
365
                $res .= `bash -c 'cat /usr/share/stabile/mergeide-CDDB.reg | /usr/bin/virt-win-reg --merge "$upath"' 2>&1`;
366
                if ($res) { debuglog($res); $res = ''; }
367
368
                # Try to copy viostor.sys into image
369
                my @winpaths = (
370
                    '/Windows/System32/drivers/viostor.sys',
371
                    '/WINDOWS/system32/drivers/viostor.sys',
372
                    '/WINDOWS/System32/drivers/viostor.sys',
373
                    '/WINNT/system32/drivers/viostor.sys'
374
                );
375
                foreach my $winpath (@winpaths) {
376
                    $res .= "Trying $winpath\n";
377
                    my $lscmd = qq|bash -c 'virt-ls -a "$upath" "$winpath"'|;
378
                    debuglog("$res"); $res = '';
379
                    my $drivers = `$lscmd`;
380
                    if ($drivers =~ /viostor/i) {
381
                        $res .= "OK: viostor already installed in $winpath in $upath\n";
382
                        debuglog($res); $res = '';
383
                        syslogit('info', "viostor already installed in $winpath in $upath");
384
                        last;
385
                    } elsif ($drivers) {
386
                        my $cmd = qq|bash -c 'guestfish -i -a "$upath" upload /usr/share/stabile/VIOSTOR.SYS $winpath/viostor.sys' 2>&1|;
387
                        my $error = `$cmd`;
388
                        if ($error) {
389
                            $res .= "Error injecting virtio drivers into $upath: $error\n";
390
                            debuglog($res); $res = '';
391
                            syslogit('info', "Error injecting virtio drivers into $upath: $error");
392
                        } else {
393
                            $res .= "Injected virtio drivers into $upath";
394
                            debuglog($res); $res = '';
395
                            syslogit('info', "Injected virtio drivers into $upath");
396
                        }
397
                        last;
398
                    } else {
399
                        $res .= "No drivers found in $winpath\n";
400
                        debuglog($res); $res = '';
401
                    }
402
                }
403
404
            } else {
405
                $res .= "No Windows OS found ($osname) in converted image, not injecting drivers: $esc_localpath2\n";
406
                syslogit('info', "No Windows OS found ($osname) in image, not injecting drivers: $esc_localpath2");
407
            }
408
409
            if (-e "$path2") {
410
                syslogit('info', "Converted image to: $path2");
411
            } else {
412
                syslogit('info', "Unable to convert image to: $path2");
413
            }
414
        }
415
        $localstatus = $oldstatus;
416
        $localstatus2 = "unused";
417
    } elsif ($status eq "rebasing") {
418
        $localpath = $path1;
419
        $localpath2 = $path2;
420
        my $macip;
421
        if ($localpath =~ m/(\d+\.\d+\.\d+\.\d+)\:(\/.+)/) {
422
            $macip = $1;
423
            $localpath = $2;
424
            my $esc_localpath = shell_esc_chars($localpath);
425
            my $esc_localpath2 = shell_esc_chars($localpath2);
426
            $res .= `$sshcmd $macip "/usr/bin/qemu-img convert $esc_localpath -O qcow2 $esc_localpath2"`;
427
            $res .= `$sshcmd $macip "if [ -f $esc_localpath2 ]; then /bin/mv -v $esc_localpath2 $esc_localpath; fi"`;
428
        } else {
429
            $res .= `/usr/bin/qemu-img convert -O qcow2 "$path1" "$path2"`;
430
            $res .= `if [ -f "$path2" ]; then /bin/mv -v "$path2" "$path1"; fi`;
431
        }
432
        $localstatus = $oldstatus;
433
434
        # Release master image if not used by other images
435
        unless (tie %imagereg,'Tie::DBI', {
436
            db=>'mysql:steamregister',
437
            table=>'images',
438
            key=>'path',
439
            autocommit=>0,
440
            CLOBBER=>3,
441
            user=>$dbiuser,
442
            password=>$dbipasswd}) {syslogit('info', "Image register could not be accessed")};
443
444
        my $master = ($imagereg{$path1}->{'master'} && $imagereg{$path1}->{'master'} ne '--')?$imagereg{$path1}->{'master'}:'';
445
        my $usedmaster = '';
446
        my @regvalues = values %imagereg;
447
        if ($master) {
448
            foreach my $valref (@regvalues) {
449
                $usedmaster = 1 if ($valref->{'master'} eq $master && $valref->{'path'} ne $path1); # Check if another image is also using this master
450
            }
451
        }
452
        if ($master && !$usedmaster) {
453
            $imagereg{$master}->{'status'} = 'unused';
454
        }
455
        $imagereg{$path1}->{'master'} = '';
456
        syslogit->('info', "Freeing master $master");
457
        untie %imagereg;
458
459
    } elsif ($status eq "cloning" || $status eq "copying" || $status eq "vcloning" || $status eq "bcloning") {
460
        $localpath = $path1;
461
        $localpath2 = $path2;
462
        my $macip;
463
        if ($localpath =~ m/(\d+\.\d+\.\d+\.\d+)\:(\/.+)/) { # Target is on a node
464
            $macip = $1;
465
            $localpath = $2;
466
            my $esc_localpath = shell_esc_chars($localpath);
467
            my $esc_localpath2 = shell_esc_chars($localpath2);
468
469
            $esc_localpath =~ /(.+)\/.*/;
470
            my $sdir = $1;
471
            $esc_localpath2 =~ /(.+)\/.*/;
472
            my $dir = $1;
473
474
        # Creating target directory in case it doesn't exist
475
            `$sshcmd $macip /bin/mkdir -p "$dir"`;
476
477
        # Mounting remote share on node in case it isn't
478
            for (my $i=0; $i<=$#tenderpathslist; $i++
479
                )
480
            {
481
                my $path = $tenderpathslist[$i];
482
                my $host = $tenderlist[$i];
483
                $host = "10.0.0.1:$path" if ($host eq 'local');
484
                if ($sdir =~ /$path\//) {
485
                    my $cmd = qq/$sshcmd $macip "mountpoint -q $path || sudo mount -o intr,noatime,nfsvers=3 $host $path"/;
486
                    $res .= `$cmd`;
487
                    last;
488
                }
489
            }
490
491
            if ($status eq "cloning" || $status eq "bcloning") {
492
                my $cmd = qq|$sshcmd $macip "/usr/bin/qemu-img create -f qcow2 -b $esc_localpath $esc_localpath2 2>\&1"|;
493
                $res .= "$cmd\n";
494
                $res .= `$cmd`;
495
            } elsif ($status eq "copying") {
496
#                $res .= `ssh -l irigo -i /var/www/.ssh/id_rsa_www $macip "/usr/bin/rsync -uv --inplace $esc_localpath $esc_localpath2"`;
497
                $res .= `$sshcmd $macip "/bin/cp -vn $esc_localpath $esc_localpath2"`;
498
            } elsif ($status eq "vcloning") {
499
                $res .= `$sshcmd $macip "/usr/bin/VBoxManage clonehd $esc_localpath $esc_localpath2"`;
500
                $res .= `$sshcmd $macip "/bin/chmod 666 $esc_localpath2"`;
501
            }
502
        } else {
503
            $path2 =~ /(.+)\/.*/;
504
            my $dir = $1;
505
            `/bin/mkdir "$dir"` unless -e $dir;
506
            if ($status eq "cloning" || $status eq "bcloning") {
507
                $res .= `/usr/bin/qemu-img create -f qcow2 -b "$path1" "$path2" 2>\&1`;
508
                debuglog($res) if ($res);
509
            } elsif ($status eq "copying") {
510
#                $res .= `/usr/bin/ionice -c3 /usr/bin/rsync -uv --inplace "$path1" "$path2"`;
511
                $res .= `/usr/bin/ionice -c3 /bin/cp -vn "$path1" "$path2"`;
512
            } elsif ($status eq "vcloning") {
513
                $res .= `/usr/bin/ionice -c3 /usr/bin/VBoxManage clonehd "$path1" "$path2"`;
514
                $res .= `/bin/chmod 666 "$path2"`;
515
            }
516
        }
517
        $newvirtualsize2 = getVirtualSize($path2, $macip); # report size of new image for billing purposes
518
        $localstatus = ($status eq "bcloning" || $status eq "cloning")?"used": $oldstatus;
519
        $localstatus2 = ($status eq "bcloning")?"unused":"unused"; # bcloning = building a system
520
521
    } elsif ($status eq "urluploading") {
522
        $localpath = $path1;
523
        $imageurl = $path2;
524
#        $res .= `/bin/dd if=/dev/zero of="$localpath"  bs=1M  count=2; /bin/rm -f "$localpath.meta"`;
525
        $res .= `/usr/bin/wget --no-check-certificate -O "$localpath" "$imageurl"; /bin/rm -f "$localpath.meta"`;
526
527 3657de20 Origo
        my $qinfo = `/usr/bin/qemu-img info --force-share "$localpath"`;
528 95b003ff Origo
        $qinfo =~ /virtual size:.*\((.+) bytes\)/g;
529
        $newvirtualsize = int($1);
530
        unless ($newvirtualsize) {
531
            my @stat = stat($localpath);
532
            $newvirtualsize = $stat[7];
533
        }
534
        $localstatus = $oldstatus;
535
    } elsif ($status eq "qcreating") {
536
        $status = "creating";
537
        $localpath = $path1;
538
        # $path2 contains the size in k
539
        my $size = ($path2 / 1024)."M";
540
        my $format = "qcow2";
541
        $format = "vmdk" if ($path1 =~ /\.vmdk$/);
542
        $res .= `/usr/bin/qemu-img create -f $format "$path1" "$size"`;
543
		if(($? >> 8) != 0) { # Report if there was an error creating the image.
544
			syslogit('err', "An error was reported creating the qcow2/raw image.");
545
		}
546
		$res .= `/bin/chmod 666 "$path1"`;
547
		$res .= "$size";
548
		$newvirtualsize = $path2 * 1024;
549
		$localstatus = "unused";
550
    } elsif ($status eq "icreating") {
551
        $status = "creating";
552
        $localpath = $path1;
553
        # $path2 contains the size in k
554
        my $size = ($path2 / 1024)."M";
555
        $res .= `/usr/bin/qemu-img create -f raw "$path1" "$size"`;
556
		$res .= `/bin/chmod 666 "$path1"`;
557
		$newvirtualsize = $path2 * 1024;
558
		$localstatus = "unused";
559
    } elsif ($status eq "vcreating") {
560
        $status = "creating";
561
        $localpath = $path1;
562
        # $path2 contains the size in k
563
        $res .= `/usr/bin/VBoxManage createhd --filename "$path1" --size "$path2" --format VDI`;
564
		$res .= `/bin/chmod 666 "$path1"`;
565
		$newvirtualsize = $path2 * 1024;
566
		$localstatus = "unused";
567
    } elsif ($status eq "resizing") {
568
        $localpath = $path1;
569
        # $path2 contains the size in k
570
        my $size = int($path2 / 1024)."M";
571
        my $macip;
572
        if ($localpath =~ m/(\d+\.\d+\.\d+\.\d+)\:(\/.+)/) { # We are dealing with an image on a node
573
            $macip = $1;
574
            $localpath = $2;
575
            my $esc_localpath = shell_esc_chars($localpath);
576
            my $cmd = qq|$sshcmd $macip "sudo /usr/bin/qemu-img resize $esc_localpath $size" 2>&1|;
577
            $res .= "COMMAND: $cmd\n";
578
            $res .= `$cmd`;
579
        } else {
580
            $res .= `/usr/bin/qemu-img resize "$path1" "$size"`;
581
        }
582
        $newvirtualsize = $path2 * 1024;
583
        $localstatus = $oldstatus;
584
    } elsif ($status eq "moving") {
585
    # On node
586
        if ($path2 =~ m/(\d+\.\d+\.\d+\.\d+)\:(\/.+)/ && $path1 =~ m/(\d+\.\d+\.\d+\.\d+)\:(\/.+)/) {
587
            my $macip = $1;
588
            $localpath = $2;
589
            $path2 =~ m/(\d+\.\d+\.\d+\.\d+)\:(\/.+)/;
590
            $localpath2 = $2;
591
592
            my $esc_path1 = shell_esc_chars($path1);
593
            my $esc_path2 = shell_esc_chars($path2);
594
            my $esc_localpath = shell_esc_chars($localpath);
595
            my $esc_localpath2 = shell_esc_chars($localpath2);
596
597
            $newvirtualsize = getVirtualSize($esc_localpath, $macip);
598
            $newvirtualsize2 = 0;
599
600
            $localpath2 =~ /(.+)\/.+/;
601
            my $localdir2 = $1;
602
            $res .= qq[Moving: $sshcmd $macip /bin/mv -n "$localpath" "$localpath2"\n];
603
            $res .= `$sshcmd $macip /bin/mv -n "$localpath" "$localpath2"`;
604
605
            $localstatus2 = $oldstatus;
606
            $localstatus = "";
607
608
    # To node
609
        } elsif ($path2 =~ m/(\d+\.\d+\.\d+\.\d+)\:(\/.+)/) {
610
        # Update billing
611
            $newvirtualsize = getVirtualSize($path1);
612
            $newvirtualsize2 = 0;
613
            my $macip = $1;
614
            $localpath = $2;
615
            $localpath2 = $path1;
616 48fcda6b Origo
        #    my $md5sum;
617
        #    my $md5sum2;
618 95b003ff Origo
619
            my $esc_path1 = shell_esc_chars($path1);
620
            my $esc_localpath = shell_esc_chars($localpath);
621
            my $esc_path2 = "$macip:$esc_localpath";
622
623
            $res .= qq[Moving: /usr/bin/rsync -vW --sparse -e "$sshcmd" $esc_path1 "$esc_path2"\n];
624 48fcda6b Origo
        #    $md5sum = (split(" ", `/usr/bin/md5sum "$path1"`))[0];
625
        #    $res .= "MD5: $md5sum\n";
626 3657de20 Origo
            my $mvres = system(qq|/usr/bin/rsync -vW --sparse -e "$sshcmd" $esc_path1 "$esc_path2"|);
627
            my $chres .= `$sshcmd $macip "/bin/chmod 666 $esc_localpath"`;
628 48fcda6b Origo
        #    $md5sum2 = (split(" ", `$sshcmd $macip "/usr/bin/md5sum -b $esc_localpath"`))[0];
629
        #    $res .= "MD5: $md5sum2\n";
630
        #    if ($md5sum && ($md5sum eq $md5sum2)) {
631 3657de20 Origo
            unless ($mvres || $chres) { # Sanity check
632
                $localstatus = $oldstatus;
633
                $localstatus2 = "unused";
634 95b003ff Origo
                unlink $path1;
635 48fcda6b Origo
                $localstatus2 = "removed"; # The image being left behind is removed from db after moving to new location
636 3657de20 Origo
            }
637 95b003ff Origo
    # From node
638
        } elsif ($path1 =~ m/(\d+\.\d+\.\d+\.\d+)\:(\/.+)/) {
639
            my $macip = $1;
640
            $localpath2 = $2;
641
            $localpath = $path2;
642 48fcda6b Origo
        #    my $md5sum;
643
        #    my $md5sum2;
644 95b003ff Origo
            my $esc_localpath = shell_esc_chars($localpath);
645
            my $esc_localpath2 = shell_esc_chars($localpath2);
646
            my $esc_path1 = "$macip:$esc_localpath2";
647
            my $esc_path2 = shell_esc_chars($path2);
648 48fcda6b Origo
        #    $md5sum = (split(" ", `$sshcmd $macip "/usr/bin/md5sum -b $esc_localpath2"`))[0];
649
        #    $res .= "MD5: $md5sum\n";
650 3657de20 Origo
            my $mvres = system(qq|/usr/bin/rsync -vW --sparse -e "$sshcmd" "$esc_path1" $esc_path2|);
651 48fcda6b Origo
        #    $md5sum2 = (split(" ", `/usr/bin/md5sum "$path2"`))[0];
652
        #    $res .= "MD5: $md5sum2\n";
653
        #    if ($md5sum && ($md5sum eq $md5sum2)) {
654 3657de20 Origo
            unless ($mvres) { # Sanity check
655
                $localstatus = $oldstatus;
656
                $localstatus2 = "unused";
657 95b003ff Origo
                `$sshcmd $macip "/usr/bin/unlink $esc_localpath2"`;
658 48fcda6b Origo
                $localstatus2 = "removed"; # The image being left behind is removed from db after moving to new location
659 3657de20 Origo
            }
660 95b003ff Origo
        # Update billing
661
            $newvirtualsize = getVirtualSize($path2);
662
            $newvirtualsize2 = 0;
663
        } else {
664
            $localpath = $path2;
665
            $localpath2 = $path1;
666
            $res .= `/bin/mv -v "$path1" "$path2"`;
667
            $res .= `/bin/mv -v "$path1.meta" "$path2.meta"` if (-e "$path1.meta");
668 3657de20 Origo
            $localstatus2 = "removed";
669 95b003ff Origo
            $localstatus = $oldstatus;
670
        # Update billing
671
            $newvirtualsize = getVirtualSize($path2);
672
            $newvirtualsize2 = 0;
673
        }
674
    } elsif ($status eq "backingup" || $status eq "lbackingup") {
675
        $user = $arg1;
676
        # $path1 is the image to back up (including potential subdir), $path2 the source dir (storage pool) and $cmd1 the target dir (general backup dir)
677
        $localpath = "$path2/$user/$path1";
678
        mkdir "$cmd1/$user" unless -d "$cmd1/$user"; # Create the target dirs which will contain the backup
679
        my $pool = $path2;
680
        my $image = $path1;
681
        my $subdir; # 1 level of subdirs supported
682
        if ($path1 =~ /(.+)\/(.+)/) {
683
            $subdir = $1;
684
            $image = $2;
685
        }
686
        if ($subdir) {
687
            mkdir "$cmd1/$user/$subdir" unless -d "$cmd1/$user/$subdir";
688
            mkdir "$cmd1/$user/$subdir/$image" unless -d "$cmd1/$user/$subdir/$image";
689
        } else {
690
            mkdir "$cmd1/$user/$image" unless -d "$cmd1/$user/$image";
691
        }
692
693
        if (-d "/mnt/$user-$image") {
694
            $res .= "Image is already being backed up";
695
        } else {
696
            my $snapname;
697
            my $snappath;
698
            my $snapsrcdir;
699
            my $lvolgroup;
700
            if ($status eq "lbackingup") { # Do a local lvm snapshot before backing up
701
                `/sbin/modprobe dm-snapshot`; # Make sure we can make lvm snapshots
702
                $snapname = "$user-$image";
703
                $snapname =~ tr/ /-/; #No spaces allowed in snapshot names...
704
                $snapname =~ tr/@/_/; #No funny chars allowed in snapshot names...
705
                $snappath = "/mnt/$snapname"; # The path to mount our snapshot on
706
                mkdir $snappath;
707
708
                my $q = `/bin/cat /proc/mounts | grep "$pool"`; # Find the lvm volume mounted on /mnt/images
709
                ($q =~ m/\/dev\/mapper\/(\S+)-(\S+) $pool.+/g)[-1]; # Select last match
710
                $lvolgroup = $1;
711
                my $lvol = $2;
712
713
                $res .= `/sbin/lvcreate -L1024M -s -n $snapname /dev/$lvolgroup/$lvol`; # Take a snapshot
714
715
                debuglog("$oldstatus $pool /dev/$lvolgroup/$lvol $snapname \"$snappath\"");
716
717
                $res .= changeFstab($snapname, $pool); # Change fstab to allow mount
718
                $res .= `/bin/mount "$snappath" 2>&1`; # Mount the snapshot
719
                $res .= `ls -l $snappath/$user` . "\n";
720
                $snapsrcdir = "$snappath/$user"; # Change source dir to our new snapshot
721
            } else {
722
                $snapsrcdir = "$pool/$user";
723
            }
724
725
            # Do the backup
726
            $res .= `/usr/bin/rdiff-backup --print-statistics --include "$snapsrcdir/$path1" --exclude '**' "$snapsrcdir" "$cmd1/$user/$path1"`;
727
            $res .= `/usr/bin/rdiff-backup --print-statistics --force --remove-older-than $cmd2  "$cmd1/$user/$path1"` if ($cmd2);
728
            `/bin/chown -R irigo:irigo "$cmd1/$user/$path1"`;
729
            # Clean up
730
            if ($status eq "lbackingup") {
731
                $res .= `/bin/umount "$snappath"`;
732
                $res .= changeFstab($snapname, $pool, 1);
733
                $res .= `/bin/rm -r "$snappath"` unless (-d "$snappath/$user"); # Sanity check - don't delete mount dir if snapshot still mounted
734
                debuglog("removing logical volume /dev/$lvolgroup/$snapname");
735
                $res .= `/sbin/lvremove -f /dev/$lvolgroup/$snapname`;
736
            }
737 8d7785ff Origo
738
           if (-d "$cmd1/$user/$path1") { # Report new backup size for billing
739
               if ($subdir) {
740
                   $newbackupsize = getBackupSize("/$subdir", $image, $user);
741
               } else {
742
                   $newbackupsize = getBackupSize('', $image, $user);
743
               }
744
           }
745 95b003ff Origo
        # Update btime
746
            my $buser = $user;
747
            $buser = 'irigo' if ($user eq 'common');
748 2a63870a Christian Orellana
            my $bcmd = "REMOTE_USER=$buser $base/cgi/images.cgi -a updatebtime -i " . uri_escape($localpath);
749 95b003ff Origo
            my $scmd = "/usr/bin/$sshcmd 127.0.0.1";
750
            $res .= "$scmd $bcmd\n";
751
            $res .= `$scmd $bcmd`;
752
            $res .= "Updating btime: for $localpath\n\n";
753 8d7785ff Origo
754
            my $bmes;
755
            if ($status eq "backingup" || $status eq "lbackingup") {
756
                $bmes;
757
                if ($res =~ /TotalDestinationSizeChange (\d)(.+\))/) {
758
                    if ($1 eq "0") {
759
                        $bmes = "No changes to back up";
760
                    } else {
761
                        $bmes = "Backed up $1$2";
762
                        #    $bmes .= " in $1$2" if ($res =~ /ElapsedTime (\d)(.+\))/);
763
                    }
764
                } elsif ($res =~ /(Image is already being backed up)/) {
765
                    $bmes = $1;
766
                } else {
767
                    my $hres = $res;
768
                    $hres =~ s/\n/<br>/g;
769
                    $hres =~ s/\"/\\"/g;
770
                    $bmes = "Backup failed: $hres";
771
                }
772
                $uimsg = $bmes;
773
            }
774
775 95b003ff Origo
        }
776
        $localstatus = $oldstatus;
777
778
    } elsif ($status eq "frestoring") {
779
        $user = $arg1;
780
        my($bname, $dirpath, $suffix) = fileparse($path1, (".vmdk", ".img", ".vhd", ".qcow", ".qcow2", ".vdi", ".iso"));
781
        my $mountpath = "$dirpath.$bname$suffix";
782
        my $mounts = `/bin/cat /proc/mounts`;
783
        my $mmounts = `/bin/df`;
784
        my $mounted = ($mounts =~ /$mountpath/ && $mmounts =~ /$mountpath/);
785
        my $restorepath = "$dirpath$bname.iso";
786
        if (-e $restorepath) {
787
            my $i = 1;
788
            while (-e "$dirpath$bname.$i.iso") {$i++;}
789
            $restorepath = "$dirpath$bname.$i.iso";
790
        }
791
        if ($mounted) {
792
            $res .= "Restoring files to: /tmp/restore/$user/$bname$suffix -> $restorepath\n";
793
            $res .= `/bin/echo $status > "$restorepath.meta"`;
794
795
            `/bin/mkdir -p "/tmp/restore/$user/$bname$suffix"` unless (-e "/tmp/restore/$user/$bname$suffix");
796
            my @files = split(/:/, uri_unescape($path2));
797
            foreach $f (@files) {
798
                if (-e "$mountpath$f" && chdir($mountpath)) {
799
                    $f = substr($f,1) if ($f =~ /^\//);
800
                    eval {`/usr/bin/rsync -aR --sparse "$f" /tmp/restore/$user/$bname$suffix`; 1;}
801
                        or do {$e=1; $res .= "ERROR Problem restoring files $@\n";};
802
                } else {
803
                    $res .= "ERROR $f not found in $mountpath\n";
804
                }
805
            }
806
            if (chdir "/tmp/restore/$user/$bname$suffix") {
807
                eval {$res .= `/usr/bin/genisoimage -o "$restorepath" -iso-level 4 .`; 1;}
808
                    or do {$e=1; $res .= "Stream=ERROR Problem restoring files $@\n";};
809
                $res .= `/bin/rm -rf /tmp/restore/$user/$bname$suffix`;
810
                $res .= "OK Restored files from /tmp/restore/$user/$bname$suffix to $restorepath\n";
811
            } else {
812
                $res .= "ERROR Unable to chdir to /tmp/restore/$user/$bname$suffix\n";
813
            }
814
815
            #$res .= `/bin/fusermount -u "$mountpath"`;
816
            #$res .= `/bin/umount "$mountpath"`;
817
            #my $bcmd = "REMOTE_USER=$user $base/cgi/images.cgi " . $postdata;
818
            #$res .= "Unmounting $path1 " . `$bcmd` . "\n";
819
820
            $localpath = $path1;
821
            $localstatus = $oldstatus;
822
            $localpath2 = $restorepath;
823
            $localstatus2 = "unused";
824
        # Update billing
825
            $newvirtualsize = getVirtualSize($restorepath);
826
            unlink "$restorepath.meta";
827
828
            my $postdata = "-a unmount -i " . uri_escape($path1);
829
            $res .= "Unmounted $path1 " . `REMOTE_USER=$user $base/cgi/images.cgi $postdata`;
830
    #        `/usr/bin/$sshcmd 127.0.0.1 REMOTE_USER=$user $base/cgi/images.cgi $postdata`;
831
        } else {
832
            $res .= "ERROR You must mount image on $mountpath before restoring\n";
833
        }
834
835
    } elsif ($status eq "restoring") {
836
        $user = $arg1;
837
        # $path1 is the image path, $path2 backup dir, $cmd1 the increment, $cmd2 is the restore path
838
        my $subdir; # 1 level of subdirs supported
839
        if ($path1 =~ /\/$user\/(.+\/)/) {
840
            $subdir = $1;
841
        }
842
        my($bname, $dirpath, $suffix) = fileparse($path1, (".vmdk", ".img", ".vhd", ".qcow", ".qcow2", ".vdi", ".iso"));
843
        my $incfile;
844
        my $restorepath = $cmd2;
845
846
        if ($cmd1 eq "mirror") {
847
            my $mir = `/bin/ls "$path2/$user/$subdir$bname$suffix/rdiff-backup-data" | grep current_mirror`;
848
            if ($mir =~ /current_mirror\.(\S+)\.data/) {
849
                $incfile = "$path2/$user/$subdir$bname$suffix/$bname$suffix";
850
            }
851
        } else {
852
            if ($cmd1 =~ /^SNAPSHOT-/) { # Z-restore
853
                $incfile = "$path2/$user/$subdir$bname$suffix";
854
            } else { # Not a Z-restore
855
                $incfile = "$path2/$user/$subdir$bname$suffix/rdiff-backup-data/increments/$bname$suffix.$cmd1.diff.gz";
856
            }
857
        }
858
859
        $res .= `/bin/echo $status > "$restorepath.meta"`;
860
861
        $res .= "Restoring: $incfile -> $restorepath ";
862
        if ($cmd1 eq "mirror" || $cmd1 =~ /^SNAPSHOT-/) {
863
            $res .= `/usr/bin/ionice -c3 /bin/cp -vn "$incfile" "$restorepath"`;
864
        } else {
865
            $res .= `/usr/bin/rdiff-backup "$incfile" "$restorepath"`;
866
        }
867
868
        $localpath = $path1;
869
        $localstatus = $oldstatus;
870
        $localpath2 = $restorepath;
871
        $localstatus2 = 'unused';
872
        $res .= `/bin/rm -f "$restorepath.meta"`;
873
    # Update billing
874
        $newvirtualsize = getVirtualSize($restorepath);
875
        unlink "$restorepath.meta";
876
    } else {
877
        debuglog("$arg1 : $status : $oldstatus : $path1 : $path2 : $cmd1 : $cmd2 : $res");
878
        print "No action $status\n";
879
    }
880
881
    sleep 1;
882 48fcda6b Origo
    if ($localpath) {
883
        debuglog("done: $arg1 : $localstatus : $localpath");
884
        updateImageStatus($localpath, $localstatus, $newvirtualsize, $newbackupsize);
885
    }
886
    if ($localpath2) {
887
        debuglog("done2: $arg1 : $localstatus2 : $localpath2");
888
        updateImageStatus($localpath2, $localstatus2, $newvirtualsize2, $newbackupsize2);
889
    }
890 95b003ff Origo
891 48fcda6b Origo
#    updateClientUI($arg1, $localpath, $localstatus, $dsnap1);
892 8d7785ff Origo
    my $updateobj = {user=>$arg1, tab=>"images", path=>$localpath, status=>$localstatus, snap1=>$dsnap1, type=>"update"};
893
    $updateobj->{'message'} = $uimsg if ($uimsg);
894
    my $uires = $main::updateUI->($updateobj);
895 95b003ff Origo
#    debuglog("Updating UI with user=>$arg1 path=>$localpath, status=>$localstatus, $uires");
896
897
    if ($localpath2 && ($status =~ /cloning|copying|converting|moving|restoring/)) {
898
#        updateClientUI($arg1, $localpath2, $localstatus2);
899
        $uires = $main::updateUI->({user=>$arg1, tab=>"images", path=>$localpath2, status=>$localstatus, type=>"update"});
900 48fcda6b Origo
#        debuglog("Updating UI with user=>$arg1 path=>$localpath2, status=>$localstatus2, $uires");
901 95b003ff Origo
    }
902
903
    print $res if ($res);
904
    debuglog($res) if ($res);
905
} else {
906
    print "No valid input...\n";
907
}
908
909
exit 0;
910
911
sub updateClientUI {
912 48fcda6b Origo
    return; # obsolete
913 95b003ff Origo
    my ($username, $dpath, $dstatus, $snap1) = @_;
914
    if ($username) {
915
916
        unless (tie %imagereg,'Tie::DBI', {
917
            db=>'mysql:steamregister',
918
            table=>'images',
919
            key=>'path',
920
            autocommit=>0,
921
            CLOBBER=>3,
922
            user=>$dbiuser,
923
            password=>$dbipasswd}) {syslogit('info', "Image register could not be accessed")};
924
925
        my $duuid;
926
        my $dname;
927
        if ($dpath && $imagereg{$dpath}) {
928
            $duuid = $imagereg{$dpath}->{'uuid'} ;
929
            $dname = $imagereg{$dpath}->{'name'};
930
        }
931
        untie %imagereg;
932
        #$duuid = $dpath unless ($duuid);
933
        #$duuid = 'none' unless ($duuid);
934
935
        my $bmes;
936
        if ($status eq "backingup" || $status eq "lbackingup") {
937
            $bmes;
938
            if ($res =~ /TotalDestinationSizeChange (\d)(.+\))/) {
939
                if ($1 eq "0") {
940
                    $bmes = "No changes to back up ($dname)";
941
                } else {
942
                    $bmes = "Backed up $1$2";
943
                #    $bmes .= " in $1$2" if ($res =~ /ElapsedTime (\d)(.+\))/);
944
                }
945
            } elsif ($res =~ /(Image is already being backed up)/) {
946
                $bmes = $1;
947
            } else {
948
                my $hres = $res;
949
                $hres =~ s/\n/<br>/g;
950
                $hres =~ s/\"/\\"/g;
951
                $bmess = "Backup failed: $hres";
952
            }
953
        }
954
        syslogit('info', "$bmes: $path1") if ($bmes);
955
        my $newtasks = "{\"type\":\"update\",\"tab\":\"images\",\"timestamp\":$current_time" .
956
        ($duuid?",\"uuid\":\"$duuid\"":"") .
957
        ($dstatus?",\"status\":\"$dstatus\"":"") .
958
        ($snap1?",\"snap1\":\"$snap1\"":"") .
959
        ($status eq "backingup"?",\"backup\":\"$path1\"":"") .
960
        ($bmes?",\"message\":\"$bmes\", \"backup\":\"$path1\"":"") .
961
        ",\"sender\":\"steamExec\"" .
962
        "}, ";
963
964
        opendir my($dh), '/tmp' or die "Couldn't open '/tmp': $!";
965
        my @files;
966
        if ($username eq 'common') {
967
            # write tasks to all admin user's session task pipes
968
            @files = grep { /.*~A-.*\.tasks$/ } readdir $dh;
969
        } else {
970
            # write tasks to all the user's session task pipes
971
            @files = grep { /^$username~.*\.tasks$/ } readdir $dh;
972
        }
973
        closedir $dh;
974
        my @pfiles;
975
        foreach my $f (@files) {
976
            push @pfiles, "/tmp/$f" if (`pgrep -f "$f"`); # Only include pipes with active listeners
977
        };
978
        my $tasksfiles = join(' ', @pfiles);
979
        $tasksfiles = $1 if ($tasksfiles =~ /(.+)/); #untaint
980
        # Write to users named pipes if user is logged in
981
        if ($tasksfiles) {
982
            $res = `/bin/echo \'$newtasks\' | /usr/bin/tee  $tasksfiles \&`;
983
        }
984
    }
985
}
986
987
sub changeFstab {
988
	my $image = $_[0];
989
	my $pool = $_[1];
990
	my $remove = $_[2];
991
	return 0 unless ($image);
992
	return 0 unless (index($image, " ")==-1);
993
	copy($fstab, "$fstab.steam.bak") or return 0;
994
995
	my $q = `/bin/cat /proc/mounts | grep "$pool"`; # Find the lvm volume mounted on /mnt/images
996
    # $q =~ /\/dev\/mapper\/(\S+)-(\S+) $pool.+/;
997
    ($q =~ m/\/dev\/mapper\/(\S+)-(\S+) $pool.+/g)[-1]; # Select last match
998
    my $lvolgroup = $1;
999
    my $lvol = $2;
1000
1001
	my $newfile = "";
1002
	my $match;
1003
	open (FILE, $fstab);
1004
	while (<FILE>) {
1005
		chomp;
1006
		my $line = $_;
1007
		if ($line =~ /^\/dev\/$lvolgroup\/$image/) {
1008
			$newfile .= "$line\n" unless ($remove);
1009
			$match = 1;
1010
		} else {
1011
			$newfile .= "$line\n";
1012
		}
1013
	}
1014
    $newfile .= "/dev/$lvolgroup/$image /mnt/$image ext4 users,ro 0 0\n" unless ($remove || $match);
1015
	close (FILE);
1016
	open( FILE2, ">$fstab" );
1017
	#open( FILE2, ">/tmp/fstab.new" );
1018
	print FILE2 $newfile;
1019
	close(FILE2);
1020
	#copy("/tmp/fstab.new", $fstab) or return 0;
1021
	return "$fstab updated with /dev/$lvolgroup/$image /mnt/$image $match : $remove\n";
1022
}
1023
1024
sub updateBackingFile {
1025
    my $imagepath = $_[0];
1026
    unless (-e $imagepath) {
1027
        print "Not updating backing file for image (not found) $imagepath\n";
1028
        return;
1029
    }
1030
    $imagepath = uri_escape($imagepath);
1031
    my $bcmd = qq|REMOTE_USER=irigo $base/cgi/images.cgi -a updatebackingfile -i "$imagepath"|;
1032
    print `$bcmd`;
1033
}
1034
1035
sub updateImageStatus {
1036
	my $imagepath = $_[0];
1037
	my $imagestatus = $_[1];
1038
	my $newvsize = $_[2]; # Size of image has changed
1039
	my $newbsize = $_[3]; # Size of image's backup has changed
1040
	return unless ($imagepath);
1041 48fcda6b Origo
    # if (-e $imagepath) {
1042
    #     print "Updating image $imagepath, $imagestatus, $newvsize, $newbsize\n";
1043
    # } else {
1044
    #     print "Not updating image (not found) $imagepath, $imagestatus, $newvsize, $newbsize\n";
1045
    #     return;
1046
    # }
1047 95b003ff Origo
1048
    unless (tie %imagereg,'Tie::DBI', {
1049
        db=>'mysql:steamregister',
1050
        table=>'images',
1051
        key=>'path',
1052
        autocommit=>0,
1053
        CLOBBER=>3,
1054
        user=>$dbiuser,
1055
        password=>$dbipasswd}) {syslogit('info', "Image register could not be accessed")};
1056
1057
    my $imageuser = $arg1;
1058
    my $imagename;
1059 9ce694a3 hq
    if (($imagestatus eq 'uploading' || $imagestatus eq 'downloading') && !$imagereg{$imagepath}) {
1060 95b003ff Origo
        # An image is being uploaded
1061
        my $ug = new Data::UUID;
1062
        my $newuuid = $ug->create_str();
1063
        $imagename = $imagepath;
1064
        if ($imagename =~ /.+\/(.+)\/(.+)\.(.+)/) {
1065
            $imageuser = $1;
1066
            $imagename = $2;
1067 9ce694a3 hq
            my $imagetype = $3 || 'qcow2';
1068 95b003ff Origo
            $imagereg{$imagepath} = {
1069
                uuid => $newuuid,
1070
                path => $imagepath,
1071
                name => $imagename,
1072
                user => $imageuser,
1073
                type => $imagetype,
1074
                virtualsize => $newvsize,
1075
                size => $newvsize,
1076 64c667ea hq
                status => $imagestatus
1077 95b003ff Origo
            };
1078
            $arg1 = $imageuser;
1079
        }
1080 3657de20 Origo
    } elsif ($imagestatus ne 'removed') {
1081 95b003ff Origo
        if ($imagestatus eq 'installable') {
1082
            $imagestatus = 'unused';
1083
            $imagename = $imagereg{$imagepath}->{'name'} if ($imagereg{$imagepath});
1084
            $imagereg{$imagepath}->{'installable'} = 'true';
1085
            $main::updateUI->(
1086
                {user=>"irigo", tab=>"images", path=>"$imagepath", status=>"$imagestatus", message=>"Image $imagename downloaded and ready to install", type=>"update"}
1087
            );
1088
            $arg1 = 'irigo';
1089
            syslogit('info', "Downloaded $imagepath from registry");
1090
        } elsif ($imagestatus eq 'downloaded') {
1091
            $imagestatus = 'unused';
1092
            $imagename = $imagereg{$imagepath}->{'name'} if ($imagereg{$imagepath});
1093
            $main::updateUI->(
1094
                {user=>"irigo", tab=>"images", path=>"$imagepath", status=>"$imagestatus", message=>"Image $imagename downloaded", type=>"update"}
1095
            );
1096
            $arg1 = 'irigo';
1097
            syslogit('info', "Downloaded $imagepath from registry");
1098
        }
1099
        $imagereg{$imagepath}->{'status'} = $imagestatus;
1100 9ce694a3 hq
        $imagereg{$imagepath}->{'status'} = $imagestatus;
1101 95b003ff Origo
        $imagereg{$imagepath}->{'virtualsize'} = $newvsize if ($newvsize);
1102
    } else {
1103 3657de20 Origo
        syslogit('info', "Deleting $imagepath from DB ($imagestatus)");
1104 95b003ff Origo
        delete $imagereg{$imagepath};
1105
    }
1106 48fcda6b Origo
    tied(%imagereg)->commit;
1107 95b003ff Origo
    untie %imagereg;
1108
    if ((defined $newvsize) || (defined $newbsize)) {
1109 2a63870a Christian Orellana
        updateBilling($arg1) if ($arg1 !~ /\//);
1110 95b003ff Origo
    }
1111
}
1112
1113
sub updateBillingAllNetworks {
1114
    my $t = new Proc::ProcessTable;
1115
    my $i = 0;
1116
    foreach $p ( @{$t->table} ){
1117
        my $pcmd = $p->cmndline;
1118
        if ($pcmd =~ /(.*steamExec updatenetworkbilling)/) { # || $pcmd =~ /(.*apache2 -k start)/) {
1119
            $i++;
1120
        }
1121
    }
1122
    if ($i>1) {
1123
        print "Already updating network billing! ($i)\n";
1124
        return;
1125
    }
1126
    print "Updating network billing for all users...\n";
1127
1128
    unless (tie %userreg,'Tie::DBI', {
1129
        db=>'mysql:steamregister',
1130
        table=>'users',
1131
        key=>'username',
1132
        autocommit=>0,
1133
        CLOBBER=>1,
1134
        user=>$dbiuser,
1135
        password=>$dbipasswd}) {return 0};
1136
1137
    my @regvalues = values %userreg;
1138
    foreach my $valref (@regvalues) {
1139
        my $buser = $valref->{'username'};
1140
        print "Updating billing for $buser\n";
1141
        my $bcmd = "REMOTE_USER=$buser $base/cgi/networks.cgi -a updatebilling";
1142
    # Actually do the update
1143
        print `$bcmd`;
1144
1145
    }
1146
    untie %userreg;
1147
}
1148
1149
sub updateBillingAllImages {
1150
    my $t = new Proc::ProcessTable;
1151
    my $i = 0;
1152
    foreach $p ( @{$t->table} ){
1153
        my $pcmd = $p->cmndline;
1154
        if ($pcmd =~ /(.*steamExec updateimagebilling)/) { # || $pcmd =~ /(.*apache2 -k start)/) {
1155
            $i++;
1156
        }
1157
    }
1158
    if ($i>1) {
1159
        print "Already updating image billing! ($i)\n";
1160
        return;
1161
    }
1162
    print "Updating image billing for all users...\n";
1163
1164
    unless (tie %userreg,'Tie::DBI', {
1165
        db=>'mysql:steamregister',
1166
        table=>'users',
1167
        key=>'username',
1168
        autocommit=>0,
1169
        CLOBBER=>1,
1170
        user=>$dbiuser,
1171
        password=>$dbipasswd}) {return 0};
1172
1173
    my @regvalues = values %userreg;
1174
    foreach my $valref (@regvalues) {
1175
        my $buser = $valref->{'username'};
1176
        print "Updating billing for $buser\n";
1177
        my $bcmd = "REMOTE_USER=$buser $base/cgi/images.cgi -a updatebilling";
1178
    # Actually do the update
1179
        print `$bcmd`;
1180
1181
    }
1182
    untie %userreg;
1183
}
1184
1185
sub markMonitoredServers {
1186
    print "Marking monitored servers in /var/log/stabile...\n";
1187
1188
}
1189
1190
sub releaseOldDhcpLeases {
1191
    print "Releasing DHCP leases logged as old leases in syslog...\n";
1192
    my $datanic = $config->get('ENGINE_DATA_NIC');
1193
	unless (tie %networkreg,'Tie::DBI', {
1194
		db=>'mysql:steamregister',
1195
		table=>'networks',
1196
		key=>'uuid',
1197
		autocommit=>0,
1198
		CLOBBER=>3,
1199
		user=>$dbiuser,
1200
		password=>$dbipasswd}) {throw Error::Simple("Stroke=Error Register could not be accessed")};
1201
    my %leases;
1202
    $cmd = qq[tail -n 500 /var/log/syslog | grep -oP " not using configured address .+ because it is leased to .+\$" | sort |  uniq];
1203
    my @loglines = split("\n", `$cmd`);
1204
    foreach my $line (@loglines) {
1205
        $line =~ /not using configured address (.+) because it is leased to (\S+)/;
1206
        my $relip = $1;
1207
        my $relmac = $2;
1208
        $leases{$relip} = {
1209
            ip=>$relip,
1210
            mac=>$relmac
1211
        };
1212
        my $relid;
1213
        if ($relip =~ /10\.(\d+)\.(\d+)\.\d+/) {
1214
            $relid = (0 + "$1$2");
1215
        } else {
1216
            foreach my $net (values %networkreg) {
1217
                if ($net->{'externalip'} eq $relip) {
1218
                    $relid = $net->{'id'};
1219
                    last
1220
                }
1221
            }
1222
        }
1223
        print "Releasing $datanic.$relid $relip $relmac\n";
1224
        print `/usr/bin/dhcp_release $datanic.$relid $relip $relmac`;
1225
        print `perl -i -ne 'print if !/$relip/' /var/lib/misc/dnsmasq.leases`;
1226
        print `pkill -HUP -f interface=$datanic.$relid`;
1227
    }
1228
    untie %networkreg;
1229
}
1230
1231 2a63870a Christian Orellana
sub backupAllFuel {
1232
    unless (tie %userreg,'Tie::DBI', {
1233
        db=>'mysql:steamregister',
1234
        table=>'users',
1235
        key=>'username',
1236
        autocommit=>0,
1237
        CLOBBER=>1,
1238
        user=>$dbiuser,
1239
        password=>$dbipasswd}) {return 0};
1240
1241
    my @regvalues = values %userreg;
1242
    foreach my $valref (@regvalues) {
1243
        my $buser = $valref->{'username'};
1244
        my $privileges = $valref->{'privileges'};
1245
        unless (index($privileges,"d")!=-1) {
1246
            my $bcmd = "REMOTE_USER=$buser $base/cgi/images.cgi -a backupfuel";
1247
            print `$bcmd`;
1248
        }
1249
    }
1250
    untie %userreg;
1251
}
1252
1253
1254 95b003ff Origo
sub unmountAllImages {
1255
    unless (tie %userreg,'Tie::DBI', {
1256
        db=>'mysql:steamregister',
1257
        table=>'users',
1258
        key=>'username',
1259
        autocommit=>0,
1260
        CLOBBER=>1,
1261
        user=>$dbiuser,
1262
        password=>$dbipasswd}) {return 0};
1263
1264
    my @regvalues = values %userreg;
1265
    foreach my $valref (@regvalues) {
1266
        my $buser = $valref->{'username'};
1267
        my $privileges = $valref->{'privileges'};
1268
        my $bcmd = "REMOTE_USER=$buser $base/cgi/images.cgi -a unmountall" unless (index($privileges,"d")!=-1);
1269
    # Actually do the update
1270
        print `$bcmd`;
1271
    }
1272
    untie %userreg;
1273
}
1274
1275
sub backupAllImages {
1276
    my $t = new Proc::ProcessTable;
1277
    my $i = 0;
1278
    foreach $p ( @{$t->table} ){
1279
        my $pcmd = $p->cmndline;
1280
        if ($pcmd =~ /(.*steamExec backupallimages)/) { # || $pcmd =~ /(.*apache2 -k start)/) {
1281
            $i++;
1282
        }
1283
    }
1284
    if ($i>1) {
1285
        print "Already backing up Stabile! ($i)\n";
1286
        return;
1287
    }
1288
    print "Backing up all images...\n";
1289
1290
    unless (tie %imagereg,'Tie::DBI', {
1291
        db=>'mysql:steamregister',
1292
        table=>'images',
1293
        key=>'path',
1294
        autocommit=>0,
1295
        CLOBBER=>3,
1296
        user=>$dbiuser,
1297
        password=>$dbipasswd}) {syslogit('info', "Image register could not be accessed")};
1298
1299
    my @regvalues = values %imagereg;
1300
    foreach my $valref (@regvalues) {
1301
        my $uuid = $valref->{'uuid'};
1302
        my $buser = $valref->{'user'};
1303
        my $bschedule = $valref->{'bschedule'};
1304
        if ($bschedule =~ /daily/) {
1305 2a63870a Christian Orellana
            my $bcmd = qq|REMOTE_USER=$buser $base/cgi/images.cgi -a backup -u $uuid -g '{"skipzfs":1}'|;
1306 95b003ff Origo
            print "Backing up ($bschedule): $valref->{'name'} ($uuid)\n";
1307
        # Actually do the backup
1308
            print `$bcmd`;
1309
        # If more than 4 jobs running, wait for some to finish
1310
            while (runningBackups()>4) {
1311
                print ".";
1312
                sleep 30;
1313
            }
1314
        } else {
1315
            print "Not backing up (" . ($bschedule?bschedule:'no schedule') . "): $valref->{'name'} ($uuid)\n";
1316
        # Update btime - this is done by zbackup below
1317
        #    my $bcmd = "REMOTE_USER=$buser $base/cgi/images.cgi -a updatebtime -u $uuid";
1318
        #    print `$bcmd`;
1319
        }
1320
    }
1321
    untie %imagereg;
1322
    # Finally back up all ZFS volumes
1323 27512919 Origo
    my $bcmd = "REMOTE_USER=irigo $base/cgi/images.cgi -a zbackup";
1324 95b003ff Origo
    print `$bcmd`;
1325
1326
    sub runningBackups {
1327
        my $j = 0;
1328
        foreach my $valref (@regvalues) {
1329
            $j++ if ($valref->{'status'} =~ /backingup/);
1330
        }
1331
        return $j;
1332
    }
1333
}
1334
1335
sub syslogit {
1336
	my ($priority, $msg) = @_;
1337
1338
    my $current_time = time;
1339
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($current_time);
1340
    $year += 1900;
1341
    my $month = substr("0" . ($mon+1), -2);
1342
    my $pretty_time = sprintf "%4d-%02d-%02d@%02d:%02d:%02d",$year,$mon+1,$mday,$hour,$min,$sec;
1343
1344
	if ($msg && $msg ne '') {
1345
		unless (open(TEMP3, ">>$logfile")) {print "SError log file \"$logfile\" could not be written\n";}
1346
		print TEMP3 $pretty_time, " : $arg1 : $msg\n";
1347
		close(TEMP3);
1348
	}
1349
	return 0 unless ($priority =~ /err|debug/);
1350
	setlogsock('unix');
1351
	# $programname is assumed to be a global.  Also log the PID
1352
	# and to CONSole if there's a problem.  Use facility 'user'.
1353
	openlog($programname, 'pid,cons', 'user');
1354
	syslog($priority, $msg);
1355
	closelog();
1356
	return 1;
1357
}
1358
1359
sub getVirtualSize {
1360
    my $vpath = shift;
1361
    my $macip = shift;
1362
    my $qinfo;
1363
    my($bname, $dirpath, $suffix) = fileparse($vpath, (".vmdk", ".img", ".vhd", ".qcow", ".qcow2", ".vdi", ".iso"));
1364
    if ($suffix eq ".qcow2") {
1365
        if ($macip) {
1366 3657de20 Origo
            $qinfo = `$sshcmd $macip /usr/bin/qemu-img info --force-share "$vpath"`;
1367 95b003ff Origo
        } else {
1368 3657de20 Origo
            $qinfo = `/usr/bin/qemu-img info --force-share "$vpath"`;
1369 95b003ff Origo
        }
1370
        $qinfo =~ /virtual size:.*\((.+) bytes\)/g;
1371
        return(int($1)); # report size of new image for billing purposes
1372
    } elsif ($status eq ".vdi") {
1373
        if ($macip) {
1374
            $qinfo = `$sshcmd $macip /usr/bin/VBoxManage showhdinfo "$vpath"`;
1375
        } else {
1376
            $qinfo = `/usr/bin/VBoxManage showhdinfo "$vpath"`;
1377
        }
1378
        $qinfo =~ /Logical size:\s*(\d+) MBytes/g;
1379
        return(int($1) * 1024 * 1024); # report size of new image for billing purposes
1380
    } else {
1381
        if ($macip) {
1382
            return `$sshcmd $macip perl -e 'my @stat=stat("$vpath"); print $stat[7];'`;
1383
        } else {
1384
            my @stat = stat($vpath);
1385
            return($stat[7]); # report size of new image for billing purposes
1386
        }
1387
    }
1388
}
1389
1390
sub updateBilling {
1391
    my $imageuser = shift;
1392
    if ($imageuser && $imageuser ne 'common') {
1393
        my $bcmd = "/usr/bin/$sshcmd 127.0.0.1 REMOTE_USER=$imageuser $base/cgi/images.cgi -a updatebilling";
1394
        my $ures = `$bcmd`;
1395
        debuglog("updating billing for $imageuser: $ures");
1396
    }
1397
}
1398
1399
sub debuglog {
1400
    my $msg = shift;
1401
    chomp $msg;
1402
1403
    open(my $fd, ">>", $debugfile);
1404
    print $fd "[$pretty_time] $msg\n";
1405
    close($fd);
1406
}
1407
1408
sub shell_esc_chars {
1409
	my $str = shift;
1410
	$str =~ s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'" ])/\\$1/g;
1411
	return $str;
1412
}