From 24c5e11668e324aa069cb75a32dfe29219f0cfd9 Mon Sep 17 00:00:00 2001 From: Daniel Lobato Garcia Date: Mon, 28 May 2018 15:54:37 +0200 Subject: [PATCH] Fixes #24363 - Endpoint to display variables for role(s) There should be an endpoint at the proxy to display all variables for a role and for many roles, so Foreman can use that to import the variables. --- lib/foreman_ansible_core.rb | 1 + .../variables_extractor.rb | 31 +++++++++++++++++++ lib/smart_proxy_ansible/api.rb | 31 ++++++++++++------- 3 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 lib/foreman_ansible_core/variables_extractor.rb diff --git a/lib/foreman_ansible_core.rb b/lib/foreman_ansible_core.rb index b8486bd..60d3213 100644 --- a/lib/foreman_ansible_core.rb +++ b/lib/foreman_ansible_core.rb @@ -11,6 +11,7 @@ module ForemanAnsibleCore require 'foreman_ansible_core/exception' require 'foreman_ansible_core/roles_reader' + require 'foreman_ansible_core/variables_extractor' require 'foreman_ansible_core/version' if defined? ForemanTasksCore diff --git a/lib/foreman_ansible_core/variables_extractor.rb b/lib/foreman_ansible_core/variables_extractor.rb new file mode 100644 index 0000000..f58186e --- /dev/null +++ b/lib/foreman_ansible_core/variables_extractor.rb @@ -0,0 +1,31 @@ +module ForemanAnsibleCore + # Implements the logic needed to read the roles and associated information + class VariablesExtractor + class << self + def extract_variables(role_path) + role_files = Dir.glob("#{role_path}/defaults/**/*.yml") + + Dir.glob("#{role_path}/defaults/**/*.yaml") + # not anything matching item, }}, {{, ansible_hostname or 'if' + variables = role_files.map do |role_file| + candidates = File.read(role_file).scan(/{{(.*?)}}/).select do |param| + param.first.scan(/item/) == [] && param.first.scan(/if/) == [] + + end.flatten + # Sometimes inside the {{ }} there's a OR condition. In such a case, + # let's split and choose possible variables (variables cannot contain + # parenthesis) + + candidates.map do |variable| + variable.split('|').map(&:strip).select do |var| + !var.include?('(') && # variables are not parenthesis + !var.include?('[') && # variables are not arrays + !var.include?('.') && # variables are not objects + !var.include?("'") # variables are not plain strings + end + end unless candidates.nil? + end.compact.flatten.uniq.map(&:strip) + variables + end + end + end +end diff --git a/lib/smart_proxy_ansible/api.rb b/lib/smart_proxy_ansible/api.rb index 1ad6171..5c9e73d 100644 --- a/lib/smart_proxy_ansible/api.rb +++ b/lib/smart_proxy_ansible/api.rb @@ -7,18 +7,27 @@ class Api < Sinatra::Base ::ForemanAnsibleCore::RolesReader.list_roles.to_json end + get '/roles/variables' do + variables = {} + ::ForemanAnsibleCore::RolesReader.list_roles.each do |role_name| + variables[role_name] = extract_variables(role_name)[role_name] + end + variables.to_json + end + get '/roles/:role_name/variables' do |role_name| - # not anything matching item, }}, {{, ansible_hostname or 'if' - ansible_config = '/etc/ansible/ansible.cfg' - roles_path = ::ForemanAnsibleCore::RolesReader.roles_path(ansible_config) - role_files = Dir.glob("#{roles_path}/#{role_name}/**/*.yml") - variables = role_files.map do |role_file| - File.read(role_file).scan(/{{(.*?)}}/).select do |param| - param.first.scan(/item/) == [] && param.first.scan(/if/) == [] - end.first - end.compact - variables.uniq! - variables = variables.map(&:first).map(&:strip).to_json + extract_variables(role_name).to_json + end + + private + + def extract_variables(role_name) + variables = {} + ::ForemanAnsibleCore::RolesReader.roles_path.split(':').each do |path| + variables[role_name] = ::ForemanAnsibleCore::VariablesExtractor. + extract_variables("#{path}/#{role_name}") + end + variables end end end