bosh_cli 1.0.3 → 1.5.0.pre.1113

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. data/bin/bosh +0 -9
  2. data/lib/cli.rb +69 -64
  3. data/lib/cli/backup_destination_path.rb +33 -0
  4. data/lib/cli/base_command.rb +57 -56
  5. data/lib/cli/blob_manager.rb +12 -12
  6. data/lib/cli/changeset_helper.rb +6 -7
  7. data/lib/cli/client/director.rb +724 -0
  8. data/lib/cli/command_handler.rb +6 -7
  9. data/lib/cli/commands/backup.rb +39 -0
  10. data/lib/cli/commands/biff.rb +42 -21
  11. data/lib/cli/commands/blob_management.rb +1 -1
  12. data/lib/cli/commands/cloudcheck.rb +11 -13
  13. data/lib/cli/commands/deployment.rb +53 -37
  14. data/lib/cli/commands/help.rb +3 -2
  15. data/lib/cli/commands/job_management.rb +67 -103
  16. data/lib/cli/commands/job_rename.rb +6 -8
  17. data/lib/cli/commands/log_management.rb +78 -55
  18. data/lib/cli/commands/maintenance.rb +36 -30
  19. data/lib/cli/commands/misc.rb +72 -51
  20. data/lib/cli/commands/package.rb +2 -2
  21. data/lib/cli/commands/property_management.rb +10 -12
  22. data/lib/cli/commands/release.rb +236 -133
  23. data/lib/cli/commands/snapshot.rb +93 -0
  24. data/lib/cli/commands/ssh.rb +216 -213
  25. data/lib/cli/commands/stemcell.rb +46 -34
  26. data/lib/cli/commands/task.rb +2 -2
  27. data/lib/cli/commands/user.rb +27 -3
  28. data/lib/cli/commands/vm.rb +28 -0
  29. data/lib/cli/commands/vms.rb +81 -23
  30. data/lib/cli/config.rb +6 -2
  31. data/lib/cli/core_ext.rb +31 -30
  32. data/lib/cli/deployment_helper.rb +134 -159
  33. data/lib/cli/deployment_manifest.rb +66 -0
  34. data/lib/cli/deployment_manifest_compiler.rb +0 -3
  35. data/lib/cli/event_log_renderer.rb +10 -10
  36. data/lib/cli/file_with_progress_bar.rb +52 -0
  37. data/lib/cli/job_builder.rb +1 -1
  38. data/lib/cli/job_command_args.rb +23 -0
  39. data/lib/cli/job_property_collection.rb +4 -7
  40. data/lib/cli/job_property_validator.rb +22 -12
  41. data/lib/cli/job_state.rb +54 -0
  42. data/lib/cli/line_wrap.rb +54 -0
  43. data/lib/cli/packaging_helper.rb +10 -10
  44. data/lib/cli/release.rb +18 -15
  45. data/lib/cli/release_builder.rb +9 -4
  46. data/lib/cli/release_compiler.rb +9 -9
  47. data/lib/cli/release_tarball.rb +3 -6
  48. data/lib/cli/resurrection.rb +31 -0
  49. data/lib/cli/runner.rb +56 -30
  50. data/lib/cli/stemcell.rb +25 -10
  51. data/lib/cli/task_log_renderer.rb +1 -1
  52. data/lib/cli/task_tracker.rb +10 -9
  53. data/lib/cli/validation.rb +3 -1
  54. data/lib/cli/version.rb +1 -1
  55. data/lib/cli/version_calc.rb +5 -18
  56. data/lib/cli/versions_index.rb +1 -1
  57. data/lib/cli/vm_state.rb +43 -0
  58. data/lib/cli/yaml_helper.rb +26 -35
  59. metadata +75 -208
  60. data/Rakefile +0 -56
  61. data/lib/cli/director.rb +0 -628
  62. data/spec/assets/biff/bad_gateway_config.yml +0 -28
  63. data/spec/assets/biff/good_simple_config.yml +0 -63
  64. data/spec/assets/biff/good_simple_golden_config.yml +0 -63
  65. data/spec/assets/biff/good_simple_template.erb +0 -69
  66. data/spec/assets/biff/ip_out_of_range.yml +0 -63
  67. data/spec/assets/biff/multiple_subnets_config.yml +0 -40
  68. data/spec/assets/biff/network_only_template.erb +0 -34
  69. data/spec/assets/biff/no_cc_config.yml +0 -27
  70. data/spec/assets/biff/no_range_config.yml +0 -27
  71. data/spec/assets/biff/no_subnet_config.yml +0 -16
  72. data/spec/assets/biff/ok_network_config.yml +0 -30
  73. data/spec/assets/biff/properties_template.erb +0 -6
  74. data/spec/assets/config/atmos/config/final.yml +0 -6
  75. data/spec/assets/config/atmos/config/private.yml +0 -4
  76. data/spec/assets/config/bad-providers/config/final.yml +0 -5
  77. data/spec/assets/config/bad-providers/config/private.yml +0 -4
  78. data/spec/assets/config/deprecation/config/final.yml +0 -5
  79. data/spec/assets/config/deprecation/config/private.yml +0 -2
  80. data/spec/assets/config/local/config/final.yml +0 -5
  81. data/spec/assets/config/local/config/private.yml +0 -1
  82. data/spec/assets/config/s3/config/final.yml +0 -5
  83. data/spec/assets/config/s3/config/private.yml +0 -5
  84. data/spec/assets/config/swift-hp/config/final.yml +0 -6
  85. data/spec/assets/config/swift-hp/config/private.yml +0 -7
  86. data/spec/assets/config/swift-rackspace/config/final.yml +0 -6
  87. data/spec/assets/config/swift-rackspace/config/private.yml +0 -6
  88. data/spec/assets/deployment.MF +0 -0
  89. data/spec/assets/plugins/bosh/cli/commands/echo.rb +0 -43
  90. data/spec/assets/plugins/bosh/cli/commands/ruby.rb +0 -24
  91. data/spec/assets/release/jobs/cacher.tgz +0 -0
  92. data/spec/assets/release/jobs/cacher/config/file1.conf +0 -0
  93. data/spec/assets/release/jobs/cacher/config/file2.conf +0 -0
  94. data/spec/assets/release/jobs/cacher/job.MF +0 -6
  95. data/spec/assets/release/jobs/cacher/monit +0 -1
  96. data/spec/assets/release/jobs/cleaner.tgz +0 -0
  97. data/spec/assets/release/jobs/cleaner/job.MF +0 -4
  98. data/spec/assets/release/jobs/cleaner/monit +0 -1
  99. data/spec/assets/release/jobs/sweeper.tgz +0 -0
  100. data/spec/assets/release/jobs/sweeper/config/test.conf +0 -1
  101. data/spec/assets/release/jobs/sweeper/job.MF +0 -5
  102. data/spec/assets/release/jobs/sweeper/monit +0 -1
  103. data/spec/assets/release/packages/mutator.tar.gz +0 -0
  104. data/spec/assets/release/packages/stuff.tgz +0 -0
  105. data/spec/assets/release/release.MF +0 -17
  106. data/spec/assets/release_invalid_checksum.tgz +0 -0
  107. data/spec/assets/release_invalid_jobs.tgz +0 -0
  108. data/spec/assets/release_no_name.tgz +0 -0
  109. data/spec/assets/release_no_version.tgz +0 -0
  110. data/spec/assets/stemcell/image +0 -1
  111. data/spec/assets/stemcell/stemcell.MF +0 -6
  112. data/spec/assets/stemcell_invalid_mf.tgz +0 -0
  113. data/spec/assets/stemcell_no_image.tgz +0 -0
  114. data/spec/assets/valid_release.tgz +0 -0
  115. data/spec/assets/valid_stemcell.tgz +0 -0
  116. data/spec/spec_helper.rb +0 -28
  117. data/spec/unit/base_command_spec.rb +0 -87
  118. data/spec/unit/biff_spec.rb +0 -172
  119. data/spec/unit/blob_manager_spec.rb +0 -288
  120. data/spec/unit/cache_spec.rb +0 -36
  121. data/spec/unit/cli_commands_spec.rb +0 -356
  122. data/spec/unit/config_spec.rb +0 -125
  123. data/spec/unit/core_ext_spec.rb +0 -81
  124. data/spec/unit/dependency_helper_spec.rb +0 -52
  125. data/spec/unit/deployment_manifest_compiler_spec.rb +0 -63
  126. data/spec/unit/deployment_manifest_spec.rb +0 -153
  127. data/spec/unit/director_spec.rb +0 -471
  128. data/spec/unit/director_task_spec.rb +0 -48
  129. data/spec/unit/event_log_renderer_spec.rb +0 -171
  130. data/spec/unit/hash_changeset_spec.rb +0 -73
  131. data/spec/unit/job_builder_spec.rb +0 -455
  132. data/spec/unit/job_property_collection_spec.rb +0 -111
  133. data/spec/unit/job_property_validator_spec.rb +0 -7
  134. data/spec/unit/job_rename_spec.rb +0 -200
  135. data/spec/unit/package_builder_spec.rb +0 -593
  136. data/spec/unit/release_builder_spec.rb +0 -120
  137. data/spec/unit/release_spec.rb +0 -173
  138. data/spec/unit/release_tarball_spec.rb +0 -29
  139. data/spec/unit/runner_spec.rb +0 -7
  140. data/spec/unit/ssh_spec.rb +0 -84
  141. data/spec/unit/stemcell_spec.rb +0 -17
  142. data/spec/unit/task_tracker_spec.rb +0 -131
  143. data/spec/unit/version_calc_spec.rb +0 -27
  144. data/spec/unit/versions_index_spec.rb +0 -144
@@ -9,9 +9,7 @@ module Bosh::Cli::Command
9
9
 
10
10
  # The URL of the public stemcell index.
11
11
  PUBLIC_STEMCELL_INDEX_URL =
12
- "https://blob.cfblob.com/rest/objects/4e4e78bca2" +
13
- "1e121204e4e86ee151bc04f6a19ce46b22?uid=bb6a0c89ef4048a8a0f814e2538" +
14
- "5d1c5/user1&expires=1893484800&signature=NJuAr9c8eOid7dKFmOEN7bmzAlI="
12
+ "https://s3.amazonaws.com/blob.cfblob.com/stemcells/public_stemcells_index.yml"
15
13
 
16
14
  DEFAULT_PUB_STEMCELL_TAG = "stable"
17
15
  ALL_STEMCELLS_TAG = "all"
@@ -27,9 +25,9 @@ module Bosh::Cli::Command
27
25
  nl
28
26
 
29
27
  if stemcell.valid?
30
- say("`#{tarball_path}' is a valid stemcell".green)
28
+ say("`#{tarball_path}' is a valid stemcell".make_green)
31
29
  else
32
- say("Validation errors:".red)
30
+ say("Validation errors:".make_red)
33
31
  stemcell.errors.each do |error|
34
32
  say("- %s" % [error])
35
33
  end
@@ -39,38 +37,50 @@ module Bosh::Cli::Command
39
37
 
40
38
  # bosh upload stemcell
41
39
  usage "upload stemcell"
42
- desc "Upload stemcell"
43
- def upload(tarball_path)
40
+ desc "Upload stemcell (stemcell_location can be a local file or a remote URI)"
41
+ def upload(stemcell_location)
44
42
  auth_required
45
43
 
46
- stemcell = Bosh::Cli::Stemcell.new(tarball_path, cache)
47
-
48
- nl
49
- say("Verifying stemcell...")
50
- stemcell.validate
51
- nl
44
+ stemcell_type = stemcell_location =~ /^#{URI::regexp}$/ ? "remote" : "local"
45
+ if stemcell_type == "local"
46
+ stemcell = Bosh::Cli::Stemcell.new(stemcell_location, cache)
47
+
48
+ nl
49
+ say("Verifying stemcell...")
50
+ stemcell.validate
51
+ nl
52
+
53
+ unless stemcell.valid?
54
+ err("Stemcell is invalid, please fix, verify and upload again")
55
+ end
56
+
57
+ say("Checking if stemcell already exists...")
58
+ name = stemcell.manifest["name"]
59
+ version = stemcell.manifest["version"]
60
+
61
+ if exists?(name, version)
62
+ err("Stemcell `#{name}/#{version}' already exists, " +
63
+ "increment the version if it has changed")
64
+ else
65
+ say("No")
66
+ end
67
+
68
+ stemcell_location = stemcell.stemcell_file
52
69
 
53
- unless stemcell.valid?
54
- err("Stemcell is invalid, please fix, verify and upload again")
70
+ nl
71
+ say("Uploading stemcell...")
72
+ nl
73
+ else
74
+ nl
75
+ say("Using remote stemcell `#{stemcell_location}'")
55
76
  end
56
77
 
57
- say("Checking if stemcell already exists...")
58
- name = stemcell.manifest["name"]
59
- version = stemcell.manifest["version"]
60
-
61
- if exists?(name, version)
62
- err("Stemcell `#{name}/#{version}' already exists, " +
63
- "increment the version if it has changed")
78
+ if stemcell_type == "local"
79
+ status, task_id = director.upload_stemcell(stemcell_location)
64
80
  else
65
- say("No")
81
+ status, task_id = director.upload_remote_stemcell(stemcell_location)
66
82
  end
67
83
 
68
- nl
69
- say("Uploading stemcell...")
70
- nl
71
-
72
- status, task_id = director.upload_stemcell(stemcell.stemcell_file)
73
-
74
84
  task_report(status, task_id, "Stemcell uploaded and created")
75
85
  end
76
86
 
@@ -170,15 +180,17 @@ module Bosh::Cli::Command
170
180
  err("The downloaded file sha1 `#{file_sha1}' does not match the " +
171
181
  "expected sha1 `#{sha1}'")
172
182
  else
173
- say("Download complete".green)
183
+ say("Download complete".make_green)
174
184
  end
175
185
  end
176
186
 
177
187
  # bosh delete stemcell
178
188
  usage "delete stemcell"
179
189
  desc "Delete stemcell"
190
+ option "--force", "ignore errors while deleting the stemcell"
180
191
  def delete(name, version)
181
192
  auth_required
193
+ force = !!options[:force]
182
194
 
183
195
  say("Checking if stemcell exists...")
184
196
 
@@ -186,14 +198,14 @@ module Bosh::Cli::Command
186
198
  err("Stemcell `#{name}/#{version}' does not exist")
187
199
  end
188
200
 
189
- say("You are going to delete stemcell `#{name}/#{version}'".red)
201
+ say("You are going to delete stemcell `#{name}/#{version}'".make_red)
190
202
 
191
203
  unless confirmed?
192
- say("Canceled deleting stemcell".green)
204
+ say("Canceled deleting stemcell".make_green)
193
205
  return
194
206
  end
195
207
 
196
- status, task_id = director.delete_stemcell(name, version)
208
+ status, task_id = director.delete_stemcell(name, version, :force => force)
197
209
 
198
210
  task_report(status, task_id, "Deleted stemcell `#{name}/#{version}'")
199
211
  end
@@ -232,7 +244,7 @@ module Bosh::Cli::Command
232
244
  if status_code != HTTP::Status::OK
233
245
  err("Received HTTP #{status_code} from #{PUBLIC_STEMCELL_INDEX_URL}.")
234
246
  end
235
- YAML.load(response.body)
247
+ Psych.load(response.body)
236
248
  end
237
249
 
238
250
  end
@@ -118,9 +118,9 @@ module Bosh::Cli::Command
118
118
  def show_tasks_table(tasks)
119
119
  return if tasks.empty?
120
120
  tasks_table = table do |t|
121
- t.headings = "#", "State", "Timestamp", "Description", "Result"
121
+ t.headings = "#", "State", "Timestamp", "User", "Description", "Result"
122
122
  tasks.map do |task|
123
- t << [task["id"], task["state"], Time.at(task["timestamp"]).utc,
123
+ t << [task["id"], task["state"], Time.at(task["timestamp"]).utc, task["user"],
124
124
  task["description"].to_s, task["result"].to_s.truncate(80)]
125
125
  end
126
126
  end
@@ -10,9 +10,12 @@ module Bosh::Cli::Command
10
10
  auth_required
11
11
 
12
12
  if interactive?
13
- username = ask("Enter username: ") if username.blank?
13
+ username = ask("Enter new username: ") if username.blank?
14
14
  if password.blank?
15
- password = ask("Enter password: ") { |q| q.echo = "*" }
15
+ password = ask("Enter new password: ") { |q| q.echo = "*" }
16
+ password_confirmation = ask("Verify new password: ") { |q| q.echo = "*" }
17
+
18
+ err("Passwords do not match") if password != password_confirmation
16
19
  end
17
20
  end
18
21
 
@@ -21,11 +24,32 @@ module Bosh::Cli::Command
21
24
  end
22
25
 
23
26
  if director.create_user(username, password)
24
- say("User `#{username}' has been created".green)
27
+ say("User `#{username}' has been created".make_green)
25
28
  else
26
29
  err("Error creating user")
27
30
  end
28
31
  end
29
32
 
33
+ usage "delete user"
34
+ desc "Deletes the user from the director"
35
+ def delete(username = nil)
36
+ auth_required
37
+
38
+ if interactive?
39
+ username ||= ask("Username to delete: ")
40
+ end
41
+
42
+ if username.blank?
43
+ err("Please provide a username to delete")
44
+ end
45
+
46
+ if confirmed?("Are you sure you would like to delete the user `#{username}'?")
47
+ if director.delete_user(username)
48
+ say("User `#{username}' has been deleted".make_green)
49
+ else
50
+ err("Unable to delete user")
51
+ end
52
+ end
53
+ end
30
54
  end
31
55
  end
@@ -0,0 +1,28 @@
1
+ require 'cli/job_command_args'
2
+ require 'cli/resurrection'
3
+
4
+ module Bosh::Cli
5
+ module Command
6
+ class Vm < Base
7
+ usage 'vm resurrection'
8
+ desc 'Enable/Disable resurrection for a given vm'
9
+ def resurrection_state(job=nil, index=nil, new_state)
10
+ if job.nil? && index.nil?
11
+ resurrection = Resurrection.new(new_state)
12
+
13
+ director.change_vm_resurrection_for_all(resurrection.paused?)
14
+ else
15
+ job_args = JobCommandArgs.new([job, index])
16
+ job, index, _ = job_args.to_a
17
+ resurrection = Resurrection.new(new_state)
18
+
19
+ job_must_exist_in_deployment(job)
20
+ index = valid_index_for(job, index, integer_index: true)
21
+
22
+ manifest = prepare_deployment_manifest
23
+ director.change_vm_resurrection(manifest['name'], job, index, resurrection.paused?)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -2,45 +2,103 @@
2
2
 
3
3
  module Bosh::Cli::Command
4
4
  class Vms < Base
5
- include Bosh::Cli::DeploymentHelper
6
-
7
- usage "vms"
8
- desc "List all VMs that in a deployment"
9
- option "--full", "Return detailed VM information"
5
+ usage 'vms'
6
+ desc 'List all VMs in a deployment'
7
+ option '--details', 'Return detailed VM information'
8
+ option '--dns', 'Return VM DNS A records'
9
+ option '--vitals', 'Return VM vitals information'
10
10
  def list(deployment_name = nil)
11
11
  auth_required
12
12
  no_track_unsupported
13
- show_full_stats = options[:full]
14
13
 
15
14
  if deployment_name.nil?
16
- deployment_required
17
- manifest = prepare_deployment_manifest
18
- deployment_name = manifest["name"]
15
+ deps = director.list_deployments
16
+ err('No deployments') if deps.empty?
17
+ deps.each { |dep| show_deployment(dep['name'], options) }
18
+ else
19
+ show_deployment deployment_name, options
19
20
  end
21
+ end
20
22
 
21
- say("Deployment `#{deployment_name.green}'")
22
- vms = director.fetch_vm_state(deployment_name)
23
- err("No VMs") if vms.empty?
23
+ def show_deployment(name, options={})
24
+ say("Deployment `#{name.make_green}'")
25
+
26
+ vms = director.fetch_vm_state(name)
27
+
28
+ if vms.empty?
29
+ nl
30
+ say('No VMs')
31
+ nl
32
+ return
33
+ end
24
34
 
25
35
  sorted = vms.sort do |a, b|
26
- s = a["job_name"].to_s <=> b["job_name"].to_s
27
- s = a["index"].to_i <=> b["index"].to_i if s == 0
28
- s = a["resource_pool"].to_s <=> b["resource_pool"].to_s if s == 0
36
+ s = a['job_name'].to_s <=> b['job_name'].to_s
37
+ s = a['index'].to_i <=> b['index'].to_i if s == 0
38
+ s = a['resource_pool'].to_s <=> b['resource_pool'].to_s if s == 0
29
39
  s
30
40
  end
31
41
 
32
42
  vms_table = table do |t|
33
- headings = ["Job/index", "State", "Resource Pool", "IPs"]
34
- headings += ["CID", "Agent ID"] if show_full_stats
35
-
43
+ headings = ['Job/index', 'State', 'Resource Pool', 'IPs']
44
+ if options[:details]
45
+ headings += ['CID', 'Agent ID', 'Resurrection']
46
+ end
47
+ if options[:dns]
48
+ headings += ['DNS A records']
49
+ end
50
+ if options[:vitals]
51
+ headings += [{:value => "Load\n(avg01, avg05, avg15)", :alignment => :center}]
52
+ headings += ["CPU\nUser", "CPU\nSys", "CPU\nWait"]
53
+ headings += ['Memory Usage', 'Swap Usage']
54
+ headings += ["System\nDisk Usage", "Ephemeral\nDisk Usage", "Persistent\nDisk Usage"]
55
+ end
36
56
  t.headings = headings
37
57
 
38
58
  sorted.each do |vm|
39
- job = "#{vm["job_name"] || "unknown"}/#{vm["index"] || "unknown"}"
40
- ips = Array(vm["ips"]).join(", ")
59
+ job = "#{vm['job_name'] || 'unknown'}/#{vm['index'] || 'unknown'}"
60
+ ips = Array(vm['ips']).join(', ')
61
+ dns_records = Array(vm['dns']).join("\n")
62
+ vitals = vm['vitals']
63
+
64
+ row = [job, vm['job_state'], vm['resource_pool'], ips]
65
+
66
+ if options[:details]
67
+ row += [vm['vm_cid'], vm['agent_id'], vm['resurrection_paused'] ? 'paused' : 'active']
68
+ end
69
+
70
+ if options[:dns]
71
+ row += [dns_records.empty? ? 'n/a' : dns_records]
72
+ end
73
+
74
+ if options[:vitals]
75
+ if vitals
76
+ cpu = vitals['cpu']
77
+ mem = vitals['mem']
78
+ swap = vitals['swap']
79
+ disk = vitals['disk']
41
80
 
42
- row = [job, vm["job_state"], vm["resource_pool"], ips]
43
- row += [vm["vm_cid"], vm["agent_id"]] if show_full_stats
81
+ row << vitals['load'].map { |l| "#{l}%" }.join(', ')
82
+ row << "#{cpu['user']}%"
83
+ row << "#{cpu['sys']}%"
84
+ row << "#{cpu['wait']}%"
85
+ row << "#{mem['percent']}% (#{pretty_size(mem['kb'].to_i * 1024)})"
86
+ row << "#{swap['percent']}% (#{pretty_size(swap['kb'].to_i * 1024)})"
87
+ row << "#{disk['system']['percent']}%"
88
+ if disk['ephemeral'].nil?
89
+ row << 'n/a'
90
+ else
91
+ row << "#{disk['ephemeral']['percent']}%"
92
+ end
93
+ if disk['persistent'].nil?
94
+ row << 'n/a'
95
+ else
96
+ row << "#{disk['persistent']['percent']}%"
97
+ end
98
+ else
99
+ 9.times { row << 'n/a' }
100
+ end
101
+ end
44
102
 
45
103
  t << row
46
104
  end
@@ -49,7 +107,7 @@ module Bosh::Cli::Command
49
107
  nl
50
108
  say(vms_table)
51
109
  nl
52
- say("VMs total: %d" % vms.size)
110
+ say('VMs total: %d' % vms.size)
53
111
  end
54
112
 
55
113
  end
@@ -19,6 +19,9 @@ module Bosh::Cli
19
19
 
20
20
  # @return [Bosh::Cli::Cache] CLI cache (to save task logs etc.)
21
21
  attr_accessor :cache
22
+
23
+ # @return [Integer] CLI polling interval
24
+ attr_accessor :poll_interval
22
25
  end
23
26
 
24
27
  @commands = {}
@@ -42,7 +45,7 @@ module Bosh::Cli
42
45
  @work_dir = work_dir
43
46
 
44
47
  unless File.exists?(@filename)
45
- File.open(@filename, "w") { |f| YAML.dump({}, f) }
48
+ File.open(@filename, "w") { |f| Psych.dump({}, f) }
46
49
  File.chmod(0600, @filename)
47
50
  end
48
51
 
@@ -188,12 +191,13 @@ module Bosh::Cli
188
191
 
189
192
  def save
190
193
  File.open(@filename, "w") do |f|
191
- YAML.dump(@config_file, f)
194
+ Psych.dump(@config_file, f)
192
195
  end
193
196
 
194
197
  rescue SystemCallError => e
195
198
  raise ConfigError, e.message
196
199
  end
197
200
 
201
+ attr_reader :filename
198
202
  end
199
203
  end
@@ -66,30 +66,42 @@ module BoshExtensions
66
66
  end
67
67
 
68
68
  def load_yaml_file(path, expected_type = Hash)
69
- err("Cannot find file `#{path}'") unless File.exists?(path)
70
- yaml = YAML.load_file(path)
69
+ err("Cannot find file `#{path}'".make_red) unless File.exist?(path)
71
70
 
72
- if expected_type && !yaml.is_a?(expected_type)
73
- err("Incorrect file format in `#{path}', #{expected_type} expected")
71
+ begin
72
+ yaml_str = ERB.new(File.read(path)).result
73
+ rescue SystemCallError => e
74
+ err("Cannot load YAML file at `#{path}': #{e}".make_red)
75
+ end
76
+
77
+ begin
78
+ Bosh::Cli::YamlHelper.check_duplicate_keys(yaml_str)
79
+ rescue => e
80
+ err("Incorrect YAML structure in `#{path}': #{e}".make_red)
74
81
  end
75
82
 
76
- Bosh::Cli::YamlHelper.check_duplicate_keys(path)
83
+ yaml = Psych::load(yaml_str)
84
+ if expected_type && !yaml.is_a?(expected_type)
85
+ err("Incorrect YAML structure in `#{path}': expected #{expected_type} at the root".make_red)
86
+ end
77
87
 
78
88
  yaml
79
- rescue SystemCallError => e
80
- err("Cannot load YAML file at `#{path}': #{e}")
81
89
  end
82
90
 
83
- def dump_yaml_to_file(obj, file)
84
- yaml = YAML.dump(obj)
85
- file.write(yaml.gsub(" \n", "\n"))
86
- file.flush
91
+ def write_yaml(manifest, path)
92
+ File.open(path, "w+") do |f|
93
+ f.write(manifest.to_yaml)
94
+ end
87
95
  end
88
96
 
89
97
  # @return [Fixnum]
90
98
  def terminal_width
91
99
  STDIN.tty? ? [HighLine::SystemExtensions.terminal_size[0], 120].min : 80
92
100
  end
101
+
102
+ def warning(message)
103
+ warn("[WARNING] #{message}".make_yellow)
104
+ end
93
105
  end
94
106
 
95
107
  module BoshStringExtensions
@@ -100,19 +112,19 @@ module BoshStringExtensions
100
112
  :yellow => "\e[0m\e[33m"
101
113
  }
102
114
 
103
- def red
104
- colorize(:red)
115
+ def make_red
116
+ make_color(:red)
105
117
  end
106
118
 
107
- def green
108
- colorize(:green)
119
+ def make_green
120
+ make_color(:green)
109
121
  end
110
122
 
111
- def yellow
112
- colorize(:yellow)
123
+ def make_yellow
124
+ make_color(:yellow)
113
125
  end
114
126
 
115
- def colorize(color_code)
127
+ def make_color(color_code)
116
128
  if Bosh::Cli::Config.output &&
117
129
  Bosh::Cli::Config.output.tty? &&
118
130
  Bosh::Cli::Config.colorize &&
@@ -144,18 +156,7 @@ module BoshStringExtensions
144
156
  end
145
157
 
146
158
  def columnize(width = 80, left_margin = 0)
147
- result = ""
148
- buf = ""
149
- self.split(/\s+/).each do |word|
150
- if buf.size + word.size > width
151
- result << buf << "\n" << " " * left_margin
152
- buf = word + " "
153
- else
154
- buf << word << " "
155
- end
156
-
157
- end
158
- result + buf
159
+ Bosh::Cli::LineWrap.new(width, left_margin).wrap(self)
159
160
  end
160
161
 
161
162
  def indent(margin = 2)