bosh_cli 1.0.3 → 1.5.0.pre.1113

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.
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
@@ -15,9 +15,6 @@ module Bosh::Cli
15
15
  end
16
16
 
17
17
  def result
18
- # TODO: erb is just a fancy eval, so it's not very trustworthy,
19
- # consider using more constrained template engine.
20
- # Note that we use $SAFE=4 for ERB which is a strawman sandbox.
21
18
  ERB.new(@raw_manifest, 4).result(binding.taint)
22
19
  rescue SyntaxError => e
23
20
  raise MalformedManifest,
@@ -64,7 +64,7 @@ module Bosh::Cli
64
64
  stage_header = event["stage"]
65
65
 
66
66
  if tags.size > 0
67
- stage_header += " " + tags.sort.join(", ").green
67
+ stage_header += " " + tags.sort.join(", ").make_green
68
68
  end
69
69
 
70
70
  unless @seen_stages.include?(stage_header)
@@ -122,8 +122,7 @@ module Bosh::Cli
122
122
  error += " #{code}" if code
123
123
  error += ": #{message}" if message
124
124
 
125
- # TODO: add KB article link and maybe cck reference?
126
- @buffer.puts("\n" + error.red)
125
+ @buffer.puts("\n" + error.make_red)
127
126
  end
128
127
 
129
128
  def refresh
@@ -178,12 +177,12 @@ module Bosh::Cli
178
177
 
179
178
  case state.to_s
180
179
  when "done"
181
- progress_bar.title = "Done".green
180
+ progress_bar.title = "Done".make_green
182
181
  progress_bar.finished_steps = progress_bar.total
183
182
  when "error"
184
- progress_bar.title = "Error".red
183
+ progress_bar.title = "Error".make_red
185
184
  else
186
- progress_bar.title = "Not done".yellow
185
+ progress_bar.title = "Not done".make_yellow
187
186
  end
188
187
 
189
188
  progress_bar.bar_visible = false
@@ -272,11 +271,10 @@ module Bosh::Cli
272
271
  end
273
272
 
274
273
  if event["state"] == "failed"
275
- # TODO: truncate?
276
- status = [task_name.red, event_data["error"]].compact.join(": ")
274
+ status = [task_name.make_red, event_data["error"]].compact.join(": ")
277
275
  @stage_has_error = true
278
276
  else
279
- status = task_name.yellow
277
+ status = task_name.make_yellow
280
278
  end
281
279
  @buffer.puts(" #{status} (#{format_time(task_time)})")
282
280
  when "in_progress"
@@ -376,7 +374,9 @@ module Bosh::Cli
376
374
  end
377
375
 
378
376
  def calculate_terminal_width
379
- if !ENV["TERM"].blank?
377
+ if ENV["COLUMNS"].to_s =~ /^\d+$/
378
+ ENV["COLUMNS"].to_i
379
+ elsif !ENV["TERM"].blank?
380
380
  width = `tput cols`
381
381
  $?.exitstatus == 0 ? [width.to_i, 100].min : 80
382
382
  else
@@ -0,0 +1,52 @@
1
+ module Bosh
2
+ module Cli
3
+ class FileWithProgressBar < ::File
4
+
5
+ def progress_bar
6
+ return @progress_bar if @progress_bar
7
+ out = Bosh::Cli::Config.output || StringIO.new
8
+ @progress_bar = ProgressBar.new(file_name, size, out)
9
+ @progress_bar.file_transfer_mode
10
+ @progress_bar
11
+ end
12
+
13
+ def file_name
14
+ File.basename(self.path)
15
+ end
16
+
17
+ def stop_progress_bar
18
+ progress_bar.halt unless progress_bar.finished?
19
+ end
20
+
21
+ def size
22
+ @size || File.size(self.path)
23
+ end
24
+
25
+ def size=(size)
26
+ @size=size
27
+ end
28
+
29
+ def read(*args)
30
+ result = super(*args)
31
+
32
+ if result && result.size > 0
33
+ progress_bar.inc(result.size)
34
+ else
35
+ progress_bar.finish
36
+ end
37
+
38
+ result
39
+ end
40
+
41
+ def write(*args)
42
+ count = super(*args)
43
+ if count
44
+ progress_bar.inc(count)
45
+ else
46
+ progress_bar.finish
47
+ end
48
+ count
49
+ end
50
+ end
51
+ end
52
+ end
@@ -37,7 +37,7 @@ module Bosh::Cli
37
37
  end
38
38
 
39
39
  unless $?.exitstatus == 0
40
- raise InvalidJob, "`#{script_path}' script failed"
40
+ raise InvalidJob, "`#{script_path}' script failed: #{output}"
41
41
  end
42
42
 
43
43
  output
@@ -0,0 +1,23 @@
1
+ module Bosh::Cli
2
+ class JobCommandArgs < Struct.new(:job, :index, :args)
3
+ def initialize(args)
4
+ job = args.shift
5
+ err('Please provide job name') if job.nil?
6
+ job, index = job.split('/', 2)
7
+
8
+ if index
9
+ if index =~ /^\d+$/
10
+ index = index.to_i
11
+ else
12
+ err('Invalid job index, integer number expected')
13
+ end
14
+ elsif args[0] =~ /^\d+$/
15
+ index = args.shift.to_i
16
+ end
17
+
18
+ self.job = job
19
+ self.index = index
20
+ self.args = args
21
+ end
22
+ end
23
+ end
@@ -1,5 +1,7 @@
1
1
  # Copyright (c) 2009-2012 VMware, Inc.
2
2
 
3
+ require 'common/deep_copy'
4
+
3
5
  module Bosh::Cli
4
6
  class JobPropertyCollection
5
7
  include Enumerable
@@ -12,8 +14,8 @@ module Bosh::Cli
12
14
  def initialize(job_builder, global_properties, job_properties, mappings)
13
15
  @job_builder = job_builder
14
16
 
15
- @job_properties = deep_copy(job_properties || {})
16
- merge(@job_properties, deep_copy(global_properties))
17
+ @job_properties = Bosh::Common::DeepCopy.copy(job_properties || {})
18
+ merge(@job_properties, Bosh::Common::DeepCopy.copy(global_properties))
17
19
 
18
20
  @mappings = mappings || {}
19
21
  @properties = []
@@ -64,11 +66,6 @@ module Bosh::Cli
64
66
  end
65
67
  end
66
68
 
67
- # @param [Object] object Serializable object
68
- # @return [Object] Deep copy of the object
69
- def deep_copy(object)
70
- Marshal.load(Marshal.dump(object))
71
- end
72
69
 
73
70
  # @param [Hash] base
74
71
  # @param [Hash] extras
@@ -2,7 +2,6 @@
2
2
 
3
3
  module Bosh::Cli
4
4
  class JobPropertyValidator
5
- # TODO: tests
6
5
 
7
6
  attr_reader :template_errors
8
7
  attr_reader :jobs_without_properties
@@ -49,12 +48,16 @@ module Bosh::Cli
49
48
  end
50
49
 
51
50
  @template_errors = []
52
- # TODO: track missing props and show the list to user (super helpful!)
53
51
  end
54
52
 
55
53
  def validate
56
54
  @manifest["jobs"].each do |job_spec|
57
- validate_templates(job_spec)
55
+ job_templates = Array(job_spec['template'])
56
+ job_templates.each do |job_template|
57
+ job_spec_for_template = job_spec.dup
58
+ job_spec_for_template['template'] = job_template
59
+ validate_templates(job_spec_for_template)
60
+ end
58
61
  end
59
62
  end
60
63
 
@@ -73,24 +76,31 @@ module Bosh::Cli
73
76
 
74
77
  # Spec is usually more than that but jobs rarely use anything but
75
78
  # networks and properties.
76
- # TODO: provide all keys in the spec?
77
79
  spec = {
78
- "job" => {
79
- "name" => job_spec["name"]
80
- },
81
- "networks" => {
82
- "default" => {"ip" => "10.0.0.1"}
80
+ 'job' => {
81
+ 'name' => job_spec['name']
83
82
  },
84
- "properties" => collection.to_hash,
85
- "index" => 0
83
+ 'index' => 0,
84
+ 'networks' => job_network_spec(job_spec),
85
+ 'properties' => collection.to_hash
86
86
  }
87
87
 
88
88
  built_job.all_templates.each do |template_path|
89
- # TODO: add progress bar?
90
89
  evaluate_template(built_job, template_path, spec)
91
90
  end
92
91
  end
93
92
 
93
+ def job_network_spec(job_spec)
94
+ job_spec['networks'].reduce({}) do |networks, network|
95
+ networks[network['name']] = {
96
+ 'ip' => '127.0.0.1', # faking the IP since it shouldn't affect logic
97
+ 'netmask' => '255.255.255.0',
98
+ 'gateway' => '127.0.0.2'
99
+ }
100
+ networks
101
+ end
102
+ end
103
+
94
104
  private
95
105
 
96
106
  # @param [JobBuilder] job Job builder
@@ -0,0 +1,54 @@
1
+ module Bosh::Cli
2
+ class JobState
3
+ OPERATION_DESCRIPTIONS = {
4
+ start: 'start %s',
5
+ stop: 'stop %s',
6
+ detach: 'stop %s and power off its VM(s)',
7
+ restart: 'restart %s',
8
+ recreate: 'recreate %s'
9
+ }
10
+
11
+ NEW_STATES = {
12
+ start: 'started',
13
+ stop: 'stopped',
14
+ detach: 'detached',
15
+ restart: 'restart',
16
+ recreate: 'recreate'
17
+ }
18
+
19
+ COMPLETION_DESCRIPTIONS = {
20
+ start: '%s has been started',
21
+ stop: '%s has been stopped, VM(s) still running',
22
+ detach: '%s has been detached, VM(s) powered off',
23
+ restart: '%s has been restarted',
24
+ recreate: '%s has been recreated'
25
+ }
26
+
27
+ def initialize(command, vm_state)
28
+ @command = command
29
+ @vm_state = vm_state
30
+ end
31
+
32
+ def change(state, job, index)
33
+ job_desc = job_description(job, index)
34
+ op_desc = OPERATION_DESCRIPTIONS.fetch(state) % job_desc
35
+ new_state = NEW_STATES.fetch(state)
36
+ completion_desc = COMPLETION_DESCRIPTIONS.fetch(state) % job_desc.make_green
37
+
38
+ status, task_id = perform_vm_state_change(job, index, new_state, op_desc)
39
+
40
+ [status, task_id, completion_desc]
41
+ end
42
+
43
+ private
44
+ attr_reader :command, :vm_state
45
+
46
+ def job_description(job, index)
47
+ index ? "#{job}/#{index}" : "#{job}"
48
+ end
49
+
50
+ def perform_vm_state_change(job, index, new_state, operation_desc)
51
+ vm_state.change(job, index, new_state, operation_desc)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,54 @@
1
+ module Bosh::Cli
2
+ class LineWrap
3
+ def initialize(width, left_margin = 0)
4
+ @width = width
5
+ @left_margin = left_margin
6
+ end
7
+
8
+ def wrap(string)
9
+ paragraphs = string.split("\n")
10
+
11
+ wrapped_paragraphs = paragraphs.map do |paragraph|
12
+ lines = wrapped_lines(paragraph)
13
+ lines = indent_lines(lines)
14
+
15
+ paragraph_indentation(paragraph) + lines.join("\n")
16
+ end
17
+
18
+ wrapped_paragraphs.join("\n")
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :width
24
+ attr_reader :left_margin
25
+
26
+ def paragraph_indentation(paragraph)
27
+ paragraph.start_with?(' ') ? ' ' : ''
28
+ end
29
+
30
+ def wrapped_lines(string)
31
+ result = []
32
+ buffer = ''
33
+
34
+ string.split(' ').each do |word|
35
+ if new_line_needed?(buffer, word)
36
+ result << buffer
37
+ buffer = word
38
+ else
39
+ buffer << ' ' unless buffer.empty?
40
+ buffer << word
41
+ end
42
+ end
43
+ result << buffer
44
+ end
45
+
46
+ def new_line_needed?(buffer, word)
47
+ buffer.size + word.size > width
48
+ end
49
+
50
+ def indent_lines(lines)
51
+ lines.map { |line| (' ' * left_margin) + line }
52
+ end
53
+ end
54
+ end
@@ -65,7 +65,7 @@ module Bosh::Cli
65
65
  item = @final_index[fingerprint]
66
66
 
67
67
  if item.nil?
68
- say("NOT FOUND".red)
68
+ say("NOT FOUND".make_red)
69
69
  return nil
70
70
  end
71
71
 
@@ -73,7 +73,7 @@ module Bosh::Cli
73
73
  version = item["version"]
74
74
 
75
75
  if blobstore_id.nil?
76
- say("No blobstore id".red)
76
+ say("No blobstore id".make_red)
77
77
  return nil
78
78
  end
79
79
 
@@ -81,18 +81,18 @@ module Bosh::Cli
81
81
  need_fetch = true
82
82
 
83
83
  if File.exists?(filename)
84
- say("FOUND LOCAL".green)
84
+ say("FOUND LOCAL".make_green)
85
85
  if file_checksum(filename) == item["sha1"]
86
86
  @tarball_path = filename
87
87
  need_fetch = false
88
88
  else
89
- say("LOCAL CHECKSUM MISMATCH".red)
89
+ say("LOCAL CHECKSUM MISMATCH".make_red)
90
90
  need_fetch = true
91
91
  end
92
92
  end
93
93
 
94
94
  if need_fetch
95
- say("Downloading `#{name} (#{version})'...".green)
95
+ say("Downloading `#{name} (#{version})'...".make_green)
96
96
  tmp_file = File.open(File.join(Dir.mktmpdir, name), "w")
97
97
  @blobstore.get(blobstore_id, tmp_file)
98
98
  tmp_file.close
@@ -121,7 +121,7 @@ module Bosh::Cli
121
121
  item = @dev_index[fingerprint]
122
122
 
123
123
  if item.nil?
124
- say("NOT FOUND".red)
124
+ say("NOT FOUND".make_red)
125
125
  return nil
126
126
  end
127
127
 
@@ -129,9 +129,9 @@ module Bosh::Cli
129
129
  filename = @dev_index.filename(version)
130
130
 
131
131
  if File.exists?(filename)
132
- say("FOUND LOCAL".green)
132
+ say("FOUND LOCAL".make_green)
133
133
  else
134
- say("TARBALL MISSING".red)
134
+ say("TARBALL MISSING".make_red)
135
135
  return nil
136
136
  end
137
137
 
@@ -140,7 +140,7 @@ module Bosh::Cli
140
140
  @version = version
141
141
  @used_dev_version = true
142
142
  else
143
- say("`#{name} (#{version})' tarball corrupted".red)
143
+ say("`#{name} (#{version})' tarball corrupted".make_red)
144
144
  return nil
145
145
  end
146
146
  end
@@ -182,7 +182,7 @@ module Bosh::Cli
182
182
 
183
183
  @version = version
184
184
  @tarball_generated = true
185
- say("Generated version #{version}".green)
185
+ say("Generated version #{version}".make_green)
186
186
  true
187
187
  end
188
188
 
@@ -66,6 +66,7 @@ module Bosh::Cli
66
66
  has_blobstore_secrets?(bs, "simple", "user", "password") ||
67
67
  has_blobstore_secrets?(bs, "swift", "rackspace") ||
68
68
  has_blobstore_secrets?(bs, "swift", "hp") ||
69
+ has_blobstore_secrets?(bs, "swift", "openstack") ||
69
70
  has_blobstore_secrets?(bs, "s3", "access_key_id", "secret_access_key")
70
71
  end
71
72
 
@@ -111,14 +112,8 @@ module Bosh::Cli
111
112
  end
112
113
 
113
114
  def save_config
114
- # TODO: introduce write_yaml helper
115
- File.open(@dev_config_file, "w") do |f|
116
- YAML.dump(@dev_config, f)
117
- end
118
-
119
- File.open(@final_config_file, "w") do |f|
120
- YAML.dump(@final_config, f)
121
- end
115
+ write_yaml(@dev_config_file, @dev_config)
116
+ write_yaml(@final_config_file, @final_config)
122
117
  end
123
118
 
124
119
  private
@@ -146,7 +141,7 @@ module Bosh::Cli
146
141
 
147
142
  # stores blobstore_secret as blobstore.atmos.secret
148
143
  def deprecate_blobstore_secret
149
- say("WARNING:".red + " use of blobstore_secret is deprecated")
144
+ say("WARNING:".make_red + " use of blobstore_secret is deprecated")
150
145
 
151
146
  @private_config["blobstore"] ||= {}
152
147
  bs = @private_config["blobstore"]
@@ -168,7 +163,7 @@ module Bosh::Cli
168
163
  # to migrate while the old one tells you to upgrade.
169
164
  if @dev_config.has_key?("blobstore_options") &&
170
165
  @dev_config["blobstore_options"] != "deprecated"
171
- say("Found legacy dev config file `#{@dev_config_file}'".yellow)
166
+ say("Found legacy dev config file `#{@dev_config_file}'".make_yellow)
172
167
 
173
168
  new_dev_config = {
174
169
  "dev_name" => @dev_config["name"],
@@ -184,14 +179,14 @@ module Bosh::Cli
184
179
  @dev_config = new_dev_config
185
180
 
186
181
  File.open(@dev_config_file, "w") do |f|
187
- YAML.dump(@dev_config, f)
182
+ Psych.dump(@dev_config, f)
188
183
  end
189
- say("Migrated dev config file format".green)
184
+ say("Migrated dev config file format".make_green)
190
185
  end
191
186
 
192
187
  if @final_config.has_key?("blobstore_options") &&
193
188
  @final_config["blobstore_options"] != "deprecated"
194
- say("Found legacy config file `#{@final_config_file}'".yellow)
189
+ say("Found legacy config file `#{@final_config_file}'".make_yellow)
195
190
 
196
191
  unless @final_config["blobstore_options"]["provider"] == "atmos" &&
197
192
  @final_config["blobstore_options"].has_key?("atmos_options")
@@ -211,8 +206,8 @@ module Bosh::Cli
211
206
 
212
207
  @final_config = new_final_config
213
208
 
214
- File.open(@final_config_file, "w") { |f| YAML.dump(@final_config, f) }
215
- say("Migrated final config file format".green)
209
+ File.open(@final_config_file, "w") { |f| Psych.dump(@final_config, f) }
210
+ say("Migrated final config file format".make_green)
216
211
  end
217
212
  end
218
213
 
@@ -224,6 +219,14 @@ module Bosh::Cli
224
219
  end
225
220
  end
226
221
 
222
+ def write_yaml(file, hash)
223
+ unless hash == load_config(file)
224
+ File.open(file, "w+") do |f|
225
+ Psych.dump(hash, f)
226
+ end
227
+ end
228
+ end
229
+
227
230
  end
228
231
 
229
232
  end