Keep database synced between computers in Trellis/Bedrock/Sage setup

Ok I just tried my custom vagrant-triggers and can confirm it doesn’t work anymore with Trellis 0.9.5 and up.
The problem is, the trigger commands need to read the database credentials in the wordpress_sites loop, but since the db_password variable is moved to the (encrypted) vault.yml, the database dump or import won’t succeed because there is no password set in the command. So I’m trying something like this now:

config_file = File.join(ANSIBLE_PATH, 'group_vars', 'development', 'wordpress_sites.yml')
vault_file = File.join(ANSIBLE_PATH, 'group_vars', 'development', 'vault.yml')

if File.exists?(config_file)
  wordpress_sites = YAML.load_file(config_file)['wordpress_sites']
  vaults = YAML.load_file(vault_file)['vaults'] --vault-password-file .vault_pass
  #vaults = ansible-vault YAML.load_file(vault_file)
  fail_with_message "No sites found in #{config_file}." if wordpress_sites.to_h.empty?
else
  fail_with_message "#{config_file} was not found. Please set `ANSIBLE_PATH` in your Vagrantfile."
end

# Vagrant Triggers
#
# If the vagrant-triggers plugin is installed, we can run various scripts on Vagrant
# state changes like `vagrant up`, `vagrant halt`, `vagrant suspend`, and `vagrant destroy`
#
# These scripts are run on the host machine, so we use `vagrant ssh` to tunnel back
# into the VM and execute things.
#
if Vagrant.has_plugin? 'vagrant-triggers'

  vaults.each_pair do |vault|
    #
    # Get database password
    #
    db_pass  = vault['env']['db_password']
  end

  wordpress_sites.each_pair do |site|
    #
    # Get database credentials
    #
    db_name  = site['env']['db_name']
    db_user  = site['env']['db_user']
    #
    # Importing database
    #
    config.trigger.after [:up, :resume, :reload], :force => true do
      info "Importing databases"
      run_remote  "cd /srv/database/backups/ mysql -u #{db_user} -p#{db_pass} #{db_name} < /srv/database/backups/#{db_name}.sql"
    end
    #
    # Exporting database
    #
    config.trigger.before [:halt, :suspend, :destroy], :force => true do
      info "Dumping databases"
      run_remote "mysqldump -u #{db_user} -p#{db_pass} #{db_name} > /srv/database/backups/#{db_name}.sql"
    end
  end
else
  puts 'vagrant-triggers missing, please install the plugin:'
  puts 'vagrant plugin install vagrant-triggers'
end

But that’s obviously not working yet…

How exactly can I load and set the db_password variables from the encrypted group_vars/development/vault.yml file?
http://docs.ansible.com/ansible/playbooks_vault.html#viewing-encrypted-files

Or is this not gonna work like this?
Any help is welcome, thanks!

1 Like

Ok, for now I’m not going to encrypt my groups_vars/development/vault.yml file to be able to read the db_password variables. However, since I’m not a Ruby expert;

At the top of my Vagrantfile I set the vault_wordpress_sites variable like this:

vault_file = File.join(ANSIBLE_PATH, 'group_vars', 'development', 'vault.yml')

if File.exists?(vault_file)
  vault_wordpress_sites = YAML.load_file(vault_file)['vault_wordpress_sites']
  fail_with_message "No sites found in #{vault_file}." if vault_wordpress_sites.to_h.empty?
else
  fail_with_message "#{vault_file} was not found. Please set `ANSIBLE_PATH` in your Vagrantfile."
end

Somehow I need to read the db_password variable from this vault_wordpress_sites array inside the existing wordpress_sites loop, something like this (but with correct syntax):

wordpress_sites.each_pair do |name, site|
      #
      # Get database credentials
      #
      db_name  = site['env']['db_name']
      db_user  = site['env']['db_user']
      #db_pass  = vault_wordpress_sites.#{index}.env.db_password
end

But I have no clue how to approach this… Anyone familiar with Ruby loops?
Thanks!

Got a bit further, loop is working now:

vault_passes = Array.new
vault_wordpress_sites.each_pair do |name, vault|
  db_pass  = vault['env']['db_password']
  vault_passes.push db_pass
end

wordpress_sites.each_with_index do |(name, site), index|
  #
  # Get database credentials
  #
  db_name  = site['env']['db_name']
  db_user  = site['env']['db_user']
  db_pass  = vault_passes[index]
  #
  # Importing database
  #
  config.trigger.after [:up, :resume, :reload], :force => true do
    info "Importing databases"
    run_remote "cd /srv/database/backups/ mysql -u #{db_user} -p#{db_pass} #{db_name} < /srv/database/backups/#{db_name}.sql"
  end
  #
  # Exporting database
  #
  config.trigger.before [:halt, :suspend, :destroy], :force => true do
    info "Dumping databases"
    run_remote "mysqldump -u #{db_user} -p#{db_pass} #{db_name} > /srv/database/backups/#{db_name}.sql"
  end
end

You can simplify this a lot:

config_file = File.join(ANSIBLE_PATH, 'group_vars', 'development', 'wordpress_sites.yml')
vault_file = File.join(ANSIBLE_PATH, 'group_vars', 'development', 'vault.yml')

vault_sites = YAML.load_file(vault_file)['vault_wordpress_sites']

wordpress_sites.each do |(name, site)|
  site['env'].merge!(vault_sites[name]['env'])

  # triggers in here
end
1 Like

Thanks, gonna try that next time!

Yup, that works great, thanks!
My updated triggers look like this now:

vault_file = File.join(ANSIBLE_PATH, 'group_vars', 'development', 'vault.yml')
vault_sites = YAML.load_file(vault_file)['vault_wordpress_sites']

# Vagrant Triggers
#
# If the vagrant-triggers plugin is installed, we can run various scripts on Vagrant
# state changes like `vagrant up`, `vagrant halt`, `vagrant suspend`, and `vagrant destroy`
#
# These scripts are run on the host machine, so we use `vagrant ssh` to tunnel back
# into the VM and execute things.
#
if Vagrant.has_plugin? 'vagrant-triggers'    
  wordpress_sites.each do |(name, site)|
    #
    # Get database credentials
    #
    site['env'].merge!(vault_sites[name]['env'])
    db_name  = site['env']['db_name']
    db_user  = site['env']['db_user']
    db_pass  = site['env']['db_password']
    #
    # Importing database
    #
    config.trigger.after [:up, :resume, :reload], :force => true do
      info "Importing databases"
      run_remote "mysql -u #{db_user} -p#{db_pass} #{db_name} < /srv/database/backups/#{db_name}.sql"
    end
    #
    # Exporting database
    #
    config.trigger.before [:halt, :suspend, :destroy], :force => true do
      info "Dumping databases"
      run_remote "mysqldump -u #{db_user} -p#{db_pass} #{db_name} > /srv/database/backups/#{db_name}.sql"
    end
  end
else
  puts 'vagrant-triggers missing, please install the plugin:'
  puts 'vagrant plugin install vagrant-triggers'
end
4 Likes

I have setup Trellis with an existing WP site. I’d like to use this solution to sync the database. But, I’m getting the following error message:

/trellis/Vagrantfile:145:in block (2 levels) in <top (required)>': undefined method 'merge!' for nil:NilClass (NoMethodError)

Just started to search around for solution. Thought I would post here first to see if anyone else has experienced this problem.

Did you encrypt your vault file by any chance? Because in that case it won’t be able to load the file:

vault_sites = YAML.load_file(vault_file)['vault_wordpress_sites']

and execute the merge, resulting in that error.
Haven’t found a solution for this yet, that’s why I don’t encrypt my development vault files for now.

No, I am not encrypting. I just copied and pasted your code into the main Vagrantfile. Is that the correct method?

Yes basically, it should work?
Did you try outputting the vars:
puts site['env']
and
puts vault_sites[name]['env']
and see what the output is?
Is your site up and running besides this?

Thanks for the comment. It lead me to what I think is the problem.

I do not have an env set in my wordpress_sites.yml file. I was counting on the default settings in the all/main.yml file.

The error is gone. Now to get the triggers working.

I have the same problem you mentioned in your previous post. Can you show me an example of your dev wordpress_sites and vault setup? Sorry a newbie so I might have configured it wrong. The triggers are added to the vagrant file at the end correct?

There is this plugin: https://github.com/wp-sync-db/wp-sync-db

I made a public repo for this: https://github.com/Twansparant/trellis-db-sync

3 Likes

wp-sync-db is just a rip off of migrate db pro. While legal, is not nice…

5 Likes

If it’s licensed as an open source and working into an open source ecosystem I’m not sure the term “rip off” makes sense ?

1 Like

How about “unethical”? Do the right thing — if you find it useful, pay for the license through Delicious Brains.

3 Likes

Delicious Brains choosed their bussiness model GPL based. It was their own choice. Has no sense to get upset if somebody fork it. Has no sense to wield “unethical” flag against GPL freedom terms. That is really “unethical”.

I’m sorry, but just because they’re using the GPL license doesn’t mean it’s suddenly fine to be using rip-offs of someone’s software.

How do you think we would react to people taking our paid plugins and then re-distributing them for free?

Do you think it’s okay to sign up for one of the many ‘GPL Clubs’ around, that give you access to a wide variety of WordPress plugins by paying a small fee? That fee doesn’t go to any of the people that wrote those plugins.

:rolling_eyes:

4 Likes

To use, modify or redistribute GPL software is not a rip-off. Rip-off implies something ilegal. If you are impeding the freedoms guaranteed by the license, that is a rip-off.

You were less wrong using “unethical” term since ethic is a grayscale zone and can be discussed.

You should keep in mind that you can write plugins for a lot of people just because the GPL ecosystem built a very big community of users. All this people adopt this ecosystem because they can feel it as their collective property. If you do not respect the terms of the GPL you are damaging that ecosystem. Wordpress is clear about it: “If you disagree, you might want to consider a non-GPL platform such as Serendipity (BSD license) or Habari (Apache license) instead.”

So, although I am not a friend of opportunism and I don’t like those GPL clubs, the dilemma is between two choices: To preserve the ecosystem or to preserve your personal profits. I understand that personal profits of software development are very important to software developers, but it can’t be defended with ethical arguments against GPL terms.

A metaphor: think in a lumberjack in the forest. He can persevere their profits against forest environment. If you, as a developer, make GPL software, you are seeding more trees in that forest. Otherwise, you are the lumberjack.

So, how can I survive as a developer in a GPL environment? This is a complex discussion and I’m afraid it exceed the topic of this forum. Anyway, it includes concepts like “real time economy”, “attention economy” and “economy of services”. I will be happy to discuss this further if you deem it appropriate.

Just to say that, in wp-sync-db case, I prefer clearly to buy a complete functional WP Migrate DB Pro plugin, and avoid to hack trellis to adapt it to wp-sync-db needs, but my personal situation is very hard, actually, without resources to cover my basic needs. So, to find free resources is mandatory until I get afloat.

So, unlist my previous thread was a bad decision:
https://discourse.roots.io/t/can-i-downgrade-composer/9703
Because this decision was completely based on a arguable opinion and, in strictly sense, it can be considered censorship. This kind of decision hurts me since internally I’m involved with the roots community (despite my low level as a front-end developer). I learned a lot and I got huge satisfaction here.

3 Likes