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