Project

General

Profile

Download (17.9 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
use Getopt::Std;
9
use URI::Escape;
10
use Error qw(:try);
11
use Data::Dumper;
12
use Text::SimpleTable;
13
use sigtrap 'handler' => \&cleanup, 'QUIT', 'INT', 'TERM', 'KILL', 'STOP';
14
use Term::ReadLine;
15

    
16
my %options=();
17
getopts("a:hi:du:", \%options); # -a action -h help -i image -d debug
18

    
19
my $action = $options{a};
20
my $cmduser = $options{u};
21
my $debug = $options{d};
22

    
23
my $uuser = scalar getpwuid $<;
24
my $isadmin;
25

    
26
my $user;
27
if ($uuser eq "root" || $uuser eq "irigo" || $uuser eq "mon") {
28
    $isadmin = 1;
29
    if ($cmduser) {$user = $cmduser;}
30
    else {$user = 'irigo';};
31
} elsif ($uuser =~ /irigo-(.+)/) {
32
    $user = $1;
33
} else {
34
    print "You don't have privileges to access this Stabile installation\n";
35
    exit 0;
36
}
37
inithelp();
38

    
39
$ENV{PATH} = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin';
40
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
41

    
42
$ENV{'REMOTE_USER'} = $user;
43

    
44
my $cmdpath = '/';
45
my $cmdobj = '/';
46
my $oldpath;
47
my $oldobj;
48
my $basedir = "/var/www/stabile";
49
$basedir = `cat /etc/stabile/basedir` if -e "/etc/stabile/basedir";
50
chomp $basedir;
51
my $cgi = "$basedir/cgi";
52

    
53
my $term;
54
if (-t STDIN) { # We are talking to a tty
55
    print "Welcome to stash!". ($debug?" (debug)":'') ."\nType \"help\" to list your commands.\n";
56
    $term = new Term::ReadLine 'stash';
57
}
58

    
59
try {
60
    while (!$halt) {
61
        my $cmdaction;
62
        if ($oldpath) {
63
            $cmdpath = $oldpath;
64
            $oldpath = '';
65
        }
66
        if ($oldobj) {
67
            $cmdobj = $oldobj;
68
            $oldobj = '';
69
        }
70

    
71
        chomp $cmdobj;
72
        my $prompt = "$user\@stash:" . "$cmdpath" . (($cmdobj ne '/')?"$cmdobj":"") . "\$";
73
        if ($term) {
74
    # Interactive session
75
            $input = $term->readline($prompt);
76
        } else {
77
            $input =  <STDIN>;
78
        }
79
        unless (defined $input) {
80
            exit;
81
        }
82
        chomp ($input);
83
        next unless ($input || $input eq '0');
84
        next if ($input eq '.');
85

    
86
        # Handle composite commands
87
        my @pathelements;
88
        my @params;
89
        my $paramstxt;
90
        if ($input =~ /^(\w+=.+)/) {
91
            $paramstxt = $input;
92
        } elsif ($input =~ /(.+)\/(\w+=.+)/) {
93
            @pathelements = split('/', $1);
94
            $paramstxt = $2;
95
        } elsif ($input =~ /(\S+)\s?(.*)/)  {
96
            @pathelements = split('/', $1);
97
            $paramstxt = $2;
98
        } else {
99
            "stash does not understand: $input\n";
100
            next;
101
        }
102
        @params = split(/,\s?/, $paramstxt);
103
        if (!$pathelements[0] && $pathelements[1]) { # $input starts with "/"
104
            $oldpath = $cmdpath;
105
            if ($pathelements[1] eq '..'){next;}
106
            elsif ('servers' =~ /^$pathelements[1]/) {$cmdpath = '/servers'}
107
            elsif ('images' =~ /^$pathelements[1]/) {$cmdpath = '/images'}
108
            elsif ('networks' =~ /^$pathelements[1]/) {$cmdpath = '/networks'}
109
            elsif ('nodes' =~ /^$pathelements[1]/ && $isadmin) {$cmdpath = '/nodes'}
110
            elsif ('users' =~ /^$pathelements[1]/ && $isadmin) {$cmdpath = '/users'}
111
            elsif ('systems' =~ /^$pathelements[1]/ && $isadmin) {$cmdpath = '/systems'}
112
            else {next;};
113

    
114
            if ($pathelements[2] =~ /^\w{8}-/ || ($cmdpath eq '/users' && $pathelements[2])) {
115
                $oldobj = $cmdobj;
116
                $cmdobj = "/$pathelements[2]";
117
                $cmdaction = $pathelements[3];
118
            } else {
119
                $cmdaction = $pathelements[2];
120
            }
121
            if (!$cmdaction && !@params) {
122
                $oldpath = '';
123
            }
124

    
125
        } elsif ($cmdpath ne '/') { # && $user) { # A path has been selected
126
            if ($cmdobj ne '/') { # An object has previously been selected
127
                $cmdaction = $pathelements[0];
128
            } elsif ($pathelements[0] =~ /^\w{8}-/ && $pathelements[1]) {
129
                $oldobj = $cmdobj;
130
                $cmdobj = "/$pathelements[0]";
131
                $cmdaction = $pathelements[1];
132
            } else {
133
                $cmdaction = $pathelements[0];
134
            }
135
        } else { # No path has been selected
136
            if ($pathelements[0] eq '..'){;}
137
            elsif ('servers' =~ /^$pathelements[0]/) {$cmdpath = '/servers';}
138
            elsif ('images' =~ /^$pathelements[0]/) {$cmdpath = '/images';}
139
            elsif ('networks' =~ /^$pathelements[0]/) {$cmdpath = '/networks';}
140
            elsif ('nodes' =~ /^$pathelements[0]/ && $isadmin) {$cmdpath = '/nodes';}
141
            elsif ('users' =~ /^$pathelements[0]/ && $isadmin) {$cmdpath = '/users';}
142
            elsif ('systems' =~ /^$pathelements[0]/ && $isadmin) {$cmdpath = '/systems';}
143
            else {$cmdpath = '/'; $cmdobj = '/';};
144

    
145
            if ($cmdpath ne '/') {
146
                if ($pathelements[1] =~ /^\w{8}-/ && $pathelements[2]) {
147
                    $oldpath = '/';
148
                    $oldobj = $cmdobj;
149
                    $cmdobj = "/$pathelements[1]";
150
                    $cmdaction = $pathelements[2];
151
                } else {
152
                    $cmdaction = $pathelements[1];
153
                }
154
            } else {
155
                $cmdaction = $pathelements[0];
156
            }
157
        }
158

    
159
#        my @commands = split(' ', $cmdaction);
160
#        print "Got command $cmdaction, with path $cmdpath and object $cmdobj ($oldpath and $oldobj)\n";
161

    
162
    ## General commands
163
        if ($cmdaction eq '..') {
164
            if ($cmdpath eq '/' && $cmdobj eq '/') {;}
165
            if ($cmdobj eq '/') {$cmdpath = '/'}
166
            $cmdobj = '/';
167
        } elsif ($cmdaction eq 'quit') {
168
            $halt = 1;
169
            cleanup();
170
            last;
171
        } elsif ($cmdaction eq 'listlog' || $cmdaction eq 'log') {
172
            my $p = '/nodes';
173
            print "Latest log entries:", `$cgi$p.cgi -a listlog`, "\n";
174
        } elsif ($cmdaction eq 'clearlog') {
175
            my $p = '/nodes';
176
            print `$cgi$p.cgi -a clearlog`, "\n";
177
        } elsif ($cmdpath eq '/' && $isadmin && $cmdaction eq 'setuser' && $params[0]) {
178
            $user = $params[0];
179
            $ENV{'REMOTE_USER'} = $user;
180
            print "User changed to: $user\n";
181
        } elsif ($cmdaction eq 'debug') {
182
            $debug = ($params[0] eq 'on' || !$params[0])? 1:0;
183
            print "Debug is " . ($debug?'on':'off') . "\n";
184
        } elsif ($cmdpath eq '/') {
185
            if ($cmdaction eq 'list' || $cmdaction eq 'ls') {
186
                print $objhelp{$cmdpath};
187
            } elsif ($cmdaction eq 'help') {
188
                print $cmdhelp{$cmdpath};
189
            } elsif ($cmdaction eq 'showuser') {
190
                my $suser;
191
                $suser = $params[0]if ($isadmin);
192
                $suser = $user unless ($suser);
193
                print `$cgi/users.cgi -a uuidshow -u $suser`, "\n";
194
            } elsif ($cmdaction eq 'listusers') {
195
                print `$cgi/users.cgi -a tablelist`, "\n" if ($isadmin);
196
            } else {
197
                print "Unknown command\n";
198
            }
199
        } else {
200

    
201
    ## Servers, images, networks, nodes
202
            if ($cmdpath eq '/servers' || $cmdpath eq '/images' || $cmdpath eq '/networks' || $cmdpath eq '/nodes'
203
                || $cmdpath eq '/users' || $cmdpath eq '/systems') {
204

    
205
                my $path = $cmdpath;
206

    
207
                my $parms = '';
208
                if ($params[0] eq '-f' || $params[1] eq '-f') {$parms = '-f';};
209
                if ($params[0]  && !($params[0] =~ /^-\w/)) {$parms .= " -m $params[0]";};
210
                if ($params[1]  && !($params[1] =~ /^-\w/)) {$parms .= " -m $params[1]";};
211
                if (($cmdaction eq 'list' || $cmdaction eq 'ls') && $cmdobj eq '/') {
212
                    print "Firing: $cgi$path.cgi -a tablelist $parms\n" if ($debug);
213
                    print `$cgi$path.cgi -a tablelist $parms`, "\n";
214
                } elsif (($cmdaction eq 'listall' && $cmdpath eq '/images') && $cmdobj eq '/') {
215
                    print "Firing: $cgi$path.cgi -a tablelistall $parms\n" if ($debug);
216
                    print `$cgi$path.cgi -a tablelistall $parms`, "\n";
217
                } elsif ($cmdaction eq 'longlist' || $cmdaction eq 'll') {
218
                    print `$cgi$path.cgi -a list $parms`, "\n" unless ($cmdobj ne '/');
219
                } elsif ($cmdaction eq 'help') {
220
                    if ($cmdobj eq '/') {
221
                        my $res = `$cgi$path.cgi -a help`;
222
                        chomp $res;
223
                        print "\n$res\n\n";
224
                    } else {
225
                        if ($path eq '/') {
226
                            print $objhelp{$path};
227
                        } else {
228
                            my $res = `$cgi$path.cgi -a plainhelp`;
229
                            chomp $res;
230
                            print "\n$res\n\n";
231
                        }
232
                    };
233
                } elsif ($cmdaction eq 'listbackups' && $path eq '/images' && $cmdobj ne '/') {
234
                    my $uuid = substr($cmdobj,1);
235
                    my $res = `$cgi$path.cgi -a listbackups -u $uuid`;
236
                    chomp $res;
237
                    print "\n$res\n\n";
238
                } elsif ($cmdaction =~ /updateallbtimes|removeuserimages/ && $path eq '/images' && $cmdobj eq '/') {
239
                    my $res = `$cgi$path.cgi -a $cmdaction`;
240
                    chomp $res;
241
                    print "\n$res\n\n";
242
#                } elsif ($cmdaction =~ /deactivate|deleteentirely/ && $path eq '/users' && $cmdobj eq '/') {
243
#                    my $res = `$cgi$path.cgi -a $cmdaction`;
244
#                    chomp $res;
245
#                    print "\n$res\n\n";
246
                } elsif ($cmdaction =~ /removeuserservers|destroyuserservers/ && $path eq '/servers' && $cmdobj eq '/') {
247
                    my $res = `$cgi$path.cgi -a $cmdaction`;
248
                    chomp $res;
249
                    print "\n$res\n\n";
250
                } elsif ($cmdaction =~ /removeusersystems/ && $path eq '/systems' && $cmdobj eq '/') {
251
                    my $res = `$cgi$path.cgi -a $cmdaction`;
252
                    chomp $res;
253
                    print "\n$res\n\n";
254
                } elsif ($cmdaction =~ /removeusernetworks/ && $path eq '/networks' && $cmdobj eq '/') {
255
                    my $res = `$cgi$path.cgi -a $cmdaction`;
256
                    chomp $res;
257
                    print "\n$res\n\n";
258
                } elsif ($cmdaction =~ /^monitors/ && $path eq '/systems') {
259
                    my $uuid = substr($cmdobj,1);
260
                    my $cgicmd = "$cgi$path.cgi -a monitors" . ($uuid?" -u $uuid":"") . " $parms";
261
                    my $res = `$cgicmd`;
262
                    print "Firing: $cgicmd\n" if ($debug);
263
                    chomp $res;
264
                    print "\n$res\n\n";
265
                } elsif ($cmdaction =~ /^billengine/ && $path eq '/users') {
266
                    my $cgicmd = "$cgi$path.cgi -a billengine $parms";
267
                    my $res = `$cgicmd`;
268
                    print "Firing: $cgicmd\n" if ($debug);
269
                    chomp $res;
270
                    print "\n$res\n\n";
271
                } elsif (($cmdaction eq 'listfiles' || $cmdaction eq 'lf') && $path eq '/images' && $cmdobj ne '/') {
272
                    my $uuid = substr($cmdobj,1);
273
                    my $esc_paramstxt = uri_escape($paramstxt);
274
                    print "Firing: $cgi$path.cgi -a listfiles -u $uuid path=$esc_paramstxt" if ($debug);
275
                    my $res = `$cgi$path.cgi -a listfiles -u $uuid path=$esc_paramstxt`;
276
                    chomp $res;
277
                    print "\n$res\n\n";
278
                } elsif ($cmdaction eq 'listpackages' && $path eq '/images' && $cmdobj ne '/') {
279
                    my $uuid = substr($cmdobj,1);
280
                    print "Firing: $cgi$path.cgi -a listpackages -u $uuid" if ($debug);
281
                    my $res = `$cgi$path.cgi -a listpackages -u $uuid`;
282
                    chomp $res;
283
                    print "\n$res\n\n";
284
                } elsif (($cmdaction eq 'restorefiles' || $cmdaction eq 'rf') && $path eq '/images' && $cmdobj ne '/') {
285
                    my $uuid = substr($cmdobj,1);
286
                    my $esc_paramstxt = uri_escape($paramstxt);
287
                    print "Firing: $cgi$path.cgi -a restorefiles -u $uuid files=$esc_paramstxt" if ($debug);
288
                    my $res = `$cgi$path.cgi -a restorefiles -u $uuid files=$esc_paramstxt`;
289
                    chomp $res;
290
                    print "\n$res\n\n";
291
                } elsif ($cmdaction eq 'show' || $cmdaction eq 'list' || $cmdaction eq 'ls') {
292
                    if ($cmdobj ne '/') {
293
                        my $uuid = substr($cmdobj,1);
294
                        print "Firing: $cgi$path.cgi -a uuidshow -u $uuid\n" if ($debug);
295
                        my $fcmd = qq[$cgi$path.cgi -a uuidshow -u $uuid];
296
                        $fcmd = $1 if ($fcmd =~ /(.*)/);
297
                        print `$fcmd`, "\n";
298
                    }
299
                } elsif ($cmdaction || @params) {
300
                    if ($cmdobj ne '/' || (($cmdaction =~ /^new (.+)/ || $cmdaction eq 'new') && $cmdobj eq '/')) {
301
            #Object operation
302
                        my $postdata;
303
                        my $uuid = substr($cmdobj,1);
304
                        my $actionstr;
305
                        if ($cmdaction eq 'new') { # New object
306
                            $actionstr .= qq{"action": "save", };
307
                            foreach my $action (@params) {
308
                                if ($action =~ /^(\w+)=(.+)/) {
309
                                    $actionstr .= qq{"$1": "$2", };
310
                                }
311
                            }
312
                            $actionstr .= qq{"status": "new"};
313
                        } else { # Perform action, possibly on object
314
                            my $caction = $cmdaction || 'save';
315
                            $actionstr .= qq{"action": "$caction", };
316
                            foreach my $action (@params) {
317
                                if ($action =~ /^(\w+)=(.+)/) {
318
                                    $actionstr .= qq{"$1": "$2", };
319
                                }
320
                            }
321
                            my $identifier = 'uuid';
322
                            if ($path eq '/nodes') {$identifier = 'mac';}
323
                            elsif ($path eq '/users') {$identifier = 'username';};
324
                            $actionstr .= qq{"$identifier": "$uuid"};
325
                        }
326
                        $postdata = uri_escape(
327
#                            qq/{"identifier": "uuid", "label": "uuid", "items":[{$actionstr, "console": 1}]}/
328
                             qq/[{$actionstr, "console": 1}]/
329
                            ) unless $postdata;
330
                        print "Firing: REQUEST_METHOD=post $cgi$path.cgi -k ". uri_unescape($postdata) . "\n" if ($debug);
331
                        print "$postdata\n" if ($debug);
332
                        my $res = `REQUEST_METHOD=post $cgi$path.cgi -k $postdata`;
333
                        my $outres;
334
                        chomp $res;
335
                        for (split /^/, $res) {
336
                            if ($_ =~ /\w+=OK (.+)/i || $_ =~ /\w+=ERROR (.+)/i) {$outres .= "$1\n"};
337
                        }
338
                        print "$outres\n";
339
                    } else {
340
            #Object selection
341
                        print "Firing: $cgi$path.cgi -a uuidlookup -u $cmdaction\n" if ($debug);
342
                        my $res = `$cgi$path.cgi -a uuidlookup -u $cmdaction`;
343
                        chomp $res;
344
                        if ($res || $res eq '0') {
345
                            if ($user) {
346
                                $cmdobj = "/$res";
347
                            } else {
348
                                if (isadmin || $uuser eq "irigo-$res") {
349
                                    $user = "$res";
350
                                    $ENV{'REMOTE_USER'} = $user;
351
                                }
352
                            }
353
                        } else { # No object found - treat $cmdaction as action (instead of uuid)
354
                            print "Firing: $cgi$path.cgi -a $cmdaction\n" if ($debug);
355
                            my $res = `$cgi$path.cgi -a $cmdaction`;
356
                            my $outres;
357
                            chomp $res;
358
                            #print "Got: $res\n" if ($debug);
359
                            for (split /^/, $res) {
360
                                if ($_ =~ /\w+=OK (.+)/i || $_ =~ /\w+=ERROR (.+)/i) {$outres .= "$1\n"}
361
                                else {$outres .= $_;};
362
                            }
363
                            print "$outres\n";
364
                        }
365
                    }
366
                }
367
            } else {
368
                print "Unknown command!\n";
369
            }
370
        }
371
    }
372
    print "\n";
373

    
374
} catch Error with {
375
	my $ex = shift;
376
	if ($ex->{-text}) {
377
    	print $ex->{-text}, "\n";
378
	} else {
379
	    print "Stream=ERROR\n";
380
	}
381
} finally {
382
};
383

    
384
sub cleanup {
385
    print "Unmounting all images\n";
386
    my $res = `$cgi/images.cgi -a unmountall`;
387
    print $res if ($debug);
388
    print "Thanks for now\n";
389
    exit(1);
390
}
391

    
392
sub inithelp {
393

    
394
$cmdhelp{'/'} = <<END
395
Available commands:
396
list
397
"path"
398
setuser "user"
399
END
400
;
401

    
402
$cmdhelp{'/servers'} = <<END
403
Available commands:
404
..
405
list
406
"object uuid"
407
END
408
;
409

    
410
$cmdhelp{'/images'} = <<END
411
Available commands:
412
..
413
list
414
"object uuid"
415
END
416
;
417

    
418
$cmdhelp{'/networks'} = <<END
419
Available commands:
420
..
421
list
422
"object uuid"
423
END
424
;
425

    
426
$cmdhelp{'/users'} = <<END
427
Available commands:
428
..
429
list
430
billing
431
"object uuid"
432
END
433
;
434

    
435

    
436
my $t2 = Text::SimpleTable->new(36);
437
$t2->row('Path');
438
$t2->hr;
439
$t2->row('systems');
440
$t2->row('servers');
441
$t2->row('images');
442
$t2->row('networks');
443
$t2->row('nodes') if ($isadmin);
444
$t2->row('users') if ($isadmin);
445
$objhelp{'/'} = $t2->draw;
446

    
447

    
448
#$objhelp{'/'} = <<END
449
#servers
450
#images
451
#networks
452
#END
453
#;
454

    
455
#$objhelp{'/'} .= "nodes\n" if ($isadmin);
456

    
457
$objhelp{'/networks'} = <<END
458
Available commands:
459
..
460
show
461
END
462
;
463

    
464

    
465
}
(26-26/27)