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
@@ -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)
|