bosh_cli 1.2831.0 → 1.2839.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b9f61a1c4dc97a4d1f4e909b010779a432370856
4
- data.tar.gz: c430c18acb4e3d9803e0ea1d9ce521ed60888aee
3
+ metadata.gz: 3f11dc3119b4347b9e61c770c43d31b09ec3e1aa
4
+ data.tar.gz: 5d829eee1ce9742ea980476c1b7cb769887ab59e
5
5
  SHA512:
6
- metadata.gz: 15c4b0d2a9b40972f22184ccce08917a9a0b2196b306e81cb0f53761796f7c35fadcedd4563605091f82b6dba1fa1cd4f6172e17e63b6a77475df61b208a1e85
7
- data.tar.gz: 34889ef7e9ab28a490e7f6d51001694dc36e0780781cafc320ac56aa1bebb23deb1d904d01dae88bfe28772f6c4b466194975be062fda1f994333fe22476e5be
6
+ metadata.gz: bb7ac41c08a80eee35cec3672d9969c91de24cea903e0ae1c765bfbd1c4c86940e7b4ce3953c3cf5717c610b2988c8e0609ec7621520fc882fc67c449914ab29
7
+ data.tar.gz: a0ba29122f2ff944793adb8f99473b0e29ffd39ac49db87ad368446bf38e9bdeecaebe3c33d3ccedfaa0c92a70894fbaf70ae019eb615865906108adee3f76ec
data/lib/cli.rb CHANGED
@@ -51,6 +51,7 @@ require 'common/thread_pool'
51
51
  require 'cli/config'
52
52
  require 'cli/core_ext'
53
53
  require 'cli/errors'
54
+ require 'cli/glob_match'
54
55
  require 'cli/yaml_helper'
55
56
  require 'cli/dependency_helper'
56
57
  require 'cli/deployment_manifest'
@@ -75,9 +76,12 @@ require 'cli/versions/releases_dir_migrator'
75
76
  require 'cli/versions/version_file_resolver'
76
77
  require 'cli/versions/multi_release_support'
77
78
 
78
- require 'cli/packaging_helper'
79
- require 'cli/package_builder'
80
- require 'cli/job_builder'
79
+ require 'cli/archive_builder'
80
+ require 'cli/archive_repository_provider'
81
+ require 'cli/archive_repository'
82
+ require 'cli/build_artifact'
83
+ require 'cli/resources/job'
84
+ require 'cli/resources/package'
81
85
  require 'cli/changeset_helper'
82
86
  require 'cli/deployment_manifest_compiler'
83
87
  require 'cli/task_tracking'
@@ -0,0 +1,119 @@
1
+ module Bosh::Cli
2
+ class ArchiveBuilder
3
+ attr_reader :options
4
+
5
+ def initialize(archive_repository_provider, options = {})
6
+ @archive_repository_provider = archive_repository_provider
7
+ @options = options
8
+ end
9
+
10
+ def build(resource)
11
+ @archive_repository = @archive_repository_provider.get(resource)
12
+ resource.run_script(:prepare)
13
+
14
+ artifact = nil
15
+ with_indent(' ') do
16
+ artifact = locate_artifact(resource)
17
+ if artifact.nil?
18
+ artifact = create_artifact(resource)
19
+ say("Generated version '#{artifact.fingerprint}'".make_green)
20
+
21
+ unless dry_run?
22
+ artifact = @archive_repository.install(artifact)
23
+ end
24
+ end
25
+
26
+ if final? && !dry_run?
27
+ say("Uploading final version '#{artifact.version}'...")
28
+ artifact, blobstore_id = @archive_repository.upload_to_blobstore(artifact)
29
+ say("Uploaded, blobstore id '#{blobstore_id}'")
30
+ end
31
+ end
32
+
33
+ artifact
34
+ rescue Bosh::Blobstore::BlobstoreError => e
35
+ raise BlobstoreError, "Blobstore error: #{e}"
36
+ end
37
+
38
+ def dry_run?
39
+ !!options[:dry_run]
40
+ end
41
+
42
+ def final?
43
+ !!options[:final]
44
+ end
45
+
46
+ private
47
+
48
+ def copy_files(resource)
49
+ resource.files.each do |src, dest|
50
+ dest_path = Pathname(staging_dir).join(dest)
51
+ if File.directory?(src)
52
+ FileUtils.mkdir_p(dest_path)
53
+ else
54
+ FileUtils.mkdir_p(dest_path.parent)
55
+ FileUtils.cp(src, dest_path, :preserve => true)
56
+ end
57
+ end
58
+ end
59
+
60
+ def locate_artifact(resource)
61
+ artifact = @archive_repository.lookup(resource)
62
+
63
+ if artifact.nil?
64
+ say("No artifact found for #{resource.name}".make_red)
65
+ return nil
66
+ end
67
+
68
+ if artifact.dev_artifact? && final? && !dry_run?
69
+ artifact = @archive_repository.copy_from_dev_to_final(artifact)
70
+ end
71
+
72
+ artifact
73
+ rescue Bosh::Cli::CorruptedArchive => e
74
+ say "#{"Warning".make_red}: #{e.message}"
75
+ nil
76
+ end
77
+
78
+ def create_artifact(resource)
79
+ tarball_path = safe_temp_file(resource.name, '.tgz')
80
+
81
+ say('Generating...')
82
+
83
+ copy_files(resource)
84
+ resource.run_script(:pre_packaging, staging_dir)
85
+
86
+ in_staging_dir do
87
+ tar_out = `tar -chzf #{tarball_path} . 2>&1`
88
+ unless $?.exitstatus == 0
89
+ raise PackagingError, "Cannot create tarball: #{tar_out}"
90
+ end
91
+ end
92
+
93
+ fingerprint = BuildArtifact.make_fingerprint(resource)
94
+
95
+ sha1 = BuildArtifact.checksum(tarball_path)
96
+ BuildArtifact.new(resource.name, fingerprint, tarball_path, sha1, resource.dependencies, true, !final?)
97
+ end
98
+
99
+ def file_checksum(path)
100
+ Digest::SHA1.file(path).hexdigest
101
+ end
102
+
103
+ def staging_dir
104
+ @staging_dir ||= Dir.mktmpdir
105
+ end
106
+
107
+ def in_staging_dir
108
+ Dir.chdir(staging_dir) { yield }
109
+ end
110
+
111
+ private
112
+
113
+ def safe_temp_file(prefix, suffix, dir = Dir.tmpdir)
114
+ Dir::Tmpname.create([prefix, suffix], dir) do |tmpname, _, _|
115
+ File.open(tmpname, File::RDWR|File::CREAT|File::EXCL).close
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,108 @@
1
+ module Bosh::Cli
2
+ class ArchiveRepository
3
+ def initialize(archive_dir, blobstore, resource)
4
+ @archive_dir = archive_dir
5
+ @blobstore = blobstore
6
+
7
+ dev_builds_dir = Pathname(@archive_dir).join(".dev_builds", resource.plural_type, resource.name).to_s
8
+ FileUtils.mkdir_p(dev_builds_dir)
9
+ @dev_index = Versions::VersionsIndex.new(dev_builds_dir)
10
+ @dev_storage = Versions::LocalVersionStorage.new(dev_builds_dir)
11
+
12
+ final_builds_dir = Pathname(@archive_dir).join(".final_builds", resource.plural_type, resource.name).to_s
13
+ FileUtils.mkdir_p(final_builds_dir)
14
+ @final_index = Versions::VersionsIndex.new(final_builds_dir)
15
+ @final_storage = Versions::LocalVersionStorage.new(final_builds_dir)
16
+
17
+ @final_resolver = Versions::VersionFileResolver.new(@final_storage, @blobstore)
18
+ end
19
+
20
+ def lookup(resource)
21
+ fingerprint = BuildArtifact.make_fingerprint(resource)
22
+
23
+ artifact_info = @final_index[fingerprint]
24
+ if artifact_info && artifact_info['blobstore_id']
25
+ blobstore_id = artifact_info['blobstore_id']
26
+ version = artifact_info['version'] || fingerprint
27
+ sha1 = artifact_info['sha1']
28
+
29
+ say('Using final version')
30
+ tarball_path = @final_resolver.find_file(blobstore_id, sha1, version, "#{resource.singular_type} #{resource.name} (#{version})") # todo: 'package' vs 'job'
31
+
32
+ BuildArtifact.new(resource.name, fingerprint, tarball_path, sha1, resource.dependencies, false, false)
33
+ else
34
+ artifact_info = @dev_index[fingerprint]
35
+ if artifact_info
36
+ version = artifact_info['version'] || fingerprint
37
+ if @dev_storage.has_file?(version)
38
+ say('Using dev version')
39
+
40
+ tarball_path = @dev_storage.get_file(version)
41
+ if file_checksum(tarball_path) != artifact_info['sha1']
42
+ raise CorruptedArchive, "#{resource.singular_type} #{resource.name} (#{version}) archive at #{tarball_path} corrupted"
43
+ end
44
+
45
+ BuildArtifact.new(resource.name, fingerprint, tarball_path, artifact_info['sha1'], resource.dependencies, false, true)
46
+ end
47
+ end
48
+ end
49
+
50
+ rescue Bosh::Blobstore::NotFound
51
+ raise BlobstoreError, "Final version of '#{name}' not found in blobstore"
52
+ rescue Bosh::Blobstore::BlobstoreError => e
53
+ raise BlobstoreError, "Blobstore error: #{e}"
54
+ end
55
+
56
+ def upload_to_blobstore(artifact)
57
+ artifact_info = @final_index[artifact.fingerprint]
58
+ # todo raise if artifact.dev_artifact?
59
+ return artifact, artifact_info['blobstore_id'] if artifact_info['blobstore_id']
60
+
61
+ blobstore_id = nil
62
+ File.open(artifact.tarball_path, 'r') do |f|
63
+ blobstore_id = @blobstore.create(f)
64
+ end
65
+
66
+ @final_index.update_version(artifact.fingerprint, {
67
+ 'version' => artifact.version,
68
+ 'sha1' => artifact.sha1,
69
+ 'blobstore_id' => blobstore_id
70
+ })
71
+ artifact = BuildArtifact.new(artifact.name, artifact.fingerprint, artifact.tarball_path, artifact.sha1, artifact.dependencies, artifact.new_version?, false)
72
+ return artifact, blobstore_id
73
+ end
74
+
75
+ def install(artifact)
76
+ fingerprint = artifact.fingerprint
77
+ origin_file = artifact.tarball_path
78
+ new_tarball_path = place_file_and_update_index(fingerprint, origin_file,
79
+ artifact.dev_artifact? ? @dev_index : @final_index,
80
+ artifact.dev_artifact? ? @dev_storage : @final_storage)
81
+
82
+ BuildArtifact.new(artifact.name, artifact.fingerprint, new_tarball_path, artifact.sha1, artifact.dependencies, artifact.new_version?, artifact.dev_artifact?)
83
+ end
84
+
85
+ def copy_from_dev_to_final(artifact)
86
+ final_tarball_path = place_file_and_update_index(artifact.fingerprint, artifact.tarball_path, @final_index, @final_storage)
87
+ BuildArtifact.new(artifact.name, artifact.fingerprint, final_tarball_path, artifact.sha1, artifact.dependencies, artifact.new_version?, false)
88
+ end
89
+
90
+ private
91
+
92
+ def place_file_and_update_index(fingerprint, origin_file, index, storage)
93
+ # add version (with its validation) before adding sha1
94
+ index.add_version(fingerprint, {'version' => fingerprint} )
95
+ tarball_path = storage.put_file(fingerprint, origin_file)
96
+ sha1 = file_checksum(tarball_path)
97
+ index.update_version(fingerprint, {'version' => fingerprint, 'sha1' => sha1})
98
+ tarball_path
99
+ end
100
+
101
+ def file_checksum(path)
102
+ Digest::SHA1.file(path).hexdigest
103
+ end
104
+ end
105
+
106
+ class CorruptedArchive < StandardError
107
+ end
108
+ end
@@ -0,0 +1,12 @@
1
+ module Bosh::Cli
2
+ class ArchiveRepositoryProvider
3
+ def initialize(archive_dir, blobstore)
4
+ @archive_dir = archive_dir
5
+ @blobstore = blobstore
6
+ end
7
+
8
+ def get(resource)
9
+ ArchiveRepository.new(@archive_dir, @blobstore, resource)
10
+ end
11
+ end
12
+ end
@@ -48,7 +48,7 @@ module Bosh::Cli
48
48
  def release
49
49
  return @release if @release
50
50
  check_if_release_dir
51
- @release = Bosh::Cli::Release.new(@work_dir, options[:final])
51
+ @release = Bosh::Cli::Release.new(work_dir, options[:final])
52
52
  end
53
53
 
54
54
  def progress_renderer
@@ -0,0 +1,75 @@
1
+ module Bosh::Cli
2
+ class BuildArtifact
3
+ attr_reader :name, :fingerprint, :tarball_path, :sha1, :dependencies
4
+
5
+ def initialize(name, fingerprint, tarball_path, sha1, dependencies, is_new_version, is_dev_artifact)
6
+ @name = name
7
+ @fingerprint = fingerprint
8
+ @tarball_path = tarball_path
9
+ @sha1 = sha1
10
+ @dependencies = dependencies
11
+ @is_dev_artifact = is_dev_artifact
12
+ @notes = []
13
+ @is_new_version = is_new_version
14
+ end
15
+
16
+ def version
17
+ fingerprint
18
+ end
19
+
20
+ def dev_artifact?
21
+ @is_dev_artifact
22
+ end
23
+
24
+ def new_version?
25
+ @is_new_version
26
+ end
27
+
28
+ private
29
+
30
+ def self.checksum(tarball_path)
31
+ if tarball_path && File.exists?(tarball_path)
32
+ digest_file(tarball_path)
33
+ else
34
+ nil
35
+ end
36
+ end
37
+
38
+ def self.digest_file(filename)
39
+ File.file?(filename) ? Digest::SHA1.file(filename).hexdigest : ''
40
+ end
41
+
42
+ # Git doesn't really track file permissions, it just looks at executable
43
+ # bit and uses 0755 if it's set or 0644 if not. We have to mimic that
44
+ # behavior in the fingerprint calculation to avoid the situation where
45
+ # seemingly clean working copy would trigger new fingerprints for
46
+ # artifacts with changed permissions. Also we don't want current
47
+ # fingerprints to change, hence the exact values below.
48
+ def self.file_mode(path)
49
+ if File.directory?(path)
50
+ '40755'
51
+ elsif File.executable?(path)
52
+ '100755'
53
+ else
54
+ '100644'
55
+ end
56
+ end
57
+
58
+ # TODO: be sure we are handling the case in which there was an index, with a pre-defined fingerprint
59
+ def self.make_fingerprint(resource)
60
+ scheme = 2
61
+ contents = "v#{scheme}"
62
+
63
+ resource.files.each do |filename, name|
64
+ contents << resource.format_fingerprint(digest_file(filename), filename, name, file_mode(filename))
65
+ end
66
+
67
+ contents << resource.additional_fingerprints.join(",")
68
+ Digest::SHA1.hexdigest(contents)
69
+ end
70
+
71
+ def resource
72
+ raise
73
+ end
74
+ end
75
+ end
@@ -154,18 +154,13 @@ module Bosh::Cli::Command
154
154
  end
155
155
 
156
156
  say(" - discovering packages")
157
- packages = Bosh::Cli::PackageBuilder.discover(
158
- work_dir,
159
- :dry_run => true,
160
- :final => false
161
- )
157
+ packages = Bosh::Cli::Resources::Package.discover(work_dir)
162
158
 
163
159
  say(" - discovering jobs")
164
- jobs = Bosh::Cli::JobBuilder.discover(
160
+ jobs = Bosh::Cli::Resources::Job.discover(
165
161
  work_dir,
166
- :dry_run => true,
167
- :final => false,
168
- :package_names => packages.map {|package| package.name}
162
+ # TODO: be sure this is covered in integration
163
+ packages.map {|package| package['name']}
169
164
  )
170
165
 
171
166
  say(" - validating properties")
@@ -85,13 +85,13 @@ module Bosh::Cli::Command
85
85
  end
86
86
 
87
87
  header('Building packages')
88
- packages = build_packages(dry_run, final)
88
+ package_artifacts = build_packages(dry_run, final)
89
89
 
90
90
  header('Building jobs')
91
- jobs = build_jobs(packages.map(&:name), dry_run, final)
91
+ job_artifacts = build_jobs(package_artifacts.map { |artifact| artifact.name }, dry_run, final)
92
92
 
93
93
  header('Building release')
94
- release_builder = build_release(dry_run, final, jobs, manifest_only, packages, name, version)
94
+ release_builder = build_release(dry_run, final, job_artifacts, manifest_only, package_artifacts, name, version)
95
95
 
96
96
  header('Release summary')
97
97
  show_summary(release_builder)
@@ -134,22 +134,19 @@ module Bosh::Cli::Command
134
134
  end
135
135
 
136
136
  def build_packages(dry_run, final)
137
- packages = Bosh::Cli::PackageBuilder.discover(
138
- work_dir,
139
- :final => final,
140
- :blobstore => release.blobstore,
141
- :dry_run => dry_run
142
- )
143
-
144
- packages.each do |package|
137
+ archive_builder = Bosh::Cli::ArchiveBuilder.new(archive_repository_provider,
138
+ dry_run: dry_run, final: final)
139
+ packages = Bosh::Cli::Resources::Package.discover(work_dir)
140
+ artifacts = packages.map do |package|
145
141
  say("Building #{package.name.make_green}...")
146
- package.build
142
+ artifact = archive_builder.build(package)
147
143
  nl
144
+ artifact
148
145
  end
149
146
 
150
147
  if packages.size > 0
151
- package_index = packages.inject({}) do |index, package|
152
- index[package.name] = package.dependencies
148
+ package_index = artifacts.inject({}) do |index, artifact|
149
+ index[artifact.name] = artifact.dependencies
153
150
  index
154
151
  end
155
152
  sorted_packages = tsort_packages(package_index)
@@ -161,11 +158,15 @@ module Bosh::Cli::Command
161
158
  nl
162
159
  end
163
160
 
164
- packages
161
+ artifacts
162
+ end
163
+
164
+ def archive_repository_provider
165
+ @archive_repository_provider ||= Bosh::Cli::ArchiveRepositoryProvider.new(work_dir, release.blobstore)
165
166
  end
166
167
 
167
- def build_release(dry_run, final, jobs, manifest_only, packages, name, version)
168
- release_builder = Bosh::Cli::ReleaseBuilder.new(release, packages, jobs, name,
168
+ def build_release(dry_run, final, job_artifacts, manifest_only, package_artifacts, name, version)
169
+ release_builder = Bosh::Cli::ReleaseBuilder.new(release, package_artifacts, job_artifacts, name,
169
170
  final: final,
170
171
  commit_hash: commit_hash,
171
172
  version: version,
@@ -183,22 +184,18 @@ module Bosh::Cli::Command
183
184
  release_builder
184
185
  end
185
186
 
186
- def build_jobs(built_package_names, dry_run, final)
187
- jobs = Bosh::Cli::JobBuilder.discover(
188
- work_dir,
189
- :final => final,
190
- :blobstore => release.blobstore,
191
- :dry_run => dry_run,
192
- :package_names => built_package_names
193
- )
194
-
195
- jobs.each do |job|
187
+ def build_jobs(packages, dry_run, final)
188
+ archive_builder = Bosh::Cli::ArchiveBuilder.new(archive_repository_provider,
189
+ :final => final, :dry_run => dry_run)
190
+ jobs = Bosh::Cli::Resources::Job.discover(work_dir, packages)
191
+ artifacts = jobs.map do |job|
196
192
  say("Building #{job.name.make_green}...")
197
- job.build
193
+ artifact = archive_builder.build(job)
198
194
  nl
195
+ artifact
199
196
  end
200
197
 
201
- jobs
198
+ artifacts
202
199
  end
203
200
 
204
201
  def save_final_release_name
@@ -225,15 +222,15 @@ module Bosh::Cli::Command
225
222
  def show_summary(builder)
226
223
  packages_table = table do |t|
227
224
  t.headings = %w(Name Version Notes)
228
- builder.packages.each do |package|
229
- t << artifact_summary(package)
225
+ builder.packages.each do |package_artifact|
226
+ t << artifact_summary(package_artifact)
230
227
  end
231
228
  end
232
229
 
233
230
  jobs_table = table do |t|
234
231
  t.headings = %w(Name Version Notes)
235
- builder.jobs.each do |job|
236
- t << artifact_summary(job)
232
+ builder.jobs.each do |job_artifact|
233
+ t << artifact_summary(job_artifact)
237
234
  end
238
235
  end
239
236
 
@@ -260,12 +257,12 @@ module Bosh::Cli::Command
260
257
  end
261
258
  end
262
259
 
263
- def artifact_summary(artefact)
264
- result = []
265
- result << artefact.name
266
- result << artefact.version
267
- result << artefact.notes.join(', ')
268
- result
260
+ def artifact_summary(artifact)
261
+ [
262
+ artifact.name,
263
+ artifact.version,
264
+ artifact.new_version? ? 'new version' : '',
265
+ ]
269
266
  end
270
267
 
271
268
  def commit_hash