rudy 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,102 @@
1
+
2
+ require 'right_aws'
3
+ require 'stringio'
4
+ require 'ostruct'
5
+ require 'yaml'
6
+
7
+ require 'storable'
8
+
9
+ require 'rudy/aws'
10
+ require 'rudy/scm/svn'
11
+ require 'rudy/utils'
12
+ require 'rudy/command/base'
13
+
14
+ # Autoload Command and MetaData classes
15
+ begin
16
+ Dir.glob(File.join(RUDY_LIB, 'rudy', 'command', "*.rb")).each do |path|
17
+ require path
18
+ end
19
+ Dir.glob(File.join(RUDY_LIB, 'rudy', 'metadata', "*.rb")).each do |path|
20
+ require path
21
+ end
22
+ rescue LoadError => ex
23
+ puts "Error: #{ex.message}"
24
+ exit 1
25
+ end
26
+
27
+ module Rudy #:nodoc:
28
+ RUDY_DOMAIN = ENV['RUDY_DOMAIN'] || "rudy_state"
29
+ RUDY_DELIM = ENV['RUDY_DELIM'] || '-'
30
+ DEFAULT_REGION = ENV['EC2_DEFAULT_REGION'] || 'us-east-1'
31
+ DEFAULT_ZONE = ENV['EC2_DEFAULT_ZONE'] || 'us-east-1b'
32
+
33
+ module VERSION #:nodoc:
34
+ MAJOR = 0.freeze unless defined? MAJOR
35
+ MINOR = 2.freeze unless defined? MINOR
36
+ TINY = 0.freeze unless defined? TINY
37
+ def self.to_s
38
+ [MAJOR, MINOR, TINY].join('.')
39
+ end
40
+ def self.to_f
41
+ self.to_s.to_f
42
+ end
43
+ end
44
+ end
45
+
46
+
47
+
48
+ # Capture STDOUT or STDERR to prevent it from being printed.
49
+ #
50
+ # capture(:stdout) do
51
+ # ...
52
+ # end
53
+ #
54
+ def capture(stream)
55
+ raise "We can only capture STDOUT or STDERR" unless stream == :stdout || stream == :stderr
56
+
57
+ # I'm using this to trap the annoying right_aws "peer certificate" warning.
58
+ # TODO: discover source of annoying right_aws warning and give it a hiding.
59
+ begin
60
+ stream = stream.to_s
61
+ eval "$#{stream} = StringIO.new"
62
+ yield
63
+ result = eval("$#{stream}").read
64
+ ensure
65
+ eval("$#{stream} = #{stream.upcase}")
66
+ end
67
+
68
+ result
69
+ end
70
+
71
+ def you_are_sure?
72
+ print "Are you sure? "
73
+ STDIN.gets =~ /^y|yes|ya$/i
74
+ end
75
+ def sh(command, chdir=false)
76
+ prevdir = Dir.pwd
77
+ Dir.chdir chdir if chdir
78
+ puts command if @verbose > 0
79
+ system(command)
80
+ Dir.chdir prevdir if chdir
81
+ end
82
+
83
+ # TODO: Net::SSH
84
+ def ssh(host, keypair, user, command, chdir=false, verbose=false)
85
+ cmd = "ssh -q -i #{keypair} #{user}@#{host} '"
86
+ cmd += "cd #{chdir} && " if chdir
87
+ cmd += " #{command}'"
88
+ puts cmd if verbose
89
+ system(cmd)
90
+ end
91
+
92
+
93
+ def scp(host, keypair, user, local_path, remote_path, verbose=false)
94
+ cmd = "scp -i #{keypair} #{local_path} #{user}@#{host}:#{remote_path}"
95
+ puts cmd if verbose
96
+ system(cmd)
97
+ end
98
+
99
+
100
+
101
+
102
+
@@ -0,0 +1,65 @@
1
+
2
+
3
+
4
+
5
+ module Rudy
6
+ module AWS
7
+
8
+ module ObjectBase
9
+ attr_accessor :aws
10
+ def initialize(aws_connection)
11
+ @aws = aws_connection
12
+ end
13
+ end
14
+
15
+ class EC2
16
+ @@logger = StringIO.new
17
+
18
+ attr_reader :instances
19
+ attr_reader :images
20
+ attr_reader :addresses
21
+ attr_reader :groups
22
+ attr_reader :volumes
23
+ attr_reader :aws
24
+
25
+ def initialize(access_key, secret_key)
26
+ @aws = RightAws::Ec2.new(access_key, secret_key, {:logger => Logger.new(@@logger)})
27
+ @instances = Rudy::AWS::EC2::Instances.new(@aws)
28
+ @images = Rudy::AWS::EC2::Images.new(@aws)
29
+ @groups = Rudy::AWS::EC2::Groups.new(@aws)
30
+ @addresses = Rudy::AWS::EC2::Addresses.new(@aws)
31
+ @volumes = Rudy::AWS::EC2::Volumes.new(@aws)
32
+ end
33
+
34
+ end
35
+
36
+ class S3
37
+ @@logger = StringIO.new
38
+
39
+ attr_reader :aws
40
+
41
+ def initialize(access_key, secret_key)
42
+ @aws = RightAws::S3.new(access_key, secret_key, {:logger => Logger.new(@@logger)})
43
+ end
44
+ end
45
+
46
+ class SimpleDB
47
+ @@logger = StringIO.new
48
+
49
+ attr_reader :domains
50
+ attr_reader :aws
51
+
52
+ def initialize(access_key, secret_key)
53
+ @aws = RightAws::SdbInterface.new(access_key, secret_key, {:logger => Logger.new(@@logger)})
54
+ @domains = Rudy::AWS::SimpleDB::Domains.new(@aws)
55
+ end
56
+
57
+ end
58
+
59
+ require 'rudy/aws/simpledb'
60
+ require 'rudy/aws/ec2'
61
+ require 'rudy/aws/s3'
62
+
63
+ end
64
+
65
+ end
@@ -0,0 +1,197 @@
1
+
2
+ module Rudy::AWS
3
+
4
+ class EC2
5
+ class Images
6
+ include Rudy::AWS::ObjectBase
7
+
8
+ # Returns an array of hashes:
9
+ # {:aws_architecture=>"i386", :aws_owner=>"105148267242", :aws_id=>"ami-6fe40dd5",
10
+ # :aws_image_type=>"machine", :aws_location=>"bucket-name/your-image.manifest.xml",
11
+ # :aws_kernel_id=>"aki-a71cf9ce", :aws_state=>"available", :aws_ramdisk_id=>"ari-a51cf9cc",
12
+ # :aws_is_public=>false}
13
+ def list
14
+ @aws.describe_images_by_owner('self') || []
15
+ end
16
+
17
+ end
18
+ class Volumes
19
+ include Rudy::AWS::ObjectBase
20
+
21
+ def list
22
+ list = @aws.describe_volumes() || []
23
+ list.select { |v| v[:aws_status] != "deleting" }
24
+ end
25
+
26
+ def attach(inst_id, vol_id, device)
27
+ @aws.attach_volume(vol_id, inst_id, device)
28
+ end
29
+
30
+ def create(zone, size, snapshot=nil)
31
+ @aws.create_volume(snapshot, size, zone)
32
+ end
33
+
34
+ def exists?(id)
35
+ list.each do |v|
36
+ return true if v[:aws_id] === id
37
+ end
38
+ false
39
+ end
40
+
41
+ end
42
+
43
+ class Instances
44
+ include Rudy::AWS::ObjectBase
45
+
46
+ def destroy(*list)
47
+ begin
48
+ @aws.terminate_instances(list.flatten)
49
+ rescue RightAws::AwsError => ex
50
+ raise UnknownInstance.new
51
+ end
52
+ end
53
+
54
+ def attached_volume?(id, device)
55
+ list = volumes(id)
56
+ list.each do |v|
57
+ return true if v[:aws_device] == device
58
+ end
59
+ false
60
+ end
61
+
62
+ def volumes(id)
63
+ list = @aws.describe_volumes() || []
64
+ list.select { |v| v[:aws_status] != "deleting" && v[:aws_instance_id] === id }
65
+ end
66
+
67
+ def create(ami, group, keypair_name, user_data, zone)
68
+ @aws.run_instances(ami, 1, 1, [group], keypair_name, user_data, 'public', nil, nil, nil, zone)
69
+ end
70
+
71
+ # Creates a list of running instance IDs which are in a security group
72
+ # that matches +filter+.
73
+ # Returns a hash. The keys are instance IDs and the values are a hash
74
+ # of attributes associated to that instance.
75
+ def list(filter='.')
76
+ filter = filter.to_s.downcase.tr('_|-', '.') # treat dashes, underscores as one
77
+ # Returns an array of hashes with the following keys:
78
+ # :aws_image_id, :aws_reason, :aws_state_code, :aws_owner, :aws_instance_id, :aws_reservation_id
79
+ # :aws_state, :dns_name, :ssh_key_name, :aws_groups, :private_dns_name, :aws_instance_type,
80
+ # :aws_launch_time, :aws_availability_zone :aws_kernel_id, :aws_ramdisk_id
81
+ instances = @aws.describe_instances || []
82
+ running_instances = {}
83
+ instances.each do |inst|
84
+ if inst[:aws_state] != "terminated" && (inst[:aws_groups].to_s =~ /#{filter}/)
85
+ running_instances[inst[:aws_instance_id]] = inst
86
+ end
87
+ end
88
+ running_instances
89
+ end
90
+
91
+ def get(inst_id)
92
+ instance = {}
93
+ list.each_pair do |id, hash|
94
+ next unless inst_id == id
95
+ instance = hash
96
+ end
97
+ instance
98
+ end
99
+
100
+ def running?(inst_id)
101
+ inst = get(inst_id)
102
+ (inst && inst[:aws_state] == "running")
103
+ end
104
+
105
+ def pending?(inst_id)
106
+ inst = get(inst_id)
107
+ (inst && inst[:aws_state] == "pending")
108
+ end
109
+ end
110
+
111
+ class Groups
112
+ include Rudy::AWS::ObjectBase
113
+
114
+
115
+ # +list+ is a list of security groups to look for. If it's empty, all groups
116
+ # associated to the account will be returned.
117
+ # right_aws returns an array of hashes
118
+ # :aws_group_name => "default-1",
119
+ # :aws_owner => "000000000888",
120
+ # :aws_description => "Default allowing SSH, HTTP, and HTTPS ingress",
121
+ # :aws_perms => [{:owner => "000000000888", :group => "default"},
122
+ # {:owner => "000000000888", :group => "default-1"},
123
+ # {:to_port => "-1", :protocol => "icmp", :from_port => "-1", :cidr_ips => "0.0.0.0/0"}]
124
+ # ]
125
+ def list(list=[])
126
+ glist = @aws.describe_security_groups(list) || []
127
+
128
+ end
129
+
130
+ # Create a new EC2 security group
131
+ # Returns true/false whether successful
132
+ def create(name, desc='')
133
+ @aws.create_security_group(name, desc)
134
+ end
135
+
136
+ # Delete an EC2 security group
137
+ # Returns true/false whether successful
138
+ def destroy(name)
139
+ @aws.delete_security_group(name)
140
+ end
141
+
142
+ # Modify an EC2 security group
143
+ # Returns true/false whether successful
144
+ def modify(name, from_port, to_port, protocol='tcp', ipa='0.0.0.0/0')
145
+ @aws.authorize_security_group_IP_ingress(name, from_port, to_port, protocol, ipa)
146
+ end
147
+
148
+
149
+ # Does the security group +name+ exist?
150
+ def exists?(name)
151
+ begin
152
+ g = list([name.to_s])
153
+
154
+ rescue RightAws::AwsError => ex
155
+ # Ignore (it raises an exception when the list contains an unknown group name)
156
+ ensure
157
+ g ||= []
158
+ end
159
+
160
+ !g.empty?
161
+ end
162
+
163
+ end
164
+
165
+ class Addresses
166
+ include Rudy::AWS::ObjectBase
167
+
168
+ # Returns and array of hashes:
169
+ # [{:instance_id=>"i-d630cbbf", :public_ip=>"75.101.1.140"},
170
+ # {:instance_id=>nil, :public_ip=>"75.101.1.141"}]
171
+ def list
172
+ @aws.describe_addresses || []
173
+ end
174
+
175
+
176
+ # Associate an elastic IP to an instance
177
+ def associate(instance, address)
178
+ @aws.associate_address(instance, address)
179
+ end
180
+
181
+ def valid?(address)
182
+ list.each do |a|
183
+ return true if a[:public_ip] == address
184
+ end
185
+ false
186
+ end
187
+
188
+ def associated?(address)
189
+ list.each do |a|
190
+ return true if a[:public_ip] == address && a[:instance_id]
191
+ end
192
+ false
193
+ end
194
+ end
195
+ end
196
+
197
+ end
@@ -0,0 +1,3 @@
1
+
2
+ module Rudy::AWS
3
+ end
@@ -0,0 +1,48 @@
1
+
2
+
3
+
4
+ module Rudy::AWS
5
+
6
+
7
+ class SimpleDB
8
+ class Domains
9
+ include Rudy::AWS::ObjectBase
10
+
11
+ def create(name)
12
+ @aws.create_domain(name)
13
+ end
14
+
15
+ def destroy(name)
16
+ @aws.delete_domain(name)
17
+ end
18
+
19
+ def list
20
+ @aws.list_domains
21
+ end
22
+ end
23
+
24
+ def destroy(domain, item, attributes={})
25
+ @aws.delete_attributes(domain, item, attributes)
26
+ end
27
+
28
+ def store(domain, item, attributes={}, replace=false)
29
+ @aws.put_attributes(domain, item, attributes, replace)
30
+ end
31
+
32
+ def query(domain, query=nil, max=nil)
33
+ @aws.query(domain, query, max)
34
+ end
35
+
36
+ def query_with_attributes(domain, query, max=nil)
37
+ items = {}
38
+ query(domain, query)[:items].each do |item|
39
+ items[item] = get_attributes(domain, item)[:attributes]
40
+ end
41
+ items
42
+ end
43
+
44
+ def get_attributes(domain, item, attribute=nil)
45
+ @aws.get_attributes(domain, item, attribute)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,41 @@
1
+
2
+
3
+
4
+ module Rudy
5
+ module Command
6
+ class Addresses < Rudy::Command::Base
7
+
8
+ def associate_address(address)
9
+ raise "You did not supply an instance ID" unless instance
10
+ inst = @ec2.instances.get(instance)
11
+ raise "Instance #{inst[:aws_instance_id]} is not running!" unless inst
12
+
13
+ raise "You have not supplied an IP addresses" unless address
14
+ raise "That's not an elastic IP you own!" unless @ec2.addresses.valid?(address)
15
+ raise "#{address} is already associated!" if @ec2.addresses.associated?(address)
16
+
17
+ puts "Associating #{address} to #{inst[:aws_groups]}: #{inst[:dns_name]}"
18
+ @ec2.addresses.associate(inst[:aws_instance_id], address)
19
+ puts "Done!"
20
+ puts
21
+
22
+ print_addresses
23
+ end
24
+
25
+ def print_addresses
26
+ puts "Elastic IP mappings:"
27
+ @ec2.addresses.list.each do |address|
28
+ print "IP: #{address[:public_ip]} "
29
+ if address[:instance_id]
30
+ inst = @ec2.instances.get(address[:instance_id])
31
+ puts "%s: %s %s" % [inst[:aws_groups], inst[:aws_instance_id], inst[:dns_name]]
32
+ end
33
+ end
34
+ puts
35
+ end
36
+
37
+
38
+ end
39
+ end
40
+ end
41
+