This repository was archived by the owner on Oct 24, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathinstall.pl
More file actions
executable file
·2048 lines (1773 loc) · 64.9 KB
/
install.pl
File metadata and controls
executable file
·2048 lines (1773 loc) · 64.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/perl
#
# Copyright (C) Opmantek Limited (www.opmantek.com)
#
# ALL CODE MODIFICATIONS MUST BE SENT TO CODE@OPMANTEK.COM
#
# This file is part of Network Management Information System ("NMIS").
#
# NMIS is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# NMIS is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with NMIS (most likely in a file named LICENSE).
# If not, see <http://www.gnu.org/licenses/>
#
# For further information on NMIS or for a license other than GPL please see
# www.opmantek.com or email contact@opmantek.com
#
# User group details:
# http://support.opmantek.com/users/
#
# *****************************************************************************
use 5.10.1;
# Load the necessary libraries
use FindBin;
use lib "$FindBin::Bin/lib";
use strict;
use DirHandle;
use Data::Dumper;
#! this imports the LOCK_ *constants (eg. LOCK_UN, LOCK_EX)
use Fcntl qw(:DEFAULT :flock);
use File::Copy;
use File::Find;
use File::Basename;
use File::Path;
use Cwd;
use POSIX qw(:sys_wait_h);
use version 0.77;
use Getopt::Std;
my $me = basename($0);
my $defsite = "/usr/local/nmis8";
my $usage = qq!
NMIS Copyright (C) Opmantek Limited (www.opmantek.com)
This program comes with ABSOLUTELY NO WARRANTY;
Usage: $me [-hydl] [-t /some/path|site=/some/path] [listdeps=0/1]
-h: show this help screen
-d: produce extra debug output and logs
-l: No installation, only show (missing) dependencies
-t: Installation target, default is $defsite
-y: non-interactive mode, all questions are pre-answered
with the default choice\n\n!;
# relax an overly strict umask but for the duration of the installation only
# otherwise dirs and files that are created end up inaccessible for the nmis user...
umask(0022);
my $nmisModules; # local modules used in our scripts
die $usage if ( $ARGV[0] =~ /^-(\?|h|-help)$/i );
# let's prefer std -X flags, fall back to word=value style
my (%options, %oldstyle);
die $usage if (!getopts("yldt:", \%options));
%oldstyle = getArguements(@ARGV) if (@ARGV);
my $site = $options{t} || $oldstyle{site} || $defsite;
my $listdeps = $options{l} || ($oldstyle{listdeps} =~ /^(1|true|yes)$/i);
my $debug = $options{d} || $oldstyle{debug};
my $noninteractive = $options{y};
die "This installer must be run with root privileges, terminating now!\n"
if ($> != 0);
system("clear");
my ($installLog, $mustmovelog);
if ( -d $site )
{
$installLog = "$site/install.log";
}
else
{
$installLog = "/tmp/install.log";
$mustmovelog = 1;
}
###************************************************************************###
printBanner("NMIS Installer");
my $hostname = `hostname -f`; chomp $hostname;
# figure out where we install from; current dir, check the dirname of this command's invocation, or give up
my $src = cwd();
$src = Cwd::abs_path(dirname($0)) if (!-f "$src/LICENSE");
die "Cannot determine installation source directory!\n" if (!-f "$src/LICENSE");
die "The installer cannot be run out of the live target directory!
Please unpack the NMIS sources in a different directory (e.g. /tmp)
and restart the installer there!\n\n" if ($src eq $site);
my $nmisversion;
open(G, "./lib/NMIS.pm");
for my $line (<G>)
{
if ($line =~ /^\s*(our\s+)?\$VERSION\s*=\s*"(.+)";\s*$/)
{
$nmisversion = $2;
last;
}
}
close G;
logInstall("Installation of NMIS $nmisversion on host '$hostname' started at ".scalar localtime(time));
# safeguard against local::lib breaking system-wide module installation for cpan'ables
# if PERL5LIB was set, remove all its members from @INC or the module availabilty test will
# look in the wrong places
if (defined $ENV{PERL_LOCAL_LIB_ROOT})
{
logInstall("clearing local::lib config items");
for my $dontwantpath (split(/:/,$ENV{PERL5LIB}))
{
@INC = grep($_ ne $dontwantpath, @INC); # bit inefficient but good enough
}
for my $dontwant (qw(PERL_LOCAL_LIB_ROOT PERL5LIB PERL_MM_OPT PERL_MB_OPT))
{
delete $ENV{$dontwant};
}
}
# there are some slight but annoying differences
my ($osflavour,$osmajor,$osminor,$ospatch,$osiscentos);
if (-f "/etc/redhat-release")
{
$osflavour="redhat";
logInstall("detected OS flavour RedHat/CentOS");
open(F, "/etc/redhat-release") or die "cannot read redhat-release: $!\n";
my $reldata = join('',<F>);
close(F);
($osmajor,$osminor,$ospatch) = ($1,$2,$4)
if ($reldata =~ /(\d+)\.(\d+)(\.(\d+))?/);
$osiscentos = 1 if ($reldata =~ /CentOS/);
}
elsif (-f "/etc/os-release")
{
open(F,"/etc/os-release") or die "cannot read os-release: $!\n";
my $osinfo = join("",<F>);
close(F);
if ($osinfo =~ /ID=debian/)
{
$osflavour="debian";
logInstall("detected OS flavour Debian");
}
elsif ($osinfo =~ /ID=ubuntu/)
{
$osflavour="ubuntu";
logInstall("detected OS flavour Ubuntu");
}
($osmajor,$osminor,$ospatch) = ($1,$3,$5)
if ($osinfo =~ /VERSION_ID=\"(\d+)(\.(\d+))?(\.(\d+))?\"/);
}
if (!$osflavour)
{
echolog("Attention: The installer was unable to determine the type of your OS
and won't be able to make certain installation adjustments!
We recommend that you check the NMIS Installation guide at
https://community.opmantek.com/x/Dgh4
for further info.\n\n");
&input_ok;
}
logInstall("Detected OS $osflavour, Major $osmajor, Minor $osminor, Patch $ospatch");
logInstall("Installation source is $src");
###************************************************************************###
printBanner("Checking Perl version...");
if ($^V < version->parse("5.10.1"))
{
echolog("The version of Perl installed on your server is lower than the minimum
supported version 5.10.1. Please upgrade to at least Perl 5.10.1");
exit 1;
}
else {
echolog("The version of Perl installed on your server is $^V and OK");
}
printBanner("Checking SELinux Status");
my $rawstatus = system("selinuxenabled");
if (WIFEXITED($rawstatus))
{
if (WEXITSTATUS($rawstatus) == 0)
{
my $flavour = `getenforce 2>/dev/null`;
chomp ($flavour);
if ($flavour =~ /permissive/i)
{
echolog("SELinux is enabled but in permissive mode.");
}
else
{
echolog("SELinux is enabled!");
print "\n
The installer has detected that SELinux is enabled on your system
and that it is set to enforce its policy.\n
SELinux needs extensive configuration to work properly.\n
In its default configuration it is known to interfere with NMIS,
and we do therefore recommend that you disable SELinux for NMIS.
See \"man 8 selinux\" for details.
\n";
if ("CONTINUE" ne input_str("Type CONTINUE to continue regardless of SELinux, or any other key to abort: ",
undef, undef))
{
echolog("\n\nAborting installation because of SELinux state.");
exit 1;
}
}
}
else
{
echolog("SELinux is not enabled.");
}
}
else
{
echolog("Could not determine SELinux status, exit code was $rawstatus");
}
###************************************************************************###
my $can_use_web;
if ($osflavour)
{
my @debpackages = (qw(autoconf automake gcc make libcairo2 libcairo2-dev libglib2.0-dev
libpango1.0-dev libxml2 libxml2-dev libnet-ssleay-perl
libcrypt-ssleay-perl apache2 fping nmap snmp snmpd snmptrapd libnet-snmp-perl
libcrypt-passwdmd5-perl libjson-xs-perl libnet-dns-perl
libio-socket-ssl-perl libwww-perl libnet-smtp-ssl-perl libnet-smtps-perl
libcrypt-unixcrypt-perl libcrypt-rijndael-perl libuuid-tiny-perl libproc-processtable-perl libdigest-sha-perl
libnet-ldap-perl libnet-snpp-perl libdbi-perl libtime-modules-perl
libsoap-lite-perl libauthen-simple-radius-perl libauthen-tacacsplus-perl
libauthen-sasl-perl rrdtool librrds-perl libtest-deep-perl dialog libcrypt-des-perl libdigest-hmac-perl libclone-perl
libexcel-writer-xlsx-perl libmojolicious-perl libdatetime-perl
libnet-ip-perl libscalar-list-utils-perl libtest-requires-perl libtest-fatal-perl libtest-number-delta-perl libtext-csv-perl libtext-csv-xs-perl
));
my @rhpackages = (qw(perl-core autoconf automake gcc cvs cairo cairo-devel
pango pango-devel glib glib-devel libxml2 libxml2-devel gd gd-devel
libXpm-devel libXpm openssl openssl-devel net-snmp net-snmp-libs
net-snmp-utils net-snmp-perl perl-IO-Socket-SSL perl-Net-SSLeay
perl-JSON-XS httpd fping nmap make groff perl-CPAN crontabs dejavu*
perl-libwww-perl perl-Net-DNS perl-Digest-SHA
perl-DBI perl-Net-SMTPS perl-Net-SMTP-SSL perl-CGI net-snmp-perl perl-Proc-ProcessTable perl-Authen-SASL
perl-Crypt-PasswdMD5 perl-Crypt-Rijndael perl-Net-SNPP perl-Net-SNMP perl-GD rrdtool
rrdtool-perl perl-Test-Deep dialog
perl-Excel-Writer-XLSX perl-Net-IP perl-DateTime
perl-Digest-HMAC perl-Crypt-DES perl-Clone perl-ExtUtils-CBuilder
perl-ExtUtils-ParseXS perl-ExtUtils-MakeMaker perl-Test-Fatal perl-Test-Number-Delta
perl-Test-Requires perl-JSON perl-XML-SAX perl-XML-SAX-Writer perl-Convert-ASN1
perl-Text-CSV perl-Text-CSV_XS));
# perl-Time-modules no longer a/v in rh/centos7
push @rhpackages, ($osflavour eq "redhat" && $osmajor < 7)?
"perl-Time-modules" : "perl-Time-ParseDate";
# cgi was removed from core in 5.20
if (version->parse($^V) >= version->parse("5.19.7"))
{
push @debpackages, "libcgi-pm-perl";
push @rhpackages, "perl-CGI";
}
# stretch/9 ships with these packages that jessie/8 didn't
push @debpackages, (qw(libproc-queue-perl libstatistics-lite-perl libtime-moment-perl libgd-perl ))
if ($osflavour eq "debian" and $osmajor >= 9);
# stretch no longer ships with these packages...
push @debpackages, (qw(libui-dialog-perl libsys-syslog-perl))
if ($osflavour eq "debian" and $osmajor <= 8);
# ubuntu 16.04.3 lts does have a different subset
push @debpackages, (qw(libproc-queue-perl libstatistics-lite-perl libgd-perl libui-dialog-perl))
if ($osflavour eq "ubuntu" and $osmajor >= 16);
my $pkgmgr = $osflavour eq "redhat"? "YUM": ($osflavour eq "debian" or $osflavour eq "ubuntu")? "APT": undef;
my $pkglist = $osflavour eq "redhat"? \@rhpackages : ($osflavour eq "debian" or $osflavour eq "ubuntu")? \@debpackages: undef;
# first check if internet/web access is available
printBanner("Checking Web access...");
# curl is present in most basic redhat install
# wget is present on debian/ubuntu via priority:important
# however, ca-certificates may be out of date/incomplete at this time
my $testres = system("curl --insecure -s -m 10 -o /dev/null https://opmantek.com/robots.txt 2>/dev/null") >> 8;
$testres = system("wget --no-check-certificate -q -T 10 -O /dev/null https://opmantek.com/robots.txt 2>/dev/null") >> 8
if ($testres);
$can_use_web = !$testres;
if ($can_use_web)
{
echolog("Web access is ok.");
}
else
{
echolog("No Web access available!");
print "Your system cannot access the web, therefore $pkgmgr will not
be able to download any missing software packages. If any
such missing packages are detected and you don't have
a local source of packages (e.g. an installation DVD) then the
installation won't complete successfully.
We recommend that you check our Wiki article on working around
package installation without Internet access in that case:
https://community.opmantek.com/x/boSG\n\n";
&input_ok;
}
if ($osflavour eq "debian" or $osflavour eq "ubuntu")
{
my @unresolved;
# one or two packages are not a/v in wheezy
my $osversion = `lsb_release -r`; $osversion =~ s/^.*:\s*//;
printBanner("Updating package status, please wait...");
execPrint("apt-get update -qq");
printBanner("Checking Dependencies...");
for my $pkg (@debpackages)
{
next if ($pkg =~ /^(snmptrapd|libnet-smtps-perl)$/ # in snmpd/not packaged in wheezy
and $osflavour eq "debian"
and version->parse($osversion) < version->parse("8.0"));
next if ($pkg eq "snmptrapd" # included in snmpd before 15.10
and $osflavour eq "ubuntu"
and version->parse($osversion) < version->parse("15.10"));
if (`dpkg -l $pkg 2>/dev/null` =~ /^[hi]i\s*$pkg\s*/m)
{
echolog("Required package $pkg is already installed.");
}
else
{
echolog("Required package $pkg is NOT installed!");
push @unresolved, $pkg;
}
}
if (@unresolved)
{
my $packages = join(" ",@unresolved);
echolog("\n\nSome required packages are missing:
$packages\n
The installer can use $pkgmgr to download and install these packages.\n");
if (input_yn("Do you want to install these packages with $pkgmgr now?"))
{
$ENV{"DEBIAN_FRONTEND"}="noninteractive";
for my $missing (@unresolved)
{
echolog("\nInstalling $missing with apt-get");
execPrint("apt-get -yq install $missing");
}
print "\n\n"; # apt is a bit noisy
}
else
{
echolog("Required packages not present but installer instructed to NOT install them.");
print "\nNMIS will not run correctly without the following packages installed:\n
$packages\n
You will have to resolve these
dependencies manually before NMIS can operate properly.\n\nHit <Enter> to continue:\n";
my $x = <STDIN>;
}
}
}
elsif ($osflavour eq "redhat")
{
my %unresolved;
if ($can_use_web)
{
printBanner("Updating YUM metadata cache...");
system("yum makecache");
}
printBanner("Checking Dependencies...");
# a few packages are only available via the EPEL repo, others need more magic...
# check the enabled extra repos
my %enabled_repos;
open(F, "yum -C -v repolist enabled|") or die "cannot get repository list from yum: $!\n";
for my $line (<F>)
{
if ($line =~ /^Repo-id\s*:\s*(\S+)/)
{
$enabled_repos{$1} = 1;
}
}
close(F);
# first, disable the rpmforge/repoforge repo, it's unfortunately quite dead...
if ($enabled_repos{"rpmforge"})
{
$enabled_repos{"rpmforge"} = 0;
if (open(F, "/etc/yum.repos.d/rpmforge.repo"))
{
my $repodata = join("",<F>);
close F;
$repodata =~ s/enabled\s*=\s*1/enabled=0/g;
open(F, ">/etc/yum.repos.d/rpmforge.repo") or die "cannot open rpmforge.repo: $!\n";
print F $repodata;
close F;
}
}
my @needed;
for my $pkg (@rhpackages)
{
my $installcmd = "yum -y install $pkg";
my ($ispresent, $present_version, $repo, $reponame, $repourl);
if (my $rpmstatus = `rpm -qa $pkg 2>/dev/null`)
{
$present_version = version->parse($1) if ($rpmstatus =~ /^\S+-(\d+\.\d+(\.\d+)?)/m);
$ispresent = 1;
# rrdtool and rrdtool-perl are doubly special - we need a recent enough version
$ispresent = 0
if (($pkg eq "rrdtool" or $pkg eq "rrdtool-perl")
and $present_version < version->parse("1.4.4"));
}
if ($ispresent)
{
echolog("Required package $pkg is already installed"
. ($present_version? " (version $present_version)." : "."));
next;
}
# special handling for certain packages: ghettoforge, epel
# and for centos/rh 6 mainly
if ($osmajor == 6 and
($pkg eq "fping" or $pkg eq "rrdtool" or $pkg eq "rrdtool-perl"))
{
$installcmd = "yum -y --enablerepo=gf-plus install $pkg";
$repo="gf";
$reponame="ghettoforge";
$repourl = "http://ghettoforge.org/";
}
# similar for epel
elsif ($pkg eq "perl-Net-SNMP" or $pkg eq "glib" or $pkg eq "glib-devel"
or $pkg eq "perl-Crypt-Rijndael" or $pkg eq "perl-JSON-XS"
or $pkg eq "perl-Net-SMTPS" or $pkg eq "perl-Net-SNPP"
or $pkg eq "perl-Proc-ProcessTable")
{
$installcmd = "yum -y --enablerepo=epel install $pkg";
$repo="epel";
$reponame="EPEL";
$repourl = "https://fedoraproject.org/wiki/EPEL/";
}
echolog("Required package $pkg is NOT installed!");
$unresolved{$pkg} = { installcmd => $installcmd,
repo => $repo,
reponame => $reponame,
repourl => $repourl };
push @needed, $pkg; # would like to install them in order
}
if (keys %unresolved)
{
my $packages = join(" ",@needed);
echolog("\n\nSome required packages are missing:
$packages\n
The installer can use $pkgmgr to download and install these packages.\n");
if (input_yn("Do you want to install these packages with $pkgmgr now?"))
{
for my $missing (@needed)
{
my ($installcmd, $repo, $reponame, $repourl ) = @{$unresolved{$missing}}{qw(installcmd repo reponame repourl)};
if ($repo and !$enabled_repos{$repo})
{
if (!$can_use_web)
{
printBanner("Cannot enable repository $reponame!");
print "\nThe $reponame repository is required for installing $missing, but
your system does not have web access and thus cannot
download anything from that repository.
You will have to install $missing manually (downloadable
from $repourl).\n";
&input_ok;
next;
}
else
{
enable_custom_repo($repo, $osiscentos, $osmajor);
$enabled_repos{$repo} = 1;
}
}
echolog("\nInstalling $missing with yum".($repo? " from repository $reponame": ""));
execPrint($installcmd);
if ($missing eq "httpd")
{
# silly redhat doesn't start services on installation
execPrint("chkconfig --add $missing");
execPrint("chkconfig $missing on");
}
print "\n\n"; # yum is pretty noisy
}
}
else
{
echolog("Required packages not present but installer instructed to NOT install them.");
print "\nNMIS will not run correctly without the following packages installed:\n
$packages\n
You will have to resolve these
dependencies manually before NMIS can operate properly.\n\n";
for my $missing (sort keys %unresolved)
{
print "The Package $missing can be downloaded from "
.($unresolved{$missing}->{repourl})."\n"
if ($unresolved{$missing}->{repourl});
}
&input_ok;
}
}
}
}
printBanner("Checking Perl Module Dependencies...");
my ($isok,@missingones) = &check_installed_modules;
if (!$isok)
{
print "The installer can use CPAN to install the missing Perl packages
that NMIS depends on, if your system has Internet access.\n\n";
if (!$can_use_web or !input_yn("OK to use CPAN to install missing modules?"))
{
echolog("Cannot install missing CPAN modules.");
print "NMIS will not work properly until the following Perl modules are installed (from CPAN):\n\n".join(" ",@missingones)
."\n\nWe recommend that you stop the installer now, resolve the dependencies,
and then restart the installer.\n\n";
if (input_yn("Stop the installer?"))
{
die "\nAborting the installation. Please install the missing Perl packages\nwith cpan, then restart the installer.\n";
}
}
else
{
echolog("Installing modules with CPAN");
# prime cpan if necessary: non-interactive, follow prereqs,
if (!-e $ENV{"HOME"}."/.cpan") # might be symlink
{
echolog("Performing initial CPAN configuration");
if ($noninteractive)
{
# no inputs, all defaults
execPrint('cpan');
# adjust options unsuitable for noninteractive work
open(F,"|cpan") or die "cannot fork cpan: $!\n";
print F "o conf prerequisites_policy follow\no conf commit\n";
close F;
}
else
{
# there doesn't seem an easy way to prime the cpan shell with args,
# then let interact with the user via stdin/stdout... and not all versions
# of cpan seem to start it automatically
print "\n
If the CPAN configuration doesn't start automatically, then please
enter 'o conf init' on the CPAN prompt.
Should you get prompted to choose Perl Library directories, 'local::lib'
or the like, please choose 'sudo' or 'manual' - NOT 'local::lib'!
To return to the installer when done,
please exit the CPAN\nshell with 'exit'.\n";
&input_ok;
system("cpan");
}
echolog("CPAN configuration complete, proceeding with module installation");
}
system("cpan ".join(" ",@missingones)); # can't use execprint as cpan is interactive
}
}
if ($listdeps)
{
echolog("Dependency checks completed, NOT proceeding with installation as requested.\n");
exit 0;
}
# check that rrdtool is indeed new enough
printBanner("Checking RRDTool Version");
# rrdtool/rrds new enough?
{
my $rrdisok=0;
use NMIS::uselib;
use lib "$NMIS::uselib::rrdtool_lib";
eval { require RRDs; };
if (!$@)
{
# the rrds version is given in a weird form, eg. 1.4007 meaning 1.4.7.
# the version module doesn't quite understand this flavour, expects 1.004007 to mean 1.4.7
my $foundversion = version->parse("$RRDs::VERSION");
my $minversion = version->parse("1.4004");
if ($foundversion >= $minversion)
{
echolog("rrdtool/RRDs version $foundversion is sufficient for NMIS.");
$rrdisok=1;
}
else
{
echolog("rrdtool/RRDs version $foundversion is NOT sufficient for NMIS, need at least $minversion");
}
}
else
{
echolog("No RRDs module found!");
}
if (!$rrdisok)
{
print "\nNMIS will not work properly without a sufficiently modern rrdtool/RRDs.
We HIGHLY recommend that you stop the installer now, install rrdtool
and the RRDs perl module, and then restart the installer.
You should check the NMIS Installation guide at
https://community.opmantek.com/x/Dgh4
for further info.\n\n";
if (input_yn("Stop the installer?"))
{
die "\nAborting the installation. Please install rrdtool and the RRDs perl module, then restart the installer.\n";
}
else
{
echolog("\n\nContinuing the installation as requested. NMIS won't work correctly until you install rrdtool and RRDs!\n\n");
&input_ok;
}
}
}
###************************************************************************###
printBanner("Checking Installation Target");
print "The standard NMIS installation target is \"$site\".
To install NMIS into a different directory please answer the question below
with \"no\" and restart the installer with the argument site=<custom_dir>,
e.g. ./install.pl site=/opt/nmis8\n\n";
if (!input_yn("OK to start installation/upgrade to $site?"))
{
echolog("Exiting installation as directed.\n");
exit 0;
}
###************************************************************************###
if ( -d $site )
{
printBanner("Existing NMIS8 Installation detected");
print "\nIt seems that you have an existing NMIS installation
in $site. The installer can upgrade the existing installation,
or remove it and install from scratch.\n\n";
if (input_yn("Do you want to take a backup of your current NMIS install?\n(RRD data is NOT included!)"))
{
my $backupFile = getBackupFileName();
my $apacheconfig = $osflavour eq "redhat"?
"/etc/httpd/conf.d/nmis.conf" : ($osflavour eq "debian" or $osflavour eq "ubuntu")?
"/etc/apache2/sites-available/nmis.conf" : undef;
execPrint("tar -C $site -czf ~/$backupFile ./admin ./bin ./cgi-bin ./conf ./install ./lib ./menu ./mibs ./models /etc/cron.d/nmis /etc/logrotate.d/nmis $apacheconfig");
echolog("Backup of NMIS install was created in ~/$backupFile\n");
}
if (!input_yn("\nDo you want to upgrade the existing installation?
If you say No here, the existing installation will be REMOVED and OVERWRITTEN!\n")
&& input_yn("\nPlease confirm that you want to REMOVE the existing installation:"))
{
rename($site,"$site.unwanted") or die "Cannot rename $site to $site.unwanted: $!\n";
$installLog = "$site.unwanted/install.log";
$mustmovelog = 1;
}
}
my $isnewinstall;
if (!-d $site )
{
$isnewinstall=1;
safemkdir($site);
}
# now switch to the install.log in the final location
if ($mustmovelog)
{
my $newlog = "$site/install.log";
system("mv $installLog $newlog");
$installLog = $newlog;
}
# before copying anything, kill fpingd and lock nmis (fpingd doesn't even start if locked out)
execPrint("$site/bin/fpingd.pl kill=true") if (-x "$site/bin/fpingd.pl");
open(F,">$site/conf/NMIS_IS_LOCKED");
print F "$0 is operating, started at ".(scalar localtime)."\n";
close F;
open(F, ">/tmp/nmis_install_running");
print F $$;
close(F);
printBanner("Copying NMIS files...");
echolog("Copying source files from $src to $site...\n");
my @candidates;
find(sub
{
my ($name,$dir,$fn) = ($_, $File::Find::dir, $File::Find::name);
push @candidates, [$fn] if (-d $fn); # make sure the directories are created!
push @candidates, [$dir, $name] if (-f $fn); # source contains no symlinks
}, $src);
for (@candidates)
{
my ($sourcedir,$name) = @$_;
my $sourcefile = "$sourcedir/$name";
(my $targetdir = $sourcedir) =~ s!^$src!!;
$targetdir = $site."/".$targetdir;
safemkdir($targetdir) if (!-d $targetdir);
# just make the dir
if (!defined $name)
{
safemkdir($targetdir) if (!-d $targetdir);
}
else
{
my $targetfile = Cwd::abs_path($targetdir."/".$name);
safecopy($sourcefile, $targetfile);
}
}
# catch missing nmis user, regardless of upgrade/new install
if (!getpwnam("nmis"))
{
if (input_yn("OK to create NMIS user?"))
{
# redhat/centos' adduser is non-interactive, debian/ubuntu's wants interaction
if ($osflavour eq "redhat")
{
execPrint("adduser nmis");
}
elsif ($osflavour eq "debian" or $osflavour eq "ubuntu")
{
execPrint("useradd nmis");
}
}
else
{
echolog("Continuing without nmis user.\n");
}
}
if ($isnewinstall)
{
printBanner("Installing default config files...");
safemkdir("$site/conf") if (!-d "$site/conf");
safemkdir("$site/models") if (!-d "$site/models");
# -n(oclobber) should not be required as conf site/conf/ and site/models/ should be empty
# exexprint returns exit code, ie. 0 if ok
die "copying of default config failed!\n" if (execPrint("cp -an $site/install/* $site/conf/"));
die "copying of default models failed!\n" if (execPrint("cp -an $site/models-install/* $site/models/"));
# this test plugin shouldn't be activated automatically
unlink("$site/conf/plugins/TestPlugin.pm") if (-f "$site/conf/plugins/TestPlugin.pm");
}
else
{
# copy over missing plugins if allowed
opendir(D,"$site/install/plugins") or warn "cannot open directory install/plugins: $!\n";
my @candidates = grep(/\.pm$/, readdir(D));
closedir(D);
if (@candidates)
{
safemkdir("$site/conf/plugins") if (!-d "$site/conf/plugins");
printBanner("Updating plugins");
for my $maybe (@candidates)
{
next if ($maybe eq "TestPlugin.pm"); # this example plugin shouldn't be auto-activated
my $docopy = 0;
if (-e "$site/conf/plugins/$maybe")
{
my $havechange = system("diff -q $site/install/plugins/$maybe $site/conf/plugins/$maybe >/dev/null 2>&1") >> 8;
$docopy = ($havechange and input_yn("OK to replace changed plugin $maybe?"));
}
if ($docopy)
{
safecopy("$site/install/plugins/$maybe","$site/conf/plugins/$maybe");
}
}
}
printBanner("Copying new and updated NMIS config files");
# copy if missing - note: doesn't cover syntactically broken, though
for my $cff ("License.nmis", "Access.nmis", "Config.nmis", "BusinessServices.nmis", "ServiceStatus.nmis",
"Contacts.nmis", "Enterprise.nmis", "Escalations.nmis",
"ifTypes.nmis", "Links.nmis", "Locations.nmis", "Logs.nmis",
"Customers.nmis", "Events.nmis", "Polling-Policy.nmis",
"Model-Policy.nmis", "Modules.nmis", "Nodes.nmis",
"Outage.nmis", "Portal.nmis",
"PrivMap.nmis", "Services.nmis", "Users.nmis", "users.dat")
{
if (-f "$site/install/$cff" && !-e "$site/conf/$cff")
{
safecopy("$site/install/$cff","$site/conf/$cff");
}
}
printBanner("Removing outdated/moved config files");
# script moved to admin
execPrint("rm -f $site/conf/update_config_defaults.pl $site/install/update_config_defaults.pl");
###************************************************************************###
printBanner("Updating the config files with any new options...");
if (input_yn("OK to update the config files?"))
{
# merge changes for new NMIS Config options.
execPrint("$site/admin/updateconfig.pl $site/install/Config.nmis $site/conf/Config.nmis");
execPrint("$site/admin/updateconfig.pl $site/install/Access.nmis $site/conf/Access.nmis");
# update default config options that have been changed:
execPrint("$site/admin/update_config_defaults.pl $site/conf/Config.nmis");
execPrint("$site/admin/updateconfig.pl $site/install/Modules.nmis $site/conf/Modules.nmis");
execPrint("$site/admin/updateconfig.pl $site/install/Events.nmis $site/conf/Events.nmis");
# patch config changes that affect existing entries, which update_config_defaults
# doesn't handle
# which includes enabling uuid and showing the polling_policy
execPrint("$site/admin/patch_config.pl -b $site/conf/Config.nmis /system/non_stateful_events='Node Configuration Change, Node Reset, NMIS runtime exceeded' /system/node_summary_field_list,=uuid /system/json_node_fields,=uuid /system/network_viewNode_field_list,=polling_policy");
echolog("\n");
echolog("By default this version NMIS demotes nodes that have never
been collected successfully to a single collection attempt once every 24 hours.
If you choose Y below, then the installer will change the configuration
setting demote_faulty_nodes to false, and NMIS will try to collect such nodes
every 5 minutes.");
if (input_yn("Should NMIS retry totally uncollectable nodes every 5 min?"))
{
execPrint("$site/admin/patch_config.pl $site/conf/Config.nmis /system/demote_faulty_nodes=false");
echolog("\n");
}
# ask iff required
my %escrules = eval { do "$site/conf/Escalations.nmis" } if (-f "$site/conf/Escalations.nmis");
if (!keys %escrules
or (ref($escrules{"default_default_default_default__"}) eq "HASH"
&& $escrules{"default_default_default_default__"}->{Level0}))
{
if (input_yn("OK to remove syslog and JSON logging from default event escalation?"))
{
execPrint("$site/admin/patch_config.pl -b $site/conf/Escalations.nmis /default_default_default_default__/Level0=''");
echolog("\n");
}
}
my %newconfig = eval { do "$site/conf/Config.nmis"; } if (-f "$site/conf/Config.nmis");
if (!keys %newconfig
or $newconfig{system}->{fastping_timeout} < 5000
or $newconfig{system}->{ping_timeout} < 5000)
{
if (input_yn("OK to set the FastPing/Ping timeouts to the new default of 5000ms?"))
{
execPrint("$site/admin/patch_config.pl -b -n $site/conf/Config.nmis /system/fastping_timeout=5000 /system/ping_timeout=5000");
echolog("\n");
}
}
if ($newconfig{system}->{keep_event_history}
&& $newconfig{system}->{keep_event_history} ne "false"
&& input_yn("OK to disable retaining of historic events?"))
{
execPrint("$site/admin/patch_config.pl -b $site/conf/Config.nmis /system/keep_event_history=false");
echolog("\n");
}
# offer to setup nmis-omk sso, if it's safe to do so
# ie: if omk is present, no sso is configured for omk or nmis,
# and the current cookie flavour is the (pretty unsafe old-style) 'nmis'
if (-d "/usr/local/omk")
{
my %nmisconfig = do "$site/conf/Config.nmis";
my %omkconfig = do "/usr/local/omk/conf/opCommon.nmis";
if (keys %nmisconfig
&& $nmisconfig{authentication}->{auth_cookie_flavour} eq "nmis"
&& keys %omkconfig
&& !$omkconfig{authentication}->{auth_sso_domain}
&& !$nmisconfig{authentication}->{auth_sso_domain}
&& input_yn("OK to enable authentication cookie sharing (SSO) with Opmantek applications?"))
{
my $mustsharethis = $omkconfig{omkd}->{omkd_secrets}->[0];
printBanner("Enabling NMIS-OMK Single-Sign-On");
execPrint("$site/admin/patch_config.pl -b $site/conf/Config.nmis /authentication/auth_web_key=$mustsharethis /authentication/auth_cookie_flavour=omk");
}
}
# move config/cache files to new locations where necessary
if (-f "$site/conf/WindowState.nmis")
{
printBanner("Moving old WindowState file to new location");
execPrint("mv $site/conf/WindowState.nmis $site/var/nmis-windowstate.nmis");
}
# disable the uuid plugin, which this version doesn't need
my $obsolete = "$site/conf/plugins/UUIDPlugin.pm";
if (-f $obsolete)
{
echolog("Disabling obsolete UUID Plugin");
rename($obsolete, "$obsolete.disabled");
}
# handle table files, automatically where possible
printBanner("Performing Table Upgrades");
my @upgradables = `$site/admin/upgrade_tables.pl -o $site/install $site/conf 2>&1`;
my $ucheck = $? >> 8;
my @problematic = `$site/admin/upgrade_tables.pl -p $site/install $site/conf 2>&1`;
logInstall("table upgrade check:\n".join("", @upgradables, @problematic));
# first mention the problematic files
if ($ucheck & 1)
{
printBanner("Non-upgradeable Table files detected");
print "\nThe installer has detected the following table files that require
manual updating:\n\n" .join("", @problematic) ."\n";
&input_ok;
}
else
{
echolog("No table files in need of manual updating detected.");
}
if ($ucheck & 2)
{
printBanner("Auto-upgradeable table files detected");
print "The installer has detected the following auto-upgradeable table files:\n\n"
.join("", @upgradables)."\n";
if (input_yn("Do you want to upgrade these tables now?"))
{
execPrint("$site/admin/upgrade_tables.pl -u $site/install $site/conf 2>&1");
}
else
{
echolog("Not upgrading tables, as directed.");