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 +4 -4
- data/lib/cli.rb +8 -2
- data/lib/cli/commands/misc.rb +0 -20
- data/lib/cli/deployment_helper.rb +1 -1
- data/lib/cli/job_property_collection.rb +2 -1
- data/lib/cli/job_property_validator.rb +2 -1
- data/lib/cli/packaging_helper.rb +46 -58
- data/lib/cli/release_builder.rb +13 -29
- data/lib/cli/release_compiler.rb +32 -55
- data/lib/cli/version.rb +1 -1
- data/lib/cli/versions/local_version_storage.rb +41 -0
- data/lib/cli/versions/release_versions_index.rb +18 -0
- data/lib/cli/versions/version_file_resolver.rb +49 -0
- data/lib/cli/versions/versions_index.rb +119 -0
- metadata +27 -10
- data/lib/cli/versions_index.rb +0 -111
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 206c482ff9d75e5f49d6bc0950f76bbac870e316
|
4
|
+
data.tar.gz: 06edf9a6c160e702431e5efed54cb8bbc16ed4da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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/
|
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'
|
data/lib/cli/commands/misc.rb
CHANGED
@@ -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::
|
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::
|
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::
|
112
|
+
context = Bosh::Template::EvaluationContext.new(spec)
|
112
113
|
begin
|
113
114
|
erb.result(context.get_binding)
|
114
115
|
rescue Exception => e
|
data/lib/cli/packaging_helper.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
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
|
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
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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
|
-
|
154
|
-
@
|
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
|
-
|
158
|
-
@
|
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
|
-
|
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
|
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
|
-
|
185
|
-
|
186
|
-
|
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
|
-
|
data/lib/cli/release_builder.rb
CHANGED
@@ -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
|
25
|
-
@dev_index = VersionsIndex.new(dev_releases_dir
|
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
|
-
|
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
|
144
|
-
|
145
|
-
|
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 @
|
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 =
|
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 =
|
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
|
data/lib/cli/release_compiler.rb
CHANGED
@@ -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
|
-
|
60
|
-
|
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
|
-
|
76
|
-
|
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
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
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
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
121
|
-
|
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
|
-
|
120
|
+
found_build = find_version_by_sha1(index, build.sha1)
|
125
121
|
|
126
|
-
if
|
122
|
+
if found_build.nil?
|
127
123
|
index = dev_index
|
128
|
-
|
124
|
+
found_build = find_version_by_sha1(index, build.sha1)
|
129
125
|
end
|
130
126
|
|
131
|
-
if
|
127
|
+
if found_build.nil?
|
132
128
|
say("MISSING".make_red)
|
133
|
-
err("Cannot find
|
129
|
+
err("Cannot find #{build_type} with checksum `#{build.sha1}'")
|
134
130
|
end
|
135
131
|
|
136
|
-
version =
|
137
|
-
sha1 =
|
138
|
-
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
|
-
|
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
@@ -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.
|
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-
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|
-
|
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/
|
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
|
data/lib/cli/versions_index.rb
DELETED
@@ -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
|