lib/awsssh.rb in awsssh-2.2.2 vs lib/awsssh.rb in awsssh-3.0.0.rc1

- old
+ new

@@ -1,211 +1,114 @@ require "awsssh/version" -require 'net/ssh' -require 'json' -require "aws-sdk" -# Bundler.require(:default, :development) -require "inifile" require "thor" +require "inifile" +require "aws-sdk" + module Awsssh class Awsssh < Thor - CONFIG_DIR = ENV['AWSSSH_CONFIG_DIR'] || "/Users/#{ENV['USER']}/.aws/" - CONF_FILE = ENV['AWSSSH_CONFIG_FILE'] || "aws_config_" - desc "-s SERVER [-a ACCOUNT]", "connect to a server" - option :server, :aliases => '-s', :desc => "(required) The server name to connect with" - option :account, :aliases => '-a', :desc => "Specify a account for a connection. Needet if the account don't came from the server name" - option :list, :aliases => '-l', :desc => "List any items use with -s for Servers or -a ACCOUNT for accounts", :type => :boolean - option :check, :aliases => '-c', :desc => "Alerts when -c STATE comes up for -s SERVER" - option :version, :aliases => '-v', :desc => "Version" - long_desc <<-LONGDESC - # Connect to a Server: - - - > $ awsssh -s SERVER - \x5 This will connect you to a Server. This will work only if the first part of the server name is the same as the account name. - - > $ awsssh -s SERVER -a ACCOUNT - \x5 With -a you can spezify a account to connect with. The server name don't play any role. - - # List all Account: - - > $ awsssh -l -a - \x5 This will list all Accounts - - # List all Servers for a Account - - > $ awsssh -l -s ACCOUNT - \x5 List all Servers vor Account ACCOUNT - - # Check Server Status - - LONGDESC - def connect - if options[:list] && options[:account] - list_accounts - elsif options[:list] && options[:server] - list_servers(options[:server]) - elsif options[:server] - connecting(options[:server], options[:account]) - elsif options[:version] - puts VERSION - else - help "connect" + desc "list_profiles", "List all your avavible profiles" + def list_profiles() + credentials = open_credantial_file + puts "List of all known AWS Accounts" + puts + credentials.sections.each do |section| + puts " #{section}" end end - def help(*args) - super("connect") - end + desc "list_server PROFILE", "List all Server for given profile" + def list_server(profile) + credentials = open_credantial_file + raise "Profile `#{profile}` not found. Please try `awsssh list_profiles`" if credentials[profile].empty? + aws_connection(profile, credentials) - private + puts "Stacks and instances for profile `#{profile}`" + puts - ## - # List stacks for a account - # - # * *Args* : - # - +account+ -> Account name - # - # * *Returns* : - # - [Array] StackIDs - def list_stacks(account) - ow = awscfg(account) - stacks = ow.client.describe_stacks[:stacks] - stack_ids = [] - stacks.each do |stack| - stack_ids << stack[:stack_id] + @client.describe_stacks.stacks.each do |stack| + puts "##### Stack: #{stack.name}" + @client.describe_instances({stack_id: stack.stack_id}).instances.each do |instance| + printf " %-20s status: %-11s %s\n" % [instance.hostname, instance.status, public_dns(instance)] end - return stack_ids + puts "" end + end + desc "connect SERVERNAME", "Connect to Hostname" + option :profile, :desc => "specify a profile - see `awsssh list_profiles`" + def connect (hostname) + hostname_parts = hostname.split("-") + profile = options[:profile] || hostname_parts[0] + credentials = open_credantial_file + puts "Profile `#{profile}` not found. Try `awsssh SERVERNAME --profile PROFILE`" if credentials[profile].empty? + exit -1 if credentials[profile].empty? - ## - # Read Stack - # - # * *Args* : - # - +stackid+ -> Stack ID - # - +account+ -> Account name - # - # * *Returns* : - # - Stecks JSON - # - def read_stack(stackid, account) - ow = awscfg(account) - ow.client.describe_instances({:stack_id => stackid}) - # JSON.parse(`aws opsworks describe-instances --stack-id #{stackid}`) + aws_connection(profile, credentials) + puts "looking for hostname `#{hostname}` in profile `#{profile}`. This may take a while..." + puts + public_dns = find_server(@client.describe_stacks.stacks, hostname) + if public_dns.nil? + puts "`#{hostname}` was not found or has no public ip." + puts "Try `awsssh list_server PROFILE`" + puts "checking your local ssh config..." + puts + exec "ssh #{hostname}" + exit -1 + else + puts "start ssh connection to `#{hostname}`..." + puts + exec "ssh #{public_dns}" + exit 0 end + end - ## - # Lists all AWS Accounts - # - # * *Returns* : - # - [String] - # This are the known AWS Accounts: - # - account - def list_accounts - length = 30 - puts "This are the known AWS Accounts:" - config_files = Dir.entries(CONFIG_DIR) - config_files.each do |file| - if file[0,CONF_FILE.length] == CONF_FILE - file_part = file.split("_") - unless file_part.last.nil? - printf "\t- %-#{length}s\n", file_part[2] - end - end - end - end + desc "version", "Version" + def version + puts "version #{VERSION}" + end - ## - # Server Name - # - # * *Args* : - # - +stack+ -> Stack as JSON - # - # * *Returns* : - # - [String] - # - <servername> (<status>) - def server_name(stack) - stack[:instances].each do |instance| - host = build_hostname(instance) - printf "\t- %-20s %s \t %-15s \t %s\n", instance[:hostname], instance[:status], host[:ip], host[:hostname] - end - end - ## - # List all Servers for a given AWS Account - # - # * *Args* : - # - +account+ -> AWS Account name - # - def list_servers(account) - stacks = list_stacks account - stacks.each do |stack_id| - stack = read_stack stack_id, account - server_name stack - end - end + private - ## - # Establish the connection - # - # * *Args* : - # - +server+ -> Server name - # - def connecting(server, account=nil) - public_dns = nil - host = server.split("-") - ac = account || host[0] - stack_ids = list_stacks ac - stack_ids.each do |stack_id| - stack = read_stack(stack_id, ac) - stack.instances.each do |i| - if i[:hostname] == server - public_dns = build_hostname(i)[:hostname] - break - end - end - break unless public_dns.nil? - end + ## + # open and check credential file + # + def open_credantial_file() + raise "Enviroment variable `AWS_CREDENTIAL_FILE` not set" if ENV['AWS_CREDENTIAL_FILE'].nil? + raise "Credential File not found. Please check path `#{ENV['AWS_CREDENTIAL_FILE']}`" unless File.exist?(ENV['AWS_CREDENTIAL_FILE']) + IniFile.load(ENV['AWS_CREDENTIAL_FILE']) + end - if public_dns.nil? - puts "Server '#{server}' not found. Try ssh" - exec "ssh #{server}" - exit -1 - end + ## + # + def aws_connection(profile, credentials = nil) + credentials ||= open_credantial_file + @client = Aws::OpsWorks::Client.new({ + region: credentials[profile]["region"], + credentials: Aws::Credentials.new( + credentials[profile]["aws_access_key_id"], + credentials[profile]["aws_secret_access_key"] + ) + }) + end - puts "Connecting to #{server} (#{public_dns})" - exec "ssh #{public_dns}" + def public_dns(instance) + public_ip = instance.public_ip || instance.elastic_ip + return nil if public_ip == nil + "ec2-#{public_ip.gsub(".", "-")}.#{instance.availability_zone.chop}.compute.amazonaws.com" + end - end - - def build_hostname(instance) - host = {} - if instance[:status] != 'online' - host[:ip] = host[:hostname] = nil - return host + def find_server(stacks, hostname) + stacks.each do |stack| + @client.describe_instances({stack_id: stack.stack_id}).instances.each do |instance| + return public_dns(instance) if instance.hostname == hostname end - az = (instance[:availability_zone][-1].match(/[a-z]/)) ? - instance[:availability_zone][0..-2] : - instance[:availability_zone] - host[:ip] = instance[:public_ip] || instance[:elastic_ip] - host[:hostname] = "ec2-#{host[:ip].gsub("\.", "\-")}.#{az}.compute.amazonaws.com" - host end + return nil + end - def awscfg(account) - if cnf = IniFile.load(CONFIG_DIR + CONF_FILE + account) - cnf = cnf['default'] - return AWS::OpsWorks.new( - access_key_id: cnf['aws_access_key_id'], - secret_access_key: cnf['aws_secret_access_key'], - region: cnf['region'] - ) - else - puts "No config #{CONF_FILE}#{account} found. Maybe use -a to specify a account." - exit -1 - end - end + default_task :connect end end