bosh_cli 0.19.6 → 1.0.rc1

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 (64) hide show
  1. data/bin/bosh +3 -0
  2. data/lib/cli.rb +15 -5
  3. data/lib/cli/{commands/base.rb → base_command.rb} +38 -44
  4. data/lib/cli/command_discovery.rb +40 -0
  5. data/lib/cli/command_handler.rb +135 -0
  6. data/lib/cli/commands/biff.rb +16 -12
  7. data/lib/cli/commands/blob_management.rb +10 -3
  8. data/lib/cli/commands/cloudcheck.rb +13 -11
  9. data/lib/cli/commands/complete.rb +29 -0
  10. data/lib/cli/commands/deployment.rb +137 -28
  11. data/lib/cli/commands/help.rb +96 -0
  12. data/lib/cli/commands/job.rb +4 -1
  13. data/lib/cli/commands/job_management.rb +36 -23
  14. data/lib/cli/commands/job_rename.rb +11 -12
  15. data/lib/cli/commands/log_management.rb +28 -32
  16. data/lib/cli/commands/maintenance.rb +6 -1
  17. data/lib/cli/commands/misc.rb +129 -87
  18. data/lib/cli/commands/package.rb +6 -65
  19. data/lib/cli/commands/property_management.rb +20 -8
  20. data/lib/cli/commands/release.rb +211 -206
  21. data/lib/cli/commands/ssh.rb +178 -188
  22. data/lib/cli/commands/stemcell.rb +114 -51
  23. data/lib/cli/commands/task.rb +74 -56
  24. data/lib/cli/commands/user.rb +6 -3
  25. data/lib/cli/commands/vms.rb +17 -15
  26. data/lib/cli/config.rb +27 -1
  27. data/lib/cli/core_ext.rb +27 -1
  28. data/lib/cli/deployment_helper.rb +47 -0
  29. data/lib/cli/director.rb +18 -9
  30. data/lib/cli/errors.rb +6 -0
  31. data/lib/cli/job_builder.rb +75 -23
  32. data/lib/cli/job_property_collection.rb +87 -0
  33. data/lib/cli/job_property_validator.rb +130 -0
  34. data/lib/cli/package_builder.rb +32 -5
  35. data/lib/cli/release.rb +2 -0
  36. data/lib/cli/release_builder.rb +9 -13
  37. data/lib/cli/release_compiler.rb +5 -34
  38. data/lib/cli/release_tarball.rb +4 -19
  39. data/lib/cli/runner.rb +118 -694
  40. data/lib/cli/version.rb +1 -1
  41. data/spec/assets/config/swift-hp/config/final.yml +6 -0
  42. data/spec/assets/config/swift-hp/config/private.yml +7 -0
  43. data/spec/assets/config/swift-rackspace/config/final.yml +6 -0
  44. data/spec/assets/config/swift-rackspace/config/private.yml +6 -0
  45. data/spec/spec_helper.rb +0 -5
  46. data/spec/unit/base_command_spec.rb +32 -37
  47. data/spec/unit/biff_spec.rb +11 -10
  48. data/spec/unit/cli_commands_spec.rb +96 -88
  49. data/spec/unit/core_ext_spec.rb +1 -1
  50. data/spec/unit/deployment_manifest_spec.rb +36 -0
  51. data/spec/unit/director_spec.rb +17 -3
  52. data/spec/unit/job_builder_spec.rb +2 -2
  53. data/spec/unit/job_property_collection_spec.rb +111 -0
  54. data/spec/unit/job_property_validator_spec.rb +7 -0
  55. data/spec/unit/job_rename_spec.rb +7 -6
  56. data/spec/unit/package_builder_spec.rb +2 -2
  57. data/spec/unit/release_builder_spec.rb +33 -0
  58. data/spec/unit/release_spec.rb +54 -0
  59. data/spec/unit/release_tarball_spec.rb +2 -7
  60. data/spec/unit/runner_spec.rb +1 -151
  61. data/spec/unit/ssh_spec.rb +15 -9
  62. metadata +41 -12
  63. data/lib/cli/command_definition.rb +0 -52
  64. data/lib/cli/templates/help_message.erb +0 -80
data/bin/bosh CHANGED
@@ -14,6 +14,9 @@ require "cli"
14
14
  begin
15
15
  Thread.abort_on_exception = true
16
16
  Bosh::Cli::Runner.run(ARGV.dup)
17
+ rescue Errno::EPIPE
18
+ puts("pipe closed, exiting...")
19
+ exit(0)
17
20
  rescue Interrupt
18
21
  puts "\nExiting..."
19
22
  exit(1)
data/lib/cli.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Bosh
4
4
  module Cli
5
5
  DEFAULT_CONFIG_PATH = File.expand_path("~/.bosh_config")
6
- DEFAULT_CACHE_DIR = File.expand_path("~/.bosh_cache")
6
+ DEFAULT_CACHE_DIR = File.expand_path("~/.bosh_cache")
7
7
  end
8
8
  end
9
9
 
@@ -70,13 +70,23 @@ require "cli/release_tarball"
70
70
 
71
71
  require "cli/blob_manager"
72
72
 
73
- require "cli/command_definition"
73
+ require "common/properties"
74
+ require "cli/job_property_collection"
75
+ require "cli/job_property_validator"
76
+
77
+ require "cli/command_discovery"
78
+ require "cli/command_handler"
74
79
  require "cli/runner"
80
+ require "cli/base_command"
75
81
 
76
- YAML::ENGINE.yamler = 'syck' if defined?(YAML::ENGINE.yamler)
82
+ if defined?(YAML::ENGINE.yamler)
83
+ YAML::ENGINE.yamler = "syck"
84
+ end
77
85
 
78
- require File.expand_path(File.dirname(__FILE__) + "/cli/commands/base")
86
+ tmpdir = Dir.mktmpdir
87
+ at_exit { FileUtils.rm_rf(tmpdir) }
88
+ ENV["TMPDIR"] = tmpdir
79
89
 
80
90
  Dir[File.dirname(__FILE__) + "/cli/commands/*.rb"].each do |file|
81
- require File.expand_path(file)
91
+ require file
82
92
  end
@@ -3,31 +3,50 @@
3
3
  module Bosh::Cli
4
4
  module Command
5
5
  class Base
6
- attr_reader :cache, :config, :options, :work_dir
7
- attr_accessor :out, :usage
6
+ extend Bosh::Cli::CommandDiscovery
7
+
8
+ attr_reader :options
9
+ attr_reader :work_dir
10
+ attr_reader :runner
11
+
12
+ attr_accessor :out
13
+
14
+ # @return [Array] Arguments passed to command handler
15
+ attr_accessor :args
8
16
 
9
17
  DEFAULT_DIRECTOR_PORT = 25555
10
18
 
11
- def initialize(options = {})
12
- @options = options.dup
19
+ # @param [Bosh::Cli::Runner] runner
20
+ def initialize(runner = nil)
21
+ @runner = runner
22
+ @options = {}
13
23
  @work_dir = Dir.pwd
14
- config_file = @options[:config] || Bosh::Cli::DEFAULT_CONFIG_PATH
15
- @config = Config.new(config_file)
16
- @cache = Config.cache
17
24
  @exit_code = 0
18
25
  @out = nil
19
- @usage = nil
26
+ @args = []
20
27
  end
21
28
 
22
- class << self
23
- attr_reader :commands
29
+ # @return [Bosh::Cli::Cache] Current CLI cache
30
+ def cache
31
+ Config.cache
32
+ end
24
33
 
25
- def command(name, &block)
26
- @commands ||= {}
27
- @commands[name] = block
34
+ # @return [Bosh::Cli::Config] Current configuration
35
+ def config
36
+ @config ||= begin
37
+ config_file = options[:config] || Bosh::Cli::DEFAULT_CONFIG_PATH
38
+ Bosh::Cli::Config.new(config_file)
28
39
  end
29
40
  end
30
41
 
42
+ def add_option(name, value)
43
+ @options[name] = value
44
+ end
45
+
46
+ def remove_option(name)
47
+ @options.delete(name)
48
+ end
49
+
31
50
  def director
32
51
  @director ||= Bosh::Cli::Director.new(target, username, password)
33
52
  end
@@ -51,38 +70,24 @@ module Bosh::Cli
51
70
  end
52
71
 
53
72
  def non_interactive?
54
- !interactive?
73
+ options[:non_interactive]
55
74
  end
56
75
 
57
76
  def interactive?
58
- !options[:non_interactive]
77
+ !non_interactive?
59
78
  end
60
79
 
61
80
  def verbose?
62
- options[:verbose]
63
- end
64
-
65
- # TODO: implement it
66
- def dry_run?
67
- options[:dry_run]
68
- end
69
-
70
- def show_usage
71
- say("Usage: #{@usage}") if @usage
72
- end
73
-
74
- def run(namespace, action, *args)
75
- eval(namespace.to_s.capitalize).new(options).send(action.to_sym, *args)
81
+ @options[:verbose]
76
82
  end
77
83
 
78
84
  def redirect(*args)
79
- run(*args)
80
- raise Bosh::Cli::GracefulExit, "redirected to %s" % [args.join(" ")]
85
+ Bosh::Cli::Runner.new(args, @options).run
81
86
  end
82
87
 
83
88
  def confirmed?(question = "Are you sure?")
84
- non_interactive? ||
85
- ask("#{question} (type 'yes' to continue): ") == "yes"
89
+ return true if non_interactive?
90
+ ask("#{question} (type 'yes' to continue): ") == "yes"
86
91
  end
87
92
 
88
93
  # @return [String] Target director URL
@@ -112,17 +117,6 @@ module Bosh::Cli
112
117
  config.target_name || target_url
113
118
  end
114
119
 
115
- def target_version
116
- config.target_version ? "Ver: " + config.target_version : ""
117
- end
118
-
119
- def full_target_name
120
- # TODO refactor this method
121
- ret = (target_name.blank? || target_name == target_url ?
122
- target_name : "%s (%s)" % [target_name, target_url])
123
- ret + " %s" % target_version if ret
124
- end
125
-
126
120
  # Sets or returns command exit code
127
121
  # @param [optional,Integer] code If param is given, sets exit code. If
128
122
  # it's nil, returns previously set exit_code
@@ -0,0 +1,40 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Cli
4
+ module CommandDiscovery
5
+
6
+ def usage(string = nil)
7
+ @usage = string
8
+ end
9
+
10
+ def desc(string)
11
+ @desc = string
12
+ end
13
+
14
+ def option(name, *args)
15
+ (@options ||= []) << [name, args]
16
+ end
17
+
18
+ # @param [Symbol] method_name Method name
19
+ def method_added(method_name)
20
+ if @usage && @desc
21
+ @options ||= []
22
+ method = instance_method(method_name)
23
+ register_command(method, @usage, @desc, @options)
24
+ end
25
+ @usage = nil
26
+ @desc = nil
27
+ @options = []
28
+ end
29
+
30
+ # @param [UnboundMethod] method Method implementing the command
31
+ # @param [String] usage Command usage (used to parse command)
32
+ # @param [String] desc Command description
33
+ # @param [Array] options Command options
34
+ def register_command(method, usage, desc, options = [])
35
+ command = CommandHandler.new(self, method, usage, desc, options)
36
+ Bosh::Cli::Config.register_command(command)
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,135 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Cli
4
+ class CommandHandler
5
+
6
+ # @return [Array]
7
+ attr_reader :keywords
8
+
9
+ # @return [String]
10
+ attr_reader :usage
11
+
12
+ # @return [String]
13
+ attr_reader :desc
14
+
15
+ # @return [Bosh::Cli::Runner]
16
+ attr_accessor :runner
17
+
18
+ # @param [Class] klass
19
+ # @param [UnboundMethod] method
20
+ # @param [String] usage
21
+ # @param [String] desc
22
+ def initialize(klass, method, usage, desc, options = [])
23
+ @klass = klass
24
+ @method = method
25
+ @usage = usage
26
+ @desc = desc
27
+
28
+ @options = options
29
+
30
+ @hints = []
31
+ @keywords = []
32
+
33
+ @parser = OptionParser.new
34
+ @runner = nil
35
+ extract_keywords
36
+ end
37
+
38
+ # Run handler with provided args
39
+ # @param [Array] args
40
+ # @return [Integer] Command exit code
41
+ def run(args, extra_options = {})
42
+ handler = @klass.new(@runner)
43
+
44
+ @options.each do |(name, arguments)|
45
+ @parser.on(name, *arguments) do |value|
46
+ handler.add_option(format_option_name(name), value)
47
+ end
48
+ end
49
+
50
+ extra_options.each_pair do |name, value|
51
+ handler.add_option(format_option_name(name), value)
52
+ end
53
+
54
+ args = parse_options(args)
55
+
56
+ begin
57
+ handler.send(@method.name, *args)
58
+ handler.exit_code
59
+ rescue ArgumentError => e
60
+ say(e.message)
61
+ err("Usage: #{usage_with_params}")
62
+ end
63
+ end
64
+
65
+ def usage_with_params
66
+ result = [@usage]
67
+ @method.parameters.each do |parameter|
68
+ next if parameter.size < 2
69
+ kind, name = parameter
70
+ if kind == :opt
71
+ result << "[<#{name}>]"
72
+ elsif kind == :req
73
+ result << "<#{name}>"
74
+ end
75
+ end
76
+
77
+ @options.each do |(name, _)|
78
+ result << "[#{name}]"
79
+ end
80
+
81
+ result.join(" ")
82
+ end
83
+
84
+ def has_options?
85
+ @options.size > 0
86
+ end
87
+
88
+ def options_summary
89
+ result = []
90
+ padding = 5
91
+
92
+ margin = @options.inject(0) do |max, (name, _)|
93
+ [max, name.size].max
94
+ end
95
+
96
+ @options.each do |(name, desc)|
97
+ desc = desc.select { |word| word.is_a?(String) }
98
+ column_width = terminal_width - padding - margin
99
+
100
+ result << name.ljust(margin).yellow + " " +
101
+ desc.join(" ").columnize(
102
+ column_width, [margin + 1, name.size + 1].max)
103
+ end
104
+
105
+ result.join("\n")
106
+ end
107
+
108
+ # @param [Array] args Arguments to parse
109
+ def parse_options(args)
110
+ @parser.parse!(args)
111
+ end
112
+
113
+ private
114
+
115
+ def format_option_name(name)
116
+ case name
117
+ when Symbol
118
+ name
119
+ when String
120
+ name.split(/\s+/)[0].gsub(/^-*/, "").gsub("-", "_").to_sym
121
+ else
122
+ name
123
+ end
124
+ end
125
+
126
+ def extract_keywords
127
+ words = @usage.split(/\s+/)
128
+ words.each do |word|
129
+ break unless word.match(/^[a-z]/i)
130
+ @keywords << word
131
+ end
132
+ end
133
+
134
+ end
135
+ end
@@ -8,22 +8,26 @@ module Bosh::Cli::Command
8
8
  # are diff'd and the user can choose to keep the new config.
9
9
  # @param [String] template The string path to the template that should be
10
10
  # used.
11
+ #
12
+ usage "diff"
13
+ desc "Diffs your current BOSH deployment configuration against " +
14
+ "the specified BOSH deployment configuration template so that " +
15
+ "you can keep your deployment configuration file up to date. " +
16
+ "A dev template can be found in deployments repos."
11
17
  def biff(template)
12
- begin
13
- setup(template)
18
+ setup(template)
14
19
 
15
- template_to_fill = ERB.new(File.read(@template_file), 0, "%<>-")
16
- @template_output = template_to_fill.result(binding)
20
+ template_to_fill = ERB.new(File.read(@template_file), 0, "%<>-")
21
+ @template_output = template_to_fill.result(binding)
17
22
 
18
- if @errors == 0
19
- print_string_diff(File.read(@deployment_file), @template_output)
20
- keep_new_file unless @no_differences
21
- else
22
- say("There were " + "#{@errors} errors.".red)
23
- end
24
- ensure
25
- delete_temp_diff_files
23
+ if @errors == 0
24
+ print_string_diff(File.read(@deployment_file), @template_output)
25
+ keep_new_file unless @no_differences
26
+ else
27
+ err("There were #{@errors} errors.")
26
28
  end
29
+ ensure
30
+ delete_temp_diff_files
27
31
  end
28
32
 
29
33
  private
@@ -4,6 +4,8 @@ module Bosh::Cli::Command
4
4
  class BlobManagement < Base
5
5
 
6
6
  # Prints out blobs status
7
+ usage "blobs"
8
+ desc "Print current blobs status"
7
9
  def status
8
10
  blob_manager.print_status
9
11
  end
@@ -11,11 +13,13 @@ module Bosh::Cli::Command
11
13
  # Adds blob to managed blobs
12
14
  # @param [String] local_path Local file path
13
15
  # @param [optional, String] blob_dir Directory to store blob in, relative
14
- # to blobs dir
16
+ # to blobs dir
17
+ usage "add blob"
18
+ desc "Add a local file as BOSH blob"
15
19
  def add(local_path, blob_dir = nil)
16
20
  blob_path = File.basename(local_path)
17
21
  if blob_dir
18
- # We don't need about blobs prefix,
22
+ # We don't need 'blobs/' prefix,
19
23
  # but it might be handy for people who rely on auto-completion
20
24
  if blob_dir[0..5] == "blobs/"
21
25
  blob_dir = blob_dir[6..-1]
@@ -26,6 +30,8 @@ module Bosh::Cli::Command
26
30
  end
27
31
 
28
32
  # Uploads all blobs that need to be uploaded
33
+ usage "upload blobs"
34
+ desc "Upload new and updated blobs to the blobstore"
29
35
  def upload
30
36
  blob_manager.print_status
31
37
 
@@ -38,10 +44,11 @@ module Bosh::Cli::Command
38
44
  end
39
45
 
40
46
  # Syncs blobs with blobstore
47
+ usage "sync blobs"
48
+ desc "Sync blob with the blobstore"
41
49
  def sync
42
50
  blob_manager.sync
43
51
  blob_manager.print_status
44
52
  end
45
-
46
53
  end
47
54
  end
@@ -4,23 +4,25 @@ module Bosh::Cli::Command
4
4
  class CloudCheck < Base
5
5
  include Bosh::Cli::DeploymentHelper
6
6
 
7
- def perform(*options)
7
+ # bosh cloudcheck
8
+ usage "cloudcheck"
9
+ desc "Cloud consistency check and interactive repair"
10
+ option "--auto",
11
+ "resolve problems automatically ",
12
+ "(not recommended for production)"
13
+ option "--report",
14
+ "generate report only, ",
15
+ "don't attempt to resolve problems"
16
+ def perform(deployment_name = nil)
8
17
  auth_required
9
- # TODO: introduce option helpers
10
- deployment_name = options.shift unless options[0] =~ /^--/
11
-
12
- @auto_mode = options.delete("--auto")
13
- @report_mode = options.delete("--report")
18
+ @auto_mode = options[:auto]
19
+ @report_mode = options[:report]
14
20
 
15
21
  if non_interactive? && !@report_mode
16
22
  err ("Cloudcheck cannot be run in non-interactive mode\n" +
17
23
  "Please use `--auto' flag if you want automated resolutions")
18
24
  end
19
25
 
20
- if options.size > 0
21
- err("Unknown options: #{options.join(", ")}")
22
- end
23
-
24
26
  if @auto_mode && @report_mode
25
27
  err("Can't use --auto and --report mode together")
26
28
  end
@@ -90,7 +92,7 @@ module Bosh::Cli::Command
90
92
 
91
93
  if @problems.empty?
92
94
  say("No problems found".green)
93
- quit
95
+ exit(0)
94
96
  end
95
97
 
96
98
  @problems.each do |problem|