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
@@ -4,34 +4,34 @@ module Bosh::Cli::Command
|
|
4
4
|
class JobRename < Base
|
5
5
|
include Bosh::Cli::DeploymentHelper
|
6
6
|
|
7
|
-
|
7
|
+
# bosh rename
|
8
|
+
usage "rename job"
|
9
|
+
desc "Renames a job. NOTE, your deployment manifest must also be " +
|
10
|
+
"updated to reflect the new job name."
|
11
|
+
option "--force", "Ignore errors"
|
12
|
+
def rename(old_name, new_name)
|
8
13
|
auth_required
|
9
14
|
manifest_yaml = prepare_deployment_manifest(:yaml => true)
|
10
15
|
manifest = YAML.load(manifest_yaml)
|
11
16
|
|
12
|
-
|
13
|
-
|
14
|
-
old_name = args.shift
|
15
|
-
new_name = args.shift
|
16
|
-
|
17
|
-
say("You are about to rename #{old_name.green} to #{new_name.green}")
|
17
|
+
force = options[:force]
|
18
|
+
say("You are about to rename `#{old_name.green}' to `#{new_name.green}'")
|
18
19
|
|
19
20
|
unless confirmed?
|
20
21
|
nl
|
21
22
|
say("Job rename canceled".green)
|
22
|
-
|
23
|
+
exit(0)
|
23
24
|
end
|
24
25
|
|
25
26
|
sanity_check_job_rename(manifest_yaml, old_name, new_name)
|
26
27
|
|
27
|
-
status, _ = director.rename_job(
|
28
|
-
|
28
|
+
status, _ = director.rename_job(
|
29
|
+
manifest["name"], manifest_yaml, old_name, new_name, force)
|
29
30
|
|
30
31
|
task_report(status, "Rename successful")
|
31
32
|
end
|
32
33
|
|
33
34
|
def sanity_check_job_rename(manifest_yaml, old_name, new_name)
|
34
|
-
|
35
35
|
# Makes sure the new deployment manifest contains the renamed job
|
36
36
|
manifest = YAML.load(manifest_yaml)
|
37
37
|
new_jobs = manifest["jobs"].map { |job| job["name"] }
|
@@ -87,7 +87,6 @@ module Bosh::Cli::Command
|
|
87
87
|
err("Manifest does not rename old job `#{old_name}'")
|
88
88
|
end
|
89
89
|
|
90
|
-
|
91
90
|
# Final sanity check, make sure that no
|
92
91
|
# other properties or anything other than the names
|
93
92
|
# have changed. So update current manifest with new name
|
@@ -4,55 +4,51 @@ module Bosh::Cli::Command
|
|
4
4
|
class LogManagement < Base
|
5
5
|
include Bosh::Cli::DeploymentHelper
|
6
6
|
|
7
|
-
|
7
|
+
# bosh logs
|
8
|
+
usage "logs"
|
9
|
+
desc "Fetch job or agent logs from a BOSH-managed VM"
|
10
|
+
option "--agent", "fetch agent logs"
|
11
|
+
option "--job", "fetch job logs"
|
12
|
+
option "--only filter1,filter2,...", Array,
|
13
|
+
"only fetch logs that satisfy",
|
14
|
+
"given filters (defined in job spec)"
|
15
|
+
option "--all", "fetch all files in the job or agent log directory"
|
16
|
+
def fetch_logs(job, index)
|
8
17
|
auth_required
|
9
18
|
target_required
|
10
19
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
log_type = nil
|
15
|
-
|
16
|
-
for_job = args.delete("--job")
|
17
|
-
for_agent = args.delete("--agent")
|
20
|
+
if index !~ /^\d+$/
|
21
|
+
err("Job index is expected to be a positive integer")
|
22
|
+
end
|
18
23
|
|
19
|
-
if
|
20
|
-
|
21
|
-
|
24
|
+
if options[:agent]
|
25
|
+
if options[:job]
|
26
|
+
err("You can't use --job and --agent together")
|
27
|
+
end
|
22
28
|
log_type = "agent"
|
23
|
-
else
|
29
|
+
else
|
24
30
|
log_type = "job"
|
25
31
|
end
|
26
32
|
|
27
|
-
if
|
28
|
-
|
29
|
-
|
30
|
-
if filters.nil?
|
31
|
-
err("Please provide a list of filters separated by comma")
|
33
|
+
if options[:only]
|
34
|
+
if options[:all]
|
35
|
+
err("You can't use --only and --all together")
|
32
36
|
end
|
33
|
-
|
34
|
-
|
35
|
-
elsif args.include?("--all")
|
36
|
-
args.delete("--all")
|
37
|
+
filters = options[:only].join(",")
|
38
|
+
elsif options[:all]
|
37
39
|
filters = "all"
|
40
|
+
else
|
41
|
+
filters = nil
|
38
42
|
end
|
39
43
|
|
40
|
-
if
|
44
|
+
if options[:agent] && filters && filters != "all"
|
41
45
|
err("Custom filtering is not supported for agent logs")
|
42
46
|
end
|
43
47
|
|
44
|
-
if index !~ /^\d+$/
|
45
|
-
err("Job index is expected to be a positive integer")
|
46
|
-
end
|
47
|
-
|
48
|
-
if args.size > 0
|
49
|
-
err("Unknown arguments: #{args.join(", ")}")
|
50
|
-
end
|
51
|
-
|
52
48
|
manifest = prepare_deployment_manifest
|
53
49
|
|
54
|
-
resource_id = director.fetch_logs(
|
55
|
-
|
50
|
+
resource_id = director.fetch_logs(
|
51
|
+
manifest["name"], job, index, log_type, filters)
|
56
52
|
|
57
53
|
if resource_id.nil?
|
58
54
|
err("Error retrieving logs")
|
@@ -7,6 +7,9 @@ module Bosh::Cli::Command
|
|
7
7
|
RELEASES_TO_KEEP = 2
|
8
8
|
STEMCELLS_TO_KEEP = 2
|
9
9
|
|
10
|
+
# bosh cleanup
|
11
|
+
usage "cleanup"
|
12
|
+
desc "Cleanup releases and stemcells"
|
10
13
|
def cleanup
|
11
14
|
target_required
|
12
15
|
auth_required
|
@@ -28,7 +31,9 @@ module Bosh::Cli::Command
|
|
28
31
|
Releases and stemcells that are in use will not be affected.
|
29
32
|
EOS
|
30
33
|
|
31
|
-
|
34
|
+
nl
|
35
|
+
say(desc)
|
36
|
+
nl
|
32
37
|
|
33
38
|
err("Cleanup canceled") unless confirmed?
|
34
39
|
|
data/lib/cli/commands/misc.rb
CHANGED
@@ -4,12 +4,18 @@ module Bosh::Cli::Command
|
|
4
4
|
class Misc < Base
|
5
5
|
DEFAULT_STATUS_TIMEOUT = 3 # seconds
|
6
6
|
|
7
|
+
# bosh version
|
8
|
+
usage "version"
|
9
|
+
desc "Show version"
|
7
10
|
def version
|
8
11
|
say("BOSH %s" % [Bosh::Cli::VERSION])
|
9
12
|
end
|
10
13
|
|
14
|
+
# bosh status
|
15
|
+
usage "status"
|
16
|
+
desc "Show current status (current target, user, deployment info etc)"
|
11
17
|
def status
|
12
|
-
if config.target
|
18
|
+
if config.target
|
13
19
|
say("Updating director data...", " ")
|
14
20
|
|
15
21
|
begin
|
@@ -26,58 +32,59 @@ module Bosh::Cli::Command
|
|
26
32
|
rescue TimeoutError
|
27
33
|
say("timed out".red)
|
28
34
|
rescue => e
|
29
|
-
say("error"
|
35
|
+
say("error: #{e.message}")
|
30
36
|
end
|
31
37
|
nl
|
32
38
|
end
|
33
39
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
40
|
+
say("Director".green)
|
41
|
+
if target_url.nil?
|
42
|
+
say(" not set".yellow)
|
43
|
+
else
|
44
|
+
print_value("Name", config.target_name)
|
45
|
+
print_value("URL", target_url)
|
46
|
+
print_value("Version", config.target_version)
|
47
|
+
print_value("User", username, "not logged in")
|
48
|
+
print_value("UUID", config.target_uuid)
|
49
|
+
end
|
50
|
+
|
51
|
+
nl
|
52
|
+
say("Deployment".green)
|
38
53
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
54
|
+
if deployment
|
55
|
+
print_value("Manifest", deployment)
|
56
|
+
else
|
57
|
+
say(" not set".yellow)
|
58
|
+
end
|
43
59
|
|
44
60
|
if in_release_dir?
|
45
|
-
|
61
|
+
nl
|
62
|
+
say("Release".green)
|
46
63
|
|
47
|
-
dev_name = release.dev_name
|
48
64
|
dev_version = Bosh::Cli::VersionsIndex.new(
|
49
|
-
|
65
|
+
File.join(work_dir, "dev_releases")).latest_version
|
50
66
|
|
51
|
-
final_name = release.final_name
|
52
67
|
final_version = Bosh::Cli::VersionsIndex.new(
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
say("Final version: %s" % [final_version ?
|
64
|
-
final_version.to_s.green :
|
65
|
-
"no versions yet".red])
|
66
|
-
|
67
|
-
say("\n")
|
68
|
-
say("Packages")
|
69
|
-
print_specs("package", "packages")
|
70
|
-
|
71
|
-
say("\n")
|
72
|
-
say("Jobs")
|
73
|
-
print_specs("job", "jobs")
|
68
|
+
File.join(work_dir, "releases")).latest_version
|
69
|
+
|
70
|
+
dev = release.dev_name
|
71
|
+
dev += "/#{dev_version}" if dev && dev_version
|
72
|
+
|
73
|
+
final = release.final_name
|
74
|
+
final += "/#{final_version}" if final && final_version
|
75
|
+
|
76
|
+
print_value("dev", dev)
|
77
|
+
print_value("final", final)
|
74
78
|
end
|
75
79
|
end
|
76
80
|
|
81
|
+
# bosh login
|
82
|
+
usage "login"
|
83
|
+
desc "Log in to currently targeted director"
|
77
84
|
def login(username = nil, password = nil)
|
78
85
|
target_required
|
79
86
|
|
80
|
-
|
87
|
+
if interactive?
|
81
88
|
username = ask("Your username: ").to_s if username.blank?
|
82
89
|
|
83
90
|
password_retries = 0
|
@@ -92,50 +99,57 @@ module Bosh::Cli::Command
|
|
92
99
|
end
|
93
100
|
logged_in = false
|
94
101
|
|
95
|
-
|
96
|
-
|
102
|
+
director.user = username
|
103
|
+
director.password = password
|
97
104
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
end
|
105
|
+
if director.authenticated?
|
106
|
+
say("Logged in as `#{username}'".green)
|
107
|
+
logged_in = true
|
108
|
+
elsif non_interactive?
|
109
|
+
err("Cannot log in as `#{username}'".red)
|
110
|
+
else
|
111
|
+
say("Cannot log in as `#{username}', please try again".red)
|
112
|
+
login(username)
|
107
113
|
end
|
108
114
|
|
109
|
-
if logged_in
|
115
|
+
if logged_in
|
110
116
|
config.set_credentials(target, username, password)
|
111
117
|
config.save
|
112
118
|
end
|
113
119
|
end
|
114
120
|
|
121
|
+
# bosh logout
|
122
|
+
usage "logout"
|
123
|
+
desc "Forget saved credentials for targeted director"
|
115
124
|
def logout
|
116
125
|
target_required
|
117
126
|
config.set_credentials(target, nil, nil)
|
118
127
|
config.save
|
119
|
-
say("You are no longer logged in to
|
128
|
+
say("You are no longer logged in to `#{target}'".yellow)
|
120
129
|
end
|
121
130
|
|
131
|
+
# bosh purge
|
132
|
+
usage "purge"
|
133
|
+
desc "Purge local manifest cache"
|
122
134
|
def purge_cache
|
123
135
|
if cache.cache_dir != Bosh::Cli::DEFAULT_CACHE_DIR
|
124
|
-
|
125
|
-
"please remove manually")
|
136
|
+
err("Cache directory overriden, please remove manually")
|
126
137
|
else
|
127
138
|
FileUtils.rm_rf(cache.cache_dir)
|
128
|
-
say("Purged cache")
|
139
|
+
say("Purged cache".green)
|
129
140
|
end
|
130
141
|
end
|
131
142
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
143
|
+
# bosh target
|
144
|
+
usage "target"
|
145
|
+
desc "Choose director to talk to (optionally creating an alias). " +
|
146
|
+
"If no arguments given, show currently targeted director"
|
147
|
+
def set_target(director_url = nil, name = nil)
|
148
|
+
if director_url.nil?
|
149
|
+
show_target
|
150
|
+
return
|
151
|
+
end
|
137
152
|
|
138
|
-
def set_target(director_url, name = nil)
|
139
153
|
if name.nil?
|
140
154
|
director_url =
|
141
155
|
config.resolve_alias(:target, director_url) || director_url
|
@@ -147,23 +161,19 @@ module Bosh::Cli::Command
|
|
147
161
|
|
148
162
|
director_url = normalize_url(director_url)
|
149
163
|
if target && director_url == normalize_url(target)
|
150
|
-
say("Target already set to `#{
|
164
|
+
say("Target already set to `#{target_name.green}'")
|
151
165
|
return
|
152
166
|
end
|
153
167
|
|
154
168
|
director = Bosh::Cli::Director.new(director_url)
|
155
169
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
"please set correct target")
|
164
|
-
end
|
165
|
-
else
|
166
|
-
status = {"name" => "Unknown Director", "version" => "n/a"}
|
170
|
+
begin
|
171
|
+
status = director.get_status
|
172
|
+
rescue Bosh::Cli::AuthError
|
173
|
+
status = {}
|
174
|
+
rescue Bosh::Cli::DirectorError
|
175
|
+
err("Cannot talk to director at `#{director_url}', " +
|
176
|
+
"please set correct target")
|
167
177
|
end
|
168
178
|
|
169
179
|
config.target = director_url
|
@@ -180,56 +190,88 @@ module Bosh::Cli::Command
|
|
180
190
|
end
|
181
191
|
|
182
192
|
config.save
|
183
|
-
say("Target set to `#{
|
193
|
+
say("Target set to `#{target_name.green}'")
|
184
194
|
|
185
195
|
if interactive? && !logged_in?
|
186
|
-
redirect(
|
196
|
+
redirect("login")
|
187
197
|
end
|
188
198
|
end
|
189
199
|
|
200
|
+
# bosh targets
|
201
|
+
usage "targets"
|
202
|
+
desc "Show the list of available targets"
|
190
203
|
def list_targets
|
191
|
-
# TODO: Bonus point will be checking each director status
|
192
|
-
# (maybe an --status option?)
|
193
204
|
targets = config.aliases(:target) || {}
|
194
205
|
|
195
|
-
err("No targets found") if targets.
|
206
|
+
err("No targets found") if targets.empty?
|
196
207
|
|
197
208
|
targets_table = table do |t|
|
198
209
|
t.headings = [ "Name", "Director URL" ]
|
199
210
|
targets.each { |row| t << [row[0], row[1]] }
|
200
211
|
end
|
201
212
|
|
202
|
-
|
213
|
+
nl
|
203
214
|
say(targets_table)
|
204
|
-
|
215
|
+
nl
|
205
216
|
say("Targets total: %d" % targets.size)
|
206
217
|
end
|
207
218
|
|
208
|
-
|
209
|
-
|
219
|
+
# bosh alias
|
220
|
+
usage "alias"
|
221
|
+
desc "Create an alias <name> for command <command>"
|
222
|
+
def set_alias(name, command)
|
223
|
+
config.set_alias(:cli, name, command.to_s.strip)
|
210
224
|
config.save
|
211
|
-
say("Alias `#{name.green}' created for command `#{
|
225
|
+
say("Alias `#{name.green}' created for command `#{command.green}'")
|
212
226
|
end
|
213
227
|
|
228
|
+
# bosh aliases
|
229
|
+
usage "aliases"
|
230
|
+
desc "Show the list of available command aliases"
|
214
231
|
def list_aliases
|
215
232
|
aliases = config.aliases(:cli) || {}
|
233
|
+
err("No aliases found") if aliases.empty?
|
216
234
|
|
217
|
-
|
218
|
-
|
219
|
-
sorted = aliases.sort_by { |name, value| name }
|
235
|
+
sorted = aliases.sort_by { |name, _| name }
|
220
236
|
aliases_table = table do |t|
|
221
|
-
t.headings =
|
237
|
+
t.headings = %w(Alias Command)
|
222
238
|
sorted.each { |row| t << [row[0], row[1]] }
|
223
239
|
end
|
224
240
|
|
225
|
-
|
241
|
+
nl
|
226
242
|
say(aliases_table)
|
227
|
-
|
243
|
+
nl
|
228
244
|
say("Aliases total: %d" % aliases.size)
|
229
245
|
end
|
230
246
|
|
231
247
|
private
|
232
248
|
|
249
|
+
def print_value(label, value, if_none = nil)
|
250
|
+
if value
|
251
|
+
message = label.ljust(10) + value.yellow
|
252
|
+
else
|
253
|
+
message = label.ljust(10) + (if_none || "n/a").yellow
|
254
|
+
end
|
255
|
+
say(message.indent(2))
|
256
|
+
end
|
257
|
+
|
258
|
+
def show_target
|
259
|
+
if config.target
|
260
|
+
if interactive?
|
261
|
+
if config.target_name
|
262
|
+
name = "#{config.target} (#{config.target_name})"
|
263
|
+
else
|
264
|
+
name = config.target
|
265
|
+
end
|
266
|
+
say("Current target is #{name.green}")
|
267
|
+
else
|
268
|
+
say(config.target)
|
269
|
+
end
|
270
|
+
else
|
271
|
+
err("Target not set")
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
233
275
|
def print_specs(entity, dir)
|
234
276
|
specs = Dir[File.join(work_dir, dir, "*", "spec")]
|
235
277
|
|
@@ -237,7 +279,7 @@ module Bosh::Cli::Command
|
|
237
279
|
say("No #{entity} specs found")
|
238
280
|
end
|
239
281
|
|
240
|
-
t = table
|
282
|
+
t = table %w(Name Dev Final)
|
241
283
|
|
242
284
|
specs.each do |spec_file|
|
243
285
|
if spec_file.is_a?(String) && File.file?(spec_file)
|