kitchen-salt-0.4.0/0000755000175000017500000000000013410365464013761 5ustar mathieumathieukitchen-salt-0.4.0/kitchen-salt.gemspec0000644000175000017500000000655613410365464017730 0ustar mathieumathieu######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: kitchen-salt 0.4.0 ruby lib Gem::Specification.new do |s| s.name = "kitchen-salt".freeze s.version = "0.4.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["SaltStack Inc".freeze] s.date = "2018-10-30" s.description = "salt provisioner for test-kitchen so that you can test all the things".freeze s.email = ["daniel@gtmanfred.com".freeze] s.files = ["lib/kitchen-salt/pillars.rb".freeze, "lib/kitchen-salt/states.rb".freeze, "lib/kitchen-salt/util.rb".freeze, "lib/kitchen-salt/version.rb".freeze, "lib/kitchen/provisioner/99-minion.conf.erb".freeze, "lib/kitchen/provisioner/dependencies.erb".freeze, "lib/kitchen/provisioner/formula-fetch.sh".freeze, "lib/kitchen/provisioner/gpgkey.erb".freeze, "lib/kitchen/provisioner/install.erb".freeze, "lib/kitchen/provisioner/install_win.erb".freeze, "lib/kitchen/provisioner/minion.erb".freeze, "lib/kitchen/provisioner/repository-setup.sh".freeze, "lib/kitchen/provisioner/salt_solo.rb".freeze, "lib/kitchen/provisioner/spm.erb".freeze, "lib/kitchen/transport/runtests.rb".freeze, "lib/kitchen/verifier/runtests.rb".freeze, "lib/kitchen/verifier/salttox.rb".freeze] s.homepage = "https://github.com/saltstack/kitchen-salt".freeze s.licenses = ["Apache-2.0".freeze] s.rubyforge_project = "[none]".freeze s.rubygems_version = "2.7.6".freeze s.summary = "salt provisioner for test-kitchen".freeze if s.respond_to? :specification_version then s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, ["~> 0.7.3"]) s.add_runtime_dependency(%q.freeze, [">= 3.5"]) s.add_development_dependency(%q.freeze, ["~> 2.2"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, ["~> 0.10.1"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_runtime_dependency(%q.freeze, ["~> 1.4"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["~> 0.7.3"]) s.add_dependency(%q.freeze, [">= 3.5"]) s.add_dependency(%q.freeze, ["~> 2.2"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["~> 0.10.1"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["~> 1.4"]) s.add_dependency(%q.freeze, [">= 0"]) end else s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["~> 0.7.3"]) s.add_dependency(%q.freeze, [">= 3.5"]) s.add_dependency(%q.freeze, ["~> 2.2"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["~> 0.10.1"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["~> 1.4"]) s.add_dependency(%q.freeze, [">= 0"]) end end kitchen-salt-0.4.0/lib/0000755000175000017500000000000013410365464014527 5ustar mathieumathieukitchen-salt-0.4.0/lib/kitchen/0000755000175000017500000000000013410365464016154 5ustar mathieumathieukitchen-salt-0.4.0/lib/kitchen/transport/0000755000175000017500000000000013410365464020210 5ustar mathieumathieukitchen-salt-0.4.0/lib/kitchen/transport/runtests.rb0000644000175000017500000000125013410365464022422 0ustar mathieumathieurequire 'kitchen/transport/rsync' require 'shellwords' module Kitchen module Transport class Runtests < Kitchen::Transport::Rsync class Connection < Kitchen::Transport::Rsync::Connection def execute_with_exit_code(command) if command.start_with?("sh -c") super else login = login_command() cmd = [ login.instance_variable_get("@command"), login.instance_variable_get("@arguments").join(' '), '--', command.shellescape, ].join(' ') system(cmd) $?.exitstatus end end end end end end kitchen-salt-0.4.0/lib/kitchen/verifier/0000755000175000017500000000000013410365464017767 5ustar mathieumathieukitchen-salt-0.4.0/lib/kitchen/verifier/runtests.rb0000644000175000017500000000637713410365464022220 0ustar mathieumathieu# -*- encoding: utf-8 -*- require "kitchen/verifier/base" module Kitchen module Verifier class Runtests < Kitchen::Verifier::Base kitchen_verifier_api_version 1 plugin_version Kitchen::VERSION default_config :testingdir, '/testing' default_config :python_bin, 'python2' default_config :verbose, false default_config :run_destructive, false default_config :xml, false default_config :coverage_xml, false default_config :types, [] default_config :tests, [] default_config :transport, false default_config :save, {} default_config :windows, false default_config :enable_filenames, false default_config :from_filenames, [] def call(state) info("[#{name}] Verify on instance #{instance.name} with state=#{state}") root_path = (config[:windows] ? '%TEMP%\\kitchen' : '/tmp/kitchen') if ENV['KITCHEN_TESTS'] ENV['KITCHEN_TESTS'].split(' ').each{|test| config[:tests].push(test)} end if config[:enable_filenames] and ENV['CHANGE_TARGET'] and ENV['BRANCH_NAME'] require 'git' repo = Git.open('.') config[:from_filenames] = repo.diff("origin/#{ENV['CHANGE_TARGET']}", "origin/#{ENV['BRANCH_NAME']}").name_status.keys.select{|file| file.end_with?('.py')} end command = [ (config[:windows] ? 'python.exe' : config[:python_bin]), File.join(root_path, config[:testingdir], '/tests/runtests.py'), '--sysinfo', '--output-columns=80', (config[:windows] && config[:tests].empty? ? "--names-file=#{root_path}\\testing\\tests\\whitelist.txt" : ''), (config[:transport] ? "--transport=#{config[:transport]}" : ''), (config[:verbose] ? '-vv' : '-v'), (config[:run_destructive] ? "--run-destructive" : ''), (config[:coverage_xml] ? "--coverage-xml=#{config[:coverage_xml]}" : ''), (config[:xml] ? "--xml=#{config[:xml]}" : ''), config[:types].collect{|type| "--#{type}"}.join(' '), config[:tests].collect{|test| "-n #{test}"}.join(' '), (config[:from_filenames].any? ? "--from-filenames=#{config[:from_filenames].join(',')}" : ''), '2>&1', ].join(' ') if config[:windows] command = "cmd.exe /c \"#{command}\" 2>&1" end info("Running Command: #{command}") instance.transport.connection(state) do |conn| begin if config[:windows] conn.execute('$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")') conn.execute("$env:PythonPath = [Environment]::ExpandEnvironmentVariables(\"#{root_path}\\testing\")") else conn.execute(sudo("chown -R $USER #{root_path}")) end conn.execute(sudo(command)) ensure config[:save].each do |remote, local| unless config[:windows] conn.execute(sudo("chmod -R +r #{remote}")) end info("Copying #{remote} to #{local}") conn.download(remote, local) end end end debug("[#{name}] Verify completed.") end end end end kitchen-salt-0.4.0/lib/kitchen/verifier/salttox.rb0000644000175000017500000000523513410365464022017 0ustar mathieumathieu# -*- encoding: utf-8 -*- require "kitchen/verifier/base" module Kitchen module Verifier class Salttox < Kitchen::Verifier::Base kitchen_verifier_api_version 1 plugin_version Kitchen::VERSION default_config :testingdir, '/testing' default_config :verbose, false default_config :run_destructive, false default_config :xml, false default_config :coverage_xml, false default_config :types, [] default_config :tests, [] default_config :transport, false default_config :save, {} default_config :windows, false def call(state) info("[#{name}] Verify on instance #{instance.name} with state=#{state}") root_path = (config[:windows] ? '%TEMP%\\kitchen' : '/tmp/kitchen') if ENV['KITCHEN_TESTS'] ENV['KITCHEN_TESTS'].split(' ').each{|test| config[:tests].push(test)} end command = [ 'tox -c', File.join(root_path, config[:testingdir], 'tox.ini'), "-e #{instance.suite.name}", '--', '--sysinfo', '--output-columns=80', (config[:windows] ? "--names-file=#{root_path}\\testing\\tests\\whitelist.txt" : ''), (config[:transport] ? "--transport=#{config[:transport]}" : ''), (config[:verbose] ? '-v' : ''), (config[:run_destructive] ? "--run-destructive" : ''), (config[:coverage_xml] ? "--cov=salt/ --cov-report xml:#{config[:coverage_xml]}" : ''), (config[:xml] ? "--junitxml=#{config[:xml]}" : ''), config[:types].collect{|type| "--#{type}"}.join(' '), config[:tests].join(' '), '2>&1', ].join(' ') if config[:windows] command = "cmd.exe /c \"#{command}\" 2>&1" end info("Running Command: #{command}") instance.transport.connection(state) do |conn| begin if config[:windows] conn.execute('$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")') conn.execute("$env:PythonPath = [Environment]::ExpandEnvironmentVariables(\"#{root_path}\\testing\")") else conn.execute(sudo("chown -R $USER #{root_path}")) end conn.execute(sudo(command)) ensure config[:save].each do |remote, local| unless config[:windows] conn.execute(sudo("chmod -R +r #{remote}")) end info("Copying #{remote} to #{local}") conn.download(remote, local) end end end debug("[#{name}] Verify completed.") end end end end kitchen-salt-0.4.0/lib/kitchen/provisioner/0000755000175000017500000000000013410365464020533 5ustar mathieumathieukitchen-salt-0.4.0/lib/kitchen/provisioner/salt_solo.rb0000644000175000017500000004320013410365464023056 0ustar mathieumathieu # # Author:: Simon McCartney # # Copyright (C) 2013, Chris Lundquist, Simon McCartney # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'fileutils' require 'hashie' require 'kitchen-salt/pillars' require 'kitchen-salt/states' require 'kitchen-salt/util' require 'kitchen/provisioner/base' require 'yaml' module Kitchen module Provisioner # Basic Salt Masterless Provisioner, based on work by # # @author Chris Lundquist () class SaltSolo < Base include Kitchen::Salt::Util include Kitchen::Salt::Pillars include Kitchen::Salt::States DEFAULT_CONFIG = { bootstrap_url: 'https://raw.githubusercontent.com/saltstack/kitchen-salt/master/assets/install.sh', cache_commands: [], chef_bootstrap_url: 'https://www.chef.io/chef/install.sh', dependencies: [], dry_run: false, gpg_home: '~/.gnupg/', gpg_key: nil, install_after_init_environment: false, is_file_root: false, local_salt_root: nil, omnibus_cachier: false, pillars_from_directories: [], pip_bin: 'pip', pip_editable: false, pip_extra_index_url: [], pip_index_url: 'https://pypi.python.org/simple/', pip_pkg: 'salt==%s', remote_states: nil, require_chef: true, salt_apt_repo_key: 'https://repo.saltstack.com/apt/ubuntu/16.04/amd64/latest/SALTSTACK-GPG-KEY.pub', salt_apt_repo: 'https://repo.saltstack.com/apt/ubuntu/16.04/amd64/', salt_bootstrap_options: '', salt_bootstrap_url: 'https://bootstrap.saltstack.com', salt_config: '/etc/salt', salt_copy_filter: [], salt_env: 'base', salt_file_root: '/srv/salt', salt_force_color: false, salt_install: 'bootstrap', salt_minion_config_dropin_files: [], salt_minion_config_template: nil, salt_minion_config: '/etc/salt/minion', salt_minion_extra_config: {}, salt_minion_id: nil, salt_pillar_root: '/srv/pillar', salt_ppa: 'ppa:saltstack/salt', salt_spm_root: '/srv/spm', salt_state_top: '/srv/salt/top.sls', salt_version: 'latest', salt_yum_repo_key: 'https://repo.saltstack.com/yum/redhat/$releasever/$basearch/archive/%s/SALTSTACK-GPG-KEY.pub', salt_yum_repo_latest: 'https://repo.saltstack.com/yum/redhat/salt-repo-latest-2.el7.noarch.rpm', salt_yum_repo: 'https://repo.saltstack.com/yum/redhat/$releasever/$basearch/archive/%s', salt_yum_rpm_key: 'https://repo.saltstack.com/yum/redhat/7/x86_64/archive/%s/SALTSTACK-GPG-KEY.pub', state_collection: false, state_top_from_file: false, state_top: {}, vendor_path: nil, vendor_repo: {} }.freeze WIN_DEFAULT_CONFIG = { chef_bootstrap_url: 'https://omnitruck.chef.io/install.ps1', salt_bootstrap_url: 'https://raw.githubusercontent.com/saltstack/salt-bootstrap/develop/bootstrap-salt.ps1' }.freeze # salt-call version that supports the undocumented --retcode-passthrough command RETCODE_VERSION = '0.17.5'.freeze DEFAULT_CONFIG.each do |k, v| default_config k, v end WIN_DEFAULT_CONFIG.each_key do |key| default_config key do |provisioner| provisioner.windows_os? ? WIN_DEFAULT_CONFIG[key] : DEFAULT_CONFIG[key] end end def install_command unless config[:salt_install] == 'pip' || config[:install_after_init_environment] setup_salt end end def prepare_command cmd = '' unless windows_os? cmd += <<-CHOWN #{sudo('chown')} -R "${SUDO_USER:-$USER}" "#{config[:root_path]}/#{config[:salt_file_root]}" CHOWN end if config[:prepare_salt_environment] cmd += <<-PREPARE #{config[:prepare_salt_environment]} PREPARE end if config[:salt_install] == 'pip' || config[:install_after_init_environment] cmd << setup_salt end cmd end def setup_salt debug(diagnose) salt_version = config[:salt_version] # if salt_verison is set, bootstrap is being used & bootstrap_options is empty, # set the bootstrap_options string to git install the requested version if (salt_version != 'latest') && (config[:salt_install] == 'bootstrap') && config[:salt_bootstrap_options].empty? debug("Using bootstrap git to install #{salt_version}") config[:salt_bootstrap_options] = "-P git v#{salt_version}" end install_template = if windows_os? File.expand_path('./../install_win.erb', __FILE__) else File.expand_path('./../install.erb', __FILE__) end erb = ERB.new(File.read(install_template)).result(binding) debug('Install Command:' + erb.to_s) erb end def install_chef return unless config[:require_chef] chef_url = config[:chef_bootstrap_url] if windows_os? <<-POWERSHELL if (-Not $(test-path c:\\opscode\\chef)) { if (-Not $(Test-Path c:\\temp)) { New-Item -Path c:\\temp -itemtype directory } [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 (New-Object net.webclient).DownloadFile("#{chef_url}", "c:\\temp\\chef_bootstrap.ps1") write-host "-----> Installing Chef Omnibus (for busser/serverspec ruby support)" #{sudo('powershell')} c:\\temp\\chef_bootstrap.ps1 } POWERSHELL else omnibus_download_dir = config[:omnibus_cachier] ? '/tmp/vagrant-cache/omnibus_chef' : '/tmp' bootstrap_url = config[:bootstrap_url] bootstrap_download_dir = '/tmp' <<-INSTALL echo "-----> Trying to install ruby(-dev) using assets.sh from kitchen-salt" mkdir -p #{bootstrap_download_dir} if [ ! -x #{bootstrap_download_dir}/install.sh ] then do_download #{bootstrap_url} #{bootstrap_download_dir}/install.sh fi #{sudo('sh')} #{bootstrap_download_dir}/install.sh -d #{bootstrap_download_dir} if [ $? -ne 0 ] || [ ! -d "/opt/chef" ] then echo "Failed install ruby(-dev) using assets.sh from kitchen-salt" echo "-----> Fallback to Chef Bootstrap script (for busser/serverspec ruby support)" mkdir -p "#{omnibus_download_dir}" if [ ! -x #{omnibus_download_dir}/install.sh ] then #{sudo('sh')} #{omnibus_download_dir}/install.sh -d #{omnibus_download_dir} fi; fi INSTALL end end def create_sandbox super prepare_data prepare_gpg_key prepare_install prepare_minion prepare_pillars prepare_grains prepare_states prepare_state_top prepare_cache_commands # upload scripts, cached formulas, and setup system repositories prepare_dependencies end def prepare_install salt_version = config[:salt_version] if config[:salt_install] == 'pip' debug('Using pip to install') if File.exist?(config[:pip_pkg]) debug('Installing with pip from sdist') sandbox_pip_path = File.join(sandbox_path, 'pip') FileUtils.mkdir_p(sandbox_pip_path) FileUtils.cp_r(config[:pip_pkg], sandbox_pip_path) config[:pip_install] = File.join(config[:root_path], 'pip', File.basename(config[:pip_pkg])) else debug('Installing with pip from download') if salt_version != 'latest' config[:pip_install] = format(config[:pip_pkg], salt_version) else config[:pip_pkg].slice!('==%s') config[:pip_install] = config[:pip_pkg] end end elsif config[:salt_install] == 'bootstrap' if File.exist?(config[:salt_bootstrap_url]) FileUtils.cp_r(config[:salt_bootstrap_url], File.join(sandbox_path, 'bootstrap.sh')) end end end def init_command debug("Initialising Driver #{name}") cmd = if windows_os? 'mkdir -Force -Path '"#{config[:root_path]}""\n" else "mkdir -p '#{config[:root_path]}';" end cmd += <<-INSTALL #{config[:init_environment]} INSTALL cmd end def os_join(*args) if windows_os? File.join(*args).tr('/', '\\') else File.join(*args) end end def salt_command salt_version = config[:salt_version] cmd = '' if windows_os? salt_call = "c:\\salt\\salt-call.bat" salt_config_path = config[:salt_config] cmd << "(get-content #{os_join(config[:root_path], salt_config_path, 'minion')}) -replace '\\$env:TEMP', $env:TEMP | set-content #{os_join(config[:root_path], salt_config_path, 'minion')} ;" else # install/update dependencies cmd << sudo("chmod +x #{config[:root_path]}/*.sh;") cmd << sudo("#{config[:root_path]}/dependencies.sh;") cmd << sudo("#{config[:root_path]}/gpgkey.sh;") salt_config_path = config[:salt_config] salt_call = 'salt-call' end cmd << sudo("#{salt_call} --state-output=changes --config-dir=#{os_join(config[:root_path], salt_config_path)} state.highstate") cmd << " --log-level=#{config[:log_level]}" if config[:log_level] cmd << " --id=#{config[:salt_minion_id]}" if config[:salt_minion_id] cmd << " test=#{config[:dry_run]}" if config[:dry_run] cmd << ' --force-color' if config[:salt_force_color] if "#{salt_version}" > RETCODE_VERSION || salt_version == 'latest' # hope for the best and hope it works eventually cmd << ' --retcode-passthrough' end cmd << ' 2>&1 ; exit $LASTEXITCODE' if windows_os? cmd end def run_command debug("running driver #{name}") debug(diagnose) # config[:salt_version] can be 'latest' or 'x.y.z', 'YYYY.M.x' etc # error return codes are a mess in salt: # https://github.com/saltstack/salt/pull/11337 # Unless we know we have a version that supports --retcode-passthrough # attempt to scan the output for signs of failure if "#{config[:salt_version]}" <= RETCODE_VERSION # scan the output for signs of failure, there is a risk of false negatives fail_grep = 'grep -e Result.*False -e Data.failed.to.compile -e No.matching.sls.found.for' # capture any non-zero exit codes from the salt-call | tee pipe cmd = 'set -o pipefail ; ' << salt_command # Capture the salt-call output & exit code cmd << ' 2>&1 | tee /tmp/salt-call-output ; SC=$? ; echo salt-call exit code: $SC ;' # check the salt-call output for fail messages cmd << " (sed '/#{fail_grep}/d' /tmp/salt-call-output | #{fail_grep} ; EC=$? ; echo salt-call output grep exit code ${EC} ;" # use the non-zer exit code from salt-call, then invert the results of the grep for failures cmd << ' [ ${SC} -ne 0 ] && exit ${SC} ; [ ${EC} -eq 0 ] && exit 1 ; [ ${EC} -eq 1 ] && exit 0)' cmd else salt_command end end protected def prepare_data return unless config[:data_path] info('Preparing data') debug("Using data from #{config[:data_path]}") tmpdata_dir = File.join(sandbox_path, 'data') FileUtils.mkdir_p(tmpdata_dir) cp_r_with_filter(config[:data_path], tmpdata_dir, config[:salt_copy_filter]) end def prepare_gpg_key return unless config[:gpg_key] info('Preparing gpg_key') debug("Using gpg key: #{config[:gpg_key]}") system("gpg --homedir #{config[:gpg_home]} -o #{File.join(sandbox_path, 'gpgkey.txt')} --armor --export-secret-keys #{config[:gpg_key]}") gpg_template = File.expand_path('./../gpgkey.erb', __FILE__) erb = ERB.new(File.read(gpg_template)).result(binding) debug('Install Command:' + erb.to_s) write_raw_file(File.join(sandbox_path, 'gpgkey.sh'), erb) end def prepare_minion_base_config if config[:salt_minion_config_template] minion_template = File.expand_path(config[:salt_minion_config_template], Kitchen::Config.new.kitchen_root) else minion_template = File.expand_path('./../minion.erb', __FILE__) end minion_config_content = if File.extname(minion_template) == '.erb' ERB.new(File.read(minion_template)).result(binding) else File.read(minion_template) end # create the temporary path for the salt-minion config file debug("sandbox is #{sandbox_path}") sandbox_minion_config_path = File.join(sandbox_path, config[:salt_minion_config]) write_raw_file(sandbox_minion_config_path, minion_config_content) end def prepare_minion_extra_config minion_template = File.expand_path('./../99-minion.conf.erb', __FILE__) safe_hash = Hashie.stringify_keys(config[:salt_minion_extra_config]) minion_extra_config_content = ERB.new(File.read(minion_template)).result(binding) sandbox_dropin_path = File.join(sandbox_path, 'etc/salt/minion.d') write_raw_file(File.join(sandbox_dropin_path, '99-minion.conf'), minion_extra_config_content) end def insert_minion_config_dropins sandbox_dropin_path = File.join(sandbox_path, 'etc/salt/minion.d') FileUtils.mkdir_p(sandbox_dropin_path) config[:salt_minion_config_dropin_files].each_index do |i| filename = File.basename(config[:salt_minion_config_dropin_files][i]) index = (99 - config[:salt_minion_config_dropin_files].count + i).to_s.rjust(2, '0') file = File.expand_path(config[:salt_minion_config_dropin_files][i]) data = File.read(file) write_raw_file(File.join(sandbox_dropin_path, [index, filename].join('-')), data) end end def prepare_minion info('Preparing salt-minion') prepare_minion_base_config prepare_minion_extra_config if config[:salt_minion_extra_config].keys.any? insert_minion_config_dropins if config[:salt_minion_config_dropin_files].any? end def prepare_grains debug("Grains Hash: #{config[:grains]}") return if config[:grains].nil? info("Preparing grains into #{config[:salt_config]}/grains") # generate the filename sandbox_grains_path = File.join(sandbox_path, config[:salt_config], 'grains') debug("sandbox_grains_path: #{sandbox_grains_path}") write_hash_file(sandbox_grains_path, config[:grains]) end def prepare_dependencies # upload scripts sandbox_scripts_path = File.join(sandbox_path, config[:salt_config], 'scripts') info("Preparing scripts into #{config[:salt_config]}/scripts") # PLACEHOLDER, git formulas might be fetched locally to temp and uploaded # setup spm spm_template = File.expand_path('./../spm.erb', __FILE__) spm_config_content = ERB.new(File.read(spm_template)).result(binding) sandbox_spm_config_path = File.join(sandbox_path, config[:salt_config], 'spm') write_raw_file(sandbox_spm_config_path, spm_config_content) spm_repos = config[:vendor_repo].select { |x| x[:type] == 'spm' }.each { |x| x[:url] }.map { |x| x[:url] } spm_repos.each do |url| id = url.gsub(/[htp:\/.]/, '') spmreposd = File.join(sandbox_path, 'etc', 'salt', 'spm.repos.d') repo_spec = File.join(spmreposd, 'spm.repo') FileUtils.mkdir_p(spmreposd) repo_content = " #{id}: url: #{url} " write_raw_file(repo_spec, repo_content) end # upload scripts %w[formula-fetch.sh repository-setup.sh].each do |script| write_raw_file(File.join(sandbox_path, script), File.read(File.expand_path("../#{script}", __FILE__))) end dependencies_script = File.expand_path('./../dependencies.erb', __FILE__) dependencies_content = ERB.new(File.read(dependencies_script)).result(binding) write_raw_file(File.join(sandbox_path, 'dependencies.sh'), dependencies_content) end def prepare_cache_commands ctx = to_hash config[:cache_commands].each do |cmd| system(cmd % ctx) if $?.exitstatus.nonzero? raise ActionFailed, "cache_command '#{cmd}' failed to execute (exit status #{$?.exitstatus})" end end end def to_hash hash = Hash.new instance_variables.each {|var| hash[var[1..-1]] = instance_variable_get(var) } hash.map{|k,v| [k.to_s.to_sym,v]}.to_h end end end end kitchen-salt-0.4.0/lib/kitchen/provisioner/install_win.erb0000644000175000017500000000313613410365464023553 0ustar mathieumathieu<%= salt_install = config[:salt_install] salt_url = config[:salt_bootstrap_url] bootstrap_options = config[:salt_bootstrap_options] salt_version = config[:salt_version] <<-POWERSHELL if (Test-Path c:\\salt\\salt-call.bat) { $installed_version = $(c:\\salt\\salt-call.bat --version).split(' ')[1] } if (-Not $(Test-Path c:\\temp)) { New-Item -Path c:\\temp -itemtype directory } if (-Not $installed_version -And "#{salt_install}" -eq "bootstrap") { (New-Object net.webclient).DownloadFile("#{salt_url}", "c:\\temp\\salt_bootstrap.ps1") #{sudo('powershell')} c:\\temp\\salt_bootstrap.ps1 #{bootstrap_options} } $FULL_SALT_VERSION = $(c:\\salt\\salt-call.bat --version).split(' ')[1] if ($FULL_SALT_VERSION) { $YEAR = $FULL_SALT_VERSION.split('.')[0] $MONTH = $FULL_SALT_VERSION.split('.')[1] $SALT_VERSION = "$YEAR.$MONTH" } if (-Not $SALT_VERSION) { write-host "No salt-minion installed, install must have failed!!" write-host "salt_install = #{salt_install}" write-host "salt_url = #{salt_url}" write-host "bootstrap_options = #{bootstrap_options}" } elseif ($SALT_VERSION -eq "#{salt_version}" -Or "#{salt_version}" -eq "latest" -Or "#{salt_version}" -eq "$FULL_SALT_VERSION") { write-host "You asked for #{salt_version} and you have ${FULL_SALT_VERSION} installed, sweet!" } elseif ($SALT_VERSION -And "#{salt_install}" -eq "bootstrap") { write-host "You asked for bootstrap install and you have got $SALT_VERSION, hope that's ok!" } else { write-host "You asked for #{salt_version} and you have got $SALT_VERSION installed, dunno how to fix that, sorry!" exit 2 } #{install_chef} POWERSHELL %> kitchen-salt-0.4.0/lib/kitchen/provisioner/spm.erb0000644000175000017500000000064513410365464022031 0ustar mathieumathieuspm_build_dir: <%= File.join(config[:root_path]) %>/build formula_path: <%= File.join(config[:root_path], (windows_os? ? config[:salt_spm_root].gsub('/', '\\') : config[:salt_spm_root])) %>/salt pillar_path: <%= File.join(config[:root_path], (windows_os? ? config[:salt_spm_root].gsub('/', '\\') : config[:salt_spm_root])) %>/pillar root_dir: <%= config[:root_path] %> spm_build_exclude: - .git - .svn - .idea - .kitchen kitchen-salt-0.4.0/lib/kitchen/provisioner/dependencies.erb0000644000175000017500000000544413410365464023662 0ustar mathieumathieu<%= def install_dependencies script = '' script += <<-INSTALL test ! -e "$(dirname $0)/formula-fetch.sh" || . "$(dirname $0)/formula-fetch.sh" test ! -e "$(dirname $0)/repository-setup.sh" || . "$(dirname $0)/repository-setup.sh" export SALT_ROOT="#{config[:root_path]}/#{config[:salt_file_root]}"; export SALT_SHARE_DIR='/usr/share/salt-formulas' export DEBIAN_FRONTEND=noninteractive mkdir -p "${SALT_ROOT}"; mkdir -p "${SALT_SHARE_DIR}"; INSTALL # setup apt config[:vendor_repo].select{|x| x[:type]=='apt'}.each do |repo| id =repo[:url].gsub(/[htp:\/.]/,'') arch=repo[:arch] || '[arch=amd64]' rurl=repo[:url] comp=repo[:components] || 'main' dist=repo[:distribution] || '$DISTRIB_CODENAME' rkey=repo[:key_url] script += <<-INSTALL apt_repo_add "#{id}" "#{arch}" "#{rurl}" "#{comp}" "#{dist}" "#{rkey}"; INSTALL end # setup ppa config[:vendor_repo].select{|x| x[:type]=='ppa'}.each do |repo| script += <<-INSTALL add-apt-repository "ppa:#{repo[:name]}" -y; INSTALL end # TODO, setup yum repo # update resources config[:vendor_repo].map{|x| x[:type]}.uniq.each do |type| case type when 'apt' script += <<-INSTALL apt-get update -q; sleep 10; INSTALL when 'yum' script += <<-INSTALL yum update; sleep 10; INSTALL when 'spm' script += <<-INSTALL spm update_repo; INSTALL end end # install formulas config[:dependencies].each do |formula| if formula.key?(:repo) case formula[:repo] when 'git' script += <<-INSTALL fetchGitFormula #{formula[:source]} "#{formula[:name]}" "#{formula[:branch] || 'master'}" INSTALL when 'spm' if formula[:package].nil? script += <<-INSTALL spm -c #{config[:root_path]}/etc/salt install -y #{formula[:name]}; INSTALL else script += <<-INSTALL curl -O #{formula[:package]}; spm -c #{config[:root_path]}/etc/salt local install -y "$(basename #{formula[:package]})"; INSTALL end when 'yum' script += <<-INSTALL yum install -y #{formula[:package]||formula[:name]}; INSTALL when 'apt' script += <<-INSTALL apt-get install -y #{formula[:package]||formula[:name]}; INSTALL end elsif formula.key?(:path) prepare_formula formula[:path], formula[:name] end end script += <<-INSTALL linkFormulas "$SALT_ROOT" chown -R "${SUDO_USER:-$USER}" "${SALT_SHARE_DIR}" "${SALT_ROOT}"; echo "Content of $SALT_ROOT :"; ls -la "$SALT_ROOT"; INSTALL return script end <<-INSTALL #!/usr/bin/env bash echo "Install External Dependencies"; #{install_dependencies} INSTALL %> kitchen-salt-0.4.0/lib/kitchen/provisioner/formula-fetch.sh0000755000175000017500000000642513410365464023635 0ustar mathieumathieu#!/bin/bash # Usage: # ./formula-fetch.sh # # Example: # GIT_FORMULAS_PATH=.vendor/formulas ./formula-fetch.sh https://github.com/salt-formulas/salt-formula-salt # -- # GIT_FORMULAS_PATH=/usr/share/salt-formulas/env/_formulas # xargs -n1 ./formula-fetch.sh < dependencies.txt # Parse git dependencies from metadata.yml # $1 - path to /metadata.yml # sample to output: # https://github.com/salt-formulas/salt-formula-git git # https://github.com/salt-formulas/salt-formula-salt salt function fetchDependencies() { METADATA="$1"; grep -E "^dependencies:" "$METADATA" >/dev/null || return 0 # shellcheck disable=SC2086 (python - "$METADATA" | while read -r dep; do fetchGitFormula $dep; done) <<-DEPS import sys,yaml for dep in yaml.load(open(sys.argv[1], "ro"))["dependencies"]: print("{source} {name}").format(**dep) DEPS } # Fetch formula from git repo # $1 - formula git repo url # $2 - formula name (optional) # $3 - branch (optional) function fetchGitFormula() { test -n "${FETCHED}" || declare -a FETCHED=() export GIT_FORMULAS_PATH=${GIT_FORMULAS_PATH:-/usr/share/salt-formulas/env/_formulas} mkdir -p "$GIT_FORMULAS_PATH" if [ -n "$1" ]; then source="$1" name="$2" test -n "$name" || name="${source//*salt-formula-}" test -z "$3" && branch=master || branch=$3 if ! [[ "${FETCHED[*]}" =~ $name ]]; then # dependency not yet fetched echo "Fetching: $name" if test -e "$GIT_FORMULAS_PATH/$name"; then pushd "$GIT_FORMULAS_PATH/$name" &>/dev/null test ! -e .git || git pull -r popd &>/dev/null else echo "git clone $source $GIT_FORMULAS_PATH/$name -b $branch" git clone "$source" "$GIT_FORMULAS_PATH/$name" -b "$branch" fi # install dependencies FETCHED+=($name) if [ -e "$GIT_FORMULAS_PATH/$name/metadata.yml" ]; then fetchDependencies "$GIT_FORMULAS_PATH/$name/metadata.yml" fi fi else echo Usage: fetchGitFormula "" "[local formula directory name]" "[branch]" fi } function linkFormulas() { # OPTIONAL: Link formulas from git/pkg SALT_ROOT=$1 SALT_ENV=${2:-/usr/share/salt-formulas/env} if [[ -e "$SALT_ENV" ]]; then # form git, development versions if [[ -e "$SALT_ENV/_formulas" ]]; then GIT_FORMULA_LIST=$(find "$SALT_ENV"/_formulas -maxdepth 1 -mindepth 1 -type d) for formula in $GIT_FORMULA_LIST do name=$(basename "$formula") if [[ ! -L "$SALT_ROOT/$name" ]]; then ln -fs "$formula/$name" "$SALT_ROOT/$name" fi find "$formula" -maxdepth 1 -mindepth 1 -type d |grep -E "_(modules|states|grains|renderers|returners)" | xargs -I{} \ basename {}| xargs -I{} cp -rs "$formula"/{} "$SALT_ROOT"/ done fi # form pkgs find "$SALT_ENV" -maxdepth 1 -mindepth 1 -path "*_formulas*" -prune -o -name "*" -type d -print0| xargs -I{} -0 -n1 --no-run-if-empty basename {} | xargs -I{} --no-run-if-empty \ ln -fs "$SALT_ENV"/{} "$SALT_ROOT"/{}; fi } # detect if file is being sourced [[ "$0" != "${BASH_SOURCE[0]}" ]] || { # if executed, run implicit function fetchGitFormula "${@}" } kitchen-salt-0.4.0/lib/kitchen/provisioner/gpgkey.erb0000644000175000017500000000073113410365464022514 0ustar mathieumathieu<%= <<-GPGKEY sh -c ' #{Util.shell_helpers} # if gpg key exists, install echo "Checking for a GPG Key" if [ -f "#{config[:root_path]}/gpgkey.txt" ]; then echo "Installing \"#{config[:root_path]}/gpgkey.txt\"" GPGKEY_DIR="#{config[:root_path]}/etc/salt/gpgkeys/" mkdir -p "$GPGKEY_DIR" chmod 0700 "$GPGKEY_DIR" gpg --allow-secret-key-import --no-default-keyring --homedir "$GPGKEY_DIR" --import < "#{config[:root_path]}/gpgkey.txt" fi' GPGKEY %> kitchen-salt-0.4.0/lib/kitchen/provisioner/99-minion.conf.erb0000644000175000017500000000003113410365464023673 0ustar mathieumathieu<%= safe_hash.to_yaml %> kitchen-salt-0.4.0/lib/kitchen/provisioner/install.erb0000644000175000017500000001205113410365464022672 0ustar mathieumathieu<%= salt_install = config[:salt_install] salt_url = config[:salt_bootstrap_url] salt_version = config[:salt_version] bootstrap_options = config[:salt_bootstrap_options] % [salt_version] salt_apt_repo = config[:salt_apt_repo] salt_apt_repo_key = config[:salt_apt_repo_key] salt_ppa = config[:salt_ppa] salt_yum_rpm_key = config[:salt_yum_rpm_key] % [salt_version] salt_yum_repo = config[:salt_yum_repo] % [salt_version] salt_yum_repo_key = config[:salt_yum_repo_key] % [salt_version] salt_yum_repo_latest = config[:salt_yum_repo_latest] salt_pip_pkg = config[:pip_install] salt_pip_bin = config[:pip_bin] salt_pip_install_command = ' install' salt_pip_install_command += ' -e' if config[:pip_editable] salt_pip_install_command += ' --index-url ' + config[:pip_index_url] if config[:pip_index_url] config[:pip_extra_index_url].each do |url| salt_pip_install_command += ' --extra-index-url ' + url end <<-INSTALL sh -c ' #{Util.shell_helpers} # what version of salt is installed? command -v salt-call >/dev/null 2>&1 && SALT_VERSION=$(salt-call --version|cut -d " " -f 2) command -v locale-gen >/dev/null 2>&1 && #{sudo('locale-gen')} en_US.UTF-8 set +x export DEBIAN_FRONTEND=noninteractive if [ -z "${SALT_VERSION}" -a "#{salt_install}" = "bootstrap" ] then mkdir -p "#{config[:root_path]}" BOOTSTRAP="#{config[:root_path]}/bootstrap.sh" if ! test -f $BOOTSTRAP; then do_download #{salt_url} "$BOOTSTRAP" fi #{sudo('sh')} $BOOTSTRAP #{bootstrap_options} elif [ -z "${SALT_VERSION}" -a "#{salt_install}" = "pip" ] then echo "Makesure setuptools is new enough" #{sudo(salt_pip_bin)} install "setuptools>=30" echo #{sudo(salt_pip_bin)} #{salt_pip_install_command} #{salt_pip_pkg} #{sudo(salt_pip_bin)} #{salt_pip_install_command} #{salt_pip_pkg} elif [ -z "${SALT_VERSION}" -a "#{salt_install}" = "apt" ] then if [ ! $(command -v lsb_release &>/dev/null) ]; then . /etc/lsb-release else DISTRIB_CODENAME=$(lsb_release -s -c) fi echo "-----> Install apt-transport-https" #{sudo('apt-get')} update #{sudo('apt-get')} install -y apt-transport-https gnupg echo "-----> Configuring apt repo for salt #{salt_version}" echo "deb #{salt_apt_repo}/#{salt_version} ${DISTRIB_CODENAME} main" | #{sudo('tee')} /etc/apt/sources.list.d/salt-#{salt_version}.list do_download #{salt_apt_repo_key} /tmp/repo.key #{sudo('apt-key')} add /tmp/repo.key #{sudo('apt-get')} update sleep 10 echo "-----> Installing salt-minion (#{salt_version})" #{sudo('apt-get')} install -y salt-minion salt-common salt-master elif [ -z "${SALT_VERSION}" -a "#{salt_install}" = "distrib" ] then #{sudo('apt-get')} update #{sudo('apt-get')} install -y salt-minion salt-master elif [ -z "${SALT_VERSION}" -a "#{salt_install}" = "ppa" ] then #{sudo('apt-add-repository')} -y #{salt_ppa} #{sudo('apt-get')} update #{sudo('apt-get')} install -y salt-minion salt-common salt-master elif [ -z "${SALT_VERSION}" -a "#{salt_install}" = "yum" ] then if [ -z "#{salt_version}" ] then echo "-----> Installing yum repo for salt latest" #{sudo('yum')} install #{salt_yum_repo_latest} else echo "-----> Installing yum repo for salt #{salt_version}" #{sudo('rpm')} --import '#{salt_yum_rpm_key}' #{sudo('tee')} /etc/yum.repos.d/saltstack.repo < Installing salt-minion (#{salt_version})" #{sudo('yum')} install -y salt-minion salt-common salt-master fi # check again, now that an install of some form should have happened command -v salt-call >/dev/null 2>&1 && FULL_SALT_VERSION=$(salt-call --version|cut -d " " -f 2) # extract short format of Salt version if [ ! -z "${FULL_SALT_VERSION}" ] then YEAR=$(echo "$FULL_SALT_VERSION" | cut -d "." -f1) MONTH=$(echo "$FULL_SALT_VERSION" | cut -d "." -f2) SALT_VERSION="${YEAR}.${MONTH}" fi if [ -z "${SALT_VERSION}" ] then echo "No salt-minion installed, install must have failed!!" echo "salt_install = #{salt_install}" echo "salt_url = #{salt_url}" echo "bootstrap_options = #{bootstrap_options}" echo "salt_version = #{salt_version}" echo "salt_apt_repo = #{salt_apt_repo}" echo "salt_apt_repo_key = #{salt_apt_repo_key}" echo "salt_ppa = #{salt_ppa}" echo "salt_yum_rpm_key = #{salt_yum_rpm_key}" echo "salt_yum_repo = #{salt_yum_repo}" echo "salt_yum_repo_key = #{salt_yum_repo_key}" echo "salt_yum_repo_latest = #{salt_yum_repo_latest}" exit 2 elif [ "${SALT_VERSION}" = "#{salt_version}" -o "#{salt_version}" = "latest" -o "#{salt_version}" = "${FULL_SALT_VERSION}" ] then echo "You asked for #{salt_version} and you have ${FULL_SALT_VERSION} installed, sweet!" elif [ ! -z "${SALT_VERSION}" -a "#{salt_install}" = "bootstrap" ] then echo "You asked for bootstrap install and you have got ${SALT_VERSION}, hope thats ok!" else echo "You asked for #{salt_version} and you have got ${SALT_VERSION} installed, dunno how to fix that, sorry!" exit 2 fi #{install_chef}' INSTALL %> kitchen-salt-0.4.0/lib/kitchen/provisioner/minion.erb0000644000175000017500000000124313410365464022516 0ustar mathieumathieu# @markup text local: true state_top: top.sls root_dir: <%= config[:root_path] %> file_roots: <%= config[:salt_env] %>: - <%= os_join(config[:root_path], config[:salt_file_root]) %> - <%= os_join(config[:root_path], config[:salt_spm_root], 'salt') %> pillar_roots: <%= config[:salt_env] %>: - <%= os_join(config[:root_path], config[:salt_pillar_root]) %> - <%= os_join(config[:root_path], config[:salt_spm_root], 'pillar') %> <% if windows_os? %> file_client: local winrepo_dir: <%= os_join(config[:root_path], config[:salt_file_root], 'win', 'repo') %> winrepo_dir_ng: <%= os_join(config[:root_path], config[:salt_file_root], 'win', 'repo-ng') %> <% end %> kitchen-salt-0.4.0/lib/kitchen/provisioner/repository-setup.sh0000755000175000017500000000133013410365464024444 0ustar mathieumathieu#!/bin/bash function apt_repo_add { id="$1" arch="$2" rurl="$3" comp="$4" dist="$5" rkey="$6" test -e /tmp/apt_repo_vendor_"${id}".key || { echo "-----> Configuring formula apt vendor_repo ${rurl}" eval "$(cat /etc/lsb-release)" if curl -k "${rkey}" -o /tmp/apt_repo_vendor_"${id}".key; then echo "deb ${arch} ${rurl} ${dist} ${comp}" | tee /etc/apt/sources.list.d/vendor-repo.list apt-key add /tmp/apt_repo_vendor_"${id}".key fi }; } # detect if file is being sourced [[ "$0" != "${BASH_SOURCE[0]}" ]] || { # if executed, run implicit function #apt_repo_add "${@}" echo 'Usage: apt_repo_add "custom id" "arch" "repo url" "components" "distribution" "repo gpg key"'; } kitchen-salt-0.4.0/lib/kitchen-salt/0000755000175000017500000000000013410365464017115 5ustar mathieumathieukitchen-salt-0.4.0/lib/kitchen-salt/pillars.rb0000644000175000017500000000677713410365464021131 0ustar mathieumathieumodule Kitchen module Salt module Pillars private def prepare_pillars info("Preparing pillars into #{config[:salt_pillar_root]}") pillars = config[:pillars] if config.key?(:'pillars-from-files') info("pillars-from-files is deprecated in favor of pillars_from_files") pillars_from_files = config[:'pillars-from-files'] else pillars_from_files = config[:'pillars_from_files'] end pillars_from_directories = config[:pillars_from_directories] debug("Pillars Directories: #{pillars_from_directories}") if pillars_from_directories.any? pillars_from_directories.each do |dir| if dir.is_a?(Hash) local_pillar_path = File.expand_path(dir[:source]) sandbox_pillar_path = File.join(sandbox_path, dir[:dest]) info("Copying pillars from #{dir[:source]} to #{dir[:dest]}") else local_pillar_path = File.expand_path(dir) sandbox_pillar_path = File.join(sandbox_path, '/srv/pillar') info("Copying pillars from #{dir} to /srv/pillar") end cp_r_with_filter(local_pillar_path, sandbox_pillar_path, config[:salt_copy_filter]) end end debug("Pillars Hash: #{pillars}") if pillars.nil? && pillars_from_files.nil? if not config[:local_salt_root].nil? pillars_location = File.join(config[:local_salt_root], 'pillar') sandbox_pillar_path = File.join(sandbox_path, config[:salt_pillar_root]) cp_r_with_filter(pillars_location, sandbox_pillar_path, config[:salt_copy_filter]) return end return end # we get a hash with all the keys converted to symbols, salt doesn't like this # to convert all the keys back to strings again pillars = unsymbolize(pillars) debug("unsymbolized pillars hash: #{pillars}") # write out each pillar (we get key/contents pairs) prepare_pillar_files(pillars) # copy the pillars from files straight across, as YAML.load/to_yaml and # munge multiline strings unless pillars_from_files.nil? prepare_pillars_from_files(pillars_from_files) end end def prepare_pillar_files(pillars) pillars.each do |key, contents| # convert the hash to yaml pillar = contents.to_yaml # .to_yaml will produce ! '*' for a key, Salt doesn't like this either pillar.gsub!(/(!\s'\*')/, "'*'") # generate the filename sandbox_pillar_path = File.join(sandbox_path, config[:salt_pillar_root], key) debug("Rendered pillar yaml for #{key}:\n #{pillar}") write_raw_file(sandbox_pillar_path, pillar) end end def copy_pillar(key, srcfile) debug("Copying external pillar: #{key}, #{srcfile}") # generate the filename sandbox_pillar_path = File.join(sandbox_path, config[:salt_pillar_root], key) # create the directory where the pillar file will go FileUtils.mkdir_p(File.dirname(sandbox_pillar_path)) # copy the file across FileUtils.copy srcfile, sandbox_pillar_path end def prepare_pillars_from_files(pillars) external_pillars = unsymbolize(pillars) debug("external_pillars (unsymbolize): #{external_pillars}") external_pillars.each do |key, srcfile| copy_pillar(key, srcfile) end end end end end kitchen-salt-0.4.0/lib/kitchen-salt/util.rb0000644000175000017500000000407013410365464020420 0ustar mathieumathieurequire 'find' module Kitchen module Salt module Util private def unsymbolize(obj) if obj.is_a? Hash obj.each_with_object({}) do |(k, v), a| a[k.to_s] = unsymbolize(v) a end elsif obj.is_a? Array obj.each_with_object([]) do |e, a| a << unsymbolize(e) a end else obj end end def cp_r_with_filter(source_paths, target_path, filter = []) debug("cp_r_with_filter:source_paths = #{source_paths}") debug("cp_r_with_filter:target_path = #{target_path}") debug("cp_r_with_filter:filter = #{filter}") Array(source_paths).each do |source_path| _cp_r_with_filter(source_path, target_path, filter) end end def _cp_r_with_filter(source_path, target_path, filter = []) Find.find(source_path) do |source| target = source.sub(/^#{source_path}/, target_path) debug("cp_r_with_filter:source = #{source}") debug("cp_r_with_filter:target = #{target}") filtered = filter.include?(File.basename(source)) if File.directory? source if filtered debug("Found #{source} in #{filter}, pruning it from the Find") Find.prune end FileUtils.mkdir_p target unless File.exist? target FileUtils.cp_r "#{source}/.", target if File.symlink? source elsif filtered debug("Found #{source} in #{filter}, not copying file") elsif File.symlink? source FileUtils.symlink File.readlink(source), target else FileUtils.copy source, target end end end def write_raw_file(name, contents) FileUtils.mkdir_p(File.dirname(name)) File.open(name, 'wb') do |file| file.write(contents) end end def write_hash_file(name, contents) raw_contents = unsymbolize(contents).to_yaml write_raw_file(name, raw_contents) end end end end kitchen-salt-0.4.0/lib/kitchen-salt/version.rb0000644000175000017500000000010413410365464021122 0ustar mathieumathieumodule Kitchen module Salt VERSION = '0.4.0'.freeze end end kitchen-salt-0.4.0/lib/kitchen-salt/states.rb0000644000175000017500000001047413410365464020753 0ustar mathieumathieumodule Kitchen module Salt module States private def prepare_state_top info('Preparing state_top') sandbox_state_top_path = File.join(sandbox_path, config[:salt_state_top]) if config[:state_top_from_file] == false # use the top.sls embedded in .kitchen.yml # we get a hash with all the keys converted to symbols, salt doesn't like this # to convert all the keys back to strings again state_top_content = unsymbolize(config[:state_top]).to_yaml # .to_yaml will produce ! '*' for a key, Salt doesn't like this either state_top_content.gsub!(/(!\s'\*')/, "'*'") else # load a top.sls from disk if config[:local_salt_root].nil? top_file = 'top.sls' else top_file = File.join(config[:local_salt_root], 'salt/top.sls') end state_top_content = File.read(top_file) end write_raw_file(sandbox_state_top_path, state_top_content) end def prepare_states if config[:state_collection] || config[:is_file_root] || !config[:local_salt_root].nil? prepare_state_collection elsif config[:remote_states] prepare_remote_states else prepare_formula config[:kitchen_root], config[:formula] prepare_vendor_states end end def prepare_vendor_states vendor_path = config[:vendor_path] unless vendor_path.nil? if Pathname.new(vendor_path).exist? Dir[File.join(vendor_path, '*')].each do |d| prepare_formula vendor_path, File.basename(d) end else # :vendor_path was set, but not valid raise UserError, "kitchen-salt: Invalid vendor_path set: #{vendor_path}" end end end def prepare_formula_dir(path, subdir) src = File.join(path, subdir) if File.directory?(src) debug("prepare_formula_dir: #{src} exists, copying..") subdir_path = File.join(sandbox_path, config[:salt_file_root], subdir) FileUtils.mkdir_p(subdir_path) cp_r_with_filter(src, subdir_path, config[:salt_copy_filter]) else debug("prepare_formula_dir: #{src} doesn't exist, skipping.") end end def prepare_formula(path, formula) info("Preparing formula: #{formula} from #{path}") debug("Using config #{config}") formula_dir = File.join(sandbox_path, config[:salt_file_root], formula) FileUtils.mkdir_p(formula_dir) cp_r_with_filter(File.join(path, formula), formula_dir, config[:salt_copy_filter]) # copy across the _modules etc directories for python implementation %w(_modules _states _grains _renderers _returners).each do |extrapath| prepare_formula_dir(path, extrapath) end end def prepare_state_collection info('Preparing state collection') collection_name = config[:collection_name] formula = config[:formula] if collection_name.nil? && formula.nil? info('neither collection_name or formula have been set, assuming this is a pre-built collection') collection_name = '' elsif collection_name.nil? collection_name = formula end if config[:local_salt_root].nil? states_location = config[:kitchen_root] else states_location = File.join(config[:local_salt_root], 'salt') end collection_dir = File.join(sandbox_path, config[:salt_file_root], collection_name) FileUtils.mkdir_p(collection_dir) cp_r_with_filter(states_location, collection_dir, config[:salt_copy_filter]) end def prepare_remote_states info('Preparing remote states') remoteconf = config[:remote_states] if remoteconf[:repo] == 'git' debug("Cloning #{remoteconf[:name]}") require 'git' repo = Git.clone(remoteconf[:name], File.join(sandbox_path, config[:salt_file_root]), opts={:branch => remoteconf[:branch]}) end if remoteconf[:testingdir] dest = File.join(sandbox_path, remoteconf[:testingdir]) FileUtils.mkdir_p(dest) cp_r_with_filter(config[:kitchen_root], dest, config[:salt_copy_filter]) end end end end end