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.
- 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|
|