From 94e3a8ed94b45580c51d8edbb8418eb638e36d7c Mon Sep 17 00:00:00 2001 From: William Bradford Clark Date: Thu, 8 Sep 2022 06:46:12 -0400 Subject: [PATCH] Add a multi_ansible provisioner A box may be configured with `multi_ansible`, which specifies an ordered list of ansible provisioner names, at least one of which must be the standard name 'ansible'. Forklift will expect to find a key corresponding to each provisioner name within the top level box configuration. Each provisioner may be configured with any of the same options supported by the base ansible provisioner; you may also pass `reuse_vars: true` as a shorthand to simply copy all variables from the base 'ansible' named provisioner. For example, example-box: multi_ansible: - 'bootstrap' - 'ansible' - 'post' boostrap: reuse_vars: true config_file: ansible_bootstrap.cfg playbook: - 'playbooks/bootstrap.yml' ansible: variables: var1: "value1" playbook: - 'playbooks/main.yml' post: variables: var1: "value2" playbook: - 'user_playbooks/editor.yml' - 'user_playbooks/dotfiles.yml' Forklift will run the Ansible provisioners in stages, in the order defined by `multi_ansible`. Files named ansible_*.cfg are added to .gitignore so that the user may define additional ansible config files for their custom provisioner stages. --- .gitignore | 1 + vagrant/lib/forklift/box_distributor.rb | 25 +++++++++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 2611ee18c..d4191e88a 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ playbooks/galaxy_collections inventories/local_* user_devel_env_files/ .cache +ansible_*.cfg # Vagrant .vagrant diff --git a/vagrant/lib/forklift/box_distributor.rb b/vagrant/lib/forklift/box_distributor.rb index c8508c814..f93e5f304 100644 --- a/vagrant/lib/forklift/box_distributor.rb +++ b/vagrant/lib/forklift/box_distributor.rb @@ -92,7 +92,7 @@ def define_vm(config, box = {}) networks = configure_networks(box.fetch('networks', [])) configure_shell(machine, box) - configure_ansible(machine, box['ansible'], box['name']) + configure_multi_ansible(machine, box) configure_providers(machine, box, networks) configure_synced_folders(machine, box) configure_private_network(machine, box) @@ -174,7 +174,7 @@ def configure_networks(networks) end end - def configure_ansible(machine, ansible, box_name) + def configure_ansible(machine, ansible, box_name, extra_vars, provisioner_name) return unless ansible if ansible.key?('group') && !ansible['group'].nil? @@ -189,9 +189,9 @@ def configure_ansible(machine, ansible, box_name) return unless (playbooks = ansible['playbook']) [playbooks].flatten.each_with_index do |playbook, index| - machine.vm.provision("main#{index}", type: 'ansible') do |ansible_provisioner| + machine.vm.provision("#{provisioner_name}-#{index}", type: 'ansible', preserve_order: true) do |ansible_provisioner| ansible_provisioner.playbook = playbook - ansible_provisioner.extra_vars = ansible['variables'] + ansible_provisioner.extra_vars = extra_vars ansible_provisioner.groups = @ansible_groups ansible_provisioner.verbose = ansible['verbose'] || false %w[config_file galaxy_role_file inventory_path].each do |key| @@ -203,6 +203,23 @@ def configure_ansible(machine, ansible, box_name) end end + def configure_multi_ansible(machine, box) + ansible_provisioner_names = box.fetch('multi_ansible', ['ansible']) + return unless ansible_provisioner_names.include?('ansible') + + primary_ansible = box['ansible'] + return unless primary_ansible + + primary_ansible_vars = primary_ansible['variables'] + box_name = box['name'] + + ansible_provisioner_names.each do |provisioner_name| + ansible = box[provisioner_name] + extra_vars = ansible.fetch('reuse_vars', false) ? primary_ansible_vars : ansible['variables'] + configure_ansible(machine, ansible, box_name, extra_vars, provisioner_name) + end + end + def configure_shell(machine, box) return unless box.key?('shell') && !box['shell'].nil?