PageRenderTime 1773ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/provisioners/ansible/provisioner/guest.rb

https://gitlab.com/thomasphillips3/vagrant
Ruby | 149 lines | 103 code | 28 blank | 18 comment | 13 complexity | ccb83eeac2dc002c9cd9d52052635302 MD5 | raw file
  1. require 'tempfile'
  2. require_relative "base"
  3. module VagrantPlugins
  4. module Ansible
  5. module Provisioner
  6. class Guest < Base
  7. def initialize(machine, config)
  8. super
  9. @logger = Log4r::Logger.new("vagrant::provisioners::ansible_guest")
  10. end
  11. def provision
  12. check_and_install_ansible
  13. execute_ansible_galaxy_on_guest if config.galaxy_role_file
  14. execute_ansible_playbook_on_guest
  15. end
  16. protected
  17. #
  18. # This handles verifying the Ansible installation, installing it if it was
  19. # requested, and so on. This method will raise exceptions if things are wrong.
  20. #
  21. # Current limitations:
  22. # - The installation of a specific Ansible version is not supported.
  23. # Such feature is difficult to systematically provide via package repositories (apt, yum, ...).
  24. # Installing via pip python packaging or directly from github source would be appropriate,
  25. # but these approaches require more dependency burden.
  26. # - There is no guarantee that the automated installation will replace
  27. # a previous Ansible installation.
  28. #
  29. def check_and_install_ansible
  30. @logger.info("Checking for Ansible installation...")
  31. # If the guest cannot check if Ansible is installed,
  32. # print a warning and try to continue without any installation attempt...
  33. if !@machine.guest.capability?(:ansible_installed)
  34. @machine.ui.warn(I18n.t("vagrant.provisioners.ansible.cannot_detect"))
  35. return
  36. end
  37. # Try to install Ansible (if needed and requested)
  38. if config.install &&
  39. (config.version.to_s.to_sym == :latest ||
  40. !@machine.guest.capability(:ansible_installed, config.version))
  41. @machine.ui.detail I18n.t("vagrant.provisioners.ansible.installing")
  42. @machine.guest.capability(:ansible_install)
  43. end
  44. # Check that ansible binaries are well installed on the guest,
  45. @machine.communicate.execute(
  46. "ansible-galaxy info --help && ansible-playbook --help",
  47. :error_class => Ansible::Errors::AnsibleNotFoundOnGuest,
  48. :error_key => :ansible_not_found_on_guest)
  49. # Check if requested ansible version is available
  50. if (!config.version.empty? &&
  51. config.version.to_s.to_sym != :latest &&
  52. !@machine.guest.capability(:ansible_installed, config.version))
  53. raise Ansible::Errors::AnsibleVersionNotFoundOnGuest, required_version: config.version.to_s
  54. end
  55. end
  56. def execute_ansible_galaxy_on_guest
  57. command_values = {
  58. :role_file => get_galaxy_role_file(config.provisioning_path),
  59. :roles_path => get_galaxy_roles_path(config.provisioning_path)
  60. }
  61. remote_command = config.galaxy_command % command_values
  62. execute_ansible_command_on_guest "galaxy", remote_command
  63. end
  64. def execute_ansible_playbook_on_guest
  65. prepare_common_command_arguments
  66. prepare_common_environment_variables
  67. execute_ansible_command_on_guest "playbook", ansible_playbook_command_for_shell_execution
  68. end
  69. def execute_ansible_command_on_guest(name, command)
  70. remote_command = "cd #{config.provisioning_path} && #{command}"
  71. ui_running_ansible_command name, remote_command
  72. result = execute_on_guest(remote_command)
  73. raise Ansible::Errors::AnsibleCommandFailed if result != 0
  74. end
  75. def execute_on_guest(command)
  76. @machine.communicate.execute(command, :error_check => false) do |type, data|
  77. if [:stderr, :stdout].include?(type)
  78. @machine.env.ui.info(data, :new_line => false, :prefix => false)
  79. end
  80. end
  81. end
  82. def ship_generated_inventory(inventory_content)
  83. inventory_basedir = File.join(config.tmp_path, "inventory")
  84. inventory_path = File.join(inventory_basedir, "vagrant_ansible_local_inventory")
  85. temp_inventory = Tempfile.new("vagrant_ansible_local_inventory_#{@machine.name}")
  86. temp_inventory.write(inventory_content)
  87. temp_inventory.close
  88. create_and_chown_remote_folder(inventory_basedir)
  89. @machine.communicate.tap do |comm|
  90. comm.sudo("rm -f #{inventory_path}", error_check: false)
  91. comm.upload(temp_inventory.path, inventory_path)
  92. end
  93. return inventory_basedir
  94. end
  95. def generate_inventory_machines
  96. machines = ""
  97. # TODO: Instead, why not loop over active_machines and skip missing guests, like in Host?
  98. machine.env.machine_names.each do |machine_name|
  99. begin
  100. @inventory_machines[machine_name] = machine_name
  101. if @machine.name == machine_name
  102. machines += "#{machine_name} ansible_connection=local\n"
  103. else
  104. machines += "#{machine_name}\n"
  105. end
  106. host_vars = get_inventory_host_vars_string(machine_name)
  107. machines.sub!(/\n$/, " #{host_vars}\n") if host_vars
  108. end
  109. end
  110. return machines
  111. end
  112. def create_and_chown_remote_folder(path)
  113. @machine.communicate.tap do |comm|
  114. comm.sudo("mkdir -p #{path}")
  115. comm.sudo("chown -h #{@machine.ssh_info[:username]} #{path}")
  116. end
  117. end
  118. end
  119. end
  120. end
  121. end