bosh_cli 1.5.0.pre.1332 → 1.5.0.pre.1333
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/cli/commands/stemcell.rb +57 -59
- data/lib/cli/download_with_progress.rb +36 -0
- data/lib/cli/public_stemcell.rb +34 -0
- data/lib/cli/public_stemcell_index.rb +41 -0
- data/lib/cli/public_stemcell_presenter.rb +49 -0
- data/lib/cli/version.rb +1 -1
- metadata +10 -6
@@ -1,121 +1,119 @@
|
|
1
|
-
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
-
|
3
1
|
module Bosh::Cli::Command
|
4
2
|
class Stemcell < Base
|
5
3
|
include Bosh::Cli::VersionCalc
|
6
4
|
|
7
5
|
# The filename of the public stemcell index.
|
8
|
-
PUBLIC_STEMCELL_INDEX =
|
6
|
+
PUBLIC_STEMCELL_INDEX = 'public_stemcells_index.yml'
|
9
7
|
|
10
8
|
# The URL of the public stemcell index.
|
11
9
|
PUBLIC_STEMCELL_INDEX_URL =
|
12
|
-
|
10
|
+
'https://s3.amazonaws.com/blob.cfblob.com/stemcells/public_stemcells_index.yml'
|
13
11
|
|
14
|
-
DEFAULT_PUB_STEMCELL_TAG =
|
15
|
-
ALL_STEMCELLS_TAG =
|
12
|
+
DEFAULT_PUB_STEMCELL_TAG = 'stable'
|
13
|
+
ALL_STEMCELLS_TAG = 'all'
|
16
14
|
|
17
|
-
usage
|
18
|
-
desc
|
15
|
+
usage 'verify stemcell'
|
16
|
+
desc 'Verify stemcell'
|
19
17
|
def verify(tarball_path)
|
20
18
|
stemcell = Bosh::Cli::Stemcell.new(tarball_path)
|
21
19
|
|
22
20
|
nl
|
23
|
-
say(
|
21
|
+
say('Verifying stemcell...')
|
24
22
|
stemcell.validate
|
25
23
|
nl
|
26
24
|
|
27
25
|
if stemcell.valid?
|
28
26
|
say("`#{tarball_path}' is a valid stemcell".make_green)
|
29
27
|
else
|
30
|
-
say(
|
28
|
+
say('Validation errors:'.make_red)
|
31
29
|
stemcell.errors.each do |error|
|
32
|
-
say(
|
30
|
+
say('- %s' % [error])
|
33
31
|
end
|
34
32
|
err("`#{tarball_path}' is not a valid stemcell")
|
35
33
|
end
|
36
34
|
end
|
37
35
|
|
38
36
|
# bosh upload stemcell
|
39
|
-
usage
|
40
|
-
desc
|
37
|
+
usage 'upload stemcell'
|
38
|
+
desc 'Upload stemcell (stemcell_location can be a local file or a remote URI)'
|
41
39
|
def upload(stemcell_location)
|
42
40
|
auth_required
|
43
41
|
|
44
|
-
stemcell_type = stemcell_location =~ /^#{URI::regexp}$/ ?
|
45
|
-
if stemcell_type ==
|
42
|
+
stemcell_type = stemcell_location =~ /^#{URI::regexp}$/ ? 'remote' : 'local'
|
43
|
+
if stemcell_type == 'local'
|
46
44
|
stemcell = Bosh::Cli::Stemcell.new(stemcell_location)
|
47
45
|
|
48
46
|
nl
|
49
|
-
say(
|
47
|
+
say('Verifying stemcell...')
|
50
48
|
stemcell.validate
|
51
49
|
nl
|
52
50
|
|
53
51
|
unless stemcell.valid?
|
54
|
-
err(
|
52
|
+
err('Stemcell is invalid, please fix, verify and upload again')
|
55
53
|
end
|
56
|
-
|
57
|
-
say(
|
58
|
-
name = stemcell.manifest[
|
59
|
-
version = stemcell.manifest[
|
54
|
+
|
55
|
+
say('Checking if stemcell already exists...')
|
56
|
+
name = stemcell.manifest['name']
|
57
|
+
version = stemcell.manifest['version']
|
60
58
|
|
61
59
|
if exists?(name, version)
|
62
60
|
err("Stemcell `#{name}/#{version}' already exists, " +
|
63
|
-
|
61
|
+
'increment the version if it has changed')
|
64
62
|
else
|
65
|
-
say(
|
63
|
+
say('No')
|
66
64
|
end
|
67
65
|
|
68
66
|
stemcell_location = stemcell.stemcell_file
|
69
67
|
|
70
68
|
nl
|
71
|
-
say(
|
69
|
+
say('Uploading stemcell...')
|
72
70
|
nl
|
73
71
|
else
|
74
72
|
nl
|
75
73
|
say("Using remote stemcell `#{stemcell_location}'")
|
76
74
|
end
|
77
75
|
|
78
|
-
if stemcell_type ==
|
76
|
+
if stemcell_type == 'local'
|
79
77
|
status, task_id = director.upload_stemcell(stemcell_location)
|
80
78
|
else
|
81
79
|
status, task_id = director.upload_remote_stemcell(stemcell_location)
|
82
80
|
end
|
83
81
|
|
84
|
-
task_report(status, task_id,
|
82
|
+
task_report(status, task_id, 'Stemcell uploaded and created')
|
85
83
|
end
|
86
84
|
|
87
85
|
# bosh stemcells
|
88
|
-
usage
|
89
|
-
desc
|
86
|
+
usage 'stemcells'
|
87
|
+
desc 'Show the list of available stemcells'
|
90
88
|
def list
|
91
89
|
auth_required
|
92
90
|
stemcells = director.list_stemcells.sort do |sc1, sc2|
|
93
|
-
sc1[
|
94
|
-
version_cmp(sc1[
|
95
|
-
sc1[
|
91
|
+
sc1['name'] == sc2['name'] ?
|
92
|
+
version_cmp(sc1['version'], sc2['version']) :
|
93
|
+
sc1['name'] <=> sc2['name']
|
96
94
|
end
|
97
95
|
|
98
|
-
err(
|
96
|
+
err('No stemcells') if stemcells.empty?
|
99
97
|
|
100
98
|
stemcells_table = table do |t|
|
101
|
-
t.headings =
|
99
|
+
t.headings = 'Name', 'Version', 'CID'
|
102
100
|
stemcells.each do |sc|
|
103
|
-
t << [sc[
|
101
|
+
t << [sc['name'], sc['version'], sc['cid']]
|
104
102
|
end
|
105
103
|
end
|
106
104
|
|
107
105
|
nl
|
108
106
|
say(stemcells_table)
|
109
107
|
nl
|
110
|
-
say(
|
108
|
+
say('Stemcells total: %d' % stemcells.size)
|
111
109
|
end
|
112
110
|
|
113
111
|
# Prints out the publicly available stemcells.
|
114
|
-
usage
|
115
|
-
desc
|
116
|
-
option
|
117
|
-
option
|
118
|
-
option
|
112
|
+
usage 'public stemcells'
|
113
|
+
desc 'Show the list of publicly available stemcells for download.'
|
114
|
+
option '--full', 'show the full download url'
|
115
|
+
option '--tags tag1,tag2...', Array, 'filter by tag'
|
116
|
+
option '--all', 'show all stemcells'
|
119
117
|
def list_public
|
120
118
|
full = !!options[:full]
|
121
119
|
tags = options[:tags] || [DEFAULT_PUB_STEMCELL_TAG]
|
@@ -123,14 +121,14 @@ module Bosh::Cli::Command
|
|
123
121
|
|
124
122
|
yaml = get_public_stemcell_list
|
125
123
|
stemcells_table = table do |t|
|
126
|
-
t.headings = full ? [
|
124
|
+
t.headings = full ? ['Name', 'Url', 'Tags'] : ['Name', 'Tags']
|
127
125
|
yaml.keys.sort.each do |key|
|
128
126
|
if key != PUBLIC_STEMCELL_INDEX
|
129
|
-
url = yaml[key][
|
130
|
-
yaml_tags = yaml[key][
|
127
|
+
url = yaml[key]['url']
|
128
|
+
yaml_tags = yaml[key]['tags']
|
131
129
|
next if skip_this_tag?(yaml_tags, tags)
|
132
130
|
|
133
|
-
yaml_tags = yaml_tags ? yaml_tags.join(
|
131
|
+
yaml_tags = yaml_tags ? yaml_tags.join(', ') : ''
|
134
132
|
t << (full ? [key, url, yaml_tags] : [key, yaml_tags])
|
135
133
|
end
|
136
134
|
end
|
@@ -139,12 +137,12 @@ module Bosh::Cli::Command
|
|
139
137
|
say(stemcells_table)
|
140
138
|
|
141
139
|
say("To download use `bosh download public stemcell <stemcell_name>'. " +
|
142
|
-
|
140
|
+
'For full url use --full.')
|
143
141
|
end
|
144
142
|
|
145
143
|
# Downloads one of the publicly available stemcells.
|
146
|
-
usage
|
147
|
-
desc
|
144
|
+
usage 'download public stemcell'
|
145
|
+
desc 'Downloads a stemcell from the public blobstore'
|
148
146
|
# @param [String] stemcell_name The name of the stemcell, as seen in the
|
149
147
|
# public stemcell index file.
|
150
148
|
def download_public(stemcell_name)
|
@@ -152,7 +150,7 @@ module Bosh::Cli::Command
|
|
152
150
|
yaml.delete(PUBLIC_STEMCELL_INDEX) if yaml.has_key?(PUBLIC_STEMCELL_INDEX)
|
153
151
|
|
154
152
|
unless yaml.has_key?(stemcell_name)
|
155
|
-
available_stemcells = yaml.map { |k| k }.join(
|
153
|
+
available_stemcells = yaml.map { |k| k }.join(', ')
|
156
154
|
err("'#{stemcell_name}' not found in '#{available_stemcells}'.")
|
157
155
|
end
|
158
156
|
|
@@ -161,13 +159,13 @@ module Bosh::Cli::Command
|
|
161
159
|
err("File `#{stemcell_name}' already exists")
|
162
160
|
end
|
163
161
|
|
164
|
-
url = yaml[stemcell_name][
|
165
|
-
size = yaml[stemcell_name][
|
166
|
-
sha1 = yaml[stemcell_name][
|
162
|
+
url = yaml[stemcell_name]['url']
|
163
|
+
size = yaml[stemcell_name]['size']
|
164
|
+
sha1 = yaml[stemcell_name]['sha']
|
167
165
|
progress_bar = ProgressBar.new(stemcell_name, size)
|
168
166
|
progress_bar.file_transfer_mode
|
169
167
|
|
170
|
-
File.open("#{stemcell_name}",
|
168
|
+
File.open("#{stemcell_name}", 'w') do |file|
|
171
169
|
@http_client.get(url) do |chunk|
|
172
170
|
file.write(chunk)
|
173
171
|
progress_bar.inc(chunk.size)
|
@@ -180,19 +178,19 @@ module Bosh::Cli::Command
|
|
180
178
|
err("The downloaded file sha1 `#{file_sha1}' does not match the " +
|
181
179
|
"expected sha1 `#{sha1}'")
|
182
180
|
else
|
183
|
-
say(
|
181
|
+
say('Download complete'.make_green)
|
184
182
|
end
|
185
183
|
end
|
186
184
|
|
187
185
|
# bosh delete stemcell
|
188
|
-
usage
|
189
|
-
desc
|
190
|
-
option
|
186
|
+
usage 'delete stemcell'
|
187
|
+
desc 'Delete stemcell'
|
188
|
+
option '--force', 'ignore errors while deleting the stemcell'
|
191
189
|
def delete(name, version)
|
192
190
|
auth_required
|
193
191
|
force = !!options[:force]
|
194
192
|
|
195
|
-
say(
|
193
|
+
say('Checking if stemcell exists...')
|
196
194
|
|
197
195
|
unless exists?(name, version)
|
198
196
|
err("Stemcell `#{name}/#{version}' does not exist")
|
@@ -201,7 +199,7 @@ module Bosh::Cli::Command
|
|
201
199
|
say("You are going to delete stemcell `#{name}/#{version}'".make_red)
|
202
200
|
|
203
201
|
unless confirmed?
|
204
|
-
say(
|
202
|
+
say('Canceled deleting stemcell'.make_green)
|
205
203
|
return
|
206
204
|
end
|
207
205
|
|
@@ -229,7 +227,7 @@ module Bosh::Cli::Command
|
|
229
227
|
|
230
228
|
def exists?(name, version)
|
231
229
|
existing = director.list_stemcells.select do |sc|
|
232
|
-
sc[
|
230
|
+
sc['name'] == name && sc['version'] == version
|
233
231
|
end
|
234
232
|
|
235
233
|
!existing.empty?
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Bosh::Cli
|
2
|
+
class DownloadWithProgress
|
3
|
+
def initialize(url, size)
|
4
|
+
@url = url
|
5
|
+
@size = size
|
6
|
+
@filename = File.basename(@url)
|
7
|
+
end
|
8
|
+
|
9
|
+
def perform
|
10
|
+
progress_bar = ProgressBar.new(@filename, @size)
|
11
|
+
progress_bar.file_transfer_mode
|
12
|
+
download_in_chunks { |chunk| progress_bar.inc(chunk.size) }
|
13
|
+
progress_bar.finish
|
14
|
+
end
|
15
|
+
|
16
|
+
def sha1?(sha1)
|
17
|
+
self.sha1 == sha1
|
18
|
+
end
|
19
|
+
|
20
|
+
def sha1
|
21
|
+
Digest::SHA1.file(@filename).hexdigest
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def download_in_chunks
|
27
|
+
File.open(@filename, 'w') do |file|
|
28
|
+
http_client = HTTPClient.new
|
29
|
+
http_client.get(@url) do |chunk|
|
30
|
+
file.write(chunk)
|
31
|
+
yield chunk
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Bosh::Cli
|
2
|
+
class PublicStemcell
|
3
|
+
attr_reader :name
|
4
|
+
|
5
|
+
def initialize(name, properties)
|
6
|
+
@name = name
|
7
|
+
@properties = properties
|
8
|
+
end
|
9
|
+
|
10
|
+
def url
|
11
|
+
@properties['url']
|
12
|
+
end
|
13
|
+
|
14
|
+
def size
|
15
|
+
@properties['size']
|
16
|
+
end
|
17
|
+
|
18
|
+
def sha1
|
19
|
+
@properties['sha1']
|
20
|
+
end
|
21
|
+
|
22
|
+
def tags
|
23
|
+
@properties['tags']
|
24
|
+
end
|
25
|
+
|
26
|
+
def tag_names
|
27
|
+
tags ? tags.join(', ') : ''
|
28
|
+
end
|
29
|
+
|
30
|
+
def tagged?(requested_tags)
|
31
|
+
tags.nil? || (requested_tags - tags).empty?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'cli/public_stemcell'
|
2
|
+
|
3
|
+
module Bosh::Cli
|
4
|
+
class PublicStemcellIndex
|
5
|
+
def self.download(ui)
|
6
|
+
index_url = 'https://s3.amazonaws.com/blob.cfblob.com/stemcells/public_stemcells_index.yml'
|
7
|
+
|
8
|
+
http_client = HTTPClient.new
|
9
|
+
response = http_client.get(index_url)
|
10
|
+
status_code = response.http_header.status_code
|
11
|
+
|
12
|
+
if status_code == HTTP::Status::OK
|
13
|
+
index = Psych.load(response.body)
|
14
|
+
index.delete('public_stemcells_index.yml') if index.has_key?('public_stemcells_index.yml')
|
15
|
+
new(index)
|
16
|
+
else
|
17
|
+
ui.err("Received HTTP #{status_code} from #{index_url}.")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(index)
|
22
|
+
@index = index
|
23
|
+
end
|
24
|
+
|
25
|
+
def has_stemcell?(stemcell_name)
|
26
|
+
@index.has_key?(stemcell_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def names
|
30
|
+
@index.keys.sort
|
31
|
+
end
|
32
|
+
|
33
|
+
def find(stemcell_name)
|
34
|
+
PublicStemcell.new(stemcell_name, @index[stemcell_name])
|
35
|
+
end
|
36
|
+
|
37
|
+
def each
|
38
|
+
names.map { |stemcell_name| yield find(stemcell_name) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'cli/public_stemcell_index'
|
2
|
+
require 'cli/download_with_progress'
|
3
|
+
|
4
|
+
module Bosh::Cli
|
5
|
+
class PublicStemcellPresenter
|
6
|
+
def initialize(ui)
|
7
|
+
@ui = ui
|
8
|
+
@public_stemcell_index = PublicStemcellIndex.download(@ui)
|
9
|
+
end
|
10
|
+
|
11
|
+
def list(options)
|
12
|
+
full = !!options[:full]
|
13
|
+
requested_tags = options[:tags] || %w(stable)
|
14
|
+
|
15
|
+
stemcells_table = @ui.table do |t|
|
16
|
+
t.headings = full ? %w(Name Url Tags) : %w(Name Tags)
|
17
|
+
|
18
|
+
@public_stemcell_index.each do |stemcell|
|
19
|
+
if options[:all] || stemcell.tagged?(requested_tags)
|
20
|
+
t << (full ? [stemcell.name, stemcell.url, stemcell.tag_names] : [stemcell.name, stemcell.tag_names])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
@ui.say(stemcells_table.render)
|
26
|
+
@ui.say("To download use `bosh download public stemcell <stemcell_name>'. For full url use --full.")
|
27
|
+
end
|
28
|
+
|
29
|
+
def download(stemcell_name)
|
30
|
+
unless @public_stemcell_index.has_stemcell?(stemcell_name)
|
31
|
+
@ui.err("'#{stemcell_name}' not found in '#{@public_stemcell_index.names.join(',')}'.")
|
32
|
+
end
|
33
|
+
|
34
|
+
if File.exists?(stemcell_name) && !@ui.confirmed?("Overwrite existing file `#{stemcell_name}'?")
|
35
|
+
@ui.err("File `#{stemcell_name}' already exists")
|
36
|
+
end
|
37
|
+
|
38
|
+
stemcell = @public_stemcell_index.find(stemcell_name)
|
39
|
+
download_with_progress = DownloadWithProgress.new(stemcell.size, stemcell.url)
|
40
|
+
download_with_progress.perform
|
41
|
+
|
42
|
+
if download_with_progress.sha1?(stemcell.sha1)
|
43
|
+
@ui.say('Download complete'.make_green)
|
44
|
+
else
|
45
|
+
@ui.err("The downloaded file sha1 `#{download_with_progress.sha1}' does not match the expected sha1 `#{stemcell.sha1}'")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/cli/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bosh_cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.0.pre.
|
4
|
+
version: 1.5.0.pre.1333
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 1.5.0.pre.
|
21
|
+
version: 1.5.0.pre.1333
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 1.5.0.pre.
|
29
|
+
version: 1.5.0.pre.1333
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: json_pure
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,7 +114,7 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - ~>
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 1.5.0.pre.
|
117
|
+
version: 1.5.0.pre.1333
|
118
118
|
type: :runtime
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -122,7 +122,7 @@ dependencies:
|
|
122
122
|
requirements:
|
123
123
|
- - ~>
|
124
124
|
- !ruby/object:Gem::Version
|
125
|
-
version: 1.5.0.pre.
|
125
|
+
version: 1.5.0.pre.1333
|
126
126
|
- !ruby/object:Gem::Dependency
|
127
127
|
name: net-ssh
|
128
128
|
requirement: !ruby/object:Gem::Requirement
|
@@ -221,7 +221,7 @@ dependencies:
|
|
221
221
|
version: '0'
|
222
222
|
description: ! 'BOSH CLI
|
223
223
|
|
224
|
-
|
224
|
+
063aca'
|
225
225
|
email: support@cloudfoundry.com
|
226
226
|
executables:
|
227
227
|
- bosh
|
@@ -270,6 +270,7 @@ files:
|
|
270
270
|
- lib/cli/deployment_manifest.rb
|
271
271
|
- lib/cli/deployment_manifest_compiler.rb
|
272
272
|
- lib/cli/director_task.rb
|
273
|
+
- lib/cli/download_with_progress.rb
|
273
274
|
- lib/cli/errors.rb
|
274
275
|
- lib/cli/event_log_renderer.rb
|
275
276
|
- lib/cli/file_with_progress_bar.rb
|
@@ -283,6 +284,9 @@ files:
|
|
283
284
|
- lib/cli/null_renderer.rb
|
284
285
|
- lib/cli/package_builder.rb
|
285
286
|
- lib/cli/packaging_helper.rb
|
287
|
+
- lib/cli/public_stemcell.rb
|
288
|
+
- lib/cli/public_stemcell_index.rb
|
289
|
+
- lib/cli/public_stemcell_presenter.rb
|
286
290
|
- lib/cli/release.rb
|
287
291
|
- lib/cli/release_builder.rb
|
288
292
|
- lib/cli/release_compiler.rb
|