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/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(uri)
10
- @base_uri = uri
9
+ def initialize(args={:base => ''})
10
+ @base_uri = args[:base]
11
11
  end
12
12
 
13
- def create_release_tag
14
- raise "There are local changes. Please revert or check them in!" unless everything_checked_in?
15
- raise "Invalid base URI (#{@base_uri}). Check RUDY_SVN_BASE." unless valid_uri?(@base_uri)
16
- raise "You must run this command from SVN you want to release from!" unless svn_dir?(Dir.pwd)
17
-
18
- re = `svn info`.match /^URL:\s+(.+)$/
19
- release = re[1] if re
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
- release_tag
23
+ release_uri
29
24
  end
30
25
 
31
- def generate_release_tag_name
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 = "r01"
36
- criteria = ['rudy', now.year, mon, day, rev]
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 svn_dir?(path)
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(3) do
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.3.2"
4
- s.summary = "Rudy is a handy staging and deployment tool for Amazon EC2."
5
- s.description = "Rudy is a handy staging and deployment tool for Amazon EC2."
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
- # find {bin,lib,support,tryouts} -type f | grep -v git
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/stage.rb
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: Your friend in staging and deploying with EC2", "--main", "README.rdoc"]
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!"
@@ -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
- RUDY_CONFIG_FILE='.rudy'
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 === "root") ? ['/root'] : ['/home', n]
89
- fileparts << RUDY_CONFIG_FILE
90
- filepath = File.join(fileparts)
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
- log "Updating /etc/hosts..."
101
- config[:hosts].each_pair do |name, address|
102
- # Respect existing entries
103
- next if read_file('/etc/hosts') =~ /#{name}/
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
- ip_address = (address !~ /^\d.+/) ? Resolv.getaddress(address) : address
125
+ ip_address = (address !~ /^\d.+/) ? Resolv.getaddress(address) : address
106
126
 
107
- log " ---> #{name}: #{ip_address}"
108
- write_to_file("/etc/hosts", "\n#{ip_address}\t#{name}\n")
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 (filename, s, type='a')
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
+