smart_proxy_ansible 3.2.1 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/lib/smart_proxy_ansible/api.rb +11 -3
 - data/lib/smart_proxy_ansible/configuration_loader.rb +20 -0
 - data/lib/smart_proxy_ansible/exception.rb +3 -0
 - data/lib/smart_proxy_ansible/playbooks_reader.rb +37 -0
 - data/lib/smart_proxy_ansible/plugin.rb +3 -16
 - data/lib/smart_proxy_ansible/reader_helper.rb +44 -0
 - data/lib/smart_proxy_ansible/roles_reader.rb +3 -36
 - data/lib/smart_proxy_ansible/runner/ansible_runner.rb +47 -4
 - data/lib/smart_proxy_ansible/task_launcher/ansible_runner.rb +1 -1
 - data/lib/smart_proxy_ansible/validate_settings.rb +7 -0
 - data/lib/smart_proxy_ansible/version.rb +1 -1
 - data/lib/smart_proxy_ansible.rb +4 -0
 - metadata +7 -3
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 4a1934350dedb103c779cdf61196cff80a43751d260fd5f550d26289dc63f388
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: cee72032c8d95fde92021ef8c312e9c4f0408b9ac1d88b5a0ebf9cdd97bc906c
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: a473838108c4b9cbcef9da311410a2fda5bc39047a2cd4c623533ef718918583de1c830105b92a52303bfc41e1eeb933f1d4a898380a0cf9b01c32d7fb07cb76
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: cf1aa8ca722850fd39d312cefcbf178e193fcf391ca8058638dd26db01c288f7350ea6c80e5fb004e87cdda664f5200f24b83b61a2dc3226d88006d0efff7cb3
         
     | 
| 
         @@ -28,15 +28,23 @@ module Proxy 
     | 
|
| 
       28 
28 
     | 
    
         
             
                    {}.to_json
         
     | 
| 
       29 
29 
     | 
    
         
             
                  end
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
      
 31 
     | 
    
         
            +
                  get '/playbooks_names' do
         
     | 
| 
      
 32 
     | 
    
         
            +
                    PlaybooksReader.playbooks_names.to_json
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  get '/playbooks/:playbooks_names?' do
         
     | 
| 
      
 36 
     | 
    
         
            +
                    PlaybooksReader.playbooks(params[:playbooks_names]).to_json
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
       31 
39 
     | 
    
         
             
                  private
         
     | 
| 
       32 
40 
     | 
    
         | 
| 
       33 
41 
     | 
    
         
             
                  def extract_variables(role_name)
         
     | 
| 
       34 
42 
     | 
    
         
             
                    variables = {}
         
     | 
| 
       35 
43 
     | 
    
         
             
                    role_name_parts = role_name.split('.')
         
     | 
| 
       36 
44 
     | 
    
         
             
                    if role_name_parts.count == 3
         
     | 
| 
       37 
     | 
    
         
            -
                       
     | 
| 
       38 
     | 
    
         
            -
                        variables[role_name]  
     | 
| 
       39 
     | 
    
         
            -
                                               .extract_variables("#{path}/ansible_collections/#{role_name_parts[0]}/#{role_name_parts[1]}/roles/#{role_name_parts[2]}")
         
     | 
| 
      
 45 
     | 
    
         
            +
                      ReaderHelper.collections_paths.split(':').each do |path|
         
     | 
| 
      
 46 
     | 
    
         
            +
                        variables[role_name] = VariablesExtractor
         
     | 
| 
      
 47 
     | 
    
         
            +
                                               .extract_variables("#{path}/ansible_collections/#{role_name_parts[0]}/#{role_name_parts[1]}/roles/#{role_name_parts[2]}") if variables[role_name].nil? || variables[role_name].empty?
         
     | 
| 
       40 
48 
     | 
    
         
             
                      end
         
     | 
| 
       41 
49 
     | 
    
         
             
                    else
         
     | 
| 
       42 
50 
     | 
    
         
             
                      RolesReader.roles_path.split(':').each do |path|
         
     | 
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Proxy::Ansible
         
     | 
| 
      
 2 
     | 
    
         
            +
              class ConfigurationLoader
         
     | 
| 
      
 3 
     | 
    
         
            +
                def load_classes
         
     | 
| 
      
 4 
     | 
    
         
            +
                  require 'smart_proxy_dynflow'
         
     | 
| 
      
 5 
     | 
    
         
            +
                  require 'smart_proxy_dynflow/continuous_output'
         
     | 
| 
      
 6 
     | 
    
         
            +
                  require 'smart_proxy_ansible/task_launcher/ansible_runner'
         
     | 
| 
      
 7 
     | 
    
         
            +
                  require 'smart_proxy_ansible/task_launcher/playbook'
         
     | 
| 
      
 8 
     | 
    
         
            +
                  require 'smart_proxy_ansible/actions'
         
     | 
| 
      
 9 
     | 
    
         
            +
                  require 'smart_proxy_ansible/remote_execution_core/ansible_runner'
         
     | 
| 
      
 10 
     | 
    
         
            +
                  require 'smart_proxy_ansible/runner/ansible_runner'
         
     | 
| 
      
 11 
     | 
    
         
            +
                  require 'smart_proxy_ansible/runner/command_creator'
         
     | 
| 
      
 12 
     | 
    
         
            +
                  require 'smart_proxy_ansible/runner/playbook'
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  Proxy::Dynflow::TaskLauncherRegistry.register('ansible-runner',
         
     | 
| 
      
 15 
     | 
    
         
            +
                                                                TaskLauncher::AnsibleRunner)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  Proxy::Dynflow::TaskLauncherRegistry.register('ansible-playbook',
         
     | 
| 
      
 17 
     | 
    
         
            +
                                                                TaskLauncher::Playbook)
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -37,5 +37,8 @@ module Proxy 
     | 
|
| 
       37 
37 
     | 
    
         
             
                class ReadConfigFileException < Proxy::Ansible::Exception; end
         
     | 
| 
       38 
38 
     | 
    
         
             
                class ReadRolesException < Proxy::Ansible::Exception; end
         
     | 
| 
       39 
39 
     | 
    
         
             
                class ReadVariablesException < Proxy::Ansible::Exception; end
         
     | 
| 
      
 40 
     | 
    
         
            +
                class NotExistingWorkingDirException < Proxy::Ansible::Exception; end
         
     | 
| 
      
 41 
     | 
    
         
            +
                class ReadPlaybooksNamesException < Proxy::Ansible::Exception; end
         
     | 
| 
      
 42 
     | 
    
         
            +
                class ReadPlaybooksException < Proxy::Ansible::Exception; end
         
     | 
| 
       40 
43 
     | 
    
         
             
              end
         
     | 
| 
       41 
44 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Proxy
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Ansible
         
     | 
| 
      
 3 
     | 
    
         
            +
                # Implements the logic needed to read the playbooks and associated information
         
     | 
| 
      
 4 
     | 
    
         
            +
                class PlaybooksReader
         
     | 
| 
      
 5 
     | 
    
         
            +
                  class << self
         
     | 
| 
      
 6 
     | 
    
         
            +
                    def playbooks_names
         
     | 
| 
      
 7 
     | 
    
         
            +
                      ReaderHelper.collections_paths.split(':').flat_map { |path| get_playbooks_names(path) }
         
     | 
| 
      
 8 
     | 
    
         
            +
                    end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                    def playbooks(playbooks_to_import)
         
     | 
| 
      
 11 
     | 
    
         
            +
                      ReaderHelper.collections_paths.split(':').reduce([]) do |playbooks, path|
         
     | 
| 
      
 12 
     | 
    
         
            +
                        playbooks.concat(read_collection_playbooks(path, playbooks_to_import))
         
     | 
| 
      
 13 
     | 
    
         
            +
                      end
         
     | 
| 
      
 14 
     | 
    
         
            +
                    end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    def get_playbooks_names(collections_path)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      Dir.glob("#{collections_path}/ansible_collections/*/*/playbooks/*").map do |path|
         
     | 
| 
      
 18 
     | 
    
         
            +
                        ReaderHelper.playbook_or_role_full_name(path)
         
     | 
| 
      
 19 
     | 
    
         
            +
                      end
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    def read_collection_playbooks(collections_path, playbooks_to_import = nil)
         
     | 
| 
      
 23 
     | 
    
         
            +
                      Dir.glob("#{collections_path}/ansible_collections/*/*/playbooks/*").map do |path|
         
     | 
| 
      
 24 
     | 
    
         
            +
                        name = ReaderHelper.playbook_or_role_full_name(path)
         
     | 
| 
      
 25 
     | 
    
         
            +
                        {
         
     | 
| 
      
 26 
     | 
    
         
            +
                          name: name,
         
     | 
| 
      
 27 
     | 
    
         
            +
                          playbooks_content: File.readlines(path)
         
     | 
| 
      
 28 
     | 
    
         
            +
                        } if playbooks_to_import.nil? || playbooks_to_import.include?(name)
         
     | 
| 
      
 29 
     | 
    
         
            +
                      end.compact
         
     | 
| 
      
 30 
     | 
    
         
            +
                    rescue Errno::ENOENT, Errno::EACCES => e
         
     | 
| 
      
 31 
     | 
    
         
            +
                      message = "Could not read Ansible playbooks #{collections_path} - #{e.message}"
         
     | 
| 
      
 32 
     | 
    
         
            +
                      raise ReadPlaybooksException, message
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -8,22 +8,9 @@ module Proxy 
     | 
|
| 
       8 
8 
     | 
    
         
             
                  default_settings :ansible_dir => Dir.home
         
     | 
| 
       9 
9 
     | 
    
         
             
                                   # :working_dir => nil
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
                   
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
                    require 'smart_proxy_ansible/task_launcher/ansible_runner'
         
     | 
| 
       15 
     | 
    
         
            -
                    require 'smart_proxy_ansible/task_launcher/playbook'
         
     | 
| 
       16 
     | 
    
         
            -
                    require 'smart_proxy_ansible/actions'
         
     | 
| 
       17 
     | 
    
         
            -
                    require 'smart_proxy_ansible/remote_execution_core/ansible_runner'
         
     | 
| 
       18 
     | 
    
         
            -
                    require 'smart_proxy_ansible/runner/ansible_runner'
         
     | 
| 
       19 
     | 
    
         
            -
                    require 'smart_proxy_ansible/runner/command_creator'
         
     | 
| 
       20 
     | 
    
         
            -
                    require 'smart_proxy_ansible/runner/playbook'
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                    Proxy::Dynflow::TaskLauncherRegistry.register('ansible-runner',
         
     | 
| 
       23 
     | 
    
         
            -
                      TaskLauncher::AnsibleRunner)
         
     | 
| 
       24 
     | 
    
         
            -
                    Proxy::Dynflow::TaskLauncherRegistry.register('ansible-playbook',
         
     | 
| 
       25 
     | 
    
         
            -
                      TaskLauncher::Playbook)
         
     | 
| 
       26 
     | 
    
         
            -
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
                  load_classes ::Proxy::Ansible::ConfigurationLoader
         
     | 
| 
      
 12 
     | 
    
         
            +
                  load_validators :validate_settings => ::Proxy::Ansible::ValidateSettings
         
     | 
| 
      
 13 
     | 
    
         
            +
                  validate :validate!, :validate_settings => nil
         
     | 
| 
       27 
14 
     | 
    
         
             
                end
         
     | 
| 
       28 
15 
     | 
    
         
             
              end
         
     | 
| 
       29 
16 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,44 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Proxy
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Ansible
         
     | 
| 
      
 3 
     | 
    
         
            +
                # Helper for Playbooks Reader
         
     | 
| 
      
 4 
     | 
    
         
            +
                class ReaderHelper
         
     | 
| 
      
 5 
     | 
    
         
            +
                  class << self
         
     | 
| 
      
 6 
     | 
    
         
            +
                    DEFAULT_COLLECTIONS_PATHS = '/etc/ansible/collections:/usr/share/ansible/collections'.freeze
         
     | 
| 
      
 7 
     | 
    
         
            +
                    DEFAULT_CONFIG_FILE = '/etc/ansible/ansible.cfg'.freeze
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                    def collections_paths
         
     | 
| 
      
 10 
     | 
    
         
            +
                      config_path(path_from_config('collections_paths'), DEFAULT_COLLECTIONS_PATHS)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                    def config_path(config_line, default)
         
     | 
| 
      
 14 
     | 
    
         
            +
                      return default if config_line.empty?
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                      config_line_key = config_line.first.split('=').first.strip
         
     | 
| 
      
 17 
     | 
    
         
            +
                      # In case of commented roles_path key "#roles_path" or #collections_paths, return default
         
     | 
| 
      
 18 
     | 
    
         
            +
                      return default if ['#roles_path', '#collections_paths'].include?(config_line_key)
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                      config_line.first.split('=').last.strip
         
     | 
| 
      
 21 
     | 
    
         
            +
                    end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    def path_from_config(config_key)
         
     | 
| 
      
 24 
     | 
    
         
            +
                      File.readlines(DEFAULT_CONFIG_FILE).select do |line|
         
     | 
| 
      
 25 
     | 
    
         
            +
                        line =~ /^\s*#{config_key}/
         
     | 
| 
      
 26 
     | 
    
         
            +
                      end
         
     | 
| 
      
 27 
     | 
    
         
            +
                    rescue Errno::ENOENT, Errno::EACCES => e
         
     | 
| 
      
 28 
     | 
    
         
            +
                      RolesReader.logger.debug(e.backtrace)
         
     | 
| 
      
 29 
     | 
    
         
            +
                      message = "Could not read Ansible config file #{DEFAULT_CONFIG_FILE} - #{e.message}"
         
     | 
| 
      
 30 
     | 
    
         
            +
                      raise ReadConfigFileException.new(message), message
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    def playbook_or_role_full_name(path)
         
     | 
| 
      
 34 
     | 
    
         
            +
                      parts = path.split('/')
         
     | 
| 
      
 35 
     | 
    
         
            +
                      playbook = parts.pop
         
     | 
| 
      
 36 
     | 
    
         
            +
                      parts.pop
         
     | 
| 
      
 37 
     | 
    
         
            +
                      collection = parts.pop
         
     | 
| 
      
 38 
     | 
    
         
            +
                      author = parts.pop
         
     | 
| 
      
 39 
     | 
    
         
            +
                      "#{author}.#{collection}.#{playbook}"
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -5,33 +5,16 @@ module Proxy 
     | 
|
| 
       5 
5 
     | 
    
         
             
                # Implements the logic needed to read the roles and associated information
         
     | 
| 
       6 
6 
     | 
    
         
             
                class RolesReader
         
     | 
| 
       7 
7 
     | 
    
         
             
                  class << self
         
     | 
| 
       8 
     | 
    
         
            -
                    DEFAULT_CONFIG_FILE = '/etc/ansible/ansible.cfg'.freeze
         
     | 
| 
       9 
8 
     | 
    
         
             
                    DEFAULT_ROLES_PATH = '/etc/ansible/roles:/usr/share/ansible/roles'.freeze
         
     | 
| 
       10 
     | 
    
         
            -
                    DEFAULT_COLLECTIONS_PATHS = '/etc/ansible/collections:/usr/share/ansible/collections'.freeze
         
     | 
| 
       11 
9 
     | 
    
         | 
| 
       12 
10 
     | 
    
         
             
                    def list_roles
         
     | 
| 
       13 
11 
     | 
    
         
             
                      roles = roles_path.split(':').map { |path| read_roles(path) }.flatten
         
     | 
| 
       14 
     | 
    
         
            -
                      collection_roles = collections_paths.split(':').map { |path| read_collection_roles(path) }.flatten
         
     | 
| 
      
 12 
     | 
    
         
            +
                      collection_roles = ReaderHelper.collections_paths.split(':').map { |path| read_collection_roles(path) }.flatten
         
     | 
| 
       15 
13 
     | 
    
         
             
                      roles + collection_roles
         
     | 
| 
       16 
14 
     | 
    
         
             
                    end
         
     | 
| 
       17 
15 
     | 
    
         | 
| 
       18 
16 
     | 
    
         
             
                    def roles_path
         
     | 
| 
       19 
     | 
    
         
            -
                      config_path(path_from_config('roles_path'), DEFAULT_ROLES_PATH)
         
     | 
| 
       20 
     | 
    
         
            -
                    end
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                    def collections_paths
         
     | 
| 
       23 
     | 
    
         
            -
                      config_path(path_from_config('collections_paths'), DEFAULT_COLLECTIONS_PATHS)
         
     | 
| 
       24 
     | 
    
         
            -
                    end
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                    def config_path(config_line, default)
         
     | 
| 
       27 
     | 
    
         
            -
                      # Default to /etc/ansible/roles if config_line is empty
         
     | 
| 
       28 
     | 
    
         
            -
                      return default if config_line.empty?
         
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
                      config_line_key = config_line.first.split('=').first.strip
         
     | 
| 
       31 
     | 
    
         
            -
                      # In case of commented roles_path key "#roles_path" or #collections_paths, return default
         
     | 
| 
       32 
     | 
    
         
            -
                      return default if ['#roles_path', '#collections_paths'].include?(config_line_key)
         
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
                      config_line.first.split('=').last.strip
         
     | 
| 
      
 17 
     | 
    
         
            +
                      ReaderHelper.config_path(ReaderHelper.path_from_config('roles_path'), DEFAULT_ROLES_PATH)
         
     | 
| 
       35 
18 
     | 
    
         
             
                    end
         
     | 
| 
       36 
19 
     | 
    
         | 
| 
       37 
20 
     | 
    
         
             
                    def logger
         
     | 
| 
         @@ -58,33 +41,17 @@ module Proxy 
     | 
|
| 
       58 
41 
     | 
    
         | 
| 
       59 
42 
     | 
    
         
             
                    def glob_path(path)
         
     | 
| 
       60 
43 
     | 
    
         
             
                      Dir.glob path
         
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
44 
     | 
    
         
             
                    end
         
     | 
| 
       63 
45 
     | 
    
         | 
| 
       64 
46 
     | 
    
         
             
                    def read_collection_roles(collections_path)
         
     | 
| 
       65 
47 
     | 
    
         
             
                      Dir.glob("#{collections_path}/ansible_collections/*/*/roles/*").map do |path|
         
     | 
| 
       66 
     | 
    
         
            -
                         
     | 
| 
       67 
     | 
    
         
            -
                        role = parts.pop
         
     | 
| 
       68 
     | 
    
         
            -
                        parts.pop
         
     | 
| 
       69 
     | 
    
         
            -
                        collection = parts.pop
         
     | 
| 
       70 
     | 
    
         
            -
                        author = parts.pop
         
     | 
| 
       71 
     | 
    
         
            -
                        "#{author}.#{collection}.#{role}"
         
     | 
| 
      
 48 
     | 
    
         
            +
                        ReaderHelper.playbook_or_role_full_name(path)
         
     | 
| 
       72 
49 
     | 
    
         
             
                      end
         
     | 
| 
       73 
50 
     | 
    
         
             
                    rescue Errno::ENOENT, Errno::EACCES => e
         
     | 
| 
       74 
51 
     | 
    
         
             
                      logger.debug(e.backtrace)
         
     | 
| 
       75 
52 
     | 
    
         
             
                      message = "Could not read Ansible roles #{collections_path} - #{e.message}"
         
     | 
| 
       76 
53 
     | 
    
         
             
                      raise ReadRolesException.new(message), message
         
     | 
| 
       77 
54 
     | 
    
         
             
                    end
         
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
     | 
    
         
            -
                    def path_from_config(config_key)
         
     | 
| 
       80 
     | 
    
         
            -
                      File.readlines(DEFAULT_CONFIG_FILE).select do |line|
         
     | 
| 
       81 
     | 
    
         
            -
                        line =~ /^\s*#{config_key}/
         
     | 
| 
       82 
     | 
    
         
            -
                      end
         
     | 
| 
       83 
     | 
    
         
            -
                    rescue Errno::ENOENT, Errno::EACCES => e
         
     | 
| 
       84 
     | 
    
         
            -
                      logger.debug(e.backtrace)
         
     | 
| 
       85 
     | 
    
         
            -
                      message = "Could not read Ansible config file #{DEFAULT_CONFIG_FILE} - #{e.message}"
         
     | 
| 
       86 
     | 
    
         
            -
                      raise ReadConfigFileException.new(message), message
         
     | 
| 
       87 
     | 
    
         
            -
                    end
         
     | 
| 
       88 
55 
     | 
    
         
             
                  end
         
     | 
| 
       89 
56 
     | 
    
         
             
                end
         
     | 
| 
       90 
57 
     | 
    
         
             
              end
         
     | 
| 
         @@ -1,4 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'shellwords'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'yaml'
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            require 'smart_proxy_dynflow/runner/command'
         
     | 
| 
       4 
5 
     | 
    
         
             
            require 'smart_proxy_dynflow/runner/base'
         
     | 
| 
         @@ -7,6 +8,7 @@ module Proxy::Ansible 
     | 
|
| 
       7 
8 
     | 
    
         
             
              module Runner
         
     | 
| 
       8 
9 
     | 
    
         
             
                class AnsibleRunner < ::Proxy::Dynflow::Runner::Parent
         
     | 
| 
       9 
10 
     | 
    
         
             
                  include ::Proxy::Dynflow::Runner::Command
         
     | 
| 
      
 11 
     | 
    
         
            +
                  attr_reader :execution_timeout_interval, :command_pid
         
     | 
| 
       10 
12 
     | 
    
         | 
| 
       11 
13 
     | 
    
         
             
                  def initialize(input, suspended_action:)
         
     | 
| 
       12 
14 
     | 
    
         
             
                    super input, :suspended_action => suspended_action
         
     | 
| 
         @@ -19,12 +21,16 @@ module Proxy::Ansible 
     | 
|
| 
       19 
21 
     | 
    
         
             
                    @check_mode = action_input[:check_mode]
         
     | 
| 
       20 
22 
     | 
    
         
             
                    @tags = action_input[:tags]
         
     | 
| 
       21 
23 
     | 
    
         
             
                    @tags_flag = action_input[:tags_flag]
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @passphrase = action_input['secrets']['key_passphrase']
         
     | 
| 
      
 25 
     | 
    
         
            +
                    @execution_timeout_interval = action_input[:execution_timeout_interval]
         
     | 
| 
      
 26 
     | 
    
         
            +
                    @cleanup_working_dirs = action_input.fetch(:cleanup_working_dirs, true)
         
     | 
| 
       22 
27 
     | 
    
         
             
                  end
         
     | 
| 
       23 
28 
     | 
    
         | 
| 
       24 
29 
     | 
    
         
             
                  def start
         
     | 
| 
       25 
30 
     | 
    
         
             
                    prepare_directory_structure
         
     | 
| 
       26 
31 
     | 
    
         
             
                    write_inventory
         
     | 
| 
       27 
32 
     | 
    
         
             
                    write_playbook
         
     | 
| 
      
 33 
     | 
    
         
            +
                    write_ssh_key if !@passphrase.nil? && !@passphrase.empty?
         
     | 
| 
       28 
34 
     | 
    
         
             
                    start_ansible_runner
         
     | 
| 
       29 
35 
     | 
    
         
             
                  end
         
     | 
| 
       30 
36 
     | 
    
         | 
| 
         @@ -46,9 +52,26 @@ module Proxy::Ansible 
     | 
|
| 
       46 
52 
     | 
    
         
             
                    end
         
     | 
| 
       47 
53 
     | 
    
         
             
                  end
         
     | 
| 
       48 
54 
     | 
    
         | 
| 
      
 55 
     | 
    
         
            +
                  def timeout
         
     | 
| 
      
 56 
     | 
    
         
            +
                    logger.debug('job timed out')
         
     | 
| 
      
 57 
     | 
    
         
            +
                    super
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                  def timeout_interval
         
     | 
| 
      
 61 
     | 
    
         
            +
                    execution_timeout_interval
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  def kill
         
     | 
| 
      
 65 
     | 
    
         
            +
                    ::Process.kill('SIGTERM', @command_pid)
         
     | 
| 
      
 66 
     | 
    
         
            +
                    publish_exit_status(2)
         
     | 
| 
      
 67 
     | 
    
         
            +
                    @inventory['all']['hosts'].each { |hostname| @exit_statuses[hostname] = 2 }
         
     | 
| 
      
 68 
     | 
    
         
            +
                    broadcast_data('Timeout for execution passed, stopping the job', 'stderr')
         
     | 
| 
      
 69 
     | 
    
         
            +
                    close
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
       49 
72 
     | 
    
         
             
                  def close
         
     | 
| 
       50 
73 
     | 
    
         
             
                    super
         
     | 
| 
       51 
     | 
    
         
            -
                    FileUtils.remove_entry(@root) if @tmp_working_dir
         
     | 
| 
      
 74 
     | 
    
         
            +
                    FileUtils.remove_entry(@root) if @tmp_working_dir && Dir.exist?(@root) && @cleanup_working_dirs
         
     | 
| 
       52 
75 
     | 
    
         
             
                  end
         
     | 
| 
       53 
76 
     | 
    
         | 
| 
       54 
77 
     | 
    
         
             
                  private
         
     | 
| 
         @@ -85,10 +108,17 @@ module Proxy::Ansible 
     | 
|
| 
       85 
108 
     | 
    
         
             
                  def handle_broadcast_data(event)
         
     | 
| 
       86 
109 
     | 
    
         
             
                    log_event("broadcast", event)
         
     | 
| 
       87 
110 
     | 
    
         
             
                    if event['event'] == 'playbook_on_stats'
         
     | 
| 
      
 111 
     | 
    
         
            +
                      failures = event.dig('event_data', 'failures') || {}
         
     | 
| 
      
 112 
     | 
    
         
            +
                      unreachable = event.dig('event_data', 'dark') || {}
         
     | 
| 
       88 
113 
     | 
    
         
             
                      header, *rows = event['stdout'].strip.lines.map(&:chomp)
         
     | 
| 
       89 
114 
     | 
    
         
             
                      @outputs.keys.select { |key| key.is_a? String }.each do |host|
         
     | 
| 
       90 
115 
     | 
    
         
             
                        line = rows.find { |row| row =~ /#{host}/ }
         
     | 
| 
       91 
116 
     | 
    
         
             
                        publish_data_for(host, [header, line].join("\n"), 'stdout')
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                        # If the task has been rescued, it won't consider a failure
         
     | 
| 
      
 119 
     | 
    
         
            +
                        if @exit_statuses[host].to_i != 0 && failures[host].to_i <= 0 && unreachable[host].to_i <= 0
         
     | 
| 
      
 120 
     | 
    
         
            +
                          publish_exit_status_for(host, 0)
         
     | 
| 
      
 121 
     | 
    
         
            +
                        end
         
     | 
| 
       92 
122 
     | 
    
         
             
                      end
         
     | 
| 
       93 
123 
     | 
    
         
             
                    else
         
     | 
| 
       94 
124 
     | 
    
         
             
                      broadcast_data(event['stdout'] + "\n", 'stdout')
         
     | 
| 
         @@ -111,6 +141,19 @@ module Proxy::Ansible 
     | 
|
| 
       111 
141 
     | 
    
         
             
                    File.write(File.join(@root, 'project', 'playbook.yml'), @playbook)
         
     | 
| 
       112 
142 
     | 
    
         
             
                  end
         
     | 
| 
       113 
143 
     | 
    
         | 
| 
      
 144 
     | 
    
         
            +
                  def write_ssh_key
         
     | 
| 
      
 145 
     | 
    
         
            +
                    key_path = File.join(@root, 'env', 'ssh_key')
         
     | 
| 
      
 146 
     | 
    
         
            +
                    File.symlink(File.expand_path(Proxy::RemoteExecution::Ssh::Plugin.settings[:ssh_identity_key_file]), key_path)
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
                    passwords_path = File.join(@root, 'env', 'passwords')
         
     | 
| 
      
 149 
     | 
    
         
            +
                    # here we create a secrets file for ansible-runner, which uses the key as regexp
         
     | 
| 
      
 150 
     | 
    
         
            +
                    # to match line asking for password, given the limitation to match only first 100 chars
         
     | 
| 
      
 151 
     | 
    
         
            +
                    # and the fact the line contains dynamically created temp directory, the regexp
         
     | 
| 
      
 152 
     | 
    
         
            +
                    # mentions only things that are always there, such as artifacts directory and the key name
         
     | 
| 
      
 153 
     | 
    
         
            +
                    secrets = YAML.dump({ "for.*/artifacts/.*/ssh_key_data:" => @passphrase })
         
     | 
| 
      
 154 
     | 
    
         
            +
                    File.write(passwords_path, secrets, perm: 0o600)
         
     | 
| 
      
 155 
     | 
    
         
            +
                  end
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
       114 
157 
     | 
    
         
             
                  def start_ansible_runner
         
     | 
| 
       115 
158 
     | 
    
         
             
                    env = {}
         
     | 
| 
       116 
159 
     | 
    
         
             
                    env['FOREMAN_CALLBACK_DISABLE'] = '1' if @rex_command
         
     | 
| 
         @@ -133,7 +176,7 @@ module Proxy::Ansible 
     | 
|
| 
       133 
176 
     | 
    
         
             
                  end
         
     | 
| 
       134 
177 
     | 
    
         | 
| 
       135 
178 
     | 
    
         
             
                  def check_cmd
         
     | 
| 
       136 
     | 
    
         
            -
                    check_mode? ? '--check' : ''
         
     | 
| 
      
 179 
     | 
    
         
            +
                    check_mode? ? '"--check"' : ''
         
     | 
| 
       137 
180 
     | 
    
         
             
                  end
         
     | 
| 
       138 
181 
     | 
    
         | 
| 
       139 
182 
     | 
    
         
             
                  def verbosity
         
     | 
| 
         @@ -145,11 +188,11 @@ module Proxy::Ansible 
     | 
|
| 
       145 
188 
     | 
    
         
             
                  end
         
     | 
| 
       146 
189 
     | 
    
         | 
| 
       147 
190 
     | 
    
         
             
                  def check_mode?
         
     | 
| 
       148 
     | 
    
         
            -
                    @check_mode == true
         
     | 
| 
      
 191 
     | 
    
         
            +
                    @check_mode == true && @rex_command == false
         
     | 
| 
       149 
192 
     | 
    
         
             
                  end
         
     | 
| 
       150 
193 
     | 
    
         | 
| 
       151 
194 
     | 
    
         
             
                  def prepare_directory_structure
         
     | 
| 
       152 
     | 
    
         
            -
                    inner = %w[inventory project].map { |part| File.join(@root, part) }
         
     | 
| 
      
 195 
     | 
    
         
            +
                    inner = %w[inventory project env].map { |part| File.join(@root, part) }
         
     | 
| 
       153 
196 
     | 
    
         
             
                    ([@root] + inner).each do |path|
         
     | 
| 
       154 
197 
     | 
    
         
             
                      FileUtils.mkdir_p path
         
     | 
| 
       155 
198 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -24,7 +24,7 @@ module Proxy::Ansible 
     | 
|
| 
       24 
24 
     | 
    
         
             
                  # Discard everything apart from hostname to be able to tell the actions
         
     | 
| 
       25 
25 
     | 
    
         
             
                  # apart when debugging
         
     | 
| 
       26 
26 
     | 
    
         
             
                  def transform_input(input)
         
     | 
| 
       27 
     | 
    
         
            -
                    { 'action_input' =>  
     | 
| 
      
 27 
     | 
    
         
            +
                    { 'action_input' => super['action_input'].slice('name', :task_id) }
         
     | 
| 
       28 
28 
     | 
    
         
             
                  end
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
                  # def self.input_format
         
     | 
| 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Proxy::Ansible
         
     | 
| 
      
 2 
     | 
    
         
            +
              class ValidateSettings < ::Proxy::PluginValidators::Base
         
     | 
| 
      
 3 
     | 
    
         
            +
                def validate!(settings)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  raise NotExistingWorkingDirException.new("Working directory does not exist") unless settings[:working_dir].nil? || File.directory?(File.expand_path(settings[:working_dir]))
         
     | 
| 
      
 5 
     | 
    
         
            +
                end
         
     | 
| 
      
 6 
     | 
    
         
            +
              end
         
     | 
| 
      
 7 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/smart_proxy_ansible.rb
    CHANGED
    
    | 
         @@ -4,8 +4,12 @@ module Proxy 
     | 
|
| 
       4 
4 
     | 
    
         
             
              # Basic requires for this plugin
         
     | 
| 
       5 
5 
     | 
    
         
             
              module Ansible
         
     | 
| 
       6 
6 
     | 
    
         
             
                require 'smart_proxy_ansible/version'
         
     | 
| 
      
 7 
     | 
    
         
            +
                require 'smart_proxy_ansible/configuration_loader'
         
     | 
| 
      
 8 
     | 
    
         
            +
                require 'smart_proxy_ansible/validate_settings'
         
     | 
| 
       7 
9 
     | 
    
         
             
                require 'smart_proxy_ansible/plugin'
         
     | 
| 
       8 
10 
     | 
    
         
             
                require 'smart_proxy_ansible/roles_reader'
         
     | 
| 
      
 11 
     | 
    
         
            +
                require 'smart_proxy_ansible/playbooks_reader'
         
     | 
| 
      
 12 
     | 
    
         
            +
                require 'smart_proxy_ansible/reader_helper'
         
     | 
| 
       9 
13 
     | 
    
         
             
                require 'smart_proxy_ansible/variables_extractor'
         
     | 
| 
       10 
14 
     | 
    
         
             
              end
         
     | 
| 
       11 
15 
     | 
    
         
             
            end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: smart_proxy_ansible
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 3. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 3.3.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Ivan Nečas
         
     | 
| 
         @@ -9,7 +9,7 @@ authors: 
     | 
|
| 
       9 
9 
     | 
    
         
             
            autorequire:
         
     | 
| 
       10 
10 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       11 
11 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       12 
     | 
    
         
            -
            date:  
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2022-01-17 00:00:00.000000000 Z
         
     | 
| 
       13 
13 
     | 
    
         
             
            dependencies:
         
     | 
| 
       14 
14 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       15 
15 
     | 
    
         
             
              name: rake
         
     | 
| 
         @@ -154,9 +154,12 @@ files: 
     | 
|
| 
       154 
154 
     | 
    
         
             
            - lib/smart_proxy_ansible.rb
         
     | 
| 
       155 
155 
     | 
    
         
             
            - lib/smart_proxy_ansible/actions.rb
         
     | 
| 
       156 
156 
     | 
    
         
             
            - lib/smart_proxy_ansible/api.rb
         
     | 
| 
      
 157 
     | 
    
         
            +
            - lib/smart_proxy_ansible/configuration_loader.rb
         
     | 
| 
       157 
158 
     | 
    
         
             
            - lib/smart_proxy_ansible/exception.rb
         
     | 
| 
       158 
159 
     | 
    
         
             
            - lib/smart_proxy_ansible/http_config.ru
         
     | 
| 
      
 160 
     | 
    
         
            +
            - lib/smart_proxy_ansible/playbooks_reader.rb
         
     | 
| 
       159 
161 
     | 
    
         
             
            - lib/smart_proxy_ansible/plugin.rb
         
     | 
| 
      
 162 
     | 
    
         
            +
            - lib/smart_proxy_ansible/reader_helper.rb
         
     | 
| 
       160 
163 
     | 
    
         
             
            - lib/smart_proxy_ansible/remote_execution_core/ansible_runner.rb
         
     | 
| 
       161 
164 
     | 
    
         
             
            - lib/smart_proxy_ansible/roles_reader.rb
         
     | 
| 
       162 
165 
     | 
    
         
             
            - lib/smart_proxy_ansible/runner/ansible_runner.rb
         
     | 
| 
         @@ -164,6 +167,7 @@ files: 
     | 
|
| 
       164 
167 
     | 
    
         
             
            - lib/smart_proxy_ansible/runner/playbook.rb
         
     | 
| 
       165 
168 
     | 
    
         
             
            - lib/smart_proxy_ansible/task_launcher/ansible_runner.rb
         
     | 
| 
       166 
169 
     | 
    
         
             
            - lib/smart_proxy_ansible/task_launcher/playbook.rb
         
     | 
| 
      
 170 
     | 
    
         
            +
            - lib/smart_proxy_ansible/validate_settings.rb
         
     | 
| 
       167 
171 
     | 
    
         
             
            - lib/smart_proxy_ansible/variables_extractor.rb
         
     | 
| 
       168 
172 
     | 
    
         
             
            - lib/smart_proxy_ansible/version.rb
         
     | 
| 
       169 
173 
     | 
    
         
             
            - settings.d/ansible.yml.example
         
     | 
| 
         @@ -186,7 +190,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       186 
190 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       187 
191 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       188 
192 
     | 
    
         
             
            requirements: []
         
     | 
| 
       189 
     | 
    
         
            -
            rubygems_version: 3. 
     | 
| 
      
 193 
     | 
    
         
            +
            rubygems_version: 3.3.4
         
     | 
| 
       190 
194 
     | 
    
         
             
            signing_key:
         
     | 
| 
       191 
195 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       192 
196 
     | 
    
         
             
            summary: Smart-Proxy Ansible plugin
         
     |