class EY::CLI
Constants
- OPT_TO_ROLES
Public Class Methods
start(given_args=ARGV, config={})
click to toggle source
Calls superclass method
# File lib/engineyard/cli.rb, line 20 def self.start(given_args=ARGV, config={}) Thor::Base.shell = EY::CLI::UI ui = EY::CLI::UI.new super(given_args, {shell: ui}.merge(config)) rescue Thor::Error, EY::Error, EY::CloudClient::Error => e ui.print_exception(e) raise rescue Interrupt => e puts ui.print_exception(e) ui.say("Quitting...") raise rescue SystemExit, Errno::EPIPE # don't print a message for safe exits raise rescue Exception => e ui.print_exception(e) raise end
Public Instance Methods
console()
click to toggle source
# File lib/engineyard/cli.rb, line 539 def console app_env = fetch_app_environment(options[:app], options[:environment], options[:account]) instances = filter_servers(app_env.environment, options, default: {app_master: true}) user = app_env.environment.username cmd = "cd /data/#{app_env.app.name}/current && current_user=#{api.current_user.name} bundle exec rails console" cmd = Escape.shell_command(['bash','-lc',cmd]) ssh_cmd = ["ssh"] ssh_cmd += ["-t"] trap(:INT) { abort "Aborting..." } exits = [] instances.each do |instance| host = instance.public_hostname name = instance.name ? "#{instance.role} (#{instance.name})" : instance.role ui.info "\nConnecting to #{name} #{host}..." unless cmd ui.info "Ctrl + C to abort" sleep 1.3 end sshcmd = Escape.shell_command((ssh_cmd + ["#{user}@#{host}"] + [cmd]).compact) ui.debug "$ #{sshcmd}" system sshcmd exits << $?.exitstatus end exit exits.detect {|status| status != 0 } || 0 end
deploy()
click to toggle source
# File lib/engineyard/cli.rb, line 123 def deploy app_env = fetch_app_environment(options[:app], options[:environment], options[:account]) env_config = config.environment_config(app_env.environment_name) deploy_config = EY::DeployConfig.new(options, env_config, repo, ui) deployment = app_env.new_deployment({ ref: deploy_config.ref, migrate: deploy_config.migrate, migrate_command: deploy_config.migrate_command, extra_config: deploy_config.extra_config, serverside_version: serverside_version, }) runner = serverside_runner(app_env, deploy_config.verbose, deployment.serverside_version, options[:ignore_bad_master]) out = EY::CLI::UI::Tee.new(ui.out, deployment.output) err = EY::CLI::UI::Tee.new(ui.err, deployment.output) ui.info "Beginning deploy...", :green begin deployment.start rescue ui.error "Error encountered before deploy. Deploy not started." raise end begin ui.show_deployment(deployment) out << "Deploy initiated.\n" runner.deploy do |args| args.config = deployment.config if deployment.config if deployment.migrate args.migrate = deployment.migrate_command else args.migrate = false end args.ref = deployment.resolved_ref end deployment.successful = runner.call(out, err) rescue Interrupt Signal.trap(:INT) { # The fingers you have used to dial are too fat... ui.info "\nRun `ey timeout-deploy` to mark an unfinished deployment as failed." exit 1 } err << "Interrupted. Deployment halted.\n" ui.warn <<-WARN Recording interruption of this unfinished deployment in Engine Yard Cloud... WARNING: Interrupting again may prevent Engine Yard Cloud from recording this failed deployment. Unfinished deployments can block future deploys. WARN raise rescue StandardError => e deployment.err << "Error encountered during deploy.\n#{e.class} #{e}\n" ui.print_exception(e) raise ensure ui.info "Saving log... ", :green deployment.finished if deployment.successful? ui.info "Successful deployment recorded on Engine Yard Cloud.", :green ui.info "Run `ey launch` to open the application in a browser." else ui.info "Failed deployment recorded on Engine Yard Cloud", :green raise EY::Error, "Deploy failed" end end end
environments()
click to toggle source
# File lib/engineyard/cli.rb, line 276 def environments if options[:all] && options[:simple] ui.print_simple_envs api.environments elsif options[:all] ui.print_envs api.apps else remotes = nil if options[:app] == '' repo.fail_on_no_remotes! remotes = repo.remotes end resolver = api.resolve_app_environments({ account_name: options[:account], app_name: options[:app], environment_name: options[:environment], remotes: remotes, }) resolver.no_matches do |errors| messages = errors messages << "Use #{self.class.send(:banner_base)} environments --all to see all environments." raise EY::NoMatchesError.new(messages.join("\n")) end apps = resolver.matches.map { |app_env| app_env.app }.uniq if options[:simple] if apps.size > 1 message = "# This app matches multiple Applications in Engine Yard Cloud:\n" apps.each { |app| message << "#\t#{app.name}\n" } message << "# The following environments contain those applications:\n\n" ui.warn(message) end ui.print_simple_envs(apps.map{ |app| app.environments }.flatten) else ui.print_envs(apps, config.default_environment) end end end
filter_servers(environment, cli_opts, filter_opts)
click to toggle source
# File lib/engineyard/cli.rb, line 649 def filter_servers(environment, cli_opts, filter_opts) if (cli_opts.keys.map(&:to_sym) & OPT_TO_ROLES.keys).any? options = cli_opts.dup else options = filter_opts[:default].dup end options.keep_if {|k,v| OPT_TO_ROLES.has_key?(k.to_sym) } if options[:all] instances = environment.instances else roles = {} options.each do |cli_opt,cli_val| if cli_val && OPT_TO_ROLES.has_key?(cli_opt.to_sym) OPT_TO_ROLES[cli_opt.to_sym].each do |role| roles[role] = cli_val # val is true or an array of strings end end end instances = environment.select_instances(roles) end if instances.empty? raise NoInstancesError.new(environment.name) end return instances end
help(*cmds)
click to toggle source
Calls superclass method
Thor::help
# File lib/engineyard/cli.rb, line 722 def help(*cmds) if cmds.empty? base = self.class.send(:banner_base) list = self.class.printable_tasks ui.say "Usage:" ui.say " #{base} [--help] [--version] COMMAND [ARGS]" ui.say ui.say "Deploy commands:" deploy_cmds = %w(deploy environments logs rebuild rollback status) deploy_cmds.map! do |name| list.find{|task| task[0] =~ /^#{base} #{name}/ } end list -= deploy_cmds ui.print_help(deploy_cmds) ui.say self.class.subcommands.each do |name| klass = self.class.subcommand_class_for(name) list.reject!{|cmd| cmd[0] =~ /^#{base} #{name}/} ui.say "#{name.capitalize} commands:" tasks = klass.printable_tasks.reject{|t| t[0] =~ /help$/ } ui.print_help(tasks) ui.say end %w(help version).each{|n| list.reject!{|c| c[0] =~ /^#{base} #{n}/ } } if list.any? ui.say "Other commands:" ui.print_help(list) ui.say end self.class.send(:class_options_help, shell) ui.say "See '#{base} help COMMAND' for more information on a specific command." elsif klass = self.class.subcommand_class_for(cmds.first) klass.new.help(*cmds[1..-1]) else super end end
init()
click to toggle source
# File lib/engineyard/cli.rb, line 58 def init unless EY::Repo.exist? raise EY::Error, "Working directory is not a repository. Aborting." end path = Pathname.new(options['path'] || EY::Config.pathname_for_write) existing = {} if path.exist? ui.warn "Reinitializing existing file: #{path}" existing = EY::Config.load_config end template = EY::Templates::EyYml.new(existing) template.write(path) ui.info <<-GIT Configuration generated: #{path} Go look at it, then add it to your repository! \tgit add #{path} \tgit commit -m "Add generated #{path} from ey init" GIT end
launch()
click to toggle source
# File lib/engineyard/cli.rb, line 776 def launch app_env = fetch_app_environment(options[:app], options[:environment], options[:account]) Launchy.open(app_env.uri) end
login()
click to toggle source
# File lib/engineyard/cli.rb, line 800 def login whoami end
logout()
click to toggle source
# File lib/engineyard/cli.rb, line 805 def logout eyrc = EYRC.load if eyrc.delete_api_token ui.info "API token removed: #{eyrc.path}" ui.info "Run any other command to login again." else ui.info "Already logged out. Run any other command to login again." end end
logs()
click to toggle source
# File lib/engineyard/cli.rb, line 692 def logs environment = fetch_environment(options[:environment], options[:account]) environment.logs.each do |log| ui.say "Instance: #{log.instance_name}" if log.main ui.say "Main logs for #{environment.name}:", :green ui.say log.main end if log.custom ui.say "Custom logs for #{environment.name}:", :green ui.say log.custom end end end
rebuild()
click to toggle source
# File lib/engineyard/cli.rb, line 391 def rebuild environment = fetch_environment(options[:environment], options[:account]) ui.info "Updating instances on #{environment.hierarchy_name}" environment.rebuild end
rollback()
click to toggle source
# File lib/engineyard/cli.rb, line 417 def rollback app_env = fetch_app_environment(options[:app], options[:environment], options[:account]) env_config = config.environment_config(app_env.environment_name) deploy_config = EY::DeployConfig.new(options, env_config, repo, ui) ui.info "Rolling back #{app_env.hierarchy_name}" runner = serverside_runner(app_env, deploy_config.verbose) runner.rollback do |args| args.config = {'deployed_by' => api.current_user.name, 'input_ref' => 'N/A'}.merge(deploy_config.extra_config || {}) end if runner.call(ui.out, ui.err) ui.info "Rollback complete" else raise EY::Error, "Rollback failed" end end
scp(from_path, to_path)
click to toggle source
# File lib/engineyard/cli.rb, line 606 def scp(from_path, to_path) environment = fetch_environment(options[:environment], options[:account]) instances = filter_servers(environment, options, default: {app_master: true}) user = environment.username ui.info "Copying '#{from_path}' to '#{to_path}' on #{instances.count} server#{instances.count == 1 ? '' : 's'} serially..." # default to `scp FROM_PATH HOST:TO_PATH` unless [from_path, to_path].detect { |path| path =~ /HOST:/ } to_path = "HOST:#{to_path}" end exits = [] instances.each do |instance| host = instance.public_hostname authority = "#{user}@#{host}:" name = instance.name ? "#{instance.role} (#{instance.name})" : instance.role ui.info "# #{name} #{host}" from = from_path.sub(/^HOST:/, authority) to = to_path.sub(/^HOST:/, authority) cmd = Escape.shell_command(["scp", from, to]) ui.debug "$ #{cmd}" system cmd exits << $?.exitstatus end exit exits.detect {|status| status != 0 } || 0 end
servers()
click to toggle source
# File lib/engineyard/cli.rb, line 351 def servers if options[:environment] == '' && options[:account] == '' repo.fail_on_no_remotes! end environment = nil ui.mute_if(options[:simple] || options[:host]) do environment = fetch_environment(options[:environment], options[:account]) end username = options[:user] && environment.username servers = filter_servers(environment, options, default: {all: true}) if options[:host] ui.print_hostnames(servers, username) elsif options[:simple] ui.print_simple_servers(servers, username) else ui.print_servers(servers, environment.hierarchy_name, username) end end
ssh(cmd=nil)
click to toggle source
# File lib/engineyard/cli.rb, line 476 def ssh(cmd=nil) environment = fetch_environment(options[:environment], options[:account]) instances = filter_servers(environment, options, default: {app_master: true}) user = environment.username ssh_opts = [] if cmd if options[:shell] cmd = Escape.shell_command([options[:shell],'-lc',cmd]) end if options[:pty] ssh_opts = ["-t"] elsif cmd =~ /sudo/ ui.warn "sudo commands often need a tty to run correctly. Use -t option to spawn a tty." end else if instances.size != 1 && options[:each] == false raise NoCommandError.new end if options[:bind_address] ssh_opts = ["-L", options[:bind_address]] end end ssh_cmd = ["ssh"] ssh_cmd += ssh_opts trap(:INT) { abort "Aborting..." } exits = [] instances.each do |instance| host = instance.public_hostname name = instance.name ? "#{instance.role} (#{instance.name})" : instance.role ui.info "\nConnecting to #{name} #{host}..." unless cmd ui.info "Ctrl + C to abort" sleep 1.3 end sshcmd = Escape.shell_command((ssh_cmd + ["#{user}@#{host}"] + [cmd]).compact) ui.debug "$ #{sshcmd}" system sshcmd exits << $?.exitstatus end exit exits.detect {|status| status != 0 } || 0 end
status()
click to toggle source
# File lib/engineyard/cli.rb, line 247 def status app_env = fetch_app_environment(options[:app], options[:environment], options[:account]) deployment = app_env.last_deployment if deployment ui.deployment_status(deployment) else raise EY::Error, "Application #{app_env.app.name} has not been deployed on #{app_env.environment.name}." end end
timeout_deploy()
click to toggle source
# File lib/engineyard/cli.rb, line 216 def timeout_deploy app_env = fetch_app_environment(options[:app], options[:environment], options[:account]) deployment = app_env.last_deployment if deployment && !deployment.finished? begin ui.info "Marking last deployment failed...", :green deployment.timeout ui.deployment_status(deployment) rescue EY::CloudClient::RequestFailed => e ui.error "Error encountered attempting to timeout previous deployment." raise end else raise EY::Error, "No unfinished deployment was found for #{app_env.hierarchy_name}." end end
version()
click to toggle source
# File lib/engineyard/cli.rb, line 716 def version ui.say %{engineyard version #{EY::VERSION}} end
whoami()
click to toggle source
# File lib/engineyard/cli.rb, line 782 def whoami current_user = api.current_user ui.say "#{current_user.name} (#{current_user.email})" end