vmc-ng/lib/vmc/cli/service.rb in vmc-0.4.0.beta.21 vs vmc-ng/lib/vmc/cli/service.rb in vmc-0.4.0.beta.22
- old
+ new
@@ -1,10 +1,24 @@
require "vmc/cli"
module VMC
class Service < CLI
- desc "List your services"
+ def self.find_by_name(what)
+ proc { |name, choices|
+ choices.find { |c| c.name == name } ||
+ fail("Unknown #{what} '#{name}'")
+ }
+ end
+
+ def self.by_name(what, obj = what)
+ proc { |name, *_|
+ client.send(:"#{obj}_by_name", name) ||
+ fail("Unknown #{what} '#{name}'")
+ }
+ end
+
+ desc "List your service instances"
group :services
input :name, :desc => "Filter by name regexp"
input :app, :desc => "Filter by bound application regexp"
input :service, :desc => "Filter by service regexp"
# TODO: not in v2
@@ -28,14 +42,10 @@
services_from_label = proc { |label, services|
services.select { |s| s.label == label }
}
- plan_from_name = proc { |name, plans|
- plans.find { |p| p.name == name }
- }
-
desc "Create a service"
group :services, :manage
input(:service, :argument => true,
:desc => "What kind of service (e.g. redis, mysql)",
:from_given => services_from_label) { |services|
@@ -53,31 +63,37 @@
:desc => "Name for your instance") { |service|
random = sprintf("%x", rand(1000000))
ask "Name?", :default => "#{service.label}-#{random}"
}
input(:plan, :desc => "Service plan",
- :from_given => plan_from_name) { |plans|
+ :from_given => find_by_name("plan")) { |plans|
if d100 = plans.find { |p| p.name == "D100" }
d100
else
ask "Which plan?", :choices => plans.sort_by(&:name),
:display => proc { |p| "#{p.name}: #{p.description}" },
:complete => proc(&:name)
end
}
input :provider, :desc => "Service provider"
- input :bind, :alias => "--app",
+ input :version, :desc => "Service version"
+ input :app, :alias => "--bind", :from_given => by_name("app"),
:desc => "Application to immediately bind to"
def create_service(input)
services = client.services
if input[:provider]
services.reject! { |s| s.provider != input[:provider] }
end
+ if input[:version]
+ services.reject! { |s| s.version != input[:version] }
+ end
+
until services.size < 2
- services = input[:service, services]
+ # cast to Array since it might be given as a Service with #invoke
+ services = Array(input[:service, services])
input.forget(:service)
end
if services.empty?
fail "Cannot find services matching the given criteria."
@@ -101,91 +117,113 @@
with_progress("Creating service #{c(instance.name, :name)}") do
instance.create!
end
- if app = input[:bind]
- invoke :bind_service, :name => instance.name, :app => app
+ if app = input[:app]
+ invoke :bind_service, :instance => instance, :app => app
end
instance
end
- desc "Bind a service to an application"
+ desc "Bind a service instance to an application"
group :services, :manage
- input(:name, :argument => true,
- :desc => "Service to bind") { |choices|
- ask "Which service?", :choices => choices
+ input(:instance, :argument => true,
+ :from_given => by_name("instance", :service_instance),
+ :desc => "Service to bind") { |app|
+ instances = client.service_instances
+ fail "No service instances." if instances.empty?
+
+ ask "Which service instance?",
+ :choices => instances - app.services,
+ :display => proc(&:name)
}
input(:app, :argument => true,
- :desc => "Application to bind to") { |choices|
- ask "Which application?", :choices => choices
+ :from_given => by_name("app"),
+ :desc => "Application to bind to") {
+ ask "Which application?", :choices => client.apps(2),
+ :display => proc(&:name)
}
def bind_service(input)
- name = input[:name, client.service_instances.collect(&:name)]
- appname = input[:app, client.apps.collect(&:name)]
+ app = input[:app]
+ instance = input[:instance, app]
- with_progress("Binding #{c(name, :name)} to #{c(appname, :name)}") do
- client.app_by_name(appname).bind(name)
+ with_progress(
+ "Binding #{c(instance.name, :name)} to #{c(app.name, :name)}") do
+ app.bind(instance)
end
end
desc "Unbind a service from an application"
group :services, :manage
- input(:name, :argument => true,
- :desc => "Service to unbind") { |choices|
- ask "Which service?", :choices => choices
+ input(:instance, :argument => true,
+ :from_given => find_by_name("instance"),
+ :desc => "Service to bind") { |instances|
+ ask "Which service instance?", :choices => instances,
+ :display => proc(&:name)
}
input(:app, :argument => true,
- :desc => "Application to unbind from") { |choices|
- ask "Which application?", :choices => choices
+ :from_given => find_by_name("app"),
+ :desc => "Application to bind to") { |apps|
+ ask "Which application?", :choices => apps,
+ :display => proc(&:name)
}
def unbind_service(input)
- appname = input[:app, client.apps.collect(&:name)]
+ app = input[:app, client.apps(2)]
+ instance = input[:instance, app.services]
- app = client.app_by_name(appname)
- name = input[:name, app.services]
-
- with_progress("Unbinding #{c(name, :name)} from #{c(appname, :name)}") do
- app.unbind(name)
+ with_progress(
+ "Unbinding #{c(instance.name, :name)} from #{c(app.name, :name)}") do
+ app.unbind(instance)
end
end
desc "Delete a service"
group :services, :manage
- input(:name, :argument => true,
- :desc => "Service to delete") { |choices|
- ask "Delete which service?", :choices => choices
+ input(:instance, :argument => true,
+ :from_given => find_by_name("instance"),
+ :desc => "Service to bind") { |instances|
+ ask "Which service instance?", :choices => instances,
+ :display => proc(&:name)
}
input(:really, :type => :boolean, :forget => true) { |name, color|
force? || ask("Really delete #{c(name, color)}?", :default => false)
}
input :all, :default => false, :desc => "Delete all services"
def delete_service(input)
if input[:all]
return unless input[:really, "ALL SERVICES", :bad]
- with_progress("Deleting all services") do
- client.service_instances.collect(&:delete!)
+ client.service_instances.each do |i|
+ invoke :delete_service, :instance => i, :really => true
end
return
end
instances = client.service_instances
fail "No services." if instances.empty?
- name = input[:name, instances.collect(&:name)]
- service = instances.find { |i| i.name == name }
+ instance = input[:instance, instances]
- return unless input[:really, name, :name]
+ return unless input[:really, instance.name, :name]
- with_progress("Deleting #{c(name, :name)}") do
- service.delete!
+ with_progress("Deleting #{c(instance.name, :name)}") do |s|
+ bindings = instance.service_bindings
+
+ if bindings.empty?
+ instance.delete!
+ else
+ s.skip do
+ apps = bindings.collect(&:app).collect { |a| b(a.name) }
+ err "Service instance is bound to #{human_list(apps)}."
+ end
+ end
end
end
private
@@ -225,9 +263,20 @@
puts ""
puts "#{c(i.name, :name)}: #{service.label} v#{service.version}"
puts " description: #{service.description}"
puts " plan: #{c(plan.name, :name)}"
puts " description: #{plan.description}"
+ end
+ end
+
+ def human_list(xs)
+ if xs.size == 1
+ xs.first
+ elsif xs.size == 2
+ "#{xs.first} and #{xs.last}"
+ else
+ last = xs.pop
+ xs.join(", ") + ", and #{last}"
end
end
end
end