awsam 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '../lib')
4
+
5
+ require 'awsam'
6
+
7
+ #
8
+ # Will perform an scp to/from an instance ID.
9
+ #
10
+ #
11
+ # Usage: ascp [user@]<instance ID>:remote-file local-file
12
+ # ascp local-file [user@]<instance ID>:remote-file
13
+
14
+ if ARGV.length == 0
15
+ puts 'Usage: ascp [user@]<instance ID>:remote-file local-file'
16
+ puts ' ascp local-file [user@]<instance ID>:remote-file'
17
+ exit 1
18
+ end
19
+
20
+ user = "root"
21
+
22
+ args = ARGV.clone
23
+
24
+ Awsam::Accounts::load!
25
+ acct = Awsam::Accounts::active
26
+ unless acct
27
+ puts "No active account. Use 'aem use <account name>' to select one"
28
+ exit 1
29
+ end
30
+
31
+ keyfile = nil
32
+ 0.upto(args.length - 1) do |i|
33
+ m = args[i].match(/([a-zA-Z0-9_]{1,}@){0,1}(i-[0-9a-f]{8}):/)
34
+ if m
35
+ user = m[1]
36
+ instance_id = m[2]
37
+
38
+ inst = Awsam::Ec2::find_instance(acct, instance_id)
39
+ unless inst
40
+ puts "Unable to locate instance ID #{instance_id}"
41
+ exit 1
42
+ end
43
+
44
+ if inst[:aws_state] != "running"
45
+ puts "Instance #{instance_id} is not running, it's #{inst[:aws_state]}"
46
+ exit 1
47
+ end
48
+
49
+ args[i] = args[i].gsub(instance_id, inst[:dns_name])
50
+
51
+ key = acct.find_key(inst[:ssh_key_name])
52
+ keyfile = key.path if key
53
+ break
54
+ end
55
+ end
56
+
57
+ if keyfile
58
+ args.unshift('-i', keyfile, '-o', 'IdentitiesOnly=yes')
59
+ end
60
+
61
+ exec "scp #{args.join(" ")}"
62
+
63
+ # Local Variables:
64
+ # mode: ruby
65
+ # End:
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '../lib')
4
+
5
+ require 'awsam'
6
+ require 'trollop'
7
+
8
+ $opts = Trollop::options do
9
+ banner <<-EOS
10
+
11
+ NAME
12
+ assh -- ssh client for EC2
13
+
14
+ SYNOPSIS
15
+ assh [-f --first-node] [user@]hostname
16
+
17
+ DESCRIPTION
18
+ assh is a program for logging into an EC2 node. assh allows you to specify a hostname by either an instance ID or a
19
+ tag name. Specifying a hostname by a substring of multiple tags, by default, will allow you to specify the exact node you
20
+ want to use.
21
+
22
+ The options are as follows:
23
+
24
+ -f first-node
25
+ Use first_node to specify that you want to override assh's default behavior when multiple tag names result from your
26
+ requested hostname. By enabling this flag, you're allowing assh to use any of the resulting hosts.
27
+ EOS
28
+
29
+ opt :first_node, "Use first node mode", :short => "-f"
30
+ end
31
+
32
+ user = "root"
33
+ instance_id = ARGV[0]
34
+
35
+ if instance_id.include?("@")
36
+ (user, instance_id) = instance_id.split("@")
37
+ elsif ENV['AWS_DEFAULT_USER'].to_s.length > 0
38
+ user = ENV['AWS_DEFAULT_USER']
39
+ end
40
+
41
+ Awsam::Accounts::load!
42
+
43
+ acct = Awsam::Accounts::active
44
+ unless acct
45
+ puts "No active account. Use 'aem use <account name>' to select one"
46
+ exit 1
47
+ end
48
+
49
+ inst = Awsam::Ec2::find_instance(acct, instance_id)
50
+ unless inst
51
+ puts "Unable to locate instance ID #{instance_id}"
52
+ exit 1
53
+ end
54
+
55
+ if inst[:aws_state] != "running"
56
+ puts "Instance #{instance_id} is not running, it's #{inst[:aws_state]}"
57
+ exit 1
58
+ end
59
+
60
+ puts "Logging in as #{user} to #{inst[:dns_name]}"
61
+ puts
62
+
63
+ key = acct.find_key(inst[:ssh_key_name])
64
+
65
+ if key
66
+ exec "ssh -i #{key.path} -o IdentitiesOnly=yes #{user}@#{inst[:dns_name]}"
67
+ else
68
+ exec "ssh #{user}@#{inst[:dns_name]}"
69
+ end
70
+
71
+ # Local Variables:
72
+ # mode: ruby
73
+ # End:
@@ -0,0 +1,260 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '../lib')
4
+
5
+ begin
6
+ require 'awsam'
7
+ rescue LoadError => err
8
+ $stderr.puts "ERROR: Unable to load AWSAM gem dependencies: #{err.message}"
9
+ exit 1
10
+ end
11
+
12
+ require 'optparse'
13
+
14
+ def err(*args)
15
+ $stderr.puts *args
16
+ end
17
+
18
+ def read_val(prompt, default = nil)
19
+ begin
20
+ if default
21
+ print "#{prompt} [#{default}]: "
22
+ else
23
+ print "#{prompt}: "
24
+ end
25
+
26
+ val = gets.chomp
27
+ if val.empty? && default
28
+ val = default
29
+ end
30
+ end while val.empty?
31
+
32
+ val
33
+ end
34
+
35
+ Awsam::Accounts::load!
36
+
37
+ $options = {}
38
+ $cmd = nil
39
+
40
+ def selected_account(default_fallback = false)
41
+ if !$options[:account] || $options[:account].empty?
42
+ err "Command requires an account"
43
+ exit 1
44
+ end
45
+
46
+ acct = Awsam::Accounts.find($options[:account])
47
+ unless acct
48
+ exit 1
49
+ end
50
+ acct
51
+ end
52
+
53
+ def usage
54
+ puts "Usage: raem --init"
55
+ exit
56
+ end
57
+
58
+ optparse = OptionParser.new do|opts|
59
+ opts.banner = "Usage: raem [options]\n"
60
+
61
+ # help
62
+ opts.on( '-h', '--help', 'Display this screen' ) do
63
+ usage
64
+ end
65
+
66
+ opts.on('--add') do
67
+ $cmd = :add_account
68
+ end
69
+
70
+ opts.on('--remove') do
71
+ $cmd = :remove_account
72
+ end
73
+
74
+ opts.on('--account <ACCOUNT>') do |acctname|
75
+ $options[:account] = acctname
76
+ end
77
+
78
+ opts.on('--import-key') do
79
+ $cmd = :import_key
80
+ end
81
+
82
+ opts.on('--remove-key') do
83
+ $cmd = :remove_key
84
+ end
85
+
86
+ opts.on('--keyname <KEYNAME>') do |keyname|
87
+ $options[:keyname] = keyname
88
+ end
89
+
90
+ opts.on('--keyfile <KEYFILE>') do |keyfile|
91
+ $options[:keyfile] = keyfile
92
+ end
93
+
94
+ opts.on('--list') do
95
+ $cmd = :list
96
+ end
97
+
98
+ opts.on('--environ') do
99
+ $cmd = :environ
100
+ end
101
+
102
+ opts.on('--environ-key') do
103
+ $cmd = :environ_key
104
+ end
105
+
106
+ opts.on('--init') do
107
+ $cmd = :init
108
+ end
109
+
110
+ opts.on('--print-default-acct') do
111
+ $cmd = :print_default_acct
112
+ end
113
+
114
+ opts.on('--print-default-key') do
115
+ $cmd = :print_default_key
116
+ end
117
+
118
+ opts.on('--default') do
119
+ $options[:set_default] = true
120
+ end
121
+ end
122
+
123
+ optparse.parse!(ARGV)
124
+
125
+ usage unless $cmd
126
+
127
+ case $cmd
128
+ when :init
129
+ Awsam::init_awsam
130
+
131
+ when :list
132
+ inuse = ENV['AWSAM_ACTIVE_ACCOUNT']
133
+ inusekey = ENV['AWSAM_ACTIVE_KEY']
134
+ puts "\nAWS Accounts:\n\n"
135
+
136
+ default = Awsam::Accounts::get_default
137
+ accts = Awsam::Accounts::get
138
+ accts.each_pair do |name, acct|
139
+ desc = acct.desc ? " [#{acct.desc}]" : ""
140
+ if acct.keys.length > 0
141
+ dfltkey = acct.get_default_key
142
+ names = acct.keys.keys.collect{ |k|
143
+ pfx1 = (inuse == name && inusekey == k) ? ">" : ""
144
+ pfx2 = (dfltkey && dfltkey.name == k) ? "*" : ""
145
+ "#{pfx1}#{pfx2}#{k}"
146
+ }.join(",")
147
+ plural = "key" + (acct.keys.length > 1 ? "s" : "")
148
+ desc += " [#{acct.keys.length} #{plural}: #{names}]"
149
+ end
150
+ pfx = inuse == name ? "=>" : " "
151
+ dfltmark = (default && default.name == name) ? "*" : " "
152
+ puts "#{pfx}#{dfltmark}#{name}#{desc}"
153
+ end
154
+
155
+ puts
156
+
157
+ when :print_default_acct
158
+ default = Awsam::Accounts::get_default
159
+ exit 1 unless default
160
+ puts default.name
161
+
162
+ when :print_default_key
163
+ acct = selected_account
164
+ default = acct.get_default_key
165
+ exit 1 unless default
166
+ puts default.name
167
+
168
+ when :environ
169
+ acct = selected_account
170
+
171
+ if $options[:set_default]
172
+ r = Awsam::Accounts::set_default(acct.name)
173
+ unless r
174
+ err "Failed to set account #{acct.name} as the default"
175
+ exit 1
176
+ end
177
+ end
178
+
179
+ acct.print_environ
180
+
181
+ when :environ_key
182
+ unless $options[:keyname]
183
+ err "Option requires a keyname"
184
+ exit 1
185
+ end
186
+
187
+ acct = selected_account
188
+
189
+ k = acct.find_key($options[:keyname])
190
+ unless k
191
+ err "Could not find key #{$options[:keyname]} in active account"
192
+ exit 1
193
+ end
194
+
195
+ if $options[:set_default]
196
+ r = acct.set_default_key(k.name)
197
+ unless r
198
+ err "Failed to set key #{k.name} as the default"
199
+ exit 1
200
+ end
201
+ end
202
+
203
+ k.print_environ
204
+
205
+ when :add_account
206
+ puts "Creating a new AWS account...\n"
207
+ short_name = read_val("Short name")
208
+ desc = read_val("Description")
209
+ aws_region = read_val("AWS Region", ENV['AWS_DEFAULT_REGION'])
210
+ access_key = read_val("Access key", (ENV['AMAZON_ACCESS_KEY_ID'] || ENV['AWS_ACCESS_KEY']))
211
+ secret_key = read_val("Secret key", (ENV['AMAZON_SECRET_ACCESS_KEY'] || ENV['AWS_SECRET_KEY']))
212
+ aws_id = read_val("AWS ID", ENV['AMAZON_AWS_ID'])
213
+
214
+ acct = Awsam::Account.new(short_name,
215
+ { :description => desc,
216
+ :access_key => access_key,
217
+ :secret_key => secret_key,
218
+ :aws_id => aws_id,
219
+ :aws_region => aws_region
220
+ })
221
+ acct.save
222
+
223
+ when :remove_account
224
+ selected_account.remove
225
+
226
+ when :import_key
227
+ unless $options[:keyname] && $options[:keyfile]
228
+ err "Requires keyname and keyfile!"
229
+ exit 1
230
+ end
231
+
232
+ acct = selected_account
233
+
234
+ display = acct.name + (acct.desc ? " [#{acct.desc}]" : "")
235
+
236
+ unless File.exist?($options[:keyfile])
237
+ err "Unable to locate key file: #{$options[:keyfile]}"
238
+ exit 1
239
+ end
240
+
241
+ ret = acct.import_key($options[:keyname], $options[:keyfile])
242
+ err "Imported key pair #{$options[:keyname]} for account #{display}"
243
+
244
+ when :remove_key
245
+ unless $options[:keyname]
246
+ err "Requires keyname!"
247
+ exit 1
248
+ end
249
+
250
+ acct = selected_account
251
+ unless acct.remove_key($options[:keyname])
252
+ err "Failed to remove key #{$options[:keyname]}"
253
+ exit 1
254
+ end
255
+ end
256
+
257
+
258
+ # Local Variables:
259
+ # mode: ruby
260
+ # End:
@@ -0,0 +1,46 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), 'awsam')
2
+
3
+ require 'fileutils'
4
+
5
+ $:.unshift File.join(File.dirname(__FILE__), '../vendor/right_aws/lib')
6
+ $:.unshift File.join(File.dirname(__FILE__), '../vendor/right_http_connection/lib')
7
+
8
+ require 'right_aws'
9
+
10
+ require 'accounts'
11
+ require 'ec2'
12
+
13
+ module Awsam
14
+ CONF_BASE_DIR = ".awsam"
15
+ CONF_DIR = File.join(ENV['HOME'], CONF_BASE_DIR)
16
+ DEFAULT_LINK_NAME = ".default"
17
+
18
+ def self.get_conf_dir
19
+ FileUtils.mkdir(CONF_DIR) unless File.exist?(CONF_DIR)
20
+ CONF_DIR
21
+ end
22
+
23
+ def self.get_accts_dir
24
+ base = get_conf_dir()
25
+ acctsdir = File.join(base, 'accts')
26
+ FileUtils.mkdir(acctsdir) unless File.exist?(acctsdir)
27
+ acctsdir
28
+ end
29
+
30
+ def self.init_awsam
31
+ dir = get_conf_dir
32
+ File.open(File.join(dir, "bash.rc"), "w") do |f|
33
+ f << File.read(File.join(File.dirname(__FILE__), '../bashrc/rc.scr'))
34
+ end
35
+
36
+ puts
37
+ puts "Initialized AWS Account Manager"
38
+ puts
39
+ puts "Add the following to your $HOME/.bashrc:"
40
+ puts
41
+ puts " if [ -s $HOME/#{CONF_BASE_DIR}/bash.rc ]; then"
42
+ puts " source $HOME/#{CONF_BASE_DIR}/bash.rc"
43
+ puts " fi"
44
+ puts
45
+ end
46
+ end
@@ -0,0 +1,139 @@
1
+ require 'yaml'
2
+ require 'fileutils'
3
+
4
+ require 'key'
5
+ require 'utils'
6
+
7
+ module Awsam
8
+ class Account
9
+ DEFAULT_REGION = "us-east-1"
10
+
11
+ attr_reader :name, :keys
12
+
13
+ def initialize(name, params)
14
+ if name == Awsam::DEFAULT_LINK_NAME
15
+ # We require this for our default account symlink
16
+ raise "Can not name an account: #{Awsam::DEFAULT_LINK_NAME}"
17
+ end
18
+ @name = name
19
+ @params = params
20
+
21
+ @params[:aws_region] ||= DEFAULT_REGION
22
+
23
+ load_keys
24
+ end
25
+
26
+ def self.load_from_disk(dir)
27
+ name = File.basename(dir)
28
+ conffile = File.join(dir, 'conf.yml')
29
+
30
+ return nil unless File.exist?(conffile)
31
+
32
+ File.open(conffile) do |yf|
33
+ @conf = YAML::load(yf)
34
+ end
35
+
36
+ Account.new(name, @conf)
37
+ end
38
+
39
+ def load_keys
40
+ @keys = Hash.new
41
+ base = conf_file('keys')
42
+ return unless File.exist?(base)
43
+ Utils::confdir_scan(base) do |name|
44
+ @keys[name] = Key.new(File.join(base, name))
45
+ end
46
+ end
47
+
48
+ def print_environ
49
+ envs = {
50
+ "AMAZON_ACCESS_KEY_ID" => @params[:access_key],
51
+ "AWS_ACCESS_KEY_ID" => @params[:access_key],
52
+ "AWS_ACCESS_KEY" => @params[:access_key],
53
+
54
+ "AMAZON_SECRET_ACCESS_KEY" => @params[:secret_key],
55
+ "AWS_SECRET_ACCESS_KEY" => @params[:secret_key],
56
+ "AWS_SECRET_KEY" => @params[:secret_key],
57
+
58
+ "AMAZON_AWS_ID" => @params[:aws_id],
59
+ "AWS_DEFAULT_REGION" => @params[:aws_region]
60
+ }
61
+
62
+ Utils::bash_environ(envs)
63
+ end
64
+
65
+ def find_key(name)
66
+ @keys[name]
67
+ end
68
+
69
+ def import_key(name, path)
70
+ @keys[name] = Key.import(conf_file, name, path)
71
+ end
72
+
73
+ def remove_key(name)
74
+ return false unless @keys.has_key?(name)
75
+
76
+ dflt = get_default_key
77
+ Utils::remove_default(conf_file('keys')) if dflt && dflt.name == name
78
+ @keys[name].remove
79
+ @keys.delete(name)
80
+ true
81
+ end
82
+
83
+ def set_default_key(keyname)
84
+ key = @keys[keyname]
85
+ unless key
86
+ $stderr.puts "No key named #{keyname}"
87
+ return false
88
+ end
89
+
90
+ Utils::set_default(conf_file('keys'), keyname)
91
+ end
92
+
93
+ def get_default_key
94
+ dflt = Utils::get_default(conf_file('keys'))
95
+ @keys[dflt]
96
+ end
97
+
98
+ def remove
99
+ dir = conf_file
100
+ acct = Awsam::Accounts::get_default
101
+ if acct && acct.name == @name
102
+ # Need to remove default link if we're the default account
103
+ Awsam::Accounts::remove_default
104
+ end
105
+
106
+ FileUtils.rm_rf(dir)
107
+ end
108
+
109
+ def save
110
+ dir = File.join(Awsam::get_accts_dir, @name)
111
+ FileUtils.mkdir(dir) unless File.exist?(dir)
112
+
113
+ File.open(File.join(dir, 'conf.yml'), "w", 0600) do |out|
114
+ YAML.dump(@params, out )
115
+ end
116
+ end
117
+
118
+ # Export params...need better way to do this
119
+ def desc
120
+ @params[:description]
121
+ end
122
+
123
+ def access_key
124
+ @params[:access_key]
125
+ end
126
+
127
+ def secret_key
128
+ @params[:secret_key]
129
+ end
130
+
131
+ private
132
+
133
+ def conf_file(file = nil)
134
+ dir = File.join(Awsam::get_accts_dir(), @name)
135
+
136
+ return file.nil? ? dir : File.join(dir, file)
137
+ end
138
+ end
139
+ end