Skip to content

Commit

Permalink
WSL Installation Upgrades and Documentation (#1958)
Browse files Browse the repository at this point in the history
* WSL Installation Upgrades and Documentation

- bin/homestead - Registered WslApplyFolderMapping command
- scripts\features\mariadb.sh - stop the mysql service before uninstall and remove the installation tracking file.
- scripts\features\mysql.sh - Create feature installation script for mysql.
- scripts\features\postgresql.sh - removed `systemctl disable postgresq` from the end to make sure it works after the feature install
- src\WslApplyFeatures.php - Changed the command name from wsl:apply-features to wsl:features.
- src\WslApplyFolderMapping.php - Added new command to do folder mapping
- src\WslCreateDatabaseCommand.php - Changed the command name from wsl:create-databases to wsl:databases.
- src\WslCreateSiteCommand.php - Changed the command name from wsl:create-sites to wsl:sites.
  - Remove nginx/sites-enabled/* as well while removing existing nginx sites.
  - Add cron job for laravel schedule:run if mentioned in yaml file.
- wsl.md - Documentation for Installing Homestead on Windows subsystem for Linux

* Style CI Fix

* Fixed a typo

* Added validations for WSL_USER_NAME and WSL_USER_GROUP

---------

Co-authored-by: Karmendra Suthar <karmendra.suthar@omniware.in>
  • Loading branch information
karmendra and Karmendra Suthar committed Apr 27, 2024
1 parent 219e126 commit 36bd28d
Show file tree
Hide file tree
Showing 10 changed files with 510 additions and 16 deletions.
1 change: 1 addition & 0 deletions bin/homestead
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ $app = new Symfony\Component\Console\Application('Laravel Homestead', '15.0.2');

$app->add(new Laravel\Homestead\MakeCommand);
$app->add(new Laravel\Homestead\WslApplyFeatures);
$app->add(new Laravel\Homestead\WslApplyFolderMapping);
$app->add(new Laravel\Homestead\WslCreateSiteCommand);
$app->add(new Laravel\Homestead\WslCreateDatabaseCommand());

Expand Down
59 changes: 57 additions & 2 deletions bin/wsl-init
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,67 @@
##################################
export DEBIAN_FRONTEND=noninteractive

echo "What is your WSL user name?"
echo "Changing current working directory to Homestead directory..."
cd "$(dirname "$0")/.."

if [[ $EUID -ne 0 ]]; then
echo "Error: This script must be run as root.">&2

exit 1
fi

UNAME=$(lsb_release -is)
if [[ "$UNAME" != "Ubuntu" ]]; then
echo "Error: WSL Homestead only supports Ubuntu Distro">&2

exit 1
fi
UBUNTU_VERSION=$(lsb_release -rs)
if [[ "$UBUNTU_VERSION" != "20.04" && "$UBUNTU_VERSION" != "22.04" ]]; then
echo "Error: WSL Homestead only supports Ubuntu 20.04 and 22.04.">&2

exit 1
fi

if [[ -f /root/.homestead-provisioned ]]; then
echo "Error: This server has already been provisioned by Laravel Homestead." >&2
echo "If you need to re-provision, you may remove the /root/.homestead-provisioned file and try again." >&2

exit 1
fi
echo "Starting..."

echo "What is your WSL user name? [vagrant]: "
read WSL_USER_NAME

echo "What is your WSL user group? (Same as username if you're unsure)"
echo "What is your WSL user group? (Same as username if you're unsure) [vagrant]: "
read WSL_USER_GROUP

# Set default
if [ -z "${WSL_USER_NAME}" ]; then
WSL_USER_NAME=vagrant
fi
if [ -z "${WSL_USER_GROUP}" ]; then
WSL_USER_GROUP=vagrant
fi

# Validate user and group
if ! id "$WSL_USER_NAME" &>/dev/null; then
echo "Error: User $WSL_USER_NAME does not exist.">&2

exit 1
fi
if ! getent group "$WSL_USER_GROUP" &>/dev/null; then
echo "Error: Group $WSL_USER_GROUP does not exist.">&2

exit 1
fi
if ! groups "$WSL_USER_NAME" | grep -q "\b$WSL_USER_GROUP\b"; then
echo "Error: User $WSL_USER_NAME is not a member of group $WSL_USER_GROUP.">&2

exit 1
fi

# Save necessary information for features
mkdir -p ~/.homestead-features
mkdir -p /home/$WSL_USER_NAME/.homestead-features
Expand Down
4 changes: 4 additions & 0 deletions scripts/features/mariadb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ chown -Rf $WSL_USER_NAME:$WSL_USER_GROUP /home/$WSL_USER_NAME/.homestead-feature
service apparmor stop
update-rc.d -f apparmor remove

# Stop MySQL service
service mysql stop
# Remove MySQL
apt-get -o Dpkg::Options::="--force-confnew" remove -y --purge mysql-server mysql-client
apt-get autoremove -y
Expand All @@ -31,6 +33,7 @@ apt-get autoclean
rm -rf /var/lib/mysql/*
rm -rf /var/log/mysql
rm -rf /etc/mysql
rm -r /home/$WSL_USER_NAME/.homestead-features/mysql

# Determine version from config
set -- "$1"
Expand All @@ -44,6 +47,7 @@ else
sudo bash mariadb_repo_setup --mariadb-server-version="$version"
echo "MariaDB specific target version : $version"
fi
apt-get update

debconf-set-selections <<< "mariadb-server mysql-server/data-dir select ''"
debconf-set-selections <<< "mariadb-server mysql-server/root_password password secret"
Expand Down
75 changes: 75 additions & 0 deletions scripts/features/mysql.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env bash

if [ -f ~/.homestead-features/wsl_user_name ]; then
WSL_USER_NAME="$(cat ~/.homestead-features/wsl_user_name)"
WSL_USER_GROUP="$(cat ~/.homestead-features/wsl_user_group)"
else
WSL_USER_NAME=vagrant
WSL_USER_GROUP=vagrant
fi

export DEBIAN_FRONTEND=noninteractive

if [ -f /home/$WSL_USER_NAME/.homestead-features/mysql ]; then
echo "Mysql already installed."
exit 0
fi

touch /home/$WSL_USER_NAME/.homestead-features/mysql
chown -Rf $WSL_USER_NAME:$WSL_USER_GROUP /home/$WSL_USER_NAME/.homestead-features

# Stop MariDB service
service mariadb stop
# Remove old PPA
rm -f /etc/apt/sources.list.d/mariadb.list*
# Remove MariaDB
apt-get -o Dpkg::Options::="--force-confnew" remove -y --purge mariadb-server mariadb-client mysql-common
apt-get autoremove -y
apt-get autoclean

rm -rf /var/lib/mysql/*
rm -rf /var/log/mysql
rm -rf /etc/mysql
rm -r /home/$WSL_USER_NAME/.homestead-features/mariadb

# Install MySQL
echo "mysql-server mysql-server/root_password password secret" | debconf-set-selections
echo "mysql-server mysql-server/root_password_again password secret" | debconf-set-selections
apt-get install -y mysql-server

# Configure MySQL 8 Remote Access and Native Pluggable Authentication
mkdir -p /etc/mysql/conf.d
cat > /etc/mysql/conf.d/mysqld.cnf << EOF
[mysqld]
bind-address = 0.0.0.0
disable_log_bin
default_authentication_plugin = mysql_native_password
EOF

# Configure MySQL Password Lifetime
echo "default_password_lifetime = 0" >> /etc/mysql/mysql.conf.d/mysqld.cnf

# Configure MySQL Remote Access
sed -i '/^bind-address/s/bind-address.*=.*/bind-address = 0.0.0.0/' /etc/mysql/mysql.conf.d/mysqld.cnf
service mysql restart

export MYSQL_PWD=secret

mysql --user="root" -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'secret';"
mysql --user="root" -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION;"
mysql --user="root" -e "CREATE USER 'homestead'@'0.0.0.0' IDENTIFIED BY 'secret';"
mysql --user="root" -e "CREATE USER 'homestead'@'%' IDENTIFIED BY 'secret';"
mysql --user="root" -e "GRANT ALL PRIVILEGES ON *.* TO 'homestead'@'0.0.0.0' WITH GRANT OPTION;"
mysql --user="root" -e "GRANT ALL PRIVILEGES ON *.* TO 'homestead'@'%' WITH GRANT OPTION;"
mysql --user="root" -e "FLUSH PRIVILEGES;"
mysql --user="root" -e "CREATE DATABASE homestead character set UTF8mb4 collate utf8mb4_bin;"

sudo tee /home/${WSL_USER_NAME}/.my.cnf <<EOL
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_bin
EOL

service mysql restart

unset MYSQL_PWD
2 changes: 0 additions & 2 deletions scripts/features/postgresql.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,3 @@ echo "host all all 10.0.2.2/32 md5" | t

sudo -u postgres /usr/bin/createdb --echo --owner=homestead homestead
service postgresql restart
# Disable to lower initial overhead
systemctl disable postgresql
12 changes: 6 additions & 6 deletions src/WslApplyFeatures.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class WslApplyFeatures extends Command
use GeneratesSlugs;

/**
* The base path of the Laravel installation.
* The base path of the Homestead installation.
*
* @var string
*/
Expand Down Expand Up @@ -55,7 +55,7 @@ protected function configure()
$this->featuresPath = getcwd().'/scripts/features';

$this
->setName('wsl:apply-features')
->setName('wsl:features')
->setDescription('Configure features in WSL from Homestead configuration')
->addOption('json', null, InputOption::VALUE_NONE, 'Determines if the Homestead settings file will be in json format.');
}
Expand All @@ -77,9 +77,9 @@ public function execute(InputInterface $input, OutputInterface $output)
$feature_cmd = '';
$feature_name = array_key_first($feature);
$feature_variables = $feature[$feature_name];

$output->writeln(PHP_EOL.($feature[$feature_name] ? '' : 'Not ').'Configuring feature: '.$feature_name);
if ($feature_variables !== false) {
$feature_path = "{$this->featuresPath}/{$feature_name}.sh > ~/.homestead-features/{$feature_name}.log";
$feature_path = "{$this->featuresPath}/{$feature_name}.sh | tee ~/.homestead-features/{$feature_name}.log";
// Prepare the feature variables if provided.
if (is_array($feature_variables)) {
$variables = join(' ', $feature_variables);
Expand All @@ -88,11 +88,11 @@ public function execute(InputInterface $input, OutputInterface $output)
$feature_cmd = "sudo -E bash {$feature_path}";
}
shell_exec($feature_cmd);
$output->writeln("Command output can be found via: sudo cat ~/.homestead-features/{$feature_name}.log");
$output->writeln("Feature installation log can be found via: sudo cat ~/.homestead-features/{$feature_name}.log");
}
}

$output->writeln('WSL features have been configured!');
$output->writeln(PHP_EOL.'WSL features have been configured!');

return 0;
}
Expand Down
67 changes: 67 additions & 0 deletions src/WslApplyFolderMapping.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace Laravel\Homestead;

use Laravel\Homestead\Settings\JsonSettings;
use Laravel\Homestead\Settings\YamlSettings;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class WslApplyFolderMapping extends Command
{
/**
* Configure the command options.
*
* @return void
*/
protected function configure()
{
$this
->setName('wsl:folders')
->setDescription('Configure folder mapping in WSL from Homestead configuration')
->addOption('json', null, InputOption::VALUE_NONE, 'Determines if the Homestead settings file will be in json format.');
}

/**
* Execute the command.
*
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
public function execute(InputInterface $input, OutputInterface $output)
{
// Grab the current settings or create an example configuration
$format = $input->getOption('json') ? 'json' : 'yaml';
$settings = $this->parseSettingsFromFile($format, []);

foreach ($settings['folders'] as $key => $folder) {
$folder_map = $folder['map'];
$folder_to = $folder['to'];
$parent_directory = dirname($folder_to);
$folder_map_cmd = "rm -r {$folder_to} ; mkdir -p {$parent_directory} && ln -s {$folder_map} {$folder_to}";
$out = shell_exec($folder_map_cmd);
print_r($out);
$output->writeln('Created symbolic link '.$folder_to.' to '.$folder_map.'.');
}

$output->writeln('WSL folders have been mapped!');

return 0;
}

/**
* @param string $format
* @param array $options
* @return mixed
*/
protected function parseSettingsFromFile(string $format, array $options)
{
$SettingsClass = ($format === 'json') ? JsonSettings::class : YamlSettings::class;
$filename = __DIR__."/../Homestead.{$format}";

return $SettingsClass::fromFile($filename)->toArray();
}
}
4 changes: 2 additions & 2 deletions src/WslCreateDatabaseCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ protected function configure()
$this->defaultProjectName = $this->slug($this->projectName);

$this
->setName('wsl:create-databases')
->setName('wsl:databases')
->setDescription('Create Databases in WSL from Homestead configuration')
->addOption('json', null, InputOption::VALUE_NONE, 'Determines if the Homestead settings file will be in json format.');
}
Expand All @@ -72,7 +72,7 @@ public function execute(InputInterface $input, OutputInterface $output)
// run command to create the database
$shell_output = shell_exec($create_cmd);
if (! is_null($shell_output)) {
var_dump($shell_output);
print_r($shell_output);
}
}
$output->writeln('WSL Databases have been created!');
Expand Down
25 changes: 21 additions & 4 deletions src/WslCreateSiteCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ protected function configure()
$this->defaultProjectName = $this->slug($this->projectName);

$this
->setName('wsl:create-sites')
->setName('wsl:sites')
->setDescription('Create Sites in WSL from Homestead configuration')
->addOption('json', null, InputOption::VALUE_NONE, 'Determines if the Homestead settings file will be in json format.');
}
Expand All @@ -62,7 +62,7 @@ protected function configure()
public function execute(InputInterface $input, OutputInterface $output)
{
// Remove any existing nginx sites
$shell_output = shell_exec('sudo rm -rf /etc/nginx/sites-available/*');
$shell_output = shell_exec('sudo rm -rf /etc/nginx/sites-available/* /etc/nginx/sites-enabled/*');
if (! is_null($shell_output)) {
var_dump($shell_output);
}
Expand All @@ -71,8 +71,9 @@ public function execute(InputInterface $input, OutputInterface $output)
$format = $input->getOption('json') ? 'json' : 'yaml';
$settings = $this->parseSettingsFromFile($format, []);

foreach ($settings['wsl_sites'] as $key => $site) {
foreach ($settings['sites'] as $key => $site) {
$type = $site['type'] ?? 'laravel';
$output->writeln('Configuring site: '.$site['map'].' of type '.$type);
$create_cmd = '';
$headers = false;
$rewrites = false;
Expand All @@ -94,7 +95,7 @@ public function execute(InputInterface $input, OutputInterface $output)
$site['to'], // $1
$site['port'] ?? 80, // $2
$site['ssl'] ?? 443, // $3
$site['php'] ?? '8.0', // $4
$site['php'] ?? '8.3', // $4
'', // $5 params
$site['xhgui'] ?? '', // $6
$site['exec'] ?? false, // $7
Expand All @@ -117,6 +118,22 @@ public function execute(InputInterface $input, OutputInterface $output)
if (! is_null($shell_output)) {
var_dump($shell_output);
}

// run command to setup schedule cron
if ($type == 'laravel' && ($site['schedule'] ?? false)) {
$output->writeln('Configuring scheduler cron ...');
$cron_cmd = "sudo -E bash {$this->basePath}/scripts/cron-schedule.sh {$site['map']} {$site['to']} {$args[4]}";
$shell_output = shell_exec($cron_cmd);
if (! is_null($shell_output)) {
var_dump($shell_output);
}
} else {
$no_cron_cmd = "sudo rm -f /etc/cron.d/{$site['map']}";
$shell_output = shell_exec($no_cron_cmd);
if (! is_null($shell_output)) {
var_dump($shell_output);
}
}
}

// Restart nginx
Expand Down

0 comments on commit 36bd28d

Please sign in to comment.