bosh_cli 1.3160.0 → 1.3163.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/base_command.rb +1 -1
- data/lib/cli/client/director.rb +38 -14
- data/lib/cli/commands/deployment.rb +57 -57
- data/lib/cli/commands/disks.rb +63 -0
- data/lib/cli/commands/instances.rb +99 -49
- data/lib/cli/commands/job_management.rb +11 -11
- data/lib/cli/commands/log_management.rb +9 -11
- data/lib/cli/commands/maintenance.rb +16 -40
- data/lib/cli/commands/snapshot.rb +14 -5
- data/lib/cli/commands/ssh.rb +12 -12
- data/lib/cli/commands/vm.rb +5 -5
- data/lib/cli/commands/vms.rb +36 -9
- data/lib/cli/core_ext.rb +1 -1
- data/lib/cli/deployment_helper.rb +11 -5
- data/lib/cli/job_command_args.rb +8 -12
- data/lib/cli/job_state.rb +8 -8
- data/lib/cli/logs_downloader.rb +2 -2
- data/lib/cli/resources/job.rb +2 -2
- data/lib/cli/version.rb +1 -1
- metadata +9 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9bcf51bb65be3f043bb997bca2e36565fc389ef1
|
4
|
+
data.tar.gz: 5f9c4117351b0bc8776a37afe92609ed3af980c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 20f34ebd95c481e8f9721da66a745fa199fd4465c68e66db9a5b80b756c1d93941191fbdf8f3395ea7bf4e3ac9323a4b3ef417fd6a9fd11600a424a8b0894347
|
7
|
+
data.tar.gz: ffc3ab67f387aa7f7a752d821f18e3c4f468ffd7c2123d11ac8d021e6929700bd65b8d9dd81b0282c7aa866d1b3cdc3d935b3b2043d72483ed43a0d23070bf60
|
data/lib/cli/base_command.rb
CHANGED
data/lib/cli/client/director.rb
CHANGED
@@ -180,6 +180,15 @@ module Bosh
|
|
180
180
|
body
|
181
181
|
end
|
182
182
|
|
183
|
+
def delete_orphan_disk_by_disk_cid(orphan_disk_cid)
|
184
|
+
request_and_track(:delete, "/disks/#{orphan_disk_cid}")
|
185
|
+
end
|
186
|
+
|
187
|
+
def list_orphan_disks
|
188
|
+
_, body = get_json_with_status('/disks')
|
189
|
+
body
|
190
|
+
end
|
191
|
+
|
183
192
|
def upload_release(filename, options = {})
|
184
193
|
options = options.dup
|
185
194
|
options[:content_type] = 'application/x-compressed'
|
@@ -251,7 +260,7 @@ module Bosh
|
|
251
260
|
request_and_track(:post, add_query_string(url, extras), options)
|
252
261
|
end
|
253
262
|
|
254
|
-
def setup_ssh(deployment_name, job,
|
263
|
+
def setup_ssh(deployment_name, job, id, user,
|
255
264
|
public_key, password, options = {})
|
256
265
|
options = options.dup
|
257
266
|
|
@@ -262,7 +271,8 @@ module Bosh
|
|
262
271
|
'deployment_name' => deployment_name,
|
263
272
|
'target' => {
|
264
273
|
'job' => job,
|
265
|
-
'indexes' => [
|
274
|
+
'indexes' => [id].compact, # for backwards compatibility with old director
|
275
|
+
'ids' => [id].compact,
|
266
276
|
},
|
267
277
|
'params' => {
|
268
278
|
'user' => user,
|
@@ -277,7 +287,7 @@ module Bosh
|
|
277
287
|
request_and_track(:post, url, options)
|
278
288
|
end
|
279
289
|
|
280
|
-
def cleanup_ssh(deployment_name, job, user_regex,
|
290
|
+
def cleanup_ssh(deployment_name, job, user_regex, id, options = {})
|
281
291
|
options = options.dup
|
282
292
|
|
283
293
|
url = "/deployments/#{deployment_name}/ssh"
|
@@ -287,7 +297,8 @@ module Bosh
|
|
287
297
|
'deployment_name' => deployment_name,
|
288
298
|
'target' => {
|
289
299
|
'job' => job,
|
290
|
-
'indexes' => (
|
300
|
+
'indexes' => (id || []).compact,
|
301
|
+
'ids' => (id || []).compact,
|
291
302
|
},
|
292
303
|
'params' => { 'user_regex' => user_regex }
|
293
304
|
}
|
@@ -300,13 +311,13 @@ module Bosh
|
|
300
311
|
end
|
301
312
|
|
302
313
|
def change_job_state(deployment_name, manifest_yaml,
|
303
|
-
job,
|
314
|
+
job, index_or_id, new_state, options = {})
|
304
315
|
options = options.dup
|
305
316
|
|
306
317
|
skip_drain = !!options.delete(:skip_drain)
|
307
318
|
|
308
319
|
url = "/deployments/#{deployment_name}/jobs/#{job}"
|
309
|
-
url += "/#{
|
320
|
+
url += "/#{index_or_id}" if index_or_id
|
310
321
|
url += "?state=#{new_state}"
|
311
322
|
url += "&skip_drain=true" if skip_drain
|
312
323
|
|
@@ -357,22 +368,28 @@ module Bosh
|
|
357
368
|
get_task_result(task_id)
|
358
369
|
end
|
359
370
|
|
360
|
-
def fetch_vm_state(deployment_name, options = {})
|
371
|
+
def fetch_vm_state(deployment_name, options = {}, full = true)
|
361
372
|
options = options.dup
|
362
373
|
|
363
|
-
url = "/deployments/#{deployment_name}/vms
|
374
|
+
url = "/deployments/#{deployment_name}/vms"
|
364
375
|
|
365
|
-
|
376
|
+
if full
|
377
|
+
status, task_id = request_and_track(:get, "#{url}?format=full", options)
|
366
378
|
|
367
|
-
|
368
|
-
raise DirectorError, 'Failed to fetch VMs information from director'
|
369
|
-
end
|
379
|
+
raise DirectorError, 'Failed to fetch VMs information from director' if status != :done
|
370
380
|
|
371
|
-
|
381
|
+
output = get_task_result_log(task_id)
|
382
|
+
else
|
383
|
+
status, output, _ = get(url, nil, nil, {}, options)
|
384
|
+
|
385
|
+
raise DirectorError, 'Failed to fetch VMs information from director' if status != 200
|
386
|
+
end
|
372
387
|
|
373
|
-
output.to_s.split("\n").map do |vm_state|
|
388
|
+
output = output.to_s.split("\n").map do |vm_state|
|
374
389
|
JSON.parse(vm_state)
|
375
390
|
end
|
391
|
+
|
392
|
+
output.flatten
|
376
393
|
end
|
377
394
|
|
378
395
|
def download_resource(id)
|
@@ -617,6 +634,13 @@ module Bosh
|
|
617
634
|
status == 201
|
618
635
|
end
|
619
636
|
|
637
|
+
def cleanup(config = {})
|
638
|
+
options = {}
|
639
|
+
options[:payload] = JSON.generate('config' => config)
|
640
|
+
options[:content_type] = 'application/json'
|
641
|
+
request_and_track(:post, '/cleanup', options)
|
642
|
+
end
|
643
|
+
|
620
644
|
def post(uri, content_type = nil, payload = nil, headers = {}, options = {})
|
621
645
|
request(:post, uri, content_type, payload, headers, options)
|
622
646
|
end
|
@@ -2,8 +2,8 @@
|
|
2
2
|
module Bosh::Cli::Command
|
3
3
|
class Deployment < Base
|
4
4
|
# bosh deployment
|
5
|
-
usage
|
6
|
-
desc
|
5
|
+
usage 'deployment'
|
6
|
+
desc 'Get/set current deployment'
|
7
7
|
def set_current(filename = nil)
|
8
8
|
if filename.nil?
|
9
9
|
show_current
|
@@ -19,34 +19,34 @@ module Bosh::Cli::Command
|
|
19
19
|
manifest = load_yaml_file(manifest_filename)
|
20
20
|
|
21
21
|
unless manifest.is_a?(Hash)
|
22
|
-
err(
|
22
|
+
err('Invalid manifest format')
|
23
23
|
end
|
24
24
|
|
25
|
-
unless manifest[
|
25
|
+
unless manifest['target'].blank?
|
26
26
|
err(Bosh::Cli::Manifest::MANIFEST_TARGET_UPGRADE_NOTICE)
|
27
27
|
end
|
28
28
|
|
29
|
-
if manifest[
|
30
|
-
err(
|
29
|
+
if manifest['director_uuid'].blank?
|
30
|
+
err('Director UUID is not defined in deployment manifest')
|
31
31
|
end
|
32
32
|
|
33
33
|
if target
|
34
34
|
old_director = Bosh::Cli::Client::Director.new(target, credentials, ca_cert: config.ca_cert)
|
35
|
-
old_director_uuid = old_director.get_status[
|
35
|
+
old_director_uuid = old_director.get_status['uuid'] rescue nil
|
36
36
|
else
|
37
37
|
old_director_uuid = nil
|
38
38
|
end
|
39
39
|
|
40
|
-
new_director_uuid = manifest[
|
40
|
+
new_director_uuid = manifest['director_uuid']
|
41
41
|
|
42
42
|
if old_director_uuid != new_director_uuid
|
43
43
|
new_target_url = config.resolve_alias(:target, new_director_uuid)
|
44
44
|
|
45
45
|
if new_target_url.blank?
|
46
|
-
err(
|
46
|
+
err('This manifest references director with UUID ' +
|
47
47
|
"#{new_director_uuid}.\n" +
|
48
48
|
"You've never targeted it before.\n" +
|
49
|
-
|
49
|
+
'Please find your director IP or hostname and target it first.')
|
50
50
|
end
|
51
51
|
|
52
52
|
target_ca_cert = config.ca_cert(new_target_url)
|
@@ -56,10 +56,10 @@ module Bosh::Cli::Command
|
|
56
56
|
status = new_director.get_status
|
57
57
|
|
58
58
|
config.target = new_target_url
|
59
|
-
config.target_name = status[
|
60
|
-
config.target_version = status[
|
61
|
-
config.target_uuid = status[
|
62
|
-
say("#{
|
59
|
+
config.target_name = status['name']
|
60
|
+
config.target_version = status['version']
|
61
|
+
config.target_uuid = status['uuid']
|
62
|
+
say("#{'WARNING!'.make_red} Your target has been " +
|
63
63
|
"changed to `#{target.make_red}'!")
|
64
64
|
end
|
65
65
|
|
@@ -69,20 +69,20 @@ module Bosh::Cli::Command
|
|
69
69
|
end
|
70
70
|
|
71
71
|
# bosh edit deployment
|
72
|
-
usage
|
73
|
-
desc
|
72
|
+
usage 'edit deployment'
|
73
|
+
desc 'Edit current deployment manifest'
|
74
74
|
def edit
|
75
75
|
deployment_required
|
76
|
-
editor = ENV['EDITOR'] ||
|
76
|
+
editor = ENV['EDITOR'] || 'vi'
|
77
77
|
system("#{editor} #{deployment}")
|
78
78
|
end
|
79
79
|
|
80
80
|
# bosh deploy
|
81
|
-
usage
|
82
|
-
desc
|
83
|
-
option
|
84
|
-
option
|
85
|
-
option
|
81
|
+
usage 'deploy'
|
82
|
+
desc 'Deploy according to the currently selected deployment manifest'
|
83
|
+
option '--recreate', 'Recreate all VMs in deployment'
|
84
|
+
option '--redact-diff', 'Redact manifest value changes in deployment'
|
85
|
+
option '--skip-drain [job1,job2]', String, 'Skip drain script for either specific or all jobs'
|
86
86
|
def perform
|
87
87
|
auth_required
|
88
88
|
recreate = !!options[:recreate]
|
@@ -166,9 +166,9 @@ module Bosh::Cli::Command
|
|
166
166
|
end
|
167
167
|
|
168
168
|
# bosh delete deployment
|
169
|
-
usage
|
170
|
-
desc
|
171
|
-
option
|
169
|
+
usage 'delete deployment'
|
170
|
+
desc 'Delete deployment'
|
171
|
+
option '--force', 'ignore errors while deleting'
|
172
172
|
def delete(deployment_name)
|
173
173
|
auth_required
|
174
174
|
show_current_state(deployment_name)
|
@@ -180,7 +180,7 @@ module Bosh::Cli::Command
|
|
180
180
|
say("THIS IS A VERY DESTRUCTIVE OPERATION AND IT CANNOT BE UNDONE!\n".make_red)
|
181
181
|
|
182
182
|
unless confirmed?
|
183
|
-
say(
|
183
|
+
say('Canceled deleting deployment'.make_green)
|
184
184
|
return
|
185
185
|
end
|
186
186
|
|
@@ -193,44 +193,44 @@ module Bosh::Cli::Command
|
|
193
193
|
end
|
194
194
|
|
195
195
|
# bosh validate jobs
|
196
|
-
usage
|
197
|
-
desc
|
198
|
-
|
196
|
+
usage 'validate jobs'
|
197
|
+
desc 'Validates all jobs in the current release using current ' +
|
198
|
+
'deployment manifest as the source of properties'
|
199
199
|
def validate_jobs
|
200
200
|
check_if_release_dir
|
201
201
|
manifest = prepare_deployment_manifest(:resolve_properties => true, show_state: true)
|
202
202
|
|
203
|
-
if manifest.hash[
|
204
|
-
release_name = manifest.hash[
|
205
|
-
elsif manifest.hash[
|
206
|
-
err(
|
203
|
+
if manifest.hash['release']
|
204
|
+
release_name = manifest.hash['release']['name']
|
205
|
+
elsif manifest.hash['releases'].count > 1
|
206
|
+
err('Cannot validate a deployment manifest with more than 1 release')
|
207
207
|
else
|
208
|
-
release_name = manifest.hash[
|
208
|
+
release_name = manifest.hash['releases'].first['name']
|
209
209
|
end
|
210
210
|
if release_name == release.dev_name || release_name == release.final_name
|
211
211
|
nl
|
212
|
-
say(
|
212
|
+
say('Analyzing release directory...'.make_yellow)
|
213
213
|
else
|
214
|
-
err(
|
214
|
+
err('This release was not found in deployment manifest')
|
215
215
|
end
|
216
216
|
|
217
|
-
say(
|
217
|
+
say(' - discovering packages')
|
218
218
|
packages = Bosh::Cli::Resources::Package.discover(work_dir)
|
219
219
|
|
220
|
-
say(
|
220
|
+
say(' - discovering jobs')
|
221
221
|
jobs = Bosh::Cli::Resources::Job.discover(
|
222
222
|
work_dir,
|
223
223
|
# TODO: be sure this is covered in integration
|
224
224
|
packages.map {|package| package['name']}
|
225
225
|
)
|
226
226
|
|
227
|
-
say(
|
227
|
+
say(' - validating properties')
|
228
228
|
validator = Bosh::Cli::JobPropertyValidator.new(jobs, manifest.hash)
|
229
229
|
validator.validate
|
230
230
|
|
231
231
|
unless validator.jobs_without_properties.empty?
|
232
232
|
nl
|
233
|
-
say(
|
233
|
+
say('Legacy jobs (no properties defined): '.make_yellow)
|
234
234
|
validator.jobs_without_properties.sort { |a, b|
|
235
235
|
a.name <=> b.name
|
236
236
|
}.each do |job|
|
@@ -240,10 +240,10 @@ module Bosh::Cli::Command
|
|
240
240
|
|
241
241
|
if validator.template_errors.empty?
|
242
242
|
nl
|
243
|
-
say(
|
243
|
+
say('No template errors found'.make_green)
|
244
244
|
else
|
245
245
|
nl
|
246
|
-
say(
|
246
|
+
say('Template errors: '.make_yellow)
|
247
247
|
validator.template_errors.each do |error|
|
248
248
|
nl
|
249
249
|
path = Pathname.new(error.template_path)
|
@@ -256,15 +256,15 @@ module Bosh::Cli::Command
|
|
256
256
|
end
|
257
257
|
|
258
258
|
# bosh deployments
|
259
|
-
usage
|
260
|
-
desc
|
259
|
+
usage 'deployments'
|
260
|
+
desc 'Show the list of available deployments'
|
261
261
|
def list
|
262
262
|
auth_required
|
263
263
|
show_current_state
|
264
264
|
|
265
265
|
deployments = director.list_deployments
|
266
266
|
|
267
|
-
err(
|
267
|
+
err('No deployments') if deployments.empty?
|
268
268
|
|
269
269
|
deployments_table = table do |t|
|
270
270
|
t.headings = ['Name', 'Release(s)', 'Stemcell(s)', 'Cloud Config']
|
@@ -277,30 +277,30 @@ module Bosh::Cli::Command
|
|
277
277
|
nl
|
278
278
|
say(deployments_table)
|
279
279
|
nl
|
280
|
-
say(
|
280
|
+
say('Deployments total: %d' % deployments.size)
|
281
281
|
end
|
282
282
|
|
283
283
|
# bosh download manifest
|
284
|
-
usage
|
285
|
-
desc
|
284
|
+
usage 'download manifest'
|
285
|
+
desc 'Download deployment manifest locally'
|
286
286
|
def download_manifest(deployment_name, save_as = nil)
|
287
287
|
auth_required
|
288
288
|
show_current_state(deployment_name)
|
289
289
|
|
290
290
|
if save_as && File.exists?(save_as) &&
|
291
291
|
!confirmed?("Overwrite `#{save_as}'?")
|
292
|
-
err(
|
292
|
+
err('Please choose another file to save the manifest to')
|
293
293
|
end
|
294
294
|
|
295
295
|
deployment = director.get_deployment(deployment_name)
|
296
296
|
|
297
297
|
if save_as
|
298
|
-
File.open(save_as,
|
299
|
-
f.write(deployment[
|
298
|
+
File.open(save_as, 'w') do |f|
|
299
|
+
f.write(deployment['manifest'])
|
300
300
|
end
|
301
301
|
say("Deployment manifest saved to `#{save_as}'".make_green)
|
302
302
|
else
|
303
|
-
say(deployment[
|
303
|
+
say(deployment['manifest'])
|
304
304
|
end
|
305
305
|
end
|
306
306
|
|
@@ -314,20 +314,20 @@ module Bosh::Cli::Command
|
|
314
314
|
say(config.deployment)
|
315
315
|
end
|
316
316
|
else
|
317
|
-
err(
|
317
|
+
err('Deployment not set')
|
318
318
|
end
|
319
319
|
end
|
320
320
|
|
321
321
|
def row_for_deployments_table(deployment)
|
322
|
-
stemcells = names_and_versions_from(deployment[
|
323
|
-
releases = names_and_versions_from(deployment[
|
322
|
+
stemcells = names_and_versions_from(deployment['stemcells'])
|
323
|
+
releases = names_and_versions_from(deployment['releases'])
|
324
324
|
|
325
|
-
[deployment[
|
325
|
+
[deployment['name'], releases.join("\n"), stemcells.join("\n"), deployment.fetch('cloud_config', 'none')]
|
326
326
|
end
|
327
327
|
|
328
328
|
def names_and_versions_from(arr)
|
329
329
|
arr.map { |hash|
|
330
|
-
hash.values_at(
|
330
|
+
hash.values_at('name', 'version').join('/')
|
331
331
|
}.sort
|
332
332
|
end
|
333
333
|
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Bosh::Cli::Command
|
2
|
+
class Disks < Base
|
3
|
+
usage 'disks'
|
4
|
+
desc 'List all orphaned disks in a deployment (requires --orphaned option)'
|
5
|
+
option '--orphaned', 'Return orphaned disks'
|
6
|
+
|
7
|
+
def list
|
8
|
+
auth_required
|
9
|
+
unless options[:orphaned]
|
10
|
+
err('Only `bosh disks --orphaned` is supported')
|
11
|
+
end
|
12
|
+
|
13
|
+
disks = sort(director.list_orphan_disks)
|
14
|
+
if disks.empty?
|
15
|
+
nl
|
16
|
+
say('No orphaned disks')
|
17
|
+
nl
|
18
|
+
return
|
19
|
+
end
|
20
|
+
|
21
|
+
disks_table = table do |table|
|
22
|
+
table.headings = 'Disk CID',
|
23
|
+
'Size (MiB)',
|
24
|
+
'Deployment Name',
|
25
|
+
'Instance Name',
|
26
|
+
'AZ',
|
27
|
+
'Orphaned At'
|
28
|
+
|
29
|
+
disks.each do |disk|
|
30
|
+
table << [
|
31
|
+
disk['disk_cid'],
|
32
|
+
disk['size'] || 'n/a',
|
33
|
+
disk['deployment_name'],
|
34
|
+
disk['instance_name'],
|
35
|
+
disk['az'] || 'n/a',
|
36
|
+
disk['orphaned_at']
|
37
|
+
]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
nl
|
42
|
+
say(disks_table)
|
43
|
+
end
|
44
|
+
|
45
|
+
usage 'delete disk'
|
46
|
+
desc 'Deletes an orphaned disk'
|
47
|
+
def delete(orphan_disk_cid)
|
48
|
+
auth_required
|
49
|
+
|
50
|
+
status, result = director.delete_orphan_disk_by_disk_cid(orphan_disk_cid)
|
51
|
+
|
52
|
+
task_report(status, result, "Deleted orphaned disk #{orphan_disk_cid}")
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def sort(disks)
|
58
|
+
disks.sort do |a, b|
|
59
|
+
Time.parse(b['orphaned_at']).to_i <=> Time.parse(a['orphaned_at']).to_i
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|