Last active
June 27, 2017 16:18
-
-
Save witzawitz/8587fcca47415894d943bf5c1029278c to your computer and use it in GitHub Desktop.
VPS install script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
source config.sh | |
function error { | |
echo -e "\033[0;31m$1\033[0m" | |
} | |
function info { | |
echo -e "\033[0;36m$1\033[0m" | |
} | |
function message { | |
echo -e "\033[0;40m$1\033[0m" | |
} | |
function success { | |
echo -e "\033[0;32m$1\033[0m" | |
} | |
function warning { | |
echo -e "\033[0;33m$1\033[0m" | |
} | |
function apache_user { | |
users=(_www apache httpd www-data) | |
for user in ${users[*]}; do | |
result=$(groups $user 2>&1) | |
if [[ ! $result =~ "no such user" ]]; then | |
echo $user | |
return | |
fi | |
done | |
while [ 1 ]; do | |
read -r -p "Enter apache username: " user | |
result=$(groups $user 2>&1) | |
if [[ ! "$result" =~ "no such user" ]]; then | |
echo $user | |
return | |
fi | |
done | |
} | |
function check_php_ini { | |
IFS=' ' | |
read -a ini<<<"${1}" | |
echo ${1} | |
echo ${#ini[@]} | |
if [[ ${#ini[@]} == 2 ]]; then | |
echo 2 | |
fi | |
} | |
function compare_php_ini { | |
m1=$(convert_to_bytes $1) | |
m2=$(convert_to_bytes $3) | |
case $2 in | |
'>') if [[ $m1 > $m2 ]]; then echo 0; | |
else echo "more than"; fi | |
return | |
;; | |
'>=') if [[ "$m1" -ge "$m2" ]]; then echo 0; | |
else echo "at least"; fi | |
return | |
;; | |
'<') if [[ $m1 < $m2 ]]; then echo 0; | |
else echo "less then"; fi | |
return | |
;; | |
'<=') if [[ "$m1" -le "$m2" ]]; then echo 0; | |
else echo "less or equal"; fi | |
return | |
;; | |
'==') if [[ "$m1" -eq "$m2" ]]; then echo 0; | |
else echo "equal"; fi | |
return | |
;; | |
esac | |
echo "unknown operator" | |
return | |
} | |
function compare_versions { | |
IFS='.' | |
read -a version1<<<"${1}" | |
read -a version2<<<"${2}" | |
for ((i=0; i<3; i++)); do | |
if [[ ${version1[$i]}>${version2[$i]} ]]; then | |
echo 1 | |
return | |
else | |
if [[ ${version1[$i]}<${version2[$i]} ]]; then | |
echo 2 | |
return | |
fi | |
fi | |
done | |
echo 0 | |
return | |
} | |
function convert_to_bytes { | |
n=`expr ${#1} - 1` | |
if [[ $n > 0 ]]; then | |
# Last character of string. | |
m=$(echo -n $1 | tail -c 1) | |
# Other symbols | |
f=$(echo -n $1 | head -c $n) | |
case $m in | |
K) echo $((f << 10)) | |
return | |
;; | |
M) echo $((f << 20)) | |
return | |
;; | |
G) echo $((f << 30)) | |
return | |
;; | |
T) echo $((f << 40)) | |
return | |
;; | |
esac | |
fi | |
echo $1 | |
return | |
} | |
function db_load_config { | |
db_name="" | |
db_username="" | |
db_password="" | |
db_host="localhost" | |
IFS=$'\t\r\n' | |
for line in $(cat $1); do | |
if [[ $line =~ "dbname=" ]]; then | |
db_name=$(echo $line | sed "s/.*dbname//g" | sed "s/;.*//g" | sed "s/[\"',= ]//g") | |
fi | |
if [[ $line =~ "username" ]]; then | |
db_username=$(echo $line | sed "s/['\"]username['\"] *=> *//" | sed "s/[\"', ]//g") | |
fi | |
if [[ $line =~ "password" ]]; then | |
db_password=$(echo $line | sed "s/['\"]password['\"] *=> *//" | sed "s/[\"', ]//g") | |
fi | |
if [[ $line =~ "host=" ]]; then | |
db_host=$(echo $line | sed "s/.*host=//g" | sed "s/;.*//g" | sed "s/[\"',= ]//g") | |
fi | |
done | |
echo "$db_username|$db_password|$db_name|$db_host" | |
} | |
current_dir=$(pwd) | |
cd .. | |
dir=$(pwd) | |
cd $current_dir | |
# Check if current user is not root. | |
info "Checking permissions." | |
if [ "$(id -u)" == "0" ]; then | |
error "⚡️ Do not run this script as root." | |
exit | |
fi | |
echo "Current user is $(whoami)." | |
# Requirements. | |
IFS=' ' | |
if [[ " ${config[*]} " == *" requirements "* ]]; then | |
info "Checking requirements." | |
reqOk=1 | |
for item in ${req_command[*]}; do | |
if hash $item 2>/dev/null; then | |
echo "✅ $item" | |
else | |
error "⚡️ You should install $item before continue." | |
reqOk=0 | |
fi | |
done | |
if (( reqOk == 0 )); then exit; fi | |
fi | |
php_ini_command="" | |
# Ask for other php.ini file | |
php_ini_file_current=$(php -i | grep /php.ini | awk -F ' => ' '{print $2}') | |
read -e -p "Current path to php.ini config: $php_ini_file_current. If you want to change this path please enter: " php_ini_file | |
if [ ! -z "$php_ini_file" ]; then | |
php_ini_command=" -c $php_ini_file " | |
fi | |
# Check PHP version. | |
IFS=' ' | |
if [[ " ${config[*]} " == *" php-version "* ]]; then | |
info "Checking PHP version." | |
php_version_sys=$(php $php_ini_command -v | grep -m 1 -o '[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+') | |
phpOk=$(compare_versions $php_version_sys $php_version) | |
if [[ $phpOk == '2' ]]; then | |
error "⚡️ PHP required version is $php_version. Current version is $php_version_sys." | |
exit | |
fi | |
echo "✅ PHP version." | |
fi | |
# PHP extensions | |
IFS=' ' | |
if [[ " ${config[*]} " == *" php-extensions "* ]]; then | |
info "Checking PHP extensions." | |
phpextOk=1 | |
for item in ${php_extensions[*]}; do | |
if [[ $(php $php_ini_command -m | grep -i $item) == $item ]]; then | |
echo "✅ php-$item" | |
else | |
error "⚡️ You should install php-$item before continue." | |
phpextOk=0 | |
fi | |
done | |
if ((phpextOk == 0)); then exit; fi | |
fi | |
# PHP ini | |
IFS=' ' | |
if [[ " ${config[*]} " == *" php-ini "* ]]; then | |
info "Checking PHP ini settings." | |
phpiniOk=1 | |
IFS='*' | |
for ini_item in ${php_ini[*]}; do | |
IFS=' ' | |
read -a ini<<<"${ini_item}" | |
n=${#ini[@]} | |
if [[ ($n < 2) || (($n > 2) && ($((n%2)) == 0)) ]]; then | |
error "⚡️ Invalid php ini config for ${ini[0]}." | |
phpiniOk=0 | |
else | |
value=$(php $php_ini_command -i | grep ${ini[0]} | awk -F ' => ' '{print $2}') | |
# Equals | |
if [[ $n == 2 ]]; then | |
if [[ $value == ${ini[1]} ]]; then | |
echo "✅ ${ini[0]}" | |
else | |
error "⚡️ You should set ${ini[0]} ini value equal ${ini[1]}." | |
phpiniOk=0 | |
fi | |
else | |
iniOk=1 | |
msg='' | |
for ((i=1; i<$n; i+=2)); do | |
k=${ini[$i]} # operator | |
v=${ini[$i+1]} # value | |
result=$(compare_php_ini $value $k $v) | |
msg="$msg (or) $result $v" | |
if [[ "$result" == "0" ]]; then | |
iniOk=1 | |
else | |
iniOk=0 | |
fi | |
done | |
if ((iniOk == 0)); then | |
error "⚡️ ${ini[0]} should be$msg. Current value is $value." | |
phpiniOk=0 | |
else | |
echo "✅ ${ini[0]}" | |
fi | |
fi | |
fi | |
done | |
if ((phpiniOk == 0)); then exit; fi | |
fi | |
# Check composer plugins | |
IFS=' ' | |
if [[ " ${config[*]} " == *" composer "* ]]; then | |
info "Checking composer plugins." | |
for item in ${composer_plugins[*]}; do | |
if [[ $(composer global show | grep -o $item) == $item ]]; then | |
echo "✅ $item" | |
else | |
warning "Installing $item" | |
composer global require $item | |
fi | |
done | |
# Composer | |
info "Installing composer." | |
cd $dir | |
composer update $* | |
fi | |
# DB config | |
IFS=' ' | |
if [[ " ${config[*]} " == *" db "* ]]; then | |
info "Configuring DB." | |
while true; do | |
db_overwrite="n" | |
if [ -f $dir/$db_config_to ]; then | |
read -p "We found existing configuration for database. Should we overwrite it? 'y' for YES, any other key for NO. [y/n]: " db_overwrite | |
else | |
db_overwrite="y" | |
fi | |
if [[ $db_overwrite == "y" ]]; then | |
# Promt for MySQL credential | |
read -p "Do you prefer manually create MySQL database and user or should we do it for you (in that case you should provide the MySQL root password)? Hit 'm' for manually, any other key for auto creation, then press Enter. [m/a]: " db_way | |
if [[ $db_way == "m" ]]; then | |
read -p "Database username: " db_username | |
read -s -p "Database password: " db_password | |
echo "" | |
read -p "Database name: " db_name | |
else | |
read -s -p "MySQL root password: " db_root_password | |
echo "" | |
if [[ $db_root_password == "" ]]; then | |
mysql_command="sudo mysql -uroot " | |
else | |
mysql_command="sudo mysql -uroot -p$db_root_password " | |
fi | |
db_password=$(dd if=/dev/urandom bs=1 count=18 2>/dev/null | base64 | rev | cut -b 2- | rev | sed 's/[^0-9a-zA-Z]*//g' | head -c 16) | |
# Building command for setting and restoring parameters for password generation. | |
var_names=( | |
validate_password_length | |
validate_password_mixed_case_count | |
validate_password_number_count | |
validate_password_special_char_count | |
) | |
set_variables="" | |
restore_variables="" | |
for name in ${var_names[*]}; do | |
value=$($mysql_command -s -r -e "SELECT @@$name;" 2>&1 | tail -n 1) | |
if [[ "$value" != *"ERROR"* ]]; then | |
set_variables="$set_variables SET GLOBAL $name=0;" | |
restore_variables="$restore_variables SET GLOBAL $name=$value;" | |
fi | |
done | |
$($mysql_command -e "$set_variables CREATE USER '$db_username'@'localhost' IDENTIFIED BY '$db_password'; CREATE DATABASE $db_name; GRANT ALL PRIVILEGES ON $db_name.* TO '$db_username'@'localhost'; FLUSH PRIVILEGES; $restore_variables") | |
fi | |
# Write config to file | |
db_cfg_dir=$(dirname $db_config_from) | |
if [ -w $db_cfg_dir ]; then | |
db_cfg_command="" | |
else | |
db_cfg_command="sudo " | |
fi | |
IFS=$'\r\n' | |
db_cfg_lines=$(cat $dir/$db_config_from) | |
echo -n "" > $dir/$db_config_to | |
for line in $db_cfg_lines; do | |
t=$line | |
if [[ $line =~ "dbname=" ]]; then | |
t=$(echo $line | sed "s/dbname=[a-zA-Z0-9_]*/dbname=$db_name/") | |
else | |
if [[ $line =~ "username" ]]; then | |
t=$(echo $line | sed "s/['\"]username['\"] *=> *'[a-zA-Z0-9_]*'/'username' => '$db_username'/") | |
else | |
if [[ $line =~ "password" ]]; then | |
t=$(echo $line | sed "s/['\"]password['\"] *=> *'[a-zA-Z0-9_]*'/'password' => '$db_password'/") | |
fi | |
fi | |
fi | |
echo $t >> $dir/$db_config_to | |
done | |
fi | |
# Read config from file. | |
db_loaded_config=$(db_load_config $dir/$db_config_to) | |
IFS='|' | |
read -a db_cfg_loaded_array<<<"${db_loaded_config}" | |
db_username=${db_cfg_loaded_array[0]} | |
db_password=${db_cfg_loaded_array[1]} | |
db_name=${db_cfg_loaded_array[2]} | |
db_host=${db_cfg_loaded_array[3]} | |
#Testing connection. | |
db_test=$(mysql -h$db_host -u$db_username -p$db_password -e"exit" $db_name 2>&1 | grep ERROR) | |
echo $db_test | |
if [[ "$db_test" == "" ]]; then | |
break | |
else | |
db_mysql=$(pgrep mysql | wc -l | sed 's/ //g') | |
if [[ "$db_mysql" == "0" ]]; then | |
error "⚡️ MySQL server is not running." | |
else | |
db_connect=$(mysql -h$db_host -u$db_username -p$db_password -e"exit" 2>&1 | grep ERROR) | |
if [[ "$db_connect" == "" ]]; then | |
error "⚡️ Connection with provided username and password is ok but we cannot access to database $db_name." | |
else | |
error "⚡️ Cannot connect to MySQL with provided username and password." | |
fi | |
fi | |
fi | |
done | |
# Check sql_mode variable. | |
sql_mode=$(mysql -h$db_host -u$db_username -p$db_password -e"select @@sql_mode;" -s -N 2>/dev/null) | |
if [[ "$sql_mode" =~ "ONLY_FULL_GROUP_BY" ]]; then | |
error "⚡️ You should remove ONLY_FULL_GROUP_BY from @@sql_mode variable." | |
exit | |
fi | |
fi | |
# Configuring Sphinx - just copy files | |
IFS=' ' | |
if [[ " ${config[*]} " == *" sphnix "* ]]; then | |
info "Configuring Sphinx" | |
if [ ! -f $dir/$sphinx_config_conf_to ]; then | |
cp $dir/$sphinx_config_conf_from $dir/$sphinx_config_conf_to | |
fi | |
if [ ! -f $dir/$sphinx_config_php_to ]; then | |
cp $dir/$sphinx_config_php_from $dir/$sphinx_config_php_to | |
fi | |
fi | |
# Creating dirs | |
IFS=' ' | |
if [[ " ${config[*]} " == *" directories "* ]]; then | |
info "Creating directories" | |
user="$(apache_user)" | |
IFS=' ' | |
dir_s="${dirs[*]// /}" | |
cd $dir | |
sudo mkdir -p $dir_s | |
sudo chown -R $user $dir_s | |
cd $current_dir | |
# Creating symlinks | |
n=${#symlinks[@]} | |
if [[ $((n%2)) != 0 ]];then | |
error "⚡️ Wrong config for symlinks." | |
exit | |
fi | |
for ((i=0; i<$n; i+=2)); do | |
to=${symlinks[$i+1]} | |
if [ ! -L "$dir/$to" ]; then | |
cd $dir | |
symlink_dir=$(dirname $to) | |
symlink_base=$(basename $to) | |
symlink_level=$(($(grep -o "/" <<< "$symlink_dir" | wc -l)+1)) | |
symlink_level_up=`perl -E "say '../' x $symlink_level"` | |
if [ ! -f $symlink_dir ]; then | |
mkdir -p $symlink_dir | |
fi | |
cd $symlink_dir | |
echo -n "Linking ${symlinks[$i]} to $to ... " | |
sudo ln -s $symlink_level_up${symlinks[$i]} $symlink_base | |
echo "done." | |
fi | |
done | |
cd $current_dir | |
fi | |
# Migrations | |
IFS=' ' | |
if [[ " ${config[*]} " == *" migrations "* ]]; then | |
info "Running migrations." | |
cd "$dir/console" | |
sudo php yii migrate | |
fi | |
# Assets | |
IFS=' ' | |
if [[ " ${config[*]} " == *" assets "* ]]; then | |
info "Running assets" | |
IFS=$'\n' | |
n=${#assets[*]} | |
asset_cfg_loaded=false | |
asset_block=() | |
for (( i=0; i<$n; i++ )); do | |
if [[ $asset_cfg_loaded == false ]]; then | |
if [[ (${assets[$i]} == '-') || ($i == $((n-1))) ]]; then | |
asset_cfg_loaded=true | |
else | |
asset_block+=(${assets[$i]}) | |
fi | |
fi | |
if [[ $asset_cfg_loaded == true ]]; then | |
asset_dir=${asset_block[0]} | |
message "--- $asset_dir" | |
cd $dir/$asset_dir | |
for (( j=1; j<${#asset_block[*]}; j++)); do | |
eval ${asset_block[$j]} | |
done | |
asset_cfg_loaded=false | |
asset_block=() | |
fi | |
done | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment