bosh_cli 0.16
Sign up to get free protection for your applications and to get access to all the features.
- data/README +4 -0
- data/Rakefile +55 -0
- data/bin/bosh +17 -0
- data/lib/cli.rb +76 -0
- data/lib/cli/cache.rb +44 -0
- data/lib/cli/changeset_helper.rb +142 -0
- data/lib/cli/command_definition.rb +52 -0
- data/lib/cli/commands/base.rb +245 -0
- data/lib/cli/commands/biff.rb +300 -0
- data/lib/cli/commands/blob.rb +125 -0
- data/lib/cli/commands/cloudcheck.rb +169 -0
- data/lib/cli/commands/deployment.rb +147 -0
- data/lib/cli/commands/job.rb +42 -0
- data/lib/cli/commands/job_management.rb +117 -0
- data/lib/cli/commands/log_management.rb +81 -0
- data/lib/cli/commands/maintenance.rb +131 -0
- data/lib/cli/commands/misc.rb +240 -0
- data/lib/cli/commands/package.rb +112 -0
- data/lib/cli/commands/property_management.rb +125 -0
- data/lib/cli/commands/release.rb +469 -0
- data/lib/cli/commands/ssh.rb +271 -0
- data/lib/cli/commands/stemcell.rb +184 -0
- data/lib/cli/commands/task.rb +213 -0
- data/lib/cli/commands/user.rb +28 -0
- data/lib/cli/commands/vms.rb +53 -0
- data/lib/cli/config.rb +154 -0
- data/lib/cli/core_ext.rb +145 -0
- data/lib/cli/dependency_helper.rb +62 -0
- data/lib/cli/deployment_helper.rb +263 -0
- data/lib/cli/deployment_manifest_compiler.rb +28 -0
- data/lib/cli/director.rb +633 -0
- data/lib/cli/director_task.rb +64 -0
- data/lib/cli/errors.rb +48 -0
- data/lib/cli/event_log_renderer.rb +351 -0
- data/lib/cli/job_builder.rb +226 -0
- data/lib/cli/package_builder.rb +254 -0
- data/lib/cli/packaging_helper.rb +248 -0
- data/lib/cli/release.rb +176 -0
- data/lib/cli/release_builder.rb +215 -0
- data/lib/cli/release_compiler.rb +178 -0
- data/lib/cli/release_tarball.rb +272 -0
- data/lib/cli/runner.rb +771 -0
- data/lib/cli/stemcell.rb +83 -0
- data/lib/cli/task_log_renderer.rb +40 -0
- data/lib/cli/templates/help_message.erb +75 -0
- data/lib/cli/validation.rb +42 -0
- data/lib/cli/version.rb +7 -0
- data/lib/cli/version_calc.rb +48 -0
- data/lib/cli/versions_index.rb +126 -0
- data/lib/cli/yaml_helper.rb +62 -0
- data/spec/assets/biff/bad_gateway_config.yml +28 -0
- data/spec/assets/biff/good_simple_config.yml +63 -0
- data/spec/assets/biff/good_simple_golden_config.yml +63 -0
- data/spec/assets/biff/good_simple_template.erb +69 -0
- data/spec/assets/biff/multiple_subnets_config.yml +40 -0
- data/spec/assets/biff/network_only_template.erb +34 -0
- data/spec/assets/biff/no_cc_config.yml +27 -0
- data/spec/assets/biff/no_range_config.yml +27 -0
- data/spec/assets/biff/no_subnet_config.yml +16 -0
- data/spec/assets/biff/ok_network_config.yml +30 -0
- data/spec/assets/biff/properties_template.erb +6 -0
- data/spec/assets/deployment.MF +0 -0
- data/spec/assets/plugins/bosh/cli/commands/echo.rb +43 -0
- data/spec/assets/plugins/bosh/cli/commands/ruby.rb +24 -0
- data/spec/assets/release/jobs/cacher.tgz +0 -0
- data/spec/assets/release/jobs/cacher/config/file1.conf +0 -0
- data/spec/assets/release/jobs/cacher/config/file2.conf +0 -0
- data/spec/assets/release/jobs/cacher/job.MF +6 -0
- data/spec/assets/release/jobs/cacher/monit +1 -0
- data/spec/assets/release/jobs/cleaner.tgz +0 -0
- data/spec/assets/release/jobs/cleaner/job.MF +4 -0
- data/spec/assets/release/jobs/cleaner/monit +1 -0
- data/spec/assets/release/jobs/sweeper.tgz +0 -0
- data/spec/assets/release/jobs/sweeper/config/test.conf +1 -0
- data/spec/assets/release/jobs/sweeper/job.MF +5 -0
- data/spec/assets/release/jobs/sweeper/monit +1 -0
- data/spec/assets/release/packages/mutator.tar.gz +0 -0
- data/spec/assets/release/packages/stuff.tgz +0 -0
- data/spec/assets/release/release.MF +17 -0
- data/spec/assets/release_invalid_checksum.tgz +0 -0
- data/spec/assets/release_invalid_jobs.tgz +0 -0
- data/spec/assets/release_no_name.tgz +0 -0
- data/spec/assets/release_no_version.tgz +0 -0
- data/spec/assets/stemcell/image +1 -0
- data/spec/assets/stemcell/stemcell.MF +6 -0
- data/spec/assets/stemcell_invalid_mf.tgz +0 -0
- data/spec/assets/stemcell_no_image.tgz +0 -0
- data/spec/assets/valid_release.tgz +0 -0
- data/spec/assets/valid_stemcell.tgz +0 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/unit/base_command_spec.rb +66 -0
- data/spec/unit/biff_spec.rb +135 -0
- data/spec/unit/cache_spec.rb +36 -0
- data/spec/unit/cli_commands_spec.rb +481 -0
- data/spec/unit/config_spec.rb +139 -0
- data/spec/unit/core_ext_spec.rb +77 -0
- data/spec/unit/dependency_helper_spec.rb +52 -0
- data/spec/unit/deployment_manifest_compiler_spec.rb +63 -0
- data/spec/unit/director_spec.rb +511 -0
- data/spec/unit/director_task_spec.rb +48 -0
- data/spec/unit/event_log_renderer_spec.rb +171 -0
- data/spec/unit/hash_changeset_spec.rb +73 -0
- data/spec/unit/job_builder_spec.rb +454 -0
- data/spec/unit/package_builder_spec.rb +567 -0
- data/spec/unit/release_builder_spec.rb +65 -0
- data/spec/unit/release_spec.rb +66 -0
- data/spec/unit/release_tarball_spec.rb +33 -0
- data/spec/unit/runner_spec.rb +140 -0
- data/spec/unit/ssh_spec.rb +78 -0
- data/spec/unit/stemcell_spec.rb +17 -0
- data/spec/unit/version_calc_spec.rb +27 -0
- data/spec/unit/versions_index_spec.rb +132 -0
- metadata +338 -0
@@ -0,0 +1,147 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::Cli::Command
|
4
|
+
class Deployment < Base
|
5
|
+
include Bosh::Cli::DeploymentHelper
|
6
|
+
|
7
|
+
def show_current
|
8
|
+
say(deployment ?
|
9
|
+
"Current deployment is '#{deployment.green}'" :
|
10
|
+
"Deployment not set")
|
11
|
+
end
|
12
|
+
|
13
|
+
def set_current(name)
|
14
|
+
manifest_filename = find_deployment(name)
|
15
|
+
|
16
|
+
unless File.exists?(manifest_filename)
|
17
|
+
err("Missing manifest for #{name} (tried '#{manifest_filename}')")
|
18
|
+
end
|
19
|
+
|
20
|
+
manifest = load_yaml_file(manifest_filename)
|
21
|
+
|
22
|
+
unless manifest.is_a?(Hash)
|
23
|
+
err("Invalid manifest format")
|
24
|
+
end
|
25
|
+
|
26
|
+
unless manifest["target"].blank?
|
27
|
+
err(manifest_target_upgrade_notice)
|
28
|
+
end
|
29
|
+
|
30
|
+
if manifest["director_uuid"].blank?
|
31
|
+
err("Director UUID is not defined in deployment manifest")
|
32
|
+
end
|
33
|
+
|
34
|
+
if target
|
35
|
+
old_director = Bosh::Cli::Director.new(target, username, password)
|
36
|
+
old_director_uuid = old_director.get_status["uuid"] rescue nil
|
37
|
+
else
|
38
|
+
old_director_uuid = nil
|
39
|
+
end
|
40
|
+
|
41
|
+
if old_director_uuid != manifest["director_uuid"]
|
42
|
+
new_target_url = config.resolve_alias(:target,
|
43
|
+
manifest["director_uuid"])
|
44
|
+
if new_target_url.blank?
|
45
|
+
err("Cannot find director url for " +
|
46
|
+
"UUID '#{manifest["director_uuid"]}'")
|
47
|
+
end
|
48
|
+
|
49
|
+
new_director = Bosh::Cli::Director.new(new_target_url,
|
50
|
+
username, password)
|
51
|
+
status = new_director.get_status
|
52
|
+
|
53
|
+
config.target = new_target_url
|
54
|
+
config.target_name = status["name"]
|
55
|
+
config.target_version = status["version"]
|
56
|
+
config.target_uuid = status["uuid"]
|
57
|
+
say("#{"WARNING!".red} Your target has been" +
|
58
|
+
"changed to `#{target.red}'!")
|
59
|
+
end
|
60
|
+
|
61
|
+
say("Deployment set to '#{manifest_filename.green}'")
|
62
|
+
config.set_deployment(manifest_filename)
|
63
|
+
config.save
|
64
|
+
end
|
65
|
+
|
66
|
+
def perform(*options)
|
67
|
+
auth_required
|
68
|
+
recreate = options.include?("--recreate")
|
69
|
+
|
70
|
+
manifest_yaml = prepare_deployment_manifest(:yaml => true,
|
71
|
+
:resolve_properties => true)
|
72
|
+
|
73
|
+
if interactive?
|
74
|
+
inspect_deployment_changes(YAML.load(manifest_yaml))
|
75
|
+
say("Please review all changes carefully".yellow)
|
76
|
+
end
|
77
|
+
|
78
|
+
desc = "`#{File.basename(deployment).green}' to `#{target_name.green}'"
|
79
|
+
|
80
|
+
unless confirmed?("Deploying #{desc}")
|
81
|
+
cancel_deployment
|
82
|
+
end
|
83
|
+
|
84
|
+
status, body = director.deploy(manifest_yaml, :recreate => recreate)
|
85
|
+
|
86
|
+
responses = {
|
87
|
+
:done => "Deployed #{desc}",
|
88
|
+
:non_trackable => "Started deployment but director at `#{target}' " +
|
89
|
+
"doesn't support deployment tracking",
|
90
|
+
:track_timeout => "Started deployment but timed out out " +
|
91
|
+
"while tracking status",
|
92
|
+
:error => "Started deployment but received an error " +
|
93
|
+
"while tracking status",
|
94
|
+
:invalid => "Deployment is invalid, please fix it and deploy again"
|
95
|
+
}
|
96
|
+
|
97
|
+
say(responses[status] || "Cannot deploy: #{body}")
|
98
|
+
end
|
99
|
+
|
100
|
+
def delete(name, *options)
|
101
|
+
auth_required
|
102
|
+
force = options.include?("--force")
|
103
|
+
|
104
|
+
say("\nYou are going to delete deployment `#{name}'.\n\n")
|
105
|
+
say("THIS IS A VERY DESTRUCTIVE OPERATION AND IT CANNOT BE UNDONE!\n".red)
|
106
|
+
|
107
|
+
unless confirmed?
|
108
|
+
say("Canceled deleting deployment".green)
|
109
|
+
return
|
110
|
+
end
|
111
|
+
|
112
|
+
status, message = director.delete_deployment(name, :force => force)
|
113
|
+
|
114
|
+
responses = {
|
115
|
+
:done => "Deleted deployment '#{name}'",
|
116
|
+
:non_trackable => "Deployment delete in progress but director " +
|
117
|
+
"at '#{target}' doesn't support task tracking",
|
118
|
+
:track_timeout => "Timed out out while tracking deployment " +
|
119
|
+
"deletion progress",
|
120
|
+
:error => "Attempted to delete deployment but received " +
|
121
|
+
"an error while tracking status",
|
122
|
+
}
|
123
|
+
|
124
|
+
say(responses[status] || "Cannot delete deployment: #{message}")
|
125
|
+
end
|
126
|
+
|
127
|
+
def list
|
128
|
+
auth_required
|
129
|
+
|
130
|
+
deployments = director.list_deployments
|
131
|
+
|
132
|
+
err("No deployments") if deployments.size == 0
|
133
|
+
|
134
|
+
deployments_table = table do |t|
|
135
|
+
t.headings = ["Name"]
|
136
|
+
deployments.each do |r|
|
137
|
+
t << [r["name"]]
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
say("\n")
|
142
|
+
say(deployments_table)
|
143
|
+
say("\n")
|
144
|
+
say("Deployments total: %d" % deployments.size)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::Cli::Command
|
4
|
+
class Job < Base
|
5
|
+
|
6
|
+
def generate(name)
|
7
|
+
check_if_release_dir
|
8
|
+
|
9
|
+
unless name.bosh_valid_id?
|
10
|
+
err("`#{name}' is not a vaild BOSH id")
|
11
|
+
end
|
12
|
+
|
13
|
+
job_dir = File.join("jobs", name)
|
14
|
+
|
15
|
+
if File.exists?(job_dir)
|
16
|
+
err("Job `#{name}' already exists, please pick another name")
|
17
|
+
end
|
18
|
+
|
19
|
+
say("create\t#{job_dir}")
|
20
|
+
FileUtils.mkdir_p(job_dir)
|
21
|
+
|
22
|
+
templates_dir = File.join(job_dir, "templates")
|
23
|
+
say("create\t#{templates_dir}")
|
24
|
+
FileUtils.mkdir_p(templates_dir)
|
25
|
+
|
26
|
+
spec_file = File.join(job_dir, "spec")
|
27
|
+
say("create\t#{spec_file}")
|
28
|
+
FileUtils.touch(spec_file)
|
29
|
+
|
30
|
+
monit_file = File.join(job_dir, "monit")
|
31
|
+
say("create\t#{monit_file}")
|
32
|
+
FileUtils.touch(monit_file)
|
33
|
+
|
34
|
+
File.open(spec_file, "w") do |f|
|
35
|
+
f.write("---\nname: #{name}\ntemplates:\n\npackages:\n")
|
36
|
+
end
|
37
|
+
|
38
|
+
say("\nGenerated skeleton for `#{name}' job in `#{job_dir}'")
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::Cli::Command
|
4
|
+
class JobManagement < Base
|
5
|
+
include Bosh::Cli::DeploymentHelper
|
6
|
+
|
7
|
+
def start_job(*args)
|
8
|
+
change_job_state(:start, *args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def stop_job(*args)
|
12
|
+
change_job_state(:stop, *args)
|
13
|
+
end
|
14
|
+
|
15
|
+
def restart_job(*args)
|
16
|
+
change_job_state(:restart, *args)
|
17
|
+
end
|
18
|
+
|
19
|
+
def recreate_job(*args)
|
20
|
+
change_job_state(:recreate, *args)
|
21
|
+
end
|
22
|
+
|
23
|
+
def change_job_state(operation, *args)
|
24
|
+
auth_required
|
25
|
+
manifest_yaml = prepare_deployment_manifest(:yaml => true)
|
26
|
+
manifest = YAML.load(manifest_yaml)
|
27
|
+
|
28
|
+
unless [:start, :stop, :restart, :recreate].include?(operation)
|
29
|
+
err("Unknown operation `#{operation}': supported operations are " +
|
30
|
+
"`start', `stop', `restart', `recreate'")
|
31
|
+
end
|
32
|
+
|
33
|
+
args = args.dup
|
34
|
+
hard = args.delete("--hard")
|
35
|
+
soft = args.delete("--soft")
|
36
|
+
force = args.delete("--force")
|
37
|
+
|
38
|
+
if hard && soft
|
39
|
+
err("Cannot handle both --hard and --soft options, please choose one")
|
40
|
+
end
|
41
|
+
|
42
|
+
if operation != :stop && (hard || soft)
|
43
|
+
err("--hard and --soft options only make sense for `stop' operation")
|
44
|
+
end
|
45
|
+
|
46
|
+
job = args.shift
|
47
|
+
index = args.shift
|
48
|
+
deployment_desc = "`#{deployment.green}' to `#{target_name.green}'"
|
49
|
+
job_desc = index ? "#{job}(#{index})" : "#{job}"
|
50
|
+
|
51
|
+
case operation
|
52
|
+
when :start
|
53
|
+
op_desc = "start #{job_desc}"
|
54
|
+
new_state = "started"
|
55
|
+
completion_desc = "#{job_desc.green} has been started"
|
56
|
+
when :stop
|
57
|
+
if hard
|
58
|
+
op_desc = "stop #{job_desc} and power off its VM(s)"
|
59
|
+
completion_desc = "#{job_desc.green} has been stopped, " +
|
60
|
+
"VM(s) powered off"
|
61
|
+
new_state = "detached"
|
62
|
+
else
|
63
|
+
op_desc = "stop #{job_desc}"
|
64
|
+
completion_desc = "#{job_desc.green} has been stopped, " +
|
65
|
+
"VM(s) still running"
|
66
|
+
new_state = "stopped"
|
67
|
+
end
|
68
|
+
when :restart
|
69
|
+
op_desc = "restart #{job_desc}"
|
70
|
+
new_state = "restart"
|
71
|
+
completion_desc = "#{job_desc.green} has been restarted"
|
72
|
+
when :recreate
|
73
|
+
op_desc = "recreate #{job_desc}"
|
74
|
+
new_state = "recreate"
|
75
|
+
completion_desc = "#{job_desc.green} has been recreated"
|
76
|
+
end
|
77
|
+
|
78
|
+
say("You are about to #{op_desc.green}")
|
79
|
+
|
80
|
+
if interactive?
|
81
|
+
# TODO: refactor inspect_deployment_changes
|
82
|
+
# to decouple changeset structure and rendering
|
83
|
+
other_changes_present = inspect_deployment_changes(
|
84
|
+
manifest, :show_empty_changeset => false)
|
85
|
+
|
86
|
+
if other_changes_present && !force
|
87
|
+
err("Cannot perform job management when other deployment changes " +
|
88
|
+
"are present. Please use `--force' to override.")
|
89
|
+
end
|
90
|
+
unless confirmed?("#{op_desc.capitalize}?")
|
91
|
+
cancel_deployment
|
92
|
+
end
|
93
|
+
end
|
94
|
+
nl
|
95
|
+
|
96
|
+
say("Performing `#{op_desc}'...")
|
97
|
+
|
98
|
+
status, body = director.change_job_state(manifest["name"],
|
99
|
+
manifest_yaml,
|
100
|
+
job, index, new_state)
|
101
|
+
|
102
|
+
responses = {
|
103
|
+
:done => completion_desc,
|
104
|
+
:non_trackable => "Started deployment but director at '#{target}' " +
|
105
|
+
"doesn't support deployment tracking",
|
106
|
+
:track_timeout => "Started deployment but timed out out "+
|
107
|
+
"while tracking status",
|
108
|
+
:error => "Started deployment but received an error " +
|
109
|
+
"while tracking status",
|
110
|
+
:invalid => "Deployment is invalid, please fix it and deploy again"
|
111
|
+
}
|
112
|
+
|
113
|
+
say(responses[status] || "Cannot deploy: #{body}")
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::Cli::Command
|
4
|
+
class LogManagement < Base
|
5
|
+
include Bosh::Cli::DeploymentHelper
|
6
|
+
|
7
|
+
def fetch_logs(*args)
|
8
|
+
auth_required
|
9
|
+
target_required
|
10
|
+
|
11
|
+
job = args.shift
|
12
|
+
index = args.shift
|
13
|
+
filters = nil
|
14
|
+
|
15
|
+
for_job = args.delete("--job")
|
16
|
+
for_agent = args.delete("--agent")
|
17
|
+
|
18
|
+
if for_job && for_agent
|
19
|
+
err("Please specify which logs you want, job or agent")
|
20
|
+
elsif for_agent
|
21
|
+
log_type = "agent"
|
22
|
+
else # default log type is 'job'
|
23
|
+
log_type = "job"
|
24
|
+
end
|
25
|
+
|
26
|
+
if args.include?("--only")
|
27
|
+
pos = args.index("--only")
|
28
|
+
filters = args[pos+1]
|
29
|
+
if filters.nil?
|
30
|
+
err("Please provide a list of filters separated by comma")
|
31
|
+
end
|
32
|
+
args.delete("--only")
|
33
|
+
args.delete(filters)
|
34
|
+
elsif args.include?("--all")
|
35
|
+
args.delete("--all")
|
36
|
+
filters = "all"
|
37
|
+
end
|
38
|
+
|
39
|
+
if for_agent && !filters.nil? && filters != "all"
|
40
|
+
err("Custom filtering is not supported for agent logs")
|
41
|
+
end
|
42
|
+
|
43
|
+
if index !~ /^\d+$/
|
44
|
+
err("Job index is expected to be a positive integer")
|
45
|
+
end
|
46
|
+
|
47
|
+
if args.size > 0
|
48
|
+
err("Unknown arguments: #{args.join(", ")}")
|
49
|
+
end
|
50
|
+
|
51
|
+
manifest = prepare_deployment_manifest
|
52
|
+
|
53
|
+
resource_id = director.fetch_logs(manifest["name"], job, index,
|
54
|
+
log_type, filters)
|
55
|
+
|
56
|
+
if resource_id.nil?
|
57
|
+
err("Error retrieving logs")
|
58
|
+
end
|
59
|
+
|
60
|
+
nl
|
61
|
+
say("Downloading log bundle (#{resource_id.to_s.green})...")
|
62
|
+
|
63
|
+
begin
|
64
|
+
time = Time.now.strftime("%Y-%m-%d@%H-%M-%S")
|
65
|
+
log_file = File.join(Dir.pwd, "#{job}.#{index}.#{time}.tgz")
|
66
|
+
|
67
|
+
tmp_file = director.download_resource(resource_id)
|
68
|
+
|
69
|
+
FileUtils.mv(tmp_file, log_file)
|
70
|
+
say("Logs saved in `#{log_file.green}'")
|
71
|
+
rescue Bosh::Cli::DirectorError => e
|
72
|
+
err("Unable to download logs from director: #{e}")
|
73
|
+
ensure
|
74
|
+
FileUtils.rm_rf(tmp_file) if File.exists?(tmp_file)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::Cli::Command
|
4
|
+
class Maintenance < Base
|
5
|
+
include Bosh::Cli::VersionCalc
|
6
|
+
|
7
|
+
RELEASES_TO_KEEP = 2
|
8
|
+
STEMCELLS_TO_KEEP = 2
|
9
|
+
|
10
|
+
def cleanup
|
11
|
+
target_required
|
12
|
+
auth_required
|
13
|
+
|
14
|
+
releases_to_keep = RELEASES_TO_KEEP
|
15
|
+
stemcells_to_keep = STEMCELLS_TO_KEEP
|
16
|
+
|
17
|
+
release_wording = pluralize(releases_to_keep, "latest version")
|
18
|
+
stemcell_wording = pluralize(stemcells_to_keep, "latest version")
|
19
|
+
|
20
|
+
desc = <<-EOS.gsub(/^ */, "")
|
21
|
+
Cleanup command will attempt to delete old unused
|
22
|
+
release versions and stemcells from your currently
|
23
|
+
targeted director at #{target_name.green}.
|
24
|
+
|
25
|
+
Only #{release_wording.green} of each release
|
26
|
+
and #{stemcell_wording.green} of each stemcell will be kept.
|
27
|
+
|
28
|
+
Releases and stemcells that are in use will not be affected.
|
29
|
+
EOS
|
30
|
+
|
31
|
+
say("\n#{desc}\n")
|
32
|
+
|
33
|
+
err("Cleanup canceled") unless confirmed?
|
34
|
+
|
35
|
+
nl
|
36
|
+
cleanup_stemcells(stemcells_to_keep)
|
37
|
+
nl
|
38
|
+
cleanup_releases(releases_to_keep)
|
39
|
+
|
40
|
+
nl
|
41
|
+
say("Cleanup complete".green)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def cleanup_stemcells(n_to_keep)
|
47
|
+
stemcells_by_name = director.list_stemcells.inject({}) do |h, stemcell|
|
48
|
+
h[stemcell["name"]] ||= []
|
49
|
+
h[stemcell["name"]] << stemcell
|
50
|
+
h
|
51
|
+
end
|
52
|
+
|
53
|
+
delete_list = []
|
54
|
+
say("Deleting old stemcells")
|
55
|
+
|
56
|
+
stemcells_by_name.each_pair do |name, stemcells|
|
57
|
+
stemcells.sort! do |sc1, sc2|
|
58
|
+
version_cmp(sc1["version"], sc2["version"])
|
59
|
+
end
|
60
|
+
delete_list += stemcells[0...(-n_to_keep)]
|
61
|
+
end
|
62
|
+
|
63
|
+
if delete_list.size > 0
|
64
|
+
delete_list.each do |stemcell|
|
65
|
+
name, version = stemcell["name"], stemcell["version"]
|
66
|
+
desc = "#{name}/#{version}"
|
67
|
+
perform(desc) do
|
68
|
+
director.delete_stemcell(name, version, :quiet => true)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
else
|
72
|
+
say(" none found".yellow)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def cleanup_releases(n_to_keep)
|
77
|
+
delete_list = []
|
78
|
+
say("Deleting old release versions")
|
79
|
+
|
80
|
+
director.list_releases.each do |release|
|
81
|
+
name = release["name"]
|
82
|
+
versions = release["versions"].sort { |v1, v2| version_cmp(v1, v2) }
|
83
|
+
|
84
|
+
versions[0...(-n_to_keep)].each do |version|
|
85
|
+
delete_list << [name, version]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
if delete_list.size > 0
|
90
|
+
delete_list.each do |name, version|
|
91
|
+
desc = "#{name}/#{version}"
|
92
|
+
perform(desc) do
|
93
|
+
director.delete_release(name, :force => false,
|
94
|
+
:version => version, :quiet => true)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
else
|
98
|
+
say(" none found".yellow)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def refresh(message)
|
103
|
+
say("\r", "")
|
104
|
+
say(" " * 80, "")
|
105
|
+
say("\r#{message}", "")
|
106
|
+
end
|
107
|
+
|
108
|
+
def perform(desc)
|
109
|
+
say(" #{desc.yellow.ljust(40)}", "")
|
110
|
+
say("IN PROGRESS...".yellow, "")
|
111
|
+
|
112
|
+
status, task_id = yield
|
113
|
+
responses = {
|
114
|
+
:done => "DELETED".green,
|
115
|
+
:non_trackable => "CANNOT TRACK".red,
|
116
|
+
:track_timeout => "TIMED OUT".red,
|
117
|
+
:error => "ERROR".red,
|
118
|
+
}
|
119
|
+
|
120
|
+
refresh(" #{desc.yellow.ljust(40)}#{responses[status]}\n")
|
121
|
+
|
122
|
+
if status == :error
|
123
|
+
task = director.get_task(task_id)
|
124
|
+
say(" #{task["result"].red}")
|
125
|
+
end
|
126
|
+
|
127
|
+
status == :done
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|