chefrepo-manifest-builder 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.0
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