bosh_cli 0.18 → 0.19
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 +7 -4
- data/lib/cli.rb +2 -0
- data/lib/cli/commands/base.rb +1 -18
- data/lib/cli/commands/biff.rb +3 -7
- data/lib/cli/commands/cloudcheck.rb +1 -0
- data/lib/cli/commands/deployment.rb +10 -6
- data/lib/cli/commands/job_rename.rb +116 -0
- data/lib/cli/commands/stemcell.rb +3 -3
- data/lib/cli/commands/task.rb +52 -143
- data/lib/cli/commands/vms.rb +2 -2
- data/lib/cli/config.rb +1 -0
- data/lib/cli/deployment_helper.rb +62 -22
- data/lib/cli/director.rb +85 -196
- data/lib/cli/director_task.rb +4 -4
- data/lib/cli/event_log_renderer.rb +5 -1
- data/lib/cli/null_renderer.rb +19 -0
- data/lib/cli/package_builder.rb +91 -62
- data/lib/cli/packaging_helper.rb +1 -1
- data/lib/cli/release_builder.rb +47 -13
- data/lib/cli/runner.rb +21 -39
- data/lib/cli/task_log_renderer.rb +9 -0
- data/lib/cli/task_tracker.rb +168 -0
- data/lib/cli/templates/help_message.erb +1 -0
- data/lib/cli/version.rb +1 -1
- data/lib/cli/versions_index.rb +3 -3
- data/spec/unit/biff_spec.rb +5 -0
- data/spec/unit/director_spec.rb +96 -192
- data/spec/unit/job_rename_spec.rb +195 -0
- data/spec/unit/package_builder_spec.rb +188 -186
- data/spec/unit/release_builder_spec.rb +27 -9
- data/spec/unit/runner_spec.rb +0 -25
- data/spec/unit/task_tracker_spec.rb +154 -0
- metadata +11 -4
data/bin/bosh
CHANGED
@@ -11,7 +11,10 @@ end
|
|
11
11
|
$:.unshift(File.expand_path("../../lib", __FILE__))
|
12
12
|
require "cli"
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
begin
|
15
|
+
Thread.abort_on_exception = true
|
16
|
+
Bosh::Cli::Runner.run(ARGV.dup)
|
17
|
+
rescue Interrupt
|
18
|
+
puts "\nExiting..."
|
19
|
+
exit(1)
|
20
|
+
end
|
data/lib/cli.rb
CHANGED
@@ -55,8 +55,10 @@ require "cli/packaging_helper"
|
|
55
55
|
require "cli/package_builder"
|
56
56
|
require "cli/job_builder"
|
57
57
|
require "cli/changeset_helper"
|
58
|
+
require "cli/task_tracker"
|
58
59
|
require "cli/task_log_renderer"
|
59
60
|
require "cli/event_log_renderer"
|
61
|
+
require "cli/null_renderer"
|
60
62
|
require "cli/deployment_manifest_compiler"
|
61
63
|
|
62
64
|
require "cli/release"
|
data/lib/cli/commands/base.rb
CHANGED
@@ -13,9 +13,8 @@ module Bosh::Cli
|
|
13
13
|
@options = options.dup
|
14
14
|
@work_dir = Dir.pwd
|
15
15
|
config_file = @options[:config] || Bosh::Cli::DEFAULT_CONFIG_PATH
|
16
|
-
cache_dir = @options[:cache_dir] || Bosh::Cli::DEFAULT_CACHE_DIR
|
17
16
|
@config = Config.new(config_file)
|
18
|
-
@cache =
|
17
|
+
@cache = Config.cache
|
19
18
|
end
|
20
19
|
|
21
20
|
class << self
|
@@ -107,22 +106,6 @@ module Bosh::Cli
|
|
107
106
|
ret + " %s" % target_version if ret
|
108
107
|
end
|
109
108
|
|
110
|
-
##
|
111
|
-
# Returns whether there is currently a task running. A wrapper for the
|
112
|
-
# director.rb method.
|
113
|
-
#
|
114
|
-
# @return [Boolean] Whether there is a task currently running.
|
115
|
-
def task_running?
|
116
|
-
director.has_current?
|
117
|
-
end
|
118
|
-
|
119
|
-
##
|
120
|
-
# Cancels the task currently running. A wrapper for the director.rb
|
121
|
-
# method.
|
122
|
-
def cancel_current_task
|
123
|
-
director.cancel_current
|
124
|
-
end
|
125
|
-
|
126
109
|
protected
|
127
110
|
|
128
111
|
def auth_required
|
data/lib/cli/commands/biff.rb
CHANGED
@@ -52,12 +52,8 @@ module Bosh::Cli::Command
|
|
52
52
|
# @param [String] str1 The first string to diff.
|
53
53
|
# @param [String] str2 The string to diff against.
|
54
54
|
def print_string_diff(str1, str2)
|
55
|
-
File.open(@temp_file_path_1, "w") { |f|
|
56
|
-
|
57
|
-
}
|
58
|
-
File.open(@temp_file_path_2, "w") { |f|
|
59
|
-
f.write(str2)
|
60
|
-
}
|
55
|
+
File.open(@temp_file_path_1, "w") { |f| f.write(str1) }
|
56
|
+
File.open(@temp_file_path_2, "w") { |f| f.write(str2) }
|
61
57
|
|
62
58
|
@diff_works = true
|
63
59
|
cmd = "#{DIFF_COMMAND} #{@temp_file_path_1} #{@temp_file_path_2} 2>&1"
|
@@ -123,7 +119,7 @@ module Bosh::Cli::Command
|
|
123
119
|
found = true
|
124
120
|
end
|
125
121
|
end
|
126
|
-
elsif obj[path_part]
|
122
|
+
elsif !obj[path_part].nil?
|
127
123
|
obj = obj[path_part]
|
128
124
|
found = true
|
129
125
|
end
|
@@ -31,6 +31,7 @@ module Bosh::Cli::Command
|
|
31
31
|
status, body = director.perform_cloud_scan(deployment_name)
|
32
32
|
scan_failed(status, body) if status != :done
|
33
33
|
|
34
|
+
nl
|
34
35
|
say("Scan is complete, checking if any problems found...")
|
35
36
|
@problems = director.list_problems(deployment_name)
|
36
37
|
|
@@ -38,12 +38,16 @@ module Bosh::Cli::Command
|
|
38
38
|
old_director_uuid = nil
|
39
39
|
end
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
new_director_uuid = manifest["director_uuid"]
|
42
|
+
|
43
|
+
if old_director_uuid != new_director_uuid
|
44
|
+
new_target_url = config.resolve_alias(:target, new_director_uuid)
|
45
|
+
|
44
46
|
if new_target_url.blank?
|
45
|
-
err("
|
46
|
-
|
47
|
+
err("This manifest references director with UUID " +
|
48
|
+
"#{new_director_uuid}.\n" +
|
49
|
+
"You've never targeted it before.\n" +
|
50
|
+
"Please find your director IP or hostname and target it first.")
|
47
51
|
end
|
48
52
|
|
49
53
|
new_director = Bosh::Cli::Director.new(new_target_url,
|
@@ -54,7 +58,7 @@ module Bosh::Cli::Command
|
|
54
58
|
config.target_name = status["name"]
|
55
59
|
config.target_version = status["version"]
|
56
60
|
config.target_uuid = status["uuid"]
|
57
|
-
say("#{"WARNING!".red} Your target has been" +
|
61
|
+
say("#{"WARNING!".red} Your target has been " +
|
58
62
|
"changed to `#{target.red}'!")
|
59
63
|
end
|
60
64
|
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::Cli::Command
|
4
|
+
class JobRename < Base
|
5
|
+
include Bosh::Cli::DeploymentHelper
|
6
|
+
|
7
|
+
def rename(*args)
|
8
|
+
auth_required
|
9
|
+
manifest_yaml = prepare_deployment_manifest(:yaml => true)
|
10
|
+
manifest = YAML.load(manifest_yaml)
|
11
|
+
|
12
|
+
args = args.dup
|
13
|
+
force = args.delete("--force")
|
14
|
+
old_name = args.shift
|
15
|
+
new_name = args.shift
|
16
|
+
|
17
|
+
sanity_check_job_rename(manifest_yaml, old_name, new_name)
|
18
|
+
|
19
|
+
say("You are about to rename #{old_name.green} to " +
|
20
|
+
"#{new_name.green} #{force}")
|
21
|
+
|
22
|
+
status, body = director.rename_job(manifest["name"], manifest_yaml,
|
23
|
+
old_name, new_name, force)
|
24
|
+
responses = {
|
25
|
+
:done => "Rename successful",
|
26
|
+
:non_trackable => "Started deployment but director at '#{target}' " +
|
27
|
+
"doesn't support deployment tracking",
|
28
|
+
:track_timeout => "Started deployment but timed out out "+
|
29
|
+
"while tracking status",
|
30
|
+
:error => "Started deployment but received an error " +
|
31
|
+
"while tracking status",
|
32
|
+
:invalid => "Deployment is invalid, please fix it and deploy again"
|
33
|
+
}
|
34
|
+
|
35
|
+
say(responses[status] || "Cannot deploy: #{body}")
|
36
|
+
end
|
37
|
+
|
38
|
+
def sanity_check_job_rename(manifest_yaml, old_name, new_name)
|
39
|
+
|
40
|
+
# Makes sure the new deployment manifest contains the renamed job
|
41
|
+
manifest = YAML.load(manifest_yaml)
|
42
|
+
new_jobs = manifest["jobs"].map { |job| job["name"] }
|
43
|
+
unless new_jobs.include?(new_name)
|
44
|
+
err "Please update your deployment manifest to include the " +
|
45
|
+
"new job name #{new_name.green}"
|
46
|
+
end
|
47
|
+
|
48
|
+
if new_jobs.include?(old_name)
|
49
|
+
err "Old name #{old_name.green} is still being used in the " +
|
50
|
+
"deployment file"
|
51
|
+
end
|
52
|
+
|
53
|
+
# Make sure that the old deployment manifest contains the old job
|
54
|
+
current_deployment = director.get_deployment(manifest["name"])
|
55
|
+
if current_deployment["manifest"].nil?
|
56
|
+
err "Director could not find manifest for deployment " +
|
57
|
+
"#{manifest["name"]}"
|
58
|
+
end
|
59
|
+
|
60
|
+
current_manifest = YAML.load(current_deployment["manifest"])
|
61
|
+
jobs = current_manifest["jobs"].map { |job| job["name"] }
|
62
|
+
unless jobs.include?(old_name)
|
63
|
+
err "Trying to rename a non existent job #{old_name}"
|
64
|
+
end
|
65
|
+
|
66
|
+
# Technically we could allow this
|
67
|
+
if jobs.include?(new_name)
|
68
|
+
err "Trying to reuse an existing job name #{new_name} " +
|
69
|
+
"to rename job #{old_name}"
|
70
|
+
end
|
71
|
+
|
72
|
+
# Make sure that only one job has been renamed
|
73
|
+
added_jobs = new_jobs - jobs
|
74
|
+
|
75
|
+
if added_jobs.size > 1
|
76
|
+
err "Cannot rename more than one job, you are trying to " +
|
77
|
+
"add #{added_jobs.inspect}"
|
78
|
+
end
|
79
|
+
|
80
|
+
if added_jobs.first != new_name
|
81
|
+
err "Manifest does not include new job #{new_name}"
|
82
|
+
end
|
83
|
+
|
84
|
+
renamed_jobs = jobs - new_jobs
|
85
|
+
|
86
|
+
if renamed_jobs.size > 1
|
87
|
+
err "Cannot rename more than one job, you have changes to " +
|
88
|
+
"#{renamed_jobs}"
|
89
|
+
end
|
90
|
+
|
91
|
+
if renamed_jobs.first != old_name
|
92
|
+
err "Manifest does not rename old job #{old_name}"
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
# Final sanity check, make sure that no
|
97
|
+
# other properties or anything other than the names
|
98
|
+
# have changed. So update current manifest with new name
|
99
|
+
# and check that it matches with the old manifest
|
100
|
+
current_manifest["jobs"].each do |job|
|
101
|
+
if job["name"] == old_name
|
102
|
+
job["name"] = new_name
|
103
|
+
break
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Now the manifests should be the same
|
108
|
+
manifest = YAML.load(manifest_yaml)
|
109
|
+
if deployment_changed?(current_manifest.dup, manifest.dup)
|
110
|
+
err "You cannot have any other changes to your manifest during " +
|
111
|
+
"rename. Please revert the above changes and retry."
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
@@ -114,9 +114,9 @@ module Bosh::Cli::Command
|
|
114
114
|
yaml = get_public_stemcell_list
|
115
115
|
stemcells_table = table do |t|
|
116
116
|
t.headings = "Name", "Url"
|
117
|
-
yaml.each do |
|
118
|
-
if
|
119
|
-
t << [
|
117
|
+
yaml.keys.sort.each do |key|
|
118
|
+
if key != PUBLIC_STEMCELL_INDEX
|
119
|
+
t << [key, yaml[key]["url"]]
|
120
120
|
end
|
121
121
|
end
|
122
122
|
end
|
data/lib/cli/commands/task.rb
CHANGED
@@ -4,7 +4,7 @@ module Bosh::Cli::Command
|
|
4
4
|
class Task < Base
|
5
5
|
|
6
6
|
# Tracks a running task or outputs the logs from an old task. Triggered
|
7
|
-
# with 'bosh task <task_num>'.
|
7
|
+
# with 'bosh task <task_num>'. Check parse_flags to see what flags can be
|
8
8
|
# used with this.
|
9
9
|
#
|
10
10
|
# @param [Array] args The arguments from the command line command.
|
@@ -13,34 +13,60 @@ module Bosh::Cli::Command
|
|
13
13
|
|
14
14
|
task_id, log_type, no_cache, raw_output = parse_flags(args)
|
15
15
|
|
16
|
-
|
16
|
+
track_options = {
|
17
|
+
:log_type => log_type,
|
18
|
+
:use_cache => no_cache ? false : true,
|
19
|
+
:raw_output => raw_output
|
20
|
+
}
|
17
21
|
|
18
|
-
|
19
|
-
|
22
|
+
if task_id.to_i <= 0
|
23
|
+
err("Task id must be a positive integer")
|
24
|
+
end
|
20
25
|
|
21
|
-
|
26
|
+
tracker = Bosh::Cli::TaskTracker.new(director, task_id, track_options)
|
27
|
+
tracker.track
|
28
|
+
end
|
22
29
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
30
|
+
def list_running
|
31
|
+
auth_required
|
32
|
+
tasks = director.list_running_tasks
|
33
|
+
err("No running tasks") if tasks.empty?
|
34
|
+
show_tasks_table(tasks.sort_by { |t| t["id"].to_i * -1 })
|
35
|
+
say("Total tasks running now: %d" % [tasks.size])
|
36
|
+
end
|
37
|
+
|
38
|
+
def list_recent(count = 30)
|
39
|
+
auth_required
|
40
|
+
tasks = director.list_recent_tasks(count)
|
41
|
+
err("No recent tasks") if tasks.empty?
|
42
|
+
show_tasks_table(tasks)
|
43
|
+
say("Showing %d recent %s" % [tasks.size,
|
44
|
+
tasks.size == 1 ? "task" : "tasks"])
|
45
|
+
end
|
29
46
|
|
30
|
-
|
47
|
+
def cancel(task_id)
|
48
|
+
auth_required
|
49
|
+
task = Bosh::Cli::DirectorTask.new(director, task_id)
|
50
|
+
task.cancel
|
51
|
+
say("Cancelling task #{task_id}")
|
52
|
+
end
|
31
53
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
54
|
+
private
|
55
|
+
|
56
|
+
# Parses the command line args to see what options have been specified.
|
57
|
+
#
|
58
|
+
# @param [Array] flags The args that were passed in from the command line.
|
59
|
+
# @return [String, String, Boolean, Boolean] The task id, the type of log
|
60
|
+
# output, whether to use cache or not, whether to output the raw log.
|
61
|
+
def parse_flags(flags)
|
62
|
+
task_id = flags.shift
|
63
|
+
task_id = get_last_task_id if asking_for_last_task?(task_id)
|
40
64
|
|
41
|
-
|
65
|
+
log_type = get_log_type(flags)
|
66
|
+
no_cache = flags.include?("--no-cache")
|
67
|
+
raw_output = flags.include?("--raw")
|
42
68
|
|
43
|
-
|
69
|
+
[task_id, log_type, no_cache, raw_output]
|
44
70
|
end
|
45
71
|
|
46
72
|
# Whether the bosh user has asked for the last (most recently run) task.
|
@@ -49,7 +75,7 @@ module Bosh::Cli::Command
|
|
49
75
|
# number as a string or it could be "last" or "latest".
|
50
76
|
# @return [Boolean] Whether the user is asking for the most recent task.
|
51
77
|
def asking_for_last_task?(task_id)
|
52
|
-
task_id.nil? ||
|
78
|
+
task_id.nil? || %w(last latest).include?(task_id)
|
53
79
|
end
|
54
80
|
|
55
81
|
# Returns the task id of the most recently run task.
|
@@ -71,117 +97,13 @@ module Bosh::Cli::Command
|
|
71
97
|
def get_log_type(flags)
|
72
98
|
if flags.include?("--soap")
|
73
99
|
"soap"
|
74
|
-
elsif flags.include?("--
|
75
|
-
"event"
|
76
|
-
else
|
100
|
+
elsif flags.include?("--debug")
|
77
101
|
"debug"
|
102
|
+
else
|
103
|
+
"event"
|
78
104
|
end
|
79
105
|
end
|
80
106
|
|
81
|
-
# Parses the command line args to see what options have been specified.
|
82
|
-
#
|
83
|
-
# @param [Array] flags The args that were passed in from the command line.
|
84
|
-
# @return [String, String, Boolean, Boolean] The task id, the type of log
|
85
|
-
# output, whether to use cache or not, whether to output the raw log.
|
86
|
-
def parse_flags(flags)
|
87
|
-
task_id = flags.shift
|
88
|
-
task_id = get_last_task_id if asking_for_last_task?(task_id)
|
89
|
-
|
90
|
-
log_type = get_log_type(flags)
|
91
|
-
|
92
|
-
no_cache = flags.include?("--no-cache")
|
93
|
-
|
94
|
-
raw_output = flags.include?("--raw")
|
95
|
-
|
96
|
-
[task_id, log_type, no_cache, raw_output]
|
97
|
-
end
|
98
|
-
|
99
|
-
# Grabs the log output for a task, prints it, then saves it to the cache.
|
100
|
-
#
|
101
|
-
# @param [Bosh::Cli::DirectorTask] task The director task that has all of
|
102
|
-
# the methods for retrieving/parsing the director's task JSON.
|
103
|
-
# @param [String] task_id The ID of the task to get logs on.
|
104
|
-
# @param [String] log_type The type of log output.
|
105
|
-
# @param [Bosh::Cli::TaskLogRenderer] renderer The renderer that renders the
|
106
|
-
# parsed task JSON.
|
107
|
-
def fetch_print_and_save_output(task, task_id, log_type, renderer)
|
108
|
-
complete_output = ""
|
109
|
-
|
110
|
-
begin
|
111
|
-
state, output = task.state, task.output
|
112
|
-
|
113
|
-
if output
|
114
|
-
renderer.add_output(output)
|
115
|
-
complete_output << output
|
116
|
-
end
|
117
|
-
|
118
|
-
renderer.refresh
|
119
|
-
sleep(0.5)
|
120
|
-
|
121
|
-
end while ["queued", "processing", "cancelling"].include?(state)
|
122
|
-
|
123
|
-
final_out = task.flush_output
|
124
|
-
|
125
|
-
if final_out
|
126
|
-
renderer.add_output(final_out)
|
127
|
-
complete_output << final_out << "\n"
|
128
|
-
end
|
129
|
-
|
130
|
-
renderer.finish(state)
|
131
|
-
save_task_output(task_id, log_type, complete_output)
|
132
|
-
end
|
133
|
-
|
134
|
-
# Prints the task state and timing information at the end of the output.
|
135
|
-
#
|
136
|
-
# @param [Bosh::Cli::DirectorTask] task The director task that has all of
|
137
|
-
# the methods for retrieving/parsing the director's task JSON.
|
138
|
-
# @param [String] task_id The ID of the task to get logs on.
|
139
|
-
# @param [Bosh::Cli::TaskLogRenderer] renderer The renderer that renders the
|
140
|
-
# parsed task JSON.
|
141
|
-
def print_task_state_and_timing(task, task_id, renderer)
|
142
|
-
final_state = task.state
|
143
|
-
color = {
|
144
|
-
"done" => :green,
|
145
|
-
"error" => :red,
|
146
|
-
}[final_state] || :yellow
|
147
|
-
status = "Task %s state is %s" %
|
148
|
-
[task_id.to_s.green, final_state.colorize(color)]
|
149
|
-
|
150
|
-
duration = renderer.duration
|
151
|
-
if final_state == "done" && duration && duration.kind_of?(Numeric)
|
152
|
-
status += ", started: %s, ended: %s (%s)" %
|
153
|
-
[renderer.started_at.to_s.green, renderer.finished_at.to_s.green,
|
154
|
-
format_time(duration).green]
|
155
|
-
end
|
156
|
-
|
157
|
-
say(status)
|
158
|
-
end
|
159
|
-
|
160
|
-
def list_running
|
161
|
-
auth_required
|
162
|
-
tasks = director.list_running_tasks
|
163
|
-
err("No running tasks") if tasks.empty?
|
164
|
-
show_tasks_table(tasks.sort_by { |t| t["id"].to_i * -1 })
|
165
|
-
say("Total tasks running now: %d" % [tasks.size])
|
166
|
-
end
|
167
|
-
|
168
|
-
def list_recent(count = 30)
|
169
|
-
auth_required
|
170
|
-
tasks = director.list_recent_tasks(count)
|
171
|
-
err("No recent tasks") if tasks.empty?
|
172
|
-
show_tasks_table(tasks)
|
173
|
-
say("Showing %d recent %s" % [tasks.size,
|
174
|
-
tasks.size == 1 ? "task" : "tasks"])
|
175
|
-
end
|
176
|
-
|
177
|
-
def cancel(task_id)
|
178
|
-
task = Bosh::Cli::DirectorTask.new(director, task_id)
|
179
|
-
task.cancel
|
180
|
-
say("Cancelling task #{task_id}")
|
181
|
-
end
|
182
|
-
|
183
|
-
private
|
184
|
-
|
185
107
|
def show_tasks_table(tasks)
|
186
108
|
return if tasks.empty?
|
187
109
|
tasks_table = table do |t|
|
@@ -196,18 +118,5 @@ module Bosh::Cli::Command
|
|
196
118
|
say(tasks_table)
|
197
119
|
say("\n")
|
198
120
|
end
|
199
|
-
|
200
|
-
def get_cached_task_output(task_id, log_type)
|
201
|
-
cache.read(task_cache_key(task_id, log_type))
|
202
|
-
end
|
203
|
-
|
204
|
-
def save_task_output(task_id, log_type, output)
|
205
|
-
cache.write(task_cache_key(task_id, log_type), output)
|
206
|
-
end
|
207
|
-
|
208
|
-
def task_cache_key(task_id, log_type)
|
209
|
-
"task/#{target}/#{task_id}/#{log_type}"
|
210
|
-
end
|
211
|
-
|
212
121
|
end
|
213
122
|
end
|