-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathinstall.pl
executable file
·2209 lines (1917 loc) · 70.8 KB
/
install.pl
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 [email protected]
#
# 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 [email protected]
#
# 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};
}
}
delete $ENV{"PERL_CPANM_OPT"};
if ($noninteractive)
{
$ENV{"PERL_MM_USE_DEFAULT"}=1;
}
else
{
$ENV{"PERL_MM_USE_DEFAULT"}=0;
}
# 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 cpanminus
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 libwww-mechanize-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 libdbi-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 libauthen-pam-perl
libcgi-session-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 perl-App-cpanminus crontabs dejavu*
perl-libwww-perl perl-WWW-Mechanize 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-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-Authen-PAM));
# perl-Time-modules no longer a/v in rh/centos7
push @rhpackages, ($osflavour eq "redhat" && $osmajor < 7)?
"perl-Time-modules" : "perl-Time-ParseDate";
# perl-CGI-Session gone in RHEL8
#
if ($osiscentos == 1) # all versions of Centos
{
push @rhpackages, "perl-CGI-Session";
}
elsif ($osflavour eq "redhat" && $osmajor >= 8) # RHEL8
{
# perl-CGI-Session gone in RHEL8
}
elsif ($osflavour eq "redhat") # RHEL7 and older
{
push @rhpackages, "perl-CGI-Session";
}
# 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);
# buster/10 ships with these packages...
push @debpackages, (qw(libtime-parsedate-perl libui-dialog-perl))
if ($osflavour eq "debian" and $osmajor >= 10);
# ...but buster no longer ships with those - now virtual
push @debpackages, (qw(libtime-modules-perl))
if ($osflavour eq "debian" and $osmajor <= 9);
# 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);
# ubuntu ships with that one up to and including 18.04lts
push @debpackages, (qw(libtime-modules-perl)) if ($osflavour eq "ubuntu");
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-WWW-Mechanize"
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 CPANM 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 CPANM to install missing modules?"))
{
echolog("Cannot install missing CPANM 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
{
# installed cpanm for installing cpan modules
# as it is far more robust at handling failed tests which hang on cpan installs
my $cpanm = "cpanm";
if ($debug)
{
my $type_which_cpanm = type_which($cpanm);
echolog("type_which_cpanm: $type_which_cpanm\n");
}
# fix cpanm path if not set
if (system("type $cpanm >/dev/null") != 0)
{
$cpanm = type_which($cpanm);
}
if (defined $cpanm)
{
echolog("CPANM installation complete, proceeding with module installation using cpanm");
echolog("cpanm: $cpanm");
# PERL_CPANM_OPT
# If set, adds a set of default options to every cpanm command. These options come first, and so are overridden by command-line options.
# I have deliberately not "unset" PERL_CPANM_OPT to allow one to customize cpanm behaviour other than where we have a hardcoded option
#
# --prompt option looks really useful to investigate and decide on failed tests, but we must honor $noniteractive
#
# Prompts when a test fails so that you can skip, force install, retry or look in the shell to see what's going wrong.
# It also prompts when one of the dependency failed if you want to proceed the installation.
# Defaults to false, and you can say --no-prompt to override if it's set in the default options in PERL_CPANM_OPT.
my $prompt;
if ($noninteractive)
{
$prompt = "";
}
else
{
$prompt = "--prompt";
}
# We pre-install HTTP::Daemon with --notest for this module that often hangs on testing on ubuntu, redhat and centos
# HTTP::Daemon is a dependency of WWW::Mechanize
if ( grep( /^WWW::Mechanize$/, @missingones) or grep( /^HTTP::Daemon$/, @missingones) )
{
system("cpanm HTTP::Daemon --sudo $prompt --notest 2>&1"); # can't use execprint as cpan is interactive: but is cpanm interactive?
}
# We pre-install WWW::Mechanize with --notest for this module that often hangs on testing on ubuntu, redhat and centos
if ( grep( /^WWW::Mechanize$/, @missingones) )
{
system("cpanm WWW::Mechanize --sudo $prompt --notest 2>&1"); # can't use execprint as cpan is interactive: but is cpanm interactive?
}
# Net::SNPP fails tests
if ( grep( /^Net::SNPP$/, @missingones) )
{
system("cpanm Net::SNPP --sudo $prompt --notest"); # can't use execprint as cpan is interactive: but is cpanm interactive?
}
# default test-timeout is 30 mins: install will return exit code 1 on test timeout
system("cpanm --sudo $prompt ".join(" ",@missingones)." 2>&1"); # can't use execprint as cpan is interactive but is cpanm interactive?
}
else
{
echolog("CPANM installation failed");
# we fallback to cpan code used prior to cpanm
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;
}
###************************************************************************###
# detect 'conf/Config.nmis' as proof nmis8 installed
if ( -f "$site/conf/Config.nmis" or -l "$site/conf/Config.nmis" )
{
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;
}
}
else
{
logInstall("Completely new NMIS8 Installation detected");
}
my $isnewinstall=0;
# detect 'conf/Config.nmis' as proof nmis8 installed
if ( ! -f "$site/conf/Config.nmis" and ! -l "$site/conf/Config.nmis" )
{
$isnewinstall=1;
}
logInstall("NMIS8 Installation \$isnewinstall=$isnewinstall");
if (!-d $site )
{
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;
}
if (! $isnewinstall)
{
# move debug.pl
my $debug_src="$site/cgi-bin/debug.pl";
if ( -f $debug_src or -l $debug_src )
{
my $debug_tgt="$site/admin/debug.pl";
echolog("Moving '$debug_src' to '$debug_tgt'");
safemkdir("$site/admin");
execPrint("mv -f '$debug_src' '$debug_tgt'");
}
}
# 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
{
# if somehow this got installed, lets uninstall it.
unlink("$site/conf/plugins/TestPlugin.pm") if (-f "$site/conf/plugins/TestPlugin.pm");
# 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");