Laravel Homestead, database provisioning
I have started to work with Homestead for a Laravel project that we are just starting, we have been using vagrant for a couple of years. In that time, to provisioning we have decided to use Chef, why?, because we thought that since chef uses ruby and vagrant uses ruby, will be easier to just learn ruby than any particular language to create the provision scripts.
Since Laravel has this already well known vagrant machine, instead of reinventing the wheel, we have decided to just use Homestead instead of create our own Vagrant machines with our own recipes. We are thinking of doing the same with Drupal VM for further projects with Drupal.
One of the things that we have in our current recipes is a step to provision the database of the application in the Vagrant machine looking for a fresh backup in our Backups repository.
We have process that two times in the day run and it create backups for all our databases, all environments. Our chef recipes look for the latest dump and then downloads the dump into the vagrant machine to uncompress it and import it in the local database. With that we have a good mechanism to have fresh data in our working environments.
I haven’t found something like that for Homestead, so I have tried to modify the provision to add this step into this machine.
I found that Homestead uses just plain ruby and does some cool stuff extending the Vagrantfile and calling shell scripts for each task when is needed.
My first idea was to modify the Homestead.rb file, however that file is into the vendor folder (I’m using one homestead for each project) and if a do a change there I’ll get in troubles with composer.
The plan B was to modify the Vagrantfile directly, so that I what I did using as sample the code in Homestead.rb.
The first step was to setup some parameters in the Homestead.yaml file, I added an array of possible databases dumps to download and in which database I need to import those dumps. I did something like this
db_dump: - db: mydb server: bkpsrepo.mycompany.com dump: mydb.dump auth: myuser:mypass
The database repository is accessible via HTTP and requires a Basic auth credentials, that is very practical to get the dump just with curl or wget (REST for the win), that is why server and auth is needed; db is the name of the database where the dump will be imported; Dump is the name of the dump file (without extensions).
A sample url to get the database will be
http://myuser:[email protected]/dbs/20170725-1502/mydb.dump.sql.bz2
The idea is to build that url, download the file to the vagrant machine, uncompressed the file, and import the sql dump.
In order to do that, in the Vagrantfile I have added these lines to iterate over the config file and get the dumps. Add these lines after the Homestead.configure.
//add this after Homestead.configure(config, settings) if settings.has_key?("db_dump") settings["db_dump"].each do |db| config.vm.provision "shell" do |s| s.name = "Importing MySQL Database: " + db["db"] s.path = "scripts/import-mysql.sh" s.args = [db["db"], db["server"], db["dump"], db["auth"]] end end end
These lines, for each dump, will call the shell script import-mysql.sh and will use the parameters defined in the args array.
Now, in the root of the laravel project, we need to create a scripts folder and then add the import-mysql.sh script. This script will do the heavy work.
#!/usr/bin/env bash #move the args to named variables DB=$1; SERVER=$2; DUMPFILE=$3; AUTH=$4 echo "Downloading data to $DUMPFILE from $DB"; #this dark line gets the date of the latest backup, isn't a genkidama DATE=`curl --silent "https://$AUTH@$SERVER/dbs/" | grep -e '-' | sed 's@[<a href="]@@g' | sed 's@/>.*@@g' | tail -1`; #builds the url URL="https://$AUTH@$SERVER/dbs/$DATE/$DUMPFILE.sql.bz2"; #gets the file to local wget -q -O /tmp/seed.sql.bz2 $URL; #uncompress the file bunzip2 /tmp/seed.sql.bz2 #imports the dump echo "Importing data to $DB from $DUMPFILE"; mysql -uhomestead -psecret $DB < /tmp/seed.sql
That’s it, now I have my provision complete!
I don’t think you can use this post just like I did, however, I expect this inspire you to implement your own mechanism. If you have some ideas how to provision the database I’ll love to ear it.
Cya in the next post.