bosh_cli 1.2657.0 → 1.2669.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|