bosh_cli 1.2657.0 → 1.2669.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: 600ba43a96360d7442c352820f7d65b32b59768c
4
- data.tar.gz: a4215a827e50ad57105d409ce04c3d304641ecc0
3
+ metadata.gz: 206c482ff9d75e5f49d6bc0950f76bbac870e316
4
+ data.tar.gz: 06edf9a6c160e702431e5efed54cb8bbc16ed4da
5
5
  SHA512:
6
- metadata.gz: 641e53d5f4a266d2a22b648ac0fa726803f96504c00fa2776322dd885ba5868a83c78cfb85e2a84c3e44c79ff2dfa1968b0f892d94c1f8d17f770fa7865e1262
7
- data.tar.gz: b074a90e8e060b6d8d78f1d3c828806390d307086a1812f9f3dd125cc648fbe14969e18e5db02b67d523f2a0e548d6d6c5df5f3565b7b238c3820e9d13d12f36
6
+ metadata.gz: f33ee8ddea4a3920d98e28b99b81d23af167ea7df505740b2ce3b06df28f859f03c62376660a6b17083555b0bd35e13e1c9a6cba49d24042bbed5eee2a725be0
7
+ data.tar.gz: 42ed8b5ca8743042d081163ecb092970489248db2fa75b33466df2effa66ac05383b8e9f861c7e4115d7ac4c12dba309fc1ef4c6aea594a2d7fc4af808bf18ec
data/lib/cli.rb CHANGED
@@ -31,6 +31,8 @@ require 'zlib'
31
31
  require 'archive/tar/minitar'
32
32
  include Archive::Tar
33
33
 
34
+ require 'bosh/template/evaluation_context'
35
+
34
36
  unless defined?(Bosh::Cli::VERSION)
35
37
  require 'cli/version'
36
38
  end
@@ -38,9 +40,10 @@ end
38
40
  require 'common/common'
39
41
  require 'common/exec'
40
42
  require 'common/version/release_version'
43
+ require 'common/version/release_version_list'
41
44
  require 'common/version/bosh_version'
42
45
  require 'common/version/stemcell_version'
43
- require 'common/properties'
46
+ require 'common/version/stemcell_version_list'
44
47
 
45
48
  require 'cli/config'
46
49
  require 'cli/core_ext'
@@ -58,7 +61,10 @@ require 'cli/director_task'
58
61
  require 'cli/line_wrap'
59
62
  require 'cli/backup_destination_path'
60
63
 
61
- require 'cli/versions_index'
64
+ require 'cli/versions/versions_index'
65
+ require 'cli/versions/local_version_storage'
66
+ require 'cli/versions/release_versions_index'
67
+ require 'cli/versions/version_file_resolver'
62
68
  require 'cli/packaging_helper'
63
69
  require 'cli/package_builder'
64
70
  require 'cli/job_builder'
@@ -59,26 +59,6 @@ module Bosh::Cli::Command
59
59
  else
60
60
  say(" not set".make_yellow)
61
61
  end
62
-
63
- if in_release_dir?
64
- nl
65
- say("Release".make_green)
66
-
67
- dev_version = Bosh::Cli::VersionsIndex.new(
68
- File.join(work_dir, "dev_releases")).latest_version
69
-
70
- final_version = Bosh::Cli::VersionsIndex.new(
71
- File.join(work_dir, "releases")).latest_version
72
-
73
- dev = release.dev_name
74
- dev += "/#{dev_version}" if dev && dev_version
75
-
76
- final = release.final_name
77
- final += "/#{final_version}" if final && final_version
78
-
79
- print_value("dev", dev)
80
- print_value("final", final)
81
- end
82
62
  end
83
63
  end
84
64
 
@@ -374,7 +374,7 @@ module Bosh::Cli
374
374
  end
375
375
 
376
376
  stemcells.inject({}) do |hash, (name, versions)|
377
- hash[name] = Bosh::Common::Version::StemcellVersion.parse_list(versions).latest.to_s
377
+ hash[name] = Bosh::Common::Version::StemcellVersionList.parse(versions).latest.to_s
378
378
  hash
379
379
  end
380
380
  end
@@ -1,11 +1,12 @@
1
1
  # Copyright (c) 2009-2012 VMware, Inc.
2
2
 
3
3
  require 'common/deep_copy'
4
+ require 'bosh/template/property_helper'
4
5
 
5
6
  module Bosh::Cli
6
7
  class JobPropertyCollection
7
8
  include Enumerable
8
- include Bosh::Common::PropertyHelper
9
+ include Bosh::Template::PropertyHelper
9
10
 
10
11
  # @param [JobBuilder] job_builder Which job this property collection is for
11
12
  # @param [Hash] global_properties Globally defined properties
@@ -1,4 +1,5 @@
1
1
  # Copyright (c) 2009-2012 VMware, Inc.
2
+ require 'bosh/template/evaluation_context'
2
3
 
3
4
  module Bosh::Cli
4
5
  class JobPropertyValidator
@@ -108,7 +109,7 @@ module Bosh::Cli
108
109
  # @param [Hash] spec Fake instance spec
109
110
  def evaluate_template(job, template_path, spec)
110
111
  erb = ERB.new(File.read(template_path))
111
- context = Bosh::Common::TemplateEvaluationContext.new(spec)
112
+ context = Bosh::Template::EvaluationContext.new(spec)
112
113
  begin
113
114
  erb.result(context.get_binding)
114
115
  rescue Exception => e
@@ -8,7 +8,12 @@ module Bosh::Cli
8
8
 
9
9
  def init_indices
10
10
  @dev_index = VersionsIndex.new(@dev_builds_dir)
11
+ @dev_storage = LocalVersionStorage.new(@dev_builds_dir)
12
+
11
13
  @final_index = VersionsIndex.new(@final_builds_dir)
14
+ @final_storage = LocalVersionStorage.new(@final_builds_dir)
15
+
16
+ @final_resolver = VersionFileResolver.new(@final_storage, @blobstore)
12
17
  end
13
18
 
14
19
  def final?
@@ -55,47 +60,22 @@ module Bosh::Cli
55
60
  end
56
61
 
57
62
  blobstore_id = item['blobstore_id']
58
- version = fingerprint
63
+ version = item['version'] || fingerprint
64
+ sha1 = item['sha1']
59
65
 
60
66
  if blobstore_id.nil?
61
67
  say('No blobstore id'.make_red)
62
68
  return nil
63
69
  end
64
70
 
65
- filename = @final_index.filename(version)
66
- need_fetch = true
67
-
68
- if File.exists?(filename)
69
- say('FOUND LOCAL'.make_green)
70
- if file_checksum(filename) == item['sha1']
71
- @tarball_path = filename
72
- need_fetch = false
73
- else
74
- say('LOCAL CHECKSUM MISMATCH'.make_red)
75
- need_fetch = true
76
- end
77
- end
71
+ desc = "#{name} (#{version})"
78
72
 
79
- if need_fetch
80
- say("Downloading `#{name} (#{version})'...".make_green)
81
- tmp_file = File.open(File.join(Dir.mktmpdir, name), 'w')
82
- @blobstore.get(blobstore_id, tmp_file)
83
- tmp_file.close
84
- if Digest::SHA1.file(tmp_file.path).hexdigest == item['sha1']
85
- @tarball_path = @final_index.add_version(fingerprint,
86
- item,
87
- tmp_file.path)
88
- else
89
- err("`#{name}' (#{version}) is corrupted in blobstore " +
90
- "(id=#{blobstore_id}), " +
91
- 'please remove it manually and re-generate the final release')
92
- end
93
- end
73
+ @tarball_path = @final_resolver.find_file(blobstore_id, sha1, version, "package #{desc}")
94
74
 
95
75
  @version = version
96
76
  @used_final_version = true
97
77
  true
98
- rescue Bosh::Blobstore::NotFound => e
78
+ rescue Bosh::Blobstore::NotFound
99
79
  raise BlobstoreError, "Final version of `#{name}' not found in blobstore"
100
80
  rescue Bosh::Blobstore::BlobstoreError => e
101
81
  raise BlobstoreError, "Blobstore error: #{e}"
@@ -110,24 +90,31 @@ module Bosh::Cli
110
90
  return nil
111
91
  end
112
92
 
113
- version = fingerprint
114
- filename = @dev_index.filename(version)
93
+ version = @dev_index['version'] || fingerprint
115
94
 
116
- if File.exists?(filename)
117
- say('FOUND LOCAL'.make_green)
118
- else
95
+ if !@dev_storage.has_file?(version)
119
96
  say('TARBALL MISSING'.make_red)
120
97
  return nil
121
98
  end
122
99
 
123
- if file_checksum(filename) == item['sha1']
124
- @tarball_path = filename
125
- @version = version
126
- @used_dev_version = true
127
- else
100
+ say('FOUND LOCAL'.make_green)
101
+ @tarball_path = @dev_storage.get_file(version)
102
+
103
+ if file_checksum(@tarball_path) != item['sha1']
128
104
  say("`#{name} (#{version})' tarball corrupted".make_red)
129
105
  return nil
130
106
  end
107
+
108
+ if final? && !dry_run?
109
+ # copy from dev index/storage to final index/storage
110
+ @final_index.add_version(fingerprint, item)
111
+ @tarball_path = @final_storage.put_file(version, @tarball_path)
112
+ item['sha1'] = Digest::SHA1.file(@tarball_path).hexdigest
113
+ @final_index.update_version(fingerprint, item)
114
+ end
115
+
116
+ @version = version
117
+ @used_dev_version = true
131
118
  end
132
119
 
133
120
  def generate_tarball
@@ -150,12 +137,18 @@ module Bosh::Cli
150
137
  }
151
138
 
152
139
  if final?
153
- @final_index.add_version(fingerprint, item, tmp_file.path)
154
- @tarball_path = @final_index.filename(version)
140
+ # add version (with its validation) before adding sha1
141
+ @final_index.add_version(fingerprint, item)
142
+ @tarball_path = @final_storage.put_file(fingerprint, tmp_file.path)
143
+ item['sha1'] = file_checksum(@tarball_path)
144
+ @final_index.update_version(fingerprint, item)
155
145
  elsif dry_run?
156
146
  else
157
- @dev_index.add_version(fingerprint, item, tmp_file.path)
158
- @tarball_path = @dev_index.filename(version)
147
+ # add version (with its validation) before adding sha1
148
+ @dev_index.add_version(fingerprint, item)
149
+ @tarball_path = @dev_storage.put_file(fingerprint, tmp_file.path)
150
+ item['sha1'] = file_checksum(@tarball_path)
151
+ @dev_index.update_version(fingerprint, item)
159
152
  end
160
153
 
161
154
  @version = version
@@ -167,29 +160,25 @@ module Bosh::Cli
167
160
  def upload_tarball(path)
168
161
  item = @final_index[fingerprint]
169
162
 
170
- say("Uploading final version #{version}...")
163
+ unless item
164
+ say("Failed to find entry `#{fingerprint}' in index, check local storage")
165
+ return
166
+ end
171
167
 
172
- if item
173
- say('This package has already been uploaded')
168
+ if item['blobstore_id']
174
169
  return
175
170
  end
176
171
 
177
- version = fingerprint
172
+ say("Uploading final version `#{version}'...")
178
173
 
179
174
  blobstore_id = nil
180
175
  File.open(path, 'r') do |f|
181
176
  blobstore_id = @blobstore.create(f)
182
177
  end
183
178
 
184
- item = {
185
- 'blobstore_id' => blobstore_id,
186
- 'version' => version
187
- }
188
-
189
- say("Uploaded, blobstore id #{blobstore_id}")
190
- @final_index.add_version(fingerprint, item, path)
191
- @tarball_path = @final_index.filename(version)
192
- @version = version
179
+ say("Uploaded, blobstore id `#{blobstore_id}'")
180
+ item['blobstore_id'] = blobstore_id
181
+ @final_index.update_version(fingerprint, item)
193
182
  @promoted = true
194
183
  true
195
184
  rescue Bosh::Blobstore::BlobstoreError => e
@@ -226,4 +215,3 @@ module Bosh::Cli
226
215
  end
227
216
  end
228
217
  end
229
-
@@ -21,11 +21,14 @@ module Bosh::Cli
21
21
 
22
22
  raise ReleaseVersionError.new('Version numbers cannot be specified for dev releases') if (@version && !@final)
23
23
 
24
- @final_index = VersionsIndex.new(final_releases_dir, release_name)
25
- @dev_index = VersionsIndex.new(dev_releases_dir, release_name)
24
+ @final_index = VersionsIndex.new(final_releases_dir)
25
+ @dev_index = VersionsIndex.new(dev_releases_dir)
26
26
  @index = @final ? @final_index : @dev_index
27
+ @release_storage = LocalVersionStorage.new(@index.storage_dir, release_name)
27
28
 
28
- raise ReleaseVersionError.new('Release version already exists') if (@version && @index.version_exists?(@version))
29
+ if @version && @release_storage.has_file?(@version)
30
+ raise ReleaseVersionError.new('Release version already exists')
31
+ end
29
32
 
30
33
  @build_dir = Dir.mktmpdir
31
34
 
@@ -136,19 +139,12 @@ module Bosh::Cli
136
139
  manifest["name"] = release_name
137
140
 
138
141
  unless manifest["name"].bosh_valid_id?
139
- raise InvalidRelease, "Release name `#{manifest["name"]}' " +
140
- "is not a valid BOSH identifier"
142
+ raise InvalidRelease, "Release name `#{manifest["name"]}' is not a valid BOSH identifier"
141
143
  end
142
144
 
143
- fingerprint = make_fingerprint(manifest)
144
-
145
- if @index[fingerprint]
146
- old_version = @index[fingerprint]["version"]
147
- say("This version is no different from version #{old_version}")
148
- @version = old_version
149
- else
150
- @index.add_version(fingerprint, { "version" => version })
151
- end
145
+ # New release versions are allowed to have the same fingerprint as old versions.
146
+ # For reverse compatibility, random uuids are stored instead.
147
+ @index.add_version(SecureRandom.uuid, { "version" => version })
152
148
 
153
149
  manifest["version"] = version
154
150
  manifest_yaml = Psych.dump(manifest)
@@ -167,7 +163,7 @@ module Bosh::Cli
167
163
 
168
164
  def generate_tarball
169
165
  generate_manifest unless @manifest_generated
170
- return if @index.version_exists?(version)
166
+ return if @release_storage.has_file?(@version)
171
167
 
172
168
  unless @jobs_copied
173
169
  header("Copying jobs...")
@@ -211,22 +207,10 @@ module Bosh::Cli
211
207
  File.join(releases_dir, "#{release_name}-#{version}.yml")
212
208
  end
213
209
 
214
- def make_fingerprint(item)
215
- case item
216
- when Array
217
- source = item.map { |e| make_fingerprint(e) }.sort.join("")
218
- when Hash
219
- source = item.keys.sort.map{ |k| make_fingerprint(item[k]) }.join("")
220
- else
221
- source = item.to_s
222
- end
223
- Digest::SHA1.hexdigest(source)
224
- end
225
-
226
210
  private
227
211
 
228
212
  def assign_version
229
- latest_final_version = Bosh::Common::Version::ReleaseVersion.parse_list(@final_index.versions).latest
213
+ latest_final_version = ReleaseVersionsIndex.new(@final_index).latest_version
230
214
  latest_final_version ||= Bosh::Common::Version::ReleaseVersion.parse('0')
231
215
 
232
216
  if @final
@@ -234,7 +218,7 @@ module Bosh::Cli
234
218
  latest_final_version.increment_release
235
219
  else
236
220
  # Increment or Reset the post-release segment
237
- dev_versions = Bosh::Common::Version::ReleaseVersion.parse_list(@dev_index.versions)
221
+ dev_versions = ReleaseVersionsIndex.new(@dev_index).versions
238
222
  latest_dev_version = dev_versions.latest_with_pre_release(latest_final_version)
239
223
 
240
224
  if latest_dev_version
@@ -45,9 +45,7 @@ module Bosh::Cli
45
45
  quit("You already have this version in `#{tarball_path.make_green}'")
46
46
  end
47
47
 
48
- FileUtils.cp(@manifest_file,
49
- File.join(@build_dir, "release.MF"),
50
- :preserve => true)
48
+ FileUtils.cp(@manifest_file, File.join(@build_dir, "release.MF"), :preserve => true)
51
49
 
52
50
  header("Copying packages")
53
51
  @packages.each do |package|
@@ -56,11 +54,8 @@ module Bosh::Cli
56
54
  say("SKIP".make_yellow)
57
55
  next
58
56
  end
59
- package_filename = find_package(package)
60
- if package_filename.nil?
61
- err("Cannot find package `#{package.name} (#{package.version})'")
62
- end
63
- FileUtils.cp(package_filename,
57
+ package_file_path = find_package(package)
58
+ FileUtils.cp(package_file_path,
64
59
  File.join(@packages_dir, "#{package.name}.tgz"),
65
60
  :preserve => true)
66
61
  end
@@ -72,11 +67,8 @@ module Bosh::Cli
72
67
  say("SKIP".make_yellow)
73
68
  next
74
69
  end
75
- job_filename = find_job(job)
76
- if job_filename.nil?
77
- err("Cannot find job `#{job.name} (#{job.version})")
78
- end
79
- FileUtils.cp(job_filename,
70
+ job_file_path = find_job(job)
71
+ FileUtils.cp(job_file_path,
80
72
  File.join(@jobs_dir, "#{job.name}.tgz"),
81
73
  :preserve => true)
82
74
  end
@@ -102,63 +94,49 @@ module Bosh::Cli
102
94
  end
103
95
 
104
96
  def find_package(package)
105
- final_index = VersionsIndex.new(
106
- File.join(@release_dir, ".final_builds", "packages", package.name))
107
- dev_index = VersionsIndex.new(
108
- File.join(@release_dir, ".dev_builds", "packages", package.name))
109
- find_in_indices(final_index, dev_index, package)
97
+ final_package_dir = File.join(@release_dir, ".final_builds", "packages", package.name)
98
+ final_index = VersionsIndex.new(final_package_dir)
99
+ dev_package_dir = File.join(@release_dir, ".dev_builds", "packages", package.name)
100
+ dev_index = VersionsIndex.new(dev_package_dir)
101
+ find_in_indices(final_index, dev_index, package, 'package')
110
102
  end
111
103
 
112
104
  def find_job(job)
113
- final_index = VersionsIndex.new(
114
- File.join(@release_dir, ".final_builds", "jobs", job.name))
115
- dev_index = VersionsIndex.new(
116
- File.join(@release_dir, ".dev_builds", "jobs", job.name))
117
- find_in_indices(final_index, dev_index, job)
105
+ final_jobs_dir = File.join(@release_dir, ".final_builds", "jobs", job.name)
106
+ final_index = VersionsIndex.new(final_jobs_dir)
107
+ dev_jobs_dir = File.join(@release_dir, ".dev_builds", "jobs", job.name)
108
+ dev_index = VersionsIndex.new(dev_jobs_dir)
109
+ find_in_indices(final_index, dev_index, job, 'job')
118
110
  end
119
111
 
120
- def find_in_indices(final_index, dev_index, object)
121
- desc = "#{object.name} (#{object.version})"
112
+ def find_version_by_sha1(index, sha1)
113
+ index.select{ |_, build| build['sha1'] == sha1 }.values.first
114
+ end
115
+
116
+ def find_in_indices(final_index, dev_index, build, build_type)
117
+ desc = "#{build.name} (#{build.version})"
122
118
 
123
119
  index = final_index
124
- build_data = index.find_by_checksum(object.sha1)
120
+ found_build = find_version_by_sha1(index, build.sha1)
125
121
 
126
- if build_data.nil?
122
+ if found_build.nil?
127
123
  index = dev_index
128
- build_data = index.find_by_checksum(object.sha1)
124
+ found_build = find_version_by_sha1(index, build.sha1)
129
125
  end
130
126
 
131
- if build_data.nil?
127
+ if found_build.nil?
132
128
  say("MISSING".make_red)
133
- err("Cannot find object with given checksum")
129
+ err("Cannot find #{build_type} with checksum `#{build.sha1}'")
134
130
  end
135
131
 
136
- version = build_data["version"]
137
- sha1 = build_data["sha1"]
138
- blobstore_id = build_data["blobstore_id"]
139
- filename = index.filename(version)
132
+ version = found_build["version"]
133
+ sha1 = found_build["sha1"]
134
+ blobstore_id = found_build["blobstore_id"]
140
135
 
141
- if File.exists?(filename)
142
- say("FOUND LOCAL".make_green)
143
- if Digest::SHA1.file(filename) != sha1
144
- err("#{desc} is corrupted locally")
145
- end
146
- elsif blobstore_id
147
- say("FOUND REMOTE".make_yellow)
148
- say("Downloading #{blobstore_id.to_s.make_green}...")
149
- tmp_file = Tempfile.new("")
150
- @blobstore.get(blobstore_id, tmp_file)
151
- tmp_file.close
152
-
153
- if Digest::SHA1.file(tmp_file.path).hexdigest == sha1
154
- FileUtils.mv(tmp_file.path, filename)
155
- else
156
- err("#{desc} is corrupted in blobstore (id=#{blobstore_id})")
157
- end
158
- end
159
-
160
- File.exists?(filename) ? filename : nil
136
+ storage = LocalVersionStorage.new(index.storage_dir)
161
137
 
138
+ resolver = VersionFileResolver.new(storage, @blobstore)
139
+ resolver.find_file(blobstore_id, sha1, version, "#{build_type} #{desc}")
162
140
  rescue Bosh::Blobstore::BlobstoreError => e
163
141
  raise BlobstoreError, "Blobstore error: #{e}"
164
142
  end
@@ -180,5 +158,4 @@ module Bosh::Cli
180
158
  false
181
159
  end
182
160
  end
183
-
184
161
  end
data/lib/cli/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Bosh
2
2
  module Cli
3
- VERSION = '1.2657.0'
3
+ VERSION = '1.2669.0'
4
4
  end
5
5
  end
@@ -0,0 +1,41 @@
1
+ module Bosh::Cli
2
+ class LocalVersionStorage
3
+
4
+ class Sha1MismatchError < StandardError; end
5
+
6
+ attr_reader :storage_dir
7
+
8
+ def initialize(storage_dir, name_prefix=nil)
9
+ @storage_dir = storage_dir
10
+ @name_prefix = name_prefix
11
+ end
12
+
13
+ def put_file(version, src_file_path)
14
+ destination = file_path(version)
15
+ unless File.exist?(src_file_path)
16
+ raise "Trying to store non-existant file `#{src_file_path}' for version `#{version}'"
17
+ end
18
+ FileUtils.cp(src_file_path, destination, :preserve => true)
19
+
20
+ File.expand_path(destination)
21
+ end
22
+
23
+ def get_file(version)
24
+ destination = file_path(version)
25
+ unless File.exist?(destination)
26
+ raise "Trying to retrieve non-existant file `#{destination}' for version `#{version}'"
27
+ end
28
+
29
+ File.expand_path(destination)
30
+ end
31
+
32
+ def has_file?(version)
33
+ File.exists?(file_path(version))
34
+ end
35
+
36
+ def file_path(version)
37
+ name = @name_prefix.blank? ? "#{version}.tgz" : "#{@name_prefix}-#{version}.tgz"
38
+ File.join(@storage_dir, name)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,18 @@
1
+ module Bosh::Cli
2
+ class ReleaseVersionsIndex
3
+
4
+ def initialize(versions_index)
5
+ @versions_index = versions_index
6
+ end
7
+
8
+ def latest_version
9
+ version_strings = @versions_index.version_strings
10
+ return nil if version_strings.empty?
11
+ Bosh::Common::Version::ReleaseVersionList.parse(version_strings).latest
12
+ end
13
+
14
+ def versions
15
+ Bosh::Common::Version::ReleaseVersionList.parse(@versions_index.version_strings)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,49 @@
1
+ module Bosh::Cli
2
+ class VersionFileResolver
3
+
4
+ def initialize(storage, blobstore, tmpdir=Dir.tmpdir)
5
+ @storage = storage
6
+ @blobstore = blobstore
7
+ @tmpdir = tmpdir
8
+ end
9
+
10
+ def find_file(blobstore_id, sha1, version, desc)
11
+ if @storage.has_file?(version)
12
+ say('FOUND LOCAL'.make_green)
13
+ file_path = @storage.get_file(version)
14
+ file_sha1 = Digest::SHA1.file(file_path).hexdigest
15
+ if file_sha1 == sha1
16
+ return file_path
17
+ end
18
+ say("SHA1 `#{file_sha1}' of #{desc} does not match expected SHA1 `#{sha1}'".make_red)
19
+ end
20
+
21
+ if blobstore_id.nil?
22
+ err("Cannot find #{desc}")
23
+ end
24
+
25
+ say('FOUND REMOTE'.make_yellow)
26
+ say("Downloading #{desc} from blobstore (id=#{blobstore_id})...".make_green)
27
+
28
+ tmp_file_path = File.join(@tmpdir, "bosh-tmp-file-#{SecureRandom.uuid}")
29
+ begin
30
+ File.open(tmp_file_path, 'w') do |tmp_file|
31
+ @blobstore.get(blobstore_id, tmp_file)
32
+ end
33
+
34
+ file_sha1 = Digest::SHA1.file(tmp_file_path).hexdigest
35
+ if file_sha1 != sha1
36
+ err("SHA1 `#{file_sha1}' of #{desc} from blobstore (id=#{blobstore_id}) " +
37
+ "does not match expected SHA1 `#{sha1}'" +
38
+ 'please remove it manually and re-create the release')
39
+ end
40
+
41
+ @storage.put_file(version, tmp_file_path)
42
+ ensure
43
+ FileUtils.rm(tmp_file_path, :force => true)
44
+ end
45
+ end
46
+
47
+
48
+ end
49
+ end
@@ -0,0 +1,119 @@
1
+ module Bosh::Cli
2
+ class VersionsIndex
3
+
4
+ attr_reader :index_file
5
+ attr_reader :storage_dir
6
+
7
+ def initialize(storage_dir)
8
+ @storage_dir = File.expand_path(storage_dir)
9
+ @index_file = File.join(@storage_dir, 'index.yml')
10
+
11
+ if File.file?(@index_file)
12
+ init_index(load_yaml_file(@index_file, nil))
13
+ else
14
+ init_index({})
15
+ end
16
+ end
17
+
18
+ def [](key)
19
+ @data['builds'][key]
20
+ end
21
+
22
+ def each_pair(&block)
23
+ @data['builds'].each_pair(&block)
24
+ end
25
+
26
+ def latest_version
27
+ builds = @data['builds'].values
28
+
29
+ return nil if builds.empty?
30
+
31
+ version_strings = builds.map { |b| b['version'] }
32
+ Bosh::Common::Version::ReleaseVersionList.parse(version_strings).latest.to_s
33
+ end
34
+
35
+ def select(&block)
36
+ @data['builds'].select(&block)
37
+ end
38
+
39
+ # both (tmp_file_path=nil only used by release)
40
+ def add_version(new_key, new_build)
41
+ version = new_build['version']
42
+
43
+ if version.blank?
44
+ raise InvalidIndex, "Cannot save index entry without a version: `#{new_build}'"
45
+ end
46
+
47
+ if @data['builds'][new_key]
48
+ raise "Trying to add duplicate entry `#{new_key}' into index `#{@index_file}'"
49
+ end
50
+
51
+ self.each_pair do |key, build|
52
+ if build['version'] == version && key != new_key
53
+ raise "Trying to add duplicate version `#{version}' into index `#{@index_file}'"
54
+ end
55
+ end
56
+
57
+ create_directories
58
+
59
+ @data['builds'][new_key] = new_build
60
+
61
+ File.open(@index_file, 'w') do |f|
62
+ f.write(Psych.dump(@data))
63
+ end
64
+
65
+ version
66
+ end
67
+
68
+ def update_version(key, new_build)
69
+ old_build = @data['builds'][key]
70
+ unless old_build
71
+ raise "Cannot update non-existent entry with key `#{key}'"
72
+ end
73
+
74
+ if new_build['version'] != old_build['version']
75
+ raise "Cannot update entry `#{old_build}' with a different version: `#{new_build}'"
76
+ end
77
+
78
+ @data['builds'][key] = new_build
79
+
80
+ File.open(@index_file, 'w') do |f|
81
+ f.write(Psych.dump(@data))
82
+ end
83
+ end
84
+
85
+ def version_strings
86
+ @data['builds'].map { |_, build| build['version'].to_s }
87
+ end
88
+
89
+ def to_s
90
+ @data['builds'].to_s
91
+ end
92
+
93
+ private
94
+
95
+ def create_directories
96
+ begin
97
+ FileUtils.mkdir_p(@storage_dir)
98
+ rescue SystemCallError => e
99
+ raise InvalidIndex, "Cannot create index storage directory: #{e}"
100
+ end
101
+
102
+ begin
103
+ FileUtils.touch(@index_file)
104
+ rescue SystemCallError => e
105
+ raise InvalidIndex, "Cannot create index file: #{e}"
106
+ end
107
+ end
108
+
109
+ def init_index(data)
110
+ data ||= {}
111
+
112
+ unless data.kind_of?(Hash)
113
+ raise InvalidIndex, "Invalid versions index data type, #{data.class} given, Hash expected"
114
+ end
115
+ @data = data
116
+ @data['builds'] ||= {}
117
+ end
118
+ end
119
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bosh_cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2657.0
4
+ version: 1.2669.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - VMware
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-24 00:00:00.000000000 Z
11
+ date: 2014-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bosh_common
@@ -16,14 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.2657.0
19
+ version: 1.2669.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.2657.0
26
+ version: 1.2669.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bosh-template
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.2669.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.2669.0
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: json_pure
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -72,14 +86,14 @@ dependencies:
72
86
  requirements:
73
87
  - - '='
74
88
  - !ruby/object:Gem::Version
75
- version: 2.2.4
89
+ version: 2.4.0
76
90
  type: :runtime
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - '='
81
95
  - !ruby/object:Gem::Version
82
- version: 2.2.4
96
+ version: 2.4.0
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: terminal-table
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +114,14 @@ dependencies:
100
114
  requirements:
101
115
  - - "~>"
102
116
  - !ruby/object:Gem::Version
103
- version: 1.2657.0
117
+ version: 1.2669.0
104
118
  type: :runtime
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
122
  - - "~>"
109
123
  - !ruby/object:Gem::Version
110
- version: 1.2657.0
124
+ version: 1.2669.0
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: net-ssh
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -180,7 +194,7 @@ dependencies:
180
194
  version: 0.5.4
181
195
  description: |-
182
196
  BOSH CLI
183
- a6c527
197
+ bf0b96
184
198
  email: support@cloudfoundry.com
185
199
  executables:
186
200
  - bosh
@@ -268,7 +282,10 @@ files:
268
282
  - lib/cli/task_tracking/total_duration.rb
269
283
  - lib/cli/validation.rb
270
284
  - lib/cli/version.rb
271
- - lib/cli/versions_index.rb
285
+ - lib/cli/versions/local_version_storage.rb
286
+ - lib/cli/versions/release_versions_index.rb
287
+ - lib/cli/versions/version_file_resolver.rb
288
+ - lib/cli/versions/versions_index.rb
272
289
  - lib/cli/vm_state.rb
273
290
  - lib/cli/yaml_helper.rb
274
291
  homepage: https://github.com/cloudfoundry/bosh
@@ -1,111 +0,0 @@
1
- module Bosh::Cli
2
- class VersionsIndex
3
-
4
- def initialize(storage_dir, name_prefix = nil)
5
- @storage_dir = File.expand_path(storage_dir)
6
- @index_file = File.join(@storage_dir, "index.yml")
7
- @name_prefix = name_prefix
8
-
9
- if File.file?(@index_file)
10
- init_index(load_yaml_file(@index_file, nil))
11
- else
12
- init_index({})
13
- end
14
- end
15
-
16
- def find_by_checksum(checksum)
17
- @data["builds"].each_pair do |fingerprint, build_data|
18
- return build_data if build_data["sha1"] == checksum
19
- end
20
- nil
21
- end
22
-
23
- def [](fingerprint)
24
- @data["builds"][fingerprint]
25
- end
26
-
27
- def latest_version
28
- builds = @data["builds"].values
29
-
30
- return nil if builds.empty?
31
-
32
- version_strings = builds.map { |b| b["version"] }
33
- Bosh::Common::Version::ReleaseVersion.parse_list(version_strings).latest.to_s
34
- end
35
-
36
- def version_exists?(version)
37
- File.exists?(filename(version))
38
- end
39
-
40
- def add_version(fingerprint, item, tmp_file_path = nil)
41
- version = item["version"]
42
-
43
- if version.blank?
44
- raise InvalidIndex,
45
- "Cannot save index entry without knowing its version"
46
- end
47
-
48
- create_directories
49
-
50
- if tmp_file_path
51
- FileUtils.cp(tmp_file_path, filename(version), :preserve => true)
52
- end
53
-
54
- @data["builds"].each_pair do |fp, build|
55
- if build["version"] == version && fp != fingerprint
56
- raise "Trying to add duplicate version `#{version}' " +
57
- "into index `#{@index_file}'"
58
- end
59
- end
60
-
61
- @data["builds"][fingerprint] = item
62
- if tmp_file_path
63
- file_sha1 = Digest::SHA1.file(tmp_file_path).hexdigest
64
- @data["builds"][fingerprint]["sha1"] = file_sha1
65
- end
66
-
67
- File.open(@index_file, "w") do |f|
68
- f.write(Psych.dump(@data))
69
- end
70
-
71
- File.expand_path(filename(version))
72
- end
73
-
74
- def filename(version)
75
- name = @name_prefix.blank? ?
76
- "#{version}.tgz" : "#{@name_prefix}-#{version}.tgz"
77
- File.join(@storage_dir, name)
78
- end
79
-
80
- def versions
81
- @data['builds'].map { |_, build| build['version'] }
82
- end
83
-
84
- private
85
-
86
- def create_directories
87
- begin
88
- FileUtils.mkdir_p(@storage_dir)
89
- rescue SystemCallError => e
90
- raise InvalidIndex, "Cannot create index storage directory: #{e}"
91
- end
92
-
93
- begin
94
- FileUtils.touch(@index_file)
95
- rescue SystemCallError => e
96
- raise InvalidIndex, "Cannot create index file: #{e}"
97
- end
98
- end
99
-
100
- def init_index(data)
101
- data ||= {}
102
-
103
- unless data.kind_of?(Hash)
104
- raise InvalidIndex, "Invalid versions index data type, " +
105
- "#{data.class} given, Hash expected"
106
- end
107
- @data = data
108
- @data["builds"] ||= {}
109
- end
110
- end
111
- end