bosh_cli 0.18 → 0.19

Sign up to get free protection for your applications and to get access to all the features.
data/bin/bosh CHANGED
@@ -11,7 +11,10 @@ end
11
11
  $:.unshift(File.expand_path("../../lib", __FILE__))
12
12
  require "cli"
13
13
 
14
- trap("INT") { puts "\nExiting..."; exit(1) }
15
-
16
- Thread.abort_on_exception = true
17
- Bosh::Cli::Runner.run(ARGV.dup)
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"
@@ -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 = Cache.new(cache_dir)
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
@@ -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
- f.write(str1)
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
- if old_director_uuid != manifest["director_uuid"]
42
- new_target_url = config.resolve_alias(:target,
43
- manifest["director_uuid"])
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("Cannot find director url for " +
46
- "UUID '#{manifest["director_uuid"]}'")
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 |name, value|
118
- if name != PUBLIC_STEMCELL_INDEX
119
- t << [name, value["url"]]
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
@@ -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>'. Check parse_flags to see what flags can be
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
- err("Task id must be a positive integer") unless task_id.to_i > 0
16
+ track_options = {
17
+ :log_type => log_type,
18
+ :use_cache => no_cache ? false : true,
19
+ :raw_output => raw_output
20
+ }
17
21
 
18
- task = Bosh::Cli::DirectorTask.new(director, task_id, log_type)
19
- say("Task state: #{task.state}")
22
+ if task_id.to_i <= 0
23
+ err("Task id must be a positive integer")
24
+ end
20
25
 
21
- cached_output = get_cached_task_output(task_id, log_type) unless no_cache
26
+ tracker = Bosh::Cli::TaskTracker.new(director, task_id, track_options)
27
+ tracker.track
28
+ end
22
29
 
23
- if raw_output
24
- renderer = Bosh::Cli::TaskLogRenderer.new
25
- else
26
- renderer = Bosh::Cli::TaskLogRenderer.create_for_log_type(log_type)
27
- renderer.time_adjustment = director.get_time_difference
28
- end
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
- say("Task log:")
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
- if cached_output
33
- renderer.add_output(cached_output)
34
- # renderer.finish calls render which prints the output.
35
- renderer.finish(task.state)
36
- else
37
- # This calls renderer.finish which calls render and prints the output.
38
- fetch_print_and_save_output(task, task_id, log_type, renderer)
39
- end
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
- nl
65
+ log_type = get_log_type(flags)
66
+ no_cache = flags.include?("--no-cache")
67
+ raw_output = flags.include?("--raw")
42
68
 
43
- print_task_state_and_timing(task, task_id, renderer)
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? || ["last", "latest"].include?(task_id)
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?("--event")
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