rudy 0.3.2 → 0.4.0
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.
- data/CHANGES.txt +53 -3
- data/README.rdoc +9 -5
- data/bin/rudy +115 -292
- data/bin/rudy-ec2 +107 -0
- data/lib/console.rb +322 -278
- data/lib/rudy.rb +78 -55
- data/lib/rudy/aws/ec2.rb +63 -5
- data/lib/rudy/command/addresses.rb +18 -13
- data/lib/rudy/command/backups.rb +175 -0
- data/lib/rudy/command/base.rb +664 -146
- data/lib/rudy/command/config.rb +77 -0
- data/lib/rudy/command/deploy.rb +12 -0
- data/lib/rudy/command/disks.rb +165 -195
- data/lib/rudy/command/environment.rb +42 -64
- data/lib/rudy/command/groups.rb +21 -19
- data/lib/rudy/command/images.rb +34 -19
- data/lib/rudy/command/instances.rb +46 -92
- data/lib/rudy/command/machines.rb +161 -0
- data/lib/rudy/command/metadata.rb +14 -30
- data/lib/rudy/command/release.rb +174 -0
- data/lib/rudy/command/volumes.rb +26 -10
- data/lib/rudy/config.rb +93 -0
- data/lib/rudy/metadata/backup.rb +1 -1
- data/lib/rudy/metadata/disk.rb +15 -50
- data/lib/rudy/scm/svn.rb +32 -21
- data/lib/rudy/utils.rb +2 -3
- data/lib/storable.rb +4 -0
- data/lib/tryouts.rb +40 -0
- data/rudy.gemspec +25 -9
- data/support/mailtest +40 -0
- data/support/rudy-ec2-startup +41 -15
- data/tryouts/console_tryout.rb +91 -0
- metadata +86 -11
- data/lib/drydock.rb +0 -524
- data/lib/rudy/command/stage.rb +0 -45
- data/lib/rudy/metadata/config.rb +0 -8
- data/lib/rudy/metadata/environment.rb +0 -0
data/lib/rudy/scm/svn.rb
CHANGED
@@ -6,41 +6,52 @@ module Rudy
|
|
6
6
|
class SVN
|
7
7
|
attr_accessor :base_uri
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
@base_uri =
|
9
|
+
def initialize(args={:base => ''})
|
10
|
+
@base_uri = args[:base]
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
release_tag = "#{@base_uri}/#{generate_release_tag_name}"
|
22
|
-
|
23
|
-
puts "Creating tag: #{release_tag}"
|
24
|
-
cmd = "svn copy -m 'Another Release by Rudy!' #{release} #{release_tag}"
|
13
|
+
def create_release(username=nil, msg=nil)
|
14
|
+
local_uri, local_revision = local_info
|
15
|
+
rtag = generate_release_tag_name(username)
|
16
|
+
release_uri = "#{@base_uri}/#{rtag}"
|
17
|
+
msg ||= 'Another Release by Rudy!'
|
18
|
+
msg.tr!("'", "\\'")
|
19
|
+
cmd = "svn copy -m '#{msg}' #{local_uri} #{release_uri}"
|
25
20
|
|
26
21
|
`#{cmd} 2>&1`
|
27
22
|
|
28
|
-
|
23
|
+
release_uri
|
29
24
|
end
|
30
25
|
|
31
|
-
def
|
26
|
+
def switch_working_copy(tag)
|
27
|
+
raise "Invalid release tag (#{tag})." unless valid_uri?(tag)
|
28
|
+
`svn switch #{tag}`
|
29
|
+
end
|
30
|
+
|
31
|
+
# rel-2009-03-05-user-rev
|
32
|
+
def generate_release_tag_name(username=nil)
|
32
33
|
now = Time.now
|
33
34
|
mon = now.mon.to_s.rjust(2, '0')
|
34
35
|
day = now.day.to_s.rjust(2, '0')
|
35
|
-
rev = "
|
36
|
-
criteria = ['
|
36
|
+
rev = "01"
|
37
|
+
criteria = ['rel', now.year, mon, day, rev]
|
38
|
+
criteria.insert(-2, username) if username
|
37
39
|
tag = criteria.join(RUDY_DELIM)
|
38
|
-
# Keep incrementing the revision number until we find the next one.
|
39
|
-
tag.succ! while (valid_uri?("#{@base_uri}/#{tag}"))
|
40
|
+
# Keep incrementing the revision number until we find the next one.
|
41
|
+
tag.succ! while (valid_uri?("#{@base_uri}/#{tag}"))
|
40
42
|
tag
|
41
43
|
end
|
42
44
|
|
43
|
-
def
|
45
|
+
def local_info
|
46
|
+
ret = `svn info 2>&1`
|
47
|
+
# URL: http://some/uri/path
|
48
|
+
# Repository Root: http://some/uri
|
49
|
+
# Repository UUID: c5abe49d-53e4-4ea3-9314-89e1e25aa7e1
|
50
|
+
# Revision: 921
|
51
|
+
ret.scan(/URL: (http:.+?)\s*\n.+Revision: (\d+)/m).flatten
|
52
|
+
end
|
53
|
+
|
54
|
+
def working_copy?(path)
|
44
55
|
(File.exists?(File.join(path, '.svn')))
|
45
56
|
end
|
46
57
|
|
data/lib/rudy/utils.rb
CHANGED
@@ -3,7 +3,6 @@ require 'socket'
|
|
3
3
|
require 'open-uri'
|
4
4
|
require 'date'
|
5
5
|
|
6
|
-
require 'socket'
|
7
6
|
require 'timeout'
|
8
7
|
|
9
8
|
module Rudy
|
@@ -49,9 +48,9 @@ module Rudy
|
|
49
48
|
end
|
50
49
|
|
51
50
|
|
52
|
-
def service_available?(host, port)
|
51
|
+
def service_available?(host, port, wait=3)
|
53
52
|
begin
|
54
|
-
status = Timeout::timeout(
|
53
|
+
status = Timeout::timeout(wait) do
|
55
54
|
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
|
56
55
|
sockaddr = Socket.pack_sockaddr_in( port, host )
|
57
56
|
socket.connect( sockaddr )
|
data/lib/storable.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#--
|
2
2
|
# TODO: Handle nested hashes and arrays.
|
3
3
|
# TODO: to_xml, see: http://codeforpeople.com/lib/ruby/xx/xx-2.0.0/README
|
4
|
+
# TODO: Rename to Stuffany
|
4
5
|
#++
|
5
6
|
|
6
7
|
require 'yaml'
|
@@ -26,7 +27,10 @@ class Storable
|
|
26
27
|
@format = v
|
27
28
|
end
|
28
29
|
|
30
|
+
# TODO: from_args([HASH or ordered params])
|
31
|
+
|
29
32
|
def init
|
33
|
+
# NOTE: I think this can be removed
|
30
34
|
self.class.send(:class_variable_set, :@@field_names, []) unless class_variable_defined?(:@@field_names)
|
31
35
|
self.class.send(:class_variable_set, :@@field_types, []) unless class_variable_defined?(:@@field_types)
|
32
36
|
end
|
data/lib/tryouts.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module Tryouts
|
5
|
+
|
6
|
+
def before(&b)
|
7
|
+
b.call
|
8
|
+
end
|
9
|
+
def after(&b)
|
10
|
+
at_exit &b
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
# tryout :name do
|
15
|
+
# ...
|
16
|
+
# end
|
17
|
+
def tryout(name, &b)
|
18
|
+
puts "Running#{@poop}: #{name}"
|
19
|
+
begin
|
20
|
+
b.call
|
21
|
+
puts $/*2
|
22
|
+
sleep 1
|
23
|
+
rescue Interrupt
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Ignore everything
|
28
|
+
def xtryout(name, &b)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Is this wacky syntax useful for anything?
|
32
|
+
# t2 :set .
|
33
|
+
# run = "poop"
|
34
|
+
def t2(*args)
|
35
|
+
OpenStruct.new
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
include Tryouts
|
data/rudy.gemspec
CHANGED
@@ -1,58 +1,74 @@
|
|
1
1
|
@spec = Gem::Specification.new do |s|
|
2
2
|
s.name = "rudy"
|
3
|
-
s.version = "0.
|
4
|
-
s.summary = "
|
5
|
-
s.description =
|
3
|
+
s.version = "0.4.0"
|
4
|
+
s.summary = "Your friend in staging and deploying with EC2."
|
5
|
+
s.description = s.summary
|
6
6
|
s.author = "Delano Mandelbaum"
|
7
7
|
s.email = "delano@solutious.com"
|
8
8
|
s.homepage = "http://github.com/solutious/rudy"
|
9
9
|
|
10
10
|
# = MANIFEST =
|
11
|
-
#
|
11
|
+
# git ls-files
|
12
12
|
s.files = %w(
|
13
13
|
CHANGES.txt
|
14
14
|
LICENSE.txt
|
15
15
|
README.rdoc
|
16
16
|
Rakefile
|
17
17
|
bin/rudy
|
18
|
+
bin/rudy-ec2
|
18
19
|
lib/aws_sdb.rb
|
19
20
|
lib/aws_sdb/error.rb
|
20
21
|
lib/aws_sdb/service.rb
|
21
22
|
lib/console.rb
|
22
|
-
lib/drydock.rb
|
23
23
|
lib/rudy.rb
|
24
24
|
lib/rudy/aws.rb
|
25
25
|
lib/rudy/aws/ec2.rb
|
26
26
|
lib/rudy/aws/s3.rb
|
27
27
|
lib/rudy/aws/simpledb.rb
|
28
28
|
lib/rudy/command/addresses.rb
|
29
|
+
lib/rudy/command/backups.rb
|
29
30
|
lib/rudy/command/base.rb
|
31
|
+
lib/rudy/command/config.rb
|
32
|
+
lib/rudy/command/deploy.rb
|
30
33
|
lib/rudy/command/disks.rb
|
31
34
|
lib/rudy/command/environment.rb
|
32
35
|
lib/rudy/command/groups.rb
|
33
36
|
lib/rudy/command/images.rb
|
34
37
|
lib/rudy/command/instances.rb
|
38
|
+
lib/rudy/command/machines.rb
|
35
39
|
lib/rudy/command/metadata.rb
|
36
|
-
lib/rudy/command/
|
40
|
+
lib/rudy/command/release.rb
|
37
41
|
lib/rudy/command/volumes.rb
|
42
|
+
lib/rudy/config.rb
|
38
43
|
lib/rudy/metadata.rb
|
39
44
|
lib/rudy/metadata/backup.rb
|
40
|
-
lib/rudy/metadata/config.rb
|
41
45
|
lib/rudy/metadata/disk.rb
|
42
|
-
lib/rudy/metadata/environment.rb
|
43
46
|
lib/rudy/scm/svn.rb
|
44
47
|
lib/rudy/utils.rb
|
45
48
|
lib/storable.rb
|
49
|
+
lib/tryouts.rb
|
46
50
|
rudy.gemspec
|
51
|
+
support/mailtest
|
47
52
|
support/rudy-ec2-startup
|
53
|
+
tryouts/console_tryout.rb
|
48
54
|
)
|
49
55
|
s.executables = %w[rudy]
|
50
56
|
|
51
57
|
s.extra_rdoc_files = %w[README.rdoc LICENSE.txt]
|
52
58
|
s.has_rdoc = true
|
53
|
-
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Rudy:
|
59
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Rudy: #{s.summary}", "--main", "README.rdoc"]
|
54
60
|
s.require_paths = %w[lib]
|
55
61
|
s.rubygems_version = '1.1.1'
|
62
|
+
|
56
63
|
|
64
|
+
s.add_dependency 'drydock'
|
65
|
+
s.add_dependency 'caesars'
|
66
|
+
s.add_dependency 'net-ssh'
|
67
|
+
s.add_dependency 'net-scp'
|
68
|
+
s.add_dependency 'net-ssh-gateway'
|
69
|
+
s.add_dependency 'net-ssh-multi'
|
70
|
+
s.add_dependency 'highline'
|
71
|
+
|
72
|
+
|
57
73
|
s.rubyforge_project = 'rudy'
|
58
74
|
end
|
data/support/mailtest
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# A simple SMTP mailer.
|
4
|
+
# You can use this to test mail configuration between machines.
|
5
|
+
|
6
|
+
# Usage: mailtest hostname email
|
7
|
+
|
8
|
+
require 'net/smtp'
|
9
|
+
|
10
|
+
unless ARGV.size == 2
|
11
|
+
puts "Usage: mailtest HOSTNAME EMAIL"
|
12
|
+
exit 1
|
13
|
+
end
|
14
|
+
|
15
|
+
HOSTNAME = ARGV[0]
|
16
|
+
EMAIL = ARGV[1]
|
17
|
+
|
18
|
+
def send_email(from, from_alias, to, to_alias, subject, message)
|
19
|
+
msg = <<END_OF_MESSAGE
|
20
|
+
From: #{from_alias} <#{from}>
|
21
|
+
To: #{to_alias} <#{to}>
|
22
|
+
Subject: #{subject}
|
23
|
+
|
24
|
+
#{message}
|
25
|
+
END_OF_MESSAGE
|
26
|
+
|
27
|
+
Net::SMTP.start(HOSTNAME) do |smtp|
|
28
|
+
smtp.send_message msg, from, to
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
begin
|
33
|
+
spice = sprintf("%.3f", rand)
|
34
|
+
send_email(HOSTNAME, "Rudy", EMAIL, "Rudy's Friend", "Mail config (#{spice})", "You received this email via #{HOSTNAME}")
|
35
|
+
rescue => ex
|
36
|
+
puts "ERROR: #{ex.message}"
|
37
|
+
exit 1
|
38
|
+
end
|
39
|
+
|
40
|
+
puts "Success!"
|
data/support/rudy-ec2-startup
CHANGED
@@ -33,7 +33,8 @@ METADATA = 'http://169.254.169.254/2008-02-01/meta-data'
|
|
33
33
|
|
34
34
|
METADATAPARAMS = ['instance-id', 'instance-type']
|
35
35
|
|
36
|
-
|
36
|
+
RUDY_CONFIG_DIR=File.join('.rudy')
|
37
|
+
RUDY_CONFIG_FILE=File.join('config')
|
37
38
|
|
38
39
|
module Rudy
|
39
40
|
module EC2Startup
|
@@ -68,7 +69,11 @@ module Rudy
|
|
68
69
|
|
69
70
|
config = YAML::load(config_yaml)
|
70
71
|
config ||= {}
|
71
|
-
|
72
|
+
|
73
|
+
# Print to STDOUT and NOT to the log.
|
74
|
+
# We don't want sensitive config values available in the log
|
75
|
+
puts "CONFIG: " << config_yaml
|
76
|
+
|
72
77
|
zone = config[:zone] ? config[:zone].downcase : "zone"
|
73
78
|
environment = config[:environment] ? config[:environment].downcase : "env"
|
74
79
|
role = config[:role] ? config[:role].downcase : "role"
|
@@ -85,9 +90,22 @@ module Rudy
|
|
85
90
|
# TODO: How to we get the path to any user's home directory?
|
86
91
|
# (when we're not running as that user.)
|
87
92
|
config[:userdata].each_pair do |n,hash|
|
88
|
-
fileparts = (n
|
89
|
-
fileparts <<
|
90
|
-
|
93
|
+
fileparts = (n == :root) ? ['/root'] : [user_home_dir(n)]
|
94
|
+
fileparts << RUDY_CONFIG_DIR
|
95
|
+
dirpath = File.join(fileparts)
|
96
|
+
filepath = File.join(dirpath, RUDY_CONFIG_FILE)
|
97
|
+
|
98
|
+
# Backwards compatability
|
99
|
+
if !File.directory?(dirpath)
|
100
|
+
log "Deleting the deprecated #{dirpath} config"
|
101
|
+
File.unlink(dirpath)
|
102
|
+
end
|
103
|
+
|
104
|
+
unless File.exists?(dirpath)
|
105
|
+
log "Creating #{dirpath}"
|
106
|
+
Dir.mkdir(dirpath, 0700)
|
107
|
+
end
|
108
|
+
|
91
109
|
log "Writing to #{filepath}"
|
92
110
|
user_data = {
|
93
111
|
:userdata => hash
|
@@ -97,15 +115,18 @@ module Rudy
|
|
97
115
|
end
|
98
116
|
|
99
117
|
if config[:hosts] && config[:hosts].is_a?(Hash)
|
100
|
-
|
101
|
-
|
102
|
-
#
|
103
|
-
|
118
|
+
unless read_file('/etc/hosts') =~ /----- RUDY SAYS -----/
|
119
|
+
log "Updating /etc/hosts..."
|
120
|
+
write_to_file("/etc/hosts", "\n# ----- RUDY SAYS -----\n", :append)
|
121
|
+
config[:hosts].each_pair do |name, address|
|
122
|
+
# Respect existing entries
|
123
|
+
next if read_file('/etc/hosts') =~ /#{name}/
|
104
124
|
|
105
|
-
|
125
|
+
ip_address = (address !~ /^\d.+/) ? Resolv.getaddress(address) : address
|
106
126
|
|
107
|
-
|
108
|
-
|
127
|
+
log " ---> #{name}: #{ip_address}"
|
128
|
+
write_to_file("/etc/hosts", "\n#{ip_address}\t#{name}\n", :append)
|
129
|
+
end
|
109
130
|
end
|
110
131
|
end
|
111
132
|
|
@@ -143,7 +164,8 @@ module Rudy
|
|
143
164
|
t_out = t.strftime("%H:%M:%S%p (%m/%d/%Y)")
|
144
165
|
end
|
145
166
|
|
146
|
-
def write_to_file
|
167
|
+
def write_to_file(filename, s, type)
|
168
|
+
type = (type == :append) ? 'a' : 'w'
|
147
169
|
f = File.open(filename,type)
|
148
170
|
f.puts s
|
149
171
|
f.close
|
@@ -161,10 +183,14 @@ module Rudy
|
|
161
183
|
end
|
162
184
|
contents
|
163
185
|
end
|
164
|
-
|
186
|
+
|
187
|
+
def user_home_dir(user)
|
188
|
+
(`su #{user} -c "echo \\$HOME"` || '').chomp
|
189
|
+
end
|
190
|
+
|
165
191
|
def log(s)
|
166
192
|
msg = "#{get_formatted_time}: #{s}"
|
167
|
-
write_to_file(LOGFILE, msg)
|
193
|
+
write_to_file(LOGFILE, msg, :append)
|
168
194
|
puts msg
|
169
195
|
end
|
170
196
|
|
@@ -0,0 +1,91 @@
|
|
1
|
+
RUDY_HOME = File.join(File.dirname(__FILE__), '..')
|
2
|
+
RUDY_LIB = File.join(RUDY_HOME, 'lib')
|
3
|
+
$:.unshift RUDY_LIB # Put our local lib in first place
|
4
|
+
|
5
|
+
require 'yaml'
|
6
|
+
require 'date'
|
7
|
+
|
8
|
+
require 'tryouts'
|
9
|
+
require 'console'
|
10
|
+
|
11
|
+
raise "Sorry Ruby 1.9 only!" unless RUBY_VERSION =~ /1.9/
|
12
|
+
|
13
|
+
before do
|
14
|
+
@title = "RUDY v0.3"
|
15
|
+
@now_utc = Time.now.utc.strftime("%Y-%m-%d %H:%M:%S")
|
16
|
+
@props = {
|
17
|
+
:zone => "us-east-1b",
|
18
|
+
:environment => "stage",
|
19
|
+
:role =>"app",
|
20
|
+
:position => "01"
|
21
|
+
}
|
22
|
+
# PROMPT_COMMAND
|
23
|
+
end
|
24
|
+
|
25
|
+
after do
|
26
|
+
#Console.clear
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
tryout :positioned do
|
31
|
+
Console.print_at(@title, {:y => Cursor.y, :x => Cursor.x })
|
32
|
+
sleep 1
|
33
|
+
Console.print_at(@now_utc, {:y => Cursor.y, :x => Console.width, :minus => true})
|
34
|
+
puts
|
35
|
+
sleep 1
|
36
|
+
Console.print_left(@title)
|
37
|
+
sleep 1
|
38
|
+
Console.print_right(@now_utc)
|
39
|
+
puts
|
40
|
+
sleep 1
|
41
|
+
Console.print_spaced('1'*25, 2, 3, '4'*30, 5, 6)
|
42
|
+
puts
|
43
|
+
sleep 1
|
44
|
+
Console.print_center(Window.bar(50))
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
tryout :u_r_d_l do
|
49
|
+
puts
|
50
|
+
Cursor.up && print('.')
|
51
|
+
sleep 1
|
52
|
+
Cursor.right && print('.')
|
53
|
+
sleep 1
|
54
|
+
Cursor.left && Cursor.down && print('.')
|
55
|
+
sleep 1
|
56
|
+
Cursor.left(3) && print('.')
|
57
|
+
end
|
58
|
+
|
59
|
+
tryout :update_inplace do
|
60
|
+
[(0..11).to_a, (90..110).to_a].flatten.each do |i|
|
61
|
+
Console.print_at(i, {:y => Cursor.y, :x => 4 })
|
62
|
+
sleep 0.05
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
tryout :danger! do
|
69
|
+
win = Window.new(:width => 100, :height => 100)
|
70
|
+
|
71
|
+
# DEBUGGING: There is a threading bug where the values of props and the
|
72
|
+
# string to print are being shared. Make Console and class and give an instance
|
73
|
+
# to each thread. However, that could fuck up shit like Cursor.position.
|
74
|
+
|
75
|
+
|
76
|
+
win.static(:right, 0.2, {:y => 0}) do
|
77
|
+
Time.now.utc.strftime("%Y-%m-%d %H:%M:%S").colour(:blue, :white, :underline)
|
78
|
+
end
|
79
|
+
win.static(:left, 0.2) do
|
80
|
+
rand
|
81
|
+
end
|
82
|
+
|
83
|
+
win.join_threads
|
84
|
+
|
85
|
+
puts $/, "Done!"
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
|