bosh_cli 0.19.6 → 1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/bosh +3 -0
- data/lib/cli.rb +15 -5
- data/lib/cli/{commands/base.rb → base_command.rb} +38 -44
- data/lib/cli/command_discovery.rb +40 -0
- data/lib/cli/command_handler.rb +135 -0
- data/lib/cli/commands/biff.rb +16 -12
- data/lib/cli/commands/blob_management.rb +10 -3
- data/lib/cli/commands/cloudcheck.rb +13 -11
- data/lib/cli/commands/complete.rb +29 -0
- data/lib/cli/commands/deployment.rb +137 -28
- data/lib/cli/commands/help.rb +96 -0
- data/lib/cli/commands/job.rb +4 -1
- data/lib/cli/commands/job_management.rb +36 -23
- data/lib/cli/commands/job_rename.rb +11 -12
- data/lib/cli/commands/log_management.rb +28 -32
- data/lib/cli/commands/maintenance.rb +6 -1
- data/lib/cli/commands/misc.rb +129 -87
- data/lib/cli/commands/package.rb +6 -65
- data/lib/cli/commands/property_management.rb +20 -8
- data/lib/cli/commands/release.rb +211 -206
- data/lib/cli/commands/ssh.rb +178 -188
- data/lib/cli/commands/stemcell.rb +114 -51
- data/lib/cli/commands/task.rb +74 -56
- data/lib/cli/commands/user.rb +6 -3
- data/lib/cli/commands/vms.rb +17 -15
- data/lib/cli/config.rb +27 -1
- data/lib/cli/core_ext.rb +27 -1
- data/lib/cli/deployment_helper.rb +47 -0
- data/lib/cli/director.rb +18 -9
- data/lib/cli/errors.rb +6 -0
- data/lib/cli/job_builder.rb +75 -23
- data/lib/cli/job_property_collection.rb +87 -0
- data/lib/cli/job_property_validator.rb +130 -0
- data/lib/cli/package_builder.rb +32 -5
- data/lib/cli/release.rb +2 -0
- data/lib/cli/release_builder.rb +9 -13
- data/lib/cli/release_compiler.rb +5 -34
- data/lib/cli/release_tarball.rb +4 -19
- data/lib/cli/runner.rb +118 -694
- data/lib/cli/version.rb +1 -1
- data/spec/assets/config/swift-hp/config/final.yml +6 -0
- data/spec/assets/config/swift-hp/config/private.yml +7 -0
- data/spec/assets/config/swift-rackspace/config/final.yml +6 -0
- data/spec/assets/config/swift-rackspace/config/private.yml +6 -0
- data/spec/spec_helper.rb +0 -5
- data/spec/unit/base_command_spec.rb +32 -37
- data/spec/unit/biff_spec.rb +11 -10
- data/spec/unit/cli_commands_spec.rb +96 -88
- data/spec/unit/core_ext_spec.rb +1 -1
- data/spec/unit/deployment_manifest_spec.rb +36 -0
- data/spec/unit/director_spec.rb +17 -3
- data/spec/unit/job_builder_spec.rb +2 -2
- data/spec/unit/job_property_collection_spec.rb +111 -0
- data/spec/unit/job_property_validator_spec.rb +7 -0
- data/spec/unit/job_rename_spec.rb +7 -6
- data/spec/unit/package_builder_spec.rb +2 -2
- data/spec/unit/release_builder_spec.rb +33 -0
- data/spec/unit/release_spec.rb +54 -0
- data/spec/unit/release_tarball_spec.rb +2 -7
- data/spec/unit/runner_spec.rb +1 -151
- data/spec/unit/ssh_spec.rb +15 -9
- metadata +41 -12
- data/lib/cli/command_definition.rb +0 -52
- data/lib/cli/templates/help_message.erb +0 -80
data/bin/bosh
CHANGED
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
|
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 "
|
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
|
-
|
82
|
+
if defined?(YAML::ENGINE.yamler)
|
83
|
+
YAML::ENGINE.yamler = "syck"
|
84
|
+
end
|
77
85
|
|
78
|
-
|
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
|
91
|
+
require file
|
82
92
|
end
|
@@ -3,31 +3,50 @@
|
|
3
3
|
module Bosh::Cli
|
4
4
|
module Command
|
5
5
|
class Base
|
6
|
-
|
7
|
-
|
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
|
-
|
12
|
-
|
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
|
-
@
|
26
|
+
@args = []
|
20
27
|
end
|
21
28
|
|
22
|
-
|
23
|
-
|
29
|
+
# @return [Bosh::Cli::Cache] Current CLI cache
|
30
|
+
def cache
|
31
|
+
Config.cache
|
32
|
+
end
|
24
33
|
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
73
|
+
options[:non_interactive]
|
55
74
|
end
|
56
75
|
|
57
76
|
def interactive?
|
58
|
-
!
|
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
|
-
|
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
|
-
|
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
|
data/lib/cli/commands/biff.rb
CHANGED
@@ -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
|
-
|
13
|
-
setup(template)
|
18
|
+
setup(template)
|
14
19
|
|
15
|
-
|
16
|
-
|
20
|
+
template_to_fill = ERB.new(File.read(@template_file), 0, "%<>-")
|
21
|
+
@template_output = template_to_fill.result(binding)
|
17
22
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
#
|
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
|
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
|
-
|
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
|
-
|
10
|
-
|
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
|
-
|
95
|
+
exit(0)
|
94
96
|
end
|
95
97
|
|
96
98
|
@problems.each do |problem|
|