r10k 3.3.0 → 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/docker/Makefile CHANGED
@@ -4,18 +4,18 @@ git_describe = $(shell git describe)
4
4
  vcs_ref := $(shell git rev-parse HEAD)
5
5
  build_date := $(shell date -u +%FT%T)
6
6
  hadolint_available := $(shell hadolint --help > /dev/null 2>&1; echo $$?)
7
- hadolint_command := hadolint --ignore DL3008 --ignore DL3018 --ignore DL4000 --ignore DL4001
7
+ hadolint_command := hadolint --ignore DL3008 --ignore DL3018 --ignore DL3028 --ignore DL4000 --ignore DL4001
8
8
  hadolint_container := hadolint/hadolint:latest
9
9
  pwd := $(shell pwd)
10
10
  export BUNDLE_PATH = $(pwd)/.bundle/gems
11
11
  export BUNDLE_BIN = $(pwd)/.bundle/bin
12
12
  export GEMFILE = $(pwd)/Gemfile
13
13
 
14
- version = $(shell echo $(git_describe) | sed 's/-.*//')
14
+ version := $(shell command grep VERSION ../lib/r10k/version.rb | awk '{print $$3}' | sed "s/'//g")
15
15
  dockerfile := Dockerfile
16
16
 
17
17
  prep:
18
- @git fetch --unshallow ||:
18
+ @git fetch --unshallow 2> /dev/null ||:
19
19
  @git fetch origin 'refs/tags/*:refs/tags/*'
20
20
 
21
21
  lint:
@@ -34,8 +34,7 @@ build: prep
34
34
  --build-arg version=$(version) \
35
35
  --build-arg pupperware_analytics_stream=$(PUPPERWARE_ANALYTICS_STREAM) \
36
36
  --file r10k/$(dockerfile) \
37
- --tag $(NAMESPACE)/r10k:$(version) \
38
- r10k
37
+ --tag $(NAMESPACE)/r10k:$(version) $(pwd)/..
39
38
  ifeq ($(IS_LATEST),true)
40
39
  @docker tag $(NAMESPACE)/r10k:$(version) puppet/r10k:latest
41
40
  endif
@@ -44,7 +43,7 @@ test: prep
44
43
  @bundle install --path $$BUNDLE_PATH --gemfile $$GEMFILE
45
44
  @PUPPET_TEST_DOCKER_IMAGE=$(NAMESPACE)/r10k:$(version) \
46
45
  bundle exec --gemfile $$GEMFILE \
47
- rspec r10k/spec
46
+ rspec spec
48
47
 
49
48
  push-image: prep
50
49
  @docker push $(NAMESPACE)/r10k:$(version)
@@ -64,4 +63,4 @@ push-readme:
64
63
 
65
64
  publish: push-image push-readme
66
65
 
67
- .PHONY: prep lint build test publish push-image push-readme
66
+ .PHONY: lint build test prep publish push-image push-readme
@@ -1,3 +1,12 @@
1
+ FROM alpine:3.9 as build
2
+
3
+ RUN apk add --no-cache ruby git
4
+ RUN mkdir /workspace
5
+ WORKDIR /workspace
6
+ COPY . /workspace
7
+ RUN gem build r10k.gemspec && \
8
+ mv r10k*.gem r10k.gem
9
+
1
10
  FROM alpine:3.9
2
11
 
3
12
  ARG vcs_ref
@@ -23,14 +32,15 @@ LABEL org.label-schema.maintainer="Puppet Release Team <release@puppet.com>" \
23
32
  org.label-schema.dockerfile="/Dockerfile"
24
33
 
25
34
  RUN apk add --no-cache ruby openssh-client git ruby-rugged curl ruby-dev make gcc musl-dev
35
+ COPY --from=build /workspace/r10k.gem /
36
+ RUN gem install --no-doc r10k.gem json etc && \
37
+ rm -f r10k.gem
26
38
 
27
- RUN gem install --no-doc r10k:"$R10K_VERSION" json etc
28
-
29
- COPY docker-entrypoint.sh /
39
+ COPY docker/r10k/docker-entrypoint.sh /
30
40
  RUN chmod +x /docker-entrypoint.sh
31
- COPY docker-entrypoint.d /docker-entrypoint.d
41
+ COPY docker/r10k/docker-entrypoint.d /docker-entrypoint.d
32
42
 
33
43
  ENTRYPOINT ["/docker-entrypoint.sh"]
34
44
  CMD ["help"]
35
45
 
36
- COPY Dockerfile /
46
+ COPY docker/r10k/Dockerfile /
@@ -14,16 +14,7 @@ describe 'r10k container' do
14
14
  end
15
15
 
16
16
  before(:all) do
17
- @image = ENV['PUPPET_TEST_DOCKER_IMAGE']
18
- if @image.nil?
19
- error_message = <<-MSG
20
- * * * * *
21
- PUPPET_TEST_DOCKER_IMAGE environment variable must be set so we
22
- know which image to test against!
23
- * * * * *
24
- MSG
25
- fail error_message
26
- end
17
+ @image = require_test_image
27
18
  end
28
19
 
29
20
  after(:all) do
File without changes
@@ -129,7 +129,7 @@ module R10K
129
129
  end
130
130
 
131
131
  def visit_puppetfile(puppetfile)
132
- puppetfile.load
132
+ puppetfile.load(@opts[:'default-branch-override'])
133
133
 
134
134
  yield
135
135
 
@@ -145,11 +145,24 @@ module R10K
145
145
  end
146
146
 
147
147
  def write_environment_info!(environment, started_at, success)
148
+ module_deploys = []
149
+ begin
150
+ environment.puppetfile.modules.each do |mod|
151
+ name = mod.name
152
+ version = mod.version
153
+ sha = mod.repo.head rescue nil
154
+ module_deploys.push({:name => name, :version => version, :sha => sha})
155
+ end
156
+ rescue
157
+ logger.debug("Unable to get environment module deploy data for .r10k-deploy.json at #{environment.path}")
158
+ end
159
+
148
160
  File.open("#{environment.path}/.r10k-deploy.json", 'w') do |f|
149
161
  deploy_info = environment.info.merge({
150
162
  :started_at => started_at,
151
163
  :finished_at => Time.new,
152
164
  :deploy_success => success,
165
+ :module_deploys => module_deploys,
153
166
  })
154
167
 
155
168
  f.puts(JSON.pretty_generate(deploy_info))
@@ -166,7 +179,12 @@ module R10K
166
179
  end
167
180
 
168
181
  def allowed_initialize_opts
169
- super.merge(puppetfile: :self, cachedir: :self, 'no-force': :self, 'generate-types': :self, 'puppet-path': :self)
182
+ super.merge(puppetfile: :self,
183
+ cachedir: :self,
184
+ 'no-force': :self,
185
+ 'generate-types': :self,
186
+ 'puppet-path': :self,
187
+ 'default-branch-override': :self)
170
188
  end
171
189
  end
172
190
  end
@@ -61,6 +61,7 @@ scheduled. On subsequent deployments, Puppetfile deployment will default to off.
61
61
  DESCRIPTION
62
62
 
63
63
  flag :p, :puppetfile, 'Deploy modules from a puppetfile'
64
+ required nil, :'default-branch-override', 'Specify a branchname to override the default branch in the puppetfile'
64
65
 
65
66
  runner R10K::Action::CriRunner.wrap(R10K::Action::Deploy::Environment)
66
67
  end
@@ -40,6 +40,10 @@ module R10K
40
40
  # @return [Pathname] Where the md5 of the cached tarball is stored.
41
41
  attr_accessor :md5_file_path
42
42
 
43
+ # @!attribute [rw] sha256_file_path
44
+ # @return [Pathname] Where the SHA256 of the cached tarball is stored.
45
+ attr_accessor :sha256_file_path
46
+
43
47
  # @!attribute [rw] unpack_path
44
48
  # @return [Pathname] Where the module will be unpacked to.
45
49
  attr_accessor :unpack_path
@@ -65,6 +69,9 @@ module R10K
65
69
  md5_filename = @forge_release.slug + '.md5'
66
70
  @md5_file_path = @tarball_cache_root + md5_filename
67
71
 
72
+ sha256_filename = @forge_release.slug + '.sha256'
73
+ @sha256_file_path = @tarball_cache_root + sha256_filename
74
+
68
75
  @unpack_path = Pathname.new(Dir.mktmpdir) + @forge_release.slug
69
76
  end
70
77
 
@@ -104,54 +111,79 @@ module R10K
104
111
  # module release checksum given by the Puppet Forge. On mismatch, remove
105
112
  # the cached copy.
106
113
  #
114
+ # @raise [R10K::Error] when no SHA256 is available and FIPS mode is on
107
115
  # @return [void]
108
116
  def verify
109
117
  logger.debug1 "Verifying that #{@tarball_cache_path} matches checksum"
110
118
 
111
- md5_of_tarball = Digest::MD5.hexdigest(File.read(@tarball_cache_path, mode: 'rb'))
119
+ sha256_of_tarball = Digest::SHA256.file(@tarball_cache_path).hexdigest
112
120
 
113
- if @md5_file_path.exist?
114
- verify_from_md5_file(md5_of_tarball)
121
+ if @sha256_file_path.exist?
122
+ verify_from_file(sha256_of_tarball, @sha256_file_path)
115
123
  else
116
- verify_from_forge(md5_of_tarball)
124
+ if @forge_release.respond_to?(:file_sha256) && !@forge_release.file_sha256.nil? && !@forge_release.file_sha256.size.zero?
125
+ forge_256_checksum = @forge_release.file_sha256
126
+ verify_from_forge(sha256_of_tarball, forge_256_checksum, @sha256_file_path)
127
+ else
128
+ if R10K::Util::Platform.fips?
129
+ raise R10K::Error, "Could not verify module, no SHA256 checksum available, and MD5 checksums not allowed in FIPS mode"
130
+ end
131
+
132
+ logger.debug1 "No SHA256 checksum available, falling back to MD5"
133
+ md5_of_tarball = Digest::MD5.file(@tarball_cache_path).hexdigest
134
+ if @md5_file_path.exist?
135
+ verify_from_file(md5_of_tarball, @md5_file_path)
136
+ else
137
+ verify_from_forge(md5_of_tarball, @forge_release.file_md5, @md5_file_path)
138
+ end
139
+ end
117
140
  end
118
141
  end
119
142
 
120
- # Verify the md5 of the cached tarball against the
143
+ # Verify the checksum of the cached tarball against the
121
144
  # module release checksum stored in the cache as well.
122
145
  # On mismatch, remove the cached copy of both files.
146
+ # @param tarball_checksum [String] the checksum (either md5 or SHA256)
147
+ # of the downloaded module tarball
148
+ # @param file [Pathname] the file containing the checksum as downloaded
149
+ # previously from the forge
150
+ # @param digest_class [Digest::SHA256, Digest::MD5] which checksum type
151
+ # to verify with
123
152
  #
124
153
  # @raise [PuppetForge::V3::Release::ChecksumMismatch] The
125
154
  # cached module release checksum doesn't match the cached checksum.
126
155
  #
127
156
  # @return [void]
128
- def verify_from_md5_file(md5_of_tarball)
129
- md5_from_file = File.read(@md5_file_path).strip
130
- if md5_of_tarball != md5_from_file
131
- logger.error "MD5 of #{@tarball_cache_path} (#{md5_of_tarball}) does not match checksum #{md5_from_file} in #{@md5_file_path}. Removing both files."
132
- cleanup_cached_tarball_path
133
- cleanup_md5_file_path
157
+ def verify_from_file(tarball_checksum, checksum_file_path)
158
+ checksum_from_file = File.read(checksum_file_path).strip
159
+ if tarball_checksum != checksum_from_file
160
+ logger.error "Checksum of #{@tarball_cache_path} (#{tarball_checksum}) does not match checksum #{checksum_from_file} in #{checksum_file_path}. Removing both files."
161
+ @tarball_cache_path.delete
162
+ checksum_file_path.delete
134
163
  raise PuppetForge::V3::Release::ChecksumMismatch.new
135
164
  end
136
165
  end
137
166
 
138
- # Verify the md5 of the cached tarball against the
167
+ # Verify the checksum of the cached tarball against the
139
168
  # module release checksum from the forge.
140
169
  # On mismatch, remove the cached copy of the tarball.
170
+ # @param tarball_checksum [String] the checksum (either md5 or SHA256)
171
+ # of the downloaded module tarball
172
+ # @param forge_checksum [String] the checksum downloaded from the Forge
173
+ # @param checksum_file_path [Pathname] the path to write the verified
174
+ # checksum to
141
175
  #
142
176
  # @raise [PuppetForge::V3::Release::ChecksumMismatch] The
143
177
  # cached module release checksum doesn't match the forge checksum.
144
178
  #
145
179
  # @return [void]
146
- def verify_from_forge(md5_of_tarball)
147
- md5_from_forge = @forge_release.file_md5
148
- #compare file_md5 to md5_of_tarball
149
- if md5_of_tarball != md5_from_forge
150
- logger.debug1 "MD5 of #{@tarball_cache_path} (#{md5_of_tarball}) does not match checksum #{md5_from_forge} found on the forge. Removing tarball."
151
- cleanup_cached_tarball_path
180
+ def verify_from_forge(tarball_checksum, forge_checksum, checksum_file_path)
181
+ if tarball_checksum != forge_checksum
182
+ logger.debug1 "Checksum of #{@tarball_cache_path} (#{tarball_checksum}) does not match checksum #{forge_checksum} found on the forge. Removing tarball."
183
+ @tarball_cache_path.delete
152
184
  raise PuppetForge::V3::Release::ChecksumMismatch.new
153
185
  else
154
- File.write(@md5_file_path, md5_from_forge)
186
+ File.write(checksum_file_path, forge_checksum)
155
187
  end
156
188
  end
157
189
 
@@ -191,20 +223,6 @@ module R10K
191
223
  download_path.parent.rmtree
192
224
  end
193
225
  end
194
-
195
- # Remove the cached module release.
196
- def cleanup_cached_tarball_path
197
- if tarball_cache_path.exist?
198
- tarball_cache_path.delete
199
- end
200
- end
201
-
202
- # Remove the module release md5.
203
- def cleanup_md5_file_path
204
- if md5_file_path.exist?
205
- md5_file_path.delete
206
- end
207
- end
208
226
  end
209
227
  end
210
228
  end
@@ -23,6 +23,11 @@ class R10K::Module::Git < R10K::Module::Base
23
23
  # @return [String]
24
24
  attr_reader :desired_ref
25
25
 
26
+ # @!attribute [r] default_ref
27
+ # @api private
28
+ # @return [String]
29
+ attr_reader :default_ref
30
+
26
31
  def initialize(title, dirname, args, environment=nil)
27
32
  super
28
33
 
@@ -63,17 +63,20 @@ class Puppetfile
63
63
  @loaded = false
64
64
  end
65
65
 
66
- def load
66
+ def load(default_branch_override = nil)
67
67
  if File.readable? @puppetfile_path
68
- self.load!
68
+ self.load!(default_branch_override)
69
69
  else
70
70
  logger.debug _("Puppetfile %{path} missing or unreadable") % {path: @puppetfile_path.inspect}
71
71
  end
72
72
  end
73
73
 
74
- def load!
74
+ def load!(default_branch_override = nil)
75
+ @default_branch_override = default_branch_override
76
+
75
77
  dsl = R10K::Puppetfile::DSL.new(self)
76
78
  dsl.instance_eval(puppetfile_contents, @puppetfile_path)
79
+
77
80
  validate_no_duplicate_names(@modules)
78
81
  @loaded = true
79
82
  rescue SyntaxError, LoadError, ArgumentError, NameError => e
@@ -118,6 +121,10 @@ class Puppetfile
118
121
  install_path = @moduledir
119
122
  end
120
123
 
124
+ if args.is_a?(Hash) && @default_branch_override != nil
125
+ args[:default_branch] = @default_branch_override
126
+ end
127
+
121
128
  # Keep track of all the content this Puppetfile is managing to enable purging.
122
129
  @managed_content[install_path] = Array.new unless @managed_content.has_key?(install_path)
123
130
 
@@ -179,7 +186,21 @@ class Puppetfile
179
186
  logger.debug _("Updating modules with %{pool_size} threads") % {pool_size: pool_size}
180
187
  mods_queue = modules_queue(visitor)
181
188
  thread_pool = pool_size.times.map { visitor_thread(visitor, mods_queue) }
182
- thread_pool.each(&:join)
189
+ thread_exception = nil
190
+
191
+ # If any threads raise an exception the deployment is considered a failure.
192
+ # In that event clear the queue, wait for other threads to finish their
193
+ # current work, then re-raise the first exception caught.
194
+ begin
195
+ thread_pool.each(&:join)
196
+ rescue => e
197
+ logger.error _("Error during concurrent deploy of a module: %{message}") % {message: e.message}
198
+ mods_queue.clear
199
+ thread_exception ||= e
200
+ retry
201
+ ensure
202
+ raise thread_exception unless thread_exception.nil?
203
+ end
183
204
  end
184
205
 
185
206
  def modules_queue(visitor)
@@ -195,8 +216,10 @@ class Puppetfile
195
216
  begin
196
217
  while mod = mods_queue.pop(true) do mod.accept(visitor) end
197
218
  rescue ThreadError => e
198
- logger.error _("Thread error during concurrent module deploy: %{message}") % {message: e.message}
219
+ logger.debug _("Module thread %{id} exiting: %{message}") % {message: e.message, id: Thread.current.object_id}
199
220
  Thread.exit
221
+ rescue => e
222
+ Thread.main.raise(e)
200
223
  end
201
224
  end
202
225
  end
@@ -3,6 +3,8 @@ require 'rbconfig'
3
3
  module R10K
4
4
  module Util
5
5
  module Platform
6
+ FIPS_FILE = "/proc/sys/crypto/fips_enabled"
7
+
6
8
  def self.platform
7
9
  # Test JRuby first to handle JRuby on Windows as well.
8
10
  if self.jruby?
@@ -14,6 +16,16 @@ module R10K
14
16
  end
15
17
  end
16
18
 
19
+ # We currently only suport FIPS mode on redhat 7, where it is
20
+ # toggled via a file.
21
+ def self.fips?
22
+ if File.exist?(FIPS_FILE)
23
+ File.read(FIPS_FILE).chomp == "1"
24
+ else
25
+ false
26
+ end
27
+ end
28
+
17
29
  def self.windows?
18
30
  RbConfig::CONFIG['host_os'] =~ /mswin|win32|dos|mingw|cygwin/i
19
31
  end
data/lib/r10k/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module R10K
2
- VERSION = '3.3.0'
2
+ VERSION = '3.3.1'
3
3
  end
data/locales/r10k.pot CHANGED
@@ -6,11 +6,11 @@
6
6
  #, fuzzy
7
7
  msgid ""
8
8
  msgstr ""
9
- "Project-Id-Version: r10k 3.2.0-7-g213f14b\n"
9
+ "Project-Id-Version: r10k 3.3.0-7-g6a2159a\n"
10
10
  "\n"
11
11
  "Report-Msgid-Bugs-To: docs@puppetlabs.com\n"
12
- "POT-Creation-Date: 2019-04-18 21:10+0000\n"
13
- "PO-Revision-Date: 2019-04-18 21:10+0000\n"
12
+ "POT-Creation-Date: 2019-06-14 22:40+0000\n"
13
+ "PO-Revision-Date: 2019-06-14 22:40+0000\n"
14
14
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
15
15
  "Language-Team: LANGUAGE <LL@li.org>\n"
16
16
  "Language: \n"
@@ -343,11 +343,15 @@ msgstr ""
343
343
  msgid "Updating modules with %{pool_size} threads"
344
344
  msgstr ""
345
345
 
346
- #: ../lib/r10k/puppetfile.rb:198
347
- msgid "Thread error during concurrent module deploy: %{message}"
346
+ #: ../lib/r10k/puppetfile.rb:190
347
+ msgid "Error during concurrent deploy of a module: %{message}"
348
348
  msgstr ""
349
349
 
350
- #: ../lib/r10k/puppetfile.rb:253
350
+ #: ../lib/r10k/puppetfile.rb:212
351
+ msgid "Module thread %{id} exiting: %{message}"
352
+ msgstr ""
353
+
354
+ #: ../lib/r10k/puppetfile.rb:269
351
355
  msgid "unrecognized declaration '%{method}'"
352
356
  msgstr ""
353
357