diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a3bb8fc3..59159b5e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ WIP ### Enhancements +* Monolithic docker beta support ( #2632 ) * Added the GMP PHP extension to the default PHP installation ( #2676 ) ### Maintenance diff --git a/README.md b/README.md index 3a9ed604e..130938dc9 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ _VVV stands for Varying Vagrant Vagrants._ ## How To Use -To use it, download and install [Vagrant](https://www.vagrantup.com) and [VirtualBox](https://www.virtualbox.org/). Then, clone this repository and run: +To use it, download and install [Vagrant](https://www.vagrantup.com) and a provider such as [VirtualBox](https://www.virtualbox.org/), Docker, or Parallels Pro. Then, clone this repository and run: ```shell vagrant plugin install --local diff --git a/Vagrantfile b/Vagrantfile index 819a39dcc..d408b8908 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -9,6 +9,7 @@ Vagrant.require_version '>= 2.2.4' require 'yaml' require 'fileutils' require 'pathname' +require 'socket' def sudo_warnings red = "\033[38;5;9m" # 124m" @@ -216,9 +217,9 @@ defaults['memory'] = 2048 defaults['cores'] = 1 defaults['provider'] = 'virtualbox' -# if Arm default to parallels +# if Arm default to docker if Etc.uname[:version].include? 'ARM64' - defaults['provider'] = 'parallels' + defaults['provider'] = 'docker' end # This should rarely be overridden, so it's not included in the config/default-config.yml file. @@ -461,6 +462,19 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| override.vm.box = 'bento/ubuntu-20.04' end + # Docker use image. + config.vm.provider :docker do |d, override| + d.image = 'pentatonicfunk/vagrant-ubuntu-base-images:20.04' + d.has_ssh = true + d.ports = [ "80:80" ] # HTTP + d.ports += [ "443:443" ] # HTTPS + d.ports += [ "3306:3306" ] # MySQL + d.ports += [ "8025:8025" ] # Mailhog + + ## Fix goodhosts aliases format for docker + override.goodhosts.aliases = { '127.0.0.1' => vvv_config['hosts'], '::1' => vvv_config['hosts'] } + end + # Virtualbox. config.vm.provider :virtualbox do |_v, override| # Default Ubuntu Box @@ -514,7 +528,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| # Access to the guest machine is only available to your local host. To provide access to # other devices, a public network should be configured or port forwarding enabled. # - # Note: If your existing network is using the 192.168.50.x subnet, this default IP address + # Note: If your existing network is using the 192.168.56.x subnet, this default IP address # should be changed. If more than one VM is running through VirtualBox, including other # Vagrant machines, different subnets should be used for each. # @@ -884,7 +898,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| if config.vagrant.plugins.include? 'vagrant-goodhosts' config.goodhosts.aliases = vvv_config['hosts'] config.goodhosts.remove_on_suspend = true - + # goodhosts already disables clean by default, but lets enforce this at both ends config.goodhosts.disable_clean = true elsif config.vagrant.plugins.include? 'vagrant-hostsmanager' diff --git a/config/default-config.yml b/config/default-config.yml index f8f0f3505..d343fe1f4 100644 --- a/config/default-config.yml +++ b/config/default-config.yml @@ -125,6 +125,7 @@ vm_config: # provider: hyperv # provider: parallels # provider: vmware_desktop + # provider: docker # General VVV options general: diff --git a/config/homebin/vagrant_up b/config/homebin/vagrant_up index a1a3dfa85..7331d32fb 100755 --- a/config/homebin/vagrant_up +++ b/config/homebin/vagrant_up @@ -27,12 +27,25 @@ if [[ -f /srv/config/homebin/vagrant_up_custom ]]; then /srv/config/homebin/vagrant_up_custom fi +# /etc/host doesn't survive restart on docker +vvv_info " * Reinit /etc/hosts" +vvv_update_guest_hosts + vvv_info " * Restarting Nginx" sudo service nginx restart vvv_info " * Restarting MariaDB" sudo service mariadb restart +vvv_info " * Restarting PHP-FPM" +find /etc/init.d/ -name "php*-fpm" -exec bash -c 'sudo service "$(basename "$0")" restart' {} \; + +vvv_info " * Restarting Memcache" +sudo service memcached restart + +vvv_info " * Restarting Mailhog" +/usr/bin/env /usr/local/bin/mailhog > /dev/null 2>&1 & + if [ -x "$(command -v ntpdate)" ]; then vvv_info " * Syncing clocks" if sudo ntpdate -u ntp.ubuntu.com; then diff --git a/provision/core/mailhog/provision.sh b/provision/core/mailhog/provision.sh index 75b13430a..99154f63a 100644 --- a/provision/core/mailhog/provision.sh +++ b/provision/core/mailhog/provision.sh @@ -45,11 +45,14 @@ function mailhog_setup() { # Start on reboot if [ "${VVV_DOCKER}" != 1 ]; then + # no systemd vvv_info " * Enabling MailHog Service" - systemctl enable mailhog + # systemctl enable mailhog vvv_info " * Starting MailHog Service" - systemctl start mailhog + # systemctl start mailhog + /usr/bin/env /usr/local/bin/mailhog > /dev/null 2>&1 & + vvv_info " * Started MailHog Service" fi } export -f mailhog_setup @@ -57,9 +60,7 @@ export -f mailhog_setup vvv_add_hook after_packages mailhog_setup function mailhog_restart() { - if [ "${VVV_DOCKER}" != 1 ]; then - service mailhog restart - fi + killall mailhog; /usr/bin/env /usr/local/bin/mailhog > /dev/null 2>&1 & } export -f mailhog_restart diff --git a/provision/core/mariadb/config/debian.cnf b/provision/core/mariadb/config/debian.cnf new file mode 100644 index 000000000..c8e226190 --- /dev/null +++ b/provision/core/mariadb/config/debian.cnf @@ -0,0 +1,15 @@ +# THIS FILE IS OBSOLETE. STOP USING IT IF POSSIBLE. +# This file exists only for backwards compatibility for +# tools that run '--defaults-file=/etc/mysql/debian.cnf' +# and have root level access to the local filesystem. +# With those permissions one can run 'mariadb' directly +# anyway thanks to unix socket authentication and hence +# this file is useless. See package README for more info. +[client] +user = root +password = root + +[mysqladmin] +user = root +password = root +# THIS FILE WILL BE REMOVED IN A FUTURE DEBIAN RELEASE. diff --git a/provision/core/mariadb/provision.sh b/provision/core/mariadb/provision.sh index 9bcf3a5e4..702203645 100644 --- a/provision/core/mariadb/provision.sh +++ b/provision/core/mariadb/provision.sh @@ -114,6 +114,10 @@ function mysql_setup() { chmod 0644 "/home/vagrant/.my.cnf" vvv_info " * Copied /srv/provision/core/mariadb/config/root-my.cnf to /home/vagrant/.my.cnf" + # this file should been obsolete, but somehow mariadb init.d script use it + cp -f "/srv/provision/core/mariadb/config/debian.cnf" "/etc/mysql/debian.cnf" + vvv_info " * Copied /srv/provision/core/mariadb/config/debian.cnf to /etc/mysql/debian.cnf" + # Due to systemd dependencies, in docker, mysql service is not auto started vvv_info " * Ensuring MariaDB service is started" service mariadb restart @@ -125,7 +129,7 @@ function mysql_setup() { # MySQL gives us an error if we restart a non running service, which # happens after a `vagrant halt`. Check to see if it's running before # deciding whether to start or restart. - if [ $(service mariadb status|grep 'mysql start/running' | wc -l) -ne 1 ]; then + if [ $(service mariadb status|grep 'Uptime' | wc -l) -ne 1 ]; then vvv_info " * Starting the mariadb service" service mariadb start else diff --git a/provision/core/php/provision.sh b/provision/core/php/provision.sh index b418d4673..c9ec64a85 100644 --- a/provision/core/php/provision.sh +++ b/provision/core/php/provision.sh @@ -109,6 +109,11 @@ function phpfpm_setup() { fi fi done + + if [[ ! -d "/run/php" ]]; then + mkdir -p "/run/php" + chown -R www-data:www-data "/run/php" + fi } export -f phpfpm_setup diff --git a/provision/core/vvv/provision.sh b/provision/core/vvv/provision.sh index 1b6582d62..8e734a6a3 100644 --- a/provision/core/vvv/provision.sh +++ b/provision/core/vvv/provision.sh @@ -121,7 +121,7 @@ function cleanup_vvv(){ echo "127.0.0.1 tideways.vvv.test # vvv-auto" >> "/etc/hosts" echo "127.0.0.1 xhgui.vvv.test # vvv-auto" >> "/etc/hosts" fi - mv /tmp/hosts /etc/hosts + echo "$( /dev/null } export -f cleanup_vvv diff --git a/provision/provision-helpers.sh b/provision/provision-helpers.sh index 3e5fad11b..dc9c881d8 100755 --- a/provision/provision-helpers.sh +++ b/provision/provision-helpers.sh @@ -164,7 +164,8 @@ export -f network_check # # @arg $1 string name of the provisioner function log_to_file() { - local date_time=$(cat /vagrant/provisioned_at) + local date_time + date_time=$(cat /vagrant/provisioned_at) local logfolder="/var/log/provisioners/${date_time}" local logfile="${logfolder}/${1}.log" mkdir -p "${logfolder}" @@ -237,10 +238,12 @@ function vvv_format_output() { ['']="${CRESET}" ) - local MSG="${1}" + local MSG + MSG="${1}" for TAG in "${!TAGS[@]}"; do - local VAL="${TAGS[$TAG]}" - MSG=$(echo "${MSG//"${TAG}"/"${VAL}"}" ) + local VAL + VAL="${TAGS[$TAG]}" + MSG="${MSG//"${TAG}"/"${VAL}"}" done echo -e "${MSG}" } @@ -250,7 +253,8 @@ export -f vvv_format_output # # @arg $1 string The message to print function vvv_output() { - local MSG=$(vvv_format_output "${1}") + local MSG + MSG=$(vvv_format_output "${1}") echo -e "${MSG}" if [[ ! -z "${VVV_LOG}" ]]; then if [ "${VVV_LOG}" != "main" ]; then @@ -272,7 +276,8 @@ export -f vvv_info # # @arg $1 string The message to print function vvv_error() { - local MSG=$(vvv_format_output ) + local MSG + MSG=$(vvv_format_output ) vvv_output "${1}" } export -f vvv_error @@ -299,7 +304,8 @@ export -f vvv_success # @arg $1 string the path/key to read from, e.g. sites.wordpress-one.repo # @arg $2 string a default value to fall back upon function get_config_value() { - local value=$(shyaml get-value "${1}" 2> /dev/null < "${VVV_CONFIG}") + local value + value=$(shyaml get-value "${1}" 2> /dev/null < "${VVV_CONFIG}") echo "${value:-${2:-}}" } export -f get_config_value @@ -310,7 +316,8 @@ export -f get_config_value # @arg $1 string the path/key to read from, e.g. sites.wordpress-one.hosts # @arg $2 string a default value to fall back upon function get_config_values() { - local value=$(shyaml get-values "${1}" 2> /dev/null < "${VVV_CONFIG}") + local value + value=$(shyaml get-values "${1}" 2> /dev/null < "${VVV_CONFIG}") echo "${value:-${2:-}}" } export -f get_config_values @@ -320,7 +327,8 @@ export -f get_config_values # # @arg $1 string the path/key to read from, e.g. sites.wordpress-one.repo function get_config_type() { - local value=$(shyaml get-type "${1}" 2> /dev/null < "${VVV_CONFIG}") + local value + value=$(shyaml get-type "${1}" 2> /dev/null < "${VVV_CONFIG}") echo "${value}" } export -f get_config_type @@ -331,7 +339,8 @@ export -f get_config_type # @arg $1 string the path/key to read from, e.g. sites.wordpress-one.repo # @arg $2 string a default value to fall back upon function get_config_keys() { - local value=$(shyaml keys "${1}" 2> /dev/null < "${VVV_CONFIG}") + local value + value=$(shyaml keys "${1}" 2> /dev/null < "${VVV_CONFIG}") echo "${value:-${2:-}}" } export -f get_config_keys @@ -385,28 +394,30 @@ vvv_hook() { fi local hook_var_prios="VVV_HOOKS_${1}" - local start=`date +%s` + local start + start=$(date +%s) vvv_info " ▷ Running ${1} hook" eval "if [ -z \"\${${hook_var_prios}}\" ]; then return 0; fi" local sorted eval "if [ ! -z \"\${${hook_var_prios}}\" ]; then IFS=$'\n' sorted=(\$(sort -n <<<\"\${${hook_var_prios}[*]}\")); unset IFS; fi" - for i in ${!sorted[@]}; do + for i in "${!sorted[@]}"; do local prio="${sorted[$i]}" hooks_on_prio="${hook_var_prios}_${prio}[@]" for f in ${!hooks_on_prio}; do $f done done - local end=`date +%s` - vvv_success " ✔ Finished ${1} hook in `expr $end - $start`s" + local end + end=$(date +%s) + vvv_success " ✔ Finished ${1} hook in $((end - start))s" } export -f vvv_hook # @description Necessary for vvv_parallel_hook, do not use. # @internal function vvv_run_parallel_hook_function() { - eval $1 + eval "${1}" # kill all sub-processes pkill -P $$ @@ -427,13 +438,14 @@ function vvv_parallel_hook() { fi local hook_var_prios="VVV_HOOKS_${1}" - local start=`date +%s` + local start + start=$(date +%s) eval "if [ -z \"\${${hook_var_prios}}\" ]; then return 0; fi" vvv_info " ▷ Running ${1} hook" local sorted eval "if [ ! -z \"\${${hook_var_prios}}\" ]; then IFS=$'\n' sorted=(\$(sort -n <<<\"\${${hook_var_prios}[*]}\")); unset IFS; fi" - for i in ${!sorted[@]}; do + for i in "${!sorted[@]}"; do local prio="${sorted[$i]}" hooks_on_prio="${hook_var_prios}_${prio}[@]" for f in ${!hooks_on_prio}; do @@ -444,8 +456,9 @@ function vvv_parallel_hook() { vvv_info " - Subhooks completed for ${1} with priority ${prio}" done - local end=`date +%s` - vvv_success " ✔ Finished ${1} hook in `expr $end - $start`s" + local end + end=$(date +%s) + vvv_success " ✔ Finished ${1} hook in $((end - start))s" } export -f vvv_parallel_hook @@ -529,7 +542,7 @@ export -f vvv_package_install; # @arg $1 string the package to check for vvv_is_apt_pkg_installed() { # Get the number of packages installed that match $1 - num=$(dpkg --dry-run -l "${1}" 2>/dev/null | egrep '^ii' | wc -l) + num=$(dpkg --dry-run -l "${1}" 2>/dev/null | grep -E '^ii' | wc -l) if [[ $num -eq 1 ]]; then # it is installed @@ -572,7 +585,7 @@ vvv_apt_package_remove() { return 0 fi - vvv_info " * Removing ${#packages[@]} apt packages: '${packages[@]}'." + vvv_info " * Removing ${#packages[@]} apt packages: '${packages[*]}'." vvv_cleanup_dpkg_locks @@ -614,7 +627,6 @@ function vvv_maybe_install_nginx_config() { fi sudo mkdir -p "${TARGET_DIR}" - sudo cp -f "${SOURCE_FILE}" "${TARGET_FILE}" if ! sudo nginx -t; then @@ -628,15 +640,16 @@ function vvv_maybe_install_nginx_config() { return 0 } - export -f vvv_maybe_install_nginx_config; # @description Retrieves a list of sites. # @noargs function vvv_get_sites() { - local sites=$(shyaml -q keys "sites" <${VVV_CONFIG}) + local sites + sites=$(shyaml -q keys "sites" <${VVV_CONFIG}) echo "${sites}" } +export -f vvv_get_sites # @description Updates the guest environments hosts file. # @noargs @@ -644,11 +657,13 @@ function vvv_update_guest_hosts() { if test -f "/tmp/site-hosts"; then sudo rm /tmp/site-hosts fi - local SITES=$(vvv_get_sites) + local SITES + SITES=$(vvv_get_sites) for SITE in $SITES; do SITE_ESCAPED="${SITE//./\\.}" VVV_SITE_NAME=${SITE} - local value=$(shyaml -q get-values "sites.${SITE_ESCAPED}.hosts" <${VVV_CONFIG}) + local value + value=$(shyaml -q get-values "sites.${SITE_ESCAPED}.hosts" <${VVV_CONFIG}) for v in $value; do echo "127.0.0.1 ${v:-"${VVV_SITE_NAME}.test"}" >> /tmp/site-hosts done @@ -661,5 +676,44 @@ function vvv_update_guest_hosts() { sudo rm /tmp/site-hosts fi } - export -f vvv_update_guest_hosts + +# @description Performs an in place sed command via a temporary +# file to avoid permission issues +function vvv_safe_sed() { + local expression="${1}" + local file="${2}" + local tempfile + tempfile=$(mktemp /tmp/safe-sed.XXXXXX) + /usr/bin/sed "${expression}" "${file}" > "${tempfile}" + cat "${tempfile}" > "${file}" + rm "${tempfile}" +} +export -f vvv_safe_sed + +# @description Takes a string and replaces all instances of a token with a value +function vvv_search_replace() { + local content="$1" + local token="$2" + local value="$3" + + # Read the file contents and replace the token with the value + content=${content//$token/$value} + echo "${content}" +} +export -f vvv_search_replace + +# @description Takes a file, and replaces all instances of a token with a value +function vvv_search_replace_in_file() { + local file="$1" + + # Read the file contents and replace the token with the value + local content + if [[ -f "${file}" ]]; then + content=$(<"${file}") + vvv_search_replace "${content}" "${2}" "${3}" + else + return 1 + fi +} +export -f vvv_search_replace_in_file diff --git a/provision/provision-site.sh b/provision/provision-site.sh index 59e1c294c..0ce2624ca 100644 --- a/provision/provision-site.sh +++ b/provision/provision-site.sh @@ -158,11 +158,14 @@ function vvv_provision_site_nginx_config() { # We allow the replacement of the {vvv_path_to_folder} token with # whatever you want, allowing flexible placement of the site folder # while still having an Nginx config which works. - local DIR="$(dirname "${SITE_NGINX_FILE}")" - sed "s#{vvv_path_to_folder}#${DIR}#" "${SITE_NGINX_FILE}" > "${TMPFILE}" - sed -i "s#{vvv_path_to_site}#${VM_DIR}#" "${TMPFILE}" - sed -i "s#{vvv_site_name}#${SITE_NAME}#" "${TMPFILE}" - sed -i "s#{vvv_hosts}#${VVV_HOSTS}#" "${TMPFILE}" + local DIR + DIR="$(dirname "${SITE_NGINX_FILE}")" + + local NCONFIG + NCONFIG=$(vvv_search_replace_in_file "${SITE_NGINX_FILE}" "{vvv_path_to_folder}" "${DIR}") + NCONFIG=$(vvv_search_replace "${NCONFIG}" "{vvv_path_to_site}" "${VM_DIR}/") + NCONFIG=$(vvv_search_replace "${NCONFIG}" "{vvv_site_name}" "${SITE_NAME}") + NCONFIG=$(vvv_search_replace "${NCONFIG}" "{vvv_hosts}" "${VVV_HOSTS}") # if php: is configured, set the upstream to match SITE_PHP=$(vvv_get_site_php_version) @@ -177,30 +180,35 @@ function vvv_provision_site_nginx_config() { NGINX_UPSTREAM='php' fi - sed -i "s#{upstream}#${NGINX_UPSTREAM}#" "${TMPFILE}" + NCONFIG=$(vvv_search_replace "${NCONFIG}" "{upstream}" "${NGINX_UPSTREAM}") if [ -f "/srv/certificates/${SITE_NAME}/dev.crt" ]; then - sed -i "s#{vvv_tls_cert}#ssl_certificate \"/srv/certificates/${SITE_NAME}/dev.crt\";#" "${TMPFILE}" - sed -i "s#{vvv_tls_key}#ssl_certificate_key \"/srv/certificates/${SITE_NAME}/dev.key\";#" "${TMPFILE}" + NCONFIG=$(vvv_search_replace "${NCONFIG}" "{vvv_tls_cert}" "ssl_certificate \"/srv/certificates/${SITE_NAME}/dev.crt\";") + NCONFIG=$(vvv_search_replace "${NCONFIG}" "{vvv_tls_key}" "ssl_certificate_key \"/srv/certificates/${SITE_NAME}/dev.key\";") + else - sed -i "s#{vvv_tls_cert}#\# TLS cert not included as the certificate file is not present#" "${TMPFILE}" - sed -i "s#{vvv_tls_key}#\# TLS key not included as the certificate file is not present#" "${TMPFILE}" + NCONFIG=$(vvv_search_replace "${NCONFIG}" "{vvv_tls_cert}" "# TLS cert not included as the certificate file is not present") + NCONFIG=$(vvv_search_replace "${NCONFIG}" "{vvv_tls_key}" "# TLS key not included as the certificate file is not present") + fi # Resolve relative paths since not supported in Nginx root. - while grep -sqE '/[^/][^/]*/\.\.' "${TMPFILE}"; do - sed -i 's#/[^/][^/]*/\.\.##g' "${TMPFILE}" + while [[ $NCONFIG =~ /[^/][^/]*/\.\. ]]; do + NCONFIG=${NCONFIG//\/[^\/][^\/]*\/\.\./} done # "/etc/nginx/custom-sites/${DEST_NGINX_FILE}" - local DEST_NGINX_FILE=${SITE_NGINX_FILE//\/srv\/www\//} - local DEST_NGINX_FILE=${DEST_NGINX_FILE//\//\-} - local DEST_NGINX_FILE=${DEST_NGINX_FILE//-srv-provision-core-nginx-config-/\-} - local DEST_NGINX_FILE=${DEST_NGINX_FILE//-provision/} # remove the provision folder name - local DEST_NGINX_FILE=${DEST_NGINX_FILE//-.vvv/} # remove the .vvv folder name + local DEST_NGINX_FILE + DEST_NGINX_FILE=${SITE_NGINX_FILE//\/srv\/www\//} + DEST_NGINX_FILE=${DEST_NGINX_FILE//\//\-} + DEST_NGINX_FILE=${DEST_NGINX_FILE//-srv-provision-core-nginx-config-/\-} + DEST_NGINX_FILE=${DEST_NGINX_FILE//-provision/} # remove the provision folder name + DEST_NGINX_FILE=${DEST_NGINX_FILE//-.vvv/} # remove the .vvv folder name #local DEST_NGINX_FILE=${DEST_NGINX_FILE//\-\-/\-} - local DEST_NGINX_FILE=${DEST_NGINX_FILE/%-vvv-nginx.conf/} - local DEST_NGINX_FILE="vvv-${DEST_NGINX_FILE}-$(md5sum <<< "${SITE_NGINX_FILE}" | cut -c1-8).conf" + DEST_NGINX_FILE=${DEST_NGINX_FILE/%-vvv-nginx.conf/} + DEST_NGINX_FILE="vvv-${DEST_NGINX_FILE}-$(md5sum <<< "${SITE_NGINX_FILE}" | cut -c1-8).conf" + + echo "${NCONFIG}" > "${TMPFILE}" if ! vvv_maybe_install_nginx_config "${TMPFILE}" "${DEST_NGINX_FILE}" "sites"; then vvv_warn " ! This sites nginx config had problems, it may not load. Look at the above errors to diagnose the problem" @@ -216,9 +224,9 @@ function vvv_provision_site_nginx_config() { # @internal function vvv_provision_hosts_file() { local HOSTFILE=$1 - while read HOSTFILE; do - while IFS='' read -r line || [ -n "$line" ]; do - if [[ "#" != ${line:0:1} ]]; then + while read -r HOSTFILE; do + while IFS='' read -r line || [ -n "${line}" ]; do + if [[ "#" != "${line:0:1}" ]]; then if [[ -z "$(grep -q "^127.0.0.1 ${line}$" /etc/hosts)" ]]; then echo "127.0.0.1 $line # vvv-auto" >> "/etc/hosts" echo " - Added ${line} from ${HOSTFILE}"