chefrepo-manifest-builder 0.1.0 → 0.1.1
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/.gitignore +35 -0
- data/.rakeTasks +7 -0
- data/.rspec +1 -0
- data/ChangeLog.md +4 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +172 -0
- data/LICENSE +201 -0
- data/LICENSE.txt +203 -0
- data/README.md +2 -0
- data/Rakefile +36 -0
- data/bin/chefrepomanifestbuilder +33 -0
- data/chefrepo-manifest-builder.gemspec +32 -0
- data/features/.gitkeep +0 -0
- data/features/manifestrepo-builder.feature +1 -0
- data/features/step_definitions/.gitkeep +0 -0
- data/features/step_definitions/manifestrepo-builder_steps.rb +1 -0
- data/lib/cicd/builder/chefrepo-manifest/mixlib/build.rb +62 -0
- data/lib/cicd/builder/chefrepo-manifest/mixlib/repo/artifactory.rb +323 -0
- data/lib/cicd/builder/chefrepo-manifest/version.rb +10 -0
- data/lib/cicd/builder/chefrepo-manifest.rb +39 -0
- data/openssl +0 -0
- data/spec/builder_spec.rb +8 -0
- data/spec/spec_helper.rb +4 -0
- data/tests/infinite-etag.rb +166 -0
- metadata +35 -4
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'aws-sdk-core'
|
2
|
+
require 'aws-sdk-resources'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
# ---------------------------------------------------------------------------------------------------------------
|
6
|
+
def getS3()
|
7
|
+
region = ENV['AWS_REGION'] || ::Aws.config[:region] || 'us-east-1'
|
8
|
+
unless @s3
|
9
|
+
# noinspection RubyArgCount
|
10
|
+
@s3 = ::Aws::S3::Client.new(region: region)
|
11
|
+
end
|
12
|
+
unless @s3 and ((@s3.config.access_key_id and @s3.config.secret_access_key) or @s3.config.credentials)
|
13
|
+
@logger.warn "Unable to find AWS credentials in standard locations:
|
14
|
+
ENV['AWS_ACCESS_KEY'] and ENV['AWS_SECRET_ACCESS_KEY']
|
15
|
+
Aws.config[:credentials]
|
16
|
+
Shared credentials file, ~/.aws/credentials
|
17
|
+
EC2 Instance profile
|
18
|
+
"
|
19
|
+
if ENV['AWS_PROFILE']
|
20
|
+
@logger.info "Trying profile '#{ENV['AWS_PROFILE']}' explicitly"
|
21
|
+
creds = Aws::SharedCredentials.new( path: File.expand_path('~/.aws/credentials'), profile: ENV['AWS_PROFILE'] )
|
22
|
+
if creds.loadable?
|
23
|
+
# noinspection RubyArgCount
|
24
|
+
@s3 = ::Aws::S3::Client.new(region: region, credentials: creds)
|
25
|
+
end
|
26
|
+
else
|
27
|
+
@logger.warn 'No AWS_PROFILE defined'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
unless @s3 and ((@s3.config.access_key_id and @s3.config.secret_access_key) or @s3.config.credentials)
|
31
|
+
raise 'Unable to find AWS credentials!'
|
32
|
+
end
|
33
|
+
@s3
|
34
|
+
end
|
35
|
+
|
36
|
+
# ---------------------------------------------------------------------------------------------------------------
|
37
|
+
def getBucket(name = nil)
|
38
|
+
@s3 = getS3()
|
39
|
+
begin
|
40
|
+
::Aws::S3::Bucket.new(name: name || ENV['AWS_S3_BUCKET'], client: @s3)
|
41
|
+
rescue Aws::S3::Errors::NotFound
|
42
|
+
@vars[:return_code] = Errors::BUCKET
|
43
|
+
nil
|
44
|
+
rescue Exception => e
|
45
|
+
@logger.error "S3 Bucket resource API error: #{e.class.name} #{e.message}"
|
46
|
+
raise e
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# ---------------------------------------------------------------------------------------------------------------
|
51
|
+
def getObjects(artifact, path)
|
52
|
+
parts = URI(path).path.gsub(%r'^#{File::SEPARATOR}', '').split(File::SEPARATOR)
|
53
|
+
name = parts.shift
|
54
|
+
bucket = getBucket(name)
|
55
|
+
key = File.join(parts, '')
|
56
|
+
@logger.info "S3://#{name}:#{key} URL: #{path} #{artifact}"
|
57
|
+
objects = []
|
58
|
+
bucket.objects(prefix: key).each do |object|
|
59
|
+
if artifact.empty? or (not artifact.empty? and object.key =~ %r'#{key}#{artifact}')
|
60
|
+
objects << object
|
61
|
+
end
|
62
|
+
end
|
63
|
+
@logger.debug "S3://#{name}:#{key} has #{objects.size} objects"
|
64
|
+
return key, name, objects
|
65
|
+
end
|
66
|
+
|
67
|
+
# ---------------------------------------------------------------------------------------------------------------
|
68
|
+
def calcLocalETag(etag, local, size = nil)
|
69
|
+
if size == nil
|
70
|
+
stat = File.stat(local)
|
71
|
+
size = stat.size
|
72
|
+
end
|
73
|
+
@logger.debug "Calculate etag to match #{etag}"
|
74
|
+
match = etag.match(%r'-(\d+)$')
|
75
|
+
check = if match
|
76
|
+
require 's3etag'
|
77
|
+
parts = match[1].to_i
|
78
|
+
chunk = size.to_f / parts.to_f
|
79
|
+
mbs = (chunk.to_f / 1024 /1024 + 0.5).to_i
|
80
|
+
part_size = mbs * 1024 * 1024
|
81
|
+
chkit = S3Etag.calc(file: local, threshold: part_size, min_part_size: part_size, max_parts: parts)
|
82
|
+
@logger.debug "S3Etag Calculated #{chkit} : (#{size} / #{part_size}) <= #{parts}"
|
83
|
+
chunks = size / part_size
|
84
|
+
while chkit != etag and chunks <= parts and chunks > 0 and (size > part_size)
|
85
|
+
# Go one larger if a modulus remains and we have the right number of parts
|
86
|
+
mbs += 1
|
87
|
+
part_size = mbs * 1024 * 1024
|
88
|
+
chunks = size.to_f / part_size
|
89
|
+
chkit = S3Etag.calc(file: local, threshold: part_size, min_part_size: part_size, max_parts: parts)
|
90
|
+
@logger.debug "S3Etag Calculated #{chkit} : (#{size} / #{part_size}) <= #{parts}"
|
91
|
+
end
|
92
|
+
#raise "Unable to match etag #{etag}!" if chkit != etag
|
93
|
+
chkit
|
94
|
+
else
|
95
|
+
Digest::MD5.file(local).hexdigest
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# ---------------------------------------------------------------------------------------------------------------
|
100
|
+
def shouldDownload?(etag, local, object)
|
101
|
+
if File.exists?(local)
|
102
|
+
@logger.debug "\t\tchecking etag on #{local}"
|
103
|
+
stat = File.stat(local)
|
104
|
+
check = calcLocalETag(etag, local, stat.size)
|
105
|
+
if etag != check or object.size != stat.size or object.last_modified > stat.mtime
|
106
|
+
@logger.debug "\t\t#{etag} != \"#{check}\" #{object.size} != #{stat.size} #{object.last_modified} > #{stat.mtime}"
|
107
|
+
true
|
108
|
+
else
|
109
|
+
@logger.debug "\t\tmatched #{etag}"
|
110
|
+
false
|
111
|
+
end
|
112
|
+
else
|
113
|
+
true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# ---------------------------------------------------------------------------------------------------------------
|
118
|
+
def doDownload(etag, local, object)
|
119
|
+
@logger.info "\t\tdownload #{object.size} bytes"
|
120
|
+
response = object.get(:response_target => local)
|
121
|
+
File.utime(response.last_modified, response.last_modified, local)
|
122
|
+
@logger.info "\t\tdone"
|
123
|
+
check = calcLocalETag(etag, local)
|
124
|
+
if check.eql?(etag)
|
125
|
+
false
|
126
|
+
else
|
127
|
+
@logger.info "\tETag different: #{etag} != #{check}"
|
128
|
+
true
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
class FakeLogger
|
134
|
+
def initialize
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
def method_missing(*args)
|
139
|
+
puts "#{args[0]}: #{args[1..-1].join(' ')}"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
@logger = FakeLogger.new()
|
144
|
+
artifact, path = ['', 'https://s3.amazonaws.com/wgen-sto-artifacts/release/com/amplify/learning/enrollment/1.3.0-265']
|
145
|
+
local_dir = File.join('/tmp', 'enrollment', '')
|
146
|
+
Dir.mkdir(local_dir, 0700) unless File.directory?(local_dir)
|
147
|
+
artifacts = []
|
148
|
+
|
149
|
+
key, name, objects = getObjects(artifact, path)
|
150
|
+
# 1 or more objects on the key/ path
|
151
|
+
if objects.size > 0
|
152
|
+
objects.each do |object|
|
153
|
+
@logger.info "\tchecking #{object.key}"
|
154
|
+
local = File.join(local_dir, File.basename(object.key))
|
155
|
+
etag = object.etag.gsub(%r/['"]/, '')
|
156
|
+
download = shouldDownload?(etag, local, object)
|
157
|
+
if download
|
158
|
+
changed = doDownload(etag, local, object)
|
159
|
+
else
|
160
|
+
@logger.info "\t\tunchanged"
|
161
|
+
end
|
162
|
+
artifacts << local
|
163
|
+
end
|
164
|
+
else
|
165
|
+
@logger.fatal "Artifact not found: s3://#{name}/#{key}#{artifact}"
|
166
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chefrepo-manifest-builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christo De Lange
|
@@ -187,10 +187,35 @@ dependencies:
|
|
187
187
|
description: ChefRepo builder of the software manifest for Continuous Integration/Continuous
|
188
188
|
Delivery artifact promotion style deployments
|
189
189
|
email: rubygems@dldinternet.com
|
190
|
-
executables:
|
190
|
+
executables:
|
191
|
+
- chefrepomanifestbuilder
|
191
192
|
extensions: []
|
192
193
|
extra_rdoc_files: []
|
193
|
-
files:
|
194
|
+
files:
|
195
|
+
- ".gitignore"
|
196
|
+
- ".rakeTasks"
|
197
|
+
- ".rspec"
|
198
|
+
- ChangeLog.md
|
199
|
+
- Gemfile
|
200
|
+
- Gemfile.lock
|
201
|
+
- LICENSE
|
202
|
+
- LICENSE.txt
|
203
|
+
- README.md
|
204
|
+
- Rakefile
|
205
|
+
- bin/chefrepomanifestbuilder
|
206
|
+
- chefrepo-manifest-builder.gemspec
|
207
|
+
- features/.gitkeep
|
208
|
+
- features/manifestrepo-builder.feature
|
209
|
+
- features/step_definitions/.gitkeep
|
210
|
+
- features/step_definitions/manifestrepo-builder_steps.rb
|
211
|
+
- lib/cicd/builder/chefrepo-manifest.rb
|
212
|
+
- lib/cicd/builder/chefrepo-manifest/mixlib/build.rb
|
213
|
+
- lib/cicd/builder/chefrepo-manifest/mixlib/repo/artifactory.rb
|
214
|
+
- lib/cicd/builder/chefrepo-manifest/version.rb
|
215
|
+
- openssl
|
216
|
+
- spec/builder_spec.rb
|
217
|
+
- spec/spec_helper.rb
|
218
|
+
- tests/infinite-etag.rb
|
194
219
|
homepage: https://rubygems.org/gems/manifest-builder
|
195
220
|
licenses:
|
196
221
|
- Apachev2
|
@@ -215,4 +240,10 @@ rubygems_version: 2.2.2
|
|
215
240
|
signing_key:
|
216
241
|
specification_version: 4
|
217
242
|
summary: ChefRepo builder for a software manifest
|
218
|
-
test_files:
|
243
|
+
test_files:
|
244
|
+
- features/.gitkeep
|
245
|
+
- features/manifestrepo-builder.feature
|
246
|
+
- features/step_definitions/.gitkeep
|
247
|
+
- features/step_definitions/manifestrepo-builder_steps.rb
|
248
|
+
- spec/builder_spec.rb
|
249
|
+
- spec/spec_helper.rb
|