require "uuidtools" module VMC::Cli::Command class Services < Base include VMC::Cli::ServicesHelper include VMC::Cli::TunnelHelper def services ss = client.services_info ps = client.services ps.sort! {|a, b| a[:name] <=> b[:name] } if @options[:json] services = { :system => ss, :provisioned => ps } return display JSON.pretty_generate(services) end display_system_services(ss) display_provisioned_services(ps) end def create_service(service=nil, name=nil, appname=nil) unless no_prompt || service services = client.services_info err 'No services available to provision' if services.empty? service = ask( "Which service would you like to provision?", { :indexed => true, :choices => services.values.collect { |type| type.keys.collect(&:to_s) }.flatten } ) end name = @options[:name] unless name unless name name = random_service_name(service) picked_name = true end if client.infra_supported? unless no_prompt || @options[:infra] @options[:infra] = VMC::Cli::InfraHelper.name_for_description( ask("Select Infrastructure", :indexed => true, :choices => VMC::Cli::InfraHelper.infra_descriptions)) end end create_service_banner(service, name, picked_name, @options[:infra]) appname = @options[:bind] unless appname bind_service_banner(name, appname) if appname end def delete_service(service=nil) unless no_prompt || service user_services = client.services err 'No services available to delete' if user_services.empty? service = ask( "Which service would you like to delete?", { :indexed => true, :choices => user_services.collect { |s| s[:name] } } ) end err "Service name required." unless service display "Deleting service [#{service}]: ", false client.delete_service(service) display 'OK'.green end def bind_service(service, appname) bind_service_banner(service, appname) end def unbind_service(service, appname) unbind_service_banner(service, appname) end def clone_services(src_app, dest_app) begin src = client.app_info(src_app) dest = client.app_info(dest_app) rescue end err "Application '#{src_app}' does not exist" unless src err "Application '#{dest_app}' does not exist" unless dest services = src[:services] err 'No services to clone' unless services && !services.empty? services.each { |service| bind_service_banner(service, dest_app, false) } check_app_for_restart(dest_app) end def tunnel(service=nil, client_name=nil) unless defined? Caldecott display "To use `af tunnel', you must first install Caldecott:" display "" display "\tgem install caldecott" display "" display "Note that you'll need a C compiler. If you're on OS X, Xcode" display "will provide one. If you're on Windows, try DevKit." display "" display "This manual step will be removed in the future." display "" err "Caldecott is not installed." end ps = client.services err "No services available to tunnel to" if ps.empty? unless service choices = ps.collect { |s| s[:name] }.sort service = ask( "Which service to tunnel to?", :choices => choices, :indexed => true ) end info = ps.select { |s| s[:name] == service }.first err "Unknown service '#{service}'" unless info port = pick_tunnel_port(@options[:port] || 10000) raise VMC::Client::AuthError unless client.logged_in? infra_name = info[:infra] ? info[:infra][:name] : default_infra if infra_name err "Infra '#{infra_name}' is not valid" unless VMC::Cli::InfraHelper.valid?(infra_name) end if not tunnel_pushed?(infra_name) display "Deploying tunnel application '#{tunnel_appname(infra_name)}'." auth = UUIDTools::UUID.random_create.to_s push_caldecott(auth,infra_name) bind_service_banner(service, tunnel_appname(infra_name), false) start_caldecott(infra_name) else auth = tunnel_auth(infra_name) end if not tunnel_healthy?(auth,infra_name) display "Redeploying tunnel application '#{tunnel_appname(infra_name)}'." # We don't expect caldecott not to be running, so take the # most aggressive restart method.. delete/re-push client.delete_app(tunnel_appname(infra_name)) invalidate_tunnel_app_info(infra_name) push_caldecott(auth,infra_name) bind_service_banner(service, tunnel_appname(infra_name), false) start_caldecott(infra_name) end if not tunnel_bound?(service,infra_name) bind_service_banner(service, tunnel_appname(infra_name)) end conn_info = tunnel_connection_info info[:vendor], service, auth, infra_name display_tunnel_connection_info(conn_info) display "Starting tunnel to #{service.bold} on port #{port.to_s.bold}." start_tunnel(port, conn_info, auth, infra_name) clients = get_clients_for(info[:vendor]) if clients.empty? client_name ||= "none" else client_name ||= ask( "Which client would you like to start?", :choices => ["none"] + clients.keys, :indexed => true ) end if client_name == "none" wait_for_tunnel_end else wait_for_tunnel_start(port) unless start_local_prog(clients, client_name, conn_info, port) err "'#{client_name}' execution failed; is it in your $PATH?" end end end def get_clients_for(type) conf = VMC::Cli::Config.clients conf[type] || {} end end end