-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvm_setup.pl
1329 lines (1073 loc) · 41.7 KB
/
vm_setup.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/local/cpanel/3rdparty/bin/perl
# vm_setup.pl
package VMS;
use strict;
use warnings;
use Getopt::Long;
use Fcntl;
use IO::Handle;
use IO::Select;
use String::Random;
use IPC::Open3;
use Term::ANSIColor qw(:constants);
# reset colors to default when done
$Term::ANSIColor::AUTORESET = 1;
# VMS should only be ran as root
if ( $< != 0 ) {
die "VMS must be run as root\n";
}
my $VERSION = '2.0.2';
# declare variables for script options and handle them
my @bashurl;
my %opts = ( 'bashurl' => \@bashurl );
GetOptions( \%opts, 'help', 'verbose', 'full', 'fast', 'force', 'skipyum', 'skiphostname', 'hostname=s', 'tier=s', 'skip', 'clam', 'munin', 'solr', 'quota', 'pdns', 'bashurl=s' )
or die($!);
# --skip should be a shortcut for --fast --skipyum and --skiphostname
# if it is setup, then it is like passing the following options
if ( exists $opts{skip} ) {
$opts{fast} = 1;
$opts{skipyum} = 1;
$opts{skiphostname} = 1;
}
# do not allow the script to run if mutually exclusive arguments are passed
if ( exists $opts{skiphostname} && exists $opts{hostname} ) {
die "script usage: skiphostname and hostname arguments are mutually exclusive\n";
}
# --fast and --full should be mutually exclusive arguments
if ( exists $opts{full} && exists $opts{fast} ) {
die "script usage: fast and full arguments are mutually exclusive\n";
}
# declare global variables for script
# both of these variables are used during the CL install portion
# of script and their necessity should be reviewed during TECH-407
my $VMS_LOG = '/var/log/vm_setup.log';
__PACKAGE__->run(@ARGV) unless caller();
# Every below this should be a subroutine
1;
sub run {
# print header
print "\n";
print_vms("VM Server Setup Script");
print_vms("Version: $VERSION\n");
# help option should be processed first to ensure that nothing is erroneously executed if this option is passed
# converted this to a function to make main less clunky and it may be of use if we add more script arguments in the future
# ex: or die print_help_and_exit();
if ( exists $opts{help} ) {
print_help_and_exit();
}
# vm_setup depends on multiple cPanel api calls
# if the license is invalid, we should immediately die
check_license();
# we should check for the lock file and exit if force argument not passed right after checking for help
# to ensure that no work is performed in this scenario
handle_lock_file();
create_vms_log_file();
setup_resolv_conf();
install_packages();
set_screen_perms();
configure_etc_cpupdate_conf() if ( exists $opts{tier} );
# '/vat/cpanel/cpnat' is sometimes populated with incorrect IP information
# on new openstack builds
# build cpnat to ensure that '/var/cpanel/cpnat' has the correct IPs in it
print_vms("Building cpnat");
system_formatted("/usr/local/cpanel/scripts/build_cpnat");
# use a hash for system information
my %sysinfo = (
"ostype" => undef,
"osversion" => undef,
"tier" => undef,
"hostname" => undef,
"ip" => undef,
"natip" => undef,
);
# hostname is in the format of 'os.cptier.tld'
get_sysinfo( \%sysinfo );
my $natip = $sysinfo{'natip'};
my $ip = $sysinfo{'ip'};
# set_hostname() will return the value of the new hostname for the server
# and the value may not be the same as what is in %sysinfo
my $hostname = set_hostname( $sysinfo{'hostname'} );
# edit files with the new hostname
configure_99_hostname_cfg($hostname);
configure_sysconfig_network($hostname);
configure_wwwacct_conf( $hostname, $natip );
configure_mainip($natip);
configure_whostmgrft(); # this is really just touching the file in order to skip initial WHM setup
disable_feature_showcase();
configure_etc_hosts( $hostname, $ip );
append_history_options_to_bashrc();
add_custom_bashrc_to_bash_profile();
# set env variable
# I am not entirely sure what we need this for or if it is even needed
# leaving for now but will need to be reevaluated in later on
local $ENV{'REMOTE_USER'} = 'root';
# ensure mysql is running and accessible before creating account
set_local_mysql_root_password();
# header message for '/etc/motd' placed here to ensure it is added before anything else
add_motd("\n\nVM Setup Script created the following test accounts:\n");
create_api_token();
# create cptest account along with a test email account and database
create_primary_account();
# create a reseller account and an account owned by the reseller account
if ( not create_account( "reseller", 1, "root" ) ) {
create_account( "owned", 0, "reseller" );
}
update_tweak_settings();
disable_cphulkd();
# user has the option to make install additional components such as clamav
# this takes user input if necessary and executes these two processes if desired
handle_additional_options();
# restart cpsrvd
restart_cpsrvd();
final_words();
# since this is now a modulino, return instead of exit
return;
}
############## END OF MAIN ##########################
#
# list of subroutines for the script
#
# system_formatted() - takes a system call as an argument and uses open3() to make the syscall
# add_motd() - appends all arguments to '/etc/motd'
# get_sysinfo() - populates %sysinfo hash with data
# install_packages() - installs some useful yum packages
# set_hostname() - returns the new hostname of the server after potentially setting it
# set_local_mysql_root_password() - sets the local root password for mysql which ensures that mysql is running and we have access to it
# create_api_token() - make API call to create an API token with the 'all' acl and add the token to '/etc/motd'
# create_primary_account() - create 'cptest' cPanel acct w/ email address, db, and dbuser - then add info to '/etc/motd'
# create_account() - create a cPanel account based on the arguments passed. arg 1 is the name of the account, arg 2 is whether it is a reseller account, and arg 3 is the owner of the account
# update_tweak_settings() - update tweak settings to allow remote domains and unregisteredomains
# disable_cphulkd() - stop and disable cphulkd
# restart_cpsrvd() - restarts cpsrvd
#
# print_help_and_exit() - ran if --help is passed - prints script usage/info and exits
# check_license() - perform a cPanel license check and die if it does not succeed
# handle_lock_file() - exit if lock file exists and --force is not passed, otherwise, create lock file
# handle_additional_options() - the script user has the option to install additional software such as clam, this script handles those options
# clam_and_munin_options() - offer to install clamav and munin and install them if the user desires
# solr_option() - offer to install solr and install it if the user desires
# quotas_option() - offer to enable quotas and run fixquotas if the user desires
# pdns_option() - offer to switch to use PowerDNS and switch the nameserver to PowerDNS if the user desires
# final_words() - print some helpful output for the user before exiting
#
# setup_resolv_conf() - sets '/etc/resolv.conf' to use cPanel resolvers
# configure_99_hostname_cfg() - ensure '/etc/cloud/cloud.cfg.d/99_hostname.cfg' has proper contents
# configure_sysconfig_network() - ensure '/etc/sysconfig/network' has proper contents
# configure_mainip() - ensure '/var/cpanel/mainip' has proper contents
# configure_whostmgrft() - touch '/etc/.whostmgrft' to skip initial WHM setup
# disable_feature_showcase() - touch '/var/cpanel/activate/features/disable_feature_showcase' to disable the feature showcase
# configure_wwwacct_conf() - ensure '/etc/wwwacct.conf' has proper contents
# configure_etc_hosts() - ensure '/etc/hosts' has proper contents
# add_custom_bashrc_to_bash_profile() - append command to '/etc/.bash_profile' that changes source to https://ssp.cpanel.net/aliases/aliases.txt upon login
# append_history_options_to_bashrc() - append options to '/root/.bashrc' so that we have unlimited bash history
# create_vms_log_file() - creates the scripts log file
# append_vms_log() - appends a line (given as argument) to the scripts log file
# disable_ea4_experimental() - disables the ea4-experimental repository if yum succeeds in install_packages()
#
#
# process_output() - processes the output of syscalls passed to system_formatted()
# print_formatted() - listens to read filehandle from syscall, and prints the output to STDOUT if verbose flag is used
# set_screen_perms() - ensure 'screen' binary has proper ownership/permissions
# ensure_working_rpmdb() - make sure that rpmdb is in working order before making yum syscall
# get_answer() - determines answer from user regarding additional options. This subroutine takes a prompt string for STDOUT to the user and returns 'y' or 'n' depending on their answer
#
# print_vms() - color formatted output to make script output look better
# print_warn() - color formatted output to make script output look better
# print_info() - color formatted output to make script output look better
# print_question() - color formatted output to make script output look better
# print_command() - color formatted output to make script output look better
# print_header() - color formatted output to make print_help_and_exit() look better
# print_status() - color formatted output to make print_help_and_exit() look better
#
# _gen_pw() - returns a 25 char rand pw
# _stdin() - returns a string taken from STDIN
# _create_touch_file - take file name as argument and works similar to 'touch' command in bash
# _get_ip_and_natip() - called by get_sysinfo() to populate %sysinfo hash with system IP and NATIP
# _get_cpanel_tier - called by get_sysinfo() to populate %sysinfo hash with the cPanel tier
# _get_ostype_and_version() - called by get_sysinfo() to populate %sysinfo hash with the ostype and osversion
# _cpanel_getsysinfo() - called by get_sysinfo() to ensure that '/var/cpanel/sysinfo.config' is up to date
# _check_license() - works much like system_formatted() but is only intended for the license check
# _check_for_failure() - looks at output of the license check and dies if it fails
# _process_whmapi_output() - called by process_output() and processes the output of whmapi1 calls to ensure the call completed successfully and to check for token output
# _process_uapi_output() - called by process_output() and processes the output of UAPI calls to ensure the call copmleted successfully
#
############## BEGIN SUBROUTINES ####################
# called by process_output() and processes the output of whmapi1 calls to ensure the call completed successfully and to check for token output
# takes the output of a whmapi1 call as an argument (array)
# returns 0 if the call succeeded
# otherwise, it returns a string that contains the reason that the call failed
sub _process_whmapi_output {
my @output = @_;
my $key;
my $value;
my $reason;
foreach my $line (@output) {
if ( $line =~ /reason:/ ) {
( $key, $value ) = split /:/, $line;
$reason = $value;
}
if ( $line =~ /result:/ ) {
( $key, $value ) = split /:/, $line;
if ( $value == 0 ) {
return "whmapi call failed: $reason";
}
}
if ( $line =~ /^\s*token:/ ) {
( $key, $value ) = split /:/, $line;
add_motd( "Token name - all_access: " . $value . "\n" );
}
}
return 0;
}
# called by process_output() and processes the output of UAPI calls to ensure the call completed successfully
# takes the output of a UAPI call as an argument (array)
# returns 0 if the call succeeds
# otherwise, it returns a string that contains the reason that the call failed
sub _process_uapi_output {
my @output = @_;
my $key;
my $value;
my $error;
my $i = 0;
foreach my $line (@output) {
if ($i) {
$error = $line;
chomp($error);
$i = 0;
}
if ( $line =~ /errors:/ ) {
$i = 1;
}
if ( $line =~ /status:/ ) {
( $key, $value ) = split /:/, $line;
if ( $value == 0 ) {
return "uapi call failed: $error";
}
}
}
return 0;
}
# deterines if the command is a whmapi1 or UAPI call and calls the appropriate subroutine to handle it
# takes two arguments
# arg[0] = the command that was called
# arg 2 = an array contianing the output of the call
# return 0 if the command was an API call and it failed
# otherwise, return 1
sub process_output {
my @output = @_;
my $cmd = shift @output;
my $result;
if ( $cmd =~ /whmapi1/ ) {
$result = _process_whmapi_output(@output);
if ( $result ne '0' ) {
print_command($cmd);
print_warn($result);
return 0;
}
}
elsif ( $cmd =~ /uapi/ ) {
$result = _process_uapi_output(@output);
if ( $result ne '0' ) {
print_command($cmd);
print_warn($result);
return 0;
}
}
return;
}
# logs the output of the system call
# and prints the output to STDOUT if --verbose was passed
# takes 3 arguments
# argument 1 is the command that was passed to system_formatted()
# arguments 2 and 3 are file handles for where the system call was made
# return 0 if the system call was an API call that failed
# otherwise, return 1
sub print_formatted {
my $cmd = shift;
my $r_fh = shift;
my $e_fh = shift;
my @output = $cmd;
my $sel = IO::Select->new(); # notify us of reads on on our FHs
$sel->add($r_fh); # add the STDOUT FH
$sel->add($e_fh); # add the STDERR FH
while ( my @ready = $sel->can_read ) {
foreach my $fh (@ready) {
my $line = <$fh>;
if ( not defined $line ) { # EOF for FH
$sel->remove($fh);
next;
}
else {
push @output, $line;
}
append_vms_log($line);
if ( exists $opts{verbose} ) {
print $line;
}
}
}
return 0 if not process_output(@output);
return;
}
# takes a command to make a system call with as an argument
# uses open3() to make the system call
# if the call is a call to yum, check the return value of the call and warn if yum fails
# return 0 if the command is an API call that fails
# otherwise, return 1
sub system_formatted {
my $cmd = shift;
my ( $pid, $r_fh, $e_fh );
my $retval = 1;
append_vms_log("\nCommand: $cmd\n");
if ( exists $opts{verbose} ) {
print_command($cmd);
}
eval { $pid = open3( undef, $r_fh, $e_fh, $cmd ); };
die "open3: $@\n" if $@;
if ( not print_formatted( $cmd, $r_fh, $e_fh ) ) {
$retval = 0;
}
# wait on child to finish before proceeding
waitpid( $pid, 0 );
# process output for yum
if ( $cmd =~ /yum/ ) {
my $exit_status = $? >> 8;
if ( $exit_status && $exit_status != 0 ) {
print_command($cmd);
print_warn("Some yum modules may have failed to install, check log for detail");
}
# yum completed successfully
else {
disable_ea4_experimental();
}
}
if ( not $retval ) {
return 0;
}
else {
return;
}
}
# use String::Random to generate 25 digit password
# only use alphanumeric chars in pw
# return the pw
sub _genpw {
my $gen = String::Random->new();
return $gen->randregex('\w{25}');
}
# appends argument(s) to the end of /etc/motd
sub add_motd {
open( my $etc_motd, ">>", '/etc/motd' ) or die $!;
print $etc_motd "@_\n";
close $etc_motd;
return;
}
# get stdin from user and return it
sub _stdin {
my $string = q{};
chomp( $string = <> );
return $string;
}
# used to make print_help_and_exit() more presentable
sub print_header {
my $text = shift // '';
return if ( $text eq '' );
print BOLD CYAN "$text\n";
return;
}
# used to make print_help_and_exit() more presentable
sub print_status {
my $text = shift // '';
return if ( $text eq '' );
print YELLOW "$text\n";
return;
}
# print script usage information and exit
sub print_help_and_exit {
print_info("Usage: /usr/local/cpanel/3rdparty/bin/perl vm_setup.pl [options]");
print "\n";
print "Description: Performs a number of functions to prepare VMs (on service.cpanel.ninja) for immediate use. \n\n";
print_header("Options:");
print "-------------- \n";
print_status("--force: Ignores previous run check");
print_status("--fast: Skips all optional setup functions");
print_status("--verbose: pretty self explanatory");
print_status("--full: Passes yes to all optional setup functions");
print_status("--skipyum: Skips installing yum packages");
print_status("--skiphostname: Skips setting the hostname");
print_status("--hostname=\$hostname: allows user to provide a hostname for the system");
print_status("--tier=\$cpanel_tier: allows user to provide a cPanel update tier for the server to be set to and enables daily updates");
print_status("--bashurl=\$URL_to_bash_file: allows user to provide the URL to their own bashrc file rather than using the script's default one located at https://ssp.cpanel.net/aliases/aliases.txt");
print_status(" this option can be passed multiple times for more than one bashrc file and/or accept a ',' separated list as well.");
print_status("--skip: shortcut to passing --fast --skipyum --skiphostname");
print_status("--clam: install ClamAV regardless of --fast/--skip option being passed");
print_status("--munin: install Munin regardless of --fast/--skip option being passed");
print_status("--solr: install Solr regardless of --fast/--skip option being passed");
print_status("--quota: enable quotas regardless of --fast/--skip option being passed");
print_status("--pdns: switch nameserver to PowerDNS regardless of --fast/--skip option being passed");
print "\n";
print_info("--skiphostname and --hostname=\$hostname are mutually exclusive");
print_info("--fast and --full arguments are mutually exclusive");
print "\n";
print_header("Full list of things this does:");
print "-------------- \n";
print_status("- Installs common/useful packages");
print_status("- Install the ea4-experimental repository and disables it");
print_status("- Sets hostname");
print_status("- Updates /var/cpanel/cpanel.config (Tweak Settings)");
print_status("- Performs basic setup wizard");
print_status("- Disables feature showcase");
print_status("- Fixes /etc/hosts");
print_status("- Fixes screen permissions");
print_status("- Sets local mysql password to ensure mysql access");
print_status("- Creates test account (with email and database)");
print_status("- Disables cphulkd");
print_status("- Creates api key");
print_status("- Updates motd");
print_status("- Sets unlimited bash history");
print_status("- Creates /root/.bash_profile with helpful aliases");
print_status("- This includes a script that will allow for git auto-completion");
print_status("- Installs ClamAV, Munin, and Solr (optional)");
print_status("- Switches the nameserver to PowerDNS (optional)");
exit;
}
# script should only be run once without force
# exit if it has been ran and force not passed
# do nothing if force passed
# create lock file otherwise
sub handle_lock_file {
if ( -e "/root/vmsetup.lock" ) {
if ( exists $opts{force} ) {
print_info("/root/vmsetup.lock exists. --force passed. Ignoring...");
}
else {
print_warn("/root/vmsetup.lock exists. This script may have already been run. Use --force to bypass. Exiting...");
exit;
}
}
else {
# create lock file
print_vms("creating lock file");
_create_touch_file('/root/vmsetup.lock');
}
return;
}
# mimic bash touch command
sub _create_touch_file {
my $fn = shift;
open( my $touch_file, ">", $fn ) or die $!;
close $touch_file;
return;
}
# recreate resolv.conf using cPanel resolvers
sub setup_resolv_conf {
print_vms("Adding resolvers");
open( my $etc_resolv_conf, '>', '/etc/resolv.conf' )
or die $!;
print $etc_resolv_conf "search cpanel.net\n" . "nameserver 208.74.121.50\n" . "nameserver 208.74.125.59\n";
close($etc_resolv_conf);
return;
}
###### accepts a reference to a hash
## original declaration
##my %sysinfo = (
## "ostype" => undef,
## "osversion" => undef,
## "tier" => undef,
## "hostname" => undef,
## "ip" => undef,
## "natip" => undef,
## );
sub get_sysinfo {
# populate '/var/cpanel/sysinfo.config'
_cpanel_gensysinfo();
my $ref = shift;
# get value for keys 'ostype' and 'osversion'
_get_ostype_and_version($ref);
# get value for key 'tier'
_get_cpanel_tier($ref);
# concatanate it all together
# get value for key 'hostname'
$ref->{'hostname'} = $ref->{'ostype'} . $ref->{'osversion'} . '.' . $ref->{'tier'} . ".tld";
# get value for keys 'ip' and 'natip'
_get_ip_and_natip($ref);
return;
}
###### accepts a reference to a hash
### original declaration
###my %sysinfo = (
### "ostype" => undef,
### "osversion" => undef,
### "tier" => undef,
### "hostname" => undef,
### "ip" => undef,
### "natip" => undef,
### );
sub _get_ip_and_natip {
my $ref = shift;
open( my $fh, '<', '/var/cpanel/cpnat' )
or die $!;
while (<$fh>) {
if ( $_ =~ /^[1-9]/ ) {
( $ref->{'natip'}, $ref->{'ip'} ) = split / /, $_;
chomp( $ref->{'ip'} );
}
}
close $fh;
return;
}
###### accepts a reference to a hash
### original declaration
###my %sysinfo = (
### "ostype" => undef,
### "osversion" => undef,
### "tier" => undef,
### "hostname" => undef,
### "ip" => undef,
### "natip" => undef,
### );
sub _get_cpanel_tier {
my $ref = shift;
my $key;
open( my $fh, '<', '/etc/cpupdate.conf' )
or die $!;
while (<$fh>) {
chomp($_);
if ( $_ =~ /^CPANEL/ ) {
( $key, $ref->{'tier'} ) = split /=/, $_;
}
}
close $fh;
# replace . with - for hostname purposes
$ref->{'tier'} =~ s/\./-/g;
return;
}
###### accepts a reference to a hash
### original declaration
###my %sysinfo = (
### "ostype" => undef,
### "osversion" => undef,
### "tier" => undef,
### "hostname" => undef,
### "ip" => undef,
### "natip" => undef,
### );
sub _get_ostype_and_version {
my $ref = shift;
my $key;
open( my $fh, '<', '/var/cpanel/sysinfo.config' )
or die $!;
while (<$fh>) {
chomp($_);
if ( $_ =~ /^rpm_dist_ver/ ) {
( $key, $ref->{'osversion'} ) = split /=/, $_;
}
elsif ( $_ =~ /^rpm_dist/ ) {
( $key, $ref->{'ostype'} ) = split /=/, $_;
}
}
close $fh;
return;
}
# we need a function to process the output from system_formatted in order to catch and throw exceptions
# in particular, the 'gensysinfo' will throw an exception that needs to be caught if the rpmdb is broken
sub _cpanel_gensysinfo {
unlink '/var/cpanel/sysinfo.config';
_create_touch_file('/var/cpanel/sysinfo.config');
system_formatted("/usr/local/cpanel/scripts/gensysinfo");
return;
}
# verifies the integrity of the rpmdb and install some useful yum packages
sub install_packages {
# do not install packages if skipyum option is passed
if ( exists $opts{skipyum} ) {
print_info("skipyum option passed, no packages were installed");
return;
}
# install useful yum packages
# added perl-CDB_FILE to be installed through yum instead of cpanm
# per request, enabling the ea4-experimental repo
# adding git-extras to help automate some git tasks: https://github.com/tj/git-extras
print_vms("Installing utilities via yum [ mtr nmap telnet nc vim s3cmd bind-utils pwgen jwhois git moreutils tmux rpmrebuild rpm-build gdb perl-CDB_File perl-JSON ea4-experimental git-extras perl-Net-DNS ] (this may take a couple minutes)");
ensure_working_rpmdb();
system_formatted('/usr/bin/yum -y install mtr nmap telnet nc vim s3cmd bind-utils pwgen jwhois git moreutils tmux rpmrebuild rpm-build gdb perl-CDB_File perl-JSON ea4-experimental git-extras perl-Net-DNS');
return;
}
# takes a hostname as an argument
sub configure_99_hostname_cfg {
my $hn = shift;
if ( -e '/etc/cloud/cloud.cfg.d/' and -d '/etc/cloud/cloud.cfg.d/' ) {
# Now create a file in /etc/cloud/cloud.cfg.d/ called 99_hostname.cfg
open( my $cloud_cfg, '>', '/etc/cloud/cloud.cfg.d/99_hostname.cfg' )
or die $!;
print $cloud_cfg "#cloud-config\n" . "hostname: $hn\n";
close($cloud_cfg);
}
return;
}
# takes a hostname as an argument
sub configure_sysconfig_network {
my $hn = shift;
# set /etc/sysconfig/network
print_vms("Updating /etc/sysconfig/network");
open( my $etc_network, '>', '/etc/sysconfig/network' )
or die $!;
print $etc_network "NETWORKING=yes\n" . "NOZEROCONF=yes\n" . "HOSTNAME=$hn\n";
close($etc_network);
return;
}
# takes the systems natip as an argument
sub configure_mainip {
my $nat = shift;
print_vms("Updating /var/cpanel/mainip");
open( my $fh, '>', '/var/cpanel/mainip' )
or die $!;
print $fh "$nat";
close($fh);
return;
}
# touches '/var/cpanel/activate/features/disable_feature_showcase'
sub disable_feature_showcase {
_create_touch_file('/var/cpanel/activate/features/disable_feature_showcase');
return;
}
# touches '/etc/.whostmgrft'
sub configure_whostmgrft {
_create_touch_file('/etc/.whostmgrft');
return;
}
# takes two arguments
# arg1 = hostname
# arg2 = natip
sub configure_wwwacct_conf {
my $hn = shift;
my $nat = shift;
# correct wwwacct.conf
print_vms("Correcting /etc/wwwacct.conf");
open( my $fh, '>', '/etc/wwwacct.conf' )
or die $!;
print $fh "HOST $hn\n";
print $fh "ADDR $nat\n";
print $fh "HOMEDIR /home\n";
print $fh "ETHDEV eth0\n";
print $fh "NS ns1.os.cpanel.vm\n";
print $fh "NS2 ns2.os.cpanel.vm\n";
print $fh "NS3\n";
print $fh "NS4\n";
print $fh "HOMEMATCH home\n";
print $fh "NSTTL 86400\n";
print $fh "TTL 14400\n";
print $fh "DEFMOD paper_lantern\n";
print $fh "SCRIPTALIAS y\n";
print $fh "CONTACTPAGER\n";
print $fh "CONTACTEMAIL\n";
print $fh "LOGSTYLE combined\n";
print $fh "DEFWEBMAILTHEME paper_lantern\n";
close($fh);
return;
}
# takes two arguments
# # arg1 = hostname
# # arg2 = ip
sub configure_etc_hosts {
my $hn = shift;
my $local_ip = shift;
( my $short_hn, undef, undef ) = split /\./, $hn;
# corrent /etc/hosts
print_vms("Correcting /etc/hosts");
open( my $fh, '>', '/etc/hosts' )
or die $!;
print $fh "127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4\n";
print $fh "::1 localhost localhost.localdomain localhost6 localhost6.localdomain6\n";
print $fh "$local_ip $short_hn $hn\n";
close($fh);
return;
}
# ensure proper screen ownership/permissions
sub set_screen_perms {
print_vms("Fixing screen perms");
system_formatted('/bin/rpm --setugids screen && /bin/rpm --setperms screen');
return;
}
# fixes common issues with rpmdb if they exist
sub ensure_working_rpmdb {
system_formatted('/usr/local/cpanel/scripts/find_and_fix_rpm_issues');
return;
}
# this creates an api token and adds it to '/etc/motd'
sub create_api_token {
print_vms("Creating api token");
system_formatted('/usr/local/cpanel/bin/whmapi1 api_token_create token_name=all_access acl-1=all');
return;
}
# creates account using whmapi1
# https://documentation.cpanel.net/display/DD/WHM+API+1+Functions+-+createacct
# three arguments
# user, is a reseller account, owner of account
sub create_account {
my $user = shift;
my $is_reseller = shift;
my $owner = shift;
my $rndpass;
print_vms("Create test account - $user");
$rndpass = _genpw();
if ( not system_formatted("/usr/local/cpanel/bin/whmapi1 createacct username=$user domain=$user.tld password=$rndpass pkgname=my_package savepgk=1 maxpark=unlimited maxaddon=unlimited reseller=$is_reseller owner=$owner") and not exists $opts{force} ) {
print_warn("Failed to create account: $user.tld");
return;
}
return 0;
}
# create the primary test account
# and add one-liners to motd for access
# if the whmapi1 call to create the primary account fails, and force is not passed
# then we print a warning and fail since the rest of UAPI calls depend on this call to pass and should fail as well
sub create_primary_account {
my $rndpass;
add_motd( "one-liner for access to WHM root access:\n", q(USER=root; IP=$(awk '{print$2}' /var/cpanel/cpnat); URL=$(whmapi1 create_user_session user=$USER service=whostmgrd | awk '/url:/ {match($2,"/cpsess.*",URL)}END{print URL[0]}'); echo "https://$IP:2087$URL"), "\n" );
# create test account
print_vms("Creating test account - cptest");
$rndpass = _genpw();
if ( not system_formatted( "/usr/local/cpanel/bin/whmapi1 createacct username=cptest domain=cptest.tld password=" . $rndpass . " pkgname=my_package savepgk=1 maxpark=unlimited maxaddon=unlimited" ) and not exists $opts{force} ) {
print_warn(q[Failed to create primary account (cptest.tld), skipping additional configurations for the account]);
return;
}
add_motd( "one-liner for access to cPanel user: cptest\n", q(USER=cptest; IP=$(awk '{print$2}' /var/cpanel/cpnat); URL=$(whmapi1 create_user_session user=$USER service=cpaneld | awk '/url:/ {match($2,"/cpsess.*",URL)}END{print URL[0]}'); echo "https://$IP:2083$URL"), "\n" );
print_vms("Creating test email - testing\@cptest.tld");
$rndpass = _genpw();
system_formatted( "/usr/local/cpanel/bin/uapi --user=cptest Email add_pop email=testing\@cptest.tld password=" . $rndpass );
add_motd( "one-liner for access to test email account: testing\@cptest.tld\n", q(USER='testing@cptest.tld'; IP=$(awk '{print$2}' /var/cpanel/cpnat); URL=$(whmapi1 create_user_session user=$USER service=webmaild | awk '/url:/ {match($2,"/cpsess.*",URL)}END{print URL[0]}'); echo "https://$IP:2096$URL"), "\n" );
print_vms("Creating test database - cptest_testdb");
system_formatted("/usr/local/cpanel/bin/uapi --user=cptest Mysql create_database name=cptest_testdb");
print_vms("Creating test db user - cptest_testuser");
$rndpass = _genpw();
system_formatted( "/usr/local/cpanel/bin/uapi --user=cptest Mysql create_user name=cptest_testuser password=" . $rndpass );
add_motd("mysql test user: username: cptest_testuser");
add_motd(" password: $rndpass\n");
print_vms("Adding all privs for cptest_testuser to cptest_testdb");
system_formatted("/usr/local/cpanel/bin/uapi --user=cptest Mysql set_privileges_on_database user=cptest_testuser database=cptest_testdb privileges='ALL PRIVILEGES'");
return;
}
# update tweak settings to allow creation of nonexistent addon domains
sub update_tweak_settings {
print_vms("Updating tweak settings (cpanel.config)");
system_formatted("/usr/local/cpanel/bin/whmapi1 set_tweaksetting key=allowremotedomains value=1");
system_formatted("/usr/local/cpanel/bin/whmapi1 set_tweaksetting key=allowunregistereddomains value=1");
return;
}
# append aliases directly into STDIN upon login
sub add_custom_bashrc_to_bash_profile {
my $txt;
print_vms("Updating '/root/.bash_profile with help aliases");
open( my $fh, ">>", '/root/.bash_profile' ) or die $!;
# returns -1 if the user did not define this argument
if ( $#bashurl != -1 ) {
# allows for the user to only issue --bashurl and provide a comma separated list as well
@bashurl = split( /,/, join( ',', @bashurl ) );
# iterate through the list of URLs and append them to '/root/.bash_profile'
foreach my $url (@bashurl) {
$txt = q[ source /dev/stdin <<< "$(curl -s ] . $url . q[ )" ];
print $fh "$txt\n";
}
}
else {
$txt = q[ source /dev/stdin <<< "$(curl -s https://ssp.cpanel.net/aliases/aliases.txt)" ];
print $fh "$txt\n";
}
# add script to provide git auto-completion
$txt = q[ source /dev/stdin <<< "$(curl -s https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash)" ];
print $fh "$txt\n";
close $fh;
return;
}
# stop and disable cphulkd
sub disable_cphulkd {
print_vms("Disabling cphulkd");
system_formatted('/usr/local/cpanel/bin/whmapi1 disable_cphulk');
return;
}
# RPM versions system documentation
# https://documentation.cpanel.net/display/68Docs/RPM+Targets
# https://documentation.cpanel.net/display/68Docs/The+update_local_rpm_versions+Script
# offer to install clamav and munin
sub clam_and_munin_options {
my $answer = 0;
my $check_rpms = 0;
if ( exists $opts{clam} ) {
$answer = 'y';
}
else {
$answer = get_answer("would you like to install ClamAV? [n]: ");
}
if ( $answer eq "y" ) {
$check_rpms = 1;
print_vms("Setting ClamAV to installed");
system_formatted('/usr/local/cpanel/scripts/update_local_rpm_versions --edit target_settings.clamav installed');
}
if ( exists $opts{munin} ) {
$answer = 'y';
}
else {
$answer = get_answer("would you like to install Munin? [n]: ");
}
if ( $answer eq "y" ) {
$check_rpms = 1;
print_vms("Setting Munin to installed");
system_formatted('/usr/local/cpanel/scripts/update_local_rpm_versions --edit target_settings.munin installed');
}
if ($check_rpms) {
print_vms("running check_cpanel_rpms to install additional packages (This may take a few minutes)");
system_formatted('/usr/local/cpanel/scripts/check_cpanel_rpms --fix');
}
return;
}