kitchen-salt 0.0.24 → 0.0.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/kitchen-salt/pillars.rb +73 -0
- data/lib/kitchen-salt/states.rb +107 -0
- data/lib/kitchen-salt/util.rb +69 -0
- data/lib/kitchen-salt/version.rb +1 -1
- data/lib/kitchen/provisioner/dependencies.erb +99 -0
- data/lib/kitchen/provisioner/formula-fetch.sh +82 -0
- data/lib/kitchen/provisioner/install.erb +82 -0
- data/lib/kitchen/provisioner/install_win.erb +32 -0
- data/lib/kitchen/provisioner/minion.erb +13 -0
- data/lib/kitchen/provisioner/repository-setup.sh +26 -0
- data/lib/kitchen/provisioner/salt_solo.rb +182 -366
- metadata +12 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2508f6579671b6cfbb285f7024faa9c4265645d9
|
4
|
+
data.tar.gz: f506596a5019cea93aaada988025bcc1b691a9d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8af0c3817e2fd7e454eb7343dd2b9d013caa7e42a228c53a2fe46231390bb8b1f73b9aa08a59d74ce6e5c565039ae53ec21979c424a8cc99b9b74986cf8fa6ed
|
7
|
+
data.tar.gz: 34f6645a153a85fd2126491768c2402776d4235f31e132b5e7e75de757cd40e63de05119b9d4c2330698732ba4ff199e3bbcc43391d8841f11ef29be2ee4918d
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Kitchen
|
2
|
+
module Salt
|
3
|
+
module Pillars
|
4
|
+
private
|
5
|
+
|
6
|
+
def prepare_pillars
|
7
|
+
info("Preparing pillars into #{config[:salt_pillar_root]}")
|
8
|
+
|
9
|
+
pillars = config[:pillars]
|
10
|
+
pillars_from_files = config[:'pillars-from-files']
|
11
|
+
debug("Pillars Hash: #{pillars}")
|
12
|
+
|
13
|
+
if pillars.nil? && pillars_from_files.nil?
|
14
|
+
if not config[:local_salt_root].nil?
|
15
|
+
pillars_location = File.join(config[:local_salt_root], 'pillar')
|
16
|
+
sandbox_pillar_path = File.join(sandbox_path, config[:salt_pillar_root])
|
17
|
+
cp_r_with_filter(pillars_location, sandbox_pillar_path, config[:salt_copy_filter])
|
18
|
+
return
|
19
|
+
end
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
# we get a hash with all the keys converted to symbols, salt doesn't like this
|
24
|
+
# to convert all the keys back to strings again
|
25
|
+
pillars = unsymbolize(pillars)
|
26
|
+
debug("unsymbolized pillars hash: #{pillars}")
|
27
|
+
|
28
|
+
# write out each pillar (we get key/contents pairs)
|
29
|
+
prepare_pillar_files(pillars)
|
30
|
+
|
31
|
+
# copy the pillars from files straight across, as YAML.load/to_yaml and
|
32
|
+
# munge multiline strings
|
33
|
+
unless pillars_from_files.nil?
|
34
|
+
prepare_pillars_from_files(pillars_from_files)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def prepare_pillar_files(pillars)
|
39
|
+
pillars.each do |key, contents|
|
40
|
+
# convert the hash to yaml
|
41
|
+
pillar = contents.to_yaml
|
42
|
+
|
43
|
+
# .to_yaml will produce ! '*' for a key, Salt doesn't like this either
|
44
|
+
pillar.gsub!(/(!\s'\*')/, "'*'")
|
45
|
+
|
46
|
+
# generate the filename
|
47
|
+
sandbox_pillar_path = File.join(sandbox_path, config[:salt_pillar_root], key)
|
48
|
+
|
49
|
+
debug("Rendered pillar yaml for #{key}:\n #{pillar}")
|
50
|
+
write_raw_file(sandbox_pillar_path, pillar)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def copy_pillar(key, srcfile)
|
55
|
+
debug("Copying external pillar: #{key}, #{srcfile}")
|
56
|
+
# generate the filename
|
57
|
+
sandbox_pillar_path = File.join(sandbox_path, config[:salt_pillar_root], key)
|
58
|
+
# create the directory where the pillar file will go
|
59
|
+
FileUtils.mkdir_p(File.dirname(sandbox_pillar_path))
|
60
|
+
# copy the file across
|
61
|
+
FileUtils.copy srcfile, sandbox_pillar_path
|
62
|
+
end
|
63
|
+
|
64
|
+
def prepare_pillars_from_files(pillars)
|
65
|
+
external_pillars = unsymbolize(pillars)
|
66
|
+
debug("external_pillars (unsymbolize): #{external_pillars}")
|
67
|
+
external_pillars.each do |key, srcfile|
|
68
|
+
copy_pillar(key, srcfile)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Kitchen
|
2
|
+
module Salt
|
3
|
+
module States
|
4
|
+
private
|
5
|
+
|
6
|
+
def prepare_state_top
|
7
|
+
info('Preparing state_top')
|
8
|
+
|
9
|
+
sandbox_state_top_path = File.join(sandbox_path, config[:salt_state_top])
|
10
|
+
|
11
|
+
if config[:state_top_from_file] == false
|
12
|
+
# use the top.sls embedded in .kitchen.yml
|
13
|
+
|
14
|
+
# we get a hash with all the keys converted to symbols, salt doesn't like this
|
15
|
+
# to convert all the keys back to strings again
|
16
|
+
state_top_content = unsymbolize(config[:state_top]).to_yaml
|
17
|
+
# .to_yaml will produce ! '*' for a key, Salt doesn't like this either
|
18
|
+
state_top_content.gsub!(/(!\s'\*')/, "'*'")
|
19
|
+
else
|
20
|
+
# load a top.sls from disk
|
21
|
+
if config[:local_salt_root].nil?
|
22
|
+
top_file = 'top.sls'
|
23
|
+
else
|
24
|
+
top_file = File.join(config[:local_salt_root], 'salt/top.sls')
|
25
|
+
end
|
26
|
+
state_top_content = File.read(top_file)
|
27
|
+
end
|
28
|
+
|
29
|
+
write_raw_file(sandbox_state_top_path, state_top_content)
|
30
|
+
end
|
31
|
+
|
32
|
+
def prepare_states
|
33
|
+
if config[:state_collection] || config[:is_file_root] || !config[:local_salt_root].nil?
|
34
|
+
prepare_state_collection
|
35
|
+
else
|
36
|
+
prepare_formula config[:kitchen_root], config[:formula]
|
37
|
+
prepare_vendor_states
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
def prepare_vendor_states
|
43
|
+
vendor_path = config[:vendor_path]
|
44
|
+
|
45
|
+
unless vendor_path.nil?
|
46
|
+
if Pathname.new(vendor_path).exist?
|
47
|
+
Dir[File.join(vendor_path, '*')].each do |d|
|
48
|
+
prepare_formula vendor_path, File.basename(d)
|
49
|
+
end
|
50
|
+
else
|
51
|
+
# :vendor_path was set, but not valid
|
52
|
+
raise UserError, "kitchen-salt: Invalid vendor_path set: #{vendor_path}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def prepare_formula_dir(path, subdir)
|
58
|
+
src = File.join(path, subdir)
|
59
|
+
|
60
|
+
if File.directory?(src)
|
61
|
+
debug("prepare_formula_dir: #{src} exists, copying..")
|
62
|
+
subdir_path = File.join(sandbox_path, config[:salt_file_root], subdir)
|
63
|
+
FileUtils.mkdir_p(subdir_path)
|
64
|
+
cp_r_with_filter(src, subdir_path, config[:salt_copy_filter])
|
65
|
+
else
|
66
|
+
debug("prepare_formula_dir: #{src} doesn't exist, skipping.")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def prepare_formula(path, formula)
|
71
|
+
info("Preparing formula: #{formula} from #{path}")
|
72
|
+
debug("Using config #{config}")
|
73
|
+
|
74
|
+
formula_dir = File.join(sandbox_path, config[:salt_file_root], formula)
|
75
|
+
FileUtils.mkdir_p(formula_dir)
|
76
|
+
cp_r_with_filter(File.join(path, formula), formula_dir, config[:salt_copy_filter])
|
77
|
+
|
78
|
+
# copy across the _modules etc directories for python implementation
|
79
|
+
%w(_modules _states _grains _renderers _returners).each do |extrapath|
|
80
|
+
prepare_formula_dir(path, extrapath)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def prepare_state_collection
|
85
|
+
info('Preparing state collection')
|
86
|
+
collection_name = config[:collection_name]
|
87
|
+
formula = config[:formula]
|
88
|
+
|
89
|
+
if collection_name.nil? && formula.nil?
|
90
|
+
info('neither collection_name or formula have been set, assuming this is a pre-built collection')
|
91
|
+
collection_name = ''
|
92
|
+
elsif collection_name.nil?
|
93
|
+
collection_name = formula
|
94
|
+
end
|
95
|
+
|
96
|
+
if config[:local_salt_root].nil?
|
97
|
+
states_location = config[:kitchen_root]
|
98
|
+
else
|
99
|
+
states_location = File.join(config[:local_salt_root], 'salt')
|
100
|
+
end
|
101
|
+
collection_dir = File.join(sandbox_path, config[:salt_file_root], collection_name)
|
102
|
+
FileUtils.mkdir_p(collection_dir)
|
103
|
+
cp_r_with_filter(states_location, collection_dir, config[:salt_copy_filter])
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'find'
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
module Salt
|
5
|
+
module Util
|
6
|
+
private
|
7
|
+
|
8
|
+
def unsymbolize(obj)
|
9
|
+
if obj.is_a? Hash
|
10
|
+
obj.each_with_object({}) do |(k, v), a|
|
11
|
+
a[k.to_s] = unsymbolize(v)
|
12
|
+
a
|
13
|
+
end
|
14
|
+
elsif obj.is_a? Array
|
15
|
+
obj.each_with_object([]) do |e, a|
|
16
|
+
a << unsymbolize(e)
|
17
|
+
a
|
18
|
+
end
|
19
|
+
else
|
20
|
+
obj
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def cp_r_with_filter(source_paths, target_path, filter = [])
|
25
|
+
debug("cp_r_with_filter:source_paths = #{source_paths}")
|
26
|
+
debug("cp_r_with_filter:target_path = #{target_path}")
|
27
|
+
debug("cp_r_with_filter:filter = #{filter}")
|
28
|
+
|
29
|
+
Array(source_paths).each do |source_path|
|
30
|
+
_cp_r_with_filter(source_path, target_path, filter)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def _cp_r_with_filter(source_path, target_path, filter = [])
|
35
|
+
Find.find(source_path) do |source|
|
36
|
+
target = source.sub(/^#{source_path}/, target_path)
|
37
|
+
debug("cp_r_with_filter:source = #{source}")
|
38
|
+
debug("cp_r_with_filter:target = #{target}")
|
39
|
+
filtered = filter.include?(File.basename(source))
|
40
|
+
if File.directory? source
|
41
|
+
if filtered
|
42
|
+
debug("Found #{source} in #{filter}, pruning it from the Find")
|
43
|
+
Find.prune
|
44
|
+
end
|
45
|
+
FileUtils.mkdir_p target unless File.exist? target
|
46
|
+
|
47
|
+
FileUtils.cp_r "#{source}/.", target if File.symlink? source
|
48
|
+
elsif filtered
|
49
|
+
debug("Found #{source} in #{filter}, not copying file")
|
50
|
+
else
|
51
|
+
FileUtils.copy source, target
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def write_raw_file(name, contents)
|
57
|
+
FileUtils.mkdir_p(File.dirname(name))
|
58
|
+
File.open(name, 'wb') do |file|
|
59
|
+
file.write(contents)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def write_hash_file(name, contents)
|
64
|
+
raw_contents = unsymbolize(contents).to_yaml
|
65
|
+
write_raw_file(name, raw_contents)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/kitchen-salt/version.rb
CHANGED
@@ -0,0 +1,99 @@
|
|
1
|
+
<%=
|
2
|
+
|
3
|
+
def install_dependencies
|
4
|
+
script = ''
|
5
|
+
|
6
|
+
script += <<-INSTALL
|
7
|
+
test ! -e "$(dirname $0)/formula-fetch.sh" || . "$(dirname $0)/formula-fetch.sh"
|
8
|
+
test ! -e "$(dirname $0)/repository-setup.sh" || . "$(dirname $0)/repository-setup.sh"
|
9
|
+
|
10
|
+
export SALT_ROOT="#{config[:root_path]}/#{config[:salt_file_root]}";
|
11
|
+
mkdir -p "${SALT_ROOT}";
|
12
|
+
INSTALL
|
13
|
+
|
14
|
+
|
15
|
+
# setup apt
|
16
|
+
config[:vendor_repo].select{|x| x[:type]=='apt'}.each do |repo|
|
17
|
+
id =repo[:url].gsub(/[htp:\/.]/,'')
|
18
|
+
arch=repo[:arch] || '[arch=amd64]'
|
19
|
+
rurl=repo[:url]
|
20
|
+
comp=repo[:components] || 'main'
|
21
|
+
dist=repo[:distribution] || '$DISTRIB_CODENAME'
|
22
|
+
rkey=repo[:key_url]
|
23
|
+
script += <<-INSTALL
|
24
|
+
apt_repo_add "#{id}" "#{arch}" "#{rurl}" "#{comp}" "#{dist}" "#{rkey}";
|
25
|
+
INSTALL
|
26
|
+
end
|
27
|
+
|
28
|
+
# setup ppa
|
29
|
+
config[:vendor_repo].select{|x| x[:type]=='ppa'}.each do |repo|
|
30
|
+
script += <<-INSTALL
|
31
|
+
#{sudo('add-apt-repository')} "ppa:#{repo[:name]}" -y;
|
32
|
+
INSTALL
|
33
|
+
end
|
34
|
+
|
35
|
+
# TODO, setup yum repo
|
36
|
+
|
37
|
+
# update resources
|
38
|
+
config[:vendor_repo].map{|x| x[:type]}.uniq.each do |type|
|
39
|
+
case type
|
40
|
+
when 'apt'
|
41
|
+
script += <<-INSTALL
|
42
|
+
#{sudo('apt-get')} update -q;
|
43
|
+
sleep 10;
|
44
|
+
INSTALL
|
45
|
+
when 'yum'
|
46
|
+
script += <<-INSTALL
|
47
|
+
#{sudo('yum')} update;
|
48
|
+
sleep 10;
|
49
|
+
INSTALL
|
50
|
+
when 'spm'
|
51
|
+
script += <<-INSTALL
|
52
|
+
#{sudo('spm')} update_repo;
|
53
|
+
INSTALL
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# install formulas
|
58
|
+
config[:dependencies].select{|dependency| dependency.has_key?(:repo)}.each do |formula|
|
59
|
+
#unless config[:vendor_repo].has_key?(formula[:repo])
|
60
|
+
# raise UserError, "kitchen-salt: Invalid dependency formula :repo, no such vendor_repo '#{formula[:repo]}' specified."
|
61
|
+
#end
|
62
|
+
case formula[:repo]
|
63
|
+
when 'git'
|
64
|
+
script += <<-INSTALL
|
65
|
+
fetchGitFormula #{formula[:source]} "#{formula[:name]}" "#{formula[:branch] || 'master'}"
|
66
|
+
INSTALL
|
67
|
+
when 'spm'
|
68
|
+
# TODO: SPM should know the sandbox_path is /tmp/kitchen/etc
|
69
|
+
script += <<-INSTALL
|
70
|
+
#{sudo('spm')} install #{formula[:package]||formula[:name]};
|
71
|
+
INSTALL
|
72
|
+
when 'yum'
|
73
|
+
script += <<-INSTALL
|
74
|
+
#{sudo('yum')} install -y #{formula[:package]||formula[:name]};
|
75
|
+
INSTALL
|
76
|
+
when 'apt'
|
77
|
+
script += <<-INSTALL
|
78
|
+
#{sudo('apt-get')} install -y #{formula[:package]||formula[:name]};
|
79
|
+
INSTALL
|
80
|
+
end
|
81
|
+
end
|
82
|
+
script += <<-INSTALL
|
83
|
+
linkFormulas "$SALT_ROOT"
|
84
|
+
#{sudo('chown')} kitchen.kitchen -R /usr/share/salt-formulas;
|
85
|
+
#{sudo('chown')} kitchen.kitchen -R "$SALT_ROOT";
|
86
|
+
ls -la "$SALT_ROOT";
|
87
|
+
INSTALL
|
88
|
+
return script
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
<<-INSTALL
|
93
|
+
#!/bin/bash
|
94
|
+
|
95
|
+
echo "Install External Dependencies";
|
96
|
+
#{install_dependencies}
|
97
|
+
|
98
|
+
INSTALL
|
99
|
+
%>
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# Usage:
|
4
|
+
# ./formula-fetch.sh <Formula URL> <Name> <Branch>
|
5
|
+
#
|
6
|
+
# Example:
|
7
|
+
# GIT_FORMULAS_PATH=.vendor/formulas ./formula-fetch.sh https://github.com/salt-formulas/salt-formula-salt
|
8
|
+
# --
|
9
|
+
# GIT_FORMULAS_PATH=/usr/share/salt-formulas/env/_formulas
|
10
|
+
# xargs -n1 ./formula-fetch.sh < dependencies.txt
|
11
|
+
|
12
|
+
|
13
|
+
# Parse git dependencies from metadata.yml
|
14
|
+
# $1 - path to <formula>/metadata.yml
|
15
|
+
# sample to output:
|
16
|
+
# https://github.com/salt-formulas/salt-formula-git git
|
17
|
+
# https://github.com/salt-formulas/salt-formula-salt salt
|
18
|
+
function fetchDependencies() {
|
19
|
+
METADATA="$1";
|
20
|
+
grep -E "^dependencies:" "$METADATA" >/dev/null || return 0
|
21
|
+
# shellcheck disable=SC2086
|
22
|
+
(python - "$METADATA" | while read -r dep; do fetchGitFormula $dep; done) <<-DEPS
|
23
|
+
import sys,yaml
|
24
|
+
for dep in yaml.load(open(sys.argv[1], "ro"))["dependencies"]:
|
25
|
+
print("{source} {name}").format(**dep)
|
26
|
+
DEPS
|
27
|
+
}
|
28
|
+
|
29
|
+
# Fetch formula from git repo
|
30
|
+
# $1 - formula git repo url
|
31
|
+
# $2 - formula name (optional)
|
32
|
+
# $3 - branch (optional)
|
33
|
+
function fetchGitFormula() {
|
34
|
+
test -n "${FETCHED}" || declare -a FETCHED=()
|
35
|
+
export GIT_FORMULAS_PATH=${GIT_FORMULAS_PATH:-/usr/share/salt-formulas/env/_formulas}
|
36
|
+
mkdir -p "$GIT_FORMULAS_PATH"
|
37
|
+
if [ -n "$1" ]; then
|
38
|
+
source="$1"
|
39
|
+
name="$2"
|
40
|
+
test -n "$name" || name="${source//*salt-formula-}"
|
41
|
+
test -z "$3" && branch=master || branch=$3
|
42
|
+
if ! [[ "${FETCHED[*]}" =~ $name ]]; then # dependency not yet fetched
|
43
|
+
echo "Fetching: $name"
|
44
|
+
if test -e "$GIT_FORMULAS_PATH/$name"; then
|
45
|
+
pushd "$GIT_FORMULAS_PATH/$name" &>/dev/null
|
46
|
+
test ! -e .git || git pull -r
|
47
|
+
popd &>/dev/null
|
48
|
+
else
|
49
|
+
echo "git clone $source $GIT_FORMULAS_PATH/$name -b $branch"
|
50
|
+
git clone "$source" "$GIT_FORMULAS_PATH/$name" -b "$branch"
|
51
|
+
fi
|
52
|
+
# install dependencies
|
53
|
+
FETCHED+=($name)
|
54
|
+
fetchDependencies "$GIT_FORMULAS_PATH/$name/metadata.yml"
|
55
|
+
fi
|
56
|
+
else
|
57
|
+
echo Usage: fetchGitFormula "<git repo>" "[local formula directory name]" "[branch]"
|
58
|
+
fi
|
59
|
+
}
|
60
|
+
|
61
|
+
function linkFormulas() {
|
62
|
+
# OPTIONAL: Link formulas from git/pkg
|
63
|
+
|
64
|
+
SALT_ROOT=$1
|
65
|
+
SALT_ENV=${2:-/usr/share/salt-formulas/env}
|
66
|
+
|
67
|
+
# form git, development versions
|
68
|
+
find "$SALT_ENV"/_formulas -maxdepth 1 -mindepth 1 -type d -print0| xargs -0 -n1 basename | xargs -I{} \
|
69
|
+
ln -fs "$SALT_ENV"/_formulas/{}/{} "$SALT_ROOT"/{};
|
70
|
+
|
71
|
+
# form pkgs
|
72
|
+
find "$SALT_ENV" -path "*_formulas*" -prune -o -name "*" -maxdepth 1 -mindepth 1 -type d -print0| xargs -0 -n1 basename | xargs -I{} \
|
73
|
+
ln -fs "$SALT_ENV"/{} "$SALT_ROOT"/{};
|
74
|
+
|
75
|
+
}
|
76
|
+
|
77
|
+
# detect if file is being sourced
|
78
|
+
[[ "$0" != "${BASH_SOURCE[@]}" ]] || {
|
79
|
+
# if executed, run implicit function
|
80
|
+
fetchGitFormula "${@}"
|
81
|
+
}
|
82
|
+
|
@@ -0,0 +1,82 @@
|
|
1
|
+
|
2
|
+
<%=
|
3
|
+
salt_install = config[:salt_install]
|
4
|
+
salt_url = config[:salt_bootstrap_url]
|
5
|
+
bootstrap_options = config[:salt_bootstrap_options]
|
6
|
+
salt_version = config[:salt_version]
|
7
|
+
salt_apt_repo = config[:salt_apt_repo]
|
8
|
+
salt_apt_repo_key = config[:salt_apt_repo_key]
|
9
|
+
salt_ppa = config[:salt_ppa]
|
10
|
+
|
11
|
+
<<-INSTALL
|
12
|
+
sh -c '
|
13
|
+
#{Util.shell_helpers}
|
14
|
+
|
15
|
+
# what version of salt is installed?
|
16
|
+
SALT_VERSION=`salt-call --version | cut -d " " -f 2`
|
17
|
+
set +x
|
18
|
+
|
19
|
+
|
20
|
+
if [ -z "${SALT_VERSION}" -a "#{salt_install}" = "bootstrap" ]
|
21
|
+
then
|
22
|
+
do_download #{salt_url} /tmp/bootstrap-salt.sh
|
23
|
+
#{sudo('sh')} /tmp/bootstrap-salt.sh #{bootstrap_options}
|
24
|
+
elif [ -z "${SALT_VERSION}" -a "#{salt_install}" = "apt" ]
|
25
|
+
then
|
26
|
+
if [ ! $(command -v lsb_release &>/dev/null) ]; then
|
27
|
+
. /etc/lsb-release
|
28
|
+
else
|
29
|
+
DISTRIB_CODENAME=$(lsb_release -s -c)
|
30
|
+
fi
|
31
|
+
|
32
|
+
echo "-----> Configuring apt repo for salt #{salt_version}"
|
33
|
+
echo "deb #{salt_apt_repo}/#{salt_version} ${DISTRIB_CODENAME} main" | #{sudo('tee')} /etc/apt/sources.list.d/salt-#{salt_version}.list
|
34
|
+
|
35
|
+
do_download #{salt_apt_repo_key} /tmp/repo.key
|
36
|
+
#{sudo('apt-key')} add /tmp/repo.key
|
37
|
+
|
38
|
+
#{sudo('apt-get')} update
|
39
|
+
sleep 10
|
40
|
+
echo "-----> Installing salt-minion (#{salt_version})"
|
41
|
+
#{sudo('apt-get')} install -y python-support
|
42
|
+
#{sudo('apt-get')} install -y salt-minion salt-common
|
43
|
+
elif [ -z "${SALT_VERSION}" -a "#{salt_install}" = "distrib" ]
|
44
|
+
then
|
45
|
+
#{sudo('apt-get')} update
|
46
|
+
#{sudo('apt-get')} install -y salt-minion
|
47
|
+
elif [ -z "${SALT_VERSION}" -a "#{salt_install}" = "ppa" ]
|
48
|
+
then
|
49
|
+
#{sudo('apt-add-repository')} -y #{salt_ppa}
|
50
|
+
#{sudo('apt-get')} update
|
51
|
+
#{sudo('apt-get')} install -y salt-minion salt-common
|
52
|
+
fi
|
53
|
+
|
54
|
+
# check again, now that an install of some form should have happened
|
55
|
+
SALT_VERSION=`salt-call --version | cut -d " " -f 2`
|
56
|
+
|
57
|
+
if [ -z "${SALT_VERSION}" ]
|
58
|
+
then
|
59
|
+
echo "No salt-minion installed, install must have failed!!"
|
60
|
+
echo "salt_install = #{salt_install}"
|
61
|
+
echo "salt_url = #{salt_url}"
|
62
|
+
echo "bootstrap_options = #{bootstrap_options}"
|
63
|
+
echo "salt_version = #{salt_version}"
|
64
|
+
echo "salt_apt_repo = #{salt_apt_repo}"
|
65
|
+
echo "salt_apt_repo_key = #{salt_apt_repo_key}"
|
66
|
+
echo "salt_ppa = #{salt_ppa}"
|
67
|
+
exit 2
|
68
|
+
elif [ "${SALT_VERSION}" = "#{salt_version}" -o "#{salt_version}" = "latest" ]
|
69
|
+
then
|
70
|
+
echo "You asked for #{salt_version} and you have ${SALT_VERSION} installed, sweet!"
|
71
|
+
elif [ ! -z "${SALT_VERSION}" -a "#{salt_install}" = "bootstrap" ]
|
72
|
+
then
|
73
|
+
echo "You asked for bootstrap install and you have got ${SALT_VERSION}, hope thats ok!"
|
74
|
+
else
|
75
|
+
echo "You asked for #{salt_version} and you have got ${SALT_VERSION} installed, dunno how to fix that, sorry!"
|
76
|
+
exit 2
|
77
|
+
fi
|
78
|
+
|
79
|
+
#{install_chef}
|
80
|
+
'
|
81
|
+
INSTALL
|
82
|
+
%>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<%=
|
2
|
+
salt_install = config[:salt_install]
|
3
|
+
salt_url = config[:salt_bootstrap_url]
|
4
|
+
bootstrap_options = config[:salt_bootstrap_options]
|
5
|
+
salt_version = config[:salt_version]
|
6
|
+
|
7
|
+
<<-POWERSHELL
|
8
|
+
if (Test-Path c:\\salt\\salt-call.bat) {
|
9
|
+
$installed_version = $(c:\\salt\\salt-call.bat --version).split(' ')[1]
|
10
|
+
}
|
11
|
+
if (-Not $(Test-Path c:\\temp)) {
|
12
|
+
New-Item -Path c:\\temp -itemtype directory
|
13
|
+
}
|
14
|
+
if (-Not $installed_version -And "#{salt_install}" -eq "bootstrap") {
|
15
|
+
(New-Object net.webclient).DownloadFile("#{salt_url}", "c:\\temp\\salt_bootstrap.ps1")
|
16
|
+
#{sudo('powershell')} c:\\temp\\salt_bootstrap.ps1 #{bootstrap_options}
|
17
|
+
}
|
18
|
+
$installed_version = $(c:\\salt\\salt-call.bat --version).split(' ')[1]
|
19
|
+
if (-Not $installed_version) {
|
20
|
+
write-host "No salt-minion installed, install must have failed!!"
|
21
|
+
write-host "salt_install = #{salt_install}"
|
22
|
+
write-host "salt_url = #{salt_url}"
|
23
|
+
write-host "bootstrap_options = #{bootstrap_options}"
|
24
|
+
} elseif ($installed_version -And "#{salt_install}" -eq "bootstrap") {
|
25
|
+
write-host "You asked for bootstrap install and you have got $installed_version, hope that's ok!"
|
26
|
+
} else {
|
27
|
+
write-host "You asked for #{salt_version} and you have got $installed_version installed, dunno ho to fix that, sorry!"
|
28
|
+
exit 2
|
29
|
+
}
|
30
|
+
#{install_chef}
|
31
|
+
POWERSHELL
|
32
|
+
%>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
state_top: top.sls
|
2
|
+
|
3
|
+
file_client: local
|
4
|
+
|
5
|
+
file_roots:
|
6
|
+
<%= config[:salt_env] %>:
|
7
|
+
|
8
|
+
- <%= File.join(config[:root_path], (windows_os? ? config[:salt_file_root].gsub('/', '\\') : config[:salt_file_root])) %>
|
9
|
+
- <%= File.join(config[:root_path], (windows_os? ? config[:salt_file_root].gsub('/', '\\') : config[:salt_file_root]), 'spm') %>
|
10
|
+
|
11
|
+
pillar_roots:
|
12
|
+
<%= config[:salt_env] %>:
|
13
|
+
- <%= File.join(config[:root_path], (windows_os? ? config[:salt_pillar_root].gsub('/', '\\') : config[:salt_pillar_root])) %>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
function apt_repo_add {
|
4
|
+
id="$1"
|
5
|
+
arch="$2"
|
6
|
+
rurl="$3"
|
7
|
+
comp="$4"
|
8
|
+
dist="$5"
|
9
|
+
rkey="$6"
|
10
|
+
test -e /tmp/apt_repo_vendor_"${id}".key || {
|
11
|
+
echo "-----> Configuring formula apt vendor_repo ${rurl}"
|
12
|
+
eval "$(cat /etc/lsb-release)"
|
13
|
+
if curl -k "${rkey}" -o /tmp/apt_repo_vendor_"${id}".key; then
|
14
|
+
echo "deb ${arch} ${rurl} ${dist} ${comp}" | tee /etc/apt/sources.list.d/vendor-repo.list
|
15
|
+
apt-key add /tmp/apt_repo_vendor_"${id}".key
|
16
|
+
fi
|
17
|
+
};
|
18
|
+
}
|
19
|
+
|
20
|
+
# detect if file is being sourced
|
21
|
+
[[ "$0" != "${BASH_SOURCE[@]}" ]] || {
|
22
|
+
# if executed, run implicit function
|
23
|
+
#apt_repo_add "${@}"
|
24
|
+
echo 'Usage: apt_repo_add "custom id" "arch" "repo url" "components" "distribution" "repo gpg key"';
|
25
|
+
}
|
26
|
+
|
@@ -17,163 +17,122 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
19
|
require 'kitchen/provisioner/base'
|
20
|
-
require '
|
20
|
+
require 'kitchen-salt/util'
|
21
|
+
require 'kitchen-salt/pillars'
|
22
|
+
require 'kitchen-salt/states'
|
21
23
|
require 'fileutils'
|
22
24
|
require 'yaml'
|
23
25
|
|
24
26
|
module Kitchen
|
25
|
-
|
26
27
|
module Provisioner
|
27
|
-
|
28
28
|
# Basic Salt Masterless Provisioner, based on work by
|
29
29
|
#
|
30
30
|
# @author Chris Lundquist (<chris.ludnquist@github.com>)
|
31
|
-
class SaltSolo < Base
|
32
|
-
|
33
|
-
default_config :salt_version, "latest"
|
34
|
-
|
35
|
-
# supported install methods: bootstrap|apt
|
36
|
-
default_config :salt_install, "bootstrap"
|
37
|
-
|
38
|
-
default_config :salt_bootstrap_url, "http://bootstrap.saltstack.org"
|
39
|
-
default_config :salt_bootstrap_options, ""
|
40
31
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
32
|
+
class SaltSolo < Base
|
33
|
+
include Kitchen::Salt::Util
|
34
|
+
include Kitchen::Salt::Pillars
|
35
|
+
include Kitchen::Salt::States
|
36
|
+
|
37
|
+
DEFAULT_CONFIG = {
|
38
|
+
dry_run: false,
|
39
|
+
salt_version: 'latest',
|
40
|
+
salt_install: 'bootstrap',
|
41
|
+
salt_bootstrap_url: 'https://bootstrap.saltstack.org',
|
42
|
+
salt_bootstrap_options: '',
|
43
|
+
salt_apt_repo: 'https://repo.saltstack.com/apt/ubuntu/16.04/amd64/latest',
|
44
|
+
salt_apt_repo_key: 'https://repo.saltstack.com/apt/ubuntu/16.04/amd64/latest/SALTSTACK-GPG-KEY.pub',
|
45
|
+
salt_ppa: 'ppa:saltstack/salt',
|
46
|
+
bootstrap_url: 'https://raw.githubusercontent.com/saltstack/kitchen-salt/master/assets/install.sh',
|
47
|
+
chef_bootstrap_url: 'https://www.getchef.com/chef/install.sh',
|
48
|
+
salt_config: '/etc/salt',
|
49
|
+
salt_minion_config: '/etc/salt/minion',
|
50
|
+
salt_minion_config_template: nil,
|
51
|
+
salt_minion_id: nil,
|
52
|
+
salt_env: 'base',
|
53
|
+
salt_file_root: '/srv/salt',
|
54
|
+
salt_pillar_root: '/srv/pillar',
|
55
|
+
salt_spm_root: '/srv/spm',
|
56
|
+
salt_state_top: '/srv/salt/top.sls',
|
57
|
+
state_collection: false,
|
58
|
+
state_top: {},
|
59
|
+
state_top_from_file: false,
|
60
|
+
salt_run_highstate: true,
|
61
|
+
salt_copy_filter: [],
|
62
|
+
is_file_root: false,
|
63
|
+
require_chef: true,
|
64
|
+
dependencies: [],
|
65
|
+
vendor_path: nil,
|
66
|
+
vendor_repo: {},
|
67
|
+
omnibus_cachier: false,
|
68
|
+
local_salt_root: nil
|
69
|
+
}
|
65
70
|
|
66
71
|
# salt-call version that supports the undocumented --retcode-passthrough command
|
67
|
-
RETCODE_VERSION = '0.17.5'
|
72
|
+
RETCODE_VERSION = '0.17.5'.freeze
|
73
|
+
|
74
|
+
DEFAULT_CONFIG.each do |k, v|
|
75
|
+
default_config k, v
|
76
|
+
end
|
68
77
|
|
69
78
|
def install_command
|
70
|
-
debug(diagnose
|
79
|
+
debug(diagnose)
|
80
|
+
salt_version = config[:salt_version]
|
71
81
|
|
72
82
|
# if salt_verison is set, bootstrap is being used & bootstrap_options is empty,
|
73
83
|
# set the bootstrap_options string to git install the requested version
|
74
|
-
if (
|
75
|
-
debug("Using bootstrap git to install #{
|
76
|
-
config[:salt_bootstrap_options] = "-P git v#{
|
84
|
+
if (salt_version != 'latest') && (config[:salt_install] == 'bootstrap') && config[:salt_bootstrap_options].empty?
|
85
|
+
debug("Using bootstrap git to install #{salt_version}")
|
86
|
+
config[:salt_bootstrap_options] = "-P git v#{salt_version}"
|
77
87
|
end
|
78
88
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
salt_version = config[:salt_version]
|
85
|
-
salt_apt_repo = config[:salt_apt_repo]
|
86
|
-
salt_apt_repo_key = config[:salt_apt_repo_key]
|
87
|
-
salt_ppa = config[:salt_ppa]
|
88
|
-
|
89
|
-
|
90
|
-
<<-INSTALL
|
91
|
-
sh -c '
|
92
|
-
#{Util.shell_helpers}
|
93
|
-
|
94
|
-
# what version of salt is installed?
|
95
|
-
SALT_VERSION=`salt-call --version | cut -d " " -f 2`
|
96
|
-
|
97
|
-
|
98
|
-
if [ -z "${SALT_VERSION}" -a "#{salt_install}" = "bootstrap" ]
|
99
|
-
then
|
100
|
-
do_download #{salt_url} /tmp/bootstrap-salt.sh
|
101
|
-
#{sudo('sh')} /tmp/bootstrap-salt.sh #{bootstrap_options}
|
102
|
-
elif [ -z "${SALT_VERSION}" -a "#{salt_install}" = "apt" ]
|
103
|
-
then
|
104
|
-
if [ -z "`which lsb_release`" ]; then
|
105
|
-
. /etc/lsb-release
|
106
|
-
else
|
107
|
-
DISTRIB_CODENAME=`lsb_release -s -c`
|
108
|
-
fi
|
109
|
-
|
110
|
-
echo "-----> Configuring apt repo for salt #{salt_version}"
|
111
|
-
echo "deb #{salt_apt_repo}/salt-#{salt_version} ${DISTRIB_CODENAME} main" | #{sudo('tee')} /etc/apt/sources.list.d/salt-#{salt_version}.list
|
112
|
-
|
113
|
-
do_download #{salt_apt_repo_key} /tmp/repo.key
|
114
|
-
#{sudo('apt-key')} add /tmp/repo.key
|
115
|
-
|
116
|
-
#{sudo('apt-get')} update
|
117
|
-
sleep 10
|
118
|
-
echo "-----> Installing salt-minion (#{salt_version})"
|
119
|
-
#{sudo('apt-get')} install -y python-support
|
120
|
-
#{sudo('apt-get')} install -y salt-minion
|
121
|
-
#{sudo('apt-get')} install -y salt-common
|
122
|
-
#{sudo('apt-get')} install -y salt-minion
|
123
|
-
elif [ -z "${SALT_VERSION}" -a "#{salt_install}" = "ppa" ]
|
124
|
-
then
|
125
|
-
#{sudo('apt-add-repository')} -y #{salt_ppa}
|
126
|
-
#{sudo('apt-get')} update
|
127
|
-
#{sudo('apt-get')} install -y salt-minion
|
128
|
-
fi
|
129
|
-
|
130
|
-
# check again, now that an install of some form should have happened
|
131
|
-
SALT_VERSION=`salt-call --version | cut -d " " -f 2`
|
132
|
-
|
133
|
-
if [ -z "${SALT_VERSION}" ]
|
134
|
-
then
|
135
|
-
echo "No salt-minion installed, install must have failed!!"
|
136
|
-
echo "salt_install = #{salt_install}"
|
137
|
-
echo "salt_url = #{salt_url}"
|
138
|
-
echo "bootstrap_options = #{bootstrap_options}"
|
139
|
-
echo "salt_version = #{salt_version}"
|
140
|
-
echo "salt_apt_repo = #{salt_apt_repo}"
|
141
|
-
echo "salt_apt_repo_key = #{salt_apt_repo_key}"
|
142
|
-
echo "salt_ppa = #{salt_ppa}"
|
143
|
-
exit 2
|
144
|
-
elif [ "${SALT_VERSION}" = "#{salt_version}" -o "#{salt_version}" = "latest" ]
|
145
|
-
then
|
146
|
-
echo "You asked for #{salt_version} and you have ${SALT_VERSION} installed, sweet!"
|
147
|
-
elif [ ! -z "${SALT_VERSION}" -a "#{salt_install}" = "bootstrap" ]
|
148
|
-
then
|
149
|
-
echo "You asked for bootstrap install and you have got ${SALT_VERSION}, hope thats ok!"
|
150
|
-
else
|
151
|
-
echo "You asked for #{salt_version} and you have got ${SALT_VERSION} installed, dunno how to fix that, sorry!"
|
152
|
-
exit 2
|
153
|
-
fi
|
154
|
-
|
155
|
-
#{install_chef}
|
89
|
+
if windows_os?
|
90
|
+
install_template = File.expand_path("./../install_win.erb", __FILE__)
|
91
|
+
else
|
92
|
+
install_template = File.expand_path("./../install.erb", __FILE__)
|
93
|
+
end
|
156
94
|
|
157
|
-
|
158
|
-
|
95
|
+
erb = ERB.new(File.read(install_template)).result(binding)
|
96
|
+
debug("Install Command:" + erb.to_s)
|
97
|
+
erb
|
159
98
|
end
|
160
99
|
|
161
100
|
def install_chef
|
162
101
|
return unless config[:require_chef]
|
163
102
|
chef_url = config[:chef_bootstrap_url]
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
103
|
+
if windows_os?
|
104
|
+
<<-POWERSHELL
|
105
|
+
if (-Not $(test-path c:\\opscode\\chef) {
|
106
|
+
if (-Not $(Test-Path c:\\temp)) {
|
107
|
+
New-Item -Path c:\\temp -itemtype directory
|
108
|
+
}
|
109
|
+
(New-Object net.webclient).DownloadFile("#{chef_url}", "c:\\temp\\chef_bootstrap.ps1")
|
110
|
+
write-host "-----> Installing Chef Omnibus (for busser/serverspec ruby support)"
|
111
|
+
#{sudo('powershell')} c:\\temp\\chef_bootstrap.ps1
|
112
|
+
}
|
113
|
+
POWERSHELL
|
114
|
+
else
|
115
|
+
omnibus_download_dir = config[:omnibus_cachier] ? '/tmp/vagrant-cache/omnibus_chef' : '/tmp'
|
116
|
+
bootstrap_url = config[:bootstrap_url]
|
117
|
+
bootstrap_download_dir = '/tmp'
|
118
|
+
<<-INSTALL
|
119
|
+
echo "-----> Trying to install ruby(-dev) using assets.sh from kitchen-salt"
|
120
|
+
mkdir -p #{bootstrap_download_dir}
|
121
|
+
if [ ! -x #{bootstrap_download_dir}/install.sh ]
|
122
|
+
then
|
123
|
+
do_download #{bootstrap_url} #{bootstrap_download_dir}/install.sh
|
124
|
+
fi
|
125
|
+
#{sudo('sh')} #{bootstrap_download_dir}/install.sh -d #{bootstrap_download_dir}
|
126
|
+
if [ $? -ne 0 ] || [ ! -d "/opt/chef" ]
|
127
|
+
then
|
128
|
+
echo "Failed install ruby(-dev) using assets.sh from kitchen-salt"
|
129
|
+
echo "-----> Fallback to Chef Bootstrap script (for busser/serverspec ruby support)"
|
130
|
+
mkdir -p "#{omnibus_download_dir}"
|
131
|
+
if [ ! -x #{omnibus_download_dir}/install.sh ]
|
132
|
+
#{sudo('sh')} #{omnibus_download_dir}/install.sh -d #{omnibus_download_dir}
|
133
|
+
fi;
|
134
|
+
INSTALL
|
135
|
+
end
|
177
136
|
end
|
178
137
|
|
179
138
|
def create_sandbox
|
@@ -182,75 +141,78 @@ module Kitchen
|
|
182
141
|
prepare_minion
|
183
142
|
prepare_pillars
|
184
143
|
prepare_grains
|
185
|
-
|
186
|
-
if config[:state_collection] || config[:is_file_root]
|
187
|
-
prepare_state_collection
|
188
|
-
else
|
189
|
-
prepare_formula config[:kitchen_root], config[:formula]
|
190
|
-
|
191
|
-
unless config[:vendor_path].nil?
|
192
|
-
if Pathname.new(config[:vendor_path]).exist?
|
193
|
-
deps = if Pathname.new(config[:vendor_path]).absolute?
|
194
|
-
Dir["#{config[:vendor_path]}/*"]
|
195
|
-
else
|
196
|
-
Dir["#{config[:kitchen_root]}/#{config[:vendor_path]}/*"]
|
197
|
-
end
|
198
|
-
|
199
|
-
deps.each do |d|
|
200
|
-
prepare_formula "#{config[:kitchen_root]}/#{config[:vendor_path]}", File.basename(d)
|
201
|
-
end
|
202
|
-
else
|
203
|
-
# :vendor_path was set, but not valid
|
204
|
-
raise UserError, "kitchen-salt: Invalid vendor_path set: #{config[:vendor_path]}"
|
205
|
-
end
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
config[:dependencies].each do |formula|
|
210
|
-
prepare_formula formula[:path], formula[:name]
|
211
|
-
end
|
144
|
+
prepare_states
|
212
145
|
prepare_state_top
|
146
|
+
# upload scripts, cached formulas, and setup system repositories
|
147
|
+
prepare_dependencies
|
213
148
|
end
|
214
149
|
|
215
150
|
def init_command
|
216
|
-
debug("Initialising Driver #{
|
217
|
-
|
151
|
+
debug("Initialising Driver #{name}")
|
152
|
+
if windows_os?
|
153
|
+
cmd = "mkdir -Force -Path ""#{config[:root_path]}"""
|
154
|
+
else
|
155
|
+
cmd = "mkdir -p '#{config[:root_path]}';"
|
156
|
+
end
|
157
|
+
cmd += <<-INSTALL
|
158
|
+
#{config[:init_environment]}
|
159
|
+
INSTALL
|
160
|
+
cmd
|
218
161
|
end
|
219
162
|
|
220
|
-
def
|
221
|
-
|
222
|
-
# sudo(File.join(config[:root_path], File.basename(config[:script])))
|
223
|
-
debug(diagnose())
|
224
|
-
if config[:salt_run_highstate]
|
225
|
-
cmd = sudo("salt-call --config-dir=#{File.join(config[:root_path], config[:salt_config])} --local state.highstate")
|
226
|
-
end
|
163
|
+
def salt_command
|
164
|
+
salt_version = config[:salt_version]
|
227
165
|
|
228
|
-
|
229
|
-
|
166
|
+
cmd = ""
|
167
|
+
if windows_os?
|
168
|
+
salt_call = "c:\\salt\\salt-call.bat"
|
169
|
+
salt_config_path = config[:salt_config].gsub('/', '\\')
|
170
|
+
cmd << "(get-content #{File.join(config[:root_path], salt_config_path, 'minion').gsub('/', '\\')}).replace(\"`$env`:TEMP\", $env:TEMP) | set-content #{File.join(config[:root_path], salt_config_path, 'minion').gsub('/', '\\')} ;"
|
171
|
+
else
|
172
|
+
# install/update dependencies
|
173
|
+
cmd << sudo("chmod +x #{config[:root_path]}/*.sh;")
|
174
|
+
cmd << sudo("#{config[:root_path]}/dependencies.sh;")
|
175
|
+
salt_config_path = config[:salt_config]
|
176
|
+
salt_call = "salt-call"
|
177
|
+
end
|
178
|
+
cmd << sudo("#{salt_call} --state-output=changes --config-dir=#{File.join(config[:root_path], salt_config_path)} --local state.highstate")
|
179
|
+
cmd << " --log-level=#{config[:log_level]}" if config[:log_level]
|
180
|
+
cmd << " --id=#{config[:salt_minion_id]}" if config[:salt_minion_id]
|
181
|
+
cmd << " test=#{config[:dry_run]}" if config[:dry_run]
|
182
|
+
if salt_version > RETCODE_VERSION || salt_version == 'latest'
|
183
|
+
# hope for the best and hope it works eventually
|
184
|
+
cmd << ' --retcode-passthrough'
|
230
185
|
end
|
186
|
+
if windows_os?
|
187
|
+
cmd << ' ; exit $LASTEXITCODE'
|
188
|
+
end
|
189
|
+
cmd
|
190
|
+
end
|
191
|
+
|
192
|
+
def run_command
|
193
|
+
debug("running driver #{name}")
|
194
|
+
debug(diagnose)
|
231
195
|
|
232
196
|
# config[:salt_version] can be 'latest' or 'x.y.z', 'YYYY.M.x' etc
|
233
197
|
# error return codes are a mess in salt:
|
234
198
|
# https://github.com/saltstack/salt/pull/11337
|
235
199
|
# Unless we know we have a version that supports --retcode-passthrough
|
236
200
|
# attempt to scan the output for signs of failure
|
237
|
-
if config[:salt_version]
|
238
|
-
# hope for the best and hope it works eventually
|
239
|
-
cmd = cmd + " --retcode-passthrough"
|
240
|
-
else
|
201
|
+
if config[:salt_version] <= RETCODE_VERSION
|
241
202
|
# scan the output for signs of failure, there is a risk of false negatives
|
242
203
|
fail_grep = 'grep -e Result.*False -e Data.failed.to.compile -e No.matching.sls.found.for'
|
243
204
|
# capture any non-zero exit codes from the salt-call | tee pipe
|
244
|
-
cmd = 'set -o pipefail ; ' <<
|
205
|
+
cmd = 'set -o pipefail ; ' << salt_command
|
245
206
|
# Capture the salt-call output & exit code
|
246
|
-
cmd <<
|
207
|
+
cmd << ' 2>&1 | tee /tmp/salt-call-output ; SC=$? ; echo salt-call exit code: $SC ;'
|
247
208
|
# check the salt-call output for fail messages
|
248
209
|
cmd << " (sed '/#{fail_grep}/d' /tmp/salt-call-output | #{fail_grep} ; EC=$? ; echo salt-call output grep exit code ${EC} ;"
|
249
210
|
# use the non-zer exit code from salt-call, then invert the results of the grep for failures
|
250
|
-
cmd <<
|
211
|
+
cmd << ' [ ${SC} -ne 0 ] && exit ${SC} ; [ ${EC} -eq 0 ] && exit 1 ; [ ${EC} -eq 1 ] && exit 0)'
|
212
|
+
cmd
|
213
|
+
else
|
214
|
+
salt_command
|
251
215
|
end
|
252
|
-
|
253
|
-
cmd
|
254
216
|
end
|
255
217
|
|
256
218
|
protected
|
@@ -258,123 +220,34 @@ module Kitchen
|
|
258
220
|
def prepare_data
|
259
221
|
return unless config[:data_path]
|
260
222
|
|
261
|
-
info(
|
223
|
+
info('Preparing data')
|
262
224
|
debug("Using data from #{config[:data_path]}")
|
263
225
|
|
264
|
-
tmpdata_dir = File.join(sandbox_path,
|
226
|
+
tmpdata_dir = File.join(sandbox_path, 'data')
|
265
227
|
FileUtils.mkdir_p(tmpdata_dir)
|
266
|
-
#FileUtils.cp_r(Dir.glob("#{config[:data_path]}/*"), tmpdata_dir)
|
267
228
|
cp_r_with_filter(config[:data_path], tmpdata_dir, config[:salt_copy_filter])
|
268
229
|
end
|
269
230
|
|
270
231
|
def prepare_minion
|
271
|
-
info(
|
272
|
-
|
273
|
-
minion_config_content = <<-MINION_CONFIG.gsub(/^ {10}/, '')
|
274
|
-
state_top: top.sls
|
275
|
-
|
276
|
-
file_client: local
|
277
|
-
|
278
|
-
file_roots:
|
279
|
-
#{config[:salt_env]}:
|
280
|
-
- #{File.join(config[:root_path], config[:salt_file_root])}
|
281
|
-
|
282
|
-
pillar_roots:
|
283
|
-
#{config[:salt_env]}:
|
284
|
-
- #{File.join(config[:root_path], config[:salt_pillar_root])}
|
285
|
-
MINION_CONFIG
|
286
|
-
|
287
|
-
# create the temporary path for the salt-minion config file
|
288
|
-
debug("sandbox is #{sandbox_path}")
|
289
|
-
sandbox_minion_config_path = File.join(sandbox_path, config[:salt_minion_config])
|
290
|
-
|
291
|
-
# create the directory & drop the file in
|
292
|
-
FileUtils.mkdir_p(File.dirname(sandbox_minion_config_path))
|
293
|
-
File.open(sandbox_minion_config_path, "wb") do |file|
|
294
|
-
file.write(minion_config_content)
|
295
|
-
end
|
232
|
+
info('Preparing salt-minion')
|
296
233
|
|
297
|
-
|
298
|
-
|
299
|
-
def unsymbolize(obj)
|
300
|
-
return obj.inject({}){|memo,(k,v)| memo[k.to_s] = unsymbolize(v); memo} if obj.is_a? Hash
|
301
|
-
return obj.inject([]){|memo,v| memo << unsymbolize(v); memo} if obj.is_a? Array
|
302
|
-
return obj
|
303
|
-
end
|
304
|
-
|
305
|
-
def prepare_state_top
|
306
|
-
info("Preparing state_top")
|
307
|
-
|
308
|
-
sandbox_state_top_path = File.join(sandbox_path, config[:salt_state_top])
|
309
|
-
|
310
|
-
if (config[:state_top_from_file] == false)
|
311
|
-
# use the top.sls embedded in .kitchen.yml
|
312
|
-
|
313
|
-
# we get a hash with all the keys converted to symbols, salt doesn't like this
|
314
|
-
# to convert all the keys back to strings again
|
315
|
-
state_top_content = unsymbolize(config[:state_top]).to_yaml
|
316
|
-
# .to_yaml will produce ! '*' for a key, Salt doesn't like this either
|
317
|
-
state_top_content.gsub!(/(!\s'\*')/, "'*'")
|
234
|
+
if config[:salt_minion_config_template]
|
235
|
+
minion_template = File.expand_path(config[:salt_minion_config_template], Kitchen::Config.new.kitchen_root)
|
318
236
|
else
|
319
|
-
|
320
|
-
state_top_content = File.read("top.sls")
|
237
|
+
minion_template = File.expand_path("./../minion.erb", __FILE__)
|
321
238
|
end
|
322
239
|
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
240
|
+
if File.extname(minion_template) == ".erb"
|
241
|
+
minion_config_content = ERB.new(File.read(minion_template)).result(binding)
|
242
|
+
else
|
243
|
+
minion_config_content = File.read(minion_template)
|
327
244
|
end
|
328
|
-
end
|
329
|
-
|
330
|
-
def prepare_pillars
|
331
|
-
info("Preparing pillars into #{config[:salt_pillar_root]}")
|
332
|
-
debug("Pillars Hash: #{config[:pillars]}")
|
333
|
-
|
334
|
-
return if config[:pillars].nil? && config[:'pillars-from-files'].nil?
|
335
245
|
|
336
|
-
#
|
337
|
-
|
338
|
-
|
339
|
-
debug("unsymbolized pillars hash: #{pillars}")
|
340
|
-
|
341
|
-
# write out each pillar (we get key/contents pairs)
|
342
|
-
pillars.each do |key,contents|
|
343
|
-
|
344
|
-
# convert the hash to yaml
|
345
|
-
pillar = contents.to_yaml
|
346
|
-
|
347
|
-
# .to_yaml will produce ! '*' for a key, Salt doesn't like this either
|
348
|
-
pillar.gsub!(/(!\s'\*')/, "'*'")
|
349
|
-
|
350
|
-
# generate the filename
|
351
|
-
sandbox_pillar_path = File.join(sandbox_path, config[:salt_pillar_root], key)
|
352
|
-
|
353
|
-
# create the directory where the pillar file will go
|
354
|
-
FileUtils.mkdir_p(File.dirname(sandbox_pillar_path))
|
355
|
-
|
356
|
-
debug("Rendered pillar yaml for #{key}:\n #{pillar}")
|
357
|
-
# create the directory & drop the file in
|
358
|
-
File.open(sandbox_pillar_path, "wb") do |file|
|
359
|
-
file.write(pillar)
|
360
|
-
end
|
361
|
-
end
|
246
|
+
# create the temporary path for the salt-minion config file
|
247
|
+
debug("sandbox is #{sandbox_path}")
|
248
|
+
sandbox_minion_config_path = File.join(sandbox_path, config[:salt_minion_config])
|
362
249
|
|
363
|
-
|
364
|
-
# munge multiline strings
|
365
|
-
if !config[:'pillars-from-files'].nil?
|
366
|
-
external_pillars = unsymbolize(config[:'pillars-from-files'])
|
367
|
-
debug("external_pillars (unsymbolize): #{external_pillars}")
|
368
|
-
external_pillars.each do |key, srcfile|
|
369
|
-
debug("Copying external pillar: #{key}, #{srcfile}")
|
370
|
-
# generate the filename
|
371
|
-
sandbox_pillar_path = File.join(sandbox_path, config[:salt_pillar_root], key)
|
372
|
-
# create the directory where the pillar file will go
|
373
|
-
FileUtils.mkdir_p(File.dirname(sandbox_pillar_path))
|
374
|
-
# copy the file across
|
375
|
-
FileUtils.copy srcfile, sandbox_pillar_path
|
376
|
-
end
|
377
|
-
end
|
250
|
+
write_raw_file(sandbox_minion_config_path, minion_config_content)
|
378
251
|
end
|
379
252
|
|
380
253
|
def prepare_grains
|
@@ -383,101 +256,44 @@ module Kitchen
|
|
383
256
|
return if config[:grains].nil?
|
384
257
|
|
385
258
|
info("Preparing grains into #{config[:salt_config]}/grains")
|
386
|
-
# we get a hash with all the keys converted to symbols, salt doesn't like this
|
387
|
-
# to convert all the keys back to strings again we use unsymbolize
|
388
|
-
# then we convert the hash to yaml
|
389
|
-
grains = unsymbolize(config[:grains]).to_yaml
|
390
259
|
|
391
260
|
# generate the filename
|
392
261
|
sandbox_grains_path = File.join(sandbox_path, config[:salt_config], 'grains')
|
393
262
|
debug("sandbox_grains_path: #{sandbox_grains_path}")
|
394
263
|
|
395
|
-
|
396
|
-
FileUtils.mkdir_p(File.dirname(sandbox_grains_path))
|
397
|
-
|
398
|
-
debug("Rendered grains yaml")
|
399
|
-
# create the directory & drop the file in
|
400
|
-
File.open(sandbox_grains_path, "wb") do |file|
|
401
|
-
file.write(grains)
|
402
|
-
end
|
264
|
+
write_hash_file(sandbox_grains_path, config[:grains])
|
403
265
|
end
|
404
266
|
|
405
|
-
def
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
formula_dir = File.join(sandbox_path, config[:salt_file_root], formula)
|
410
|
-
FileUtils.mkdir_p(formula_dir)
|
411
|
-
cp_r_with_filter(File.join(path, formula), formula_dir, config[:salt_copy_filter])
|
412
|
-
|
413
|
-
# copy across the _modules etc directories for python implementation
|
414
|
-
['_modules', '_states', '_grains', '_renderers', '_returners'].each do |extrapath|
|
415
|
-
src = File.join(path, extrapath)
|
416
|
-
|
417
|
-
if (File.directory?(src))
|
418
|
-
debug("prepare_formula: #{src} exists, copying..")
|
419
|
-
extrapath_dir = File.join(sandbox_path, config[:salt_file_root], extrapath)
|
420
|
-
FileUtils.mkdir_p(extrapath_dir)
|
421
|
-
#FileUtils.cp_r(Dir.glob(File.join(src, "*")), extrapath_dir)
|
422
|
-
cp_r_with_filter(src, extrapath_dir, config[:salt_copy_filter])
|
423
|
-
else
|
424
|
-
debug("prepare_formula: #{src} doesn't exist, skipping.")
|
425
|
-
end
|
426
|
-
end
|
427
|
-
end
|
267
|
+
def prepare_dependencies
|
268
|
+
# upload scripts
|
269
|
+
sandbox_scripts_path = File.join(sandbox_path, config[:salt_config], 'scripts')
|
270
|
+
info("Preparing scripts into #{config[:salt_config]}/scripts")
|
428
271
|
|
429
|
-
|
430
|
-
info("Preparing state collection")
|
431
|
-
debug("Using config #{config}")
|
272
|
+
# PLACEHOLDER, git formulas might be fetched locally to temp and uploaded
|
432
273
|
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
274
|
+
# setup spm
|
275
|
+
spm_repos = config[:vendor_repo].select{|x| x[:type]=='spm'}.each{|x| x[:url]}.map {|x| x[:url] }
|
276
|
+
spm_repos.each do |url|
|
277
|
+
id=url.gsub(/[htp:\/.]/,'')
|
278
|
+
spmreposd = File.join(sandbox_path, 'etc', 'salt', 'spm.repos.d')
|
279
|
+
repo_spec = File.join(spmreposd, 'spm.repo')
|
280
|
+
FileUtils.mkdir_p(spmreposd)
|
281
|
+
repo_content = '
|
282
|
+
#{id}:
|
283
|
+
url: #{url}
|
442
284
|
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
collection_dir = File.join(sandbox_path, config[:salt_file_root], config[:collection_name])
|
447
|
-
FileUtils.mkdir_p(collection_dir)
|
448
|
-
cp_r_with_filter(config[:kitchen_root], collection_dir, config[:salt_copy_filter])
|
449
|
-
|
450
|
-
end
|
285
|
+
'
|
286
|
+
write_raw_file(repo_spec, repo_content)
|
287
|
+
end
|
451
288
|
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
debug("cp_r_with_filter:filter = #{filter}")
|
456
|
-
|
457
|
-
Array(source_path).each do |source_path|
|
458
|
-
Find.find(source_path) do |source|
|
459
|
-
target = source.sub(/^#{source_path}/, target_path)
|
460
|
-
debug("cp_r_with_filter:source = #{source}")
|
461
|
-
debug("cp_r_with_filter:target = #{target}")
|
462
|
-
filtered = filter.include?(File.basename(source))
|
463
|
-
if File.directory? source
|
464
|
-
if filtered
|
465
|
-
debug("Found #{source} in #{filter}, pruning it from the Find")
|
466
|
-
Find.prune
|
467
|
-
end
|
468
|
-
FileUtils.mkdir target unless File.exists? target
|
469
|
-
if File.symlink? source
|
470
|
-
FileUtils.cp_r "#{source}/.", target
|
471
|
-
end
|
472
|
-
else
|
473
|
-
if filtered
|
474
|
-
debug("Found #{source} in #{filter}, not copying file")
|
475
|
-
else
|
476
|
-
FileUtils.copy source, target
|
477
|
-
end
|
478
|
-
end
|
479
|
-
end
|
289
|
+
# upload scripts
|
290
|
+
%w(formula-fetch.sh repository-setup.sh).each do |script|
|
291
|
+
write_raw_file(File.join(sandbox_path, script), File.read(File.expand_path("../#{script}", __FILE__)))
|
480
292
|
end
|
293
|
+
dependencies_script = File.expand_path("./../dependencies.erb", __FILE__)
|
294
|
+
dependencies_content = ERB.new(File.read(dependencies_script)).result(binding)
|
295
|
+
write_raw_file(File.join(sandbox_path, 'dependencies.sh'), dependencies_content)
|
296
|
+
|
481
297
|
end
|
482
298
|
end
|
483
299
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kitchen-salt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.25
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Simon McCartney
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-06-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: test-kitchen
|
@@ -73,7 +73,16 @@ executables: []
|
|
73
73
|
extensions: []
|
74
74
|
extra_rdoc_files: []
|
75
75
|
files:
|
76
|
+
- lib/kitchen-salt/pillars.rb
|
77
|
+
- lib/kitchen-salt/states.rb
|
78
|
+
- lib/kitchen-salt/util.rb
|
76
79
|
- lib/kitchen-salt/version.rb
|
80
|
+
- lib/kitchen/provisioner/dependencies.erb
|
81
|
+
- lib/kitchen/provisioner/formula-fetch.sh
|
82
|
+
- lib/kitchen/provisioner/install.erb
|
83
|
+
- lib/kitchen/provisioner/install_win.erb
|
84
|
+
- lib/kitchen/provisioner/minion.erb
|
85
|
+
- lib/kitchen/provisioner/repository-setup.sh
|
77
86
|
- lib/kitchen/provisioner/salt_solo.rb
|
78
87
|
homepage: https://github.com//kitchen-salt
|
79
88
|
licenses:
|
@@ -95,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
104
|
version: '0'
|
96
105
|
requirements: []
|
97
106
|
rubyforge_project: "[none]"
|
98
|
-
rubygems_version: 2.
|
107
|
+
rubygems_version: 2.6.12
|
99
108
|
signing_key:
|
100
109
|
specification_version: 4
|
101
110
|
summary: salt provisioner for test-kitchen
|