rudy 0.2

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,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
+