cloulu 0.0.0 → 0.1.1
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/{cloulu → cl} +0 -0
- data/lib/cc_api_stub/applications.rb +53 -0
- data/lib/cc_api_stub/domains.rb +16 -0
- data/lib/cc_api_stub/frameworks.rb +22 -0
- data/lib/cc_api_stub/helper.rb +131 -0
- data/lib/cc_api_stub/login.rb +21 -0
- data/lib/cc_api_stub/organization_users.rb +21 -0
- data/lib/cc_api_stub/organizations.rb +70 -0
- data/lib/cc_api_stub/routes.rb +26 -0
- data/lib/cc_api_stub/runtimes.rb +22 -0
- data/lib/cc_api_stub/service_bindings.rb +22 -0
- data/lib/cc_api_stub/service_instances.rb +22 -0
- data/lib/cc_api_stub/services.rb +25 -0
- data/lib/cc_api_stub/spaces.rb +49 -0
- data/lib/cc_api_stub/users.rb +84 -0
- data/lib/cc_api_stub.rb +17 -0
- data/lib/cfoundry/auth_token.rb +63 -0
- data/lib/cfoundry/baseclient.rb +201 -0
- data/lib/cfoundry/chatty_hash.rb +46 -0
- data/lib/cfoundry/client.rb +46 -0
- data/lib/cfoundry/concerns/login_helpers.rb +13 -0
- data/lib/cfoundry/errors.rb +160 -0
- data/lib/cfoundry/rest_client.rb +299 -0
- data/lib/cfoundry/test_support.rb +3 -0
- data/lib/cfoundry/trace_helpers.rb +40 -0
- data/lib/cfoundry/uaaclient.rb +112 -0
- data/lib/cfoundry/upload_helpers.rb +187 -0
- data/lib/cfoundry/v1/app.rb +363 -0
- data/lib/cfoundry/v1/base.rb +72 -0
- data/lib/cfoundry/v1/client.rb +193 -0
- data/lib/cfoundry/v1/framework.rb +21 -0
- data/lib/cfoundry/v1/model.rb +178 -0
- data/lib/cfoundry/v1/model_magic.rb +129 -0
- data/lib/cfoundry/v1/runtime.rb +24 -0
- data/lib/cfoundry/v1/service.rb +39 -0
- data/lib/cfoundry/v1/service_instance.rb +32 -0
- data/lib/cfoundry/v1/service_plan.rb +19 -0
- data/lib/cfoundry/v1/user.rb +22 -0
- data/lib/cfoundry/v2/app.rb +392 -0
- data/lib/cfoundry/v2/base.rb +83 -0
- data/lib/cfoundry/v2/client.rb +138 -0
- data/lib/cfoundry/v2/domain.rb +11 -0
- data/lib/cfoundry/v2/framework.rb +14 -0
- data/lib/cfoundry/v2/model.rb +148 -0
- data/lib/cfoundry/v2/model_magic.rb +449 -0
- data/lib/cfoundry/v2/organization.rb +16 -0
- data/lib/cfoundry/v2/route.rb +15 -0
- data/lib/cfoundry/v2/runtime.rb +12 -0
- data/lib/cfoundry/v2/service.rb +19 -0
- data/lib/cfoundry/v2/service_auth_token.rb +9 -0
- data/lib/cfoundry/v2/service_binding.rb +10 -0
- data/lib/cfoundry/v2/service_instance.rb +14 -0
- data/lib/cfoundry/v2/service_plan.rb +12 -0
- data/lib/cfoundry/v2/space.rb +18 -0
- data/lib/cfoundry/v2/user.rb +64 -0
- data/lib/cfoundry/validator.rb +39 -0
- data/lib/cfoundry/version.rb +4 -0
- data/lib/cfoundry/zip.rb +56 -0
- data/lib/cfoundry.rb +2 -0
- data/lib/manifests-vmc-plugin/errors.rb +21 -0
- data/lib/manifests-vmc-plugin/loader/builder.rb +34 -0
- data/lib/manifests-vmc-plugin/loader/normalizer.rb +149 -0
- data/lib/manifests-vmc-plugin/loader/resolver.rb +79 -0
- data/lib/manifests-vmc-plugin/loader.rb +31 -0
- data/lib/manifests-vmc-plugin/plugin.rb +145 -0
- data/lib/manifests-vmc-plugin/version.rb +3 -0
- data/lib/manifests-vmc-plugin.rb +313 -0
- data/lib/mothership/base.rb +99 -0
- data/lib/mothership/callbacks.rb +85 -0
- data/lib/mothership/command.rb +146 -0
- data/lib/mothership/errors.rb +38 -0
- data/lib/mothership/help/commands.rb +53 -0
- data/lib/mothership/help/printer.rb +170 -0
- data/lib/mothership/help.rb +64 -0
- data/lib/mothership/inputs.rb +189 -0
- data/lib/mothership/parser.rb +182 -0
- data/lib/mothership/version.rb +3 -0
- data/lib/mothership.rb +64 -0
- data/lib/tunnel-vmc-plugin/plugin.rb +178 -0
- data/lib/tunnel-vmc-plugin/tunnel.rb +308 -0
- data/lib/tunnel-vmc-plugin/version.rb +3 -0
- data/lib/uaa/http.rb +168 -0
- data/lib/uaa/misc.rb +121 -0
- data/lib/uaa/scim.rb +292 -0
- data/lib/uaa/token_coder.rb +196 -0
- data/lib/uaa/token_issuer.rb +255 -0
- data/lib/uaa/util.rb +235 -0
- data/lib/uaa/version.rb +19 -0
- data/lib/uaa.rb +18 -0
- data/lib/vmc/cli/app/app.rb +45 -0
- data/lib/vmc/cli/app/apps.rb +99 -0
- data/lib/vmc/cli/app/base.rb +90 -0
- data/lib/vmc/cli/app/crashes.rb +42 -0
- data/lib/vmc/cli/app/delete.rb +95 -0
- data/lib/vmc/cli/app/deprecated.rb +11 -0
- data/lib/vmc/cli/app/env.rb +78 -0
- data/lib/vmc/cli/app/files.rb +137 -0
- data/lib/vmc/cli/app/health.rb +26 -0
- data/lib/vmc/cli/app/instances.rb +53 -0
- data/lib/vmc/cli/app/logs.rb +76 -0
- data/lib/vmc/cli/app/push/create.rb +165 -0
- data/lib/vmc/cli/app/push/interactions.rb +94 -0
- data/lib/vmc/cli/app/push/sync.rb +64 -0
- data/lib/vmc/cli/app/push.rb +109 -0
- data/lib/vmc/cli/app/rename.rb +35 -0
- data/lib/vmc/cli/app/restart.rb +20 -0
- data/lib/vmc/cli/app/scale.rb +71 -0
- data/lib/vmc/cli/app/start.rb +143 -0
- data/lib/vmc/cli/app/stats.rb +67 -0
- data/lib/vmc/cli/app/stop.rb +27 -0
- data/lib/vmc/cli/help.rb +11 -0
- data/lib/vmc/cli/interactive.rb +105 -0
- data/lib/vmc/cli/route/base.rb +12 -0
- data/lib/vmc/cli/route/map.rb +82 -0
- data/lib/vmc/cli/route/routes.rb +25 -0
- data/lib/vmc/cli/route/unmap.rb +94 -0
- data/lib/vmc/cli/service/base.rb +8 -0
- data/lib/vmc/cli/service/bind.rb +44 -0
- data/lib/vmc/cli/service/create.rb +126 -0
- data/lib/vmc/cli/service/delete.rb +86 -0
- data/lib/vmc/cli/service/rename.rb +35 -0
- data/lib/vmc/cli/service/service.rb +42 -0
- data/lib/vmc/cli/service/services.rb +114 -0
- data/lib/vmc/cli/service/unbind.rb +38 -0
- data/lib/vmc/cli/start/base.rb +94 -0
- data/lib/vmc/cli/start/colors.rb +13 -0
- data/lib/vmc/cli/start/info.rb +126 -0
- data/lib/vmc/cli/start/login.rb +97 -0
- data/lib/vmc/cli/start/logout.rb +17 -0
- data/lib/vmc/cli/start/target.rb +60 -0
- data/lib/vmc/cli/start/target_interactions.rb +37 -0
- data/lib/vmc/cli/start/targets.rb +16 -0
- data/lib/vmc/cli/user/base.rb +29 -0
- data/lib/vmc/cli/user/create.rb +39 -0
- data/lib/vmc/cli/user/delete.rb +27 -0
- data/lib/vmc/cli/user/passwd.rb +50 -0
- data/lib/vmc/cli/user/register.rb +42 -0
- data/lib/vmc/cli/user/users.rb +32 -0
- data/lib/vmc/cli/v2_check_cli.rb +16 -0
- data/lib/vmc/cli.rb +474 -0
- data/lib/vmc/constants.rb +13 -0
- data/lib/vmc/detect.rb +129 -0
- data/lib/vmc/errors.rb +19 -0
- data/lib/vmc/plugin.rb +56 -0
- data/lib/vmc/spacing.rb +89 -0
- data/lib/vmc/spec_helper.rb +1 -0
- data/lib/vmc/test_support.rb +6 -0
- data/lib/vmc/version.rb +3 -0
- data/lib/vmc.rb +8 -0
- data/vendor/errors/v1.yml +189 -0
- data/vendor/errors/v2.yml +360 -0
- metadata +303 -190
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require "vmc/cli/app/base"
|
|
2
|
+
|
|
3
|
+
module VMC::App
|
|
4
|
+
class Instances < Base
|
|
5
|
+
desc "List an app's instances"
|
|
6
|
+
group :apps, :info
|
|
7
|
+
input :apps, :desc => "Applications whose instances to list",
|
|
8
|
+
:argument => :splat, :singular => :app,
|
|
9
|
+
:from_given => by_name(:app)
|
|
10
|
+
def instances
|
|
11
|
+
apps = input[:apps]
|
|
12
|
+
fail "No applications given." if apps.empty?
|
|
13
|
+
|
|
14
|
+
spaced(apps) do |app|
|
|
15
|
+
instances =
|
|
16
|
+
with_progress("Getting instances for #{c(app.name, :name)}") do
|
|
17
|
+
app.instances
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
line unless quiet?
|
|
21
|
+
|
|
22
|
+
spaced(instances.sort { |a, b| a.id.to_i <=> b.id.to_i }) do |i|
|
|
23
|
+
if quiet?
|
|
24
|
+
line i.id
|
|
25
|
+
else
|
|
26
|
+
display_instance(i)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def display_instance(i)
|
|
35
|
+
start_line "instance #{c("\##{i.id}", :instance)}: "
|
|
36
|
+
puts "#{b(c(i.state.downcase, state_color(i.state)))}"
|
|
37
|
+
|
|
38
|
+
indented do
|
|
39
|
+
if s = i.since
|
|
40
|
+
line "started: #{c(s.strftime("%F %r"), :neutral)}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if d = i.debugger
|
|
44
|
+
line "debugger: port #{b(d[:port])} at #{b(d[:ip])}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
if c = i.console
|
|
48
|
+
line "console: port #{b(c[:port])} at #{b(c[:ip])}"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require "vmc/cli/app/base"
|
|
2
|
+
|
|
3
|
+
module VMC::App
|
|
4
|
+
class Logs < Base
|
|
5
|
+
desc "Print out an app's logs"
|
|
6
|
+
group :apps, :info
|
|
7
|
+
input :app, :desc => "Application to get the logs of", :argument => true,
|
|
8
|
+
:from_given => by_name(:app)
|
|
9
|
+
input :instance, :desc => "Instance of application to get the logs of",
|
|
10
|
+
:default => "0"
|
|
11
|
+
input :all, :desc => "Get logs for every instance", :default => false
|
|
12
|
+
def logs
|
|
13
|
+
app = input[:app]
|
|
14
|
+
|
|
15
|
+
instances =
|
|
16
|
+
if input[:all] || input[:instance] == "all"
|
|
17
|
+
app.instances
|
|
18
|
+
else
|
|
19
|
+
app.instances.select { |i| i.id == input[:instance] }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
if instances.empty?
|
|
23
|
+
if input[:all]
|
|
24
|
+
fail "No instances found."
|
|
25
|
+
else
|
|
26
|
+
fail "Instance #{app.name} \##{input[:instance]} not found."
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
spaced(instances) do |i|
|
|
31
|
+
show_instance_logs(app, i)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
desc "Print out the logs for an app's crashed instances"
|
|
36
|
+
group :apps, :info, :hidden => true
|
|
37
|
+
input :app, :desc => "Application to get the logs of", :argument => true,
|
|
38
|
+
:from_given => by_name(:app)
|
|
39
|
+
def crashlogs
|
|
40
|
+
app = input[:app]
|
|
41
|
+
|
|
42
|
+
crashes = app.crashes
|
|
43
|
+
|
|
44
|
+
fail "No crashed instances found." if crashes.empty?
|
|
45
|
+
|
|
46
|
+
most_recent = crashes.sort_by(&:since).last
|
|
47
|
+
show_instance_logs(app, most_recent)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def show_instance_logs(app, i)
|
|
51
|
+
return unless i.id
|
|
52
|
+
|
|
53
|
+
logs =
|
|
54
|
+
with_progress(
|
|
55
|
+
"Getting logs for #{c(app.name, :name)} " +
|
|
56
|
+
c("\##{i.id}", :instance)) do
|
|
57
|
+
i.files("logs")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
line unless quiet?
|
|
61
|
+
|
|
62
|
+
spaced(logs) do |log|
|
|
63
|
+
begin
|
|
64
|
+
body =
|
|
65
|
+
with_progress("Reading " + b(log.join("/"))) do |s|
|
|
66
|
+
i.file(*log)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
lines body
|
|
70
|
+
line unless body.empty?
|
|
71
|
+
rescue CFoundry::NotFound
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
require "vmc/detect"
|
|
2
|
+
|
|
3
|
+
module VMC::App
|
|
4
|
+
module Create
|
|
5
|
+
attr_accessor :input
|
|
6
|
+
attr_writer :path
|
|
7
|
+
|
|
8
|
+
def get_inputs
|
|
9
|
+
inputs = {}
|
|
10
|
+
inputs[:name] = input[:name]
|
|
11
|
+
inputs[:total_instances] = input[:instances]
|
|
12
|
+
inputs[:space] = client.current_space if client.current_space
|
|
13
|
+
|
|
14
|
+
if v2?
|
|
15
|
+
inputs[:production] = !!(input[:plan] =~ /^p/i)
|
|
16
|
+
inputs[:command] = input[:command] if input.has?(:command) || !has_procfile?
|
|
17
|
+
else
|
|
18
|
+
framework = inputs[:framework] = determine_framework
|
|
19
|
+
inputs[:runtime] = determine_runtime(framework)
|
|
20
|
+
inputs[:command] = input[:command] if can_have_custom_start_command?(framework)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
inputs[:buildpack] = input[:buildpack] if v2?
|
|
24
|
+
|
|
25
|
+
if v2?
|
|
26
|
+
detected = detector.detected
|
|
27
|
+
human_mb = human_mb((detected && detected.memory_suggestion) || 64)
|
|
28
|
+
else
|
|
29
|
+
human_mb = human_mb(detector.suggested_memory(framework) || 64)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
inputs[:memory] = megabytes(input[:memory, human_mb])
|
|
33
|
+
|
|
34
|
+
inputs[:stack] = input[:stack] if v2?
|
|
35
|
+
|
|
36
|
+
inputs
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def determine_framework
|
|
40
|
+
return input[:framework] if input.has?(:framework)
|
|
41
|
+
|
|
42
|
+
if (detected_framework = detector.detect_framework)
|
|
43
|
+
input[:framework, [detected_framework], detected_framework, :other]
|
|
44
|
+
else
|
|
45
|
+
input[:framework, detector.all_frameworks, nil, nil]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def determine_runtime(framework)
|
|
50
|
+
return input[:runtime] if input.has?(:runtime)
|
|
51
|
+
|
|
52
|
+
detected_runtimes =
|
|
53
|
+
if framework.name == "standalone"
|
|
54
|
+
detector.detect_runtimes
|
|
55
|
+
else
|
|
56
|
+
detector.runtimes(framework)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
default_runtime = detected_runtimes.size == 1 ? detected_runtimes.first : nil
|
|
60
|
+
|
|
61
|
+
if detected_runtimes.empty?
|
|
62
|
+
input[:runtime, detector.all_runtimes, nil, nil]
|
|
63
|
+
else
|
|
64
|
+
input[:runtime, detected_runtimes, default_runtime, :other]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def create_app(inputs)
|
|
69
|
+
fail "appname should be at least five characters in length." if inputs[:name].length < 5
|
|
70
|
+
|
|
71
|
+
app = client.app
|
|
72
|
+
|
|
73
|
+
inputs.each { |key, value| app.send(:"#{key}=", value) }
|
|
74
|
+
|
|
75
|
+
app = filter(:create_app, app)
|
|
76
|
+
|
|
77
|
+
with_progress("Creating #{c(app.name, :name)}") do
|
|
78
|
+
wrap_message_format_errors do
|
|
79
|
+
begin
|
|
80
|
+
app.create!
|
|
81
|
+
rescue CFoundry::NotAuthorized
|
|
82
|
+
fail "You need the Project Developer role in #{b(client.current_space.name)} to push."
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
app
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def map_route(app)
|
|
91
|
+
line unless quiet?
|
|
92
|
+
|
|
93
|
+
host = input[:host, app.name] if v2?
|
|
94
|
+
domain = input[:domain, app]
|
|
95
|
+
|
|
96
|
+
mapped_url = false
|
|
97
|
+
until domain == "none" || !domain || mapped_url
|
|
98
|
+
begin
|
|
99
|
+
host = "" if host == "none"
|
|
100
|
+
invoke :map, :app => app, :host => host, :domain => domain
|
|
101
|
+
mapped_url = true
|
|
102
|
+
rescue CFoundry::RouteHostTaken, CFoundry::UriAlreadyTaken => e
|
|
103
|
+
raise if force?
|
|
104
|
+
|
|
105
|
+
line c(e.description, :bad)
|
|
106
|
+
line
|
|
107
|
+
|
|
108
|
+
input.forget(:host) if v2?
|
|
109
|
+
input.forget(:domain)
|
|
110
|
+
|
|
111
|
+
host = input[:host, app.name] if v2?
|
|
112
|
+
domain = input[:domain, app]
|
|
113
|
+
|
|
114
|
+
# version bumps on v1 even though mapping fails
|
|
115
|
+
app.invalidate! unless v2?
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def create_services(app)
|
|
121
|
+
return unless input[:create_services]
|
|
122
|
+
|
|
123
|
+
while true
|
|
124
|
+
invoke :create_service, { :app => app }, :plan => :interact
|
|
125
|
+
break unless ask("Create another service?", :default => false)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def bind_services(app)
|
|
130
|
+
return unless input[:bind_services]
|
|
131
|
+
|
|
132
|
+
while true
|
|
133
|
+
invoke :bind_service, :app => app
|
|
134
|
+
break if (all_instances - app.services).empty?
|
|
135
|
+
break unless ask("Bind another service?", :default => false)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def start_app(app)
|
|
140
|
+
invoke :start, :app => app if input[:start]
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
private
|
|
144
|
+
|
|
145
|
+
def has_procfile?
|
|
146
|
+
File.exists?("#@path/Procfile")
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def can_have_custom_start_command?(framework)
|
|
150
|
+
framework.name == "standalone"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def all_instances
|
|
154
|
+
@all_instances ||= client.service_instances
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def detector
|
|
158
|
+
@detector ||= VMC::Detector.new(client, @path)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def target_base
|
|
162
|
+
client.target.sub(/^https?:\/\/([^\.]+\.)?(.+)\/?/, '\2')
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
module VMC::App
|
|
2
|
+
module PushInteractions
|
|
3
|
+
def ask_name
|
|
4
|
+
ask("Name")
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def ask_host(name)
|
|
8
|
+
ask "Subdomain", :choices => [name, "none"],
|
|
9
|
+
:default => name,
|
|
10
|
+
:allow_other => true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def ask_domain(app)
|
|
14
|
+
choices = v2? ? app.space.domains : ["#{app.name}.#{target_base}"]
|
|
15
|
+
|
|
16
|
+
options = {
|
|
17
|
+
:choices => choices + ["none"],
|
|
18
|
+
:display => proc { |d| d.is_a?(String) ? d : d.name },
|
|
19
|
+
:allow_other => true
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
options[:default] = choices.first if choices.size == 1
|
|
23
|
+
|
|
24
|
+
ask "Domain", options
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def ask_memory(default)
|
|
28
|
+
ask("Memory Limit",
|
|
29
|
+
:choices => memory_choices,
|
|
30
|
+
:allow_other => true,
|
|
31
|
+
:default => default || "64M")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def ask_instances
|
|
35
|
+
ask("Instances", :default => 1)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def ask_framework(choices, default, other)
|
|
39
|
+
ask_with_other("Framework", client.frameworks, choices, default, other)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def ask_runtime(choices, default, other)
|
|
43
|
+
ask_with_other("Runtime", client.runtimes, choices, default, other)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def ask_command
|
|
47
|
+
command = ask("Custom startup command", :default => "none")
|
|
48
|
+
|
|
49
|
+
if command != "none"
|
|
50
|
+
command
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def ask_create_services
|
|
55
|
+
line unless quiet?
|
|
56
|
+
ask "Create services for application?", :default => false
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def ask_bind_services
|
|
60
|
+
return if all_instances.empty?
|
|
61
|
+
|
|
62
|
+
ask "Bind other services to application?", :default => false
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def ask_with_other(message, all, choices, default, other)
|
|
68
|
+
choices = choices.sort_by(&:name)
|
|
69
|
+
choices << other if other
|
|
70
|
+
|
|
71
|
+
opts = {
|
|
72
|
+
:choices => choices,
|
|
73
|
+
:display => proc { |x|
|
|
74
|
+
if other && x == other
|
|
75
|
+
"other"
|
|
76
|
+
else
|
|
77
|
+
x.name
|
|
78
|
+
end
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
opts[:default] = default if default
|
|
83
|
+
|
|
84
|
+
res = ask(message, opts)
|
|
85
|
+
|
|
86
|
+
if other && res == other
|
|
87
|
+
opts[:choices] = all
|
|
88
|
+
res = ask(message, opts)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
res
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module VMC::App
|
|
2
|
+
module Sync
|
|
3
|
+
def apply_changes(app)
|
|
4
|
+
app.memory = megabytes(input[:memory]) if input.has?(:memory)
|
|
5
|
+
app.total_instances = input[:instances] if input.has?(:instances)
|
|
6
|
+
app.command = input[:command] if input.has?(:command)
|
|
7
|
+
app.production = input[:plan].upcase.start_with?("P") if input.has?(:plan)
|
|
8
|
+
app.framework = input[:framework] if input.has?(:framework)
|
|
9
|
+
app.runtime = input[:runtime] if input.has?(:runtime)
|
|
10
|
+
app.buildpack = input[:buildpack] if input.has?(:buildpack)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def display_changes(app)
|
|
14
|
+
return unless app.changed?
|
|
15
|
+
|
|
16
|
+
line "Changes:"
|
|
17
|
+
|
|
18
|
+
indented do
|
|
19
|
+
app.changes.each do |attr, (old, new)|
|
|
20
|
+
line "#{c(attr, :name)}: #{diff_str(attr, old)} -> #{diff_str(attr, new)}"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def commit_changes(app)
|
|
26
|
+
if app.changed?
|
|
27
|
+
with_progress("Updating #{c(app.name, :name)}") do
|
|
28
|
+
wrap_message_format_errors do
|
|
29
|
+
app.update!
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
if input[:restart] && app.started?
|
|
35
|
+
invoke :restart, :app => app
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def diff_str(attr, val)
|
|
42
|
+
case attr
|
|
43
|
+
when :memory
|
|
44
|
+
human_mb(val)
|
|
45
|
+
when :framework, :runtime
|
|
46
|
+
val.name
|
|
47
|
+
when :command, :buildpack
|
|
48
|
+
"'#{val}'"
|
|
49
|
+
when :production
|
|
50
|
+
bool(val)
|
|
51
|
+
else
|
|
52
|
+
val
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def bool(b)
|
|
57
|
+
if b
|
|
58
|
+
c("true", :yes)
|
|
59
|
+
else
|
|
60
|
+
c("false", :no)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
require "vmc/cli/app/base"
|
|
2
|
+
require "vmc/cli/app/push/sync"
|
|
3
|
+
require "vmc/cli/app/push/create"
|
|
4
|
+
require "vmc/cli/app/push/interactions"
|
|
5
|
+
|
|
6
|
+
module VMC::App
|
|
7
|
+
class Push < Base
|
|
8
|
+
include Sync
|
|
9
|
+
include Create
|
|
10
|
+
|
|
11
|
+
desc "Push an application, syncing changes if it exists"
|
|
12
|
+
group :apps, :manage
|
|
13
|
+
input :name, :desc => "Application name", :argument => :optional
|
|
14
|
+
input :path, :desc => "Path containing the bits", :default => "."
|
|
15
|
+
input :host, :desc => "Subdomain for the app's URL"
|
|
16
|
+
input :domain, :desc => "Domain for the app",
|
|
17
|
+
:from_given => proc { |given, app|
|
|
18
|
+
if !v2? || given == "none"
|
|
19
|
+
given
|
|
20
|
+
else
|
|
21
|
+
app.space.domain_by_name(given) ||
|
|
22
|
+
fail_unknown("domain", given)
|
|
23
|
+
end
|
|
24
|
+
}
|
|
25
|
+
input :memory, :desc => "Memory limit"
|
|
26
|
+
input :instances, :desc => "Number of instances to run", :type => :integer
|
|
27
|
+
input :framework, :desc => "Framework to use",
|
|
28
|
+
:from_given => by_name(:framework)
|
|
29
|
+
input :runtime, :desc => "Runtime to use",
|
|
30
|
+
:from_given => by_name(:runtime)
|
|
31
|
+
input :command, :desc => "Startup command"
|
|
32
|
+
input :plan, :desc => "Application plan", :default => "D100"
|
|
33
|
+
input :start, :desc => "Start app after pushing?", :default => true
|
|
34
|
+
input :restart, :desc => "Restart app after updating?", :default => true
|
|
35
|
+
input :buildpack, :desc => "Custom buildpack URL", :default => nil
|
|
36
|
+
input :stack, :desc => "Stack to use", :default => nil,
|
|
37
|
+
:from_given => by_name(:stack)
|
|
38
|
+
input :create_services, :desc => "Interactively create services?",
|
|
39
|
+
:type => :boolean, :default => proc { force? ? false : interact }
|
|
40
|
+
input :bind_services, :desc => "Interactively bind services?",
|
|
41
|
+
:type => :boolean, :default => proc { force? ? false : interact }
|
|
42
|
+
interactions PushInteractions
|
|
43
|
+
|
|
44
|
+
def push
|
|
45
|
+
name = input[:name]
|
|
46
|
+
path = File.expand_path(input[:path])
|
|
47
|
+
app = client.app_by_name(name)
|
|
48
|
+
|
|
49
|
+
if app
|
|
50
|
+
sync_app(app, path)
|
|
51
|
+
else
|
|
52
|
+
setup_new_app(path)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def sync_app(app, path)
|
|
57
|
+
upload_app(app, path)
|
|
58
|
+
apply_changes(app)
|
|
59
|
+
display_changes(app)
|
|
60
|
+
commit_changes(app)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def setup_new_app(path)
|
|
64
|
+
self.path = path
|
|
65
|
+
app = create_app(get_inputs)
|
|
66
|
+
map_route(app)
|
|
67
|
+
create_services(app)
|
|
68
|
+
bind_services(app)
|
|
69
|
+
upload_app(app, path)
|
|
70
|
+
start_app(app)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def url_choices(name)
|
|
76
|
+
if v2?
|
|
77
|
+
client.current_space.domains.sort_by(&:name).collect do |d|
|
|
78
|
+
# TODO: check availability
|
|
79
|
+
"#{name}.#{d.name}"
|
|
80
|
+
end
|
|
81
|
+
else
|
|
82
|
+
%W(#{name}.#{target_base})
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def upload_app(app, path)
|
|
87
|
+
app = filter(:push_app, app)
|
|
88
|
+
|
|
89
|
+
with_progress("Uploading #{c(app.name, :name)}") do
|
|
90
|
+
app.upload(path)
|
|
91
|
+
end
|
|
92
|
+
rescue
|
|
93
|
+
err "Upload failed. Try again with 'vmc push'."
|
|
94
|
+
raise
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def wrap_message_format_errors
|
|
98
|
+
yield
|
|
99
|
+
rescue CFoundry::MessageParseError => e
|
|
100
|
+
md = e.description.match /Field: ([^,]+)/
|
|
101
|
+
field = md[1]
|
|
102
|
+
|
|
103
|
+
case field
|
|
104
|
+
when "buildpack"
|
|
105
|
+
fail "Buildpack must be a public git repository URI."
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require "vmc/cli/app/base"
|
|
2
|
+
|
|
3
|
+
module VMC::App
|
|
4
|
+
class Rename < Base
|
|
5
|
+
desc "Rename an application"
|
|
6
|
+
group :apps, :manage, :hidden => true
|
|
7
|
+
input :app, :desc => "Application to rename", :argument => :optional,
|
|
8
|
+
:from_given => by_name(:app)
|
|
9
|
+
input :name, :desc => "New application name", :argument => :optional
|
|
10
|
+
def rename
|
|
11
|
+
app = input[:app]
|
|
12
|
+
name = input[:name]
|
|
13
|
+
|
|
14
|
+
app.name = name
|
|
15
|
+
|
|
16
|
+
with_progress("Renaming to #{c(name, :name)}") do
|
|
17
|
+
app.update!
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def ask_app
|
|
24
|
+
apps = client.apps
|
|
25
|
+
fail "No applications." if apps.empty?
|
|
26
|
+
|
|
27
|
+
ask("Rename which application?", :choices => apps.sort_by(&:name),
|
|
28
|
+
:display => proc(&:name))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def ask_name
|
|
32
|
+
ask("New name")
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require "vmc/cli/app/base"
|
|
2
|
+
|
|
3
|
+
module VMC::App
|
|
4
|
+
class Restart < Base
|
|
5
|
+
desc "Stop and start an application"
|
|
6
|
+
group :apps, :manage
|
|
7
|
+
input :apps, :desc => "Applications to start", :argument => :splat,
|
|
8
|
+
:singular => :app, :from_given => by_name(:app)
|
|
9
|
+
input :debug_mode, :desc => "Debug mode to start in", :aliases => "-d"
|
|
10
|
+
input :all, :desc => "Restart all applications", :default => false
|
|
11
|
+
def restart
|
|
12
|
+
invoke :stop, :all => input[:all], :apps => input[:apps]
|
|
13
|
+
|
|
14
|
+
line unless quiet?
|
|
15
|
+
|
|
16
|
+
invoke :start, :all => input[:all], :apps => input[:apps],
|
|
17
|
+
:debug_mode => input[:debug_mode]
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require "vmc/cli/app/base"
|
|
2
|
+
|
|
3
|
+
module VMC::App
|
|
4
|
+
class Scale < Base
|
|
5
|
+
desc "Update the instances/memory limit for an application"
|
|
6
|
+
group :apps, :info
|
|
7
|
+
input :app, :desc => "Application to update", :argument => true,
|
|
8
|
+
:from_given => by_name(:app)
|
|
9
|
+
input :instances, :desc => "Number of instances to run",
|
|
10
|
+
:type => :numeric
|
|
11
|
+
input :memory, :desc => "Memory limit"
|
|
12
|
+
input :disk, :desc => "Disk quota"
|
|
13
|
+
input :plan, :desc => "Application plan", :default => "D100"
|
|
14
|
+
input :restart, :desc => "Restart app after updating?", :default => true
|
|
15
|
+
def scale
|
|
16
|
+
app = input[:app]
|
|
17
|
+
|
|
18
|
+
if input.has?(:instances)
|
|
19
|
+
instances = input[:instances, app.total_instances]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
if input.has?(:memory)
|
|
23
|
+
memory = input[:memory, app.memory]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
if input.has?(:disk)
|
|
27
|
+
disk = input[:disk, human_mb(app.disk_quota)]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
if input.has?(:plan)
|
|
31
|
+
fail "Plans not supported on target cloud." unless v2?
|
|
32
|
+
|
|
33
|
+
plan_name = input[:plan]
|
|
34
|
+
production = !!(plan_name =~ /^p/i)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
unless instances || memory || disk || plan_name
|
|
38
|
+
instances = input[:instances, app.total_instances]
|
|
39
|
+
memory = input[:memory, app.memory]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
app.total_instances = instances if input.has?(:instances)
|
|
43
|
+
app.memory = megabytes(memory) if input.has?(:memory)
|
|
44
|
+
app.disk_quota = megabytes(disk) if input.has?(:disk)
|
|
45
|
+
app.production = production if input.has?(:plan)
|
|
46
|
+
|
|
47
|
+
fail "No changes!" unless app.changed?
|
|
48
|
+
|
|
49
|
+
with_progress("Scaling #{c(app.name, :name)}") do
|
|
50
|
+
app.update!
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
needs_restart = app.changes.key?(:memory) || app.changes.key?(:disk_quota)
|
|
54
|
+
|
|
55
|
+
if needs_restart && app.started? && input[:restart]
|
|
56
|
+
invoke :restart, :app => app
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def ask_instances(default)
|
|
63
|
+
ask("Instances", :default => default)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def ask_memory(default)
|
|
67
|
+
ask("Memory Limit", :choices => memory_choices(default),
|
|
68
|
+
:default => human_mb(default), :allow_other => true)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|