puppet-armature 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +6 -5
- data/TODO.md +0 -8
- data/bin/armature +21 -6
- data/lib/armature.rb +12 -4
- data/lib/armature/cache.rb +98 -73
- data/lib/armature/environments.rb +53 -20
- data/lib/armature/errors.rb +7 -0
- data/lib/armature/puppetfile.rb +41 -17
- data/lib/armature/ref/base.rb +21 -0
- data/lib/armature/ref/identity.rb +5 -0
- data/lib/armature/ref/immutable.rb +5 -0
- data/lib/armature/ref/mutable.rb +5 -0
- data/lib/armature/repo.rb +56 -0
- data/lib/armature/repo/forge.rb +154 -0
- data/lib/armature/repo/git.rb +228 -0
- data/lib/armature/run.rb +44 -13
- data/lib/armature/util.rb +51 -2
- data/lib/armature/version.rb +2 -1
- data/puppet-armature.gemspec +1 -1
- data/test/deploy_test.rb +39 -39
- data/test/helpers.rb +27 -25
- data/test/puppetfile_test.rb +41 -0
- metadata +12 -4
- data/lib/armature/gitrepo.rb +0 -139
data/lib/armature/run.rb
CHANGED
@@ -4,7 +4,7 @@ require 'shellwords'
|
|
4
4
|
module Armature::Run
|
5
5
|
extend self
|
6
6
|
|
7
|
-
class CommandFailureError <
|
7
|
+
class CommandFailureError < Armature::Error
|
8
8
|
attr_reader :status
|
9
9
|
attr_reader :command
|
10
10
|
attr_reader :output
|
@@ -17,30 +17,57 @@ module Armature::Run
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def to_s
|
20
|
-
command_str = Armature::Run.command_to_string(
|
20
|
+
command_str = Armature::Run.command_to_string(@command)
|
21
21
|
"Command failed: #{command_str}\nReturn: #{@status}\nOutput:\n#{@output}\n"
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
def command_to_string(
|
26
|
-
|
25
|
+
def command_to_string(cmd)
|
26
|
+
escaped_words = cmd.map do |word|
|
27
|
+
escaped = Shellwords.escape(word)
|
28
|
+
if escaped == word || word.include?("'") || word.include?("\\")
|
29
|
+
escaped
|
30
|
+
else
|
31
|
+
# The word needs to be quoted, but doesn't contain ' or \. It can just
|
32
|
+
# singled-quoted.
|
33
|
+
"'#{word}'"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
escaped_words.join(" ")
|
38
|
+
end
|
39
|
+
|
40
|
+
def command(environment={}, *cmd)
|
41
|
+
pipe_command("", environment, *cmd)
|
27
42
|
end
|
28
43
|
|
29
|
-
def
|
30
|
-
|
44
|
+
def pipe_command(input, environment={}, *cmd)
|
45
|
+
if input == ""
|
46
|
+
logger.debug("Run: " + command_to_string(cmd))
|
47
|
+
else
|
48
|
+
logger.debug("Run with input: " + command_to_string(cmd))
|
49
|
+
end
|
31
50
|
|
32
|
-
|
33
|
-
|
34
|
-
|
51
|
+
start_time = Time.now
|
52
|
+
output, status = nil, nil
|
53
|
+
Open3.popen2e(environment, *cmd) do |pipe_in, pipe_out, promise|
|
54
|
+
pipe_in.write(input)
|
55
|
+
pipe_in.close()
|
56
|
+
output = pipe_out.read()
|
57
|
+
pipe_out.close()
|
58
|
+
status = promise.value
|
59
|
+
end
|
60
|
+
seconds = Time.now - start_time
|
61
|
+
logger.debug("Finished " + command_to_string([cmd.first]) + " in #{seconds}: #{status}")
|
35
62
|
|
36
63
|
if ! status.success?
|
37
|
-
raise CommandFailureError.new(status,
|
64
|
+
raise CommandFailureError.new(status, cmd, output)
|
38
65
|
end
|
39
66
|
|
40
|
-
|
67
|
+
output
|
41
68
|
end
|
42
69
|
|
43
|
-
def clean_git(*
|
70
|
+
def clean_git(*cmd)
|
44
71
|
# Disable general configuration files
|
45
72
|
environment = {
|
46
73
|
"HOME" => "",
|
@@ -48,6 +75,10 @@ module Armature::Run
|
|
48
75
|
"GIT_CONFIG_NOSYSTEM" => "1",
|
49
76
|
}
|
50
77
|
|
51
|
-
command(environment, "git", *
|
78
|
+
command(environment, "git", *cmd)
|
79
|
+
end
|
80
|
+
|
81
|
+
def logger
|
82
|
+
Logging.logger[self]
|
52
83
|
end
|
53
84
|
end
|
data/lib/armature/util.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
require
|
1
|
+
require "json"
|
2
|
+
require "net/http"
|
3
|
+
require "uri"
|
2
4
|
|
3
5
|
module Armature::Util
|
4
6
|
extend self
|
@@ -46,7 +48,6 @@ module Armature::Util
|
|
46
48
|
# operations to block.
|
47
49
|
File.open(path, File::RDWR|File::CREAT, 0600) do |lock|
|
48
50
|
if not lock.flock(mode | File::LOCK_NB)
|
49
|
-
logger = Logging.logger[self]
|
50
51
|
logger.info("Waiting for lock on #{path}")
|
51
52
|
|
52
53
|
start_time = Time.now
|
@@ -71,4 +72,52 @@ module Armature::Util
|
|
71
72
|
yield lock
|
72
73
|
end
|
73
74
|
end
|
75
|
+
|
76
|
+
def http_get_json(url, request_headers={})
|
77
|
+
accept = { "Accept" => "application/json" }
|
78
|
+
body = http_get(url, request_headers.merge(accept))
|
79
|
+
JSON.parse(body)
|
80
|
+
end
|
81
|
+
|
82
|
+
def http_get_request(url, request_headers={})
|
83
|
+
uri = URI.parse(url)
|
84
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
85
|
+
http.use_ssl = (uri.scheme == "https")
|
86
|
+
|
87
|
+
request = Net::HTTP::Get.new(uri)
|
88
|
+
request["User-Agent"] = "armature #{Armature::VERSION} #{Armature::HOMEPAGE}"
|
89
|
+
request_headers.each do |key, value|
|
90
|
+
request[key] = value
|
91
|
+
end
|
92
|
+
|
93
|
+
http.request(request)
|
94
|
+
end
|
95
|
+
|
96
|
+
def http_get(url, request_headers={})
|
97
|
+
start_time = Time.now
|
98
|
+
|
99
|
+
current_url = url
|
100
|
+
body = nil
|
101
|
+
|
102
|
+
while body == nil do
|
103
|
+
response = http_get_request(current_url, request_headers)
|
104
|
+
if response.kind_of? Net::HTTPRedirection
|
105
|
+
logger.debug("HTTP redirection: #{current_url} to #{response["Location"].inspect}")
|
106
|
+
current_url = response["Location"]
|
107
|
+
next
|
108
|
+
end
|
109
|
+
|
110
|
+
response.value() # Raise error if we don't get 2xx response
|
111
|
+
body = response.body()
|
112
|
+
end
|
113
|
+
|
114
|
+
seconds = Time.now - start_time
|
115
|
+
logger.debug("Downloaded #{body.length()} bytes from #{current_url} in #{seconds}")
|
116
|
+
|
117
|
+
body
|
118
|
+
end
|
119
|
+
|
120
|
+
def logger
|
121
|
+
Logging.logger[self]
|
122
|
+
end
|
74
123
|
end
|
data/lib/armature/version.rb
CHANGED
data/puppet-armature.gemspec
CHANGED
@@ -5,7 +5,7 @@ spec = Gem::Specification.new do |s|
|
|
5
5
|
s.version = Armature::VERSION
|
6
6
|
s.author = 'Daniel Parks'
|
7
7
|
s.email = 'dp-os-armature@oxidized.org'
|
8
|
-
s.homepage =
|
8
|
+
s.homepage = Armature::HOMEPAGE
|
9
9
|
s.license = 'BSD-2-Clause'
|
10
10
|
s.platform = Gem::Platform::RUBY
|
11
11
|
s.summary = 'Deploy Puppet environments and manage modules'
|
data/test/deploy_test.rb
CHANGED
@@ -6,7 +6,7 @@ class DeployTest < Minitest::Test
|
|
6
6
|
|
7
7
|
def test_deploy_just_master_branch
|
8
8
|
with_context do
|
9
|
-
repo = @cache
|
9
|
+
repo = Armature::Repo::Git::from_url(@cache, repo_path("control"))
|
10
10
|
branches = Set.new(repo.get_branches())
|
11
11
|
|
12
12
|
assert_equal(Set.new(['master']), branches,
|
@@ -14,11 +14,13 @@ class DeployTest < Minitest::Test
|
|
14
14
|
assert_equal([], @environments.names(),
|
15
15
|
"Environments before test incorrect")
|
16
16
|
|
17
|
-
@environments.
|
17
|
+
@environments.check_out_ref(repo, "master")
|
18
18
|
|
19
19
|
assert_equal(["master"], @environments.names(),
|
20
20
|
"Environments after test incorrect")
|
21
|
-
assert_equal(
|
21
|
+
assert_equal(
|
22
|
+
[".", "..", "master"].sort(),
|
23
|
+
Dir.entries(@environments.path).sort(),
|
22
24
|
"Environments directory after test incorrect")
|
23
25
|
end
|
24
26
|
end
|
@@ -26,13 +28,13 @@ class DeployTest < Minitest::Test
|
|
26
28
|
### FIXME: should this generate an error?
|
27
29
|
def test_deploy_nonexistant_branch
|
28
30
|
with_context do
|
29
|
-
repo = @cache
|
31
|
+
repo = Armature::Repo::Git::from_url(@cache, repo_path("control"))
|
30
32
|
branches = Set.new(repo.get_branches())
|
31
33
|
|
32
34
|
assert_equal(Set.new(['master']), branches,
|
33
35
|
"Branches before test incorrect")
|
34
36
|
|
35
|
-
@environments.
|
37
|
+
@environments.check_out_ref(repo, "foo")
|
36
38
|
|
37
39
|
assert_equal([], @environments.names(),
|
38
40
|
"Environments after test incorrect")
|
@@ -41,11 +43,11 @@ class DeployTest < Minitest::Test
|
|
41
43
|
|
42
44
|
def test_deploy_all_branches
|
43
45
|
with_context do
|
44
|
-
repo = @cache
|
46
|
+
repo = Armature::Repo::Git::from_url(@cache, repo_path("control"))
|
45
47
|
branches = Set.new(repo.get_branches())
|
46
48
|
|
47
|
-
Dir.mkdir(
|
48
|
-
File.symlink(
|
49
|
+
Dir.mkdir("foo")
|
50
|
+
File.symlink("foo", @environments.path + "/foo")
|
49
51
|
|
50
52
|
assert_equal(["foo"], @environments.names(),
|
51
53
|
"Environments before test incorrect")
|
@@ -55,7 +57,7 @@ class DeployTest < Minitest::Test
|
|
55
57
|
end
|
56
58
|
|
57
59
|
branches.each do |branch|
|
58
|
-
@environments.
|
60
|
+
@environments.check_out_ref(repo, branch)
|
59
61
|
end
|
60
62
|
|
61
63
|
assert_equal(["master"], @environments.names(),
|
@@ -65,20 +67,20 @@ class DeployTest < Minitest::Test
|
|
65
67
|
|
66
68
|
def test_deploy_one_module
|
67
69
|
with_context do
|
68
|
-
repo = @cache
|
69
|
-
@environments.
|
70
|
+
repo = Armature::Repo::Git::from_url(@cache, repo_path("control"))
|
71
|
+
@environments.check_out_ref(repo, "master")
|
70
72
|
|
71
73
|
assert_equal(
|
72
|
-
[".", "..", "module1"],
|
73
|
-
Dir.entries(@environments.path + "/master/modules"),
|
74
|
+
[".", "..", "module1"].sort(),
|
75
|
+
Dir.entries(@environments.path + "/master/modules").sort(),
|
74
76
|
"Modules installed after test incorrect")
|
75
77
|
end
|
76
78
|
end
|
77
79
|
|
78
80
|
def test_adding_module_and_redeploying
|
79
81
|
with_context do
|
80
|
-
repo = @cache
|
81
|
-
@environments.
|
82
|
+
repo = Armature::Repo::Git::from_url(@cache, repo_path("control"))
|
83
|
+
@environments.check_out_ref(repo, "master")
|
82
84
|
|
83
85
|
repo_init("module-2")
|
84
86
|
repo_commit("control", "Add module-2") do
|
@@ -91,10 +93,10 @@ class DeployTest < Minitest::Test
|
|
91
93
|
end
|
92
94
|
|
93
95
|
@cache.flush_memory!
|
94
|
-
@environments.
|
96
|
+
@environments.check_out_ref(repo, "master")
|
95
97
|
assert_equal(
|
96
|
-
[".", "..", "module1", "module2"],
|
97
|
-
Dir.entries(@environments.path + "/master/modules"),
|
98
|
+
[".", "..", "module1", "module2"].sort(),
|
99
|
+
Dir.entries(@environments.path + "/master/modules").sort(),
|
98
100
|
"Modules installed after test incorrect")
|
99
101
|
assert_environment_file_contains(
|
100
102
|
"master/modules/module1/README.md",
|
@@ -107,8 +109,8 @@ class DeployTest < Minitest::Test
|
|
107
109
|
|
108
110
|
def test_removing_module_and_redeploying
|
109
111
|
with_context do
|
110
|
-
repo = @cache
|
111
|
-
@environments.
|
112
|
+
repo = Armature::Repo::Git::from_url(@cache, repo_path("control"))
|
113
|
+
@environments.check_out_ref(repo, "master")
|
112
114
|
|
113
115
|
repo_commit("control", "Remove module-1") do
|
114
116
|
File.write("Puppetfile", <<-PUPPETFILE)
|
@@ -117,17 +119,16 @@ class DeployTest < Minitest::Test
|
|
117
119
|
end
|
118
120
|
|
119
121
|
@cache.flush_memory!
|
120
|
-
@environments.
|
122
|
+
@environments.check_out_ref(repo, "master")
|
121
123
|
assert_equal(
|
122
|
-
[".", ".."],
|
123
|
-
Dir.entries(@environments.path + "/master/modules"),
|
124
|
+
[".", ".."].sort(),
|
125
|
+
Dir.entries(@environments.path + "/master/modules").sort(),
|
124
126
|
"Modules installed after test incorrect")
|
125
127
|
end
|
126
128
|
end
|
127
129
|
|
128
130
|
def test_module_with_bad_ref
|
129
131
|
with_context do
|
130
|
-
repo = @cache.get_repo(repo_path("control"))
|
131
132
|
repo_commit("control", "Set module-1 to bad ref") do
|
132
133
|
File.write("Puppetfile", <<-PUPPETFILE)
|
133
134
|
forge "https://forge.puppet.com"
|
@@ -136,23 +137,24 @@ class DeployTest < Minitest::Test
|
|
136
137
|
PUPPETFILE
|
137
138
|
end
|
138
139
|
|
140
|
+
repo = Armature::Repo::Git::from_url(@cache, repo_path("control"))
|
139
141
|
assert_raises(Armature::RefError) do
|
140
|
-
@environments.
|
142
|
+
@environments.check_out_ref(repo, "master")
|
141
143
|
end
|
142
144
|
|
143
145
|
### FIXME state of repo after an error is undefined, but this behavior
|
144
146
|
### seems reasonable.
|
145
147
|
assert_equal(
|
146
|
-
[".", ".."],
|
147
|
-
Dir.entries(@environments.path),
|
148
|
+
[".", ".."].sort(),
|
149
|
+
Dir.entries(@environments.path).sort(),
|
148
150
|
"Modules installed after test incorrect")
|
149
151
|
end
|
150
152
|
end
|
151
153
|
|
152
154
|
def test_redeploying_module_with_bad_ref
|
153
155
|
with_context do
|
154
|
-
repo = @cache
|
155
|
-
@environments.
|
156
|
+
repo = Armature::Repo::Git::from_url(@cache, repo_path("control"))
|
157
|
+
@environments.check_out_ref(repo, "master")
|
156
158
|
|
157
159
|
repo_commit("control", "Set module-1 to bad ref") do
|
158
160
|
File.write("Puppetfile", <<-PUPPETFILE)
|
@@ -164,15 +166,15 @@ class DeployTest < Minitest::Test
|
|
164
166
|
|
165
167
|
@cache.flush_memory!
|
166
168
|
assert_raises(Armature::RefError) do
|
167
|
-
@environments.
|
169
|
+
@environments.check_out_ref(repo, "master")
|
168
170
|
end
|
169
171
|
|
170
172
|
### FIXME state of repo after an error is undefined
|
171
173
|
### What happens if other modules already exist?
|
172
174
|
skip("state of repo after an error is undefined")
|
173
175
|
assert_equal(
|
174
|
-
[".", "..", "module1"],
|
175
|
-
Dir.entries(@environments.path + "/master/modules"),
|
176
|
+
[".", "..", "module1"].sort(),
|
177
|
+
Dir.entries(@environments.path + "/master/modules").sort(),
|
176
178
|
"Modules installed after test incorrect")
|
177
179
|
end
|
178
180
|
end
|
@@ -247,9 +249,8 @@ class DeployTest < Minitest::Test
|
|
247
249
|
add_module_class("interesting", "two_b")
|
248
250
|
|
249
251
|
@cache.flush_memory!
|
250
|
-
@environments.
|
252
|
+
@environments.check_out_ref(Armature::Repo::Git::from_url(@cache, repo_path("control")), "master")
|
251
253
|
|
252
|
-
skip("checkout_ref doesn't update branches at the moment")
|
253
254
|
assert_module_manifests("interesting",
|
254
255
|
["one.pp", "two.pp", "two_a.pp", "two_b.pp"],
|
255
256
|
"Incorrect module version after redeploy")
|
@@ -265,7 +266,7 @@ class DeployTest < Minitest::Test
|
|
265
266
|
add_module_class("interesting", "two_b")
|
266
267
|
|
267
268
|
@cache.flush_memory!
|
268
|
-
@cache.
|
269
|
+
@cache.update_mutable_refs()
|
269
270
|
|
270
271
|
assert_module_manifests("interesting",
|
271
272
|
["one.pp", "two.pp", "two_a.pp", "two_b.pp"],
|
@@ -278,13 +279,12 @@ private
|
|
278
279
|
|
279
280
|
# The "interesting" repo must be created first so it can be queried for shas
|
280
281
|
def redeploy_module_with_ref_of_type(ref_type, ref)
|
281
|
-
repo = @cache.get_repo(repo_path("control"))
|
282
|
-
|
283
282
|
repo_puppetfile_update("control", <<-MODULES)
|
284
283
|
mod "interesting", :git=>"#{repo_path('interesting')}"
|
285
284
|
MODULES
|
286
285
|
|
287
|
-
@
|
286
|
+
control_repo = Armature::Repo::Git::from_url(@cache, repo_path("control"))
|
287
|
+
@environments.check_out_ref(control_repo, "master")
|
288
288
|
|
289
289
|
assert_module_manifests("interesting", ["one.pp", "two.pp", "three.pp"],
|
290
290
|
"Incorrect module version after initial deploy")
|
@@ -299,7 +299,7 @@ private
|
|
299
299
|
end
|
300
300
|
|
301
301
|
@cache.flush_memory!
|
302
|
-
@environments.
|
302
|
+
@environments.check_out_ref(control_repo, "master")
|
303
303
|
|
304
304
|
yield
|
305
305
|
end
|
data/test/helpers.rb
CHANGED
@@ -3,8 +3,17 @@ require 'fileutils'
|
|
3
3
|
require 'tmpdir'
|
4
4
|
|
5
5
|
module ArmatureTestHelpers
|
6
|
+
def with_temp_dir(name="test")
|
7
|
+
work_path = Dir.mktmpdir("armature.#{name}.")
|
8
|
+
Dir.chdir(work_path) do
|
9
|
+
yield
|
10
|
+
end
|
11
|
+
ensure
|
12
|
+
FileUtils.rm_rf(work_path)
|
13
|
+
end
|
14
|
+
|
6
15
|
def repo_path(name)
|
7
|
-
|
16
|
+
"repos/" + name
|
8
17
|
end
|
9
18
|
|
10
19
|
def repo_init(name)
|
@@ -71,40 +80,32 @@ module ArmatureTestHelpers
|
|
71
80
|
add_module_class(module_name, "three")
|
72
81
|
end
|
73
82
|
|
74
|
-
def
|
75
|
-
|
76
|
-
|
83
|
+
def with_context
|
84
|
+
with_temp_dir("context") do
|
85
|
+
@cache = Armature::Cache.new("cache")
|
77
86
|
|
78
|
-
|
79
|
-
|
87
|
+
Dir.mkdir("environments")
|
88
|
+
@environments = Armature::Environments.new("environments", @cache)
|
80
89
|
|
81
|
-
|
90
|
+
repo_init("module-1")
|
82
91
|
|
83
|
-
|
84
|
-
|
85
|
-
|
92
|
+
repo_init("control") do
|
93
|
+
File.write("Puppetfile", <<-PUPPETFILE)
|
94
|
+
forge "https://forge.puppet.com"
|
86
95
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
def tear_down_context
|
93
|
-
FileUtils.rm_rf(@context_path)
|
96
|
+
mod "module1", :git=>"#{repo_path('module-1')}"
|
97
|
+
PUPPETFILE
|
98
|
+
end
|
94
99
|
|
100
|
+
yield
|
101
|
+
end
|
102
|
+
ensure
|
95
103
|
# Ensure that code trying to use these after this point fails in a
|
96
104
|
# predictable way.
|
97
|
-
@context_path = nil
|
98
105
|
@cache = nil
|
99
106
|
@environments = nil
|
100
107
|
end
|
101
108
|
|
102
|
-
def with_context
|
103
|
-
set_up_context
|
104
|
-
yield
|
105
|
-
tear_down_context
|
106
|
-
end
|
107
|
-
|
108
109
|
def environment_file_contains?(path, search)
|
109
110
|
File.foreach(@environments.path + "/" + path).any? do
|
110
111
|
|line| line.include? search
|
@@ -122,9 +123,10 @@ module ArmatureTestHelpers
|
|
122
123
|
def assert_module_manifests(module_name, manifest_names=["init.pp"],
|
123
124
|
message="Incorrect manifests in module '#{module_name}'",
|
124
125
|
environment="master")
|
126
|
+
module_path = "#{@environments.path}/#{environment}/modules/#{module_name}"
|
125
127
|
assert_equal(
|
126
128
|
([".", "..", ".keep"] + manifest_names).sort(),
|
127
|
-
Dir.entries(
|
129
|
+
Dir.entries("#{module_path}/manifests").sort(),
|
128
130
|
message)
|
129
131
|
end
|
130
132
|
end
|