#!/usr/bin/perl ## # plBake AUTHOR: Scott Sullivan (ssullivan@liquidweb.com) # LWBake AUTHOR: Dennis Walters # # DESCRIPTION: Common methods that plBake recipes use. # use Term::ANSIColor; use POSIX qw(strftime); use vars qw($recipe); use vars qw($SRCDIR); use vars qw($src_ball); use vars qw($src_url); use vars qw($FIN_MSG); use vars qw($configure); use vars qw($php_configure); use vars qw($make_install); our $RECIPEURI='http://scripts.ssullivan.org/recipes/'; # # Helper methods ########################################################################################### ## # This method returns the path to php.ini # sub php_ini { my $call = `php -i | grep php.ini`; chomp($call); my $php_ini = substr($call, 81, 35); if ( ! -e $php_ini ) { print color 'yellow'; print "[ ",POSIX::strftime("%m/%d/%Y %H:%M:%S ", localtime) ,"] "; print color 'reset'; print "WARNING: Pure perl method failed to get location of php.ini. Trying different method...\n"; $php_ini = `php -i | grep php.ini | awk 'BEGIN \{ FS = "=>" } \; { print \$2 }' | grep php.ini | sed 's/ //g'`; chomp($php_ini); } return $php_ini; } ## # The "php_ext" method checks the system php.ini for the inclusion of the # given module. If the module is not already referenced, then a reference # is added. This check needs to be rethought. sub php_ext { my $extension = $_[0]; my $phpini = php_ini(); my $grepChk = `grep -i -c $extension $phpini`; if ( $grepChk == 0 ) { system("echo \"extension = $extension\" >> $phpini"); } } ## # The "php_config_check" method checks the php configuration for a given grep # regex to ensure the availability of functionality. sub php_config_check { my $extension = $_[0]; my $isLoaded; my $confCheck = `php -i | grep -c $extension`; if ( $confCheck == 0 ) { $isLoaded = 'false'; } else { $isLoaded = 'true'; } return $isLoaded; } ## # The "what_arch" method returns if the system is 32 or 64 bit. # sub what_arch { my $arch_chk = `uname -m`; chomp($arch_chk); my $arch; if ( $arch_chk =~ /x86_64/ ) { $arch = '64bit'; } else { $arch = '32bit'; } return $arch; } ## # Determine if the package is installed in RPM or not. Returns yes or no. # sub rpm_is_installed { my $package = $_[0]; my $return; my $rpmQuery = `rpm -qa|grep -i $package`; if ( $rpmQuery =~ /$package/ ) { $return = 'yes'; } else { $return = 'no'; } return $return; } ## # This method removes the passed packaged via yum. # sub yum_rm_package { my $package = $_[0]; my $stderr = `yum remove -y $package 2>&1 1>/dev/null`; if ( $? != 0 ) { die_log("Failed to remove $package with yum: $stderr"); } } ## # This method starts the passed service with init script in /etc/init.d. # After start cmd issued, checks to ensure it is showing in process listing. # sub start_and_check { my $init_script_name = $_[0]; my $proc_name = $_[1]; my $result; if ( ! -e "/etc/init.d/$init_script_name" ) { die_log("Init script /etc/init.d/$init_script_name cannot be found."); } my $stderr = `/etc/init.d/$init_script_name restart 2>&1 1>/dev/null`; if ( $? != 0 ) { die_log("Failed to start $init_script_name with /etc/init.d/$init_script_name: $stderr"); } my $proc_check = `pgrep $proc_name`; unless ( $proc_check ) { die_log("Started $init_script_name with /etc/init.d/$init_script_name but $proc_name is not running."); } } ## # This method returns a password of specified length. # sub pw_generate { my $password_length = $_[0]; my $password; my @chars=('a'..'z','A'..'Z','0'..'9','_','=','@','-','|','{','}','/',']','['); foreach (1..$password_length) { $password.=$chars[rand @chars]; }; return $password; } ## # This method determines the apxs to use. # sub which_apxs { my $apxs; if ( -e '/usr/local/apache/bin/apxs' ) { $apxs = '/usr/local/apache/bin/apxs'; } elsif ( -e '/usr/bin/apxs' ) { $apxs = '/usr/bin/apxs'; } else { die_log("apxs not found on system. If this box doesn't have cPanel, try installing httpd-devel."); } return $apxs; } ## # This method determines the Apache directory. # sub find_apache_dir { my $apache_dir; if ( -d '/usr/local/apache' ) { $apache_dir = '/usr/local/apache'; } elsif ( -d '/etc/httpd' ) { $apache_dir = '/etc/httpd'; } else { die_log("Couldn't find a valid Apache directory."); } return $apache_dir; } ## # This method returns the path to htpasswd. If it cannot be found, dies and logs the error. # sub find_htpasswd { my $htpasswd_path; if ( -e '/usr/local/apache/bin/htpasswd' ) { $htpasswd_path = '/usr/local/apache/bin/htpasswd'; } elsif ( -e '/usr/bin/htpasswd' ) { $htpasswd_path = '/usr/bin/htpasswd'; } else { die_log("Unable to find htpasswd on this system. Is it present?"); } return $htpasswd_path; } ## # This method is for the lulz. # sub lol { print color 'bold yellow'; print "[ ",POSIX::strftime("%m/%d/%Y %H:%M:%S ", localtime) ,"] "; print color 'reset'; print "Needs moar /scripts/easymurphy!\n"; } # # Build methods ########################################################################################### ## # The "build" method is defined with the default values here to do a # build for more or less any properly packaged autotools-based source # project, which covers a LOAD of source-based packages. If the recipe # specifies $configure, then that is used in place of stock './configure'. sub build { my $stderr; if ( $configure ) { $stderr = `cd $BUILDPREF/$SRCDIR && $configure 2>&1 1>/dev/null`; } else { $stderr = `cd $BUILDPREF/$SRCDIR && ./configure 2>&1 1>/dev/null`; } if ( $? != 0 ) { die_log("./configure threw STDERR: $stderr"); } $stderr = `cd $BUILDPREF/$SRCDIR && make 2>&1 1>/dev/null`; if ( $? != 0 ) { die_log("make threw STDERR $stderr"); } } ## # The "php_ext_build" method does a check for phpize, and runs it if found. Next, # ./configure is ran unless a custom configure is specified in the recipe via # $php_configure. After the configure process, make is ran. sub php_ext_build { my $phpizeChk = `which phpize`; chomp($phpizeChk); if ( ! -e $phpizeChk ) { die_log("phpize was not found on this system; please install it (or put in path). Detected: $phpizeChk"); } my $stderr = `cd $BUILDPREF/$SRCDIR && phpize 2>&1 1>/dev/null`; if ( $? != 0 ) { die_log("phpize threw STDERR $stderr"); } if ( $php_configure ) { $stderr = `cd $BUILDPREF/$SRCDIR && $php_configure 2>&1 1>/dev/null`; } else { $stderr = `cd $BUILDPREF/$SRCDIR && ./configure 2>&1 1>/dev/null`; } if ( $? != 0 ) { die_log("configure command threw STDERR: $stderr"); } $stderr = `cd $BUILDPREF/$SRCDIR && make 2>&1 1>/dev/null`; if ( $? != 0 ) { die_log("make threw STDERR $stderr"); } } # # Install methods ########################################################################################### ## # The "do_install" method is defined with the default values here to do a # build for more or less any properly packaged autotools-based source # project, which covers a LOAD of source-based packages. If $make_install is defined # in the recipe, that is used rather than the typical 'make install'. sub do_install { my $stderr; if ( $make_install ) { $stderr = `cd $BUILDPREF/$SRCDIR && $make_install 2>&1 1>/dev/null`; if ( $? != 0 ) { die_log("make install threw error $stderr"); } } else { $stderr = `cd $BUILDPREF/$SRCDIR && make install 2>&1 1>/dev/null`; if ( $? != 0 ) { die_log("make install threw error $stderr"); } } } ## # This method is used to install packages through yum. # sub yum_install { my $package = $_[0]; my @pre_check = `rpm -qa |grep $package`; my $stderr; if ( scalar(@pre_check) >= 1 ) { print color 'yellow'; print "[ ",POSIX::strftime("%m/%d/%Y %H:%M:%S ", localtime) ,"] "; print "$package is already installed, skipping.\n"; print color 'reset'; } else { $stderr = `yum install -y $package 2>&1 1>/dev/null`; if ( $? != 0 ) { die_log("Failed to install $package with yum: $stderr"); } } } # # Internal methods ########################################################################################### ## # Downloads and unpacks a source tar ball. # sub un_pack { my $tar_cmd; if ( $src_ball =~ /.tar.bz2/ ) { $tar_cmd = 'tar xjvf'; } elsif ( $src_ball =~ /.tar.gz/ || $src_ball =~ /.tgz/ ) { $tar_cmd = 'tar zxvf'; } else { die_log("plBake only supports bzip2 or gzip compression."); } my $stderr = `wget -O $BUILDPREF/$src_ball $src_url/$src_ball 2>&1 1>/dev/null`; if ( $? != 0 ) { die_log("Failed to download $src_url/$src_ball $stderr"); } $stderr = `cd $BUILDPREF &> /dev/null && $tar_cmd $src_ball 2>&1 1>/dev/null`; if ( $? != 0 ) { die_log("Failed to extract $src_ball $stderr"); } } ## # Die and log the error. # sub die_log { my $msg = $_[0]; my $build_log = "$BUILDPREF/$recipe.log"; open(FILE,">$build_log") || die("Cannot open $build_log"); print FILE "$msg\n"; close(FILE); print color 'red'; print "\n[ ",POSIX::strftime("%m/%d/%Y %H:%M:%S ", localtime) ,"] "; print color 'reset'; print "plBake error: error baking $recipe. Check $build_log for details.\n"; exit(1); } ## # Determine the URL to pull the recipe from. # sub gen_url { my $recipe = $_[0]; my $url = $RECIPEURI.$recipe; return $url; } ## # Display the finished message defined in the recipe to the user. # sub fin_msg { if ( $FIN_MSG ) { print color 'green'; print "[ ",POSIX::strftime("%m/%d/%Y %H:%M:%S ", localtime) ,"] "; print color 'reset'; print "$FIN_MSG\n"; } } ## # Installs any pre-reqs listed in the %SRCREQ array in the recipe. # sub bake_reqs { my $SRCREQref = $_[0]; for my $req( @{$SRCREQref} ) { is_installed("depcheck","$req"); my $req_url = gen_url($req); source_http("$req_url"); ## create the file so we know recipe is installed. system("touch $installed_dir/$req"); print color 'green'; print "[ ",POSIX::strftime("%m/%d/%Y %H:%M:%S ", localtime) ,"] "; print color 'reset'; print "Dependency $req installed successfully.\n"; }; } ## # Performs first run setup if needed # sub first_run { our $BUILDPREF = '/usr/local/src/plBake'; our $installed_dir = "$BUILDPREF/.installed"; if ( $< != 0 ) { print color 'red'; print "Must be root to bake.\n"; print color 'reset'; exit(1); } print color 'bold blue'; if ( ! -d $BUILDPREF ) { print "* Creating $BUILDPREF\n"; system("mkdir $BUILDPREF"); } if ( ! -d $installed_dir ) { print "* Creating $installed_dir\n"; system("mkdir $installed_dir"); } print color 'reset'; } ## # Determines if the recipe is already installed or not. # sub is_installed { my $arg = $_[0]; my $dep = $_[1]; if ( $arg eq 'depcheck' ) { if ( -e "$installed_dir/$dep" ) { print color 'green'; print "[ ",POSIX::strftime("%m/%d/%Y %H:%M:%S ", localtime) ,"] "; print color 'reset'; print "Dependency $dep already installed.\n"; } else { print color 'blue'; print "[ ",POSIX::strftime("%m/%d/%Y %H:%M:%S ", localtime) ,"] "; print color 'reset'; print "Baking dependency $dep...\n"; } } else { if ( -e "$installed_dir/$recipe" ) { if ( ! $params{'--refried'} ) { print "$recipe is served. Add --refried to force.\n"; exit; } elsif ( $params{'--refried'} ) { print color 'blue'; print "[ ",POSIX::strftime("%m/%d/%Y %H:%M:%S ", localtime) ,"] "; print color 'reset'; print "Refrying $recipe ... Better second time around?\n"; } } } } ## # Show basic help # sub help { print "usage - ./plBake ((--help) recipe_to_bake (--refried)) --help Shows this message. --refried Bakes the recipe regardless of a previous successful bake. recipe_to_bake This is the recipe to bake. A full list of recipes is currently available at the following URL: $RECIPEURI\n"; exit; } ## # Commands to run before we start baking the recipe. # sub pre_install { my $cmdsRef = $_[0]; my $stderr; for my $cmd( @{$cmdsRef} ) { $stderr = `$cmd`; if ( $? != 0 ) { die_log("Command failed ($cmd): $stderr"); } }; } ## # The "ldrefresh" method just refreshes the library search path cache so # that whatever it is that we just installed can be, you know, used by # the system. Since most of the things that we install are prefixed to # /usr/local, it also runs an ldcheck for /usr/local/lib. sub ldrefresh { print color 'dark blue'; print "[ ",POSIX::strftime("%m/%d/%Y %H:%M:%S ", localtime) ,"] "; print color 'reset'; print "Refreshing ld.so.cache ...\n"; system("ldcheck /usr/local/lib usr-local-lib.conf"); my $stderr = `ldconfig 2>&1 1>/dev/null`; if ( $? != 0 ) { die_log("ldconfig failed ... that's bad: $stderr"); } } ## # Flow control for plBake # sub main { if ( $params{'--help'} ) { help(); } first_run(); is_installed(); pre_install(); # For some reason, pkgconfig doesn't appear to always use its standard # search paths on our servers, so they're set here. system("export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig"); print color 'dark blue'; print "[ ",POSIX::strftime("%m/%d/%Y %H:%M:%S ", localtime) ,"] "; print color 'reset'; print "Baking $recipe ...\n"; my $url = gen_url($recipe); source_http("$url"); ## create the file so we know recipe is installed. system("touch $installed_dir/$recipe"); ldrefresh(); fin_msg(); }